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