History

update stb header and remove c2g crappy search

Sigrid Solveig Haflínudóttir committed 5 years ago

Commit e771f321 parent b43d58c3 files · +366 −408Browse files

Unified · Split

3 files
  1. pt.c +14 −12
  2. pt_private.h +0 −2
  3. stb_truetype.h +352 −394
pt.c+14−12
@@ -67,6 +67,18 @@ utf16to8(uchar *o, int osz, const uchar *s, int sz) · 66 unmodified lines
67}67}
68 68
69#define STB_TRUETYPE_IMPLEMENTATION69#define STB_TRUETYPE_IMPLEMENTATION
70static void *
71STBTT_malloc(int x, void *)
72{
73 return malloc(x);
74}
75static void
76STBTT_free(void *p, void *)
77{
78 free(p);
79}
80#define STBTT_malloc STBTT_malloc
81#define STBTT_free STBTT_free
70#define STBTT_ifloor(x) ((int)floor(x))82#define STBTT_ifloor(x) ((int)floor(x))
71#define STBTT_iceil(x) ((int)ceil(x))83#define STBTT_iceil(x) ((int)ceil(x))
72#define STBTT_sqrt(x) sqrt(x)84#define STBTT_sqrt(x) sqrt(x)
@@ -75,15 +87,13 @@ utf16to8(uchar *o, int osz, const uchar *s, int sz) · 2 unmodified lines
75#define STBTT_cos(x) cos(x)87#define STBTT_cos(x) cos(x)
76#define STBTT_acos(x) acos(x)88#define STBTT_acos(x) acos(x)
77#define STBTT_fabs(x) fabs(x)89#define STBTT_fabs(x) fabs(x)
78#define STBTT_malloc(x,u) ((void)(u),malloc(x))
79#define STBTT_free(x,u) ((void)(u),free(x))
80#define STBTT_assert(x) assert(x)90#define STBTT_assert(x) assert(x)
81#define STBTT_strlen(x) strlen(x)91#define STBTT_strlen(x) strlen(x)
82#define STBTT_memcpy memmove92#define STBTT_memcpy memmove
83#define STBTT_memset memset93#define STBTT_memset memset
84typedef usize size_t;94typedef usize size_t;
85#define NULL nil95#define NULL nil
86#define STBTT_RASTERIZER_VERSION 1 /* that one is definitely FASTER on amd64 */96#define STBTT_RASTERIZER_VERSION 2 /* that one is definitely FASTER on amd64 */
87#include "pt_private.h"97#include "pt_private.h"
88 98
89Sfont *99Sfont *
@@ -95,7 +105,6 @@ pt_font(uchar *data, float height) · 5 unmodified lines
95 if(stbtt_InitFont(&f->fi, data, stbtt_GetFontOffsetForIndex(data, 0)) == 0)105 if(stbtt_InitFont(&f->fi, data, stbtt_GetFontOffsetForIndex(data, 0)) == 0)
96 goto err;106 goto err;
97 107
98 f->c2g = stbtt_Code2Glyph(&f->fi);
99 f->scale = stbtt_ScaleForPixelHeight(&f->fi, height);108 f->scale = stbtt_ScaleForPixelHeight(&f->fi, height);
100 f->height = height;109 f->height = height;
101 stbtt_GetFontVMetrics(&f->fi, &f->asc, &f->desc, &f->linegap);110 stbtt_GetFontVMetrics(&f->fi, &f->asc, &f->desc, &f->linegap);
@@ -127,7 +136,6 @@ pt_freefont(Sfont *f) · 25 unmodified lines
127{136{
128 if(f == nil)137 if(f == nil)
129 return;138 return;
130 free(f->c2g);
131 freememimage(f->g);139 freememimage(f->g);
132 freememimage(f->b);140 freememimage(f->b);
133 free(f);141 free(f);
@@ -156,13 +164,7 @@ bsearch(u32int c, u32int *t, int n) · 22 unmodified lines
156static int164static int
157code2glyph(Sfont *f, u32int c)165code2glyph(Sfont *f, u32int c)
158{166{
159 u32int *r;167 return stbtt_FindGlyphIndex(&f->fi, c);
160
161 if(f->c2g == nil)
162 return stbtt_FindGlyphIndex(&f->fi, c);
163 if((r = bsearch(c, f->c2g->code, f->c2g->num)) != nil)
164 return f->c2g->glyph[r - f->c2g->code];
165 return 0;
166}168}
167 169
168Rectangle170Rectangle
pt_private.h+0−2
@@ -4,8 +4,6 @@ struct Sfont { · 3 unmodified lines
4 Memimage *g;4 Memimage *g;
5 Memimage *b;5 Memimage *b;
6 6
7 stbtt_code2glyph *c2g;
8
9 Rectangle bb;7 Rectangle bb;
10 float scale;8 float scale;
11 float height;9 float height;
stb_truetype.h+352−394
@@ -1,5 +1,5 @@
1// stb_truetype.h - v1.24 - public domain1// stb_truetype.h - v1.26 - public domain
2// authored from 2009-2020 by Sean Barrett / RAD Game Tools2// authored from 2009-2021 by Sean Barrett / RAD Game Tools
3//3//
4// =======================================================================4// =======================================================================
5//5//
@@ -53,11 +53,13 @@ · 47 unmodified lines
53// Johan Duparc Thomas Fields53// Johan Duparc Thomas Fields
54// Hou Qiming Derek Vinyard54// Hou Qiming Derek Vinyard
55// Rob Loach Cort Stratton55// Rob Loach Cort Stratton
56// Kenney Phillis Jr. Brian Costabile 56// Kenney Phillis Jr. Brian Costabile
57// Ken Voskuil (kaesve) 57// Ken Voskuil (kaesve)
58//58//
59// VERSION HISTORY59// VERSION HISTORY
60//60//
61// 1.26 (2021-08-28) fix broken rasterizer
62// 1.25 (2021-07-11) many fixes
61// 1.24 (2020-02-05) fix warning63// 1.24 (2020-02-05) fix warning
62// 1.23 (2020-02-02) query SVG data for glyphs; query whole kerning table (but only kern not GPOS)64// 1.23 (2020-02-02) query SVG data for glyphs; query whole kerning table (but only kern not GPOS)
63// 1.22 (2019-08-11) minimize missing-glyph duplication; fix kerning if both 'GPOS' and 'kern' are defined65// 1.22 (2019-08-11) minimize missing-glyph duplication; fix kerning if both 'GPOS' and 'kern' are defined
@@ -270,8 +272,8 @@ · 206 unmodified lines
270//// SAMPLE PROGRAMS272//// SAMPLE PROGRAMS
271////273////
272//274//
273// Incomplete text-in-3d-api example, which draws quads properly aligned to be lossless275// Incomplete text-in-3d-api example, which draws quads properly aligned to be lossless.
274//276// See "tests/truetype_demo_win32.c" for a complete version.
275#if 0277#if 0
276#define STB_TRUETYPE_IMPLEMENTATION // force following include to generate implementation278#define STB_TRUETYPE_IMPLEMENTATION // force following include to generate implementation
277#include "stb_truetype.h"279#include "stb_truetype.h"
@@ -297,6 +299,8 @@ void my_stbtt_initfont(void) · 19 unmodified lines
297void my_stbtt_print(float x, float y, char *text)299void my_stbtt_print(float x, float y, char *text)
298{300{
299 // assume orthographic projection with units = screen pixels, origin at top left301 // assume orthographic projection with units = screen pixels, origin at top left
302 glEnable(GL_BLEND);
303 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
300 glEnable(GL_TEXTURE_2D);304 glEnable(GL_TEXTURE_2D);
301 glBindTexture(GL_TEXTURE_2D, ftex);305 glBindTexture(GL_TEXTURE_2D, ftex);
302 glBegin(GL_QUADS);306 glBegin(GL_QUADS);
@@ -304,10 +308,10 @@ void my_stbtt_print(float x, float y, char *text) · 1 unmodified line
304 if (*text >= 32 && *text < 128) {308 if (*text >= 32 && *text < 128) {
305 stbtt_aligned_quad q;309 stbtt_aligned_quad q;
306 stbtt_GetBakedQuad(cdata, 512,512, *text-32, &x,&y,&q,1);//1=opengl & d3d10+,0=d3d9310 stbtt_GetBakedQuad(cdata, 512,512, *text-32, &x,&y,&q,1);//1=opengl & d3d10+,0=d3d9
307 glTexCoord2f(q.s0,q.t1); glVertex2f(q.x0,q.y0);311 glTexCoord2f(q.s0,q.t0); glVertex2f(q.x0,q.y0);
308 glTexCoord2f(q.s1,q.t1); glVertex2f(q.x1,q.y0);312 glTexCoord2f(q.s1,q.t0); glVertex2f(q.x1,q.y0);
309 glTexCoord2f(q.s1,q.t0); glVertex2f(q.x1,q.y1);313 glTexCoord2f(q.s1,q.t1); glVertex2f(q.x1,q.y1);
310 glTexCoord2f(q.s0,q.t0); glVertex2f(q.x0,q.y1);314 glTexCoord2f(q.s0,q.t1); glVertex2f(q.x0,q.y1);
311 }315 }
312 ++text;316 ++text;
313 }317 }
@@ -717,10 +721,6 @@ struct stbtt_fontinfo · 403 unmodified lines
717 int loca,head,glyf,hhea,hmtx,kern,gpos,svg; // table locations as offset from start of .ttf721 int loca,head,glyf,hhea,hmtx,kern,gpos,svg; // table locations as offset from start of .ttf
718 int index_map; // a cmap mapping for our chosen character encoding722 int index_map; // a cmap mapping for our chosen character encoding
719 int indexToLocFormat; // format needed to map from glyph index to glyph723 int indexToLocFormat; // format needed to map from glyph index to glyph
720 int underlinePosition;
721 int underlineThickness;
722 char family[128];
723 char subfamily[128];
724 724
725 stbtt__buf cff; // cff font data725 stbtt__buf cff; // cff font data
726 stbtt__buf charstrings; // the charstring index726 stbtt__buf charstrings; // the charstring index
@@ -857,6 +857,7 @@ STBTT_DEF int stbtt_GetGlyphShape(const stbtt_fontinfo *info, int glyph_index, s · 130 unmodified lines
857STBTT_DEF void stbtt_FreeShape(const stbtt_fontinfo *info, stbtt_vertex *vertices);857STBTT_DEF void stbtt_FreeShape(const stbtt_fontinfo *info, stbtt_vertex *vertices);
858// frees the data allocated above858// frees the data allocated above
859 859
860STBTT_DEF unsigned char *stbtt_FindSVGDoc(const stbtt_fontinfo *info, int gl);
860STBTT_DEF int stbtt_GetCodepointSVG(const stbtt_fontinfo *info, int unicode_codepoint, const char **svg);861STBTT_DEF int stbtt_GetCodepointSVG(const stbtt_fontinfo *info, int unicode_codepoint, const char **svg);
861STBTT_DEF int stbtt_GetGlyphSVG(const stbtt_fontinfo *info, int gl, const char **svg);862STBTT_DEF int stbtt_GetGlyphSVG(const stbtt_fontinfo *info, int gl, const char **svg);
862// fills svg with the character's SVG data.863// fills svg with the character's SVG data.
@@ -1382,9 +1383,7 @@ static int stbtt__get_svg(stbtt_fontinfo *info) · 519 unmodified lines
1382static int stbtt_InitFont_internal(stbtt_fontinfo *info, unsigned char *data, int fontstart)1383static int stbtt_InitFont_internal(stbtt_fontinfo *info, unsigned char *data, int fontstart)
1383{1384{
1384 stbtt_uint32 cmap, t;1385 stbtt_uint32 cmap, t;
1385 stbtt_int32 i, numTables;1386 stbtt_int32 i,numTables;
1386
1387 memset(info, 0, sizeof(*info));
1388 1387
1389 info->data = data;1388 info->data = data;
1390 info->fontstart = fontstart;1389 info->fontstart = fontstart;
@@ -1462,43 +1461,6 @@ static int stbtt_InitFont_internal(stbtt_fontinfo *info, unsigned char *data, in · 71 unmodified lines
1462 1461
1463 info->svg = -1;1462 info->svg = -1;
1464 1463
1465 t = stbtt__find_table(data, fontstart, "post");
1466 if (t) {
1467 info->underlinePosition = ttSHORT(data+t+8);
1468 info->underlineThickness = ttUSHORT(data+t+10);
1469 }
1470
1471 t = stbtt__find_table(data, fontstart, "name");
1472 if (t) {
1473 stbtt_int32 i, platform, name, count, stringOffset, length;
1474 stbtt_uint8 *fc = data;
1475 stbtt_uint32 offset = fontstart;
1476 stbtt_uint32 nm = stbtt__find_table(fc, offset, "name");
1477 char *o, tmp[256];
1478
1479 count = ttUSHORT(fc+nm+2);
1480 stringOffset = nm + ttUSHORT(fc+nm+4);
1481 for (i=0; i < count; ++i) {
1482 stbtt_uint32 loc = nm + 6 + 12 * i;
1483 platform = ttUSHORT(fc+loc+0);
1484 if (platform != 0 && platform != 1)
1485 continue;
1486 name = ttUSHORT(fc+loc+6);
1487 if (name != 1 && name != 2) /* FIXME use 16 and 17? */
1488 continue;
1489 length = ttUSHORT(fc+loc+8);
1490 o = (char*)fc+stringOffset+ttUSHORT(fc+loc+10);
1491 if (platform == 0) {
1492 length = utf16to8((uchar*)tmp, sizeof(tmp), (uchar*)o, length);
1493 o = tmp;
1494 }
1495 if (name == 1)
1496 snprint(info->family, sizeof(info->family), "%.*s", length, o);
1497 else if (name == 2)
1498 snprint(info->subfamily, sizeof(info->subfamily), "%.*s", length, o);
1499 }
1500 }
1501
1502 // find a cmap encoding table we understand *now* to avoid searching1464 // find a cmap encoding table we understand *now* to avoid searching
1503 // later. (todo: could make this installable)1465 // later. (todo: could make this installable)
1504 // the same regardless of glyph.1466 // the same regardless of glyph.
@@ -1531,64 +1493,6 @@ static int stbtt_InitFont_internal(stbtt_fontinfo *info, unsigned char *data, in · 26 unmodified lines
1531 return 1;1493 return 1;
1532}1494}
1533 1495
1534typedef struct stbtt_code2glyph stbtt_code2glyph;
1535
1536struct stbtt_code2glyph {
1537 u32int *code;
1538 u16int *glyph;
1539 int num;
1540};
1541
1542STBTT_DEF stbtt_code2glyph *stbtt_Code2Glyph(const stbtt_fontinfo *info) {
1543 stbtt_uint8 *data = info->data;
1544 stbtt_uint32 index_map = info->index_map;
1545 stbtt_code2glyph *c2g;
1546 int i;
1547 stbtt_uint16 format = ttUSHORT(data + index_map + 0);
1548
1549 if(format == 4) // FIXME
1550 return NULL;
1551
1552 c2g = mallocz(sizeof(*c2g) + info->numGlyphs*6, 1);
1553 c2g->code = (u32int*)(c2g + 1);
1554 c2g->glyph = (u16int*)(c2g->code + info->numGlyphs);
1555 c2g->num = info->numGlyphs;
1556
1557 if (format == 0) { // apple byte encoding
1558 stbtt_int32 bytes = ttUSHORT(data + index_map + 2);
1559 for(i = 0; i < bytes-6; i++){
1560 c2g->code[i] = i;
1561 c2g->glyph[i] = ttBYTE(data + index_map + 6 + i);
1562 }
1563 } else if (format == 6) {
1564 stbtt_int32 first = ttUSHORT(data + index_map + 6);
1565 stbtt_int32 count = ttUSHORT(data + index_map + 8);
1566 for(i = 0; i < count; i++){
1567 c2g->code[i] = first + i;
1568 c2g->glyph[i] = ttUSHORT(data + index_map + 10 + i*2);
1569 }
1570 } else if (format == 2) {
1571 STBTT_assert(format == 2 && 0); // @TODO: high-byte mapping for japanese/chinese/korean
1572 } else if (format == 12 || format == 13) {
1573 stbtt_uint32 ngroups = ttULONG(data+index_map+12);
1574 stbtt_uint32 g, ch;
1575 for(i = 0, g = 0; g < ngroups; g++){
1576 stbtt_uint32 start_char = ttULONG(data+index_map+16+g*12);
1577 stbtt_uint32 end_char = ttULONG(data+index_map+16+g*12+4);
1578 stbtt_uint32 start_glyph = ttULONG(data+index_map+16+g*12+8);
1579 for(ch = start_char; ch <= end_char; ch++, i++){
1580 c2g->code[i] = ch;
1581 c2g->glyph[i] = format == 12 ? start_glyph+ch-start_char : start_glyph;
1582 }
1583 }
1584 } else {
1585 // @TODO
1586 STBTT_assert(0);
1587 }
1588
1589 return c2g;
1590}
1591
1592STBTT_DEF int stbtt_FindGlyphIndex(const stbtt_fontinfo *info, int unicode_codepoint)1496STBTT_DEF int stbtt_FindGlyphIndex(const stbtt_fontinfo *info, int unicode_codepoint)
1593{1497{
1594 stbtt_uint8 *data = info->data;1498 stbtt_uint8 *data = info->data;
@@ -1640,12 +1544,12 @@ STBTT_DEF int stbtt_FindGlyphIndex(const stbtt_fontinfo *info, int unicode_codep · 45 unmodified lines
1640 search += 2;1544 search += 2;
1641 1545
1642 {1546 {
1643 stbtt_uint16 offset, start;1547 stbtt_uint16 offset, start, last;
1644 stbtt_uint16 item = (stbtt_uint16) ((search - endCount) >> 1);1548 stbtt_uint16 item = (stbtt_uint16) ((search - endCount) >> 1);
1645 1549
1646 STBTT_assert(unicode_codepoint <= ttUSHORT(data + endCount + 2*item));
1647 start = ttUSHORT(data + index_map + 14 + segcount*2 + 2 + 2*item);1550 start = ttUSHORT(data + index_map + 14 + segcount*2 + 2 + 2*item);
1648 if (unicode_codepoint < start)1551 last = ttUSHORT(data + endCount + 2*item);
1552 if (unicode_codepoint < start || unicode_codepoint > last)
1649 return 0;1553 return 0;
1650 1554
1651 offset = ttUSHORT(data + index_map + 14 + segcount*6 + 2 + 2*item);1555 offset = ttUSHORT(data + index_map + 14 + segcount*6 + 2 + 2*item);
@@ -1972,7 +1876,7 @@ static int stbtt__GetGlyphShapeTT(const stbtt_fontinfo *info, int glyph_index, s · 320 unmodified lines
1972 if (comp_verts) STBTT_free(comp_verts, info->userdata);1876 if (comp_verts) STBTT_free(comp_verts, info->userdata);
1973 return 0;1877 return 0;
1974 }1878 }
1975 if (num_vertices > 0) STBTT_memcpy(tmp, vertices, num_vertices*sizeof(stbtt_vertex));1879 if (num_vertices > 0 && vertices) STBTT_memcpy(tmp, vertices, num_vertices*sizeof(stbtt_vertex));
1976 STBTT_memcpy(tmp+num_vertices, comp_verts, comp_num_verts*sizeof(stbtt_vertex));1880 STBTT_memcpy(tmp+num_vertices, comp_verts, comp_num_verts*sizeof(stbtt_vertex));
1977 if (vertices) STBTT_free(vertices, info->userdata);1881 if (vertices) STBTT_free(vertices, info->userdata);
1978 vertices = tmp;1882 vertices = tmp;
@@ -2235,7 +2139,7 @@ static int stbtt__run_charstring(const stbtt_fontinfo *info, int glyph_index, st · 256 unmodified lines
2235 subrs = stbtt__cid_get_glyph_subrs(info, glyph_index);2139 subrs = stbtt__cid_get_glyph_subrs(info, glyph_index);
2236 has_subrs = 1;2140 has_subrs = 1;
2237 }2141 }
2238 // fallthrough2142 // FALLTHROUGH
2239 case 0x1D: // callgsubr2143 case 0x1D: // callgsubr
2240 if (sp < 1) return STBTT__CSERR("call(g|)subr stack");2144 if (sp < 1) return STBTT__CSERR("call(g|)subr stack");
2241 v = (int) s[--sp];2145 v = (int) s[--sp];
@@ -2340,7 +2244,7 @@ static int stbtt__run_charstring(const stbtt_fontinfo *info, int glyph_index, st · 98 unmodified lines
2340 } break;2244 } break;
2341 2245
2342 default:2246 default:
2343 if (b0 != 255 && b0 != 28 && (b0 < 32 || b0 > 254))2247 if (b0 != 255 && b0 != 28 && b0 < 32)
2344 return STBTT__CSERR("reserved operator");2248 return STBTT__CSERR("reserved operator");
2345 2249
2346 // push immediate2250 // push immediate
@@ -2452,7 +2356,7 @@ STBTT_DEF int stbtt_GetKerningTable(const stbtt_fontinfo *info, stbtt_kerningent · 105 unmodified lines
2452 return length;2356 return length;
2453}2357}
2454 2358
2455static int stbtt__GetGlyphKernInfoAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2)2359static int stbtt__GetGlyphKernInfoAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2)
2456{2360{
2457 stbtt_uint8 *data = info->data + info->kern;2361 stbtt_uint8 *data = info->data + info->kern;
2458 stbtt_uint32 needle, straw;2362 stbtt_uint32 needle, straw;
@@ -2482,247 +2386,225 @@ static int stbtt__GetGlyphKernInfoAdvance(const stbtt_fontinfo *info, int glyph · 23 unmodified lines
2482 return 0;2386 return 0;
2483}2387}
2484 2388
2485static stbtt_int32 stbtt__GetCoverageIndex(stbtt_uint8 *coverageTable, int glyph)2389static stbtt_int32 stbtt__GetCoverageIndex(stbtt_uint8 *coverageTable, int glyph)
2486{2390{
2487 stbtt_uint16 coverageFormat = ttUSHORT(coverageTable);2391 stbtt_uint16 coverageFormat = ttUSHORT(coverageTable);
2488 switch(coverageFormat) {2392 switch (coverageFormat) {
2489 case 1: {2393 case 1: {
2490 stbtt_uint16 glyphCount = ttUSHORT(coverageTable + 2);2394 stbtt_uint16 glyphCount = ttUSHORT(coverageTable + 2);
2491 2395
2492 // Binary search.2396 // Binary search.
2493 stbtt_int32 l=0, r=glyphCount-1, m;2397 stbtt_int32 l=0, r=glyphCount-1, m;
2494 int straw, needle=glyph;2398 int straw, needle=glyph;
2495 while (l <= r) {2399 while (l <= r) {
2496 stbtt_uint8 *glyphArray = coverageTable + 4;2400 stbtt_uint8 *glyphArray = coverageTable + 4;
2497 stbtt_uint16 glyphID;2401 stbtt_uint16 glyphID;
2498 m = (l + r) >> 1;2402 m = (l + r) >> 1;
2499 glyphID = ttUSHORT(glyphArray + 2 * m);2403 glyphID = ttUSHORT(glyphArray + 2 * m);
2500 straw = glyphID;2404 straw = glyphID;
2501 if (needle < straw)2405 if (needle < straw)
2502 r = m - 1;2406 r = m - 1;
2503 else if (needle > straw)2407 else if (needle > straw)
2504 l = m + 1;2408 l = m + 1;
2505 else {2409 else {
2506 return m;2410 return m;
2507 }
2508 }2411 }
2509 } break;2412 }
2510 2413 break;
2511 case 2: {2414 }
2512 stbtt_uint16 rangeCount = ttUSHORT(coverageTable + 2);2415
2513 stbtt_uint8 *rangeArray = coverageTable + 4;2416 case 2: {
2514 2417 stbtt_uint16 rangeCount = ttUSHORT(coverageTable + 2);
2515 // Binary search.2418 stbtt_uint8 *rangeArray = coverageTable + 4;
2516 stbtt_int32 l=0, r=rangeCount-1, m;2419
2517 int strawStart, strawEnd, needle=glyph;2420 // Binary search.
2518 while (l <= r) {2421 stbtt_int32 l=0, r=rangeCount-1, m;
2519 stbtt_uint8 *rangeRecord;2422 int strawStart, strawEnd, needle=glyph;
2520 m = (l + r) >> 1;2423 while (l <= r) {
2521 rangeRecord = rangeArray + 6 * m;2424 stbtt_uint8 *rangeRecord;
2522 strawStart = ttUSHORT(rangeRecord);2425 m = (l + r) >> 1;
2523 strawEnd = ttUSHORT(rangeRecord + 2);2426 rangeRecord = rangeArray + 6 * m;
2524 if (needle < strawStart)2427 strawStart = ttUSHORT(rangeRecord);
2525 r = m - 1;2428 strawEnd = ttUSHORT(rangeRecord + 2);
2526 else if (needle > strawEnd)2429 if (needle < strawStart)
2527 l = m + 1;2430 r = m - 1;
2528 else {2431 else if (needle > strawEnd)
2529 stbtt_uint16 startCoverageIndex = ttUSHORT(rangeRecord + 4);2432 l = m + 1;
2530 return startCoverageIndex + glyph - strawStart;2433 else {
2531 }2434 stbtt_uint16 startCoverageIndex = ttUSHORT(rangeRecord + 4);
2435 return startCoverageIndex + glyph - strawStart;
2532 }2436 }
2533 } break;2437 }
2438 break;
2439 }
2534 2440
2535 default: {2441 default: return -1; // unsupported
2536 // There are no other cases.2442 }
2537 STBTT_assert(0);
2538 } break;
2539 }
2540 2443
2541 return -1;2444 return -1;
2542}2445}
2543 2446
2544static stbtt_int32 stbtt__GetGlyphClass(stbtt_uint8 *classDefTable, int glyph)2447static stbtt_int32 stbtt__GetGlyphClass(stbtt_uint8 *classDefTable, int glyph)
2545{2448{
2546 stbtt_uint16 classDefFormat = ttUSHORT(classDefTable);2449 stbtt_uint16 classDefFormat = ttUSHORT(classDefTable);
2547 switch(classDefFormat)2450 switch (classDefFormat)
2548 {2451 {
2549 case 1: {2452 case 1: {
2550 stbtt_uint16 startGlyphID = ttUSHORT(classDefTable + 2);2453 stbtt_uint16 startGlyphID = ttUSHORT(classDefTable + 2);
2551 stbtt_uint16 glyphCount = ttUSHORT(classDefTable + 4);2454 stbtt_uint16 glyphCount = ttUSHORT(classDefTable + 4);
2552 stbtt_uint8 *classDef1ValueArray = classDefTable + 6;2455 stbtt_uint8 *classDef1ValueArray = classDefTable + 6;
2553
2554 if (glyph >= startGlyphID && glyph < startGlyphID + glyphCount)
2555 return (stbtt_int32)ttUSHORT(classDef1ValueArray + 2 * (glyph - startGlyphID));
2556
2557 classDefTable = classDef1ValueArray + 2 * glyphCount;
2558 USED(classDefTable);
2559 } break;
2560
2561 case 2: {
2562 stbtt_uint16 classRangeCount = ttUSHORT(classDefTable + 2);
2563 stbtt_uint8 *classRangeRecords = classDefTable + 4;
2564
2565 // Binary search.
2566 stbtt_int32 l=0, r=classRangeCount-1, m;
2567 int strawStart, strawEnd, needle=glyph;
2568 while (l <= r) {
2569 stbtt_uint8 *classRangeRecord;
2570 m = (l + r) >> 1;
2571 classRangeRecord = classRangeRecords + 6 * m;
2572 strawStart = ttUSHORT(classRangeRecord);
2573 strawEnd = ttUSHORT(classRangeRecord + 2);
2574 if (needle < strawStart)
2575 r = m - 1;
2576 else if (needle > strawEnd)
2577 l = m + 1;
2578 else
2579 return (stbtt_int32)ttUSHORT(classRangeRecord + 4);
2580 }
2581 2456
2582 classDefTable = classRangeRecords + 6 * classRangeCount;2457 if (glyph >= startGlyphID && glyph < startGlyphID + glyphCount)
2583 USED(classDefTable);2458 return (stbtt_int32)ttUSHORT(classDef1ValueArray + 2 * (glyph - startGlyphID));
2584 } break;2459 break;
2460 }
2585 2461
2586 default: {2462 case 2: {
2587 // There are no other cases.2463 stbtt_uint16 classRangeCount = ttUSHORT(classDefTable + 2);
2588 STBTT_assert(0);2464 stbtt_uint8 *classRangeRecords = classDefTable + 4;
2589 } break;2465
2590 }2466 // Binary search.
2467 stbtt_int32 l=0, r=classRangeCount-1, m;
2468 int strawStart, strawEnd, needle=glyph;
2469 while (l <= r) {
2470 stbtt_uint8 *classRangeRecord;
2471 m = (l + r) >> 1;
2472 classRangeRecord = classRangeRecords + 6 * m;
2473 strawStart = ttUSHORT(classRangeRecord);
2474 strawEnd = ttUSHORT(classRangeRecord + 2);
2475 if (needle < strawStart)
2476 r = m - 1;
2477 else if (needle > strawEnd)
2478 l = m + 1;
2479 else
2480 return (stbtt_int32)ttUSHORT(classRangeRecord + 4);
2481 }
2482 break;
2483 }
2591 2484
2592 return -1;2485 default:
2486 return -1; // Unsupported definition type, return an error.
2487 }
2488
2489 // "All glyphs not assigned to a class fall into class 0". (OpenType spec)
2490 return 0;
2593}2491}
2594 2492
2595// Define to STBTT_assert(x) if you want to break on unimplemented formats.2493// Define to STBTT_assert(x) if you want to break on unimplemented formats.
2596#define STBTT_GPOS_TODO_assert(x)2494#define STBTT_GPOS_TODO_assert(x)
2597 2495
2598static stbtt_int32 stbtt__GetGlyphGPOSInfoAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2)2496static stbtt_int32 stbtt__GetGlyphGPOSInfoAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2)
2599{2497{
2600 stbtt_uint16 lookupListOffset;2498 stbtt_uint16 lookupListOffset;
2601 stbtt_uint8 *lookupList;2499 stbtt_uint8 *lookupList;
2602 stbtt_uint16 lookupCount;2500 stbtt_uint16 lookupCount;
2603 stbtt_uint8 *data;2501 stbtt_uint8 *data;
2604 stbtt_int32 i;2502 stbtt_int32 i, sti;
2605 2503
2606 if (!info->gpos) return 0;2504 if (!info->gpos) return 0;
2607 2505
2608 data = info->data + info->gpos;2506 data = info->data + info->gpos;
2609 2507
2610 if (ttUSHORT(data+0) != 1) return 0; // Major version 12508 if (ttUSHORT(data+0) != 1) return 0; // Major version 1
2611 if (ttUSHORT(data+2) != 0) return 0; // Minor version 02509 if (ttUSHORT(data+2) != 0) return 0; // Minor version 0
2612 2510
2613 lookupListOffset = ttUSHORT(data+8);2511 lookupListOffset = ttUSHORT(data+8);
2614 lookupList = data + lookupListOffset;2512 lookupList = data + lookupListOffset;
2615 lookupCount = ttUSHORT(lookupList);2513 lookupCount = ttUSHORT(lookupList);
2616 2514
2617 for (i=0; i<lookupCount; ++i) {2515 for (i=0; i<lookupCount; ++i) {
2618 stbtt_uint16 lookupOffset = ttUSHORT(lookupList + 2 + 2 * i);2516 stbtt_uint16 lookupOffset = ttUSHORT(lookupList + 2 + 2 * i);
2619 stbtt_uint8 *lookupTable = lookupList + lookupOffset;2517 stbtt_uint8 *lookupTable = lookupList + lookupOffset;
2620 2518
2621 stbtt_uint16 lookupType = ttUSHORT(lookupTable);2519 stbtt_uint16 lookupType = ttUSHORT(lookupTable);
2622 stbtt_uint16 subTableCount = ttUSHORT(lookupTable + 4);2520 stbtt_uint16 subTableCount = ttUSHORT(lookupTable + 4);
2623 stbtt_uint8 *subTableOffsets = lookupTable + 6;2521 stbtt_uint8 *subTableOffsets = lookupTable + 6;
2624 switch(lookupType) {2522 if (lookupType != 2) // Pair Adjustment Positioning Subtable
2625 case 2: { // Pair Adjustment Positioning Subtable2523 continue;
2626 stbtt_int32 sti;2524
2627 for (sti=0; sti<subTableCount; sti++) {2525 for (sti=0; sti<subTableCount; sti++) {
2628 stbtt_uint16 subtableOffset = ttUSHORT(subTableOffsets + 2 * sti);2526 stbtt_uint16 subtableOffset = ttUSHORT(subTableOffsets + 2 * sti);
2629 stbtt_uint8 *table = lookupTable + subtableOffset;2527 stbtt_uint8 *table = lookupTable + subtableOffset;
2630 stbtt_uint16 posFormat = ttUSHORT(table);2528 stbtt_uint16 posFormat = ttUSHORT(table);
2631 stbtt_uint16 coverageOffset = ttUSHORT(table + 2);2529 stbtt_uint16 coverageOffset = ttUSHORT(table + 2);
2632 stbtt_int32 coverageIndex = stbtt__GetCoverageIndex(table + coverageOffset, glyph1);2530 stbtt_int32 coverageIndex = stbtt__GetCoverageIndex(table + coverageOffset, glyph1);
2633 if (coverageIndex == -1) continue;2531 if (coverageIndex == -1) continue;
2634 2532
2635 switch (posFormat) {2533 switch (posFormat) {
2636 case 1: {2534 case 1: {
2637 stbtt_int32 l, r, m;2535 stbtt_int32 l, r, m;
2638 int straw, needle;2536 int straw, needle;
2639 stbtt_uint16 valueFormat1 = ttUSHORT(table + 4);2537 stbtt_uint16 valueFormat1 = ttUSHORT(table + 4);
2640 stbtt_uint16 valueFormat2 = ttUSHORT(table + 6);2538 stbtt_uint16 valueFormat2 = ttUSHORT(table + 6);
2641 stbtt_int32 valueRecordPairSizeInBytes = 2;2539 if (valueFormat1 == 4 && valueFormat2 == 0) { // Support more formats?
2642 stbtt_uint16 pairSetCount = ttUSHORT(table + 8);2540 stbtt_int32 valueRecordPairSizeInBytes = 2;
2643 stbtt_uint16 pairPosOffset = ttUSHORT(table + 10 + 2 * coverageIndex);2541 stbtt_uint16 pairSetCount = ttUSHORT(table + 8);
2644 stbtt_uint8 *pairValueTable = table + pairPosOffset;2542 stbtt_uint16 pairPosOffset = ttUSHORT(table + 10 + 2 * coverageIndex);
2645 stbtt_uint16 pairValueCount = ttUSHORT(pairValueTable);2543 stbtt_uint8 *pairValueTable = table + pairPosOffset;
2646 stbtt_uint8 *pairValueArray = pairValueTable + 2;2544 stbtt_uint16 pairValueCount = ttUSHORT(pairValueTable);
2647 // TODO: Support more formats.2545 stbtt_uint8 *pairValueArray = pairValueTable + 2;
2648 STBTT_GPOS_TODO_assert(valueFormat1 == 4);2546
2649 if (valueFormat1 != 4) return 0;2547 if (coverageIndex >= pairSetCount) return 0;
2650 STBTT_GPOS_TODO_assert(valueFormat2 == 0);2548
2651 if (valueFormat2 != 0) return 0;2549 needle=glyph2;
2652 2550 r=pairValueCount-1;
2653 STBTT_assert(coverageIndex < pairSetCount);2551 l=0;
2654 STBTT__NOTUSED(pairSetCount);2552
2655 2553 // Binary search.
2656 needle=glyph2;2554 while (l <= r) {
2657 r=pairValueCount-1;2555 stbtt_uint16 secondGlyph;
2658 l=0;2556 stbtt_uint8 *pairValue;
2659 2557 m = (l + r) >> 1;
2660 // Binary search.2558 pairValue = pairValueArray + (2 + valueRecordPairSizeInBytes) * m;
2661 while (l <= r) {2559 secondGlyph = ttUSHORT(pairValue);
2662 stbtt_uint16 secondGlyph;2560 straw = secondGlyph;
2663 stbtt_uint8 *pairValue;2561 if (needle < straw)
2664 m = (l + r) >> 1;2562 r = m - 1;
2665 pairValue = pairValueArray + (2 + valueRecordPairSizeInBytes) * m;2563 else if (needle > straw)
2666 secondGlyph = ttUSHORT(pairValue);2564 l = m + 1;
2667 straw = secondGlyph;2565 else {
2668 if (needle < straw)2566 stbtt_int16 xAdvance = ttSHORT(pairValue + 2);
2669 r = m - 1;2567 return xAdvance;
2670 else if (needle > straw)2568 }
2671 l = m + 1;2569 }
2672 else {2570 } else
2673 stbtt_int16 xAdvance = ttSHORT(pairValue + 2);2571 return 0;
2674 return xAdvance;2572 break;
2675 }2573 }
2676 }2574
2677 } break;2575 case 2: {
2678 2576 stbtt_uint16 valueFormat1 = ttUSHORT(table + 4);
2679 case 2: {2577 stbtt_uint16 valueFormat2 = ttUSHORT(table + 6);
2680 stbtt_uint16 valueFormat1 = ttUSHORT(table + 4);2578 if (valueFormat1 == 4 && valueFormat2 == 0) { // Support more formats?
2681 stbtt_uint16 valueFormat2 = ttUSHORT(table + 6);2579 stbtt_uint16 classDef1Offset = ttUSHORT(table + 8);
2682 2580 stbtt_uint16 classDef2Offset = ttUSHORT(table + 10);
2683 stbtt_uint16 classDef1Offset = ttUSHORT(table + 8);2581 int glyph1class = stbtt__GetGlyphClass(table + classDef1Offset, glyph1);
2684 stbtt_uint16 classDef2Offset = ttUSHORT(table + 10);2582 int glyph2class = stbtt__GetGlyphClass(table + classDef2Offset, glyph2);
2685 int glyph1class = stbtt__GetGlyphClass(table + classDef1Offset, glyph1);2583
2686 int glyph2class = stbtt__GetGlyphClass(table + classDef2Offset, glyph2);2584 stbtt_uint16 class1Count = ttUSHORT(table + 12);
2687 2585 stbtt_uint16 class2Count = ttUSHORT(table + 14);
2688 stbtt_uint16 class1Count = ttUSHORT(table + 12);2586 stbtt_uint8 *class1Records, *class2Records;
2689 stbtt_uint16 class2Count = ttUSHORT(table + 14);2587 stbtt_int16 xAdvance;
2690 if(glyph1class >= class1Count || glyph2class >= class2Count)2588
2691 return 0;2589 if (glyph1class < 0 || glyph1class >= class1Count) return 0; // malformed
2692 STBTT_assert(glyph1class < class1Count);2590 if (glyph2class < 0 || glyph2class >= class2Count) return 0; // malformed
2693 STBTT_assert(glyph2class < class2Count);2591
2694 2592 class1Records = table + 16;
2695 // TODO: Support more formats.2593 class2Records = class1Records + 2 * (glyph1class * class2Count);
2696 STBTT_GPOS_TODO_assert(valueFormat1 == 4);2594 xAdvance = ttSHORT(class2Records + 2 * glyph2class);
2697 if (valueFormat1 != 4) return 0;2595 return xAdvance;
2698 STBTT_GPOS_TODO_assert(valueFormat2 == 0);2596 } else
2699 if (valueFormat2 != 0) return 0;2597 return 0;
2700 2598 break;
2701 if (glyph1class >= 0 && glyph1class < class1Count && glyph2class >= 0 && glyph2class < class2Count) {2599 }
2702 stbtt_uint8 *class1Records = table + 16;
2703 stbtt_uint8 *class2Records = class1Records + 2 * (glyph1class * class2Count);
2704 stbtt_int16 xAdvance = ttSHORT(class2Records + 2 * glyph2class);
2705 return xAdvance;
2706 }
2707 } break;
2708
2709 default: {
2710 // There are no other cases.
2711 STBTT_assert(0);
2712 break;
2713 };
2714 }
2715 }
2716 break;
2717 };
2718 2600
2719 default:2601 default:
2720 // TODO: Implement other stuff.2602 return 0; // Unsupported position format
2721 break;2603 }
2722 }2604 }
2723 }2605 }
2724 2606
2725 return 0;2607 return 0;
2726}2608}
2727 2609
2728STBTT_DEF int stbtt_GetGlyphKernAdvance(const stbtt_fontinfo *info, int g1, int g2)2610STBTT_DEF int stbtt_GetGlyphKernAdvance(const stbtt_fontinfo *info, int g1, int g2)
@@ -2731,7 +2613,7 @@ STBTT_DEF int stbtt_GetGlyphKernAdvance(const stbtt_fontinfo *info, int g1, int · 2 unmodified lines
2731 2613
2732 if (info->gpos)2614 if (info->gpos)
2733 xAdvance += stbtt__GetGlyphGPOSInfoAdvance(info, g1, g2);2615 xAdvance += stbtt__GetGlyphGPOSInfoAdvance(info, g1, g2);
2734 if (info->kern && xAdvance == 0)2616 else if (info->kern)
2735 xAdvance += stbtt__GetGlyphKernInfoAdvance(info, g1, g2);2617 xAdvance += stbtt__GetGlyphKernInfoAdvance(info, g1, g2);
2736 2618
2737 return xAdvance;2619 return xAdvance;
@@ -2789,7 +2671,6 @@ STBTT_DEF float stbtt_ScaleForMappingEmToPixels(const stbtt_fontinfo *info, floa · 51 unmodified lines
2789 2671
2790STBTT_DEF void stbtt_FreeShape(const stbtt_fontinfo *info, stbtt_vertex *v)2672STBTT_DEF void stbtt_FreeShape(const stbtt_fontinfo *info, stbtt_vertex *v)
2791{2673{
2792 USED(info);
2793 STBTT_free(v, info->userdata);2674 STBTT_free(v, info->userdata);
2794}2675}
2795 2676
@@ -3173,14 +3054,30 @@ static void stbtt__handle_clipped_edge(float *scanline, int x, stbtt__active_edg · 377 unmodified lines
3173 3054
3174 if (x0 <= x && x1 <= x)3055 if (x0 <= x && x1 <= x)
3175 scanline[x] += e->direction * (y1-y0);3056 scanline[x] += e->direction * (y1-y0);
3176 else if (x0 >= x+1 && x1 >= x+1)3057 else if (x0 >= x+1 && x1 >= x+1) {
3177 {}3058 } else {
3178 else {
3179 STBTT_assert(x0 >= x && x0 <= x+1 && x1 >= x && x1 <= x+1);3059 STBTT_assert(x0 >= x && x0 <= x+1 && x1 >= x && x1 <= x+1);
3180 scanline[x] += e->direction * (y1-y0) * (1-((x0-x)+(x1-x))/2); // coverage = 1 - average x position3060 scanline[x] += e->direction * (y1-y0) * (1-((x0-x)+(x1-x))/2); // coverage = 1 - average x position
3181 }3061 }
3182}3062}
3183 3063
3064static float stbtt__sized_trapezoid_area(float height, float top_width, float bottom_width)
3065{
3066 STBTT_assert(top_width >= 0);
3067 STBTT_assert(bottom_width >= 0);
3068 return (top_width + bottom_width) / 2.0f * height;
3069}
3070
3071static float stbtt__position_trapezoid_area(float height, float tx0, float tx1, float bx0, float bx1)
3072{
3073 return stbtt__sized_trapezoid_area(height, tx1 - tx0, bx1 - bx0);
3074}
3075
3076static float stbtt__sized_triangle_area(float height, float width)
3077{
3078 return height * width / 2;
3079}
3080
3184static void stbtt__fill_active_edges_new(float *scanline, float *scanline_fill, int len, stbtt__active_edge *e, float y_top)3081static void stbtt__fill_active_edges_new(float *scanline, float *scanline_fill, int len, stbtt__active_edge *e, float y_top)
3185{3082{
3186 float y_bottom = y_top+1;3083 float y_bottom = y_top+1;
@@ -3235,13 +3132,13 @@ static void stbtt__fill_active_edges_new(float *scanline, float *scanline_fill, · 48 unmodified lines
3235 float height;3132 float height;
3236 // simple case, only spans one pixel3133 // simple case, only spans one pixel
3237 int x = (int) x_top;3134 int x = (int) x_top;
3238 height = sy1 - sy0;3135 height = (sy1 - sy0) * e->direction;
3239 STBTT_assert(x >= 0 && x < len);3136 STBTT_assert(x >= 0 && x < len);
3240 scanline[x] += e->direction * (1-((x_top - x) + (x_bottom-x))/2) * height;3137 scanline[x] += stbtt__position_trapezoid_area(height, x_top, x+1.0f, x_bottom, x+1.0f);
3241 scanline_fill[x] += e->direction * height; // everything right of this pixel is filled3138 scanline_fill[x] += height; // everything right of this pixel is filled
3242 } else {3139 } else {
3243 int x,x1,x2;3140 int x,x1,x2;
3244 float y_crossing, step, sign, area;3141 float y_crossing, y_final, step, sign, area;
3245 // covers 2+ pixels3142 // covers 2+ pixels
3246 if (x_top > x_bottom) {3143 if (x_top > x_bottom) {
3247 // flip scanline vertically; signed area is the same3144 // flip scanline vertically; signed area is the same
@@ -3252,32 +3149,81 @@ static void stbtt__fill_active_edges_new(float *scanline, float *scanline_fill, · 4 unmodified lines
3252 t = x_bottom, x_bottom = x_top, x_top = t;3149 t = x_bottom, x_bottom = x_top, x_top = t;
3253 dx = -dx;3150 dx = -dx;
3254 dy = -dy;3151 dy = -dy;
3255 t = x0, x0 = xb, xb = t;3152 x0 = xb;
3256 USED(dx); USED(xb);
3257 }3153 }
3154 STBTT_assert(dy >= 0);
3155 STBTT_assert(dx >= 0);
3258 3156
3259 x1 = (int) x_top;3157 x1 = (int) x_top;
3260 x2 = (int) x_bottom;3158 x2 = (int) x_bottom;
3261 // compute intersection with y axis at x1+13159 // compute intersection with y axis at x1+1
3262 y_crossing = (x1+1 - x0) * dy + y_top;3160 y_crossing = y_top + dy * (x1+1 - x0);
3161
3162 // compute intersection with y axis at x2
3163 y_final = y_top + dy * (x2 - x0);
3164
3165 // x1 x_top x2 x_bottom
3166 // y_top +------|-----+------------+------------+--------|---+------------+
3167 // | | | | | |
3168 // | | | | | |
3169 // sy0 | Txxxxx|............|............|............|............|
3170 // y_crossing | *xxxxx.......|............|............|............|
3171 // | | xxxxx..|............|............|............|
3172 // | | /- xx*xxxx........|............|............|
3173 // | | dy < | xxxxxx..|............|............|
3174 // y_final | | \- | xx*xxx.........|............|
3175 // sy1 | | | | xxxxxB...|............|
3176 // | | | | | |
3177 // | | | | | |
3178 // y_bottom +------------+------------+------------+------------+------------+
3179 //
3180 // goal is to measure the area covered by '.' in each pixel
3181
3182 // if x2 is right at the right edge of x1, y_crossing can blow up, github #1057
3183 // @TODO: maybe test against sy1 rather than y_bottom?
3184 if (y_crossing > y_bottom)
3185 y_crossing = y_bottom;
3263 3186
3264 sign = e->direction;3187 sign = e->direction;
3265 // area of the rectangle covered from y0..y_crossing3188
3189 // area of the rectangle covered from sy0..y_crossing
3266 area = sign * (y_crossing-sy0);3190 area = sign * (y_crossing-sy0);
3267 // area of the triangle (x_top,y0), (x+1,y0), (x+1,y_crossing)
3268 scanline[x1] += area * (1-((x_top - x1)+(x1+1-x1))/2);
3269 3191
3270 step = sign * dy;3192 // area of the triangle (x_top,sy0), (x1+1,sy0), (x1+1,y_crossing)
3193 scanline[x1] += stbtt__sized_triangle_area(area, x1+1 - x_top);
3194
3195 // check if final y_crossing is blown up; no test case for this
3196 if (y_final > y_bottom) {
3197 y_final = y_bottom;
3198 dy = (y_final - y_crossing ) / (x2 - (x1+1)); // if denom=0, y_final = y_crossing, so y_final <= y_bottom
3199 }
3200
3201 // in second pixel, area covered by line segment found in first pixel
3202 // is always a rectangle 1 wide * the height of that line segment; this
3203 // is exactly what the variable 'area' stores. it also gets a contribution
3204 // from the line segment within it. the THIRD pixel will get the first
3205 // pixel's rectangle contribution, the second pixel's rectangle contribution,
3206 // and its own contribution. the 'own contribution' is the same in every pixel except
3207 // the leftmost and rightmost, a trapezoid that slides down in each pixel.
3208 // the second pixel's contribution to the third pixel will be the
3209 // rectangle 1 wide times the height change in the second pixel, which is dy.
3210
3211 step = sign * dy * 1; // dy is dy/dx, change in y for every 1 change in x,
3212 // which multiplied by 1-pixel-width is how much pixel area changes for each step in x
3213 // so the area advances by 'step' every time
3214
3271 for (x = x1+1; x < x2; ++x) {3215 for (x = x1+1; x < x2; ++x) {
3272 scanline[x] += area + step/2;3216 scanline[x] += area + step/2; // area of trapezoid is 1*step/2
3273 area += step;3217 area += step;
3274 }3218 }
3275 y_crossing += dy * (x2 - (x1+1));3219 STBTT_assert(STBTT_fabs(area) <= 1.01f); // accumulated error from area += step unless we round step down
3220 STBTT_assert(sy1 > y_final-0.01f);
3276 3221
3277 STBTT_assert(STBTT_fabs(area) <= 1.01f);3222 // area covered in the last pixel is the rectangle from all the pixels to the left,
3278 3223 // plus the trapezoid filled by the line segment in this pixel all the way to the right edge
3279 scanline[x2] += area + sign * (1-((x2-x2)+(x_bottom-x2))/2) * (sy1-y_crossing);3224 scanline[x2] += area + sign * stbtt__position_trapezoid_area(sy1-y_final, (float) x2, x2+1.0f, x_bottom, x2+1.0f);
3280 3225
3226 // the rest of the line is filled based on the total height of the line segment in this pixel
3281 scanline_fill[x2] += sign * (sy1-sy0);3227 scanline_fill[x2] += sign * (sy1-sy0);
3282 }3228 }
3283 } else {3229 } else {
@@ -3285,6 +3231,9 @@ static void stbtt__fill_active_edges_new(float *scanline, float *scanline_fill, · 1 unmodified line
3285 // clipping logic. since this does not match the intended use3231 // clipping logic. since this does not match the intended use
3286 // of this library, we use a different, very slow brute3232 // of this library, we use a different, very slow brute
3287 // force implementation3233 // force implementation
3234 // note though that this does happen some of the time because
3235 // x_top and x_bottom can be extrapolated at the top & bottom of
3236 // the shape and actually lie outside the bounding box
3288 int x;3237 int x;
3289 for (x=0; x < len; ++x) {3238 for (x=0; x < len; ++x) {
3290 // cases:3239 // cases:
@@ -4521,15 +4470,14 @@ static int stbtt__compute_crossings_x(float x, float y, int nverts, stbtt_vertex · 1230 unmodified lines
4521 float y_frac;4470 float y_frac;
4522 int winding = 0;4471 int winding = 0;
4523 4472
4524 orig[0] = x;
4525 orig[1] = y;
4526
4527 // make sure y never passes through a vertex of the shape4473 // make sure y never passes through a vertex of the shape
4528 y_frac = (float) STBTT_fmod(y, 1.0f);4474 y_frac = (float) STBTT_fmod(y, 1.0f);
4529 if (y_frac < 0.01f)4475 if (y_frac < 0.01f)
4530 y += 0.01f;4476 y += 0.01f;
4531 else if (y_frac > 0.99f)4477 else if (y_frac > 0.99f)
4532 y -= 0.01f;4478 y -= 0.01f;
4479
4480 orig[0] = x;
4533 orig[1] = y;4481 orig[1] = y;
4534 4482
4535 // test a ray from (-infinity,y) to (x,y)4483 // test a ray from (-infinity,y) to (x,y)
@@ -4591,35 +4539,35 @@ static float stbtt__cuberoot( float x ) · 55 unmodified lines
4591 return (float) STBTT_pow( x,1.0f/3.0f);4539 return (float) STBTT_pow( x,1.0f/3.0f);
4592}4540}
4593 4541
4594// x^3 + c*x^2 + b*x + a = 04542// x^3 + a*x^2 + b*x + c = 0
4595static int stbtt__solve_cubic(float a, float b, float c, float* r)4543static int stbtt__solve_cubic(float a, float b, float c, float* r)
4596{4544{
4597 float s = -a / 3;4545 float s = -a / 3;
4598 float p = b - a*a / 3;4546 float p = b - a*a / 3;
4599 float q = a * (2*a*a - 9*b) / 27 + c;4547 float q = a * (2*a*a - 9*b) / 27 + c;
4600 float p3 = p*p*p;4548 float p3 = p*p*p;
4601 float d = q*q + 4*p3 / 27;4549 float d = q*q + 4*p3 / 27;
4602 if (d >= 0) {4550 if (d >= 0) {
4603 float z = (float) STBTT_sqrt(d);4551 float z = (float) STBTT_sqrt(d);
4604 float u = (-q + z) / 2;4552 float u = (-q + z) / 2;
4605 float v = (-q - z) / 2;4553 float v = (-q - z) / 2;
4606 u = stbtt__cuberoot(u);4554 u = stbtt__cuberoot(u);
4607 v = stbtt__cuberoot(v);4555 v = stbtt__cuberoot(v);
4608 r[0] = s + u + v;4556 r[0] = s + u + v;
4609 return 1;4557 return 1;
4610 } else {4558 } else {
4611 float u = (float) STBTT_sqrt(-p/3);4559 float u = (float) STBTT_sqrt(-p/3);
4612 float v = (float) STBTT_acos(-STBTT_sqrt(-27/p3) * q / 2) / 3; // p3 must be negative, since d is negative4560 float v = (float) STBTT_acos(-STBTT_sqrt(-27/p3) * q / 2) / 3; // p3 must be negative, since d is negative
4613 float m = (float) STBTT_cos(v);4561 float m = (float) STBTT_cos(v);
4614 float n = (float) STBTT_cos(v-3.141592/2)*1.732050808f;4562 float n = (float) STBTT_cos(v-3.141592/2)*1.732050808f;
4615 r[0] = s + u * 2 * m;4563 r[0] = s + u * 2 * m;
4616 r[1] = s - u * (m + n);4564 r[1] = s - u * (m + n);
4617 r[2] = s - u * (m - n);4565 r[2] = s - u * (m - n);
4618 4566
4619 //STBTT_assert( STBTT_fabs(((r[0]+a)*r[0]+b)*r[0]+c) < 0.05f); // these asserts may not be safe at all scales, though they're in bezier t parameter units so maybe?4567 //STBTT_assert( STBTT_fabs(((r[0]+a)*r[0]+b)*r[0]+c) < 0.05f); // these asserts may not be safe at all scales, though they're in bezier t parameter units so maybe?
4620 //STBTT_assert( STBTT_fabs(((r[1]+a)*r[1]+b)*r[1]+c) < 0.05f);4568 //STBTT_assert( STBTT_fabs(((r[1]+a)*r[1]+b)*r[1]+c) < 0.05f);
4621 //STBTT_assert( STBTT_fabs(((r[2]+a)*r[2]+b)*r[2]+c) < 0.05f);4569 //STBTT_assert( STBTT_fabs(((r[2]+a)*r[2]+b)*r[2]+c) < 0.05f);
4622 return 3;4570 return 3;
4623 }4571 }
4624}4572}
4625 4573
@@ -4696,18 +4644,17 @@ STBTT_DEF unsigned char * stbtt_GetGlyphSDF(const stbtt_fontinfo *info, float sc · 70 unmodified lines
4696 for (i=0; i < num_verts; ++i) {4644 for (i=0; i < num_verts; ++i) {
4697 float x0 = verts[i].x*scale_x, y0 = verts[i].y*scale_y;4645 float x0 = verts[i].x*scale_x, y0 = verts[i].y*scale_y;
4698 4646
4699 // check against every point here rather than inside line/curve primitives -- @TODO: wrong if multiple 'moves' in a row produce a garbage point, and given culling, probably more efficient to do within line/curve4647 if (verts[i].type == STBTT_vline && precompute[i] != 0.0f) {
4700 float dist2 = (x0-sx)*(x0-sx) + (y0-sy)*(y0-sy);
4701 if (dist2 < min_dist*min_dist)
4702 min_dist = (float) STBTT_sqrt(dist2);
4703
4704 if (verts[i].type == STBTT_vline) {
4705 float x1 = verts[i-1].x*scale_x, y1 = verts[i-1].y*scale_y;4648 float x1 = verts[i-1].x*scale_x, y1 = verts[i-1].y*scale_y;
4706 4649
4650 float dist,dist2 = (x0-sx)*(x0-sx) + (y0-sy)*(y0-sy);
4651 if (dist2 < min_dist*min_dist)
4652 min_dist = (float) STBTT_sqrt(dist2);
4653
4707 // coarse culling against bbox4654 // coarse culling against bbox
4708 //if (sx > STBTT_min(x0,x1)-min_dist && sx < STBTT_max(x0,x1)+min_dist &&4655 //if (sx > STBTT_min(x0,x1)-min_dist && sx < STBTT_max(x0,x1)+min_dist &&
4709 // sy > STBTT_min(y0,y1)-min_dist && sy < STBTT_max(y0,y1)+min_dist)4656 // sy > STBTT_min(y0,y1)-min_dist && sy < STBTT_max(y0,y1)+min_dist)
4710 float dist = (float) STBTT_fabs((x1-x0)*(y0-sy) - (y1-y0)*(x0-sx)) * precompute[i];4657 dist = (float) STBTT_fabs((x1-x0)*(y0-sy) - (y1-y0)*(x0-sx)) * precompute[i];
4711 STBTT_assert(i != 0);4658 STBTT_assert(i != 0);
4712 if (dist < min_dist) {4659 if (dist < min_dist) {
4713 // check position along line4660 // check position along line
@@ -4734,7 +4681,8 @@ STBTT_DEF unsigned char * stbtt_GetGlyphSDF(const stbtt_fontinfo *info, float sc · 20 unmodified lines
4734 float ax = x1-x0, ay = y1-y0;4681 float ax = x1-x0, ay = y1-y0;
4735 float bx = x0 - 2*x1 + x2, by = y0 - 2*y1 + y2;4682 float bx = x0 - 2*x1 + x2, by = y0 - 2*y1 + y2;
4736 float mx = x0 - sx, my = y0 - sy;4683 float mx = x0 - sx, my = y0 - sy;
4737 float res[3],px,py,t,it;4684 float res[3] = {0.f,0.f,0.f};
4685 float px,py,t,it,dist2;
4738 float a_inv = precompute[i];4686 float a_inv = precompute[i];
4739 if (a_inv == 0.0) { // if a_inv is 0, it's 2nd degree so use quadratic formula4687 if (a_inv == 0.0) { // if a_inv is 0, it's 2nd degree so use quadratic formula
4740 float a = 3*(ax*bx + ay*by);4688 float a = 3*(ax*bx + ay*by);
@@ -4761,6 +4709,10 @@ STBTT_DEF unsigned char * stbtt_GetGlyphSDF(const stbtt_fontinfo *info, float sc · 20 unmodified lines
4761 float d = (mx*ax+my*ay) * a_inv;4709 float d = (mx*ax+my*ay) * a_inv;
4762 num = stbtt__solve_cubic(b, c, d, res);4710 num = stbtt__solve_cubic(b, c, d, res);
4763 }4711 }
4712 dist2 = (x0-sx)*(x0-sx) + (y0-sy)*(y0-sy);
4713 if (dist2 < min_dist*min_dist)
4714 min_dist = (float) STBTT_sqrt(dist2);
4715
4764 if (num >= 1 && res[0] >= 0.0f && res[0] <= 1.0f) {4716 if (num >= 1 && res[0] >= 0.0f && res[0] <= 1.0f) {
4765 t = res[0], it = 1.0f - t;4717 t = res[0], it = 1.0f - t;
4766 px = it*it*x0 + 2*t*it*x1 + t*t*x2;4718 px = it*it*x0 + 2*t*it*x1 + t*t*x2;
@@ -5020,6 +4972,12 @@ STBTT_DEF int stbtt_CompareUTF8toUTF16_bigendian(const char *s1, int len1, const · 253 unmodified lines
5020 4972
5021// FULL VERSION HISTORY4973// FULL VERSION HISTORY
5022//4974//
4975// 1.25 (2021-07-11) many fixes
4976// 1.24 (2020-02-05) fix warning
4977// 1.23 (2020-02-02) query SVG data for glyphs; query whole kerning table (but only kern not GPOS)
4978// 1.22 (2019-08-11) minimize missing-glyph duplication; fix kerning if both 'GPOS' and 'kern' are defined
4979// 1.21 (2019-02-25) fix warning
4980// 1.20 (2019-02-07) PackFontRange skips missing codepoints; GetScaleFontVMetrics()
5023// 1.19 (2018-02-11) OpenType GPOS kerning (horizontal only), STBTT_fmod4981// 1.19 (2018-02-11) OpenType GPOS kerning (horizontal only), STBTT_fmod
5024// 1.18 (2018-01-29) add missing function4982// 1.18 (2018-01-29) add missing function
5025// 1.17 (2017-07-23) make more arguments const; doc fix4983// 1.17 (2017-07-23) make more arguments const; doc fix

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t