stb_truetype.c (149573B)
1 // stb_truetype.h - v1.26 - public domain 2 // authored from 2009-2021 by Sean Barrett / RAD Game Tools 3 // 4 // ======================================================================= 5 // 6 // NO SECURITY GUARANTEE -- DO NOT USE THIS ON UNTRUSTED FONT FILES 7 // 8 // This library does no range checking of the offsets found in the file, 9 // meaning an attacker can use it to read arbitrary memory. 10 // 11 // ======================================================================= 12 13 #include <math.h> 14 #include <stdlib.h> 15 #include <assert.h> 16 #include <string.h> 17 #include "stb_truetype.h" 18 19 ////////////////////////////////////////////////////////////////////////////// 20 ////////////////////////////////////////////////////////////////////////////// 21 //// 22 //// INTEGRATION WITH YOUR CODEBASE 23 //// 24 //// The following sections allow you to supply alternate definitions 25 //// of C library functions used by stb_truetype, e.g. if you don't 26 //// link with the C runtime library. 27 28 typedef unsigned char stbtt_uint8; 29 typedef signed char stbtt_int8; 30 typedef unsigned short stbtt_uint16; 31 typedef signed short stbtt_int16; 32 typedef unsigned int stbtt_uint32; 33 typedef signed int stbtt_int32; 34 typedef char stbtt__check_size32[sizeof(stbtt_int32)==4 ? 1 : -1]; 35 typedef char stbtt__check_size16[sizeof(stbtt_int16)==2 ? 1 : -1]; 36 #define STBTT_ifloor(x) ((int) floor(x)) 37 #define STBTT_iceil(x) ((int) ceil(x)) 38 #define STBTT_sqrt(x) sqrt(x) 39 #define STBTT_pow(x,y) pow(x,y) 40 #define STBTT_fmod(x,y) fmod(x,y) 41 #define STBTT_cos(x) cos(x) 42 #define STBTT_acos(x) acos(x) 43 #define STBTT_fabs(x) fabs(x) 44 #define STBTT_malloc(x,u) ((void)(u),malloc(x)) 45 #define STBTT_free(x,u) ((void)(u),free(x)) 46 #define STBTT_assert(x) assert(x) 47 #define STBTT_strlen(x) strlen(x) 48 #define STBTT_memcpy memcpy 49 #define STBTT_memset memset 50 51 /////////////////////////////////////////////////////////////////////////////// 52 /////////////////////////////////////////////////////////////////////////////// 53 //// 54 //// IMPLEMENTATION 55 //// 56 //// 57 58 #ifndef STBTT_MAX_OVERSAMPLE 59 #define STBTT_MAX_OVERSAMPLE 8 60 #endif 61 62 #if STBTT_MAX_OVERSAMPLE > 255 63 #error "STBTT_MAX_OVERSAMPLE cannot be > 255" 64 #endif 65 66 typedef int stbtt__test_oversample_pow2[(STBTT_MAX_OVERSAMPLE & (STBTT_MAX_OVERSAMPLE-1)) == 0 ? 1 : -1]; 67 68 #ifndef STBTT_RASTERIZER_VERSION 69 #define STBTT_RASTERIZER_VERSION 2 70 #endif 71 72 #ifdef _MSC_VER 73 #define STBTT__NOTUSED(v) (void)(v) 74 #else 75 #define STBTT__NOTUSED(v) (void)sizeof(v) 76 #endif 77 78 ////////////////////////////////////////////////////////////////////////// 79 // 80 // stbtt__buf helpers to parse data from file 81 // 82 83 static stbtt_uint8 stbtt__buf_get8(stbtt__buf *b) 84 { 85 if (b->cursor >= b->size) 86 return 0; 87 return b->data[b->cursor++]; 88 } 89 90 static stbtt_uint8 stbtt__buf_peek8(stbtt__buf *b) 91 { 92 if (b->cursor >= b->size) 93 return 0; 94 return b->data[b->cursor]; 95 } 96 97 static void stbtt__buf_seek(stbtt__buf *b, int o) 98 { 99 STBTT_assert(!(o > b->size || o < 0)); 100 b->cursor = (o > b->size || o < 0) ? b->size : o; 101 } 102 103 static void stbtt__buf_skip(stbtt__buf *b, int o) 104 { 105 stbtt__buf_seek(b, b->cursor + o); 106 } 107 108 static stbtt_uint32 stbtt__buf_get(stbtt__buf *b, int n) 109 { 110 stbtt_uint32 v = 0; 111 int i; 112 STBTT_assert(n >= 1 && n <= 4); 113 for (i = 0; i < n; i++) 114 v = (v << 8) | stbtt__buf_get8(b); 115 return v; 116 } 117 118 static stbtt__buf stbtt__new_buf(const void *p, size_t size) 119 { 120 stbtt__buf r; 121 STBTT_assert(size < 0x40000000); 122 r.data = (stbtt_uint8*) p; 123 r.size = (int) size; 124 r.cursor = 0; 125 return r; 126 } 127 128 #define stbtt__buf_get16(b) stbtt__buf_get((b), 2) 129 #define stbtt__buf_get32(b) stbtt__buf_get((b), 4) 130 131 static stbtt__buf stbtt__buf_range(const stbtt__buf *b, int o, int s) 132 { 133 stbtt__buf r = stbtt__new_buf(NULL, 0); 134 if (o < 0 || s < 0 || o > b->size || s > b->size - o) return r; 135 r.data = b->data + o; 136 r.size = s; 137 return r; 138 } 139 140 static stbtt__buf stbtt__cff_get_index(stbtt__buf *b) 141 { 142 int count, start, offsize; 143 start = b->cursor; 144 count = stbtt__buf_get16(b); 145 if (count) { 146 offsize = stbtt__buf_get8(b); 147 STBTT_assert(offsize >= 1 && offsize <= 4); 148 stbtt__buf_skip(b, offsize * count); 149 stbtt__buf_skip(b, stbtt__buf_get(b, offsize) - 1); 150 } 151 return stbtt__buf_range(b, start, b->cursor - start); 152 } 153 154 static stbtt_uint32 stbtt__cff_int(stbtt__buf *b) 155 { 156 int b0 = stbtt__buf_get8(b); 157 if (b0 >= 32 && b0 <= 246) return b0 - 139; 158 else if (b0 >= 247 && b0 <= 250) return (b0 - 247)*256 + stbtt__buf_get8(b) + 108; 159 else if (b0 >= 251 && b0 <= 254) return -(b0 - 251)*256 - stbtt__buf_get8(b) - 108; 160 else if (b0 == 28) return stbtt__buf_get16(b); 161 else if (b0 == 29) return stbtt__buf_get32(b); 162 STBTT_assert(0); 163 return 0; 164 } 165 166 static void stbtt__cff_skip_operand(stbtt__buf *b) { 167 int v, b0 = stbtt__buf_peek8(b); 168 STBTT_assert(b0 >= 28); 169 if (b0 == 30) { 170 stbtt__buf_skip(b, 1); 171 while (b->cursor < b->size) { 172 v = stbtt__buf_get8(b); 173 if ((v & 0xF) == 0xF || (v >> 4) == 0xF) 174 break; 175 } 176 } else { 177 stbtt__cff_int(b); 178 } 179 } 180 181 static stbtt__buf stbtt__dict_get(stbtt__buf *b, int key) 182 { 183 stbtt__buf_seek(b, 0); 184 while (b->cursor < b->size) { 185 int start = b->cursor, end, op; 186 while (stbtt__buf_peek8(b) >= 28) 187 stbtt__cff_skip_operand(b); 188 end = b->cursor; 189 op = stbtt__buf_get8(b); 190 if (op == 12) op = stbtt__buf_get8(b) | 0x100; 191 if (op == key) return stbtt__buf_range(b, start, end-start); 192 } 193 return stbtt__buf_range(b, 0, 0); 194 } 195 196 static void stbtt__dict_get_ints(stbtt__buf *b, int key, int outcount, stbtt_uint32 *out) 197 { 198 int i; 199 stbtt__buf operands = stbtt__dict_get(b, key); 200 for (i = 0; i < outcount && operands.cursor < operands.size; i++) 201 out[i] = stbtt__cff_int(&operands); 202 } 203 204 static int stbtt__cff_index_count(stbtt__buf *b) 205 { 206 stbtt__buf_seek(b, 0); 207 return stbtt__buf_get16(b); 208 } 209 210 static stbtt__buf stbtt__cff_index_get(stbtt__buf b, int i) 211 { 212 int count, offsize, start, end; 213 stbtt__buf_seek(&b, 0); 214 count = stbtt__buf_get16(&b); 215 offsize = stbtt__buf_get8(&b); 216 STBTT_assert(i >= 0 && i < count); 217 STBTT_assert(offsize >= 1 && offsize <= 4); 218 stbtt__buf_skip(&b, i*offsize); 219 start = stbtt__buf_get(&b, offsize); 220 end = stbtt__buf_get(&b, offsize); 221 return stbtt__buf_range(&b, 2+(count+1)*offsize+start, end - start); 222 } 223 224 ////////////////////////////////////////////////////////////////////////// 225 // 226 // accessors to parse data from file 227 // 228 229 // on platforms that don't allow misaligned reads, if we want to allow 230 // truetype fonts that aren't padded to alignment, define ALLOW_UNALIGNED_TRUETYPE 231 232 #define ttBYTE(p) (* (stbtt_uint8 *) (p)) 233 #define ttCHAR(p) (* (stbtt_int8 *) (p)) 234 #define ttFixed(p) ttLONG(p) 235 236 static stbtt_uint16 ttUSHORT(stbtt_uint8 *p) { return p[0]*256 + p[1]; } 237 static stbtt_int16 ttSHORT(stbtt_uint8 *p) { return p[0]*256 + p[1]; } 238 static stbtt_uint32 ttULONG(stbtt_uint8 *p) { return (p[0]<<24) + (p[1]<<16) + (p[2]<<8) + p[3]; } 239 static stbtt_int32 ttLONG(stbtt_uint8 *p) { return (p[0]<<24) + (p[1]<<16) + (p[2]<<8) + p[3]; } 240 241 #define stbtt_tag4(p,c0,c1,c2,c3) ((p)[0] == (c0) && (p)[1] == (c1) && (p)[2] == (c2) && (p)[3] == (c3)) 242 #define stbtt_tag(p,str) stbtt_tag4(p,str[0],str[1],str[2],str[3]) 243 244 static int stbtt__isfont(stbtt_uint8 *font) 245 { 246 // check the version number 247 if (stbtt_tag4(font, '1',0,0,0)) return 1; // TrueType 1 248 if (stbtt_tag(font, "typ1")) return 1; // TrueType with type 1 font -- we don't support this! 249 if (stbtt_tag(font, "OTTO")) return 1; // OpenType with CFF 250 if (stbtt_tag4(font, 0,1,0,0)) return 1; // OpenType 1.0 251 if (stbtt_tag(font, "true")) return 1; // Apple specification for TrueType fonts 252 return 0; 253 } 254 255 // @OPTIMIZE: binary search 256 static stbtt_uint32 stbtt__find_table(stbtt_uint8 *data, stbtt_uint32 fontstart, const char *tag) 257 { 258 stbtt_int32 num_tables = ttUSHORT(data+fontstart+4); 259 stbtt_uint32 tabledir = fontstart + 12; 260 stbtt_int32 i; 261 for (i=0; i < num_tables; ++i) { 262 stbtt_uint32 loc = tabledir + 16*i; 263 if (stbtt_tag(data+loc+0, tag)) 264 return ttULONG(data+loc+8); 265 } 266 return 0; 267 } 268 269 static int stbtt_GetFontOffsetForIndex_internal(unsigned char *font_collection, int index) 270 { 271 // if it's just a font, there's only one valid index 272 if (stbtt__isfont(font_collection)) 273 return index == 0 ? 0 : -1; 274 275 // check if it's a TTC 276 if (stbtt_tag(font_collection, "ttcf")) { 277 // version 1? 278 if (ttULONG(font_collection+4) == 0x00010000 || ttULONG(font_collection+4) == 0x00020000) { 279 stbtt_int32 n = ttLONG(font_collection+8); 280 if (index >= n) 281 return -1; 282 return ttULONG(font_collection+12+index*4); 283 } 284 } 285 return -1; 286 } 287 288 static int stbtt_GetNumberOfFonts_internal(unsigned char *font_collection) 289 { 290 // if it's just a font, there's only one valid font 291 if (stbtt__isfont(font_collection)) 292 return 1; 293 294 // check if it's a TTC 295 if (stbtt_tag(font_collection, "ttcf")) { 296 // version 1? 297 if (ttULONG(font_collection+4) == 0x00010000 || ttULONG(font_collection+4) == 0x00020000) { 298 return ttLONG(font_collection+8); 299 } 300 } 301 return 0; 302 } 303 304 static stbtt__buf stbtt__get_subrs(stbtt__buf cff, stbtt__buf fontdict) 305 { 306 stbtt_uint32 subrsoff = 0, private_loc[2] = { 0, 0 }; 307 stbtt__buf pdict; 308 stbtt__dict_get_ints(&fontdict, 18, 2, private_loc); 309 if (!private_loc[1] || !private_loc[0]) return stbtt__new_buf(NULL, 0); 310 pdict = stbtt__buf_range(&cff, private_loc[1], private_loc[0]); 311 stbtt__dict_get_ints(&pdict, 19, 1, &subrsoff); 312 if (!subrsoff) return stbtt__new_buf(NULL, 0); 313 stbtt__buf_seek(&cff, private_loc[1]+subrsoff); 314 return stbtt__cff_get_index(&cff); 315 } 316 317 // since most people won't use this, find this table the first time it's needed 318 static int stbtt__get_svg(stbtt_fontinfo *info) 319 { 320 stbtt_uint32 t; 321 if (info->svg < 0) { 322 t = stbtt__find_table(info->data, info->fontstart, "SVG "); 323 if (t) { 324 stbtt_uint32 offset = ttULONG(info->data + t + 2); 325 info->svg = t + offset; 326 } else { 327 info->svg = 0; 328 } 329 } 330 return info->svg; 331 } 332 333 static int stbtt_InitFont_internal(stbtt_fontinfo *info, unsigned char *data, int fontstart) 334 { 335 stbtt_uint32 cmap, t; 336 stbtt_int32 i,numTables; 337 338 info->data = data; 339 info->fontstart = fontstart; 340 info->cff = stbtt__new_buf(NULL, 0); 341 342 cmap = stbtt__find_table(data, fontstart, "cmap"); // required 343 info->loca = stbtt__find_table(data, fontstart, "loca"); // required 344 info->head = stbtt__find_table(data, fontstart, "head"); // required 345 info->glyf = stbtt__find_table(data, fontstart, "glyf"); // required 346 info->hhea = stbtt__find_table(data, fontstart, "hhea"); // required 347 info->hmtx = stbtt__find_table(data, fontstart, "hmtx"); // required 348 info->kern = stbtt__find_table(data, fontstart, "kern"); // not required 349 info->gpos = stbtt__find_table(data, fontstart, "GPOS"); // not required 350 351 if (!cmap || !info->head || !info->hhea || !info->hmtx) 352 return 0; 353 if (info->glyf) { 354 // required for truetype 355 if (!info->loca) return 0; 356 } else { 357 // initialization for CFF / Type2 fonts (OTF) 358 stbtt__buf b, topdict, topdictidx; 359 stbtt_uint32 cstype = 2, charstrings = 0, fdarrayoff = 0, fdselectoff = 0; 360 stbtt_uint32 cff; 361 362 cff = stbtt__find_table(data, fontstart, "CFF "); 363 if (!cff) return 0; 364 365 info->fontdicts = stbtt__new_buf(NULL, 0); 366 info->fdselect = stbtt__new_buf(NULL, 0); 367 368 // @TODO this should use size from table (not 512MB) 369 info->cff = stbtt__new_buf(data+cff, 512*1024*1024); 370 b = info->cff; 371 372 // read the header 373 stbtt__buf_skip(&b, 2); 374 stbtt__buf_seek(&b, stbtt__buf_get8(&b)); // hdrsize 375 376 // @TODO the name INDEX could list multiple fonts, 377 // but we just use the first one. 378 stbtt__cff_get_index(&b); // name INDEX 379 topdictidx = stbtt__cff_get_index(&b); 380 topdict = stbtt__cff_index_get(topdictidx, 0); 381 stbtt__cff_get_index(&b); // string INDEX 382 info->gsubrs = stbtt__cff_get_index(&b); 383 384 stbtt__dict_get_ints(&topdict, 17, 1, &charstrings); 385 stbtt__dict_get_ints(&topdict, 0x100 | 6, 1, &cstype); 386 stbtt__dict_get_ints(&topdict, 0x100 | 36, 1, &fdarrayoff); 387 stbtt__dict_get_ints(&topdict, 0x100 | 37, 1, &fdselectoff); 388 info->subrs = stbtt__get_subrs(b, topdict); 389 390 // we only support Type 2 charstrings 391 if (cstype != 2) return 0; 392 if (charstrings == 0) return 0; 393 394 if (fdarrayoff) { 395 // looks like a CID font 396 if (!fdselectoff) return 0; 397 stbtt__buf_seek(&b, fdarrayoff); 398 info->fontdicts = stbtt__cff_get_index(&b); 399 info->fdselect = stbtt__buf_range(&b, fdselectoff, b.size-fdselectoff); 400 } 401 402 stbtt__buf_seek(&b, charstrings); 403 info->charstrings = stbtt__cff_get_index(&b); 404 } 405 406 t = stbtt__find_table(data, fontstart, "maxp"); 407 if (t) 408 info->numGlyphs = ttUSHORT(data+t+4); 409 else 410 info->numGlyphs = 0xffff; 411 412 info->svg = -1; 413 414 // find a cmap encoding table we understand *now* to avoid searching 415 // later. (todo: could make this installable) 416 // the same regardless of glyph. 417 numTables = ttUSHORT(data + cmap + 2); 418 info->index_map = 0; 419 for (i=0; i < numTables; ++i) { 420 stbtt_uint32 encoding_record = cmap + 4 + 8 * i; 421 // find an encoding we understand: 422 switch(ttUSHORT(data+encoding_record)) { 423 case STBTT_PLATFORM_ID_MICROSOFT: 424 switch (ttUSHORT(data+encoding_record+2)) { 425 case STBTT_MS_EID_UNICODE_BMP: 426 case STBTT_MS_EID_UNICODE_FULL: 427 // MS/Unicode 428 info->index_map = cmap + ttULONG(data+encoding_record+4); 429 break; 430 } 431 break; 432 case STBTT_PLATFORM_ID_UNICODE: 433 // Mac/iOS has these 434 // all the encodingIDs are unicode, so we don't bother to check it 435 info->index_map = cmap + ttULONG(data+encoding_record+4); 436 break; 437 } 438 } 439 if (info->index_map == 0) 440 return 0; 441 442 info->indexToLocFormat = ttUSHORT(data+info->head + 50); 443 return 1; 444 } 445 446 STBTT_DEF int stbtt_FindGlyphIndex(const stbtt_fontinfo *info, int unicode_codepoint) 447 { 448 stbtt_uint8 *data = info->data; 449 stbtt_uint32 index_map = info->index_map; 450 451 stbtt_uint16 format = ttUSHORT(data + index_map + 0); 452 if (format == 0) { // apple byte encoding 453 stbtt_int32 bytes = ttUSHORT(data + index_map + 2); 454 if (unicode_codepoint < bytes-6) 455 return ttBYTE(data + index_map + 6 + unicode_codepoint); 456 return 0; 457 } else if (format == 6) { 458 stbtt_uint32 first = ttUSHORT(data + index_map + 6); 459 stbtt_uint32 count = ttUSHORT(data + index_map + 8); 460 if ((stbtt_uint32) unicode_codepoint >= first && (stbtt_uint32) unicode_codepoint < first+count) 461 return ttUSHORT(data + index_map + 10 + (unicode_codepoint - first)*2); 462 return 0; 463 } else if (format == 2) { 464 STBTT_assert(0); // @TODO: high-byte mapping for japanese/chinese/korean 465 return 0; 466 } else if (format == 4) { // standard mapping for windows fonts: binary search collection of ranges 467 stbtt_uint16 segcount = ttUSHORT(data+index_map+6) >> 1; 468 stbtt_uint16 searchRange = ttUSHORT(data+index_map+8) >> 1; 469 stbtt_uint16 entrySelector = ttUSHORT(data+index_map+10); 470 stbtt_uint16 rangeShift = ttUSHORT(data+index_map+12) >> 1; 471 472 // do a binary search of the segments 473 stbtt_uint32 endCount = index_map + 14; 474 stbtt_uint32 search = endCount; 475 476 if (unicode_codepoint > 0xffff) 477 return 0; 478 479 // they lie from endCount .. endCount + segCount 480 // but searchRange is the nearest power of two, so... 481 if (unicode_codepoint >= ttUSHORT(data + search + rangeShift*2)) 482 search += rangeShift*2; 483 484 // now decrement to bias correctly to find smallest 485 search -= 2; 486 while (entrySelector) { 487 stbtt_uint16 end; 488 searchRange >>= 1; 489 end = ttUSHORT(data + search + searchRange*2); 490 if (unicode_codepoint > end) 491 search += searchRange*2; 492 --entrySelector; 493 } 494 search += 2; 495 496 { 497 stbtt_uint16 offset, start, last; 498 stbtt_uint16 item = (stbtt_uint16) ((search - endCount) >> 1); 499 500 start = ttUSHORT(data + index_map + 14 + segcount*2 + 2 + 2*item); 501 last = ttUSHORT(data + endCount + 2*item); 502 if (unicode_codepoint < start || unicode_codepoint > last) 503 return 0; 504 505 offset = ttUSHORT(data + index_map + 14 + segcount*6 + 2 + 2*item); 506 if (offset == 0) 507 return (stbtt_uint16) (unicode_codepoint + ttSHORT(data + index_map + 14 + segcount*4 + 2 + 2*item)); 508 509 return ttUSHORT(data + offset + (unicode_codepoint-start)*2 + index_map + 14 + segcount*6 + 2 + 2*item); 510 } 511 } else if (format == 12 || format == 13) { 512 stbtt_uint32 ngroups = ttULONG(data+index_map+12); 513 stbtt_int32 low,high; 514 low = 0; high = (stbtt_int32)ngroups; 515 // Binary search the right group. 516 while (low < high) { 517 stbtt_int32 mid = low + ((high-low) >> 1); // rounds down, so low <= mid < high 518 stbtt_uint32 start_char = ttULONG(data+index_map+16+mid*12); 519 stbtt_uint32 end_char = ttULONG(data+index_map+16+mid*12+4); 520 if ((stbtt_uint32) unicode_codepoint < start_char) 521 high = mid; 522 else if ((stbtt_uint32) unicode_codepoint > end_char) 523 low = mid+1; 524 else { 525 stbtt_uint32 start_glyph = ttULONG(data+index_map+16+mid*12+8); 526 if (format == 12) 527 return start_glyph + unicode_codepoint-start_char; 528 else // format == 13 529 return start_glyph; 530 } 531 } 532 return 0; // not found 533 } 534 // @TODO 535 STBTT_assert(0); 536 return 0; 537 } 538 539 STBTT_DEF int stbtt_GetCodepointShape(const stbtt_fontinfo *info, int unicode_codepoint, stbtt_vertex **vertices) 540 { 541 return stbtt_GetGlyphShape(info, stbtt_FindGlyphIndex(info, unicode_codepoint), vertices); 542 } 543 544 static void stbtt_setvertex(stbtt_vertex *v, stbtt_uint8 type, stbtt_int32 x, stbtt_int32 y, stbtt_int32 cx, stbtt_int32 cy) 545 { 546 v->type = type; 547 v->x = (stbtt_int16) x; 548 v->y = (stbtt_int16) y; 549 v->cx = (stbtt_int16) cx; 550 v->cy = (stbtt_int16) cy; 551 } 552 553 static int stbtt__GetGlyfOffset(const stbtt_fontinfo *info, int glyph_index) 554 { 555 int g1,g2; 556 557 STBTT_assert(!info->cff.size); 558 559 if (glyph_index >= info->numGlyphs) return -1; // glyph index out of range 560 if (info->indexToLocFormat >= 2) return -1; // unknown index->glyph map format 561 562 if (info->indexToLocFormat == 0) { 563 g1 = info->glyf + ttUSHORT(info->data + info->loca + glyph_index * 2) * 2; 564 g2 = info->glyf + ttUSHORT(info->data + info->loca + glyph_index * 2 + 2) * 2; 565 } else { 566 g1 = info->glyf + ttULONG (info->data + info->loca + glyph_index * 4); 567 g2 = info->glyf + ttULONG (info->data + info->loca + glyph_index * 4 + 4); 568 } 569 570 return g1==g2 ? -1 : g1; // if length is 0, return -1 571 } 572 573 static int stbtt__GetGlyphInfoT2(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1); 574 575 STBTT_DEF int stbtt_GetGlyphBox(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1) 576 { 577 if (info->cff.size) { 578 stbtt__GetGlyphInfoT2(info, glyph_index, x0, y0, x1, y1); 579 } else { 580 int g = stbtt__GetGlyfOffset(info, glyph_index); 581 if (g < 0) return 0; 582 583 if (x0) *x0 = ttSHORT(info->data + g + 2); 584 if (y0) *y0 = ttSHORT(info->data + g + 4); 585 if (x1) *x1 = ttSHORT(info->data + g + 6); 586 if (y1) *y1 = ttSHORT(info->data + g + 8); 587 } 588 return 1; 589 } 590 591 STBTT_DEF int stbtt_GetCodepointBox(const stbtt_fontinfo *info, int codepoint, int *x0, int *y0, int *x1, int *y1) 592 { 593 return stbtt_GetGlyphBox(info, stbtt_FindGlyphIndex(info,codepoint), x0,y0,x1,y1); 594 } 595 596 STBTT_DEF int stbtt_IsGlyphEmpty(const stbtt_fontinfo *info, int glyph_index) 597 { 598 stbtt_int16 numberOfContours; 599 int g; 600 if (info->cff.size) 601 return stbtt__GetGlyphInfoT2(info, glyph_index, NULL, NULL, NULL, NULL) == 0; 602 g = stbtt__GetGlyfOffset(info, glyph_index); 603 if (g < 0) return 1; 604 numberOfContours = ttSHORT(info->data + g); 605 return numberOfContours == 0; 606 } 607 608 static int stbtt__close_shape(stbtt_vertex *vertices, int num_vertices, int was_off, int start_off, 609 stbtt_int32 sx, stbtt_int32 sy, stbtt_int32 scx, stbtt_int32 scy, stbtt_int32 cx, stbtt_int32 cy) 610 { 611 if (start_off) { 612 if (was_off) 613 stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, (cx+scx)>>1, (cy+scy)>>1, cx,cy); 614 stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, sx,sy,scx,scy); 615 } else { 616 if (was_off) 617 stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve,sx,sy,cx,cy); 618 else 619 stbtt_setvertex(&vertices[num_vertices++], STBTT_vline,sx,sy,0,0); 620 } 621 return num_vertices; 622 } 623 624 static int stbtt__GetGlyphShapeTT(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **pvertices) 625 { 626 stbtt_int16 numberOfContours; 627 stbtt_uint8 *endPtsOfContours; 628 stbtt_uint8 *data = info->data; 629 stbtt_vertex *vertices=0; 630 int num_vertices=0; 631 int g = stbtt__GetGlyfOffset(info, glyph_index); 632 633 *pvertices = NULL; 634 635 if (g < 0) return 0; 636 637 numberOfContours = ttSHORT(data + g); 638 639 if (numberOfContours > 0) { 640 stbtt_uint8 flags=0,flagcount; 641 stbtt_int32 ins, i,j=0,m,n, next_move, was_off=0, off, start_off=0; 642 stbtt_int32 x,y,cx,cy,sx,sy, scx,scy; 643 stbtt_uint8 *points; 644 endPtsOfContours = (data + g + 10); 645 ins = ttUSHORT(data + g + 10 + numberOfContours * 2); 646 points = data + g + 10 + numberOfContours * 2 + 2 + ins; 647 648 n = 1+ttUSHORT(endPtsOfContours + numberOfContours*2-2); 649 650 m = n + 2*numberOfContours; // a loose bound on how many vertices we might need 651 vertices = (stbtt_vertex *) STBTT_malloc(m * sizeof(vertices[0]), info->userdata); 652 if (vertices == 0) 653 return 0; 654 655 next_move = 0; 656 flagcount=0; 657 658 // in first pass, we load uninterpreted data into the allocated array 659 // above, shifted to the end of the array so we won't overwrite it when 660 // we create our final data starting from the front 661 662 off = m - n; // starting offset for uninterpreted data, regardless of how m ends up being calculated 663 664 // first load flags 665 666 for (i=0; i < n; ++i) { 667 if (flagcount == 0) { 668 flags = *points++; 669 if (flags & 8) 670 flagcount = *points++; 671 } else 672 --flagcount; 673 vertices[off+i].type = flags; 674 } 675 676 // now load x coordinates 677 x=0; 678 for (i=0; i < n; ++i) { 679 flags = vertices[off+i].type; 680 if (flags & 2) { 681 stbtt_int16 dx = *points++; 682 x += (flags & 16) ? dx : -dx; // ??? 683 } else { 684 if (!(flags & 16)) { 685 x = x + (stbtt_int16) (points[0]*256 + points[1]); 686 points += 2; 687 } 688 } 689 vertices[off+i].x = (stbtt_int16) x; 690 } 691 692 // now load y coordinates 693 y=0; 694 for (i=0; i < n; ++i) { 695 flags = vertices[off+i].type; 696 if (flags & 4) { 697 stbtt_int16 dy = *points++; 698 y += (flags & 32) ? dy : -dy; // ??? 699 } else { 700 if (!(flags & 32)) { 701 y = y + (stbtt_int16) (points[0]*256 + points[1]); 702 points += 2; 703 } 704 } 705 vertices[off+i].y = (stbtt_int16) y; 706 } 707 708 // now convert them to our format 709 num_vertices=0; 710 sx = sy = cx = cy = scx = scy = 0; 711 for (i=0; i < n; ++i) { 712 flags = vertices[off+i].type; 713 x = (stbtt_int16) vertices[off+i].x; 714 y = (stbtt_int16) vertices[off+i].y; 715 716 if (next_move == i) { 717 if (i != 0) 718 num_vertices = stbtt__close_shape(vertices, num_vertices, was_off, start_off, sx,sy,scx,scy,cx,cy); 719 720 // now start the new one 721 start_off = !(flags & 1); 722 if (start_off) { 723 // if we start off with an off-curve point, then when we need to find a point on the curve 724 // where we can start, and we need to save some state for when we wraparound. 725 scx = x; 726 scy = y; 727 if (!(vertices[off+i+1].type & 1)) { 728 // next point is also a curve point, so interpolate an on-point curve 729 sx = (x + (stbtt_int32) vertices[off+i+1].x) >> 1; 730 sy = (y + (stbtt_int32) vertices[off+i+1].y) >> 1; 731 } else { 732 // otherwise just use the next point as our start point 733 sx = (stbtt_int32) vertices[off+i+1].x; 734 sy = (stbtt_int32) vertices[off+i+1].y; 735 ++i; // we're using point i+1 as the starting point, so skip it 736 } 737 } else { 738 sx = x; 739 sy = y; 740 } 741 stbtt_setvertex(&vertices[num_vertices++], STBTT_vmove,sx,sy,0,0); 742 was_off = 0; 743 next_move = 1 + ttUSHORT(endPtsOfContours+j*2); 744 ++j; 745 } else { 746 if (!(flags & 1)) { // if it's a curve 747 if (was_off) // two off-curve control points in a row means interpolate an on-curve midpoint 748 stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, (cx+x)>>1, (cy+y)>>1, cx, cy); 749 cx = x; 750 cy = y; 751 was_off = 1; 752 } else { 753 if (was_off) 754 stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, x,y, cx, cy); 755 else 756 stbtt_setvertex(&vertices[num_vertices++], STBTT_vline, x,y,0,0); 757 was_off = 0; 758 } 759 } 760 } 761 num_vertices = stbtt__close_shape(vertices, num_vertices, was_off, start_off, sx,sy,scx,scy,cx,cy); 762 } else if (numberOfContours < 0) { 763 // Compound shapes. 764 int more = 1; 765 stbtt_uint8 *comp = data + g + 10; 766 num_vertices = 0; 767 vertices = 0; 768 while (more) { 769 stbtt_uint16 flags, gidx; 770 int comp_num_verts = 0, i; 771 stbtt_vertex *comp_verts = 0, *tmp = 0; 772 float mtx[6] = {1,0,0,1,0,0}, m, n; 773 774 flags = ttSHORT(comp); comp+=2; 775 gidx = ttSHORT(comp); comp+=2; 776 777 if (flags & 2) { // XY values 778 if (flags & 1) { // shorts 779 mtx[4] = ttSHORT(comp); comp+=2; 780 mtx[5] = ttSHORT(comp); comp+=2; 781 } else { 782 mtx[4] = ttCHAR(comp); comp+=1; 783 mtx[5] = ttCHAR(comp); comp+=1; 784 } 785 } 786 else { 787 // @TODO handle matching point 788 STBTT_assert(0); 789 } 790 if (flags & (1<<3)) { // WE_HAVE_A_SCALE 791 mtx[0] = mtx[3] = ttSHORT(comp)/16384.0f; comp+=2; 792 mtx[1] = mtx[2] = 0; 793 } else if (flags & (1<<6)) { // WE_HAVE_AN_X_AND_YSCALE 794 mtx[0] = ttSHORT(comp)/16384.0f; comp+=2; 795 mtx[1] = mtx[2] = 0; 796 mtx[3] = ttSHORT(comp)/16384.0f; comp+=2; 797 } else if (flags & (1<<7)) { // WE_HAVE_A_TWO_BY_TWO 798 mtx[0] = ttSHORT(comp)/16384.0f; comp+=2; 799 mtx[1] = ttSHORT(comp)/16384.0f; comp+=2; 800 mtx[2] = ttSHORT(comp)/16384.0f; comp+=2; 801 mtx[3] = ttSHORT(comp)/16384.0f; comp+=2; 802 } 803 804 // Find transformation scales. 805 m = (float) STBTT_sqrt(mtx[0]*mtx[0] + mtx[1]*mtx[1]); 806 n = (float) STBTT_sqrt(mtx[2]*mtx[2] + mtx[3]*mtx[3]); 807 808 // Get indexed glyph. 809 comp_num_verts = stbtt_GetGlyphShape(info, gidx, &comp_verts); 810 if (comp_num_verts > 0) { 811 // Transform vertices. 812 for (i = 0; i < comp_num_verts; ++i) { 813 stbtt_vertex* v = &comp_verts[i]; 814 stbtt_vertex_type x,y; 815 x=v->x; y=v->y; 816 v->x = (stbtt_vertex_type)(m * (mtx[0]*x + mtx[2]*y + mtx[4])); 817 v->y = (stbtt_vertex_type)(n * (mtx[1]*x + mtx[3]*y + mtx[5])); 818 x=v->cx; y=v->cy; 819 v->cx = (stbtt_vertex_type)(m * (mtx[0]*x + mtx[2]*y + mtx[4])); 820 v->cy = (stbtt_vertex_type)(n * (mtx[1]*x + mtx[3]*y + mtx[5])); 821 } 822 // Append vertices. 823 tmp = (stbtt_vertex*)STBTT_malloc((num_vertices+comp_num_verts)*sizeof(stbtt_vertex), info->userdata); 824 if (!tmp) { 825 if (vertices) STBTT_free(vertices, info->userdata); 826 if (comp_verts) STBTT_free(comp_verts, info->userdata); 827 return 0; 828 } 829 if (num_vertices > 0 && vertices) STBTT_memcpy(tmp, vertices, num_vertices*sizeof(stbtt_vertex)); 830 STBTT_memcpy(tmp+num_vertices, comp_verts, comp_num_verts*sizeof(stbtt_vertex)); 831 if (vertices) STBTT_free(vertices, info->userdata); 832 vertices = tmp; 833 STBTT_free(comp_verts, info->userdata); 834 num_vertices += comp_num_verts; 835 } 836 // More components ? 837 more = flags & (1<<5); 838 } 839 } else { 840 // numberOfCounters == 0, do nothing 841 } 842 843 *pvertices = vertices; 844 return num_vertices; 845 } 846 847 typedef struct 848 { 849 int bounds; 850 int started; 851 float first_x, first_y; 852 float x, y; 853 stbtt_int32 min_x, max_x, min_y, max_y; 854 855 stbtt_vertex *pvertices; 856 int num_vertices; 857 } stbtt__csctx; 858 859 #define STBTT__CSCTX_INIT(bounds) {bounds,0, 0,0, 0,0, 0,0,0,0, NULL, 0} 860 861 static void stbtt__track_vertex(stbtt__csctx *c, stbtt_int32 x, stbtt_int32 y) 862 { 863 if (x > c->max_x || !c->started) c->max_x = x; 864 if (y > c->max_y || !c->started) c->max_y = y; 865 if (x < c->min_x || !c->started) c->min_x = x; 866 if (y < c->min_y || !c->started) c->min_y = y; 867 c->started = 1; 868 } 869 870 static void stbtt__csctx_v(stbtt__csctx *c, stbtt_uint8 type, stbtt_int32 x, stbtt_int32 y, stbtt_int32 cx, stbtt_int32 cy, stbtt_int32 cx1, stbtt_int32 cy1) 871 { 872 if (c->bounds) { 873 stbtt__track_vertex(c, x, y); 874 if (type == STBTT_vcubic) { 875 stbtt__track_vertex(c, cx, cy); 876 stbtt__track_vertex(c, cx1, cy1); 877 } 878 } else { 879 stbtt_setvertex(&c->pvertices[c->num_vertices], type, x, y, cx, cy); 880 c->pvertices[c->num_vertices].cx1 = (stbtt_int16) cx1; 881 c->pvertices[c->num_vertices].cy1 = (stbtt_int16) cy1; 882 } 883 c->num_vertices++; 884 } 885 886 static void stbtt__csctx_close_shape(stbtt__csctx *ctx) 887 { 888 if (ctx->first_x != ctx->x || ctx->first_y != ctx->y) 889 stbtt__csctx_v(ctx, STBTT_vline, (int)ctx->first_x, (int)ctx->first_y, 0, 0, 0, 0); 890 } 891 892 static void stbtt__csctx_rmove_to(stbtt__csctx *ctx, float dx, float dy) 893 { 894 stbtt__csctx_close_shape(ctx); 895 ctx->first_x = ctx->x = ctx->x + dx; 896 ctx->first_y = ctx->y = ctx->y + dy; 897 stbtt__csctx_v(ctx, STBTT_vmove, (int)ctx->x, (int)ctx->y, 0, 0, 0, 0); 898 } 899 900 static void stbtt__csctx_rline_to(stbtt__csctx *ctx, float dx, float dy) 901 { 902 ctx->x += dx; 903 ctx->y += dy; 904 stbtt__csctx_v(ctx, STBTT_vline, (int)ctx->x, (int)ctx->y, 0, 0, 0, 0); 905 } 906 907 static void stbtt__csctx_rccurve_to(stbtt__csctx *ctx, float dx1, float dy1, float dx2, float dy2, float dx3, float dy3) 908 { 909 float cx1 = ctx->x + dx1; 910 float cy1 = ctx->y + dy1; 911 float cx2 = cx1 + dx2; 912 float cy2 = cy1 + dy2; 913 ctx->x = cx2 + dx3; 914 ctx->y = cy2 + dy3; 915 stbtt__csctx_v(ctx, STBTT_vcubic, (int)ctx->x, (int)ctx->y, (int)cx1, (int)cy1, (int)cx2, (int)cy2); 916 } 917 918 static stbtt__buf stbtt__get_subr(stbtt__buf idx, int n) 919 { 920 int count = stbtt__cff_index_count(&idx); 921 int bias = 107; 922 if (count >= 33900) 923 bias = 32768; 924 else if (count >= 1240) 925 bias = 1131; 926 n += bias; 927 if (n < 0 || n >= count) 928 return stbtt__new_buf(NULL, 0); 929 return stbtt__cff_index_get(idx, n); 930 } 931 932 static stbtt__buf stbtt__cid_get_glyph_subrs(const stbtt_fontinfo *info, int glyph_index) 933 { 934 stbtt__buf fdselect = info->fdselect; 935 int nranges, start, end, v, fmt, fdselector = -1, i; 936 937 stbtt__buf_seek(&fdselect, 0); 938 fmt = stbtt__buf_get8(&fdselect); 939 if (fmt == 0) { 940 // untested 941 stbtt__buf_skip(&fdselect, glyph_index); 942 fdselector = stbtt__buf_get8(&fdselect); 943 } else if (fmt == 3) { 944 nranges = stbtt__buf_get16(&fdselect); 945 start = stbtt__buf_get16(&fdselect); 946 for (i = 0; i < nranges; i++) { 947 v = stbtt__buf_get8(&fdselect); 948 end = stbtt__buf_get16(&fdselect); 949 if (glyph_index >= start && glyph_index < end) { 950 fdselector = v; 951 break; 952 } 953 start = end; 954 } 955 } 956 if (fdselector == -1) stbtt__new_buf(NULL, 0); 957 return stbtt__get_subrs(info->cff, stbtt__cff_index_get(info->fontdicts, fdselector)); 958 } 959 960 static int stbtt__run_charstring(const stbtt_fontinfo *info, int glyph_index, stbtt__csctx *c) 961 { 962 int in_header = 1, maskbits = 0, subr_stack_height = 0, sp = 0, v, i, b0; 963 int has_subrs = 0, clear_stack; 964 float s[48]; 965 stbtt__buf subr_stack[10], subrs = info->subrs, b; 966 float f; 967 968 #define STBTT__CSERR(s) (0) 969 970 // this currently ignores the initial width value, which isn't needed if we have hmtx 971 b = stbtt__cff_index_get(info->charstrings, glyph_index); 972 while (b.cursor < b.size) { 973 i = 0; 974 clear_stack = 1; 975 b0 = stbtt__buf_get8(&b); 976 switch (b0) { 977 // @TODO implement hinting 978 case 0x13: // hintmask 979 case 0x14: // cntrmask 980 if (in_header) 981 maskbits += (sp / 2); // implicit "vstem" 982 in_header = 0; 983 stbtt__buf_skip(&b, (maskbits + 7) / 8); 984 break; 985 986 case 0x01: // hstem 987 case 0x03: // vstem 988 case 0x12: // hstemhm 989 case 0x17: // vstemhm 990 maskbits += (sp / 2); 991 break; 992 993 case 0x15: // rmoveto 994 in_header = 0; 995 if (sp < 2) return STBTT__CSERR("rmoveto stack"); 996 stbtt__csctx_rmove_to(c, s[sp-2], s[sp-1]); 997 break; 998 case 0x04: // vmoveto 999 in_header = 0; 1000 if (sp < 1) return STBTT__CSERR("vmoveto stack"); 1001 stbtt__csctx_rmove_to(c, 0, s[sp-1]); 1002 break; 1003 case 0x16: // hmoveto 1004 in_header = 0; 1005 if (sp < 1) return STBTT__CSERR("hmoveto stack"); 1006 stbtt__csctx_rmove_to(c, s[sp-1], 0); 1007 break; 1008 1009 case 0x05: // rlineto 1010 if (sp < 2) return STBTT__CSERR("rlineto stack"); 1011 for (; i + 1 < sp; i += 2) 1012 stbtt__csctx_rline_to(c, s[i], s[i+1]); 1013 break; 1014 1015 // hlineto/vlineto and vhcurveto/hvcurveto alternate horizontal and vertical 1016 // starting from a different place. 1017 1018 case 0x07: // vlineto 1019 if (sp < 1) return STBTT__CSERR("vlineto stack"); 1020 goto vlineto; 1021 case 0x06: // hlineto 1022 if (sp < 1) return STBTT__CSERR("hlineto stack"); 1023 for (;;) { 1024 if (i >= sp) break; 1025 stbtt__csctx_rline_to(c, s[i], 0); 1026 i++; 1027 vlineto: 1028 if (i >= sp) break; 1029 stbtt__csctx_rline_to(c, 0, s[i]); 1030 i++; 1031 } 1032 break; 1033 1034 case 0x1F: // hvcurveto 1035 if (sp < 4) return STBTT__CSERR("hvcurveto stack"); 1036 goto hvcurveto; 1037 case 0x1E: // vhcurveto 1038 if (sp < 4) return STBTT__CSERR("vhcurveto stack"); 1039 for (;;) { 1040 if (i + 3 >= sp) break; 1041 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); 1042 i += 4; 1043 hvcurveto: 1044 if (i + 3 >= sp) break; 1045 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]); 1046 i += 4; 1047 } 1048 break; 1049 1050 case 0x08: // rrcurveto 1051 if (sp < 6) return STBTT__CSERR("rcurveline stack"); 1052 for (; i + 5 < sp; i += 6) 1053 stbtt__csctx_rccurve_to(c, s[i], s[i+1], s[i+2], s[i+3], s[i+4], s[i+5]); 1054 break; 1055 1056 case 0x18: // rcurveline 1057 if (sp < 8) return STBTT__CSERR("rcurveline stack"); 1058 for (; i + 5 < sp - 2; i += 6) 1059 stbtt__csctx_rccurve_to(c, s[i], s[i+1], s[i+2], s[i+3], s[i+4], s[i+5]); 1060 if (i + 1 >= sp) return STBTT__CSERR("rcurveline stack"); 1061 stbtt__csctx_rline_to(c, s[i], s[i+1]); 1062 break; 1063 1064 case 0x19: // rlinecurve 1065 if (sp < 8) return STBTT__CSERR("rlinecurve stack"); 1066 for (; i + 1 < sp - 6; i += 2) 1067 stbtt__csctx_rline_to(c, s[i], s[i+1]); 1068 if (i + 5 >= sp) return STBTT__CSERR("rlinecurve stack"); 1069 stbtt__csctx_rccurve_to(c, s[i], s[i+1], s[i+2], s[i+3], s[i+4], s[i+5]); 1070 break; 1071 1072 case 0x1A: // vvcurveto 1073 case 0x1B: // hhcurveto 1074 if (sp < 4) return STBTT__CSERR("(vv|hh)curveto stack"); 1075 f = 0.0; 1076 if (sp & 1) { f = s[i]; i++; } 1077 for (; i + 3 < sp; i += 4) { 1078 if (b0 == 0x1B) 1079 stbtt__csctx_rccurve_to(c, s[i], f, s[i+1], s[i+2], s[i+3], 0.0); 1080 else 1081 stbtt__csctx_rccurve_to(c, f, s[i], s[i+1], s[i+2], 0.0, s[i+3]); 1082 f = 0.0; 1083 } 1084 break; 1085 1086 case 0x0A: // callsubr 1087 if (!has_subrs) { 1088 if (info->fdselect.size) 1089 subrs = stbtt__cid_get_glyph_subrs(info, glyph_index); 1090 has_subrs = 1; 1091 } 1092 // FALLTHROUGH 1093 case 0x1D: // callgsubr 1094 if (sp < 1) return STBTT__CSERR("call(g|)subr stack"); 1095 v = (int) s[--sp]; 1096 if (subr_stack_height >= 10) return STBTT__CSERR("recursion limit"); 1097 subr_stack[subr_stack_height++] = b; 1098 b = stbtt__get_subr(b0 == 0x0A ? subrs : info->gsubrs, v); 1099 if (b.size == 0) return STBTT__CSERR("subr not found"); 1100 b.cursor = 0; 1101 clear_stack = 0; 1102 break; 1103 1104 case 0x0B: // return 1105 if (subr_stack_height <= 0) return STBTT__CSERR("return outside subr"); 1106 b = subr_stack[--subr_stack_height]; 1107 clear_stack = 0; 1108 break; 1109 1110 case 0x0E: // endchar 1111 stbtt__csctx_close_shape(c); 1112 return 1; 1113 1114 case 0x0C: { // two-byte escape 1115 float dx1, dx2, dx3, dx4, dx5, dx6, dy1, dy2, dy3, dy4, dy5, dy6; 1116 float dx, dy; 1117 int b1 = stbtt__buf_get8(&b); 1118 switch (b1) { 1119 // @TODO These "flex" implementations ignore the flex-depth and resolution, 1120 // and always draw beziers. 1121 case 0x22: // hflex 1122 if (sp < 7) return STBTT__CSERR("hflex stack"); 1123 dx1 = s[0]; 1124 dx2 = s[1]; 1125 dy2 = s[2]; 1126 dx3 = s[3]; 1127 dx4 = s[4]; 1128 dx5 = s[5]; 1129 dx6 = s[6]; 1130 stbtt__csctx_rccurve_to(c, dx1, 0, dx2, dy2, dx3, 0); 1131 stbtt__csctx_rccurve_to(c, dx4, 0, dx5, -dy2, dx6, 0); 1132 break; 1133 1134 case 0x23: // flex 1135 if (sp < 13) return STBTT__CSERR("flex stack"); 1136 dx1 = s[0]; 1137 dy1 = s[1]; 1138 dx2 = s[2]; 1139 dy2 = s[3]; 1140 dx3 = s[4]; 1141 dy3 = s[5]; 1142 dx4 = s[6]; 1143 dy4 = s[7]; 1144 dx5 = s[8]; 1145 dy5 = s[9]; 1146 dx6 = s[10]; 1147 dy6 = s[11]; 1148 //fd is s[12] 1149 stbtt__csctx_rccurve_to(c, dx1, dy1, dx2, dy2, dx3, dy3); 1150 stbtt__csctx_rccurve_to(c, dx4, dy4, dx5, dy5, dx6, dy6); 1151 break; 1152 1153 case 0x24: // hflex1 1154 if (sp < 9) return STBTT__CSERR("hflex1 stack"); 1155 dx1 = s[0]; 1156 dy1 = s[1]; 1157 dx2 = s[2]; 1158 dy2 = s[3]; 1159 dx3 = s[4]; 1160 dx4 = s[5]; 1161 dx5 = s[6]; 1162 dy5 = s[7]; 1163 dx6 = s[8]; 1164 stbtt__csctx_rccurve_to(c, dx1, dy1, dx2, dy2, dx3, 0); 1165 stbtt__csctx_rccurve_to(c, dx4, 0, dx5, dy5, dx6, -(dy1+dy2+dy5)); 1166 break; 1167 1168 case 0x25: // flex1 1169 if (sp < 11) return STBTT__CSERR("flex1 stack"); 1170 dx1 = s[0]; 1171 dy1 = s[1]; 1172 dx2 = s[2]; 1173 dy2 = s[3]; 1174 dx3 = s[4]; 1175 dy3 = s[5]; 1176 dx4 = s[6]; 1177 dy4 = s[7]; 1178 dx5 = s[8]; 1179 dy5 = s[9]; 1180 dx6 = dy6 = s[10]; 1181 dx = dx1+dx2+dx3+dx4+dx5; 1182 dy = dy1+dy2+dy3+dy4+dy5; 1183 if (STBTT_fabs(dx) > STBTT_fabs(dy)) 1184 dy6 = -dy; 1185 else 1186 dx6 = -dx; 1187 stbtt__csctx_rccurve_to(c, dx1, dy1, dx2, dy2, dx3, dy3); 1188 stbtt__csctx_rccurve_to(c, dx4, dy4, dx5, dy5, dx6, dy6); 1189 break; 1190 1191 default: 1192 return STBTT__CSERR("unimplemented"); 1193 } 1194 } break; 1195 1196 default: 1197 if (b0 != 255 && b0 != 28 && b0 < 32) 1198 return STBTT__CSERR("reserved operator"); 1199 1200 // push immediate 1201 if (b0 == 255) { 1202 f = (float)(stbtt_int32)stbtt__buf_get32(&b) / 0x10000; 1203 } else { 1204 stbtt__buf_skip(&b, -1); 1205 f = (float)(stbtt_int16)stbtt__cff_int(&b); 1206 } 1207 if (sp >= 48) return STBTT__CSERR("push stack overflow"); 1208 s[sp++] = f; 1209 clear_stack = 0; 1210 break; 1211 } 1212 if (clear_stack) sp = 0; 1213 } 1214 return STBTT__CSERR("no endchar"); 1215 1216 #undef STBTT__CSERR 1217 } 1218 1219 static int stbtt__GetGlyphShapeT2(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **pvertices) 1220 { 1221 // runs the charstring twice, once to count and once to output (to avoid realloc) 1222 stbtt__csctx count_ctx = STBTT__CSCTX_INIT(1); 1223 stbtt__csctx output_ctx = STBTT__CSCTX_INIT(0); 1224 if (stbtt__run_charstring(info, glyph_index, &count_ctx)) { 1225 *pvertices = (stbtt_vertex*)STBTT_malloc(count_ctx.num_vertices*sizeof(stbtt_vertex), info->userdata); 1226 output_ctx.pvertices = *pvertices; 1227 if (stbtt__run_charstring(info, glyph_index, &output_ctx)) { 1228 STBTT_assert(output_ctx.num_vertices == count_ctx.num_vertices); 1229 return output_ctx.num_vertices; 1230 } 1231 } 1232 *pvertices = NULL; 1233 return 0; 1234 } 1235 1236 static int stbtt__GetGlyphInfoT2(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1) 1237 { 1238 stbtt__csctx c = STBTT__CSCTX_INIT(1); 1239 int r = stbtt__run_charstring(info, glyph_index, &c); 1240 if (x0) *x0 = r ? c.min_x : 0; 1241 if (y0) *y0 = r ? c.min_y : 0; 1242 if (x1) *x1 = r ? c.max_x : 0; 1243 if (y1) *y1 = r ? c.max_y : 0; 1244 return r ? c.num_vertices : 0; 1245 } 1246 1247 STBTT_DEF int stbtt_GetGlyphShape(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **pvertices) 1248 { 1249 if (!info->cff.size) 1250 return stbtt__GetGlyphShapeTT(info, glyph_index, pvertices); 1251 else 1252 return stbtt__GetGlyphShapeT2(info, glyph_index, pvertices); 1253 } 1254 1255 STBTT_DEF void stbtt_GetGlyphHMetrics(const stbtt_fontinfo *info, int glyph_index, int *advanceWidth, int *leftSideBearing) 1256 { 1257 stbtt_uint16 numOfLongHorMetrics = ttUSHORT(info->data+info->hhea + 34); 1258 if (glyph_index < numOfLongHorMetrics) { 1259 if (advanceWidth) *advanceWidth = ttSHORT(info->data + info->hmtx + 4*glyph_index); 1260 if (leftSideBearing) *leftSideBearing = ttSHORT(info->data + info->hmtx + 4*glyph_index + 2); 1261 } else { 1262 if (advanceWidth) *advanceWidth = ttSHORT(info->data + info->hmtx + 4*(numOfLongHorMetrics-1)); 1263 if (leftSideBearing) *leftSideBearing = ttSHORT(info->data + info->hmtx + 4*numOfLongHorMetrics + 2*(glyph_index - numOfLongHorMetrics)); 1264 } 1265 } 1266 1267 STBTT_DEF int stbtt_GetKerningTableLength(const stbtt_fontinfo *info) 1268 { 1269 stbtt_uint8 *data = info->data + info->kern; 1270 1271 // we only look at the first table. it must be 'horizontal' and format 0. 1272 if (!info->kern) 1273 return 0; 1274 if (ttUSHORT(data+2) < 1) // number of tables, need at least 1 1275 return 0; 1276 if (ttUSHORT(data+8) != 1) // horizontal flag must be set in format 1277 return 0; 1278 1279 return ttUSHORT(data+10); 1280 } 1281 1282 STBTT_DEF int stbtt_GetKerningTable(const stbtt_fontinfo *info, stbtt_kerningentry* table, int table_length) 1283 { 1284 stbtt_uint8 *data = info->data + info->kern; 1285 int k, length; 1286 1287 // we only look at the first table. it must be 'horizontal' and format 0. 1288 if (!info->kern) 1289 return 0; 1290 if (ttUSHORT(data+2) < 1) // number of tables, need at least 1 1291 return 0; 1292 if (ttUSHORT(data+8) != 1) // horizontal flag must be set in format 1293 return 0; 1294 1295 length = ttUSHORT(data+10); 1296 if (table_length < length) 1297 length = table_length; 1298 1299 for (k = 0; k < length; k++) 1300 { 1301 table[k].glyph1 = ttUSHORT(data+18+(k*6)); 1302 table[k].glyph2 = ttUSHORT(data+20+(k*6)); 1303 table[k].advance = ttSHORT(data+22+(k*6)); 1304 } 1305 1306 return length; 1307 } 1308 1309 static int stbtt__GetGlyphKernInfoAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2) 1310 { 1311 stbtt_uint8 *data = info->data + info->kern; 1312 stbtt_uint32 needle, straw; 1313 int l, r, m; 1314 1315 // we only look at the first table. it must be 'horizontal' and format 0. 1316 if (!info->kern) 1317 return 0; 1318 if (ttUSHORT(data+2) < 1) // number of tables, need at least 1 1319 return 0; 1320 if (ttUSHORT(data+8) != 1) // horizontal flag must be set in format 1321 return 0; 1322 1323 l = 0; 1324 r = ttUSHORT(data+10) - 1; 1325 needle = glyph1 << 16 | glyph2; 1326 while (l <= r) { 1327 m = (l + r) >> 1; 1328 straw = ttULONG(data+18+(m*6)); // note: unaligned read 1329 if (needle < straw) 1330 r = m - 1; 1331 else if (needle > straw) 1332 l = m + 1; 1333 else 1334 return ttSHORT(data+22+(m*6)); 1335 } 1336 return 0; 1337 } 1338 1339 static stbtt_int32 stbtt__GetCoverageIndex(stbtt_uint8 *coverageTable, int glyph) 1340 { 1341 stbtt_uint16 coverageFormat = ttUSHORT(coverageTable); 1342 switch (coverageFormat) { 1343 case 1: { 1344 stbtt_uint16 glyphCount = ttUSHORT(coverageTable + 2); 1345 1346 // Binary search. 1347 stbtt_int32 l=0, r=glyphCount-1, m; 1348 int straw, needle=glyph; 1349 while (l <= r) { 1350 stbtt_uint8 *glyphArray = coverageTable + 4; 1351 stbtt_uint16 glyphID; 1352 m = (l + r) >> 1; 1353 glyphID = ttUSHORT(glyphArray + 2 * m); 1354 straw = glyphID; 1355 if (needle < straw) 1356 r = m - 1; 1357 else if (needle > straw) 1358 l = m + 1; 1359 else { 1360 return m; 1361 } 1362 } 1363 break; 1364 } 1365 1366 case 2: { 1367 stbtt_uint16 rangeCount = ttUSHORT(coverageTable + 2); 1368 stbtt_uint8 *rangeArray = coverageTable + 4; 1369 1370 // Binary search. 1371 stbtt_int32 l=0, r=rangeCount-1, m; 1372 int strawStart, strawEnd, needle=glyph; 1373 while (l <= r) { 1374 stbtt_uint8 *rangeRecord; 1375 m = (l + r) >> 1; 1376 rangeRecord = rangeArray + 6 * m; 1377 strawStart = ttUSHORT(rangeRecord); 1378 strawEnd = ttUSHORT(rangeRecord + 2); 1379 if (needle < strawStart) 1380 r = m - 1; 1381 else if (needle > strawEnd) 1382 l = m + 1; 1383 else { 1384 stbtt_uint16 startCoverageIndex = ttUSHORT(rangeRecord + 4); 1385 return startCoverageIndex + glyph - strawStart; 1386 } 1387 } 1388 break; 1389 } 1390 1391 default: return -1; // unsupported 1392 } 1393 1394 return -1; 1395 } 1396 1397 static stbtt_int32 stbtt__GetGlyphClass(stbtt_uint8 *classDefTable, int glyph) 1398 { 1399 stbtt_uint16 classDefFormat = ttUSHORT(classDefTable); 1400 switch (classDefFormat) 1401 { 1402 case 1: { 1403 stbtt_uint16 startGlyphID = ttUSHORT(classDefTable + 2); 1404 stbtt_uint16 glyphCount = ttUSHORT(classDefTable + 4); 1405 stbtt_uint8 *classDef1ValueArray = classDefTable + 6; 1406 1407 if (glyph >= startGlyphID && glyph < startGlyphID + glyphCount) 1408 return (stbtt_int32)ttUSHORT(classDef1ValueArray + 2 * (glyph - startGlyphID)); 1409 break; 1410 } 1411 1412 case 2: { 1413 stbtt_uint16 classRangeCount = ttUSHORT(classDefTable + 2); 1414 stbtt_uint8 *classRangeRecords = classDefTable + 4; 1415 1416 // Binary search. 1417 stbtt_int32 l=0, r=classRangeCount-1, m; 1418 int strawStart, strawEnd, needle=glyph; 1419 while (l <= r) { 1420 stbtt_uint8 *classRangeRecord; 1421 m = (l + r) >> 1; 1422 classRangeRecord = classRangeRecords + 6 * m; 1423 strawStart = ttUSHORT(classRangeRecord); 1424 strawEnd = ttUSHORT(classRangeRecord + 2); 1425 if (needle < strawStart) 1426 r = m - 1; 1427 else if (needle > strawEnd) 1428 l = m + 1; 1429 else 1430 return (stbtt_int32)ttUSHORT(classRangeRecord + 4); 1431 } 1432 break; 1433 } 1434 1435 default: 1436 return -1; // Unsupported definition type, return an error. 1437 } 1438 1439 // "All glyphs not assigned to a class fall into class 0". (OpenType spec) 1440 return 0; 1441 } 1442 1443 // Define to STBTT_assert(x) if you want to break on unimplemented formats. 1444 #define STBTT_GPOS_TODO_assert(x) 1445 1446 static stbtt_int32 stbtt__GetGlyphGPOSInfoAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2) 1447 { 1448 stbtt_uint16 lookupListOffset; 1449 stbtt_uint8 *lookupList; 1450 stbtt_uint16 lookupCount; 1451 stbtt_uint8 *data; 1452 stbtt_int32 i, sti; 1453 1454 if (!info->gpos) return 0; 1455 1456 data = info->data + info->gpos; 1457 1458 if (ttUSHORT(data+0) != 1) return 0; // Major version 1 1459 if (ttUSHORT(data+2) != 0) return 0; // Minor version 0 1460 1461 lookupListOffset = ttUSHORT(data+8); 1462 lookupList = data + lookupListOffset; 1463 lookupCount = ttUSHORT(lookupList); 1464 1465 for (i=0; i<lookupCount; ++i) { 1466 stbtt_uint16 lookupOffset = ttUSHORT(lookupList + 2 + 2 * i); 1467 stbtt_uint8 *lookupTable = lookupList + lookupOffset; 1468 1469 stbtt_uint16 lookupType = ttUSHORT(lookupTable); 1470 stbtt_uint16 subTableCount = ttUSHORT(lookupTable + 4); 1471 stbtt_uint8 *subTableOffsets = lookupTable + 6; 1472 if (lookupType != 2) // Pair Adjustment Positioning Subtable 1473 continue; 1474 1475 for (sti=0; sti<subTableCount; sti++) { 1476 stbtt_uint16 subtableOffset = ttUSHORT(subTableOffsets + 2 * sti); 1477 stbtt_uint8 *table = lookupTable + subtableOffset; 1478 stbtt_uint16 posFormat = ttUSHORT(table); 1479 stbtt_uint16 coverageOffset = ttUSHORT(table + 2); 1480 stbtt_int32 coverageIndex = stbtt__GetCoverageIndex(table + coverageOffset, glyph1); 1481 if (coverageIndex == -1) continue; 1482 1483 switch (posFormat) { 1484 case 1: { 1485 stbtt_int32 l, r, m; 1486 int straw, needle; 1487 stbtt_uint16 valueFormat1 = ttUSHORT(table + 4); 1488 stbtt_uint16 valueFormat2 = ttUSHORT(table + 6); 1489 if (valueFormat1 == 4 && valueFormat2 == 0) { // Support more formats? 1490 stbtt_int32 valueRecordPairSizeInBytes = 2; 1491 stbtt_uint16 pairSetCount = ttUSHORT(table + 8); 1492 stbtt_uint16 pairPosOffset = ttUSHORT(table + 10 + 2 * coverageIndex); 1493 stbtt_uint8 *pairValueTable = table + pairPosOffset; 1494 stbtt_uint16 pairValueCount = ttUSHORT(pairValueTable); 1495 stbtt_uint8 *pairValueArray = pairValueTable + 2; 1496 1497 if (coverageIndex >= pairSetCount) return 0; 1498 1499 needle=glyph2; 1500 r=pairValueCount-1; 1501 l=0; 1502 1503 // Binary search. 1504 while (l <= r) { 1505 stbtt_uint16 secondGlyph; 1506 stbtt_uint8 *pairValue; 1507 m = (l + r) >> 1; 1508 pairValue = pairValueArray + (2 + valueRecordPairSizeInBytes) * m; 1509 secondGlyph = ttUSHORT(pairValue); 1510 straw = secondGlyph; 1511 if (needle < straw) 1512 r = m - 1; 1513 else if (needle > straw) 1514 l = m + 1; 1515 else { 1516 stbtt_int16 xAdvance = ttSHORT(pairValue + 2); 1517 return xAdvance; 1518 } 1519 } 1520 } else 1521 return 0; 1522 break; 1523 } 1524 1525 case 2: { 1526 stbtt_uint16 valueFormat1 = ttUSHORT(table + 4); 1527 stbtt_uint16 valueFormat2 = ttUSHORT(table + 6); 1528 if (valueFormat1 == 4 && valueFormat2 == 0) { // Support more formats? 1529 stbtt_uint16 classDef1Offset = ttUSHORT(table + 8); 1530 stbtt_uint16 classDef2Offset = ttUSHORT(table + 10); 1531 int glyph1class = stbtt__GetGlyphClass(table + classDef1Offset, glyph1); 1532 int glyph2class = stbtt__GetGlyphClass(table + classDef2Offset, glyph2); 1533 1534 stbtt_uint16 class1Count = ttUSHORT(table + 12); 1535 stbtt_uint16 class2Count = ttUSHORT(table + 14); 1536 stbtt_uint8 *class1Records, *class2Records; 1537 stbtt_int16 xAdvance; 1538 1539 if (glyph1class < 0 || glyph1class >= class1Count) return 0; // malformed 1540 if (glyph2class < 0 || glyph2class >= class2Count) return 0; // malformed 1541 1542 class1Records = table + 16; 1543 class2Records = class1Records + 2 * (glyph1class * class2Count); 1544 xAdvance = ttSHORT(class2Records + 2 * glyph2class); 1545 return xAdvance; 1546 } else 1547 return 0; 1548 break; 1549 } 1550 1551 default: 1552 return 0; // Unsupported position format 1553 } 1554 } 1555 } 1556 1557 return 0; 1558 } 1559 1560 STBTT_DEF int stbtt_GetGlyphKernAdvance(const stbtt_fontinfo *info, int g1, int g2) 1561 { 1562 int xAdvance = 0; 1563 1564 if (info->gpos) 1565 xAdvance += stbtt__GetGlyphGPOSInfoAdvance(info, g1, g2); 1566 else if (info->kern) 1567 xAdvance += stbtt__GetGlyphKernInfoAdvance(info, g1, g2); 1568 1569 return xAdvance; 1570 } 1571 1572 STBTT_DEF int stbtt_GetCodepointKernAdvance(const stbtt_fontinfo *info, int ch1, int ch2) 1573 { 1574 if (!info->kern && !info->gpos) // if no kerning table, don't waste time looking up both codepoint->glyphs 1575 return 0; 1576 return stbtt_GetGlyphKernAdvance(info, stbtt_FindGlyphIndex(info,ch1), stbtt_FindGlyphIndex(info,ch2)); 1577 } 1578 1579 STBTT_DEF void stbtt_GetCodepointHMetrics(const stbtt_fontinfo *info, int codepoint, int *advanceWidth, int *leftSideBearing) 1580 { 1581 stbtt_GetGlyphHMetrics(info, stbtt_FindGlyphIndex(info,codepoint), advanceWidth, leftSideBearing); 1582 } 1583 1584 STBTT_DEF void stbtt_GetFontVMetrics(const stbtt_fontinfo *info, int *ascent, int *descent, int *lineGap) 1585 { 1586 if (ascent ) *ascent = ttSHORT(info->data+info->hhea + 4); 1587 if (descent) *descent = ttSHORT(info->data+info->hhea + 6); 1588 if (lineGap) *lineGap = ttSHORT(info->data+info->hhea + 8); 1589 } 1590 1591 STBTT_DEF int stbtt_GetFontVMetricsOS2(const stbtt_fontinfo *info, int *typoAscent, int *typoDescent, int *typoLineGap) 1592 { 1593 int tab = stbtt__find_table(info->data, info->fontstart, "OS/2"); 1594 if (!tab) 1595 return 0; 1596 if (typoAscent ) *typoAscent = ttSHORT(info->data+tab + 68); 1597 if (typoDescent) *typoDescent = ttSHORT(info->data+tab + 70); 1598 if (typoLineGap) *typoLineGap = ttSHORT(info->data+tab + 72); 1599 return 1; 1600 } 1601 1602 STBTT_DEF void stbtt_GetFontBoundingBox(const stbtt_fontinfo *info, int *x0, int *y0, int *x1, int *y1) 1603 { 1604 *x0 = ttSHORT(info->data + info->head + 36); 1605 *y0 = ttSHORT(info->data + info->head + 38); 1606 *x1 = ttSHORT(info->data + info->head + 40); 1607 *y1 = ttSHORT(info->data + info->head + 42); 1608 } 1609 1610 STBTT_DEF float stbtt_ScaleForPixelHeight(const stbtt_fontinfo *info, float height) 1611 { 1612 int fheight = ttSHORT(info->data + info->hhea + 4) - ttSHORT(info->data + info->hhea + 6); 1613 return (float) height / fheight; 1614 } 1615 1616 STBTT_DEF float stbtt_ScaleForMappingEmToPixels(const stbtt_fontinfo *info, float pixels) 1617 { 1618 int unitsPerEm = ttUSHORT(info->data + info->head + 18); 1619 return pixels / unitsPerEm; 1620 } 1621 1622 STBTT_DEF void stbtt_FreeShape(const stbtt_fontinfo *info, stbtt_vertex *v) 1623 { 1624 STBTT_free(v, info->userdata); 1625 } 1626 1627 STBTT_DEF stbtt_uint8 *stbtt_FindSVGDoc(const stbtt_fontinfo *info, int gl) 1628 { 1629 int i; 1630 stbtt_uint8 *data = info->data; 1631 stbtt_uint8 *svg_doc_list = data + stbtt__get_svg((stbtt_fontinfo *) info); 1632 1633 int numEntries = ttUSHORT(svg_doc_list); 1634 stbtt_uint8 *svg_docs = svg_doc_list + 2; 1635 1636 for(i=0; i<numEntries; i++) { 1637 stbtt_uint8 *svg_doc = svg_docs + (12 * i); 1638 if ((gl >= ttUSHORT(svg_doc)) && (gl <= ttUSHORT(svg_doc + 2))) 1639 return svg_doc; 1640 } 1641 return 0; 1642 } 1643 1644 STBTT_DEF int stbtt_GetGlyphSVG(const stbtt_fontinfo *info, int gl, const char **svg) 1645 { 1646 stbtt_uint8 *data = info->data; 1647 stbtt_uint8 *svg_doc; 1648 1649 if (info->svg == 0) 1650 return 0; 1651 1652 svg_doc = stbtt_FindSVGDoc(info, gl); 1653 if (svg_doc != NULL) { 1654 *svg = (char *) data + info->svg + ttULONG(svg_doc + 4); 1655 return ttULONG(svg_doc + 8); 1656 } else { 1657 return 0; 1658 } 1659 } 1660 1661 STBTT_DEF int stbtt_GetCodepointSVG(const stbtt_fontinfo *info, int unicode_codepoint, const char **svg) 1662 { 1663 return stbtt_GetGlyphSVG(info, stbtt_FindGlyphIndex(info, unicode_codepoint), svg); 1664 } 1665 1666 ////////////////////////////////////////////////////////////////////////////// 1667 // 1668 // antialiasing software rasterizer 1669 // 1670 1671 STBTT_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) 1672 { 1673 int x0=0,y0=0,x1,y1; // =0 suppresses compiler warning 1674 if (!stbtt_GetGlyphBox(font, glyph, &x0,&y0,&x1,&y1)) { 1675 // e.g. space character 1676 if (ix0) *ix0 = 0; 1677 if (iy0) *iy0 = 0; 1678 if (ix1) *ix1 = 0; 1679 if (iy1) *iy1 = 0; 1680 } else { 1681 // move to integral bboxes (treating pixels as little squares, what pixels get touched)? 1682 if (ix0) *ix0 = STBTT_ifloor( x0 * scale_x + shift_x); 1683 if (iy0) *iy0 = STBTT_ifloor(-y1 * scale_y + shift_y); 1684 if (ix1) *ix1 = STBTT_iceil ( x1 * scale_x + shift_x); 1685 if (iy1) *iy1 = STBTT_iceil (-y0 * scale_y + shift_y); 1686 } 1687 } 1688 1689 STBTT_DEF void stbtt_GetGlyphBitmapBox(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1) 1690 { 1691 stbtt_GetGlyphBitmapBoxSubpixel(font, glyph, scale_x, scale_y,0.0f,0.0f, ix0, iy0, ix1, iy1); 1692 } 1693 1694 STBTT_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) 1695 { 1696 stbtt_GetGlyphBitmapBoxSubpixel(font, stbtt_FindGlyphIndex(font,codepoint), scale_x, scale_y,shift_x,shift_y, ix0,iy0,ix1,iy1); 1697 } 1698 1699 STBTT_DEF void stbtt_GetCodepointBitmapBox(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1) 1700 { 1701 stbtt_GetCodepointBitmapBoxSubpixel(font, codepoint, scale_x, scale_y,0.0f,0.0f, ix0,iy0,ix1,iy1); 1702 } 1703 1704 ////////////////////////////////////////////////////////////////////////////// 1705 // 1706 // Rasterizer 1707 1708 typedef struct stbtt__hheap_chunk 1709 { 1710 struct stbtt__hheap_chunk *next; 1711 } stbtt__hheap_chunk; 1712 1713 typedef struct stbtt__hheap 1714 { 1715 struct stbtt__hheap_chunk *head; 1716 void *first_free; 1717 int num_remaining_in_head_chunk; 1718 } stbtt__hheap; 1719 1720 static void *stbtt__hheap_alloc(stbtt__hheap *hh, size_t size, void *userdata) 1721 { 1722 if (hh->first_free) { 1723 void *p = hh->first_free; 1724 hh->first_free = * (void **) p; 1725 return p; 1726 } else { 1727 if (hh->num_remaining_in_head_chunk == 0) { 1728 int count = (size < 32 ? 2000 : size < 128 ? 800 : 100); 1729 stbtt__hheap_chunk *c = (stbtt__hheap_chunk *) STBTT_malloc(sizeof(stbtt__hheap_chunk) + size * count, userdata); 1730 if (c == NULL) 1731 return NULL; 1732 c->next = hh->head; 1733 hh->head = c; 1734 hh->num_remaining_in_head_chunk = count; 1735 } 1736 --hh->num_remaining_in_head_chunk; 1737 return (char *) (hh->head) + sizeof(stbtt__hheap_chunk) + size * hh->num_remaining_in_head_chunk; 1738 } 1739 } 1740 1741 static void stbtt__hheap_free(stbtt__hheap *hh, void *p) 1742 { 1743 *(void **) p = hh->first_free; 1744 hh->first_free = p; 1745 } 1746 1747 static void stbtt__hheap_cleanup(stbtt__hheap *hh, void *userdata) 1748 { 1749 stbtt__hheap_chunk *c = hh->head; 1750 while (c) { 1751 stbtt__hheap_chunk *n = c->next; 1752 STBTT_free(c, userdata); 1753 c = n; 1754 } 1755 } 1756 1757 typedef struct stbtt__edge { 1758 float x0,y0, x1,y1; 1759 int invert; 1760 } stbtt__edge; 1761 1762 1763 typedef struct stbtt__active_edge 1764 { 1765 struct stbtt__active_edge *next; 1766 #if STBTT_RASTERIZER_VERSION==1 1767 int x,dx; 1768 float ey; 1769 int direction; 1770 #elif STBTT_RASTERIZER_VERSION==2 1771 float fx,fdx,fdy; 1772 float direction; 1773 float sy; 1774 float ey; 1775 #else 1776 #error "Unrecognized value of STBTT_RASTERIZER_VERSION" 1777 #endif 1778 } stbtt__active_edge; 1779 1780 #if STBTT_RASTERIZER_VERSION == 1 1781 #define STBTT_FIXSHIFT 10 1782 #define STBTT_FIX (1 << STBTT_FIXSHIFT) 1783 #define STBTT_FIXMASK (STBTT_FIX-1) 1784 1785 static stbtt__active_edge *stbtt__new_active(stbtt__hheap *hh, stbtt__edge *e, int off_x, float start_point, void *userdata) 1786 { 1787 stbtt__active_edge *z = (stbtt__active_edge *) stbtt__hheap_alloc(hh, sizeof(*z), userdata); 1788 float dxdy = (e->x1 - e->x0) / (e->y1 - e->y0); 1789 STBTT_assert(z != NULL); 1790 if (!z) return z; 1791 1792 // round dx down to avoid overshooting 1793 if (dxdy < 0) 1794 z->dx = -STBTT_ifloor(STBTT_FIX * -dxdy); 1795 else 1796 z->dx = STBTT_ifloor(STBTT_FIX * dxdy); 1797 1798 z->x = STBTT_ifloor(STBTT_FIX * e->x0 + z->dx * (start_point - e->y0)); // use z->dx so when we offset later it's by the same amount 1799 z->x -= off_x * STBTT_FIX; 1800 1801 z->ey = e->y1; 1802 z->next = 0; 1803 z->direction = e->invert ? 1 : -1; 1804 return z; 1805 } 1806 #elif STBTT_RASTERIZER_VERSION == 2 1807 static stbtt__active_edge *stbtt__new_active(stbtt__hheap *hh, stbtt__edge *e, int off_x, float start_point, void *userdata) 1808 { 1809 stbtt__active_edge *z = (stbtt__active_edge *) stbtt__hheap_alloc(hh, sizeof(*z), userdata); 1810 float dxdy = (e->x1 - e->x0) / (e->y1 - e->y0); 1811 STBTT_assert(z != NULL); 1812 //STBTT_assert(e->y0 <= start_point); 1813 if (!z) return z; 1814 z->fdx = dxdy; 1815 z->fdy = dxdy != 0.0f ? (1.0f/dxdy) : 0.0f; 1816 z->fx = e->x0 + dxdy * (start_point - e->y0); 1817 z->fx -= off_x; 1818 z->direction = e->invert ? 1.0f : -1.0f; 1819 z->sy = e->y0; 1820 z->ey = e->y1; 1821 z->next = 0; 1822 return z; 1823 } 1824 #else 1825 #error "Unrecognized value of STBTT_RASTERIZER_VERSION" 1826 #endif 1827 1828 #if STBTT_RASTERIZER_VERSION == 1 1829 // note: this routine clips fills that extend off the edges... ideally this 1830 // wouldn't happen, but it could happen if the truetype glyph bounding boxes 1831 // are wrong, or if the user supplies a too-small bitmap 1832 static void stbtt__fill_active_edges(unsigned char *scanline, int len, stbtt__active_edge *e, int max_weight) 1833 { 1834 // non-zero winding fill 1835 int x0=0, w=0; 1836 1837 while (e) { 1838 if (w == 0) { 1839 // if we're currently at zero, we need to record the edge start point 1840 x0 = e->x; w += e->direction; 1841 } else { 1842 int x1 = e->x; w += e->direction; 1843 // if we went to zero, we need to draw 1844 if (w == 0) { 1845 int i = x0 >> STBTT_FIXSHIFT; 1846 int j = x1 >> STBTT_FIXSHIFT; 1847 1848 if (i < len && j >= 0) { 1849 if (i == j) { 1850 // x0,x1 are the same pixel, so compute combined coverage 1851 scanline[i] = scanline[i] + (stbtt_uint8) ((x1 - x0) * max_weight >> STBTT_FIXSHIFT); 1852 } else { 1853 if (i >= 0) // add antialiasing for x0 1854 scanline[i] = scanline[i] + (stbtt_uint8) (((STBTT_FIX - (x0 & STBTT_FIXMASK)) * max_weight) >> STBTT_FIXSHIFT); 1855 else 1856 i = -1; // clip 1857 1858 if (j < len) // add antialiasing for x1 1859 scanline[j] = scanline[j] + (stbtt_uint8) (((x1 & STBTT_FIXMASK) * max_weight) >> STBTT_FIXSHIFT); 1860 else 1861 j = len; // clip 1862 1863 for (++i; i < j; ++i) // fill pixels between x0 and x1 1864 scanline[i] = scanline[i] + (stbtt_uint8) max_weight; 1865 } 1866 } 1867 } 1868 } 1869 1870 e = e->next; 1871 } 1872 } 1873 1874 static void stbtt__rasterize_sorted_edges(stbtt__bitmap *result, stbtt__edge *e, int n, int vsubsample, int off_x, int off_y, void *userdata) 1875 { 1876 stbtt__hheap hh = { 0, 0, 0 }; 1877 stbtt__active_edge *active = NULL; 1878 int y,j=0; 1879 int max_weight = (255 / vsubsample); // weight per vertical scanline 1880 int s; // vertical subsample index 1881 unsigned char scanline_data[512], *scanline; 1882 1883 if (result->w > 512) 1884 scanline = (unsigned char *) STBTT_malloc(result->w, userdata); 1885 else 1886 scanline = scanline_data; 1887 1888 y = off_y * vsubsample; 1889 e[n].y0 = (off_y + result->h) * (float) vsubsample + 1; 1890 1891 while (j < result->h) { 1892 STBTT_memset(scanline, 0, result->w); 1893 for (s=0; s < vsubsample; ++s) { 1894 // find center of pixel for this scanline 1895 float scan_y = y + 0.5f; 1896 stbtt__active_edge **step = &active; 1897 1898 // update all active edges; 1899 // remove all active edges that terminate before the center of this scanline 1900 while (*step) { 1901 stbtt__active_edge * z = *step; 1902 if (z->ey <= scan_y) { 1903 *step = z->next; // delete from list 1904 STBTT_assert(z->direction); 1905 z->direction = 0; 1906 stbtt__hheap_free(&hh, z); 1907 } else { 1908 z->x += z->dx; // advance to position for current scanline 1909 step = &((*step)->next); // advance through list 1910 } 1911 } 1912 1913 // resort the list if needed 1914 for(;;) { 1915 int changed=0; 1916 step = &active; 1917 while (*step && (*step)->next) { 1918 if ((*step)->x > (*step)->next->x) { 1919 stbtt__active_edge *t = *step; 1920 stbtt__active_edge *q = t->next; 1921 1922 t->next = q->next; 1923 q->next = t; 1924 *step = q; 1925 changed = 1; 1926 } 1927 step = &(*step)->next; 1928 } 1929 if (!changed) break; 1930 } 1931 1932 // insert all edges that start before the center of this scanline -- omit ones that also end on this scanline 1933 while (e->y0 <= scan_y) { 1934 if (e->y1 > scan_y) { 1935 stbtt__active_edge *z = stbtt__new_active(&hh, e, off_x, scan_y, userdata); 1936 if (z != NULL) { 1937 // find insertion point 1938 if (active == NULL) 1939 active = z; 1940 else if (z->x < active->x) { 1941 // insert at front 1942 z->next = active; 1943 active = z; 1944 } else { 1945 // find thing to insert AFTER 1946 stbtt__active_edge *p = active; 1947 while (p->next && p->next->x < z->x) 1948 p = p->next; 1949 // at this point, p->next->x is NOT < z->x 1950 z->next = p->next; 1951 p->next = z; 1952 } 1953 } 1954 } 1955 ++e; 1956 } 1957 1958 // now process all active edges in XOR fashion 1959 if (active) 1960 stbtt__fill_active_edges(scanline, result->w, active, max_weight); 1961 1962 ++y; 1963 } 1964 STBTT_memcpy(result->pixels + j * result->stride, scanline, result->w); 1965 ++j; 1966 } 1967 1968 stbtt__hheap_cleanup(&hh, userdata); 1969 1970 if (scanline != scanline_data) 1971 STBTT_free(scanline, userdata); 1972 } 1973 1974 #elif STBTT_RASTERIZER_VERSION == 2 1975 1976 // the edge passed in here does not cross the vertical line at x or the vertical line at x+1 1977 // (i.e. it has already been clipped to those) 1978 static void stbtt__handle_clipped_edge(float *scanline, int x, stbtt__active_edge *e, float x0, float y0, float x1, float y1) 1979 { 1980 if (y0 == y1) return; 1981 STBTT_assert(y0 < y1); 1982 STBTT_assert(e->sy <= e->ey); 1983 if (y0 > e->ey) return; 1984 if (y1 < e->sy) return; 1985 if (y0 < e->sy) { 1986 x0 += (x1-x0) * (e->sy - y0) / (y1-y0); 1987 y0 = e->sy; 1988 } 1989 if (y1 > e->ey) { 1990 x1 += (x1-x0) * (e->ey - y1) / (y1-y0); 1991 y1 = e->ey; 1992 } 1993 1994 if (x0 == x) 1995 STBTT_assert(x1 <= x+1); 1996 else if (x0 == x+1) 1997 STBTT_assert(x1 >= x); 1998 else if (x0 <= x) 1999 STBTT_assert(x1 <= x); 2000 else if (x0 >= x+1) 2001 STBTT_assert(x1 >= x+1); 2002 else 2003 STBTT_assert(x1 >= x && x1 <= x+1); 2004 2005 if (x0 <= x && x1 <= x) 2006 scanline[x] += e->direction * (y1-y0); 2007 else if (x0 >= x+1 && x1 >= x+1) 2008 ; 2009 else { 2010 STBTT_assert(x0 >= x && x0 <= x+1 && x1 >= x && x1 <= x+1); 2011 scanline[x] += e->direction * (y1-y0) * (1-((x0-x)+(x1-x))/2); // coverage = 1 - average x position 2012 } 2013 } 2014 2015 static float stbtt__sized_trapezoid_area(float height, float top_width, float bottom_width) 2016 { 2017 STBTT_assert(top_width >= 0); 2018 STBTT_assert(bottom_width >= 0); 2019 return (top_width + bottom_width) / 2.0f * height; 2020 } 2021 2022 static float stbtt__position_trapezoid_area(float height, float tx0, float tx1, float bx0, float bx1) 2023 { 2024 return stbtt__sized_trapezoid_area(height, tx1 - tx0, bx1 - bx0); 2025 } 2026 2027 static float stbtt__sized_triangle_area(float height, float width) 2028 { 2029 return height * width / 2; 2030 } 2031 2032 static void stbtt__fill_active_edges_new(float *scanline, float *scanline_fill, int len, stbtt__active_edge *e, float y_top) 2033 { 2034 float y_bottom = y_top+1; 2035 2036 while (e) { 2037 // brute force every pixel 2038 2039 // compute intersection points with top & bottom 2040 STBTT_assert(e->ey >= y_top); 2041 2042 if (e->fdx == 0) { 2043 float x0 = e->fx; 2044 if (x0 < len) { 2045 if (x0 >= 0) { 2046 stbtt__handle_clipped_edge(scanline,(int) x0,e, x0,y_top, x0,y_bottom); 2047 stbtt__handle_clipped_edge(scanline_fill-1,(int) x0+1,e, x0,y_top, x0,y_bottom); 2048 } else { 2049 stbtt__handle_clipped_edge(scanline_fill-1,0,e, x0,y_top, x0,y_bottom); 2050 } 2051 } 2052 } else { 2053 float x0 = e->fx; 2054 float dx = e->fdx; 2055 float xb = x0 + dx; 2056 float x_top, x_bottom; 2057 float sy0,sy1; 2058 float dy = e->fdy; 2059 STBTT_assert(e->sy <= y_bottom && e->ey >= y_top); 2060 2061 // compute endpoints of line segment clipped to this scanline (if the 2062 // line segment starts on this scanline. x0 is the intersection of the 2063 // line with y_top, but that may be off the line segment. 2064 if (e->sy > y_top) { 2065 x_top = x0 + dx * (e->sy - y_top); 2066 sy0 = e->sy; 2067 } else { 2068 x_top = x0; 2069 sy0 = y_top; 2070 } 2071 if (e->ey < y_bottom) { 2072 x_bottom = x0 + dx * (e->ey - y_top); 2073 sy1 = e->ey; 2074 } else { 2075 x_bottom = xb; 2076 sy1 = y_bottom; 2077 } 2078 2079 if (x_top >= 0 && x_bottom >= 0 && x_top < len && x_bottom < len) { 2080 // from here on, we don't have to range check x values 2081 2082 if ((int) x_top == (int) x_bottom) { 2083 float height; 2084 // simple case, only spans one pixel 2085 int x = (int) x_top; 2086 height = (sy1 - sy0) * e->direction; 2087 STBTT_assert(x >= 0 && x < len); 2088 scanline[x] += stbtt__position_trapezoid_area(height, x_top, x+1.0f, x_bottom, x+1.0f); 2089 scanline_fill[x] += height; // everything right of this pixel is filled 2090 } else { 2091 int x,x1,x2; 2092 float y_crossing, y_final, step, sign, area; 2093 // covers 2+ pixels 2094 if (x_top > x_bottom) { 2095 // flip scanline vertically; signed area is the same 2096 float t; 2097 sy0 = y_bottom - (sy0 - y_top); 2098 sy1 = y_bottom - (sy1 - y_top); 2099 t = sy0, sy0 = sy1, sy1 = t; 2100 t = x_bottom, x_bottom = x_top, x_top = t; 2101 dx = -dx; 2102 dy = -dy; 2103 t = x0, x0 = xb, xb = t; 2104 } 2105 STBTT_assert(dy >= 0); 2106 STBTT_assert(dx >= 0); 2107 2108 x1 = (int) x_top; 2109 x2 = (int) x_bottom; 2110 // compute intersection with y axis at x1+1 2111 y_crossing = y_top + dy * (x1+1 - x0); 2112 2113 // compute intersection with y axis at x2 2114 y_final = y_top + dy * (x2 - x0); 2115 2116 // x1 x_top x2 x_bottom 2117 // y_top +------|-----+------------+------------+--------|---+------------+ 2118 // | | | | | | 2119 // | | | | | | 2120 // sy0 | Txxxxx|............|............|............|............| 2121 // y_crossing | *xxxxx.......|............|............|............| 2122 // | | xxxxx..|............|............|............| 2123 // | | /- xx*xxxx........|............|............| 2124 // | | dy < | xxxxxx..|............|............| 2125 // y_final | | \- | xx*xxx.........|............| 2126 // sy1 | | | | xxxxxB...|............| 2127 // | | | | | | 2128 // | | | | | | 2129 // y_bottom +------------+------------+------------+------------+------------+ 2130 // 2131 // goal is to measure the area covered by '.' in each pixel 2132 2133 // if x2 is right at the right edge of x1, y_crossing can blow up, github #1057 2134 // @TODO: maybe test against sy1 rather than y_bottom? 2135 if (y_crossing > y_bottom) 2136 y_crossing = y_bottom; 2137 2138 sign = e->direction; 2139 2140 // area of the rectangle covered from sy0..y_crossing 2141 area = sign * (y_crossing-sy0); 2142 2143 // area of the triangle (x_top,sy0), (x1+1,sy0), (x1+1,y_crossing) 2144 scanline[x1] += stbtt__sized_triangle_area(area, x1+1 - x_top); 2145 2146 // check if final y_crossing is blown up; no test case for this 2147 if (y_final > y_bottom) { 2148 y_final = y_bottom; 2149 dy = (y_final - y_crossing ) / (x2 - (x1+1)); // if denom=0, y_final = y_crossing, so y_final <= y_bottom 2150 } 2151 2152 // in second pixel, area covered by line segment found in first pixel 2153 // is always a rectangle 1 wide * the height of that line segment; this 2154 // is exactly what the variable 'area' stores. it also gets a contribution 2155 // from the line segment within it. the THIRD pixel will get the first 2156 // pixel's rectangle contribution, the second pixel's rectangle contribution, 2157 // and its own contribution. the 'own contribution' is the same in every pixel except 2158 // the leftmost and rightmost, a trapezoid that slides down in each pixel. 2159 // the second pixel's contribution to the third pixel will be the 2160 // rectangle 1 wide times the height change in the second pixel, which is dy. 2161 2162 step = sign * dy * 1; // dy is dy/dx, change in y for every 1 change in x, 2163 // which multiplied by 1-pixel-width is how much pixel area changes for each step in x 2164 // so the area advances by 'step' every time 2165 2166 for (x = x1+1; x < x2; ++x) { 2167 scanline[x] += area + step/2; // area of trapezoid is 1*step/2 2168 area += step; 2169 } 2170 STBTT_assert(STBTT_fabs(area) <= 1.01f); // accumulated error from area += step unless we round step down 2171 STBTT_assert(sy1 > y_final-0.01f); 2172 2173 // area covered in the last pixel is the rectangle from all the pixels to the left, 2174 // plus the trapezoid filled by the line segment in this pixel all the way to the right edge 2175 scanline[x2] += area + sign * stbtt__position_trapezoid_area(sy1-y_final, (float) x2, x2+1.0f, x_bottom, x2+1.0f); 2176 2177 // the rest of the line is filled based on the total height of the line segment in this pixel 2178 scanline_fill[x2] += sign * (sy1-sy0); 2179 } 2180 } else { 2181 // if edge goes outside of box we're drawing, we require 2182 // clipping logic. since this does not match the intended use 2183 // of this library, we use a different, very slow brute 2184 // force implementation 2185 // note though that this does happen some of the time because 2186 // x_top and x_bottom can be extrapolated at the top & bottom of 2187 // the shape and actually lie outside the bounding box 2188 int x; 2189 for (x=0; x < len; ++x) { 2190 // cases: 2191 // 2192 // there can be up to two intersections with the pixel. any intersection 2193 // with left or right edges can be handled by splitting into two (or three) 2194 // regions. intersections with top & bottom do not necessitate case-wise logic. 2195 // 2196 // the old way of doing this found the intersections with the left & right edges, 2197 // then used some simple logic to produce up to three segments in sorted order 2198 // from top-to-bottom. however, this had a problem: if an x edge was epsilon 2199 // across the x border, then the corresponding y position might not be distinct 2200 // from the other y segment, and it might ignored as an empty segment. to avoid 2201 // that, we need to explicitly produce segments based on x positions. 2202 2203 // rename variables to clearly-defined pairs 2204 float y0 = y_top; 2205 float x1 = (float) (x); 2206 float x2 = (float) (x+1); 2207 float x3 = xb; 2208 float y3 = y_bottom; 2209 2210 // x = e->x + e->dx * (y-y_top) 2211 // (y-y_top) = (x - e->x) / e->dx 2212 // y = (x - e->x) / e->dx + y_top 2213 float y1 = (x - x0) / dx + y_top; 2214 float y2 = (x+1 - x0) / dx + y_top; 2215 2216 if (x0 < x1 && x3 > x2) { // three segments descending down-right 2217 stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x1,y1); 2218 stbtt__handle_clipped_edge(scanline,x,e, x1,y1, x2,y2); 2219 stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x3,y3); 2220 } else if (x3 < x1 && x0 > x2) { // three segments descending down-left 2221 stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x2,y2); 2222 stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x1,y1); 2223 stbtt__handle_clipped_edge(scanline,x,e, x1,y1, x3,y3); 2224 } else if (x0 < x1 && x3 > x1) { // two segments across x, down-right 2225 stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x1,y1); 2226 stbtt__handle_clipped_edge(scanline,x,e, x1,y1, x3,y3); 2227 } else if (x3 < x1 && x0 > x1) { // two segments across x, down-left 2228 stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x1,y1); 2229 stbtt__handle_clipped_edge(scanline,x,e, x1,y1, x3,y3); 2230 } else if (x0 < x2 && x3 > x2) { // two segments across x+1, down-right 2231 stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x2,y2); 2232 stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x3,y3); 2233 } else if (x3 < x2 && x0 > x2) { // two segments across x+1, down-left 2234 stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x2,y2); 2235 stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x3,y3); 2236 } else { // one segment 2237 stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x3,y3); 2238 } 2239 } 2240 } 2241 } 2242 e = e->next; 2243 } 2244 } 2245 2246 // directly AA rasterize edges w/o supersampling 2247 static void stbtt__rasterize_sorted_edges(stbtt__bitmap *result, stbtt__edge *e, int n, int vsubsample, int off_x, int off_y, void *userdata) 2248 { 2249 stbtt__hheap hh = { 0, 0, 0 }; 2250 stbtt__active_edge *active = NULL; 2251 int y,j=0, i; 2252 float scanline_data[129], *scanline, *scanline2; 2253 2254 STBTT__NOTUSED(vsubsample); 2255 2256 if (result->w > 64) 2257 scanline = (float *) STBTT_malloc((result->w*2+1) * sizeof(float), userdata); 2258 else 2259 scanline = scanline_data; 2260 2261 scanline2 = scanline + result->w; 2262 2263 y = off_y; 2264 e[n].y0 = (float) (off_y + result->h) + 1; 2265 2266 while (j < result->h) { 2267 // find center of pixel for this scanline 2268 float scan_y_top = y + 0.0f; 2269 float scan_y_bottom = y + 1.0f; 2270 stbtt__active_edge **step = &active; 2271 2272 STBTT_memset(scanline , 0, result->w*sizeof(scanline[0])); 2273 STBTT_memset(scanline2, 0, (result->w+1)*sizeof(scanline[0])); 2274 2275 // update all active edges; 2276 // remove all active edges that terminate before the top of this scanline 2277 while (*step) { 2278 stbtt__active_edge * z = *step; 2279 if (z->ey <= scan_y_top) { 2280 *step = z->next; // delete from list 2281 STBTT_assert(z->direction); 2282 z->direction = 0; 2283 stbtt__hheap_free(&hh, z); 2284 } else { 2285 step = &((*step)->next); // advance through list 2286 } 2287 } 2288 2289 // insert all edges that start before the bottom of this scanline 2290 while (e->y0 <= scan_y_bottom) { 2291 if (e->y0 != e->y1) { 2292 stbtt__active_edge *z = stbtt__new_active(&hh, e, off_x, scan_y_top, userdata); 2293 if (z != NULL) { 2294 if (j == 0 && off_y != 0) { 2295 if (z->ey < scan_y_top) { 2296 // this can happen due to subpixel positioning and some kind of fp rounding error i think 2297 z->ey = scan_y_top; 2298 } 2299 } 2300 STBTT_assert(z->ey >= scan_y_top); // if we get really unlucky a tiny bit of an edge can be out of bounds 2301 // insert at front 2302 z->next = active; 2303 active = z; 2304 } 2305 } 2306 ++e; 2307 } 2308 2309 // now process all active edges 2310 if (active) 2311 stbtt__fill_active_edges_new(scanline, scanline2+1, result->w, active, scan_y_top); 2312 2313 { 2314 float sum = 0; 2315 for (i=0; i < result->w; ++i) { 2316 float k; 2317 int m; 2318 sum += scanline2[i]; 2319 k = scanline[i] + sum; 2320 k = (float) STBTT_fabs(k)*255 + 0.5f; 2321 m = (int) k; 2322 if (m > 255) m = 255; 2323 result->pixels[j*result->stride + i] = (unsigned char) m; 2324 } 2325 } 2326 // advance all the edges 2327 step = &active; 2328 while (*step) { 2329 stbtt__active_edge *z = *step; 2330 z->fx += z->fdx; // advance to position for current scanline 2331 step = &((*step)->next); // advance through list 2332 } 2333 2334 ++y; 2335 ++j; 2336 } 2337 2338 stbtt__hheap_cleanup(&hh, userdata); 2339 2340 if (scanline != scanline_data) 2341 STBTT_free(scanline, userdata); 2342 } 2343 #else 2344 #error "Unrecognized value of STBTT_RASTERIZER_VERSION" 2345 #endif 2346 2347 #define STBTT__COMPARE(a,b) ((a)->y0 < (b)->y0) 2348 2349 static void stbtt__sort_edges_ins_sort(stbtt__edge *p, int n) 2350 { 2351 int i,j; 2352 for (i=1; i < n; ++i) { 2353 stbtt__edge t = p[i], *a = &t; 2354 j = i; 2355 while (j > 0) { 2356 stbtt__edge *b = &p[j-1]; 2357 int c = STBTT__COMPARE(a,b); 2358 if (!c) break; 2359 p[j] = p[j-1]; 2360 --j; 2361 } 2362 if (i != j) 2363 p[j] = t; 2364 } 2365 } 2366 2367 static void stbtt__sort_edges_quicksort(stbtt__edge *p, int n) 2368 { 2369 /* threshold for transitioning to insertion sort */ 2370 while (n > 12) { 2371 stbtt__edge t; 2372 int c01,c12,c,m,i,j; 2373 2374 /* compute median of three */ 2375 m = n >> 1; 2376 c01 = STBTT__COMPARE(&p[0],&p[m]); 2377 c12 = STBTT__COMPARE(&p[m],&p[n-1]); 2378 /* if 0 >= mid >= end, or 0 < mid < end, then use mid */ 2379 if (c01 != c12) { 2380 /* otherwise, we'll need to swap something else to middle */ 2381 int z; 2382 c = STBTT__COMPARE(&p[0],&p[n-1]); 2383 /* 0>mid && mid<n: 0>n => n; 0<n => 0 */ 2384 /* 0<mid && mid>n: 0>n => 0; 0<n => n */ 2385 z = (c == c12) ? 0 : n-1; 2386 t = p[z]; 2387 p[z] = p[m]; 2388 p[m] = t; 2389 } 2390 /* now p[m] is the median-of-three */ 2391 /* swap it to the beginning so it won't move around */ 2392 t = p[0]; 2393 p[0] = p[m]; 2394 p[m] = t; 2395 2396 /* partition loop */ 2397 i=1; 2398 j=n-1; 2399 for(;;) { 2400 /* handling of equality is crucial here */ 2401 /* for sentinels & efficiency with duplicates */ 2402 for (;;++i) { 2403 if (!STBTT__COMPARE(&p[i], &p[0])) break; 2404 } 2405 for (;;--j) { 2406 if (!STBTT__COMPARE(&p[0], &p[j])) break; 2407 } 2408 /* make sure we haven't crossed */ 2409 if (i >= j) break; 2410 t = p[i]; 2411 p[i] = p[j]; 2412 p[j] = t; 2413 2414 ++i; 2415 --j; 2416 } 2417 /* recurse on smaller side, iterate on larger */ 2418 if (j < (n-i)) { 2419 stbtt__sort_edges_quicksort(p,j); 2420 p = p+i; 2421 n = n-i; 2422 } else { 2423 stbtt__sort_edges_quicksort(p+i, n-i); 2424 n = j; 2425 } 2426 } 2427 } 2428 2429 static void stbtt__sort_edges(stbtt__edge *p, int n) 2430 { 2431 stbtt__sort_edges_quicksort(p, n); 2432 stbtt__sort_edges_ins_sort(p, n); 2433 } 2434 2435 typedef struct 2436 { 2437 float x,y; 2438 } stbtt__point; 2439 2440 static 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) 2441 { 2442 float y_scale_inv = invert ? -scale_y : scale_y; 2443 stbtt__edge *e; 2444 int n,i,j,k,m; 2445 #if STBTT_RASTERIZER_VERSION == 1 2446 int vsubsample = result->h < 8 ? 15 : 5; 2447 #elif STBTT_RASTERIZER_VERSION == 2 2448 int vsubsample = 1; 2449 #else 2450 #error "Unrecognized value of STBTT_RASTERIZER_VERSION" 2451 #endif 2452 // vsubsample should divide 255 evenly; otherwise we won't reach full opacity 2453 2454 // now we have to blow out the windings into explicit edge lists 2455 n = 0; 2456 for (i=0; i < windings; ++i) 2457 n += wcount[i]; 2458 2459 e = (stbtt__edge *) STBTT_malloc(sizeof(*e) * (n+1), userdata); // add an extra one as a sentinel 2460 if (e == 0) return; 2461 n = 0; 2462 2463 m=0; 2464 for (i=0; i < windings; ++i) { 2465 stbtt__point *p = pts + m; 2466 m += wcount[i]; 2467 j = wcount[i]-1; 2468 for (k=0; k < wcount[i]; j=k++) { 2469 int a=k,b=j; 2470 // skip the edge if horizontal 2471 if (p[j].y == p[k].y) 2472 continue; 2473 // add edge from j to k to the list 2474 e[n].invert = 0; 2475 if (invert ? p[j].y > p[k].y : p[j].y < p[k].y) { 2476 e[n].invert = 1; 2477 a=j,b=k; 2478 } 2479 e[n].x0 = p[a].x * scale_x + shift_x; 2480 e[n].y0 = (p[a].y * y_scale_inv + shift_y) * vsubsample; 2481 e[n].x1 = p[b].x * scale_x + shift_x; 2482 e[n].y1 = (p[b].y * y_scale_inv + shift_y) * vsubsample; 2483 ++n; 2484 } 2485 } 2486 2487 // now sort the edges by their highest point (should snap to integer, and then by x) 2488 //STBTT_sort(e, n, sizeof(e[0]), stbtt__edge_compare); 2489 stbtt__sort_edges(e, n); 2490 2491 // now, traverse the scanlines and find the intersections on each scanline, use xor winding rule 2492 stbtt__rasterize_sorted_edges(result, e, n, vsubsample, off_x, off_y, userdata); 2493 2494 STBTT_free(e, userdata); 2495 } 2496 2497 static void stbtt__add_point(stbtt__point *points, int n, float x, float y) 2498 { 2499 if (!points) return; // during first pass, it's unallocated 2500 points[n].x = x; 2501 points[n].y = y; 2502 } 2503 2504 // tessellate until threshold p is happy... @TODO warped to compensate for non-linear stretching 2505 static 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) 2506 { 2507 // midpoint 2508 float mx = (x0 + 2*x1 + x2)/4; 2509 float my = (y0 + 2*y1 + y2)/4; 2510 // versus directly drawn line 2511 float dx = (x0+x2)/2 - mx; 2512 float dy = (y0+y2)/2 - my; 2513 if (n > 16) // 65536 segments on one curve better be enough! 2514 return 1; 2515 if (dx*dx+dy*dy > objspace_flatness_squared) { // half-pixel error allowed... need to be smaller if AA 2516 stbtt__tesselate_curve(points, num_points, x0,y0, (x0+x1)/2.0f,(y0+y1)/2.0f, mx,my, objspace_flatness_squared,n+1); 2517 stbtt__tesselate_curve(points, num_points, mx,my, (x1+x2)/2.0f,(y1+y2)/2.0f, x2,y2, objspace_flatness_squared,n+1); 2518 } else { 2519 stbtt__add_point(points, *num_points,x2,y2); 2520 *num_points = *num_points+1; 2521 } 2522 return 1; 2523 } 2524 2525 static 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) 2526 { 2527 // @TODO this "flatness" calculation is just made-up nonsense that seems to work well enough 2528 float dx0 = x1-x0; 2529 float dy0 = y1-y0; 2530 float dx1 = x2-x1; 2531 float dy1 = y2-y1; 2532 float dx2 = x3-x2; 2533 float dy2 = y3-y2; 2534 float dx = x3-x0; 2535 float dy = y3-y0; 2536 float longlen = (float) (STBTT_sqrt(dx0*dx0+dy0*dy0)+STBTT_sqrt(dx1*dx1+dy1*dy1)+STBTT_sqrt(dx2*dx2+dy2*dy2)); 2537 float shortlen = (float) STBTT_sqrt(dx*dx+dy*dy); 2538 float flatness_squared = longlen*longlen-shortlen*shortlen; 2539 2540 if (n > 16) // 65536 segments on one curve better be enough! 2541 return; 2542 2543 if (flatness_squared > objspace_flatness_squared) { 2544 float x01 = (x0+x1)/2; 2545 float y01 = (y0+y1)/2; 2546 float x12 = (x1+x2)/2; 2547 float y12 = (y1+y2)/2; 2548 float x23 = (x2+x3)/2; 2549 float y23 = (y2+y3)/2; 2550 2551 float xa = (x01+x12)/2; 2552 float ya = (y01+y12)/2; 2553 float xb = (x12+x23)/2; 2554 float yb = (y12+y23)/2; 2555 2556 float mx = (xa+xb)/2; 2557 float my = (ya+yb)/2; 2558 2559 stbtt__tesselate_cubic(points, num_points, x0,y0, x01,y01, xa,ya, mx,my, objspace_flatness_squared,n+1); 2560 stbtt__tesselate_cubic(points, num_points, mx,my, xb,yb, x23,y23, x3,y3, objspace_flatness_squared,n+1); 2561 } else { 2562 stbtt__add_point(points, *num_points,x3,y3); 2563 *num_points = *num_points+1; 2564 } 2565 } 2566 2567 // returns number of contours 2568 static stbtt__point *stbtt_FlattenCurves(stbtt_vertex *vertices, int num_verts, float objspace_flatness, int **contour_lengths, int *num_contours, void *userdata) 2569 { 2570 stbtt__point *points=0; 2571 int num_points=0; 2572 2573 float objspace_flatness_squared = objspace_flatness * objspace_flatness; 2574 int i,n=0,start=0, pass; 2575 2576 // count how many "moves" there are to get the contour count 2577 for (i=0; i < num_verts; ++i) 2578 if (vertices[i].type == STBTT_vmove) 2579 ++n; 2580 2581 *num_contours = n; 2582 if (n == 0) return 0; 2583 2584 *contour_lengths = (int *) STBTT_malloc(sizeof(**contour_lengths) * n, userdata); 2585 2586 if (*contour_lengths == 0) { 2587 *num_contours = 0; 2588 return 0; 2589 } 2590 2591 // make two passes through the points so we don't need to realloc 2592 for (pass=0; pass < 2; ++pass) { 2593 float x=0,y=0; 2594 if (pass == 1) { 2595 points = (stbtt__point *) STBTT_malloc(num_points * sizeof(points[0]), userdata); 2596 if (points == NULL) goto error; 2597 } 2598 num_points = 0; 2599 n= -1; 2600 for (i=0; i < num_verts; ++i) { 2601 switch (vertices[i].type) { 2602 case STBTT_vmove: 2603 // start the next contour 2604 if (n >= 0) 2605 (*contour_lengths)[n] = num_points - start; 2606 ++n; 2607 start = num_points; 2608 2609 x = vertices[i].x, y = vertices[i].y; 2610 stbtt__add_point(points, num_points++, x,y); 2611 break; 2612 case STBTT_vline: 2613 x = vertices[i].x, y = vertices[i].y; 2614 stbtt__add_point(points, num_points++, x, y); 2615 break; 2616 case STBTT_vcurve: 2617 stbtt__tesselate_curve(points, &num_points, x,y, 2618 vertices[i].cx, vertices[i].cy, 2619 vertices[i].x, vertices[i].y, 2620 objspace_flatness_squared, 0); 2621 x = vertices[i].x, y = vertices[i].y; 2622 break; 2623 case STBTT_vcubic: 2624 stbtt__tesselate_cubic(points, &num_points, x,y, 2625 vertices[i].cx, vertices[i].cy, 2626 vertices[i].cx1, vertices[i].cy1, 2627 vertices[i].x, vertices[i].y, 2628 objspace_flatness_squared, 0); 2629 x = vertices[i].x, y = vertices[i].y; 2630 break; 2631 } 2632 } 2633 (*contour_lengths)[n] = num_points - start; 2634 } 2635 2636 return points; 2637 error: 2638 STBTT_free(points, userdata); 2639 STBTT_free(*contour_lengths, userdata); 2640 *contour_lengths = 0; 2641 *num_contours = 0; 2642 return NULL; 2643 } 2644 2645 STBTT_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) 2646 { 2647 float scale = scale_x > scale_y ? scale_y : scale_x; 2648 int winding_count = 0; 2649 int *winding_lengths = NULL; 2650 stbtt__point *windings = stbtt_FlattenCurves(vertices, num_verts, flatness_in_pixels / scale, &winding_lengths, &winding_count, userdata); 2651 if (windings) { 2652 stbtt__rasterize(result, windings, winding_lengths, winding_count, scale_x, scale_y, shift_x, shift_y, x_off, y_off, invert, userdata); 2653 STBTT_free(winding_lengths, userdata); 2654 STBTT_free(windings, userdata); 2655 } 2656 } 2657 2658 STBTT_DEF void stbtt_FreeBitmap(unsigned char *bitmap, void *userdata) 2659 { 2660 STBTT_free(bitmap, userdata); 2661 } 2662 2663 STBTT_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) 2664 { 2665 int ix0,iy0,ix1,iy1; 2666 stbtt__bitmap gbm; 2667 stbtt_vertex *vertices; 2668 int num_verts = stbtt_GetGlyphShape(info, glyph, &vertices); 2669 2670 if (scale_x == 0) scale_x = scale_y; 2671 if (scale_y == 0) { 2672 if (scale_x == 0) { 2673 STBTT_free(vertices, info->userdata); 2674 return NULL; 2675 } 2676 scale_y = scale_x; 2677 } 2678 2679 stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale_x, scale_y, shift_x, shift_y, &ix0,&iy0,&ix1,&iy1); 2680 2681 // now we get the size 2682 gbm.w = (ix1 - ix0); 2683 gbm.h = (iy1 - iy0); 2684 gbm.pixels = NULL; // in case we error 2685 2686 if (width ) *width = gbm.w; 2687 if (height) *height = gbm.h; 2688 if (xoff ) *xoff = ix0; 2689 if (yoff ) *yoff = iy0; 2690 2691 if (gbm.w && gbm.h) { 2692 gbm.pixels = (unsigned char *) STBTT_malloc(gbm.w * gbm.h, info->userdata); 2693 if (gbm.pixels) { 2694 gbm.stride = gbm.w; 2695 2696 stbtt_Rasterize(&gbm, 0.35f, vertices, num_verts, scale_x, scale_y, shift_x, shift_y, ix0, iy0, 1, info->userdata); 2697 } 2698 } 2699 STBTT_free(vertices, info->userdata); 2700 return gbm.pixels; 2701 } 2702 2703 STBTT_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) 2704 { 2705 return stbtt_GetGlyphBitmapSubpixel(info, scale_x, scale_y, 0.0f, 0.0f, glyph, width, height, xoff, yoff); 2706 } 2707 2708 STBTT_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) 2709 { 2710 int ix0,iy0; 2711 stbtt_vertex *vertices; 2712 int num_verts = stbtt_GetGlyphShape(info, glyph, &vertices); 2713 stbtt__bitmap gbm; 2714 2715 stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale_x, scale_y, shift_x, shift_y, &ix0,&iy0,0,0); 2716 gbm.pixels = output; 2717 gbm.w = out_w; 2718 gbm.h = out_h; 2719 gbm.stride = out_stride; 2720 2721 if (gbm.w && gbm.h) 2722 stbtt_Rasterize(&gbm, 0.35f, vertices, num_verts, scale_x, scale_y, shift_x, shift_y, ix0,iy0, 1, info->userdata); 2723 2724 STBTT_free(vertices, info->userdata); 2725 } 2726 2727 STBTT_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) 2728 { 2729 stbtt_MakeGlyphBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, scale_y, 0.0f,0.0f, glyph); 2730 } 2731 2732 STBTT_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) 2733 { 2734 return stbtt_GetGlyphBitmapSubpixel(info, scale_x, scale_y,shift_x,shift_y, stbtt_FindGlyphIndex(info,codepoint), width,height,xoff,yoff); 2735 } 2736 2737 STBTT_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) 2738 { 2739 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)); 2740 } 2741 2742 STBTT_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) 2743 { 2744 stbtt_MakeGlyphBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, scale_y, shift_x, shift_y, stbtt_FindGlyphIndex(info,codepoint)); 2745 } 2746 2747 STBTT_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) 2748 { 2749 return stbtt_GetCodepointBitmapSubpixel(info, scale_x, scale_y, 0.0f,0.0f, codepoint, width,height,xoff,yoff); 2750 } 2751 2752 STBTT_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) 2753 { 2754 stbtt_MakeCodepointBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, scale_y, 0.0f,0.0f, codepoint); 2755 } 2756 2757 ////////////////////////////////////////////////////////////////////////////// 2758 // 2759 // bitmap baking 2760 // 2761 // This is SUPER-CRAPPY packing to keep source code small 2762 2763 static int stbtt_BakeFontBitmap_internal(unsigned char *data, int offset, // font location (use offset=0 for plain .ttf) 2764 float pixel_height, // height of font in pixels 2765 unsigned char *pixels, int pw, int ph, // bitmap to be filled in 2766 int first_char, int num_chars, // characters to bake 2767 stbtt_bakedchar *chardata) 2768 { 2769 float scale; 2770 int x,y,bottom_y, i; 2771 stbtt_fontinfo f; 2772 f.userdata = NULL; 2773 if (!stbtt_InitFont(&f, data, offset)) 2774 return -1; 2775 STBTT_memset(pixels, 0, pw*ph); // background of 0 around pixels 2776 x=y=1; 2777 bottom_y = 1; 2778 2779 scale = stbtt_ScaleForPixelHeight(&f, pixel_height); 2780 2781 for (i=0; i < num_chars; ++i) { 2782 int advance, lsb, x0,y0,x1,y1,gw,gh; 2783 int g = stbtt_FindGlyphIndex(&f, first_char + i); 2784 stbtt_GetGlyphHMetrics(&f, g, &advance, &lsb); 2785 stbtt_GetGlyphBitmapBox(&f, g, scale,scale, &x0,&y0,&x1,&y1); 2786 gw = x1-x0; 2787 gh = y1-y0; 2788 if (x + gw + 1 >= pw) 2789 y = bottom_y, x = 1; // advance to next row 2790 if (y + gh + 1 >= ph) // check if it fits vertically AFTER potentially moving to next row 2791 return -i; 2792 STBTT_assert(x+gw < pw); 2793 STBTT_assert(y+gh < ph); 2794 stbtt_MakeGlyphBitmap(&f, pixels+x+y*pw, gw,gh,pw, scale,scale, g); 2795 chardata[i].x0 = (stbtt_int16) x; 2796 chardata[i].y0 = (stbtt_int16) y; 2797 chardata[i].x1 = (stbtt_int16) (x + gw); 2798 chardata[i].y1 = (stbtt_int16) (y + gh); 2799 chardata[i].xadvance = scale * advance; 2800 chardata[i].xoff = (float) x0; 2801 chardata[i].yoff = (float) y0; 2802 x = x + gw + 1; 2803 if (y+gh+1 > bottom_y) 2804 bottom_y = y+gh+1; 2805 } 2806 return bottom_y; 2807 } 2808 2809 STBTT_DEF void stbtt_GetBakedQuad(const stbtt_bakedchar *chardata, int pw, int ph, int char_index, float *xpos, float *ypos, stbtt_aligned_quad *q, int opengl_fillrule) 2810 { 2811 float d3d_bias = opengl_fillrule ? 0 : -0.5f; 2812 float ipw = 1.0f / pw, iph = 1.0f / ph; 2813 const stbtt_bakedchar *b = chardata + char_index; 2814 int round_x = STBTT_ifloor((*xpos + b->xoff) + 0.5f); 2815 int round_y = STBTT_ifloor((*ypos + b->yoff) + 0.5f); 2816 2817 q->x0 = round_x + d3d_bias; 2818 q->y0 = round_y + d3d_bias; 2819 q->x1 = round_x + b->x1 - b->x0 + d3d_bias; 2820 q->y1 = round_y + b->y1 - b->y0 + d3d_bias; 2821 2822 q->s0 = b->x0 * ipw; 2823 q->t0 = b->y0 * iph; 2824 q->s1 = b->x1 * ipw; 2825 q->t1 = b->y1 * iph; 2826 2827 *xpos += b->xadvance; 2828 } 2829 2830 ////////////////////////////////////////////////////////////////////////////// 2831 // 2832 // rectangle packing replacement routines if you don't have stb_rect_pack.h 2833 // 2834 2835 #ifndef STB_RECT_PACK_VERSION 2836 2837 typedef int stbrp_coord; 2838 2839 //////////////////////////////////////////////////////////////////////////////////// 2840 // // 2841 // // 2842 // COMPILER WARNING ?!?!? // 2843 // // 2844 // // 2845 // if you get a compile warning due to these symbols being defined more than // 2846 // once, move #include "stb_rect_pack.h" before #include "stb_truetype.h" // 2847 // // 2848 //////////////////////////////////////////////////////////////////////////////////// 2849 2850 typedef struct 2851 { 2852 int width,height; 2853 int x,y,bottom_y; 2854 } stbrp_context; 2855 2856 typedef struct 2857 { 2858 unsigned char x; 2859 } stbrp_node; 2860 2861 struct stbrp_rect 2862 { 2863 stbrp_coord x,y; 2864 int id,w,h,was_packed; 2865 }; 2866 2867 static void stbrp_init_target(stbrp_context *con, int pw, int ph, stbrp_node *nodes, int num_nodes) 2868 { 2869 con->width = pw; 2870 con->height = ph; 2871 con->x = 0; 2872 con->y = 0; 2873 con->bottom_y = 0; 2874 STBTT__NOTUSED(nodes); 2875 STBTT__NOTUSED(num_nodes); 2876 } 2877 2878 static void stbrp_pack_rects(stbrp_context *con, stbrp_rect *rects, int num_rects) 2879 { 2880 int i; 2881 for (i=0; i < num_rects; ++i) { 2882 if (con->x + rects[i].w > con->width) { 2883 con->x = 0; 2884 con->y = con->bottom_y; 2885 } 2886 if (con->y + rects[i].h > con->height) 2887 break; 2888 rects[i].x = con->x; 2889 rects[i].y = con->y; 2890 rects[i].was_packed = 1; 2891 con->x += rects[i].w; 2892 if (con->y + rects[i].h > con->bottom_y) 2893 con->bottom_y = con->y + rects[i].h; 2894 } 2895 for ( ; i < num_rects; ++i) 2896 rects[i].was_packed = 0; 2897 } 2898 #endif 2899 2900 ////////////////////////////////////////////////////////////////////////////// 2901 // 2902 // bitmap baking 2903 // 2904 // This is SUPER-AWESOME (tm Ryan Gordon) packing using stb_rect_pack.h. If 2905 // stb_rect_pack.h isn't available, it uses the BakeFontBitmap strategy. 2906 2907 STBTT_DEF int stbtt_PackBegin(stbtt_pack_context *spc, unsigned char *pixels, int pw, int ph, int stride_in_bytes, int padding, void *alloc_context) 2908 { 2909 stbrp_context *context = (stbrp_context *) STBTT_malloc(sizeof(*context) ,alloc_context); 2910 int num_nodes = pw - padding; 2911 stbrp_node *nodes = (stbrp_node *) STBTT_malloc(sizeof(*nodes ) * num_nodes,alloc_context); 2912 2913 if (context == NULL || nodes == NULL) { 2914 if (context != NULL) STBTT_free(context, alloc_context); 2915 if (nodes != NULL) STBTT_free(nodes , alloc_context); 2916 return 0; 2917 } 2918 2919 spc->user_allocator_context = alloc_context; 2920 spc->width = pw; 2921 spc->height = ph; 2922 spc->pixels = pixels; 2923 spc->pack_info = context; 2924 spc->nodes = nodes; 2925 spc->padding = padding; 2926 spc->stride_in_bytes = stride_in_bytes != 0 ? stride_in_bytes : pw; 2927 spc->h_oversample = 1; 2928 spc->v_oversample = 1; 2929 spc->skip_missing = 0; 2930 2931 stbrp_init_target(context, pw-padding, ph-padding, nodes, num_nodes); 2932 2933 if (pixels) 2934 STBTT_memset(pixels, 0, pw*ph); // background of 0 around pixels 2935 2936 return 1; 2937 } 2938 2939 STBTT_DEF void stbtt_PackEnd (stbtt_pack_context *spc) 2940 { 2941 STBTT_free(spc->nodes , spc->user_allocator_context); 2942 STBTT_free(spc->pack_info, spc->user_allocator_context); 2943 } 2944 2945 STBTT_DEF void stbtt_PackSetOversampling(stbtt_pack_context *spc, unsigned int h_oversample, unsigned int v_oversample) 2946 { 2947 STBTT_assert(h_oversample <= STBTT_MAX_OVERSAMPLE); 2948 STBTT_assert(v_oversample <= STBTT_MAX_OVERSAMPLE); 2949 if (h_oversample <= STBTT_MAX_OVERSAMPLE) 2950 spc->h_oversample = h_oversample; 2951 if (v_oversample <= STBTT_MAX_OVERSAMPLE) 2952 spc->v_oversample = v_oversample; 2953 } 2954 2955 STBTT_DEF void stbtt_PackSetSkipMissingCodepoints(stbtt_pack_context *spc, int skip) 2956 { 2957 spc->skip_missing = skip; 2958 } 2959 2960 #define STBTT__OVER_MASK (STBTT_MAX_OVERSAMPLE-1) 2961 2962 static void stbtt__h_prefilter(unsigned char *pixels, int w, int h, int stride_in_bytes, unsigned int kernel_width) 2963 { 2964 unsigned char buffer[STBTT_MAX_OVERSAMPLE]; 2965 int safe_w = w - kernel_width; 2966 int j; 2967 STBTT_memset(buffer, 0, STBTT_MAX_OVERSAMPLE); // suppress bogus warning from VS2013 -analyze 2968 for (j=0; j < h; ++j) { 2969 int i; 2970 unsigned int total; 2971 STBTT_memset(buffer, 0, kernel_width); 2972 2973 total = 0; 2974 2975 // make kernel_width a constant in common cases so compiler can optimize out the divide 2976 switch (kernel_width) { 2977 case 2: 2978 for (i=0; i <= safe_w; ++i) { 2979 total += pixels[i] - buffer[i & STBTT__OVER_MASK]; 2980 buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i]; 2981 pixels[i] = (unsigned char) (total / 2); 2982 } 2983 break; 2984 case 3: 2985 for (i=0; i <= safe_w; ++i) { 2986 total += pixels[i] - buffer[i & STBTT__OVER_MASK]; 2987 buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i]; 2988 pixels[i] = (unsigned char) (total / 3); 2989 } 2990 break; 2991 case 4: 2992 for (i=0; i <= safe_w; ++i) { 2993 total += pixels[i] - buffer[i & STBTT__OVER_MASK]; 2994 buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i]; 2995 pixels[i] = (unsigned char) (total / 4); 2996 } 2997 break; 2998 case 5: 2999 for (i=0; i <= safe_w; ++i) { 3000 total += pixels[i] - buffer[i & STBTT__OVER_MASK]; 3001 buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i]; 3002 pixels[i] = (unsigned char) (total / 5); 3003 } 3004 break; 3005 default: 3006 for (i=0; i <= safe_w; ++i) { 3007 total += pixels[i] - buffer[i & STBTT__OVER_MASK]; 3008 buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i]; 3009 pixels[i] = (unsigned char) (total / kernel_width); 3010 } 3011 break; 3012 } 3013 3014 for (; i < w; ++i) { 3015 STBTT_assert(pixels[i] == 0); 3016 total -= buffer[i & STBTT__OVER_MASK]; 3017 pixels[i] = (unsigned char) (total / kernel_width); 3018 } 3019 3020 pixels += stride_in_bytes; 3021 } 3022 } 3023 3024 static void stbtt__v_prefilter(unsigned char *pixels, int w, int h, int stride_in_bytes, unsigned int kernel_width) 3025 { 3026 unsigned char buffer[STBTT_MAX_OVERSAMPLE]; 3027 int safe_h = h - kernel_width; 3028 int j; 3029 STBTT_memset(buffer, 0, STBTT_MAX_OVERSAMPLE); // suppress bogus warning from VS2013 -analyze 3030 for (j=0; j < w; ++j) { 3031 int i; 3032 unsigned int total; 3033 STBTT_memset(buffer, 0, kernel_width); 3034 3035 total = 0; 3036 3037 // make kernel_width a constant in common cases so compiler can optimize out the divide 3038 switch (kernel_width) { 3039 case 2: 3040 for (i=0; i <= safe_h; ++i) { 3041 total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK]; 3042 buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes]; 3043 pixels[i*stride_in_bytes] = (unsigned char) (total / 2); 3044 } 3045 break; 3046 case 3: 3047 for (i=0; i <= safe_h; ++i) { 3048 total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK]; 3049 buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes]; 3050 pixels[i*stride_in_bytes] = (unsigned char) (total / 3); 3051 } 3052 break; 3053 case 4: 3054 for (i=0; i <= safe_h; ++i) { 3055 total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK]; 3056 buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes]; 3057 pixels[i*stride_in_bytes] = (unsigned char) (total / 4); 3058 } 3059 break; 3060 case 5: 3061 for (i=0; i <= safe_h; ++i) { 3062 total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK]; 3063 buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes]; 3064 pixels[i*stride_in_bytes] = (unsigned char) (total / 5); 3065 } 3066 break; 3067 default: 3068 for (i=0; i <= safe_h; ++i) { 3069 total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK]; 3070 buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes]; 3071 pixels[i*stride_in_bytes] = (unsigned char) (total / kernel_width); 3072 } 3073 break; 3074 } 3075 3076 for (; i < h; ++i) { 3077 STBTT_assert(pixels[i*stride_in_bytes] == 0); 3078 total -= buffer[i & STBTT__OVER_MASK]; 3079 pixels[i*stride_in_bytes] = (unsigned char) (total / kernel_width); 3080 } 3081 3082 pixels += 1; 3083 } 3084 } 3085 3086 static float stbtt__oversample_shift(int oversample) 3087 { 3088 if (!oversample) 3089 return 0.0f; 3090 3091 // The prefilter is a box filter of width "oversample", 3092 // which shifts phase by (oversample - 1)/2 pixels in 3093 // oversampled space. We want to shift in the opposite 3094 // direction to counter this. 3095 return (float)-(oversample - 1) / (2.0f * (float)oversample); 3096 } 3097 3098 // rects array must be big enough to accommodate all characters in the given ranges 3099 STBTT_DEF int stbtt_PackFontRangesGatherRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects) 3100 { 3101 int i,j,k; 3102 int missing_glyph_added = 0; 3103 3104 k=0; 3105 for (i=0; i < num_ranges; ++i) { 3106 float fh = ranges[i].font_size; 3107 float scale = fh > 0 ? stbtt_ScaleForPixelHeight(info, fh) : stbtt_ScaleForMappingEmToPixels(info, -fh); 3108 ranges[i].h_oversample = (unsigned char) spc->h_oversample; 3109 ranges[i].v_oversample = (unsigned char) spc->v_oversample; 3110 for (j=0; j < ranges[i].num_chars; ++j) { 3111 int x0,y0,x1,y1; 3112 int codepoint = ranges[i].array_of_unicode_codepoints == NULL ? ranges[i].first_unicode_codepoint_in_range + j : ranges[i].array_of_unicode_codepoints[j]; 3113 int glyph = stbtt_FindGlyphIndex(info, codepoint); 3114 if (glyph == 0 && (spc->skip_missing || missing_glyph_added)) { 3115 rects[k].w = rects[k].h = 0; 3116 } else { 3117 stbtt_GetGlyphBitmapBoxSubpixel(info,glyph, 3118 scale * spc->h_oversample, 3119 scale * spc->v_oversample, 3120 0,0, 3121 &x0,&y0,&x1,&y1); 3122 rects[k].w = (stbrp_coord) (x1-x0 + spc->padding + spc->h_oversample-1); 3123 rects[k].h = (stbrp_coord) (y1-y0 + spc->padding + spc->v_oversample-1); 3124 if (glyph == 0) 3125 missing_glyph_added = 1; 3126 } 3127 ++k; 3128 } 3129 } 3130 3131 return k; 3132 } 3133 3134 STBTT_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) 3135 { 3136 stbtt_MakeGlyphBitmapSubpixel(info, 3137 output, 3138 out_w - (prefilter_x - 1), 3139 out_h - (prefilter_y - 1), 3140 out_stride, 3141 scale_x, 3142 scale_y, 3143 shift_x, 3144 shift_y, 3145 glyph); 3146 3147 if (prefilter_x > 1) 3148 stbtt__h_prefilter(output, out_w, out_h, out_stride, prefilter_x); 3149 3150 if (prefilter_y > 1) 3151 stbtt__v_prefilter(output, out_w, out_h, out_stride, prefilter_y); 3152 3153 *sub_x = stbtt__oversample_shift(prefilter_x); 3154 *sub_y = stbtt__oversample_shift(prefilter_y); 3155 } 3156 3157 // rects array must be big enough to accommodate all characters in the given ranges 3158 STBTT_DEF int stbtt_PackFontRangesRenderIntoRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects) 3159 { 3160 int i,j,k, missing_glyph = -1, return_value = 1; 3161 3162 // save current values 3163 int old_h_over = spc->h_oversample; 3164 int old_v_over = spc->v_oversample; 3165 3166 k = 0; 3167 for (i=0; i < num_ranges; ++i) { 3168 float fh = ranges[i].font_size; 3169 float scale = fh > 0 ? stbtt_ScaleForPixelHeight(info, fh) : stbtt_ScaleForMappingEmToPixels(info, -fh); 3170 float recip_h,recip_v,sub_x,sub_y; 3171 spc->h_oversample = ranges[i].h_oversample; 3172 spc->v_oversample = ranges[i].v_oversample; 3173 recip_h = 1.0f / spc->h_oversample; 3174 recip_v = 1.0f / spc->v_oversample; 3175 sub_x = stbtt__oversample_shift(spc->h_oversample); 3176 sub_y = stbtt__oversample_shift(spc->v_oversample); 3177 for (j=0; j < ranges[i].num_chars; ++j) { 3178 stbrp_rect *r = &rects[k]; 3179 if (r->was_packed && r->w != 0 && r->h != 0) { 3180 stbtt_packedchar *bc = &ranges[i].chardata_for_range[j]; 3181 int advance, lsb, x0,y0,x1,y1; 3182 int codepoint = ranges[i].array_of_unicode_codepoints == NULL ? ranges[i].first_unicode_codepoint_in_range + j : ranges[i].array_of_unicode_codepoints[j]; 3183 int glyph = stbtt_FindGlyphIndex(info, codepoint); 3184 stbrp_coord pad = (stbrp_coord) spc->padding; 3185 3186 // pad on left and top 3187 r->x += pad; 3188 r->y += pad; 3189 r->w -= pad; 3190 r->h -= pad; 3191 stbtt_GetGlyphHMetrics(info, glyph, &advance, &lsb); 3192 stbtt_GetGlyphBitmapBox(info, glyph, 3193 scale * spc->h_oversample, 3194 scale * spc->v_oversample, 3195 &x0,&y0,&x1,&y1); 3196 stbtt_MakeGlyphBitmapSubpixel(info, 3197 spc->pixels + r->x + r->y*spc->stride_in_bytes, 3198 r->w - spc->h_oversample+1, 3199 r->h - spc->v_oversample+1, 3200 spc->stride_in_bytes, 3201 scale * spc->h_oversample, 3202 scale * spc->v_oversample, 3203 0,0, 3204 glyph); 3205 3206 if (spc->h_oversample > 1) 3207 stbtt__h_prefilter(spc->pixels + r->x + r->y*spc->stride_in_bytes, 3208 r->w, r->h, spc->stride_in_bytes, 3209 spc->h_oversample); 3210 3211 if (spc->v_oversample > 1) 3212 stbtt__v_prefilter(spc->pixels + r->x + r->y*spc->stride_in_bytes, 3213 r->w, r->h, spc->stride_in_bytes, 3214 spc->v_oversample); 3215 3216 bc->x0 = (stbtt_int16) r->x; 3217 bc->y0 = (stbtt_int16) r->y; 3218 bc->x1 = (stbtt_int16) (r->x + r->w); 3219 bc->y1 = (stbtt_int16) (r->y + r->h); 3220 bc->xadvance = scale * advance; 3221 bc->xoff = (float) x0 * recip_h + sub_x; 3222 bc->yoff = (float) y0 * recip_v + sub_y; 3223 bc->xoff2 = (x0 + r->w) * recip_h + sub_x; 3224 bc->yoff2 = (y0 + r->h) * recip_v + sub_y; 3225 3226 if (glyph == 0) 3227 missing_glyph = j; 3228 } else if (spc->skip_missing) { 3229 return_value = 0; 3230 } else if (r->was_packed && r->w == 0 && r->h == 0 && missing_glyph >= 0) { 3231 ranges[i].chardata_for_range[j] = ranges[i].chardata_for_range[missing_glyph]; 3232 } else { 3233 return_value = 0; // if any fail, report failure 3234 } 3235 3236 ++k; 3237 } 3238 } 3239 3240 // restore original values 3241 spc->h_oversample = old_h_over; 3242 spc->v_oversample = old_v_over; 3243 3244 return return_value; 3245 } 3246 3247 STBTT_DEF void stbtt_PackFontRangesPackRects(stbtt_pack_context *spc, stbrp_rect *rects, int num_rects) 3248 { 3249 stbrp_pack_rects((stbrp_context *) spc->pack_info, rects, num_rects); 3250 } 3251 3252 STBTT_DEF int stbtt_PackFontRanges(stbtt_pack_context *spc, const unsigned char *fontdata, int font_index, stbtt_pack_range *ranges, int num_ranges) 3253 { 3254 stbtt_fontinfo info; 3255 int i,j,n, return_value = 1; 3256 //stbrp_context *context = (stbrp_context *) spc->pack_info; 3257 stbrp_rect *rects; 3258 3259 // flag all characters as NOT packed 3260 for (i=0; i < num_ranges; ++i) 3261 for (j=0; j < ranges[i].num_chars; ++j) 3262 ranges[i].chardata_for_range[j].x0 = 3263 ranges[i].chardata_for_range[j].y0 = 3264 ranges[i].chardata_for_range[j].x1 = 3265 ranges[i].chardata_for_range[j].y1 = 0; 3266 3267 n = 0; 3268 for (i=0; i < num_ranges; ++i) 3269 n += ranges[i].num_chars; 3270 3271 rects = (stbrp_rect *) STBTT_malloc(sizeof(*rects) * n, spc->user_allocator_context); 3272 if (rects == NULL) 3273 return 0; 3274 3275 info.userdata = spc->user_allocator_context; 3276 stbtt_InitFont(&info, fontdata, stbtt_GetFontOffsetForIndex(fontdata,font_index)); 3277 3278 n = stbtt_PackFontRangesGatherRects(spc, &info, ranges, num_ranges, rects); 3279 3280 stbtt_PackFontRangesPackRects(spc, rects, n); 3281 3282 return_value = stbtt_PackFontRangesRenderIntoRects(spc, &info, ranges, num_ranges, rects); 3283 3284 STBTT_free(rects, spc->user_allocator_context); 3285 return return_value; 3286 } 3287 3288 STBTT_DEF int stbtt_PackFontRange(stbtt_pack_context *spc, const unsigned char *fontdata, int font_index, float font_size, 3289 int first_unicode_codepoint_in_range, int num_chars_in_range, stbtt_packedchar *chardata_for_range) 3290 { 3291 stbtt_pack_range range; 3292 range.first_unicode_codepoint_in_range = first_unicode_codepoint_in_range; 3293 range.array_of_unicode_codepoints = NULL; 3294 range.num_chars = num_chars_in_range; 3295 range.chardata_for_range = chardata_for_range; 3296 range.font_size = font_size; 3297 return stbtt_PackFontRanges(spc, fontdata, font_index, &range, 1); 3298 } 3299 3300 STBTT_DEF void stbtt_GetScaledFontVMetrics(const unsigned char *fontdata, int index, float size, float *ascent, float *descent, float *lineGap) 3301 { 3302 int i_ascent, i_descent, i_lineGap; 3303 float scale; 3304 stbtt_fontinfo info; 3305 stbtt_InitFont(&info, fontdata, stbtt_GetFontOffsetForIndex(fontdata, index)); 3306 scale = size > 0 ? stbtt_ScaleForPixelHeight(&info, size) : stbtt_ScaleForMappingEmToPixels(&info, -size); 3307 stbtt_GetFontVMetrics(&info, &i_ascent, &i_descent, &i_lineGap); 3308 *ascent = (float) i_ascent * scale; 3309 *descent = (float) i_descent * scale; 3310 *lineGap = (float) i_lineGap * scale; 3311 } 3312 3313 STBTT_DEF void stbtt_GetPackedQuad(const stbtt_packedchar *chardata, int pw, int ph, int char_index, float *xpos, float *ypos, stbtt_aligned_quad *q, int align_to_integer) 3314 { 3315 float ipw = 1.0f / pw, iph = 1.0f / ph; 3316 const stbtt_packedchar *b = chardata + char_index; 3317 3318 if (align_to_integer) { 3319 float x = (float) STBTT_ifloor((*xpos + b->xoff) + 0.5f); 3320 float y = (float) STBTT_ifloor((*ypos + b->yoff) + 0.5f); 3321 q->x0 = x; 3322 q->y0 = y; 3323 q->x1 = x + b->xoff2 - b->xoff; 3324 q->y1 = y + b->yoff2 - b->yoff; 3325 } else { 3326 q->x0 = *xpos + b->xoff; 3327 q->y0 = *ypos + b->yoff; 3328 q->x1 = *xpos + b->xoff2; 3329 q->y1 = *ypos + b->yoff2; 3330 } 3331 3332 q->s0 = b->x0 * ipw; 3333 q->t0 = b->y0 * iph; 3334 q->s1 = b->x1 * ipw; 3335 q->t1 = b->y1 * iph; 3336 3337 *xpos += b->xadvance; 3338 } 3339 3340 ////////////////////////////////////////////////////////////////////////////// 3341 // 3342 // sdf computation 3343 // 3344 3345 #define STBTT_min(a,b) ((a) < (b) ? (a) : (b)) 3346 #define STBTT_max(a,b) ((a) < (b) ? (b) : (a)) 3347 3348 static int stbtt__ray_intersect_bezier(float orig[2], float ray[2], float q0[2], float q1[2], float q2[2], float hits[2][2]) 3349 { 3350 float q0perp = q0[1]*ray[0] - q0[0]*ray[1]; 3351 float q1perp = q1[1]*ray[0] - q1[0]*ray[1]; 3352 float q2perp = q2[1]*ray[0] - q2[0]*ray[1]; 3353 float roperp = orig[1]*ray[0] - orig[0]*ray[1]; 3354 3355 float a = q0perp - 2*q1perp + q2perp; 3356 float b = q1perp - q0perp; 3357 float c = q0perp - roperp; 3358 3359 float s0 = 0., s1 = 0.; 3360 int num_s = 0; 3361 3362 if (a != 0.0) { 3363 float discr = b*b - a*c; 3364 if (discr > 0.0) { 3365 float rcpna = -1 / a; 3366 float d = (float) STBTT_sqrt(discr); 3367 s0 = (b+d) * rcpna; 3368 s1 = (b-d) * rcpna; 3369 if (s0 >= 0.0 && s0 <= 1.0) 3370 num_s = 1; 3371 if (d > 0.0 && s1 >= 0.0 && s1 <= 1.0) { 3372 if (num_s == 0) s0 = s1; 3373 ++num_s; 3374 } 3375 } 3376 } else { 3377 // 2*b*s + c = 0 3378 // s = -c / (2*b) 3379 s0 = c / (-2 * b); 3380 if (s0 >= 0.0 && s0 <= 1.0) 3381 num_s = 1; 3382 } 3383 3384 if (num_s == 0) 3385 return 0; 3386 else { 3387 float rcp_len2 = 1 / (ray[0]*ray[0] + ray[1]*ray[1]); 3388 float rayn_x = ray[0] * rcp_len2, rayn_y = ray[1] * rcp_len2; 3389 3390 float q0d = q0[0]*rayn_x + q0[1]*rayn_y; 3391 float q1d = q1[0]*rayn_x + q1[1]*rayn_y; 3392 float q2d = q2[0]*rayn_x + q2[1]*rayn_y; 3393 float rod = orig[0]*rayn_x + orig[1]*rayn_y; 3394 3395 float q10d = q1d - q0d; 3396 float q20d = q2d - q0d; 3397 float q0rd = q0d - rod; 3398 3399 hits[0][0] = q0rd + s0*(2.0f - 2.0f*s0)*q10d + s0*s0*q20d; 3400 hits[0][1] = a*s0+b; 3401 3402 if (num_s > 1) { 3403 hits[1][0] = q0rd + s1*(2.0f - 2.0f*s1)*q10d + s1*s1*q20d; 3404 hits[1][1] = a*s1+b; 3405 return 2; 3406 } else { 3407 return 1; 3408 } 3409 } 3410 } 3411 3412 static int equal(float *a, float *b) 3413 { 3414 return (a[0] == b[0] && a[1] == b[1]); 3415 } 3416 3417 static int stbtt__compute_crossings_x(float x, float y, int nverts, stbtt_vertex *verts) 3418 { 3419 int i; 3420 float orig[2], ray[2] = { 1, 0 }; 3421 float y_frac; 3422 int winding = 0; 3423 3424 // make sure y never passes through a vertex of the shape 3425 y_frac = (float) STBTT_fmod(y, 1.0f); 3426 if (y_frac < 0.01f) 3427 y += 0.01f; 3428 else if (y_frac > 0.99f) 3429 y -= 0.01f; 3430 3431 orig[0] = x; 3432 orig[1] = y; 3433 3434 // test a ray from (-infinity,y) to (x,y) 3435 for (i=0; i < nverts; ++i) { 3436 if (verts[i].type == STBTT_vline) { 3437 int x0 = (int) verts[i-1].x, y0 = (int) verts[i-1].y; 3438 int x1 = (int) verts[i ].x, y1 = (int) verts[i ].y; 3439 if (y > STBTT_min(y0,y1) && y < STBTT_max(y0,y1) && x > STBTT_min(x0,x1)) { 3440 float x_inter = (y - y0) / (y1 - y0) * (x1-x0) + x0; 3441 if (x_inter < x) 3442 winding += (y0 < y1) ? 1 : -1; 3443 } 3444 } 3445 if (verts[i].type == STBTT_vcurve) { 3446 int x0 = (int) verts[i-1].x , y0 = (int) verts[i-1].y ; 3447 int x1 = (int) verts[i ].cx, y1 = (int) verts[i ].cy; 3448 int x2 = (int) verts[i ].x , y2 = (int) verts[i ].y ; 3449 int ax = STBTT_min(x0,STBTT_min(x1,x2)), ay = STBTT_min(y0,STBTT_min(y1,y2)); 3450 int by = STBTT_max(y0,STBTT_max(y1,y2)); 3451 if (y > ay && y < by && x > ax) { 3452 float q0[2],q1[2],q2[2]; 3453 float hits[2][2]; 3454 q0[0] = (float)x0; 3455 q0[1] = (float)y0; 3456 q1[0] = (float)x1; 3457 q1[1] = (float)y1; 3458 q2[0] = (float)x2; 3459 q2[1] = (float)y2; 3460 if (equal(q0,q1) || equal(q1,q2)) { 3461 x0 = (int)verts[i-1].x; 3462 y0 = (int)verts[i-1].y; 3463 x1 = (int)verts[i ].x; 3464 y1 = (int)verts[i ].y; 3465 if (y > STBTT_min(y0,y1) && y < STBTT_max(y0,y1) && x > STBTT_min(x0,x1)) { 3466 float x_inter = (y - y0) / (y1 - y0) * (x1-x0) + x0; 3467 if (x_inter < x) 3468 winding += (y0 < y1) ? 1 : -1; 3469 } 3470 } else { 3471 int num_hits = stbtt__ray_intersect_bezier(orig, ray, q0, q1, q2, hits); 3472 if (num_hits >= 1) 3473 if (hits[0][0] < 0) 3474 winding += (hits[0][1] < 0 ? -1 : 1); 3475 if (num_hits >= 2) 3476 if (hits[1][0] < 0) 3477 winding += (hits[1][1] < 0 ? -1 : 1); 3478 } 3479 } 3480 } 3481 } 3482 return winding; 3483 } 3484 3485 static float stbtt__cuberoot( float x ) 3486 { 3487 if (x<0) 3488 return -(float) STBTT_pow(-x,1.0f/3.0f); 3489 else 3490 return (float) STBTT_pow( x,1.0f/3.0f); 3491 } 3492 3493 // x^3 + a*x^2 + b*x + c = 0 3494 static int stbtt__solve_cubic(float a, float b, float c, float* r) 3495 { 3496 float s = -a / 3; 3497 float p = b - a*a / 3; 3498 float q = a * (2*a*a - 9*b) / 27 + c; 3499 float p3 = p*p*p; 3500 float d = q*q + 4*p3 / 27; 3501 if (d >= 0) { 3502 float z = (float) STBTT_sqrt(d); 3503 float u = (-q + z) / 2; 3504 float v = (-q - z) / 2; 3505 u = stbtt__cuberoot(u); 3506 v = stbtt__cuberoot(v); 3507 r[0] = s + u + v; 3508 return 1; 3509 } else { 3510 float u = (float) STBTT_sqrt(-p/3); 3511 float v = (float) STBTT_acos(-STBTT_sqrt(-27/p3) * q / 2) / 3; // p3 must be negative, since d is negative 3512 float m = (float) STBTT_cos(v); 3513 float n = (float) STBTT_cos(v-3.141592/2)*1.732050808f; 3514 r[0] = s + u * 2 * m; 3515 r[1] = s - u * (m + n); 3516 r[2] = s - u * (m - n); 3517 3518 //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? 3519 //STBTT_assert( STBTT_fabs(((r[1]+a)*r[1]+b)*r[1]+c) < 0.05f); 3520 //STBTT_assert( STBTT_fabs(((r[2]+a)*r[2]+b)*r[2]+c) < 0.05f); 3521 return 3; 3522 } 3523 } 3524 3525 STBTT_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) 3526 { 3527 float scale_x = scale, scale_y = scale; 3528 int ix0,iy0,ix1,iy1; 3529 int w,h; 3530 unsigned char *data; 3531 3532 if (scale == 0) return NULL; 3533 3534 stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale, scale, 0.0f,0.0f, &ix0,&iy0,&ix1,&iy1); 3535 3536 // if empty, return NULL 3537 if (ix0 == ix1 || iy0 == iy1) 3538 return NULL; 3539 3540 ix0 -= padding; 3541 iy0 -= padding; 3542 ix1 += padding; 3543 iy1 += padding; 3544 3545 w = (ix1 - ix0); 3546 h = (iy1 - iy0); 3547 3548 if (width ) *width = w; 3549 if (height) *height = h; 3550 if (xoff ) *xoff = ix0; 3551 if (yoff ) *yoff = iy0; 3552 3553 // invert for y-downwards bitmaps 3554 scale_y = -scale_y; 3555 3556 { 3557 int x,y,i,j; 3558 float *precompute; 3559 stbtt_vertex *verts; 3560 int num_verts = stbtt_GetGlyphShape(info, glyph, &verts); 3561 data = (unsigned char *) STBTT_malloc(w * h, info->userdata); 3562 precompute = (float *) STBTT_malloc(num_verts * sizeof(float), info->userdata); 3563 3564 for (i=0,j=num_verts-1; i < num_verts; j=i++) { 3565 if (verts[i].type == STBTT_vline) { 3566 float x0 = verts[i].x*scale_x, y0 = verts[i].y*scale_y; 3567 float x1 = verts[j].x*scale_x, y1 = verts[j].y*scale_y; 3568 float dist = (float) STBTT_sqrt((x1-x0)*(x1-x0) + (y1-y0)*(y1-y0)); 3569 precompute[i] = (dist == 0) ? 0.0f : 1.0f / dist; 3570 } else if (verts[i].type == STBTT_vcurve) { 3571 float x2 = verts[j].x *scale_x, y2 = verts[j].y *scale_y; 3572 float x1 = verts[i].cx*scale_x, y1 = verts[i].cy*scale_y; 3573 float x0 = verts[i].x *scale_x, y0 = verts[i].y *scale_y; 3574 float bx = x0 - 2*x1 + x2, by = y0 - 2*y1 + y2; 3575 float len2 = bx*bx + by*by; 3576 if (len2 != 0.0f) 3577 precompute[i] = 1.0f / (bx*bx + by*by); 3578 else 3579 precompute[i] = 0.0f; 3580 } else 3581 precompute[i] = 0.0f; 3582 } 3583 3584 for (y=iy0; y < iy1; ++y) { 3585 for (x=ix0; x < ix1; ++x) { 3586 float val; 3587 float min_dist = 999999.0f; 3588 float sx = (float) x + 0.5f; 3589 float sy = (float) y + 0.5f; 3590 float x_gspace = (sx / scale_x); 3591 float y_gspace = (sy / scale_y); 3592 3593 int winding = stbtt__compute_crossings_x(x_gspace, y_gspace, num_verts, verts); // @OPTIMIZE: this could just be a rasterization, but needs to be line vs. non-tesselated curves so a new path 3594 3595 for (i=0; i < num_verts; ++i) { 3596 float x0 = verts[i].x*scale_x, y0 = verts[i].y*scale_y; 3597 3598 if (verts[i].type == STBTT_vline && precompute[i] != 0.0f) { 3599 float x1 = verts[i-1].x*scale_x, y1 = verts[i-1].y*scale_y; 3600 3601 float dist,dist2 = (x0-sx)*(x0-sx) + (y0-sy)*(y0-sy); 3602 if (dist2 < min_dist*min_dist) 3603 min_dist = (float) STBTT_sqrt(dist2); 3604 3605 // coarse culling against bbox 3606 //if (sx > STBTT_min(x0,x1)-min_dist && sx < STBTT_max(x0,x1)+min_dist && 3607 // sy > STBTT_min(y0,y1)-min_dist && sy < STBTT_max(y0,y1)+min_dist) 3608 dist = (float) STBTT_fabs((x1-x0)*(y0-sy) - (y1-y0)*(x0-sx)) * precompute[i]; 3609 STBTT_assert(i != 0); 3610 if (dist < min_dist) { 3611 // check position along line 3612 // x' = x0 + t*(x1-x0), y' = y0 + t*(y1-y0) 3613 // minimize (x'-sx)*(x'-sx)+(y'-sy)*(y'-sy) 3614 float dx = x1-x0, dy = y1-y0; 3615 float px = x0-sx, py = y0-sy; 3616 // minimize (px+t*dx)^2 + (py+t*dy)^2 = px*px + 2*px*dx*t + t^2*dx*dx + py*py + 2*py*dy*t + t^2*dy*dy 3617 // derivative: 2*px*dx + 2*py*dy + (2*dx*dx+2*dy*dy)*t, set to 0 and solve 3618 float t = -(px*dx + py*dy) / (dx*dx + dy*dy); 3619 if (t >= 0.0f && t <= 1.0f) 3620 min_dist = dist; 3621 } 3622 } else if (verts[i].type == STBTT_vcurve) { 3623 float x2 = verts[i-1].x *scale_x, y2 = verts[i-1].y *scale_y; 3624 float x1 = verts[i ].cx*scale_x, y1 = verts[i ].cy*scale_y; 3625 float box_x0 = STBTT_min(STBTT_min(x0,x1),x2); 3626 float box_y0 = STBTT_min(STBTT_min(y0,y1),y2); 3627 float box_x1 = STBTT_max(STBTT_max(x0,x1),x2); 3628 float box_y1 = STBTT_max(STBTT_max(y0,y1),y2); 3629 // coarse culling against bbox to avoid computing cubic unnecessarily 3630 if (sx > box_x0-min_dist && sx < box_x1+min_dist && sy > box_y0-min_dist && sy < box_y1+min_dist) { 3631 int num=0; 3632 float ax = x1-x0, ay = y1-y0; 3633 float bx = x0 - 2*x1 + x2, by = y0 - 2*y1 + y2; 3634 float mx = x0 - sx, my = y0 - sy; 3635 float res[3] = {0.f,0.f,0.f}; 3636 float px,py,t,it,dist2; 3637 float a_inv = precompute[i]; 3638 if (a_inv == 0.0) { // if a_inv is 0, it's 2nd degree so use quadratic formula 3639 float a = 3*(ax*bx + ay*by); 3640 float b = 2*(ax*ax + ay*ay) + (mx*bx+my*by); 3641 float c = mx*ax+my*ay; 3642 if (a == 0.0) { // if a is 0, it's linear 3643 if (b != 0.0) { 3644 res[num++] = -c/b; 3645 } 3646 } else { 3647 float discriminant = b*b - 4*a*c; 3648 if (discriminant < 0) 3649 num = 0; 3650 else { 3651 float root = (float) STBTT_sqrt(discriminant); 3652 res[0] = (-b - root)/(2*a); 3653 res[1] = (-b + root)/(2*a); 3654 num = 2; // don't bother distinguishing 1-solution case, as code below will still work 3655 } 3656 } 3657 } else { 3658 float b = 3*(ax*bx + ay*by) * a_inv; // could precompute this as it doesn't depend on sample point 3659 float c = (2*(ax*ax + ay*ay) + (mx*bx+my*by)) * a_inv; 3660 float d = (mx*ax+my*ay) * a_inv; 3661 num = stbtt__solve_cubic(b, c, d, res); 3662 } 3663 dist2 = (x0-sx)*(x0-sx) + (y0-sy)*(y0-sy); 3664 if (dist2 < min_dist*min_dist) 3665 min_dist = (float) STBTT_sqrt(dist2); 3666 3667 if (num >= 1 && res[0] >= 0.0f && res[0] <= 1.0f) { 3668 t = res[0], it = 1.0f - t; 3669 px = it*it*x0 + 2*t*it*x1 + t*t*x2; 3670 py = it*it*y0 + 2*t*it*y1 + t*t*y2; 3671 dist2 = (px-sx)*(px-sx) + (py-sy)*(py-sy); 3672 if (dist2 < min_dist * min_dist) 3673 min_dist = (float) STBTT_sqrt(dist2); 3674 } 3675 if (num >= 2 && res[1] >= 0.0f && res[1] <= 1.0f) { 3676 t = res[1], it = 1.0f - t; 3677 px = it*it*x0 + 2*t*it*x1 + t*t*x2; 3678 py = it*it*y0 + 2*t*it*y1 + t*t*y2; 3679 dist2 = (px-sx)*(px-sx) + (py-sy)*(py-sy); 3680 if (dist2 < min_dist * min_dist) 3681 min_dist = (float) STBTT_sqrt(dist2); 3682 } 3683 if (num >= 3 && res[2] >= 0.0f && res[2] <= 1.0f) { 3684 t = res[2], it = 1.0f - t; 3685 px = it*it*x0 + 2*t*it*x1 + t*t*x2; 3686 py = it*it*y0 + 2*t*it*y1 + t*t*y2; 3687 dist2 = (px-sx)*(px-sx) + (py-sy)*(py-sy); 3688 if (dist2 < min_dist * min_dist) 3689 min_dist = (float) STBTT_sqrt(dist2); 3690 } 3691 } 3692 } 3693 } 3694 if (winding == 0) 3695 min_dist = -min_dist; // if outside the shape, value is negative 3696 val = onedge_value + pixel_dist_scale * min_dist; 3697 if (val < 0) 3698 val = 0; 3699 else if (val > 255) 3700 val = 255; 3701 data[(y-iy0)*w+(x-ix0)] = (unsigned char) val; 3702 } 3703 } 3704 STBTT_free(precompute, info->userdata); 3705 STBTT_free(verts, info->userdata); 3706 } 3707 return data; 3708 } 3709 3710 STBTT_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) 3711 { 3712 return stbtt_GetGlyphSDF(info, scale, stbtt_FindGlyphIndex(info, codepoint), padding, onedge_value, pixel_dist_scale, width, height, xoff, yoff); 3713 } 3714 3715 STBTT_DEF void stbtt_FreeSDF(unsigned char *bitmap, void *userdata) 3716 { 3717 STBTT_free(bitmap, userdata); 3718 } 3719 3720 ////////////////////////////////////////////////////////////////////////////// 3721 // 3722 // font name matching -- recommended not to use this 3723 // 3724 3725 // check if a utf8 string contains a prefix which is the utf16 string; if so return length of matching utf8 string 3726 static stbtt_int32 stbtt__CompareUTF8toUTF16_bigendian_prefix(stbtt_uint8 *s1, stbtt_int32 len1, stbtt_uint8 *s2, stbtt_int32 len2) 3727 { 3728 stbtt_int32 i=0; 3729 3730 // convert utf16 to utf8 and compare the results while converting 3731 while (len2) { 3732 stbtt_uint16 ch = s2[0]*256 + s2[1]; 3733 if (ch < 0x80) { 3734 if (i >= len1) return -1; 3735 if (s1[i++] != ch) return -1; 3736 } else if (ch < 0x800) { 3737 if (i+1 >= len1) return -1; 3738 if (s1[i++] != 0xc0 + (ch >> 6)) return -1; 3739 if (s1[i++] != 0x80 + (ch & 0x3f)) return -1; 3740 } else if (ch >= 0xd800 && ch < 0xdc00) { 3741 stbtt_uint32 c; 3742 stbtt_uint16 ch2 = s2[2]*256 + s2[3]; 3743 if (i+3 >= len1) return -1; 3744 c = ((ch - 0xd800) << 10) + (ch2 - 0xdc00) + 0x10000; 3745 if (s1[i++] != 0xf0 + (c >> 18)) return -1; 3746 if (s1[i++] != 0x80 + ((c >> 12) & 0x3f)) return -1; 3747 if (s1[i++] != 0x80 + ((c >> 6) & 0x3f)) return -1; 3748 if (s1[i++] != 0x80 + ((c ) & 0x3f)) return -1; 3749 s2 += 2; // plus another 2 below 3750 len2 -= 2; 3751 } else if (ch >= 0xdc00 && ch < 0xe000) { 3752 return -1; 3753 } else { 3754 if (i+2 >= len1) return -1; 3755 if (s1[i++] != 0xe0 + (ch >> 12)) return -1; 3756 if (s1[i++] != 0x80 + ((ch >> 6) & 0x3f)) return -1; 3757 if (s1[i++] != 0x80 + ((ch ) & 0x3f)) return -1; 3758 } 3759 s2 += 2; 3760 len2 -= 2; 3761 } 3762 return i; 3763 } 3764 3765 static int stbtt_CompareUTF8toUTF16_bigendian_internal(char *s1, int len1, char *s2, int len2) 3766 { 3767 return len1 == stbtt__CompareUTF8toUTF16_bigendian_prefix((stbtt_uint8*) s1, len1, (stbtt_uint8*) s2, len2); 3768 } 3769 3770 // returns results in whatever encoding you request... but note that 2-byte encodings 3771 // will be BIG-ENDIAN... use stbtt_CompareUTF8toUTF16_bigendian() to compare 3772 STBTT_DEF const char *stbtt_GetFontNameString(const stbtt_fontinfo *font, int *length, int platformID, int encodingID, int languageID, int nameID) 3773 { 3774 stbtt_int32 i,count,stringOffset; 3775 stbtt_uint8 *fc = font->data; 3776 stbtt_uint32 offset = font->fontstart; 3777 stbtt_uint32 nm = stbtt__find_table(fc, offset, "name"); 3778 if (!nm) return NULL; 3779 3780 count = ttUSHORT(fc+nm+2); 3781 stringOffset = nm + ttUSHORT(fc+nm+4); 3782 for (i=0; i < count; ++i) { 3783 stbtt_uint32 loc = nm + 6 + 12 * i; 3784 if (platformID == ttUSHORT(fc+loc+0) && encodingID == ttUSHORT(fc+loc+2) 3785 && languageID == ttUSHORT(fc+loc+4) && nameID == ttUSHORT(fc+loc+6)) { 3786 *length = ttUSHORT(fc+loc+8); 3787 return (const char *) (fc+stringOffset+ttUSHORT(fc+loc+10)); 3788 } 3789 } 3790 return NULL; 3791 } 3792 3793 static int stbtt__matchpair(stbtt_uint8 *fc, stbtt_uint32 nm, stbtt_uint8 *name, stbtt_int32 nlen, stbtt_int32 target_id, stbtt_int32 next_id) 3794 { 3795 stbtt_int32 i; 3796 stbtt_int32 count = ttUSHORT(fc+nm+2); 3797 stbtt_int32 stringOffset = nm + ttUSHORT(fc+nm+4); 3798 3799 for (i=0; i < count; ++i) { 3800 stbtt_uint32 loc = nm + 6 + 12 * i; 3801 stbtt_int32 id = ttUSHORT(fc+loc+6); 3802 if (id == target_id) { 3803 // find the encoding 3804 stbtt_int32 platform = ttUSHORT(fc+loc+0), encoding = ttUSHORT(fc+loc+2), language = ttUSHORT(fc+loc+4); 3805 3806 // is this a Unicode encoding? 3807 if (platform == 0 || (platform == 3 && encoding == 1) || (platform == 3 && encoding == 10)) { 3808 stbtt_int32 slen = ttUSHORT(fc+loc+8); 3809 stbtt_int32 off = ttUSHORT(fc+loc+10); 3810 3811 // check if there's a prefix match 3812 stbtt_int32 matchlen = stbtt__CompareUTF8toUTF16_bigendian_prefix(name, nlen, fc+stringOffset+off,slen); 3813 if (matchlen >= 0) { 3814 // check for target_id+1 immediately following, with same encoding & language 3815 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) { 3816 slen = ttUSHORT(fc+loc+12+8); 3817 off = ttUSHORT(fc+loc+12+10); 3818 if (slen == 0) { 3819 if (matchlen == nlen) 3820 return 1; 3821 } else if (matchlen < nlen && name[matchlen] == ' ') { 3822 ++matchlen; 3823 if (stbtt_CompareUTF8toUTF16_bigendian_internal((char*) (name+matchlen), nlen-matchlen, (char*)(fc+stringOffset+off),slen)) 3824 return 1; 3825 } 3826 } else { 3827 // if nothing immediately following 3828 if (matchlen == nlen) 3829 return 1; 3830 } 3831 } 3832 } 3833 3834 // @TODO handle other encodings 3835 } 3836 } 3837 return 0; 3838 } 3839 3840 static int stbtt__matches(stbtt_uint8 *fc, stbtt_uint32 offset, stbtt_uint8 *name, stbtt_int32 flags) 3841 { 3842 stbtt_int32 nlen = (stbtt_int32) STBTT_strlen((char *) name); 3843 stbtt_uint32 nm,hd; 3844 if (!stbtt__isfont(fc+offset)) return 0; 3845 3846 // check italics/bold/underline flags in macStyle... 3847 if (flags) { 3848 hd = stbtt__find_table(fc, offset, "head"); 3849 if ((ttUSHORT(fc+hd+44) & 7) != (flags & 7)) return 0; 3850 } 3851 3852 nm = stbtt__find_table(fc, offset, "name"); 3853 if (!nm) return 0; 3854 3855 if (flags) { 3856 // if we checked the macStyle flags, then just check the family and ignore the subfamily 3857 if (stbtt__matchpair(fc, nm, name, nlen, 16, -1)) return 1; 3858 if (stbtt__matchpair(fc, nm, name, nlen, 1, -1)) return 1; 3859 if (stbtt__matchpair(fc, nm, name, nlen, 3, -1)) return 1; 3860 } else { 3861 if (stbtt__matchpair(fc, nm, name, nlen, 16, 17)) return 1; 3862 if (stbtt__matchpair(fc, nm, name, nlen, 1, 2)) return 1; 3863 if (stbtt__matchpair(fc, nm, name, nlen, 3, -1)) return 1; 3864 } 3865 3866 return 0; 3867 } 3868 3869 static int stbtt_FindMatchingFont_internal(unsigned char *font_collection, char *name_utf8, stbtt_int32 flags) 3870 { 3871 stbtt_int32 i; 3872 for (i=0;;++i) { 3873 stbtt_int32 off = stbtt_GetFontOffsetForIndex(font_collection, i); 3874 if (off < 0) return off; 3875 if (stbtt__matches((stbtt_uint8 *) font_collection, off, (stbtt_uint8*) name_utf8, flags)) 3876 return off; 3877 } 3878 } 3879 3880 #if defined(__GNUC__) || defined(__clang__) 3881 #pragma GCC diagnostic push 3882 #pragma GCC diagnostic ignored "-Wcast-qual" 3883 #endif 3884 3885 STBTT_DEF int stbtt_BakeFontBitmap(const unsigned char *data, int offset, 3886 float pixel_height, unsigned char *pixels, int pw, int ph, 3887 int first_char, int num_chars, stbtt_bakedchar *chardata) 3888 { 3889 return stbtt_BakeFontBitmap_internal((unsigned char *) data, offset, pixel_height, pixels, pw, ph, first_char, num_chars, chardata); 3890 } 3891 3892 STBTT_DEF int stbtt_GetFontOffsetForIndex(const unsigned char *data, int index) 3893 { 3894 return stbtt_GetFontOffsetForIndex_internal((unsigned char *) data, index); 3895 } 3896 3897 STBTT_DEF int stbtt_GetNumberOfFonts(const unsigned char *data) 3898 { 3899 return stbtt_GetNumberOfFonts_internal((unsigned char *) data); 3900 } 3901 3902 STBTT_DEF int stbtt_InitFont(stbtt_fontinfo *info, const unsigned char *data, int offset) 3903 { 3904 return stbtt_InitFont_internal(info, (unsigned char *) data, offset); 3905 } 3906 3907 STBTT_DEF int stbtt_FindMatchingFont(const unsigned char *fontdata, const char *name, int flags) 3908 { 3909 return stbtt_FindMatchingFont_internal((unsigned char *) fontdata, (char *) name, flags); 3910 } 3911 3912 STBTT_DEF int stbtt_CompareUTF8toUTF16_bigendian(const char *s1, int len1, const char *s2, int len2) 3913 { 3914 return stbtt_CompareUTF8toUTF16_bigendian_internal((char *) s1, len1, (char *) s2, len2); 3915 } 3916 3917 #if defined(__GNUC__) || defined(__clang__) 3918 #pragma GCC diagnostic pop 3919 #endif 3920 3921 // FULL VERSION HISTORY 3922 // 3923 // 1.25 (2021-07-11) many fixes 3924 // 1.24 (2020-02-05) fix warning 3925 // 1.23 (2020-02-02) query SVG data for glyphs; query whole kerning table (but only kern not GPOS) 3926 // 1.22 (2019-08-11) minimize missing-glyph duplication; fix kerning if both 'GPOS' and 'kern' are defined 3927 // 1.21 (2019-02-25) fix warning 3928 // 1.20 (2019-02-07) PackFontRange skips missing codepoints; GetScaleFontVMetrics() 3929 // 1.19 (2018-02-11) OpenType GPOS kerning (horizontal only), STBTT_fmod 3930 // 1.18 (2018-01-29) add missing function 3931 // 1.17 (2017-07-23) make more arguments const; doc fix 3932 // 1.16 (2017-07-12) SDF support 3933 // 1.15 (2017-03-03) make more arguments const 3934 // 1.14 (2017-01-16) num-fonts-in-TTC function 3935 // 1.13 (2017-01-02) support OpenType fonts, certain Apple fonts 3936 // 1.12 (2016-10-25) suppress warnings about casting away const with -Wcast-qual 3937 // 1.11 (2016-04-02) fix unused-variable warning 3938 // 1.10 (2016-04-02) allow user-defined fabs() replacement 3939 // fix memory leak if fontsize=0.0 3940 // fix warning from duplicate typedef 3941 // 1.09 (2016-01-16) warning fix; avoid crash on outofmem; use alloc userdata for PackFontRanges 3942 // 1.08 (2015-09-13) document stbtt_Rasterize(); fixes for vertical & horizontal edges 3943 // 1.07 (2015-08-01) allow PackFontRanges to accept arrays of sparse codepoints; 3944 // allow PackFontRanges to pack and render in separate phases; 3945 // fix stbtt_GetFontOFfsetForIndex (never worked for non-0 input?); 3946 // fixed an assert() bug in the new rasterizer 3947 // replace assert() with STBTT_assert() in new rasterizer 3948 // 1.06 (2015-07-14) performance improvements (~35% faster on x86 and x64 on test machine) 3949 // also more precise AA rasterizer, except if shapes overlap 3950 // remove need for STBTT_sort 3951 // 1.05 (2015-04-15) fix misplaced definitions for STBTT_STATIC 3952 // 1.04 (2015-04-15) typo in example 3953 // 1.03 (2015-04-12) STBTT_STATIC, fix memory leak in new packing, various fixes 3954 // 1.02 (2014-12-10) fix various warnings & compile issues w/ stb_rect_pack, C++ 3955 // 1.01 (2014-12-08) fix subpixel position when oversampling to exactly match 3956 // non-oversampled; STBTT_POINT_SIZE for packed case only 3957 // 1.00 (2014-12-06) add new PackBegin etc. API, w/ support for oversampling 3958 // 0.99 (2014-09-18) fix multiple bugs with subpixel rendering (ryg) 3959 // 0.9 (2014-08-07) support certain mac/iOS fonts without an MS platformID 3960 // 0.8b (2014-07-07) fix a warning 3961 // 0.8 (2014-05-25) fix a few more warnings 3962 // 0.7 (2013-09-25) bugfix: subpixel glyph bug fixed in 0.5 had come back 3963 // 0.6c (2012-07-24) improve documentation 3964 // 0.6b (2012-07-20) fix a few more warnings 3965 // 0.6 (2012-07-17) fix warnings; added stbtt_ScaleForMappingEmToPixels, 3966 // stbtt_GetFontBoundingBox, stbtt_IsGlyphEmpty 3967 // 0.5 (2011-12-09) bugfixes: 3968 // subpixel glyph renderer computed wrong bounding box 3969 // first vertex of shape can be off-curve (FreeSans) 3970 // 0.4b (2011-12-03) fixed an error in the font baking example 3971 // 0.4 (2011-12-01) kerning, subpixel rendering (tor) 3972 // bugfixes for: 3973 // codepoint-to-glyph conversion using table fmt=12 3974 // codepoint-to-glyph conversion using table fmt=4 3975 // stbtt_GetBakedQuad with non-square texture (Zer) 3976 // updated Hello World! sample to use kerning and subpixel 3977 // fixed some warnings 3978 // 0.3 (2009-06-24) cmap fmt=12, compound shapes (MM) 3979 // userdata, malloc-from-userdata, non-zero fill (stb) 3980 // 0.2 (2009-03-11) Fix unsigned/signed char warnings 3981 // 0.1 (2009-03-09) First public release 3982 // 3983 3984 /* 3985 ------------------------------------------------------------------------------ 3986 This software is available under 2 licenses -- choose whichever you prefer. 3987 ------------------------------------------------------------------------------ 3988 ALTERNATIVE A - MIT License 3989 Copyright (c) 2017 Sean Barrett 3990 Permission is hereby granted, free of charge, to any person obtaining a copy of 3991 this software and associated documentation files (the "Software"), to deal in 3992 the Software without restriction, including without limitation the rights to 3993 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 3994 of the Software, and to permit persons to whom the Software is furnished to do 3995 so, subject to the following conditions: 3996 The above copyright notice and this permission notice shall be included in all 3997 copies or substantial portions of the Software. 3998 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 3999 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 4000 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 4001 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 4002 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 4003 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 4004 SOFTWARE. 4005 ------------------------------------------------------------------------------ 4006 ALTERNATIVE B - Public Domain (www.unlicense.org) 4007 This is free and unencumbered software released into the public domain. 4008 Anyone is free to copy, modify, publish, use, compile, sell, or distribute this 4009 software, either in source code form or as a compiled binary, for any purpose, 4010 commercial or non-commercial, and by any means. 4011 In jurisdictions that recognize copyright laws, the author or authors of this 4012 software dedicate any and all copyright interest in the software to the public 4013 domain. We make this dedication for the benefit of the public at large and to 4014 the detriment of our heirs and successors. We intend this dedication to be an 4015 overt act of relinquishment in perpetuity of all present and future rights to 4016 this software under copyright law. 4017 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 4018 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 4019 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 4020 AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 4021 ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 4022 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 4023 ------------------------------------------------------------------------------ 4024 */