10#define STB_TRUETYPE_IMPLEMENTATION
293#ifdef STB_TRUETYPE_IMPLEMENTATION
310 #define STBTT_ifloor(x) ((int) floor(x))
311 #define STBTT_iceil(x) ((int) ceil(x))
316 #define STBTT_sqrt(x) sqrt(x)
317 #define STBTT_pow(x,y) pow(x,y)
322 #define STBTT_fmod(x,y) fmod(x,y)
327 #define STBTT_cos(x) cos(x)
328 #define STBTT_acos(x) acos(x)
333 #define STBTT_fabs(x) fabs(x)
339 #define STBTT_malloc(x,u) ((void)(u),malloc(x))
340 #define STBTT_free(x,u) ((void)(u),free(x))
345 #define STBTT_assert(x) assert(x)
350 #define STBTT_strlen(x) strlen(x)
355 #define STBTT_memcpy memcpy
356 #define STBTT_memset memset
367#ifndef PLUTOVG_STB_TRUETYPE_H
368#define PLUTOVG_STB_TRUETYPE_H
371#define STBTT_DEF static
373#define STBTT_DEF extern
397 unsigned short x0,y0,x1,y1;
401STBTT_DEF int stbtt_BakeFontBitmap(
const unsigned char *data,
int offset,
403 unsigned char *pixels,
int pw,
int ph,
404 int first_char,
int num_chars,
419 float *xpos,
float *ypos,
421 int opengl_fillrule);
432STBTT_DEF void stbtt_GetScaledFontVMetrics(
const unsigned char *fontdata,
int index,
float size,
float *ascent,
float *descent,
float *lineGap);
445 unsigned short x0,y0,x1,y1;
452#ifndef STB_RECT_PACK_VERSION
456STBTT_DEF int stbtt_PackBegin(
stbtt_pack_context *spc,
unsigned char *pixels,
int width,
int height,
int stride_in_bytes,
int padding,
void *alloc_context);
470#define STBTT_POINT_SIZE(x) (-(x))
473 int first_unicode_char_in_range,
int num_chars_in_range,
stbtt_packedchar *chardata_for_range);
527 float *xpos,
float *ypos,
529 int align_to_integer);
565STBTT_DEF int stbtt_GetNumberOfFonts(
const unsigned char *data);
572STBTT_DEF int stbtt_GetFontOffsetForIndex(
const unsigned char *data,
int index);
647STBTT_DEF int stbtt_GetFontVMetricsOS2(
const stbtt_fontinfo *info,
int *typoAscent,
int *typoDescent,
int *typoLineGap);
656STBTT_DEF void stbtt_GetCodepointHMetrics(
const stbtt_fontinfo *info,
int codepoint,
int *advanceWidth,
int *leftSideBearing);
664STBTT_DEF int stbtt_GetCodepointBox(
const stbtt_fontinfo *info,
int codepoint,
int *x0,
int *y0,
int *x1,
int *y1);
667STBTT_DEF void stbtt_GetGlyphHMetrics(
const stbtt_fontinfo *info,
int glyph_index,
int *advanceWidth,
int *leftSideBearing);
669STBTT_DEF int stbtt_GetGlyphBox(
const stbtt_fontinfo *info,
int glyph_index,
int *x0,
int *y0,
int *x1,
int *y1);
702 #define stbtt_vertex_type short
739STBTT_DEF void stbtt_FreeBitmap(
unsigned char *bitmap,
void *userdata);
742STBTT_DEF unsigned char *stbtt_GetCodepointBitmap(
const stbtt_fontinfo *info,
float scale_x,
float scale_y,
int codepoint,
int *width,
int *height,
int *xoff,
int *yoff);
751STBTT_DEF unsigned char *stbtt_GetCodepointBitmapSubpixel(
const stbtt_fontinfo *info,
float scale_x,
float scale_y,
float shift_x,
float shift_y,
int codepoint,
int *width,
int *height,
int *xoff,
int *yoff);
755STBTT_DEF void stbtt_MakeCodepointBitmap(
const stbtt_fontinfo *info,
unsigned char *output,
int out_w,
int out_h,
int out_stride,
float scale_x,
float scale_y,
int codepoint);
761STBTT_DEF void stbtt_MakeCodepointBitmapSubpixel(
const stbtt_fontinfo *info,
unsigned char *output,
int out_w,
int out_h,
int out_stride,
float scale_x,
float scale_y,
float shift_x,
float shift_y,
int codepoint);
765STBTT_DEF void stbtt_MakeCodepointBitmapSubpixelPrefilter(
const stbtt_fontinfo *info,
unsigned char *output,
int out_w,
int out_h,
int out_stride,
float scale_x,
float scale_y,
float shift_x,
float shift_y,
int oversample_x,
int oversample_y,
float *sub_x,
float *sub_y,
int codepoint);
769STBTT_DEF void stbtt_GetCodepointBitmapBox(
const stbtt_fontinfo *font,
int codepoint,
float scale_x,
float scale_y,
int *ix0,
int *iy0,
int *ix1,
int *iy1);
776STBTT_DEF void stbtt_GetCodepointBitmapBoxSubpixel(
const stbtt_fontinfo *font,
int codepoint,
float scale_x,
float scale_y,
float shift_x,
float shift_y,
int *ix0,
int *iy0,
int *ix1,
int *iy1);
782STBTT_DEF unsigned char *stbtt_GetGlyphBitmap(
const stbtt_fontinfo *info,
float scale_x,
float scale_y,
int glyph,
int *width,
int *height,
int *xoff,
int *yoff);
783STBTT_DEF unsigned char *stbtt_GetGlyphBitmapSubpixel(
const stbtt_fontinfo *info,
float scale_x,
float scale_y,
float shift_x,
float shift_y,
int glyph,
int *width,
int *height,
int *xoff,
int *yoff);
784STBTT_DEF void stbtt_MakeGlyphBitmap(
const stbtt_fontinfo *info,
unsigned char *output,
int out_w,
int out_h,
int out_stride,
float scale_x,
float scale_y,
int glyph);
785STBTT_DEF void stbtt_MakeGlyphBitmapSubpixel(
const stbtt_fontinfo *info,
unsigned char *output,
int out_w,
int out_h,
int out_stride,
float scale_x,
float scale_y,
float shift_x,
float shift_y,
int glyph);
786STBTT_DEF void stbtt_MakeGlyphBitmapSubpixelPrefilter(
const stbtt_fontinfo *info,
unsigned char *output,
int out_w,
int out_h,
int out_stride,
float scale_x,
float scale_y,
float shift_x,
float shift_y,
int oversample_x,
int oversample_y,
float *sub_x,
float *sub_y,
int glyph);
787STBTT_DEF void stbtt_GetGlyphBitmapBox(
const stbtt_fontinfo *font,
int glyph,
float scale_x,
float scale_y,
int *ix0,
int *iy0,
int *ix1,
int *iy1);
788STBTT_DEF void stbtt_GetGlyphBitmapBoxSubpixel(
const stbtt_fontinfo *font,
int glyph,
float scale_x,
float scale_y,
float shift_x,
float shift_y,
int *ix0,
int *iy0,
int *ix1,
int *iy1);
800 float flatness_in_pixels,
803 float scale_x,
float scale_y,
804 float shift_x,
float shift_y,
805 int x_off,
int y_off,
813STBTT_DEF void stbtt_FreeSDF(
unsigned char *bitmap,
void *userdata);
816STBTT_DEF unsigned char * stbtt_GetGlyphSDF(
const stbtt_fontinfo *info,
float scale,
int glyph,
int padding,
unsigned char onedge_value,
float pixel_dist_scale,
int *width,
int *height,
int *xoff,
int *yoff);
817STBTT_DEF unsigned char * stbtt_GetCodepointSDF(
const stbtt_fontinfo *info,
float scale,
int codepoint,
int padding,
unsigned char onedge_value,
float pixel_dist_scale,
int *width,
int *height,
int *xoff,
int *yoff);
889STBTT_DEF int stbtt_FindMatchingFont(
const unsigned char *fontdata,
const char *name,
int flags);
894#define STBTT_MACSTYLE_DONTCARE 0
895#define STBTT_MACSTYLE_BOLD 1
896#define STBTT_MACSTYLE_ITALIC 2
897#define STBTT_MACSTYLE_UNDERSCORE 4
898#define STBTT_MACSTYLE_NONE 8
900STBTT_DEF int stbtt_CompareUTF8toUTF16_bigendian(
const char *s1,
int len1,
const char *s2,
int len2);
904STBTT_DEF const char *stbtt_GetFontNameString(
const stbtt_fontinfo *font,
int *length,
int platformID,
int encodingID,
int languageID,
int nameID);
974#ifdef STB_TRUETYPE_IMPLEMENTATION
976#ifndef STBTT_MAX_OVERSAMPLE
977#define STBTT_MAX_OVERSAMPLE 8
980#if STBTT_MAX_OVERSAMPLE > 255
981#error "STBTT_MAX_OVERSAMPLE cannot be > 255"
986#ifndef STBTT_RASTERIZER_VERSION
987#define STBTT_RASTERIZER_VERSION 2
991#define STBTT__NOTUSED(v) (void)(v)
993#define STBTT__NOTUSED(v) (void)sizeof(v)
1015static void stbtt__buf_seek(
stbtt__buf *b,
int o)
1021static void stbtt__buf_skip(
stbtt__buf *b,
int o)
1023 stbtt__buf_seek(b, b->
cursor + o);
1031 for (i = 0; i < n; i++)
1032 v = (v << 8) | stbtt__buf_get8(b);
1036static stbtt__buf stbtt__new_buf(
const void *p,
size_t size)
1041 r.
size = (int) size;
1046#define stbtt__buf_get16(b) stbtt__buf_get((b), 2)
1047#define stbtt__buf_get32(b) stbtt__buf_get((b), 4)
1052 if (o < 0 || s < 0 || o > b->
size || s > b->
size - o)
return r;
1060 int count, start, offsize;
1064 offsize = stbtt__buf_get8(b);
1066 stbtt__buf_skip(b, offsize * count);
1067 stbtt__buf_skip(b, stbtt__buf_get(b, offsize) - 1);
1069 return stbtt__buf_range(b, start, b->
cursor - start);
1074 int b0 = stbtt__buf_get8(b);
1075 if (b0 >= 32 && b0 <= 246)
return b0 - 139;
1076 else if (b0 >= 247 && b0 <= 250)
return (b0 - 247)*256 + stbtt__buf_get8(b) + 108;
1077 else if (b0 >= 251 && b0 <= 254)
return -(b0 - 251)*256 - stbtt__buf_get8(b) - 108;
1084static void stbtt__cff_skip_operand(
stbtt__buf *b) {
1085 int v, b0 = stbtt__buf_peek8(b);
1088 stbtt__buf_skip(b, 1);
1090 v = stbtt__buf_get8(b);
1091 if ((v & 0xF) == 0xF || (v >> 4) == 0xF)
1101 stbtt__buf_seek(b, 0);
1103 int start = b->
cursor, end, op;
1104 while (stbtt__buf_peek8(b) >= 28)
1105 stbtt__cff_skip_operand(b);
1107 op = stbtt__buf_get8(b);
1108 if (op == 12) op = stbtt__buf_get8(b) | 0x100;
1109 if (op == key)
return stbtt__buf_range(b, start, end-start);
1111 return stbtt__buf_range(b, 0, 0);
1117 stbtt__buf operands = stbtt__dict_get(b, key);
1118 for (i = 0; i < outcount && operands.
cursor < operands.
size; i++)
1119 out[i] = stbtt__cff_int(&operands);
1122static int stbtt__cff_index_count(
stbtt__buf *b)
1124 stbtt__buf_seek(b, 0);
1130 int count, offsize, start, end;
1131 stbtt__buf_seek(&b, 0);
1133 offsize = stbtt__buf_get8(&b);
1136 stbtt__buf_skip(&b, i*offsize);
1137 start = stbtt__buf_get(&b, offsize);
1138 end = stbtt__buf_get(&b, offsize);
1139 return stbtt__buf_range(&b, 2+(count+1)*offsize+start, end - start);
1150#define ttBYTE(p) (* (stbtt_uint8 *) (p))
1151#define ttCHAR(p) (* (stbtt_int8 *) (p))
1152#define ttFixed(p) ttLONG(p)
1159#define stbtt_tag4(p,c0,c1,c2,c3) ((p)[0] == (c0) && (p)[1] == (c1) && (p)[2] == (c2) && (p)[3] == (c3))
1160#define stbtt_tag(p,str) stbtt_tag4(p,str[0],str[1],str[2],str[3])
1176 stbtt_int32 num_tables = ttUSHORT(data+fontstart+4);
1179 for (i=0; i < num_tables; ++i) {
1182 return ttULONG(data+loc+8);
1187static int stbtt_GetFontOffsetForIndex_internal(
unsigned char *font_collection,
int index)
1190 if (stbtt__isfont(font_collection))
1191 return index == 0 ? 0 : -1;
1194 if (
stbtt_tag(font_collection,
"ttcf")) {
1196 if (ttULONG(font_collection+4) == 0x00010000 || ttULONG(font_collection+4) == 0x00020000) {
1200 return ttULONG(font_collection+12+index*4);
1206static int stbtt_GetNumberOfFonts_internal(
unsigned char *font_collection)
1209 if (stbtt__isfont(font_collection))
1213 if (
stbtt_tag(font_collection,
"ttcf")) {
1215 if (ttULONG(font_collection+4) == 0x00010000 || ttULONG(font_collection+4) == 0x00020000) {
1216 return ttLONG(font_collection+8);
1226 stbtt__dict_get_ints(&fontdict, 18, 2, private_loc);
1227 if (!private_loc[1] || !private_loc[0])
return stbtt__new_buf(NULL, 0);
1228 pdict = stbtt__buf_range(&cff, private_loc[1], private_loc[0]);
1229 stbtt__dict_get_ints(&pdict, 19, 1, &subrsoff);
1230 if (!subrsoff)
return stbtt__new_buf(NULL, 0);
1231 stbtt__buf_seek(&cff, private_loc[1]+subrsoff);
1232 return stbtt__cff_get_index(&cff);
1239 if (info->
svg < 0) {
1243 info->
svg = t + offset;
1251static int stbtt_InitFont_internal(
stbtt_fontinfo *info,
unsigned char *data,
int fontstart)
1258 info->
cff = stbtt__new_buf(NULL, 0);
1260 cmap = stbtt__find_table(data, fontstart,
"cmap");
1261 info->
loca = stbtt__find_table(data, fontstart,
"loca");
1262 info->
head = stbtt__find_table(data, fontstart,
"head");
1263 info->
glyf = stbtt__find_table(data, fontstart,
"glyf");
1264 info->
hhea = stbtt__find_table(data, fontstart,
"hhea");
1265 info->
hmtx = stbtt__find_table(data, fontstart,
"hmtx");
1266 info->
kern = stbtt__find_table(data, fontstart,
"kern");
1267 info->
gpos = stbtt__find_table(data, fontstart,
"GPOS");
1268 info->
gsub = stbtt__find_table(data, fontstart,
"GSUB");
1270 if (!cmap || !info->
head || !info->
hhea || !info->
hmtx)
1274 if (!info->
loca)
return 0;
1278 stbtt_uint32 cstype = 2, charstrings = 0, fdarrayoff = 0, fdselectoff = 0;
1281 cff = stbtt__find_table(data, fontstart,
"CFF ");
1284 info->
fontdicts = stbtt__new_buf(NULL, 0);
1285 info->
fdselect = stbtt__new_buf(NULL, 0);
1288 info->
cff = stbtt__new_buf(data+cff, 512*1024*1024);
1292 stbtt__buf_skip(&b, 2);
1293 stbtt__buf_seek(&b, stbtt__buf_get8(&b));
1297 stbtt__cff_get_index(&b);
1298 topdictidx = stbtt__cff_get_index(&b);
1299 topdict = stbtt__cff_index_get(topdictidx, 0);
1300 stbtt__cff_get_index(&b);
1301 info->
gsubrs = stbtt__cff_get_index(&b);
1303 stbtt__dict_get_ints(&topdict, 17, 1, &charstrings);
1304 stbtt__dict_get_ints(&topdict, 0x100 | 6, 1, &cstype);
1305 stbtt__dict_get_ints(&topdict, 0x100 | 36, 1, &fdarrayoff);
1306 stbtt__dict_get_ints(&topdict, 0x100 | 37, 1, &fdselectoff);
1307 info->
subrs = stbtt__get_subrs(b, topdict);
1310 if (cstype != 2)
return 0;
1311 if (charstrings == 0)
return 0;
1315 if (!fdselectoff)
return 0;
1316 stbtt__buf_seek(&b, fdarrayoff);
1317 info->
fontdicts = stbtt__cff_get_index(&b);
1318 info->
fdselect = stbtt__buf_range(&b, fdselectoff, b.
size-fdselectoff);
1321 stbtt__buf_seek(&b, charstrings);
1325 t = stbtt__find_table(data, fontstart,
"maxp");
1336 numTables = ttUSHORT(data + cmap + 2);
1338 for (i=0; i < numTables; ++i) {
1341 switch(ttUSHORT(data+encoding_record)) {
1343 switch (ttUSHORT(data+encoding_record+2)) {
1347 info->
index_map = cmap + ttULONG(data+encoding_record+4);
1354 info->
index_map = cmap + ttULONG(data+encoding_record+4);
1372 stbtt_int32 bytes = ttUSHORT(data + index_map + 2);
1373 if (unicode_codepoint < bytes-6)
1374 return ttBYTE(data + index_map + 6 + unicode_codepoint);
1376 }
else if (format == 6) {
1380 return ttUSHORT(data + index_map + 10 + (unicode_codepoint - first)*2);
1382 }
else if (format == 2) {
1385 }
else if (format == 4) {
1386 stbtt_uint16 segcount = ttUSHORT(data+index_map+6) >> 1;
1387 stbtt_uint16 searchRange = ttUSHORT(data+index_map+8) >> 1;
1388 stbtt_uint16 entrySelector = ttUSHORT(data+index_map+10);
1389 stbtt_uint16 rangeShift = ttUSHORT(data+index_map+12) >> 1;
1395 if (unicode_codepoint > 0xffff)
1400 if (unicode_codepoint >= ttUSHORT(data + search + rangeShift*2))
1401 search += rangeShift*2;
1405 while (entrySelector) {
1408 end = ttUSHORT(data + search + searchRange*2);
1409 if (unicode_codepoint > end)
1410 search += searchRange*2;
1419 start = ttUSHORT(data + index_map + 14 + segcount*2 + 2 + 2*item);
1420 last = ttUSHORT(data + endCount + 2*item);
1421 if (unicode_codepoint < start || unicode_codepoint > last)
1424 offset = ttUSHORT(data + index_map + 14 + segcount*6 + 2 + 2*item);
1426 return (
stbtt_uint16) (unicode_codepoint + ttSHORT(data + index_map + 14 + segcount*4 + 2 + 2*item));
1428 return ttUSHORT(data + offset + (unicode_codepoint-start)*2 + index_map + 14 + segcount*6 + 2 + 2*item);
1430 }
else if (format == 12 || format == 13) {
1435 while (low < high) {
1437 stbtt_uint32 start_char = ttULONG(data+index_map+16+mid*12);
1438 stbtt_uint32 end_char = ttULONG(data+index_map+16+mid*12+4);
1444 stbtt_uint32 start_glyph = ttULONG(data+index_map+16+mid*12+8);
1446 return start_glyph + unicode_codepoint-start_char;
1460 return stbtt_GetGlyphShape(info, stbtt_FindGlyphIndex(info, unicode_codepoint), vertices);
1472static int stbtt__GetGlyfOffset(
const stbtt_fontinfo *info,
int glyph_index)
1478 if (glyph_index >= info->
numGlyphs)
return -1;
1482 g1 = info->
glyf + ttUSHORT(info->
data + info->
loca + glyph_index * 2) * 2;
1483 g2 = info->
glyf + ttUSHORT(info->
data + info->
loca + glyph_index * 2 + 2) * 2;
1485 g1 = info->
glyf + ttULONG (info->
data + info->
loca + glyph_index * 4);
1486 g2 = info->
glyf + ttULONG (info->
data + info->
loca + glyph_index * 4 + 4);
1489 return g1==g2 ? -1 : g1;
1492static int stbtt__GetGlyphInfoT2(
const stbtt_fontinfo *info,
int glyph_index,
int *x0,
int *y0,
int *x1,
int *y1);
1494STBTT_DEF int stbtt_GetGlyphBox(
const stbtt_fontinfo *info,
int glyph_index,
int *x0,
int *y0,
int *x1,
int *y1)
1497 stbtt__GetGlyphInfoT2(info, glyph_index, x0, y0, x1, y1);
1499 int g = stbtt__GetGlyfOffset(info, glyph_index);
1500 if (g < 0)
return 0;
1502 if (x0) *x0 = ttSHORT(info->
data + g + 2);
1503 if (y0) *y0 = ttSHORT(info->
data + g + 4);
1504 if (x1) *x1 = ttSHORT(info->
data + g + 6);
1505 if (y1) *y1 = ttSHORT(info->
data + g + 8);
1510STBTT_DEF int stbtt_GetCodepointBox(
const stbtt_fontinfo *info,
int codepoint,
int *x0,
int *y0,
int *x1,
int *y1)
1512 return stbtt_GetGlyphBox(info, stbtt_FindGlyphIndex(info,codepoint), x0,y0,x1,y1);
1520 return stbtt__GetGlyphInfoT2(info, glyph_index, NULL, NULL, NULL, NULL) == 0;
1521 g = stbtt__GetGlyfOffset(info, glyph_index);
1522 if (g < 0)
return 1;
1523 numberOfContours = ttSHORT(info->
data + g);
1524 return numberOfContours == 0;
1527static int stbtt__close_shape(
stbtt_vertex *vertices,
int num_vertices,
int was_off,
int start_off,
1532 stbtt_setvertex(&vertices[num_vertices++],
STBTT_vcurve, (cx+scx)>>1, (cy+scy)>>1, cx,cy);
1533 stbtt_setvertex(&vertices[num_vertices++],
STBTT_vcurve, sx,sy,scx,scy);
1536 stbtt_setvertex(&vertices[num_vertices++],
STBTT_vcurve,sx,sy,cx,cy);
1538 stbtt_setvertex(&vertices[num_vertices++],
STBTT_vline,sx,sy,0,0);
1540 return num_vertices;
1550 int g = stbtt__GetGlyfOffset(info, glyph_index);
1554 if (g < 0)
return 0;
1556 numberOfContours = ttSHORT(data + g);
1558 if (numberOfContours > 0) {
1560 stbtt_int32 ins, i,j=0,m,n, next_move, was_off=0, off, start_off=0;
1563 endPtsOfContours = (data + g + 10);
1564 ins = ttUSHORT(data + g + 10 + numberOfContours * 2);
1565 points = data + g + 10 + numberOfContours * 2 + 2 + ins;
1567 n = 1+ttUSHORT(endPtsOfContours + numberOfContours*2-2);
1569 m = n + 2*numberOfContours;
1585 for (i=0; i < n; ++i) {
1586 if (flagcount == 0) {
1589 flagcount = *points++;
1592 vertices[off+i].
type = flags;
1597 for (i=0; i < n; ++i) {
1598 flags = vertices[off+i].
type;
1601 x += (flags & 16) ? dx : -dx;
1603 if (!(flags & 16)) {
1604 x = x + (
stbtt_int16) (points[0]*256 + points[1]);
1613 for (i=0; i < n; ++i) {
1614 flags = vertices[off+i].
type;
1617 y += (flags & 32) ? dy : -dy;
1619 if (!(flags & 32)) {
1620 y = y + (
stbtt_int16) (points[0]*256 + points[1]);
1629 sx = sy = cx = cy = scx = scy = 0;
1630 for (i=0; i < n; ++i) {
1631 flags = vertices[off+i].
type;
1635 if (next_move == i) {
1637 num_vertices = stbtt__close_shape(vertices, num_vertices, was_off, start_off, sx,sy,scx,scy,cx,cy);
1640 start_off = !(flags & 1);
1646 if (!(vertices[off+i+1].type & 1)) {
1648 sx = (x + (
stbtt_int32) vertices[off+i+1].x) >> 1;
1649 sy = (y + (
stbtt_int32) vertices[off+i+1].y) >> 1;
1660 stbtt_setvertex(&vertices[num_vertices++],
STBTT_vmove,sx,sy,0,0);
1662 next_move = 1 + ttUSHORT(endPtsOfContours+j*2);
1667 stbtt_setvertex(&vertices[num_vertices++],
STBTT_vcurve, (cx+x)>>1, (cy+y)>>1, cx, cy);
1673 stbtt_setvertex(&vertices[num_vertices++],
STBTT_vcurve, x,y, cx, cy);
1675 stbtt_setvertex(&vertices[num_vertices++],
STBTT_vline, x,y,0,0);
1680 num_vertices = stbtt__close_shape(vertices, num_vertices, was_off, start_off, sx,sy,scx,scy,cx,cy);
1681 }
else if (numberOfContours < 0) {
1689 int comp_num_verts = 0, i;
1691 float mtx[6] = {1,0,0,1,0,0}, m, n;
1693 flags = ttSHORT(comp); comp+=2;
1694 gidx = ttSHORT(comp); comp+=2;
1698 mtx[4] = ttSHORT(comp); comp+=2;
1699 mtx[5] = ttSHORT(comp); comp+=2;
1701 mtx[4] =
ttCHAR(comp); comp+=1;
1702 mtx[5] =
ttCHAR(comp); comp+=1;
1709 if (flags & (1<<3)) {
1710 mtx[0] = mtx[3] = ttSHORT(comp)/16384.0f; comp+=2;
1711 mtx[1] = mtx[2] = 0;
1712 }
else if (flags & (1<<6)) {
1713 mtx[0] = ttSHORT(comp)/16384.0f; comp+=2;
1714 mtx[1] = mtx[2] = 0;
1715 mtx[3] = ttSHORT(comp)/16384.0f; comp+=2;
1716 }
else if (flags & (1<<7)) {
1717 mtx[0] = ttSHORT(comp)/16384.0f; comp+=2;
1718 mtx[1] = ttSHORT(comp)/16384.0f; comp+=2;
1719 mtx[2] = ttSHORT(comp)/16384.0f; comp+=2;
1720 mtx[3] = ttSHORT(comp)/16384.0f; comp+=2;
1724 m = (float)
STBTT_sqrt(mtx[0]*mtx[0] + mtx[1]*mtx[1]);
1725 n = (float)
STBTT_sqrt(mtx[2]*mtx[2] + mtx[3]*mtx[3]);
1728 comp_num_verts = stbtt_GetGlyphShape(info, gidx, &comp_verts);
1729 if (comp_num_verts > 0) {
1731 for (i = 0; i < comp_num_verts; ++i) {
1753 num_vertices += comp_num_verts;
1756 more = flags & (1<<5);
1762 *pvertices = vertices;
1763 return num_vertices;
1778#define STBTT__CSCTX_INIT(bounds) {bounds,0, 0,0, 0,0, 0,0,0,0, NULL, 0}
1792 stbtt__track_vertex(c, x, y);
1794 stbtt__track_vertex(c, cx, cy);
1795 stbtt__track_vertex(c, cx1, cy1);
1811static void stbtt__csctx_rmove_to(
stbtt__csctx *ctx,
float dx,
float dy)
1813 stbtt__csctx_close_shape(ctx);
1816 stbtt__csctx_v(ctx,
STBTT_vmove, (
int)ctx->
x, (
int)ctx->
y, 0, 0, 0, 0);
1819static void stbtt__csctx_rline_to(
stbtt__csctx *ctx,
float dx,
float dy)
1823 stbtt__csctx_v(ctx,
STBTT_vline, (
int)ctx->
x, (
int)ctx->
y, 0, 0, 0, 0);
1826static void stbtt__csctx_rccurve_to(
stbtt__csctx *ctx,
float dx1,
float dy1,
float dx2,
float dy2,
float dx3,
float dy3)
1828 float cx1 = ctx->
x + dx1;
1829 float cy1 = ctx->
y + dy1;
1830 float cx2 = cx1 + dx2;
1831 float cy2 = cy1 + dy2;
1834 stbtt__csctx_v(ctx,
STBTT_vcubic, (
int)ctx->
x, (
int)ctx->
y, (
int)cx1, (
int)cy1, (
int)cx2, (
int)cy2);
1839 int count = stbtt__cff_index_count(&idx);
1843 else if (count >= 1240)
1846 if (n < 0 || n >= count)
1847 return stbtt__new_buf(NULL, 0);
1848 return stbtt__cff_index_get(idx, n);
1854 int nranges, start, end, v, fmt, fdselector = -1, i;
1856 stbtt__buf_seek(&fdselect, 0);
1857 fmt = stbtt__buf_get8(&fdselect);
1860 stbtt__buf_skip(&fdselect, glyph_index);
1861 fdselector = stbtt__buf_get8(&fdselect);
1862 }
else if (fmt == 3) {
1865 for (i = 0; i < nranges; i++) {
1866 v = stbtt__buf_get8(&fdselect);
1868 if (glyph_index >= start && glyph_index < end) {
1875 if (fdselector == -1) stbtt__new_buf(NULL, 0);
1876 return stbtt__get_subrs(info->
cff, stbtt__cff_index_get(info->
fontdicts, fdselector));
1881 int in_header = 1, maskbits = 0, subr_stack_height = 0, sp = 0, v, i, b0;
1882 int has_subrs = 0, clear_stack;
1887#define STBTT__CSERR(s) (0)
1890 b = stbtt__cff_index_get(info->
charstrings, glyph_index);
1894 b0 = stbtt__buf_get8(&b);
1900 maskbits += (sp / 2);
1902 stbtt__buf_skip(&b, (maskbits + 7) / 8);
1909 maskbits += (sp / 2);
1915 stbtt__csctx_rmove_to(c, s[sp-2], s[sp-1]);
1920 stbtt__csctx_rmove_to(c, 0, s[sp-1]);
1925 stbtt__csctx_rmove_to(c, s[sp-1], 0);
1930 for (; i + 1 < sp; i += 2)
1931 stbtt__csctx_rline_to(c, s[i], s[i+1]);
1944 stbtt__csctx_rline_to(c, s[i], 0);
1948 stbtt__csctx_rline_to(c, 0, s[i]);
1959 if (i + 3 >= sp)
break;
1960 stbtt__csctx_rccurve_to(c, 0, s[i], s[i+1], s[i+2], s[i+3], (sp - i == 5) ? s[i + 4] : 0.0f);
1963 if (i + 3 >= sp)
break;
1964 stbtt__csctx_rccurve_to(c, s[i], 0, s[i+1], s[i+2], (sp - i == 5) ? s[i+4] : 0.0f, s[i+3]);
1971 for (; i + 5 < sp; i += 6)
1972 stbtt__csctx_rccurve_to(c, s[i], s[i+1], s[i+2], s[i+3], s[i+4], s[i+5]);
1977 for (; i + 5 < sp - 2; i += 6)
1978 stbtt__csctx_rccurve_to(c, s[i], s[i+1], s[i+2], s[i+3], s[i+4], s[i+5]);
1979 if (i + 1 >= sp)
return STBTT__CSERR(
"rcurveline stack");
1980 stbtt__csctx_rline_to(c, s[i], s[i+1]);
1985 for (; i + 1 < sp - 6; i += 2)
1986 stbtt__csctx_rline_to(c, s[i], s[i+1]);
1987 if (i + 5 >= sp)
return STBTT__CSERR(
"rlinecurve stack");
1988 stbtt__csctx_rccurve_to(c, s[i], s[i+1], s[i+2], s[i+3], s[i+4], s[i+5]);
1993 if (sp < 4)
return STBTT__CSERR(
"(vv|hh)curveto stack");
1995 if (sp & 1) { f = s[i]; i++; }
1996 for (; i + 3 < sp; i += 4) {
1998 stbtt__csctx_rccurve_to(c, s[i], f, s[i+1], s[i+2], s[i+3], 0.0);
2000 stbtt__csctx_rccurve_to(c, f, s[i], s[i+1], s[i+2], 0.0, s[i+3]);
2008 subrs = stbtt__cid_get_glyph_subrs(info, glyph_index);
2015 if (subr_stack_height >= 10)
return STBTT__CSERR(
"recursion limit");
2016 subr_stack[subr_stack_height++] = b;
2017 b = stbtt__get_subr(b0 == 0x0A ? subrs : info->gsubrs, v);
2024 if (subr_stack_height <= 0)
return STBTT__CSERR(
"return outside subr");
2025 b = subr_stack[--subr_stack_height];
2030 stbtt__csctx_close_shape(c);
2034 float dx1, dx2, dx3, dx4, dx5, dx6, dy1, dy2, dy3, dy4, dy5, dy6;
2036 int b1 = stbtt__buf_get8(&b);
2049 stbtt__csctx_rccurve_to(c, dx1, 0, dx2, dy2, dx3, 0);
2050 stbtt__csctx_rccurve_to(c, dx4, 0, dx5, -dy2, dx6, 0);
2068 stbtt__csctx_rccurve_to(c, dx1, dy1, dx2, dy2, dx3, dy3);
2069 stbtt__csctx_rccurve_to(c, dx4, dy4, dx5, dy5, dx6, dy6);
2083 stbtt__csctx_rccurve_to(c, dx1, dy1, dx2, dy2, dx3, 0);
2084 stbtt__csctx_rccurve_to(c, dx4, 0, dx5, dy5, dx6, -(dy1+dy2+dy5));
2100 dx = dx1+dx2+dx3+dx4+dx5;
2101 dy = dy1+dy2+dy3+dy4+dy5;
2106 stbtt__csctx_rccurve_to(c, dx1, dy1, dx2, dy2, dx3, dy3);
2107 stbtt__csctx_rccurve_to(c, dx4, dy4, dx5, dy5, dx6, dy6);
2116 if (b0 != 255 && b0 != 28 && b0 < 32)
2123 stbtt__buf_skip(&b, -1);
2126 if (sp >= 48)
return STBTT__CSERR(
"push stack overflow");
2131 if (clear_stack) sp = 0;
2143 if (stbtt__run_charstring(info, glyph_index, &count_ctx)) {
2146 if (stbtt__run_charstring(info, glyph_index, &output_ctx)) {
2155static int stbtt__GetGlyphInfoT2(
const stbtt_fontinfo *info,
int glyph_index,
int *x0,
int *y0,
int *x1,
int *y1)
2158 int r = stbtt__run_charstring(info, glyph_index, &c);
2159 if (x0) *x0 = r ? c.
min_x : 0;
2160 if (y0) *y0 = r ? c.
min_y : 0;
2161 if (x1) *x1 = r ? c.
max_x : 0;
2162 if (y1) *y1 = r ? c.
max_y : 0;
2169 return stbtt__GetGlyphShapeTT(info, glyph_index, pvertices);
2171 return stbtt__GetGlyphShapeT2(info, glyph_index, pvertices);
2174STBTT_DEF void stbtt_GetGlyphHMetrics(
const stbtt_fontinfo *info,
int glyph_index,
int *advanceWidth,
int *leftSideBearing)
2177 if (glyph_index < numOfLongHorMetrics) {
2178 if (advanceWidth) *advanceWidth = ttSHORT(info->
data + info->
hmtx + 4*glyph_index);
2179 if (leftSideBearing) *leftSideBearing = ttSHORT(info->
data + info->
hmtx + 4*glyph_index + 2);
2181 if (advanceWidth) *advanceWidth = ttSHORT(info->
data + info->
hmtx + 4*(numOfLongHorMetrics-1));
2182 if (leftSideBearing) *leftSideBearing = ttSHORT(info->
data + info->
hmtx + 4*numOfLongHorMetrics + 2*(glyph_index - numOfLongHorMetrics));
2193 if (ttUSHORT(data+2) < 1)
2195 if (ttUSHORT(data+8) != 1)
2198 return ttUSHORT(data+10);
2209 if (ttUSHORT(data+2) < 1)
2211 if (ttUSHORT(data+8) != 1)
2214 length = ttUSHORT(data+10);
2215 if (table_length < length)
2216 length = table_length;
2218 for (k = 0; k < length; k++)
2220 table[k].
glyph1 = ttUSHORT(data+18+(k*6));
2221 table[k].
glyph2 = ttUSHORT(data+20+(k*6));
2222 table[k].
advance = ttSHORT(data+22+(k*6));
2228static int stbtt__GetGlyphKernInfoAdvance(
const stbtt_fontinfo *info,
int glyph1,
int glyph2)
2237 if (ttUSHORT(data+2) < 1)
2239 if (ttUSHORT(data+8) != 1)
2243 r = ttUSHORT(data+10) - 1;
2244 needle = glyph1 << 16 | glyph2;
2247 straw = ttULONG(data+18+(m*6));
2250 else if (needle > straw)
2253 return ttSHORT(data+22+(m*6));
2261 switch (coverageFormat) {
2267 int straw, needle=glyph;
2272 glyphID = ttUSHORT(glyphArray + 2 * m);
2276 else if (needle > straw)
2291 int strawStart, strawEnd, needle=glyph;
2295 rangeRecord = rangeArray + 6 * m;
2296 strawStart = ttUSHORT(rangeRecord);
2297 strawEnd = ttUSHORT(rangeRecord + 2);
2298 if (needle < strawStart)
2300 else if (needle > strawEnd)
2303 stbtt_uint16 startCoverageIndex = ttUSHORT(rangeRecord + 4);
2304 return startCoverageIndex + glyph - strawStart;
2318static int stbtt__GetGsubLigature(
const stbtt_fontinfo *info,
int first,
const int *rest,
int nrest)
2320 if (!info->
gsub)
return 0;
2322 stbtt_uint8 *featureList = gsub + ttUSHORT(gsub + 6);
2323 stbtt_uint8 *lookupList = gsub + ttUSHORT(gsub + 8);
2324 int featureCount = ttUSHORT(featureList);
2325 int lookupCount = ttUSHORT(lookupList);
2327 for (f = 0; f < featureCount; ++f) {
2329 int isLiga = (rec[0]==
'l' && rec[1]==
'i' && rec[2]==
'g' && rec[3]==
'a');
2330 int isClig = (rec[0]==
'c' && rec[1]==
'l' && rec[2]==
'i' && rec[3]==
'g');
2331 if (!isLiga && !isClig)
continue;
2332 stbtt_uint8 *feature = featureList + ttUSHORT(rec + 4);
2333 int nLookups = ttUSHORT(feature + 2);
2334 for (l = 0; l < nLookups; ++l) {
2335 int li = ttUSHORT(feature + 4 + 2 * l);
2336 if (li >= lookupCount)
continue;
2337 stbtt_uint8 *lookup = lookupList + ttUSHORT(lookupList + 2 + 2 * li);
2338 int type = ttUSHORT(lookup);
2339 int nsub = ttUSHORT(lookup + 4);
2340 for (s = 0; s < nsub; ++s) {
2341 stbtt_uint8 *sub = lookup + ttUSHORT(lookup + 6 + 2 * s);
2344 if (ttUSHORT(sub) != 1)
continue;
2345 st = ttUSHORT(sub + 2);
2346 sub = sub + ttULONG(sub + 4);
2348 if (st != 4 || ttUSHORT(sub) != 1)
continue;
2349 int cov = stbtt__GetCoverageIndex(sub + ttUSHORT(sub + 2), first);
2350 if (cov < 0 || cov >= ttUSHORT(sub + 4))
continue;
2351 stbtt_uint8 *ligSet = sub + ttUSHORT(sub + 6 + 2 * cov);
2352 int ligCount = ttUSHORT(ligSet);
2353 for (k = 0; k < ligCount; ++k) {
2354 stbtt_uint8 *lig = ligSet + ttUSHORT(ligSet + 2 + 2 * k);
2355 int ligGlyph = ttUSHORT(lig);
2356 int compCount = ttUSHORT(lig + 2);
2357 if (compCount - 1 != nrest)
continue;
2358 for (i = 0; i < nrest; ++i)
2359 if (ttUSHORT(lig + 4 + 2 * i) != rest[i])
break;
2360 if (i == nrest)
return ligGlyph;
2371 switch (classDefFormat)
2374 stbtt_uint16 startGlyphID = ttUSHORT(classDefTable + 2);
2376 stbtt_uint8 *classDef1ValueArray = classDefTable + 6;
2378 if (glyph >= startGlyphID && glyph < startGlyphID + glyphCount)
2379 return (
stbtt_int32)ttUSHORT(classDef1ValueArray + 2 * (glyph - startGlyphID));
2384 stbtt_uint16 classRangeCount = ttUSHORT(classDefTable + 2);
2385 stbtt_uint8 *classRangeRecords = classDefTable + 4;
2389 int strawStart, strawEnd, needle=glyph;
2393 classRangeRecord = classRangeRecords + 6 * m;
2394 strawStart = ttUSHORT(classRangeRecord);
2395 strawEnd = ttUSHORT(classRangeRecord + 2);
2396 if (needle < strawStart)
2398 else if (needle > strawEnd)
2401 return (
stbtt_int32)ttUSHORT(classRangeRecord + 4);
2415#define STBTT_GPOS_TODO_assert(x)
2425 if (!info->
gpos)
return 0;
2429 if (ttUSHORT(data+0) != 1)
return 0;
2430 if (ttUSHORT(data+2) != 0)
return 0;
2432 lookupListOffset = ttUSHORT(data+8);
2433 lookupList = data + lookupListOffset;
2434 lookupCount = ttUSHORT(lookupList);
2436 for (i=0; i<lookupCount; ++i) {
2437 stbtt_uint16 lookupOffset = ttUSHORT(lookupList + 2 + 2 * i);
2438 stbtt_uint8 *lookupTable = lookupList + lookupOffset;
2441 stbtt_uint16 subTableCount = ttUSHORT(lookupTable + 4);
2443 if (lookupType != 2)
2446 for (sti=0; sti<subTableCount; sti++) {
2447 stbtt_uint16 subtableOffset = ttUSHORT(subTableOffsets + 2 * sti);
2448 stbtt_uint8 *table = lookupTable + subtableOffset;
2451 stbtt_int32 coverageIndex = stbtt__GetCoverageIndex(table + coverageOffset, glyph1);
2452 if (coverageIndex == -1)
continue;
2454 switch (posFormat) {
2460 if (valueFormat1 == 4 && valueFormat2 == 0) {
2463 stbtt_uint16 pairPosOffset = ttUSHORT(table + 10 + 2 * coverageIndex);
2464 stbtt_uint8 *pairValueTable = table + pairPosOffset;
2465 stbtt_uint16 pairValueCount = ttUSHORT(pairValueTable);
2468 if (coverageIndex >= pairSetCount)
return 0;
2479 pairValue = pairValueArray + (2 + valueRecordPairSizeInBytes) * m;
2480 secondGlyph = ttUSHORT(pairValue);
2481 straw = secondGlyph;
2484 else if (needle > straw)
2499 if (valueFormat1 == 4 && valueFormat2 == 0) {
2502 int glyph1class = stbtt__GetGlyphClass(table + classDef1Offset, glyph1);
2503 int glyph2class = stbtt__GetGlyphClass(table + classDef2Offset, glyph2);
2510 if (glyph1class < 0 || glyph1class >= class1Count)
return 0;
2511 if (glyph2class < 0 || glyph2class >= class2Count)
return 0;
2513 class1Records = table + 16;
2514 class2Records = class1Records + 2 * (glyph1class * class2Count);
2515 xAdvance = ttSHORT(class2Records + 2 * glyph2class);
2536 xAdvance += stbtt__GetGlyphGPOSInfoAdvance(info, g1, g2);
2537 else if (info->
kern)
2538 xAdvance += stbtt__GetGlyphKernInfoAdvance(info, g1, g2);
2547 return stbtt_GetGlyphKernAdvance(info, stbtt_FindGlyphIndex(info,ch1), stbtt_FindGlyphIndex(info,ch2));
2550STBTT_DEF void stbtt_GetCodepointHMetrics(
const stbtt_fontinfo *info,
int codepoint,
int *advanceWidth,
int *leftSideBearing)
2552 stbtt_GetGlyphHMetrics(info, stbtt_FindGlyphIndex(info,codepoint), advanceWidth, leftSideBearing);
2557 if (ascent ) *ascent = ttSHORT(info->
data+info->
hhea + 4);
2558 if (descent) *descent = ttSHORT(info->
data+info->
hhea + 6);
2559 if (lineGap) *lineGap = ttSHORT(info->
data+info->
hhea + 8);
2562STBTT_DEF int stbtt_GetFontVMetricsOS2(
const stbtt_fontinfo *info,
int *typoAscent,
int *typoDescent,
int *typoLineGap)
2564 int tab = stbtt__find_table(info->
data, info->
fontstart,
"OS/2");
2567 if (typoAscent ) *typoAscent = ttSHORT(info->
data+tab + 68);
2568 if (typoDescent) *typoDescent = ttSHORT(info->
data+tab + 70);
2569 if (typoLineGap) *typoLineGap = ttSHORT(info->
data+tab + 72);
2575 *x0 = ttSHORT(info->
data + info->
head + 36);
2576 *y0 = ttSHORT(info->
data + info->
head + 38);
2577 *x1 = ttSHORT(info->
data + info->
head + 40);
2578 *y1 = ttSHORT(info->
data + info->
head + 42);
2583 int fheight = ttSHORT(info->
data + info->
hhea + 4) - ttSHORT(info->
data + info->
hhea + 6);
2584 return (
float) height / fheight;
2589 int unitsPerEm = ttUSHORT(info->
data + info->
head + 18);
2590 return pixels / unitsPerEm;
2604 int numEntries = ttUSHORT(svg_doc_list);
2607 for(i=0; i<numEntries; i++) {
2609 if ((gl >= ttUSHORT(svg_doc)) && (gl <= ttUSHORT(svg_doc + 2)))
2623 svg_doc = stbtt_FindSVGDoc(info, gl);
2624 if (svg_doc != NULL) {
2625 *svg = (
char *) data + info->
svg + ttULONG(svg_doc + 4);
2626 return ttULONG(svg_doc + 8);
2634 return stbtt_GetGlyphSVG(info, stbtt_FindGlyphIndex(info, unicode_codepoint), svg);
2642STBTT_DEF void stbtt_GetGlyphBitmapBoxSubpixel(
const stbtt_fontinfo *font,
int glyph,
float scale_x,
float scale_y,
float shift_x,
float shift_y,
int *ix0,
int *iy0,
int *ix1,
int *iy1)
2644 int x0=0,y0=0,x1,y1;
2645 if (!stbtt_GetGlyphBox(font, glyph, &x0,&y0,&x1,&y1)) {
2655 if (ix1) *ix1 =
STBTT_iceil ( x1 * scale_x + shift_x);
2656 if (iy1) *iy1 =
STBTT_iceil (-y0 * scale_y + shift_y);
2660STBTT_DEF void stbtt_GetGlyphBitmapBox(
const stbtt_fontinfo *font,
int glyph,
float scale_x,
float scale_y,
int *ix0,
int *iy0,
int *ix1,
int *iy1)
2662 stbtt_GetGlyphBitmapBoxSubpixel(font, glyph, scale_x, scale_y,0.0f,0.0f, ix0, iy0, ix1, iy1);
2665STBTT_DEF void stbtt_GetCodepointBitmapBoxSubpixel(
const stbtt_fontinfo *font,
int codepoint,
float scale_x,
float scale_y,
float shift_x,
float shift_y,
int *ix0,
int *iy0,
int *ix1,
int *iy1)
2667 stbtt_GetGlyphBitmapBoxSubpixel(font, stbtt_FindGlyphIndex(font,codepoint), scale_x, scale_y,shift_x,shift_y, ix0,iy0,ix1,iy1);
2670STBTT_DEF void stbtt_GetCodepointBitmapBox(
const stbtt_fontinfo *font,
int codepoint,
float scale_x,
float scale_y,
int *ix0,
int *iy0,
int *ix1,
int *iy1)
2672 stbtt_GetCodepointBitmapBoxSubpixel(font, codepoint, scale_x, scale_y,0.0f,0.0f, ix0,iy0,ix1,iy1);
2691static void *stbtt__hheap_alloc(
stbtt__hheap *hh,
size_t size,
void *userdata)
2699 int count = (size < 32 ? 2000 : size < 128 ? 800 : 100);
2712static void stbtt__hheap_free(
stbtt__hheap *hh,
void *p)
2718static void stbtt__hheap_cleanup(
stbtt__hheap *hh,
void *userdata)
2737 #if STBTT_RASTERIZER_VERSION==1
2741 #elif STBTT_RASTERIZER_VERSION==2
2747 #error "Unrecognized value of STBTT_RASTERIZER_VERSION"
2751#if STBTT_RASTERIZER_VERSION == 1
2752#define STBTT_FIXSHIFT 10
2753#define STBTT_FIX (1 << STBTT_FIXSHIFT)
2754#define STBTT_FIXMASK (STBTT_FIX-1)
2759 float dxdy = (e->
x1 - e->
x0) / (e->
y1 - e->
y0);
2770 z->x -= off_x * STBTT_FIX;
2777#elif STBTT_RASTERIZER_VERSION == 2
2781 float dxdy = (e->
x1 - e->
x0) / (e->
y1 - e->
y0);
2786 z->
fdy = dxdy != 0.0f ? (1.0f/dxdy) : 0.0f;
2787 z->
fx = e->
x0 + dxdy * (start_point - e->
y0);
2796#error "Unrecognized value of STBTT_RASTERIZER_VERSION"
2799#if STBTT_RASTERIZER_VERSION == 1
2803static void stbtt__fill_active_edges(
unsigned char *scanline,
int len,
stbtt__active_edge *e,
int max_weight)
2816 int i = x0 >> STBTT_FIXSHIFT;
2817 int j = x1 >> STBTT_FIXSHIFT;
2819 if (i < len && j >= 0) {
2822 scanline[i] = scanline[i] + (
stbtt_uint8) ((x1 - x0) * max_weight >> STBTT_FIXSHIFT);
2825 scanline[i] = scanline[i] + (
stbtt_uint8) (((STBTT_FIX - (x0 & STBTT_FIXMASK)) * max_weight) >> STBTT_FIXSHIFT);
2830 scanline[j] = scanline[j] + (
stbtt_uint8) (((x1 & STBTT_FIXMASK) * max_weight) >> STBTT_FIXSHIFT);
2834 for (++i; i < j; ++i)
2835 scanline[i] = scanline[i] + (
stbtt_uint8) max_weight;
2845static void stbtt__rasterize_sorted_edges(
stbtt__bitmap *result,
stbtt__edge *e,
int n,
int vsubsample,
int off_x,
int off_y,
void *userdata)
2850 int max_weight = (255 / vsubsample);
2852 unsigned char scanline_data[512], *scanline;
2854 if (result->
w > 512)
2855 scanline = (
unsigned char *)
STBTT_malloc(result->
w, userdata);
2857 scanline = scanline_data;
2859 y = off_y * vsubsample;
2860 e[n].
y0 = (off_y + result->
h) * (
float) vsubsample + 1;
2862 while (j < result->h) {
2864 for (s=0; s < vsubsample; ++s) {
2866 float scan_y = y + 0.5f;
2873 if (z->
ey <= scan_y) {
2877 stbtt__hheap_free(&hh, z);
2880 step = &((*step)->next);
2888 while (*step && (*step)->next) {
2889 if ((*step)->x > (*step)->next->x) {
2898 step = &(*step)->
next;
2900 if (!changed)
break;
2904 while (e->
y0 <= scan_y) {
2905 if (e->
y1 > scan_y) {
2911 else if (z->x < active->x) {
2918 while (p->
next && p->
next->x < z->x)
2931 stbtt__fill_active_edges(scanline, result->
w, active, max_weight);
2939 stbtt__hheap_cleanup(&hh, userdata);
2941 if (scanline != scanline_data)
2945#elif STBTT_RASTERIZER_VERSION == 2
2949static void stbtt__handle_clipped_edge(
float *scanline,
int x,
stbtt__active_edge *e,
float x0,
float y0,
float x1,
float y1)
2951 if (y0 == y1)
return;
2954 if (y0 > e->
ey)
return;
2955 if (y1 < e->
sy)
return;
2957 x0 += (x1-x0) * (e->
sy - y0) / (y1-y0);
2961 x1 += (x1-x0) * (e->
ey - y1) / (y1-y0);
2976 if (x0 <= x && x1 <= x)
2978 else if (x0 >= x+1 && x1 >= x+1)
2981 STBTT_assert(x0 >= x && x0 <= x+1 && x1 >= x && x1 <= x+1);
2982 scanline[x] += e->
direction * (y1-y0) * (1-((x0-x)+(x1-x))/2);
2986static float stbtt__sized_trapezoid_area(
float height,
float top_width,
float bottom_width)
2990 return (top_width + bottom_width) / 2.0f * height;
2993static float stbtt__position_trapezoid_area(
float height,
float tx0,
float tx1,
float bx0,
float bx1)
2995 return stbtt__sized_trapezoid_area(height, tx1 - tx0, bx1 - bx0);
2998static float stbtt__sized_triangle_area(
float height,
float width)
3000 return height * width / 2;
3003static void stbtt__fill_active_edges_new(
float *scanline,
float *scanline_fill,
int len,
stbtt__active_edge *e,
float y_top)
3005 float y_bottom = y_top+1;
3017 stbtt__handle_clipped_edge(scanline,(
int) x0,e, x0,y_top, x0,y_bottom);
3018 stbtt__handle_clipped_edge(scanline_fill-1,(
int) x0+1,e, x0,y_top, x0,y_bottom);
3020 stbtt__handle_clipped_edge(scanline_fill-1,0,e, x0,y_top, x0,y_bottom);
3027 float x_top, x_bottom;
3035 if (e->
sy > y_top) {
3036 x_top = x0 + dx * (e->
sy - y_top);
3042 if (e->
ey < y_bottom) {
3043 x_bottom = x0 + dx * (e->
ey - y_top);
3050 if (x_top >= 0 && x_bottom >= 0 && x_top < len && x_bottom < len) {
3053 if ((
int) x_top == (int) x_bottom) {
3056 int x = (int) x_top;
3059 scanline[x] += stbtt__position_trapezoid_area(height, x_top, x+1.0f, x_bottom, x+1.0f);
3060 scanline_fill[x] += height;
3063 float y_crossing, y_final, step, sign, area;
3065 if (x_top > x_bottom) {
3068 sy0 = y_bottom - (sy0 - y_top);
3069 sy1 = y_bottom - (sy1 - y_top);
3070 t = sy0, sy0 = sy1, sy1 = t;
3071 t = x_bottom, x_bottom = x_top, x_top = t;
3074 t = x0, x0 = xb, xb = t;
3080 x2 = (int) x_bottom;
3082 y_crossing = y_top + dy * (x1+1 - x0);
3085 y_final = y_top + dy * (x2 - x0);
3106 if (y_crossing > y_bottom)
3107 y_crossing = y_bottom;
3112 area = sign * (y_crossing-sy0);
3115 scanline[x1] += stbtt__sized_triangle_area(area, x1+1 - x_top);
3118 if (y_final > y_bottom) {
3120 dy = (y_final - y_crossing ) / (x2 - (x1+1));
3133 step = sign * dy * 1;
3137 for (x = x1+1; x < x2; ++x) {
3138 scanline[x] += area + step/2;
3146 scanline[x2] += area + sign * stbtt__position_trapezoid_area(sy1-y_final, (
float) x2, x2+1.0f, x_bottom, x2+1.0f);
3149 scanline_fill[x2] += sign * (sy1-sy0);
3160 for (x=0; x < len; ++x) {
3176 float x1 = (float) (x);
3177 float x2 = (float) (x+1);
3179 float y3 = y_bottom;
3184 float y1 = (x - x0) / dx + y_top;
3185 float y2 = (x+1 - x0) / dx + y_top;
3187 if (x0 < x1 && x3 > x2) {
3188 stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x1,y1);
3189 stbtt__handle_clipped_edge(scanline,x,e, x1,y1, x2,y2);
3190 stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x3,y3);
3191 }
else if (x3 < x1 && x0 > x2) {
3192 stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x2,y2);
3193 stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x1,y1);
3194 stbtt__handle_clipped_edge(scanline,x,e, x1,y1, x3,y3);
3195 }
else if (x0 < x1 && x3 > x1) {
3196 stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x1,y1);
3197 stbtt__handle_clipped_edge(scanline,x,e, x1,y1, x3,y3);
3198 }
else if (x3 < x1 && x0 > x1) {
3199 stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x1,y1);
3200 stbtt__handle_clipped_edge(scanline,x,e, x1,y1, x3,y3);
3201 }
else if (x0 < x2 && x3 > x2) {
3202 stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x2,y2);
3203 stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x3,y3);
3204 }
else if (x3 < x2 && x0 > x2) {
3205 stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x2,y2);
3206 stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x3,y3);
3208 stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x3,y3);
3218static void stbtt__rasterize_sorted_edges(
stbtt__bitmap *result,
stbtt__edge *e,
int n,
int vsubsample,
int off_x,
int off_y,
void *userdata)
3223 float scanline_data[129], *scanline, *scanline2;
3228 scanline = (
float *)
STBTT_malloc((result->
w*2+1) *
sizeof(float), userdata);
3230 scanline = scanline_data;
3232 scanline2 = scanline + result->
w;
3235 e[n].
y0 = (float) (off_y + result->
h) + 1;
3237 while (j < result->h) {
3239 float scan_y_top = y + 0.0f;
3240 float scan_y_bottom = y + 1.0f;
3244 STBTT_memset(scanline2, 0, (result->
w+1)*
sizeof(scanline[0]));
3250 if (z->
ey <= scan_y_top) {
3254 stbtt__hheap_free(&hh, z);
3256 step = &((*step)->next);
3261 while (e->
y0 <= scan_y_bottom) {
3262 if (e->
y0 != e->
y1) {
3265 if (j == 0 && off_y != 0) {
3266 if (z->
ey < scan_y_top) {
3282 stbtt__fill_active_edges_new(scanline, scanline2+1, result->
w, active, scan_y_top);
3286 for (i=0; i < result->
w; ++i) {
3289 sum += scanline2[i];
3290 k = scanline[i] + sum;
3293 if (m > 255) m = 255;
3294 result->
pixels[j*result->
stride + i] = (
unsigned char) m;
3302 step = &((*step)->next);
3309 stbtt__hheap_cleanup(&hh, userdata);
3311 if (scanline != scanline_data)
3315#error "Unrecognized value of STBTT_RASTERIZER_VERSION"
3318#define STBTT__COMPARE(a,b) ((a)->y0 < (b)->y0)
3320static void stbtt__sort_edges_ins_sort(
stbtt__edge *p,
int n)
3323 for (i=1; i < n; ++i) {
3338static void stbtt__sort_edges_quicksort(
stbtt__edge *p,
int n)
3343 int c01,c12,c,m,i,j;
3356 z = (c == c12) ? 0 : n-1;
3390 stbtt__sort_edges_quicksort(p,j);
3394 stbtt__sort_edges_quicksort(p+i, n-i);
3400static void stbtt__sort_edges(
stbtt__edge *p,
int n)
3402 stbtt__sort_edges_quicksort(p, n);
3403 stbtt__sort_edges_ins_sort(p, n);
3411static void stbtt__rasterize(
stbtt__bitmap *result,
stbtt__point *pts,
int *wcount,
int windings,
float scale_x,
float scale_y,
float shift_x,
float shift_y,
int off_x,
int off_y,
int invert,
void *userdata)
3413 float y_scale_inv = invert ? -scale_y : scale_y;
3416#if STBTT_RASTERIZER_VERSION == 1
3417 int vsubsample = result->
h < 8 ? 15 : 5;
3418#elif STBTT_RASTERIZER_VERSION == 2
3421 #error "Unrecognized value of STBTT_RASTERIZER_VERSION"
3427 for (i=0; i < windings; ++i)
3435 for (i=0; i < windings; ++i) {
3439 for (k=0; k < wcount[i]; j=k++) {
3442 if (p[j].y == p[k].y)
3446 if (invert ? p[j].y > p[k].y : p[j].
y < p[k].
y) {
3450 e[n].
x0 = p[a].
x * scale_x + shift_x;
3451 e[n].
y0 = (p[a].
y * y_scale_inv + shift_y) * vsubsample;
3452 e[n].
x1 = p[b].
x * scale_x + shift_x;
3453 e[n].
y1 = (p[b].
y * y_scale_inv + shift_y) * vsubsample;
3460 stbtt__sort_edges(e, n);
3463 stbtt__rasterize_sorted_edges(result, e, n, vsubsample, off_x, off_y, userdata);
3468static void stbtt__add_point(
stbtt__point *points,
int n,
float x,
float y)
3470 if (!points)
return;
3476static int stbtt__tesselate_curve(
stbtt__point *points,
int *num_points,
float x0,
float y0,
float x1,
float y1,
float x2,
float y2,
float objspace_flatness_squared,
int n)
3479 float mx = (x0 + 2*x1 + x2)/4;
3480 float my = (y0 + 2*y1 + y2)/4;
3482 float dx = (x0+x2)/2 - mx;
3483 float dy = (y0+y2)/2 - my;
3486 if (dx*dx+dy*dy > objspace_flatness_squared) {
3487 stbtt__tesselate_curve(points, num_points, x0,y0, (x0+x1)/2.0f,(y0+y1)/2.0f, mx,my, objspace_flatness_squared,n+1);
3488 stbtt__tesselate_curve(points, num_points, mx,my, (x1+x2)/2.0f,(y1+y2)/2.0f, x2,y2, objspace_flatness_squared,n+1);
3490 stbtt__add_point(points, *num_points,x2,y2);
3491 *num_points = *num_points+1;
3496static void stbtt__tesselate_cubic(
stbtt__point *points,
int *num_points,
float x0,
float y0,
float x1,
float y1,
float x2,
float y2,
float x3,
float y3,
float objspace_flatness_squared,
int n)
3508 float shortlen = (float)
STBTT_sqrt(dx*dx+dy*dy);
3509 float flatness_squared = longlen*longlen-shortlen*shortlen;
3514 if (flatness_squared > objspace_flatness_squared) {
3515 float x01 = (x0+x1)/2;
3516 float y01 = (y0+y1)/2;
3517 float x12 = (x1+x2)/2;
3518 float y12 = (y1+y2)/2;
3519 float x23 = (x2+x3)/2;
3520 float y23 = (y2+y3)/2;
3522 float xa = (x01+x12)/2;
3523 float ya = (y01+y12)/2;
3524 float xb = (x12+x23)/2;
3525 float yb = (y12+y23)/2;
3527 float mx = (xa+xb)/2;
3528 float my = (ya+yb)/2;
3530 stbtt__tesselate_cubic(points, num_points, x0,y0, x01,y01, xa,ya, mx,my, objspace_flatness_squared,n+1);
3531 stbtt__tesselate_cubic(points, num_points, mx,my, xb,yb, x23,y23, x3,y3, objspace_flatness_squared,n+1);
3533 stbtt__add_point(points, *num_points,x3,y3);
3534 *num_points = *num_points+1;
3539static stbtt__point *stbtt_FlattenCurves(
stbtt_vertex *vertices,
int num_verts,
float objspace_flatness,
int **contour_lengths,
int *num_contours,
void *userdata)
3544 float objspace_flatness_squared = objspace_flatness * objspace_flatness;
3545 int i,n=0,start=0, pass;
3548 for (i=0; i < num_verts; ++i)
3553 if (n == 0)
return 0;
3555 *contour_lengths = (
int *)
STBTT_malloc(
sizeof(**contour_lengths) * n, userdata);
3557 if (*contour_lengths == 0) {
3563 for (pass=0; pass < 2; ++pass) {
3567 if (points == NULL)
goto error;
3571 for (i=0; i < num_verts; ++i) {
3572 switch (vertices[i].type) {
3576 (*contour_lengths)[n] = num_points - start;
3580 x = vertices[i].
x, y = vertices[i].
y;
3581 stbtt__add_point(points, num_points++, x,y);
3584 x = vertices[i].
x, y = vertices[i].
y;
3585 stbtt__add_point(points, num_points++, x, y);
3588 stbtt__tesselate_curve(points, &num_points, x,y,
3589 vertices[i].cx, vertices[i].cy,
3590 vertices[i].x, vertices[i].y,
3591 objspace_flatness_squared, 0);
3592 x = vertices[i].
x, y = vertices[i].
y;
3595 stbtt__tesselate_cubic(points, &num_points, x,y,
3596 vertices[i].cx, vertices[i].cy,
3597 vertices[i].cx1, vertices[i].cy1,
3598 vertices[i].x, vertices[i].y,
3599 objspace_flatness_squared, 0);
3600 x = vertices[i].
x, y = vertices[i].
y;
3604 (*contour_lengths)[n] = num_points - start;
3611 *contour_lengths = 0;
3616STBTT_DEF void stbtt_Rasterize(
stbtt__bitmap *result,
float flatness_in_pixels,
stbtt_vertex *vertices,
int num_verts,
float scale_x,
float scale_y,
float shift_x,
float shift_y,
int x_off,
int y_off,
int invert,
void *userdata)
3618 float scale = scale_x > scale_y ? scale_y : scale_x;
3619 int winding_count = 0;
3620 int *winding_lengths = NULL;
3621 stbtt__point *windings = stbtt_FlattenCurves(vertices, num_verts, flatness_in_pixels / scale, &winding_lengths, &winding_count, userdata);
3623 stbtt__rasterize(result, windings, winding_lengths, winding_count, scale_x, scale_y, shift_x, shift_y, x_off, y_off, invert, userdata);
3629STBTT_DEF void stbtt_FreeBitmap(
unsigned char *bitmap,
void *userdata)
3634STBTT_DEF unsigned char *stbtt_GetGlyphBitmapSubpixel(
const stbtt_fontinfo *info,
float scale_x,
float scale_y,
float shift_x,
float shift_y,
int glyph,
int *width,
int *height,
int *xoff,
int *yoff)
3636 int ix0,iy0,ix1,iy1;
3639 int num_verts = stbtt_GetGlyphShape(info, glyph, &vertices);
3641 if (scale_x == 0) scale_x = scale_y;
3650 stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale_x, scale_y, shift_x, shift_y, &ix0,&iy0,&ix1,&iy1);
3653 gbm.
w = (ix1 - ix0);
3654 gbm.
h = (iy1 - iy0);
3657 if (width ) *width = gbm.
w;
3658 if (height) *height = gbm.
h;
3659 if (xoff ) *xoff = ix0;
3660 if (yoff ) *yoff = iy0;
3662 if (gbm.
w && gbm.
h) {
3667 stbtt_Rasterize(&gbm, 0.35f, vertices, num_verts, scale_x, scale_y, shift_x, shift_y, ix0, iy0, 1, info->
userdata);
3674STBTT_DEF unsigned char *stbtt_GetGlyphBitmap(
const stbtt_fontinfo *info,
float scale_x,
float scale_y,
int glyph,
int *width,
int *height,
int *xoff,
int *yoff)
3676 return stbtt_GetGlyphBitmapSubpixel(info, scale_x, scale_y, 0.0f, 0.0f, glyph, width, height, xoff, yoff);
3679STBTT_DEF void stbtt_MakeGlyphBitmapSubpixel(
const stbtt_fontinfo *info,
unsigned char *output,
int out_w,
int out_h,
int out_stride,
float scale_x,
float scale_y,
float shift_x,
float shift_y,
int glyph)
3683 int num_verts = stbtt_GetGlyphShape(info, glyph, &vertices);
3686 stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale_x, scale_y, shift_x, shift_y, &ix0,&iy0,0,0);
3693 stbtt_Rasterize(&gbm, 0.35f, vertices, num_verts, scale_x, scale_y, shift_x, shift_y, ix0,iy0, 1, info->
userdata);
3698STBTT_DEF void stbtt_MakeGlyphBitmap(
const stbtt_fontinfo *info,
unsigned char *output,
int out_w,
int out_h,
int out_stride,
float scale_x,
float scale_y,
int glyph)
3700 stbtt_MakeGlyphBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, scale_y, 0.0f,0.0f, glyph);
3703STBTT_DEF unsigned char *stbtt_GetCodepointBitmapSubpixel(
const stbtt_fontinfo *info,
float scale_x,
float scale_y,
float shift_x,
float shift_y,
int codepoint,
int *width,
int *height,
int *xoff,
int *yoff)
3705 return stbtt_GetGlyphBitmapSubpixel(info, scale_x, scale_y,shift_x,shift_y, stbtt_FindGlyphIndex(info,codepoint), width,height,xoff,yoff);
3708STBTT_DEF void stbtt_MakeCodepointBitmapSubpixelPrefilter(
const stbtt_fontinfo *info,
unsigned char *output,
int out_w,
int out_h,
int out_stride,
float scale_x,
float scale_y,
float shift_x,
float shift_y,
int oversample_x,
int oversample_y,
float *sub_x,
float *sub_y,
int codepoint)
3710 stbtt_MakeGlyphBitmapSubpixelPrefilter(info, output, out_w, out_h, out_stride, scale_x, scale_y, shift_x, shift_y, oversample_x, oversample_y, sub_x, sub_y, stbtt_FindGlyphIndex(info,codepoint));
3713STBTT_DEF void stbtt_MakeCodepointBitmapSubpixel(
const stbtt_fontinfo *info,
unsigned char *output,
int out_w,
int out_h,
int out_stride,
float scale_x,
float scale_y,
float shift_x,
float shift_y,
int codepoint)
3715 stbtt_MakeGlyphBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, scale_y, shift_x, shift_y, stbtt_FindGlyphIndex(info,codepoint));
3718STBTT_DEF unsigned char *stbtt_GetCodepointBitmap(
const stbtt_fontinfo *info,
float scale_x,
float scale_y,
int codepoint,
int *width,
int *height,
int *xoff,
int *yoff)
3720 return stbtt_GetCodepointBitmapSubpixel(info, scale_x, scale_y, 0.0f,0.0f, codepoint, width,height,xoff,yoff);
3723STBTT_DEF void stbtt_MakeCodepointBitmap(
const stbtt_fontinfo *info,
unsigned char *output,
int out_w,
int out_h,
int out_stride,
float scale_x,
float scale_y,
int codepoint)
3725 stbtt_MakeCodepointBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, scale_y, 0.0f,0.0f, codepoint);
3734static int stbtt_BakeFontBitmap_internal(
unsigned char *data,
int offset,
3736 unsigned char *pixels,
int pw,
int ph,
3737 int first_char,
int num_chars,
3741 int x,y,bottom_y, i;
3744 if (!stbtt_InitFont(&f, data, offset))
3750 scale = stbtt_ScaleForPixelHeight(&f, pixel_height);
3752 for (i=0; i < num_chars; ++i) {
3753 int advance, lsb, x0,y0,x1,y1,gw,gh;
3754 int g = stbtt_FindGlyphIndex(&f, first_char + i);
3755 stbtt_GetGlyphHMetrics(&f, g, &advance, &lsb);
3756 stbtt_GetGlyphBitmapBox(&f, g, scale,scale, &x0,&y0,&x1,&y1);
3759 if (x + gw + 1 >= pw)
3760 y = bottom_y, x = 1;
3761 if (y + gh + 1 >= ph)
3765 stbtt_MakeGlyphBitmap(&f, pixels+x+y*pw, gw,gh,pw, scale,scale, g);
3770 chardata[i].
xadvance = scale * advance;
3771 chardata[i].
xoff = (float) x0;
3772 chardata[i].
yoff = (float) y0;
3774 if (y+gh+1 > bottom_y)
3782 float d3d_bias = opengl_fillrule ? 0 : -0.5f;
3783 float ipw = 1.0f / pw, iph = 1.0f / ph;
3788 q->
x0 = round_x + d3d_bias;
3789 q->
y0 = round_y + d3d_bias;
3790 q->
x1 = round_x + b->
x1 - b->
x0 + d3d_bias;
3791 q->
y1 = round_y + b->
y1 - b->
y0 + d3d_bias;
3793 q->
s0 = b->
x0 * ipw;
3794 q->
t0 = b->
y0 * iph;
3795 q->
s1 = b->
x1 * ipw;
3796 q->
t1 = b->
y1 * iph;
3806#ifndef STB_RECT_PACK_VERSION
3852 for (i=0; i < num_rects; ++i) {
3853 if (con->
x + rects[i].w > con->
width) {
3857 if (con->
y + rects[i].h > con->
height)
3859 rects[i].
x = con->
x;
3860 rects[i].
y = con->
y;
3862 con->
x += rects[i].
w;
3863 if (con->
y + rects[i].h > con->
bottom_y)
3866 for ( ; i < num_rects; ++i)
3867 rects[i].was_packed = 0;
3878STBTT_DEF int stbtt_PackBegin(
stbtt_pack_context *spc,
unsigned char *pixels,
int pw,
int ph,
int stride_in_bytes,
int padding,
void *alloc_context)
3881 int num_nodes = pw - padding;
3884 if (context == NULL || nodes == NULL) {
3885 if (context != NULL)
STBTT_free(context, alloc_context);
3886 if (nodes != NULL)
STBTT_free(nodes , alloc_context);
3902 stbrp_init_target(context, pw-padding, ph-padding, nodes, num_nodes);
3931#define STBTT__OVER_MASK (STBTT_MAX_OVERSAMPLE-1)
3933static void stbtt__h_prefilter(
unsigned char *pixels,
int w,
int h,
int stride_in_bytes,
unsigned int kernel_width)
3936 int safe_w = w - kernel_width;
3939 for (j=0; j < h; ++j) {
3947 switch (kernel_width) {
3949 for (i=0; i <= safe_w; ++i) {
3952 pixels[i] = (
unsigned char) (total / 2);
3956 for (i=0; i <= safe_w; ++i) {
3959 pixels[i] = (
unsigned char) (total / 3);
3963 for (i=0; i <= safe_w; ++i) {
3966 pixels[i] = (
unsigned char) (total / 4);
3970 for (i=0; i <= safe_w; ++i) {
3973 pixels[i] = (
unsigned char) (total / 5);
3977 for (i=0; i <= safe_w; ++i) {
3980 pixels[i] = (
unsigned char) (total / kernel_width);
3985 for (; i < w; ++i) {
3988 pixels[i] = (
unsigned char) (total / kernel_width);
3991 pixels += stride_in_bytes;
3995static void stbtt__v_prefilter(
unsigned char *pixels,
int w,
int h,
int stride_in_bytes,
unsigned int kernel_width)
3998 int safe_h = h - kernel_width;
4001 for (j=0; j < w; ++j) {
4009 switch (kernel_width) {
4011 for (i=0; i <= safe_h; ++i) {
4014 pixels[i*stride_in_bytes] = (
unsigned char) (total / 2);
4018 for (i=0; i <= safe_h; ++i) {
4021 pixels[i*stride_in_bytes] = (
unsigned char) (total / 3);
4025 for (i=0; i <= safe_h; ++i) {
4028 pixels[i*stride_in_bytes] = (
unsigned char) (total / 4);
4032 for (i=0; i <= safe_h; ++i) {
4035 pixels[i*stride_in_bytes] = (
unsigned char) (total / 5);
4039 for (i=0; i <= safe_h; ++i) {
4042 pixels[i*stride_in_bytes] = (
unsigned char) (total / kernel_width);
4047 for (; i < h; ++i) {
4050 pixels[i*stride_in_bytes] = (
unsigned char) (total / kernel_width);
4057static float stbtt__oversample_shift(
int oversample)
4066 return (
float)-(oversample - 1) / (2.0f * (
float)oversample);
4073 int missing_glyph_added = 0;
4076 for (i=0; i < num_ranges; ++i) {
4078 float scale = fh > 0 ? stbtt_ScaleForPixelHeight(info, fh) : stbtt_ScaleForMappingEmToPixels(info, -fh);
4081 for (j=0; j < ranges[i].
num_chars; ++j) {
4084 int glyph = stbtt_FindGlyphIndex(info, codepoint);
4085 if (glyph == 0 && (spc->
skip_missing || missing_glyph_added)) {
4086 rects[k].
w = rects[k].
h = 0;
4088 stbtt_GetGlyphBitmapBoxSubpixel(info,glyph,
4096 missing_glyph_added = 1;
4105STBTT_DEF void stbtt_MakeGlyphBitmapSubpixelPrefilter(
const stbtt_fontinfo *info,
unsigned char *output,
int out_w,
int out_h,
int out_stride,
float scale_x,
float scale_y,
float shift_x,
float shift_y,
int prefilter_x,
int prefilter_y,
float *sub_x,
float *sub_y,
int glyph)
4107 stbtt_MakeGlyphBitmapSubpixel(info,
4109 out_w - (prefilter_x - 1),
4110 out_h - (prefilter_y - 1),
4118 if (prefilter_x > 1)
4119 stbtt__h_prefilter(output, out_w, out_h, out_stride, prefilter_x);
4121 if (prefilter_y > 1)
4122 stbtt__v_prefilter(output, out_w, out_h, out_stride, prefilter_y);
4124 *sub_x = stbtt__oversample_shift(prefilter_x);
4125 *sub_y = stbtt__oversample_shift(prefilter_y);
4131 int i,j,k, missing_glyph = -1, return_value = 1;
4138 for (i=0; i < num_ranges; ++i) {
4140 float scale = fh > 0 ? stbtt_ScaleForPixelHeight(info, fh) : stbtt_ScaleForMappingEmToPixels(info, -fh);
4141 float recip_h,recip_v,sub_x,sub_y;
4148 for (j=0; j < ranges[i].
num_chars; ++j) {
4152 int advance, lsb, x0,y0,x1,y1;
4154 int glyph = stbtt_FindGlyphIndex(info, codepoint);
4162 stbtt_GetGlyphHMetrics(info, glyph, &advance, &lsb);
4163 stbtt_GetGlyphBitmapBox(info, glyph,
4167 stbtt_MakeGlyphBitmapSubpixel(info,
4191 bc->xadvance = scale * advance;
4192 bc->xoff = (float) x0 * recip_h + sub_x;
4193 bc->yoff = (float) y0 * recip_v + sub_y;
4194 bc->xoff2 = (x0 + r->
w) * recip_h + sub_x;
4195 bc->yoff2 = (y0 + r->
h) * recip_v + sub_y;
4201 }
else if (r->
was_packed && r->
w == 0 && r->
h == 0 && missing_glyph >= 0) {
4215 return return_value;
4226 int i,j,n, return_value = 1;
4231 for (i=0; i < num_ranges; ++i)
4233 ranges[i].chardata_for_range[j].x0 =
4234 ranges[i].chardata_for_range[j].y0 =
4235 ranges[i].chardata_for_range[j].x1 =
4236 ranges[i].chardata_for_range[j].y1 = 0;
4239 for (i=0; i < num_ranges; ++i)
4240 n += ranges[i].num_chars;
4247 stbtt_InitFont(&info, fontdata, stbtt_GetFontOffsetForIndex(fontdata,font_index));
4249 n = stbtt_PackFontRangesGatherRects(spc, &info, ranges, num_ranges, rects);
4251 stbtt_PackFontRangesPackRects(spc, rects, n);
4253 return_value = stbtt_PackFontRangesRenderIntoRects(spc, &info, ranges, num_ranges, rects);
4256 return return_value;
4260 int first_unicode_codepoint_in_range,
int num_chars_in_range,
stbtt_packedchar *chardata_for_range)
4268 return stbtt_PackFontRanges(spc, fontdata, font_index, &range, 1);
4271STBTT_DEF void stbtt_GetScaledFontVMetrics(
const unsigned char *fontdata,
int index,
float size,
float *ascent,
float *descent,
float *lineGap)
4273 int i_ascent, i_descent, i_lineGap;
4276 stbtt_InitFont(&info, fontdata, stbtt_GetFontOffsetForIndex(fontdata, index));
4277 scale = size > 0 ? stbtt_ScaleForPixelHeight(&info, size) : stbtt_ScaleForMappingEmToPixels(&info, -size);
4278 stbtt_GetFontVMetrics(&info, &i_ascent, &i_descent, &i_lineGap);
4279 *ascent = (float) i_ascent * scale;
4280 *descent = (float) i_descent * scale;
4281 *lineGap = (float) i_lineGap * scale;
4286 float ipw = 1.0f / pw, iph = 1.0f / ph;
4289 if (align_to_integer) {
4303 q->
s0 = b->
x0 * ipw;
4304 q->
t0 = b->
y0 * iph;
4305 q->
s1 = b->
x1 * ipw;
4306 q->
t1 = b->
y1 * iph;
4316#define STBTT_min(a,b) ((a) < (b) ? (a) : (b))
4317#define STBTT_max(a,b) ((a) < (b) ? (b) : (a))
4319static int stbtt__ray_intersect_bezier(
float orig[2],
float ray[2],
float q0[2],
float q1[2],
float q2[2],
float hits[2][2])
4321 float q0perp = q0[1]*ray[0] - q0[0]*ray[1];
4322 float q1perp = q1[1]*ray[0] - q1[0]*ray[1];
4323 float q2perp = q2[1]*ray[0] - q2[0]*ray[1];
4324 float roperp = orig[1]*ray[0] - orig[0]*ray[1];
4326 float a = q0perp - 2*q1perp + q2perp;
4327 float b = q1perp - q0perp;
4328 float c = q0perp - roperp;
4330 float s0 = 0., s1 = 0.;
4334 float discr = b*b - a*c;
4336 float rcpna = -1 / a;
4340 if (s0 >= 0.0 && s0 <= 1.0)
4342 if (d > 0.0 && s1 >= 0.0 && s1 <= 1.0) {
4343 if (num_s == 0) s0 = s1;
4351 if (s0 >= 0.0 && s0 <= 1.0)
4358 float rcp_len2 = 1 / (ray[0]*ray[0] + ray[1]*ray[1]);
4359 float rayn_x = ray[0] * rcp_len2, rayn_y = ray[1] * rcp_len2;
4361 float q0d = q0[0]*rayn_x + q0[1]*rayn_y;
4362 float q1d = q1[0]*rayn_x + q1[1]*rayn_y;
4363 float q2d = q2[0]*rayn_x + q2[1]*rayn_y;
4364 float rod = orig[0]*rayn_x + orig[1]*rayn_y;
4366 float q10d = q1d - q0d;
4367 float q20d = q2d - q0d;
4368 float q0rd = q0d - rod;
4370 hits[0][0] = q0rd + s0*(2.0f - 2.0f*s0)*q10d + s0*s0*q20d;
4371 hits[0][1] = a*s0+b;
4374 hits[1][0] = q0rd + s1*(2.0f - 2.0f*s1)*q10d + s1*s1*q20d;
4375 hits[1][1] = a*s1+b;
4383static int equal(
float *a,
float *b)
4385 return (a[0] == b[0] && a[1] == b[1]);
4388static int stbtt__compute_crossings_x(
float x,
float y,
int nverts,
stbtt_vertex *verts)
4391 float orig[2], ray[2] = { 1, 0 };
4399 else if (y_frac > 0.99f)
4406 for (i=0; i < nverts; ++i) {
4408 int x0 = (int) verts[i-1].x, y0 = (
int) verts[i-1].
y;
4409 int x1 = (int) verts[i ].x, y1 = (
int) verts[i ].
y;
4411 float x_inter = (y - y0) / (y1 - y0) * (x1-x0) + x0;
4413 winding += (y0 < y1) ? 1 : -1;
4417 int x0 = (int) verts[i-1].x , y0 = (
int) verts[i-1].
y ;
4418 int x1 = (int) verts[i ].cx, y1 = (
int) verts[i ].
cy;
4419 int x2 = (int) verts[i ].x , y2 = (
int) verts[i ].
y ;
4422 if (y > ay && y < by && x > ax) {
4423 float q0[2],q1[2],q2[2];
4431 if (equal(q0,q1) || equal(q1,q2)) {
4432 x0 = (int)verts[i-1].x;
4433 y0 = (int)verts[i-1].y;
4434 x1 = (int)verts[i ].x;
4435 y1 = (int)verts[i ].y;
4437 float x_inter = (y - y0) / (y1 - y0) * (x1-x0) + x0;
4439 winding += (y0 < y1) ? 1 : -1;
4442 int num_hits = stbtt__ray_intersect_bezier(orig, ray, q0, q1, q2, hits);
4445 winding += (hits[0][1] < 0 ? -1 : 1);
4448 winding += (hits[1][1] < 0 ? -1 : 1);
4456static float stbtt__cuberoot(
float x )
4459 return -(float)
STBTT_pow(-x,1.0f/3.0f);
4465static int stbtt__solve_cubic(
float a,
float b,
float c,
float* r)
4468 float p = b - a*a / 3;
4469 float q = a * (2*a*a - 9*b) / 27 + c;
4471 float d = q*q + 4*p3 / 27;
4474 float u = (-q + z) / 2;
4475 float v = (-q - z) / 2;
4476 u = stbtt__cuberoot(u);
4477 v = stbtt__cuberoot(v);
4484 float n = (float)
STBTT_cos(v-3.141592/2)*1.732050808f;
4485 r[0] = s + u * 2 * m;
4486 r[1] = s - u * (m + n);
4487 r[2] = s - u * (m - n);
4496STBTT_DEF unsigned char * stbtt_GetGlyphSDF(
const stbtt_fontinfo *info,
float scale,
int glyph,
int padding,
unsigned char onedge_value,
float pixel_dist_scale,
int *width,
int *height,
int *xoff,
int *yoff)
4498 float scale_x = scale, scale_y = scale;
4499 int ix0,iy0,ix1,iy1;
4501 unsigned char *data;
4503 if (scale == 0)
return NULL;
4505 stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale, scale, 0.0f,0.0f, &ix0,&iy0,&ix1,&iy1);
4508 if (ix0 == ix1 || iy0 == iy1)
4519 if (width ) *width = w;
4520 if (height) *height = h;
4521 if (xoff ) *xoff = ix0;
4522 if (yoff ) *yoff = iy0;
4531 int num_verts = stbtt_GetGlyphShape(info, glyph, &verts);
4535 for (i=0,j=num_verts-1; i < num_verts; j=i++) {
4537 float x0 = verts[i].
x*scale_x, y0 = verts[i].
y*scale_y;
4538 float x1 = verts[j].
x*scale_x, y1 = verts[j].
y*scale_y;
4539 float dist = (float)
STBTT_sqrt((x1-x0)*(x1-x0) + (y1-y0)*(y1-y0));
4540 precompute[i] = (dist == 0) ? 0.0f : 1.0f / dist;
4542 float x2 = verts[j].
x *scale_x, y2 = verts[j].
y *scale_y;
4543 float x1 = verts[i].
cx*scale_x, y1 = verts[i].
cy*scale_y;
4544 float x0 = verts[i].
x *scale_x, y0 = verts[i].
y *scale_y;
4545 float bx = x0 - 2*x1 + x2, by = y0 - 2*y1 + y2;
4546 float len2 = bx*bx + by*by;
4548 precompute[i] = 1.0f / (bx*bx + by*by);
4550 precompute[i] = 0.0f;
4552 precompute[i] = 0.0f;
4555 for (y=iy0; y < iy1; ++y) {
4556 for (x=ix0; x < ix1; ++x) {
4558 float min_dist = 999999.0f;
4559 float sx = (float) x + 0.5f;
4560 float sy = (float) y + 0.5f;
4561 float x_gspace = (sx / scale_x);
4562 float y_gspace = (sy / scale_y);
4564 int winding = stbtt__compute_crossings_x(x_gspace, y_gspace, num_verts, verts);
4566 for (i=0; i < num_verts; ++i) {
4567 float x0 = verts[i].
x*scale_x, y0 = verts[i].
y*scale_y;
4569 if (verts[i].type ==
STBTT_vline && precompute[i] != 0.0f) {
4570 float x1 = verts[i-1].
x*scale_x, y1 = verts[i-1].
y*scale_y;
4572 float dist,dist2 = (x0-sx)*(x0-sx) + (y0-sy)*(y0-sy);
4573 if (dist2 < min_dist*min_dist)
4579 dist = (float)
STBTT_fabs((x1-x0)*(y0-sy) - (y1-y0)*(x0-sx)) * precompute[i];
4581 if (dist < min_dist) {
4585 float dx = x1-x0, dy = y1-y0;
4586 float px = x0-sx, py = y0-sy;
4589 float t = -(px*dx + py*dy) / (dx*dx + dy*dy);
4590 if (t >= 0.0f && t <= 1.0f)
4594 float x2 = verts[i-1].
x *scale_x, y2 = verts[i-1].
y *scale_y;
4595 float x1 = verts[i ].
cx*scale_x, y1 = verts[i ].
cy*scale_y;
4601 if (sx > box_x0-min_dist && sx < box_x1+min_dist && sy > box_y0-min_dist && sy < box_y1+min_dist) {
4603 float ax = x1-x0, ay = y1-y0;
4604 float bx = x0 - 2*x1 + x2, by = y0 - 2*y1 + y2;
4605 float mx = x0 - sx, my = y0 - sy;
4606 float res[3] = {0.f,0.f,0.f};
4607 float px,py,t,it,dist2;
4608 float a_inv = precompute[i];
4610 float a = 3*(ax*bx + ay*by);
4611 float b = 2*(ax*ax + ay*ay) + (mx*bx+my*by);
4612 float c = mx*ax+my*ay;
4618 float discriminant = b*b - 4*a*c;
4619 if (discriminant < 0)
4622 float root = (float)
STBTT_sqrt(discriminant);
4623 res[0] = (-b - root)/(2*a);
4624 res[1] = (-b + root)/(2*a);
4629 float b = 3*(ax*bx + ay*by) * a_inv;
4630 float c = (2*(ax*ax + ay*ay) + (mx*bx+my*by)) * a_inv;
4631 float d = (mx*ax+my*ay) * a_inv;
4632 num = stbtt__solve_cubic(b, c, d, res);
4634 dist2 = (x0-sx)*(x0-sx) + (y0-sy)*(y0-sy);
4635 if (dist2 < min_dist*min_dist)
4638 if (num >= 1 && res[0] >= 0.0f && res[0] <= 1.0f) {
4639 t = res[0], it = 1.0f - t;
4640 px = it*it*x0 + 2*t*it*x1 + t*t*x2;
4641 py = it*it*y0 + 2*t*it*y1 + t*t*y2;
4642 dist2 = (px-sx)*(px-sx) + (py-sy)*(py-sy);
4643 if (dist2 < min_dist * min_dist)
4646 if (num >= 2 && res[1] >= 0.0f && res[1] <= 1.0f) {
4647 t = res[1], it = 1.0f - t;
4648 px = it*it*x0 + 2*t*it*x1 + t*t*x2;
4649 py = it*it*y0 + 2*t*it*y1 + t*t*y2;
4650 dist2 = (px-sx)*(px-sx) + (py-sy)*(py-sy);
4651 if (dist2 < min_dist * min_dist)
4654 if (num >= 3 && res[2] >= 0.0f && res[2] <= 1.0f) {
4655 t = res[2], it = 1.0f - t;
4656 px = it*it*x0 + 2*t*it*x1 + t*t*x2;
4657 py = it*it*y0 + 2*t*it*y1 + t*t*y2;
4658 dist2 = (px-sx)*(px-sx) + (py-sy)*(py-sy);
4659 if (dist2 < min_dist * min_dist)
4666 min_dist = -min_dist;
4667 val = onedge_value + pixel_dist_scale * min_dist;
4672 data[(y-iy0)*w+(x-ix0)] = (
unsigned char) val;
4681STBTT_DEF unsigned char * stbtt_GetCodepointSDF(
const stbtt_fontinfo *info,
float scale,
int codepoint,
int padding,
unsigned char onedge_value,
float pixel_dist_scale,
int *width,
int *height,
int *xoff,
int *yoff)
4683 return stbtt_GetGlyphSDF(info, scale, stbtt_FindGlyphIndex(info, codepoint), padding, onedge_value, pixel_dist_scale, width, height, xoff, yoff);
4686STBTT_DEF void stbtt_FreeSDF(
unsigned char *bitmap,
void *userdata)
4705 if (i >= len1)
return -1;
4706 if (s1[i++] != ch)
return -1;
4707 }
else if (ch < 0x800) {
4708 if (i+1 >= len1)
return -1;
4709 if (s1[i++] != 0xc0 + (ch >> 6))
return -1;
4710 if (s1[i++] != 0x80 + (ch & 0x3f))
return -1;
4711 }
else if (ch >= 0xd800 && ch < 0xdc00) {
4714 if (i+3 >= len1)
return -1;
4715 c = ((ch - 0xd800) << 10) + (ch2 - 0xdc00) + 0x10000;
4716 if (s1[i++] != 0xf0 + (c >> 18))
return -1;
4717 if (s1[i++] != 0x80 + ((c >> 12) & 0x3f))
return -1;
4718 if (s1[i++] != 0x80 + ((c >> 6) & 0x3f))
return -1;
4719 if (s1[i++] != 0x80 + ((c ) & 0x3f))
return -1;
4722 }
else if (ch >= 0xdc00 && ch < 0xe000) {
4725 if (i+2 >= len1)
return -1;
4726 if (s1[i++] != 0xe0 + (ch >> 12))
return -1;
4727 if (s1[i++] != 0x80 + ((ch >> 6) & 0x3f))
return -1;
4728 if (s1[i++] != 0x80 + ((ch ) & 0x3f))
return -1;
4736static int stbtt_CompareUTF8toUTF16_bigendian_internal(
char *s1,
int len1,
char *s2,
int len2)
4738 return len1 == stbtt__CompareUTF8toUTF16_bigendian_prefix((
stbtt_uint8*) s1, len1, (
stbtt_uint8*) s2, len2);
4743STBTT_DEF const char *stbtt_GetFontNameString(
const stbtt_fontinfo *font,
int *length,
int platformID,
int encodingID,
int languageID,
int nameID)
4748 stbtt_uint32 nm = stbtt__find_table(fc, offset,
"name");
4749 if (!nm)
return NULL;
4751 count = ttUSHORT(fc+nm+2);
4752 stringOffset = nm + ttUSHORT(fc+nm+4);
4753 for (i=0; i < count; ++i) {
4755 if (platformID == ttUSHORT(fc+loc+0) && encodingID == ttUSHORT(fc+loc+2)
4756 && languageID == ttUSHORT(fc+loc+4) && nameID == ttUSHORT(fc+loc+6)) {
4757 *length = ttUSHORT(fc+loc+8);
4758 return (
const char *) (fc+stringOffset+ttUSHORT(fc+loc+10));
4768 stbtt_int32 stringOffset = nm + ttUSHORT(fc+nm+4);
4770 for (i=0; i < count; ++i) {
4773 if (
id == target_id) {
4775 stbtt_int32 platform = ttUSHORT(fc+loc+0), encoding = ttUSHORT(fc+loc+2), language = ttUSHORT(fc+loc+4);
4778 if (platform == 0 || (platform == 3 && encoding == 1) || (platform == 3 && encoding == 10)) {
4783 stbtt_int32 matchlen = stbtt__CompareUTF8toUTF16_bigendian_prefix(name, nlen, fc+stringOffset+off,slen);
4784 if (matchlen >= 0) {
4786 if (i+1 < count && ttUSHORT(fc+loc+12+6) == next_id && ttUSHORT(fc+loc+12) == platform && ttUSHORT(fc+loc+12+2) == encoding && ttUSHORT(fc+loc+12+4) == language) {
4787 slen = ttUSHORT(fc+loc+12+8);
4788 off = ttUSHORT(fc+loc+12+10);
4790 if (matchlen == nlen)
4792 }
else if (matchlen < nlen && name[matchlen] ==
' ') {
4794 if (stbtt_CompareUTF8toUTF16_bigendian_internal((
char*) (name+matchlen), nlen-matchlen, (
char*)(fc+stringOffset+off),slen))
4799 if (matchlen == nlen)
4815 if (!stbtt__isfont(fc+offset))
return 0;
4819 hd = stbtt__find_table(fc, offset,
"head");
4820 if ((ttUSHORT(fc+hd+44) & 7) != (flags & 7))
return 0;
4823 nm = stbtt__find_table(fc, offset,
"name");
4828 if (stbtt__matchpair(fc, nm, name, nlen, 16, -1))
return 1;
4829 if (stbtt__matchpair(fc, nm, name, nlen, 1, -1))
return 1;
4830 if (stbtt__matchpair(fc, nm, name, nlen, 3, -1))
return 1;
4832 if (stbtt__matchpair(fc, nm, name, nlen, 16, 17))
return 1;
4833 if (stbtt__matchpair(fc, nm, name, nlen, 1, 2))
return 1;
4834 if (stbtt__matchpair(fc, nm, name, nlen, 3, -1))
return 1;
4840static int stbtt_FindMatchingFont_internal(
unsigned char *font_collection,
char *name_utf8,
stbtt_int32 flags)
4844 stbtt_int32 off = stbtt_GetFontOffsetForIndex(font_collection, i);
4845 if (off < 0)
return off;
4851#if defined(__GNUC__) || defined(__clang__)
4852#pragma GCC diagnostic push
4853#pragma GCC diagnostic ignored "-Wcast-qual"
4856STBTT_DEF int stbtt_BakeFontBitmap(
const unsigned char *data,
int offset,
4857 float pixel_height,
unsigned char *pixels,
int pw,
int ph,
4860 return stbtt_BakeFontBitmap_internal((
unsigned char *) data, offset, pixel_height, pixels, pw, ph, first_char, num_chars, chardata);
4863STBTT_DEF int stbtt_GetFontOffsetForIndex(
const unsigned char *data,
int index)
4865 return stbtt_GetFontOffsetForIndex_internal((
unsigned char *) data, index);
4868STBTT_DEF int stbtt_GetNumberOfFonts(
const unsigned char *data)
4870 return stbtt_GetNumberOfFonts_internal((
unsigned char *) data);
4875 return stbtt_InitFont_internal(info, (
unsigned char *) data, offset);
4878STBTT_DEF int stbtt_FindMatchingFont(
const unsigned char *fontdata,
const char *name,
int flags)
4880 return stbtt_FindMatchingFont_internal((
unsigned char *) fontdata, (
char *) name, flags);
4883STBTT_DEF int stbtt_CompareUTF8toUTF16_bigendian(
const char *s1,
int len1,
const char *s2,
int len2)
4885 return stbtt_CompareUTF8toUTF16_bigendian_internal((
char *) s1, len1, (
char *) s2, len2);
4888#if defined(__GNUC__) || defined(__clang__)
4889#pragma GCC diagnostic pop
5004static int text_iterator_length(
const void* data,
text_encoding_t encoding)
5010 const uint8_t*
text =
static_cast<const uint8_t*
>(data);
5015 const uint16_t*
text =
static_cast<const uint16_t*
>(data);
5020 const uint32_t*
text =
static_cast<const uint32_t*
>(data);
5034 length = text_iterator_length(
text, encoding);
5051 const uint8_t*
text =
static_cast<const uint8_t*
>(it->
text);
5055 static const uint8_t trailing[256] = {
5056 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5057 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5058 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5059 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5060 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5061 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5062 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5063 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5
5066 static const uint32_t offsets[6] = {
5067 0x00000000, 0x00003080, 0x000E2080, 0x03C82080, 0xFA082080, 0x82082080
5070 const uint8_t*
text =
static_cast<const uint8_t*
>(it->
text);
5071 uint8_t trailing_offset = trailing[
text[it->
index]];
5072 uint32_t offset_value = offsets[trailing_offset];
5073 while(trailing_offset > 0 && it->
index < it->
length - 1) {
5080 codepoint -= offset_value;
5083 const uint16_t*
text =
static_cast<const uint16_t*
>(it->
text);
5085 if(((codepoint) & 0xfffffc00) == 0xd800) {
5086 if(it->
index < it->
length && (((codepoint) & 0xfffffc00) == 0xdc00)) {
5088 codepoint = (codepoint << 10) + trail - ((0xD800u << 10) - 0x10000u + 0xDC00u);
5094 const uint32_t*
text =
static_cast<const uint32_t*
>(it->
text);
5112typedef CRITICAL_SECTION
mutex_t;
5114#define novasvg_mutex_init(mutex) InitializeCriticalSection(mutex)
5115#define novasvg_mutex_lock(mutex) EnterCriticalSection(mutex)
5116#define novasvg_mutex_unlock(mutex) LeaveCriticalSection(mutex)
5117#define novasvg_mutex_destroy(mutex) DeleteCriticalSection(mutex)
5119#elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L && defined(HAVE_THREADS_H) && !defined(__STDC_NO_THREADS__)
5129#define novasvg_mutex_init(mutex) mtx_init(mutex, mtx_plain | mtx_recursive)
5130#define novasvg_mutex_lock(mutex) mtx_lock(mutex)
5131#define novasvg_mutex_unlock(mutex) mtx_unlock(mutex)
5132#define novasvg_mutex_destroy(mutex) mtx_destroy(mutex)
5138#define novasvg_mutex_init(mutex) ((void)(mutex))
5139#define novasvg_mutex_lock(mutex) ((void)(mutex))
5140#define novasvg_mutex_unlock(mutex) ((void)(mutex))
5141#define novasvg_mutex_destroy(mutex) ((void)(mutex))
5197static void glyph_cache_finish(glyph_cache_t* cache,
font_face_t* face)
5202 for(
size_t i = 0; i < cache->capacity; ++i) {
5203 glyph_t* glyph = cache->glyphs[i];
5206 stbtt_FreeShape(&face->info, glyph->vertices);
5212 free(cache->glyphs);
5213 cache->glyphs = NULL;
5214 cache->capacity = 0;
5221#define GLYPH_CACHE_INIT_CAPACITY 128
5227 if(cache->glyphs == NULL) {
5228 assert(cache->size == 0);
5233 size_t index = codepoint & (cache->capacity - 1);
5234 glyph_t* glyph = cache->glyphs[index];
5235 while(glyph && glyph->codepoint != codepoint) {
5236 glyph = glyph->
next;
5240 glyph =
static_cast<decltype(glyph)
>(malloc(
sizeof(
glyph_t)));
5242 glyph->index = stbtt_FindGlyphIndex(&face->info, codepoint);
5243 glyph->nvertices = stbtt_GetGlyphShape(&face->info, glyph->index, &glyph->vertices);
5244 stbtt_GetGlyphHMetrics(&face->info, glyph->index, &glyph->advance_width, &glyph->left_side_bearing);
5245 if(!stbtt_GetGlyphBox(&face->info, glyph->index, &glyph->x1, &glyph->y1, &glyph->x2, &glyph->y2)) {
5246 glyph->x1 = glyph->y1 = glyph->x2 = glyph->y2 = 0;
5249 glyph->next = cache->glyphs[index];
5250 cache->glyphs[index] = glyph;
5253 if(cache->size > (cache->capacity * 3 / 4)) {
5254 size_t newcapacity = cache->capacity << 1;
5257 for(
size_t i = 0; i < cache->capacity; ++i) {
5258 glyph_t* entry = cache->glyphs[i];
5261 size_t newindex = entry->
codepoint & (newcapacity - 1);
5262 entry->next = newglyphs[newindex];
5263 newglyphs[newindex] = entry;
5268 free(cache->glyphs);
5269 cache->glyphs = newglyphs;
5270 cache->capacity = newcapacity;
5280 FILE* fp = fopen(filename,
"rb");
5285 fseek(fp, 0, SEEK_END);
5286 long length = ftell(fp);
5292 void* data =
static_cast<void*
>(malloc(length));
5298 fseek(fp, 0, SEEK_SET);
5299 size_t nread = fread(data, 1, length, fp);
5302 if(nread != length) {
5313 int offset = stbtt_GetFontOffsetForIndex(
static_cast<const unsigned char*
>(data), ttcindex);
5314 if(offset == -1 || !stbtt_InitFont(&info,
static_cast<const unsigned char*
>(data), offset)) {
5316 destroy_func(closure);
5324 stbtt_GetFontBoundingBox(&face->
info, &face->
x1, &face->
y1, &face->
x2, &face->
y2);
5326 glyph_cache_init(&face->
cache);
5343 glyph_cache_finish(&face->
cache, face);
5356static float font_face_get_scale(
const font_face_t* face,
float size)
5358 return stbtt_ScaleForMappingEmToPixels(&face->
info, size);
5372 return 1.0f / stbtt_ScaleForMappingEmToPixels(&face->
info, 1.0f);
5398 stbtt_uint16 segcount = ttUSHORT(data + index_map + 6) >> 1;
5400 stbtt_uint32 start_count_base = end_count_base + segcount * 2 + 2;
5402 stbtt_uint16 end = ttUSHORT(data + end_count_base + s * 2);
5403 stbtt_uint16 start = ttUSHORT(data + start_count_base + s * 2);
5404 if(start == 0xFFFF && end == 0xFFFF)
5406 for(uint32_t cp = start; cp <= end && cp != 0xFFFFu; ++cp) {
5407 if(stbtt_FindGlyphIndex(info, (
int)cp) != 0)
5408 callback(cp, closure);
5411 }
else if(format == 12 || format == 13) {
5414 stbtt_uint32 start_char = ttULONG(data + index_map + 16 + g * 12);
5415 stbtt_uint32 end_char = ttULONG(data + index_map + 16 + g * 12 + 4);
5416 for(uint32_t cp = start_char; cp <= end_char; ++cp)
5417 callback(cp, closure);
5424 float scale = font_face_get_scale(face, size);
5425 if(ascent) *ascent = face->
ascent * scale;
5426 if(descent) *descent = face->
descent * scale;
5427 if(line_gap) *line_gap = face->
line_gap * scale;
5429 extents->
x = face->
x1 * scale;
5430 extents->
y = face->
y2 * -scale;
5431 extents->
w = (face->
x2 - face->
x1) * scale;
5432 extents->
h = (face->
y1 - face->
y2) * -scale;
5438 return glyph_cache_get(&face->
cache, face, codepoint);
5443 float scale = font_face_get_scale(face, size);
5468 float scale = font_face_get_scale(face, size);
5469 return static_cast<float>(stbtt_GetCodepointKernAdvance(&face->
info,
static_cast<int>(ch1),
static_cast<int>(ch2))) * scale;
5472static void glyph_traverse_func(
void* closure,
path_command_t command,
const point_t* points,
int npoints)
5483 path_cubic_to(
path, points[0].x, points[0].y, points[1].x, points[1].y, points[2].x, points[2].y);
5497 float scale = font_face_get_scale(face, size);
5503 point_t current_point = {0, 0};
5510 current_point = points[0];
5517 current_point = points[0];
5528 current_point = points[2];
5539 current_point = points[2];
5559 {{
'f',
'f',
'i'}, 3, 0xFB03}, {{
'f',
'f',
'l'}, 3, 0xFB04}, {{
'f',
'f', 0}, 2, 0xFB00},
5560 {{
'f',
'i', 0}, 2, 0xFB01}, {{
'f',
'l', 0}, 2, 0xFB02},
5565 for(
int c = 0; c < 5; ++c) {
5566 int glyphs[3] = {0, 0, 0};
5568 for(
int i = 0; i < candidates[c].len; ++i) {
5569 glyphs[i] = stbtt_FindGlyphIndex(&face->
info, candidates[c].seq[i]);
5573 int presentation = stbtt_FindGlyphIndex(&face->
info, candidates[c].ligature);
5574 if(!ok || presentation == 0)
5576 if(stbtt__GetGsubLigature(&face->
info, glyphs[0], glyphs + 1, candidates[c].len - 1) != presentation)
5579 for(
int i = 0; i < 3; ++i)
5580 e.seq[i] = candidates[c].seq[i];
5581 e.len = candidates[c].len;
5582 e.ligature = candidates[c].ligature;
5594 if(codepoint !=
'f')
5602 for(
int i = 1; i < e.len; ++i) {
5620 rect_t* text_extents = NULL;
5621 float total_advance_width = 0.f;
5623 bool has_previous =
false;
5629 previous = codepoint;
5630 has_previous =
true;
5632 float advance_width;
5633 if(extents == NULL) {
5635 total_advance_width += advance_width;
5642 glyph_extents.
x += total_advance_width;
5643 total_advance_width += advance_width;
5644 if(text_extents == NULL) {
5645 text_extents = extents;
5646 *text_extents = glyph_extents;
5652 float x2 =
NOVASVG_MAX(text_extents->
x + text_extents->
w, glyph_extents.
x + glyph_extents.
w);
5653 float y2 =
NOVASVG_MAX(text_extents->
y + text_extents->
h, glyph_extents.
y + glyph_extents.
h);
5655 text_extents->
x = x1;
5656 text_extents->
y = y1;
5657 text_extents->
w = x2 - x1;
5658 text_extents->
h = y2 - y1;
5661 if(extents && !text_extents) {
5668 return total_advance_width;
5726 for(
int i = 0; i < cache->
size; ++i) {
5749 for(
int i = 0; i < cache->
size; ++i) {
5772 if(family == NULL) family =
"";
5773 size_t family_length = strlen(family) + 1;
5777 entry->
family = (
char*)(entry + 1);
5778 memcpy(entry->
family, family, family_length);
5785 font_face_cache_add_entry(cache, entry);
5800 int a_score = (bold == a->
bold) + (italic == a->
italic);
5801 int b_score = (bold == b->
bold) + (italic == b->
italic);
5802 return a_score > b_score ? a : b;
5805static int font_face_entry_compare(
const void* a,
const void* b)
5809 return strcmp(a_entry->family, b_entry->family);
5817 qsort(cache->
entries, cache->
size,
sizeof(cache->
entries[0]), font_face_entry_compare);
5822 entry_key.
family = (
char*)(family);
5830 font_face_entry_compare
5838 selected = font_face_entry_select(entry, selected, bold, italic);
5839 entry = entry->
next;
5844 face = selected->
face;
5851#ifndef NOVASVG_DISABLE_FONT_FACE_CACHE_LOAD
5885#include <linux/limits.h>
5898#include <sys/mman.h>
5903#include <sys/stat.h>
5910static void* mmap(
const char* filename,
long* length)
5912 HANDLE file = CreateFileA(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
5913 if(file == INVALID_HANDLE_VALUE)
5915 DWORD size = GetFileSize(file, NULL);
5916 if(size == INVALID_FILE_SIZE) {
5921 HANDLE mapping = CreateFileMappingA(file, NULL, PAGE_READONLY, 0, 0, NULL);
5922 if(mapping == NULL) {
5927 void* data = MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0);
5928 CloseHandle(mapping);
5937static void unmap(
void* data,
long length)
5939 UnmapViewOfFile(data);
5944static void* mmap(
const char* filename,
long* length)
5946 int fd = open(filename, O_RDONLY);
5950 if(fstat(fd, &st) < 0) {
5955 if(st.st_size == 0) {
5960 void* data = ::mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
5963 if(data == MAP_FAILED)
5965 *length = st.st_size;
5969static void unmap(
void* data,
long length)
5971 munmap(data, length);
5986 int num_fonts = stbtt_GetNumberOfFonts(data);
5987 for(
int index = 0; index < num_fonts; ++index) {
5988 int offset = stbtt_GetFontOffsetForIndex(data, index);
5989 if(offset == -1 || !stbtt__isfont(data + offset)) {
5993 stbtt_uint32 nm = stbtt__find_table(data, offset,
"name");
5999 size_t family_length = 0;
6010 const stbtt_uint8* family_name = data + nm + ttUSHORT(data + nm + 4) + ttUSHORT(data + loc + 10);
6011 if(platform == 1 && encoding == 0) {
6012 family_length = ttUSHORT(data + loc + 8);
6013 roman_family_name = family_name;
6017 if(platform == 0 || (platform == 3 && encoding == 1) || (platform == 3 && encoding == 10)) {
6018 family_length = ttUSHORT(data + loc + 8);
6019 unicode_family_name = family_name;
6024 if(unicode_family_name == NULL && roman_family_name == NULL)
6026 size_t filename_length = strlen(filename) + 1;
6027 size_t max_family_length = (unicode_family_name ? 3 * (family_length / 2) : family_length * 3) + 1;
6030 entry->
family = (
char*)(entry + 1);
6032 memcpy(entry->
filename, filename, filename_length);
6034 size_t family_index = 0;
6035 if(unicode_family_name) {
6036 const stbtt_uint8* family_name = unicode_family_name;
6037 while(family_length) {
6038 stbtt_uint16 ch = family_name[0] * 256 + family_name[1];
6040 entry->
family[family_index++] = ch;
6041 }
else if(ch < 0x800) {
6042 entry->
family[family_index++] = (0xc0 + (ch >> 6));
6043 entry->
family[family_index++] = (0x80 + (ch & 0x3f));
6044 }
else if(ch >= 0xd800 && ch < 0xdc00) {
6045 stbtt_uint16 ch2 = family_name[2] * 256 + family_name[3];
6046 stbtt_uint32 c = ((ch - 0xd800) << 10) + (ch2 - 0xdc00) + 0x10000;
6048 entry->
family[family_index++] = (0xf0 + (c >> 18));
6049 entry->
family[family_index++] = (0x80 + ((c >> 12) & 0x3f));
6050 entry->
family[family_index++] = (0x80 + ((c >> 6) & 0x3f));
6051 entry->
family[family_index++] = (0x80 + ((c) & 0x3f));
6056 entry->
family[family_index++] = (0xe0 + (ch >> 12));
6057 entry->
family[family_index++] = (0x80 + ((ch >> 6) & 0x3f));
6058 entry->
family[family_index++] = (0x80 + ((ch) & 0x3f));
6065 entry->
family[family_index] =
'\0';
6068 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
6069 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
6070 0x0010, 0x2318, 0x21E7, 0x2325, 0x2303, 0x0015, 0x0016, 0x0017,
6071 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F,
6072 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
6073 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
6074 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
6075 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
6076 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
6077 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F,
6078 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
6079 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F,
6080 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
6081 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
6082 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
6083 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F,
6084 0x00C4, 0x00C5, 0x00C7, 0x00C9, 0x00D1, 0x00D6, 0x00DC, 0x00E1,
6085 0x00E0, 0x00E2, 0x00E4, 0x00E3, 0x00E5, 0x00E7, 0x00E9, 0x00E8,
6086 0x00EA, 0x00EB, 0x00ED, 0x00EC, 0x00EE, 0x00EF, 0x00F1, 0x00F3,
6087 0x00F2, 0x00F4, 0x00F6, 0x00F5, 0x00FA, 0x00F9, 0x00FB, 0x00FC,
6088 0x2020, 0x00B0, 0x00A2, 0x00A3, 0x00A7, 0x2022, 0x00B6, 0x00DF,
6089 0x00AE, 0x00A9, 0x2122, 0x00B4, 0x00A8, 0x2260, 0x00C6, 0x00D8,
6090 0x221E, 0x00B1, 0x2264, 0x2265, 0x00A5, 0x00B5, 0x2202, 0x2211,
6091 0x220F, 0x03C0, 0x222B, 0x00AA, 0x00BA, 0x03A9, 0x00E6, 0x00F8,
6092 0x00BF, 0x00A1, 0x00AC, 0x221A, 0x0192, 0x2248, 0x2206, 0x00AB,
6093 0x00BB, 0x2026, 0x00A0, 0x00C0, 0x00C3, 0x00D5, 0x0152, 0x0153,
6094 0x2013, 0x2014, 0x201C, 0x201D, 0x2018, 0x2019, 0x00F7, 0x25CA,
6095 0x00FF, 0x0178, 0x2044, 0x20AC, 0x2039, 0x203A, 0xFB01, 0xFB02,
6096 0x2021, 0x00B7, 0x201A, 0x201E, 0x2030, 0x00C2, 0x00CA, 0x00C1,
6097 0x00CB, 0x00C8, 0x00CD, 0x00CE, 0x00CF, 0x00CC, 0x00D3, 0x00D4,
6098 0xF8FF, 0x00D2, 0x00DA, 0x00DB, 0x00D9, 0x0131, 0x02C6, 0x02DC,
6099 0x00AF, 0x02D8, 0x02D9, 0x02DA, 0x00B8, 0x02DD, 0x02DB, 0x02C7,
6102 const stbtt_uint8* family_name = roman_family_name;
6103 while(family_length) {
6106 entry->
family[family_index++] = ch;
6107 }
else if(ch < 0x800) {
6108 entry->
family[family_index++] = (0xc0 + (ch >> 6));
6109 entry->
family[family_index++] = (0x80 + (ch & 0x3f));
6111 entry->
family[family_index++] = (0xe0 + (ch >> 12));
6112 entry->
family[family_index++] = (0x80 + ((ch >> 6) & 0x3f));
6113 entry->
family[family_index++] = (0x80 + ((ch) & 0x3f));
6120 entry->
family[family_index] =
'\0';
6124 entry->
bold =
false;
6128 stbtt_uint32 hd = stbtt__find_table(data, offset,
"head");
6136 font_face_cache_add_entry(cache, entry);
6140 unmap(data, length);
6144static bool font_face_supports_file(
const char* filename)
6146 const char* extension = strrchr(filename,
'.');
6149 size_t length = strlen(extension);
6151 for(
size_t i = 0; i < length; ++i)
6152 ext[i] = tolower(extension[i]);
6154 return strcmp(ext,
".ttf") == 0
6155 || strcmp(ext,
".otf") == 0
6156 || strcmp(ext,
".ttc") == 0
6157 || strcmp(ext,
".otc") == 0;
6168 char search_path[MAX_PATH];
6169 snprintf(search_path,
sizeof(search_path),
"%s\\*", dirname);
6171 WIN32_FIND_DATAA find_data;
6172 HANDLE handle = FindFirstFileA(search_path, &find_data);
6173 if(handle == INVALID_HANDLE_VALUE) {
6180 const char* name = find_data.cFileName;
6181 if(strcmp(name,
".") == 0 || strcmp(name,
"..") == 0)
6183 char path[MAX_PATH * 2];
6184 snprintf(path,
sizeof(path),
"%s\\%s", dirname, name);
6186 if(find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
6188 }
else if(font_face_supports_file(path)) {
6191 }
while(FindNextFileA(handle, &find_data));
6201 DIR* dir = opendir(dirname);
6208 struct dirent* entry;
6209 while((entry = readdir(dir)) != NULL) {
6210 if(strcmp(entry->d_name,
".") == 0 || strcmp(entry->d_name,
"..") == 0)
6212 char path[PATH_MAX];
6213 snprintf(
path,
sizeof(
path),
"%s/%s", dirname, entry->d_name);
6216 if(stat(
path, &st) == -1)
6218 if(S_ISDIR(st.st_mode)) {
6220 }
else if(S_ISREG(st.st_mode) && font_face_supports_file(
path)) {
6236#elif defined(__APPLE__)
6239#elif defined(__linux__)
#define NOVASVG_MAX(a, b)
#define NOVASVG_MIN(a, b)
NOVASVG_INLINE codepoint_t font_face_apply_ligature(font_face_t *face, text_iterator_t *it, codepoint_t codepoint)
NOVASVG_INLINE void font_face_cache_add(font_face_cache_t *cache, const char *family, bool bold, bool italic, font_face_t *face)
Add a font face to the cache with the specified family and style.
@ NOVASVG_PATH_COMMAND_CUBIC_TO
Draws a cubic Bézier curve to a new point.
@ NOVASVG_PATH_COMMAND_CLOSE
Closes the current path by drawing a line to the starting point.
@ NOVASVG_PATH_COMMAND_LINE_TO
Draws a straight line to a new point.
@ NOVASVG_PATH_COMMAND_MOVE_TO
Moves the current point to a new position.
NOVASVG_INLINE void font_face_cache_destroy(font_face_cache_t *cache)
Decrement the reference count of a font‐face cache and destroy it when it reaches zero.
NOVASVG_INLINE float font_face_text_extents(font_face_t *face, float size, const void *text, int length, text_encoding_t encoding, rect_t *extents)
Computes the bounding box of a text string and its advance width.
NOVASVG_INLINE float font_face_get_units_per_em(const font_face_t *face)
NOVASVG_INLINE int font_face_cache_load_dir(font_face_cache_t *cache, const char *dirname)
Load all font faces from files in a directory recursively and add them to the cache.
NOVASVG_INLINE void font_face_destroy(font_face_t *face)
Decrements the reference count and potentially destroys the font face.
NOVASVG_INLINE void path_move_to(path_t *path, float x, float y)
Moves the current point to a new position.
enum novasvg::render::path_command path_command_t
Enumeration defining path commands.
NOVASVG_INLINE void matrix_map_points(const matrix_t *matrix, const point_t *src, point_t *dst, int count)
Transforms an array of src points using matrix and stores the results in dst.
NOVASVG_INLINE float font_face_traverse_glyph_path(font_face_t *face, float size, float x, float y, codepoint_t codepoint, path_traverse_func_t traverse_func, void *closure)
Traverses the path of a glyph and calls a callback for each path element.
NOVASVG_INLINE void path_cubic_to(path_t *path, float x1, float y1, float x2, float y2, float x3, float y3)
Adds a cubic Bézier curve to the path.
struct novasvg::render::glyph glyph_t
unsigned int codepoint_t
Represents a Unicode code point.
NOVASVG_INLINE int font_face_cache_reference_count(const font_face_cache_t *cache)
Retrieve the current reference count of a font‐face cache.
NOVASVG_INLINE int font_face_get_reference_count(const font_face_t *face)
Retrieves the current reference count of a font face.
NOVASVG_INLINE font_face_cache_t * font_face_cache_reference(font_face_cache_t *cache)
Increments the reference count of a font‐face cache.
NOVASVG_INLINE font_face_t * font_face_load_from_data(const void *data, unsigned int length, int ttcindex, destroy_func_t destroy_func, void *closure)
Loads a font face from memory.
void(* path_traverse_func_t)(void *closure, path_command_t command, const point_t *points, int npoints)
Callback function type for traversing a path.
NOVASVG_INLINE font_face_t * font_face_load_from_file(const char *filename, int ttcindex)
Loads a font face from a file.
NOVASVG_INLINE void font_face_get_glyph_metrics(font_face_t *face, float size, codepoint_t codepoint, float *advance_width, float *left_side_bearing, rect_t *extents)
Retrieves metrics for a specified glyph at a given size.
NOVASVG_INLINE font_face_t * font_face_cache_get(font_face_cache_t *cache, const char *family, bool bold, bool italic)
Retrieve a font face from the cache by family and style.
void(* destroy_func_t)(void *closure)
A function pointer type for a cleanup callback.
NOVASVG_INLINE float font_face_get_kern_advance(font_face_t *face, float size, codepoint_t ch1, codepoint_t ch2)
NOVASVG_INLINE void font_face_enumerate_codepoints(const font_face_t *face, void(*callback)(uint32_t codepoint, void *closure), void *closure)
enum novasvg::render::text_encoding text_encoding_t
Text encodings used for converting text data to code points.
NOVASVG_INLINE void font_face_cache_reset(font_face_cache_t *cache)
Remove all entries from a font‐face cache.
NOVASVG_INLINE codepoint_t text_iterator_next(text_iterator_t *it)
Retrieves the next code point and advances the iterator.
@ NOVASVG_TEXT_ENCODING_UTF16
UTF-16 encoding.
@ NOVASVG_TEXT_ENCODING_UTF32
UTF-32 encoding.
@ NOVASVG_TEXT_ENCODING_UTF8
UTF-8 encoding.
@ NOVASVG_TEXT_ENCODING_LATIN1
Latin-1 encoding.
struct novasvg::render::font_face_entry font_face_entry_t
NOVASVG_INLINE void font_face_init_ligatures(font_face_t *face)
NOVASVG_INLINE void font_face_get_metrics(const font_face_t *face, float size, float *ascent, float *descent, float *line_gap, rect_t *extents)
Retrieves metrics for a font face at a specified size.
struct font_face_cache font_face_cache_t
Represents a cache of loaded font faces.
NOVASVG_INLINE bool text_iterator_has_next(const text_iterator_t *it)
Checks if there are more code points to iterate.
NOVASVG_INLINE int font_face_cache_load_file(font_face_cache_t *cache, const char *filename)
Load all font faces from a file and add them to the cache.
NOVASVG_INLINE void matrix_scale(matrix_t *matrix, float sx, float sy)
Scales the matrix by factors sx and sy
NOVASVG_INLINE bool font_face_cache_add_file(font_face_cache_t *cache, const char *family, bool bold, bool italic, const char *filename, int ttcindex)
Load a font face from a file and add it to the cache with the specified family and style.
NOVASVG_INLINE void path_line_to(path_t *path, float x, float y)
Adds a straight line segment to the path.
struct font_face font_face_t
Represents a font face.
NOVASVG_INLINE float font_face_get_glyph_path(font_face_t *face, float size, float x, float y, codepoint_t codepoint, path_t *path)
Retrieves the path of a glyph and its advance width.
NOVASVG_INLINE int font_face_cache_load_sys(font_face_cache_t *cache)
Load all available system font faces and add them to the cache.
NOVASVG_INLINE void text_iterator_init(text_iterator_t *it, const void *text, int length, text_encoding_t encoding)
Initializes a text iterator.
NOVASVG_INLINE void matrix_init_translate(matrix_t *matrix, float tx, float ty)
Initializes a 2D transformation matrix for translation.
NOVASVG_INLINE font_face_t * font_face_reference(font_face_t *face)
Increments the reference count of a font face.
NOVASVG_INLINE font_face_cache_t * font_face_cache_create(void)
Create a new, empty font‐face cache.
Main namespace for the NovaSVG library.
#define novasvg_get_reference_count(ob)
#define novasvg_destroy_reference(ob)
#define novasvg_init_reference(ob)
#define novasvg_increment_reference(ob)
@ STBTT_MAC_EID_CHINESE_TRAD
#define stbtt__buf_get16(b)
unsigned int stbtt_uint32
#define novasvg_mutex_init(mutex)
#define STBTT__NOTUSED(v)
#define novasvg_mutex_lock(mutex)
#define STBTT_MAX_OVERSAMPLE
#define stbtt_tag4(p, c0, c1, c2, c3)
@ STBTT_UNICODE_EID_ISO_10646
@ STBTT_UNICODE_EID_UNICODE_2_0_BMP
@ STBTT_UNICODE_EID_UNICODE_2_0_FULL
@ STBTT_UNICODE_EID_UNICODE_1_1
@ STBTT_UNICODE_EID_UNICODE_1_0
int stbtt__test_oversample_pow2[(8 &(8 -1))==0 ? 1 :-1]
char stbtt__check_size16[sizeof(stbtt_int16)==2 ? 1 :-1]
unsigned char stbtt_uint8
#define GLYPH_CACHE_INIT_CAPACITY
#define novasvg_mutex_destroy(mutex)
@ STBTT_MS_EID_UNICODE_FULL
@ STBTT_MS_EID_UNICODE_BMP
#define STBTT__COMPARE(a, b)
#define STBTT_malloc(x, u)
#define stbtt_tag(p, str)
#define stbtt__buf_get32(b)
#define novasvg_mutex_unlock(mutex)
@ STBTT_MAC_LANG_CHINESE_SIMPLIFIED
@ STBTT_MAC_LANG_JAPANESE
@ STBTT_MAC_LANG_CHINESE_TRAD
#define stbtt_vertex_type
unsigned short stbtt_uint16
#define STBTT__CSCTX_INIT(bounds)
@ STBTT_PLATFORM_ID_UNICODE
@ STBTT_PLATFORM_ID_MICROSOFT
char stbtt__check_size32[sizeof(stbtt_int32)==4 ? 1 :-1]
font_face_entry_t ** entries
struct font_face_entry * next
struct novasvg::render::font_face::@10 ligatures[5]
destroy_func_t destroy_func
A structure representing a 2D transformation matrix.
A structure representing a point in 2D space.
float y
The y-coordinate of the point.
float x
The x-coordinate of the point.
A structure representing a rectangle in 2D space.
float x
The x-coordinate of the top-left corner of the rectangle.
float w
The width of the rectangle.
float h
The height of the rectangle.
float y
The y-coordinate of the top-left corner of the rectangle.
Iterator for traversing code points in text data.
text_encoding_t encoding
Encoding format of the text data.
int length
Length of the text data.
const void * text
Pointer to the text data.
int index
Current position in the text data.
struct stbtt__active_edge * next
struct stbtt__hheap_chunk * next
struct stbtt__hheap_chunk * head
int num_remaining_in_head_chunk
void * user_allocator_context
unsigned int v_oversample
unsigned int h_oversample
int * array_of_unicode_codepoints
int first_unicode_codepoint_in_range
unsigned char v_oversample
unsigned char h_oversample
stbtt_packedchar * chardata_for_range
std::string text
UTF-8; ' ' marks a forced line break ( ,.