imstb_truetype.h (199485B)
1 // [DEAR IMGUI] 2 // This is a slightly modified version of stb_truetype.h 1.26. 3 // Mostly fixing for compiler and static analyzer warnings. 4 // Grep for [DEAR IMGUI] to find the changes. 5 6 // stb_truetype.h - v1.26 - public domain 7 // authored from 2009-2021 by Sean Barrett / RAD Game Tools 8 // 9 // ======================================================================= 10 // 11 // NO SECURITY GUARANTEE -- DO NOT USE THIS ON UNTRUSTED FONT FILES 12 // 13 // This library does no range checking of the offsets found in the file, 14 // meaning an attacker can use it to read arbitrary memory. 15 // 16 // ======================================================================= 17 // 18 // This library processes TrueType files: 19 // parse files 20 // extract glyph metrics 21 // extract glyph shapes 22 // render glyphs to one-channel bitmaps with antialiasing (box filter) 23 // render glyphs to one-channel SDF bitmaps (signed-distance field/function) 24 // 25 // Todo: 26 // non-MS cmaps 27 // crashproof on bad data 28 // hinting? (no longer patented) 29 // cleartype-style AA? 30 // optimize: use simple memory allocator for intermediates 31 // optimize: build edge-list directly from curves 32 // optimize: rasterize directly from curves? 33 // 34 // ADDITIONAL CONTRIBUTORS 35 // 36 // Mikko Mononen: compound shape support, more cmap formats 37 // Tor Andersson: kerning, subpixel rendering 38 // Dougall Johnson: OpenType / Type 2 font handling 39 // Daniel Ribeiro Maciel: basic GPOS-based kerning 40 // 41 // Misc other: 42 // Ryan Gordon 43 // Simon Glass 44 // github:IntellectualKitty 45 // Imanol Celaya 46 // Daniel Ribeiro Maciel 47 // 48 // Bug/warning reports/fixes: 49 // "Zer" on mollyrocket Fabian "ryg" Giesen github:NiLuJe 50 // Cass Everitt Martins Mozeiko github:aloucks 51 // stoiko (Haemimont Games) Cap Petschulat github:oyvindjam 52 // Brian Hook Omar Cornut github:vassvik 53 // Walter van Niftrik Ryan Griege 54 // David Gow Peter LaValle 55 // David Given Sergey Popov 56 // Ivan-Assen Ivanov Giumo X. Clanjor 57 // Anthony Pesch Higor Euripedes 58 // Johan Duparc Thomas Fields 59 // Hou Qiming Derek Vinyard 60 // Rob Loach Cort Stratton 61 // Kenney Phillis Jr. Brian Costabile 62 // Ken Voskuil (kaesve) 63 // 64 // VERSION HISTORY 65 // 66 // 1.26 (2021-08-28) fix broken rasterizer 67 // 1.25 (2021-07-11) many fixes 68 // 1.24 (2020-02-05) fix warning 69 // 1.23 (2020-02-02) query SVG data for glyphs; query whole kerning table (but only kern not GPOS) 70 // 1.22 (2019-08-11) minimize missing-glyph duplication; fix kerning if both 'GPOS' and 'kern' are defined 71 // 1.21 (2019-02-25) fix warning 72 // 1.20 (2019-02-07) PackFontRange skips missing codepoints; GetScaleFontVMetrics() 73 // 1.19 (2018-02-11) GPOS kerning, STBTT_fmod 74 // 1.18 (2018-01-29) add missing function 75 // 1.17 (2017-07-23) make more arguments const; doc fix 76 // 1.16 (2017-07-12) SDF support 77 // 1.15 (2017-03-03) make more arguments const 78 // 1.14 (2017-01-16) num-fonts-in-TTC function 79 // 1.13 (2017-01-02) support OpenType fonts, certain Apple fonts 80 // 1.12 (2016-10-25) suppress warnings about casting away const with -Wcast-qual 81 // 1.11 (2016-04-02) fix unused-variable warning 82 // 1.10 (2016-04-02) user-defined fabs(); rare memory leak; remove duplicate typedef 83 // 1.09 (2016-01-16) warning fix; avoid crash on outofmem; use allocation userdata properly 84 // 1.08 (2015-09-13) document stbtt_Rasterize(); fixes for vertical & horizontal edges 85 // 1.07 (2015-08-01) allow PackFontRanges to accept arrays of sparse codepoints; 86 // variant PackFontRanges to pack and render in separate phases; 87 // fix stbtt_GetFontOFfsetForIndex (never worked for non-0 input?); 88 // fixed an assert() bug in the new rasterizer 89 // replace assert() with STBTT_assert() in new rasterizer 90 // 91 // Full history can be found at the end of this file. 92 // 93 // LICENSE 94 // 95 // See end of file for license information. 96 // 97 // USAGE 98 // 99 // Include this file in whatever places need to refer to it. In ONE C/C++ 100 // file, write: 101 // #define STB_TRUETYPE_IMPLEMENTATION 102 // before the #include of this file. This expands out the actual 103 // implementation into that C/C++ file. 104 // 105 // To make the implementation private to the file that generates the implementation, 106 // #define STBTT_STATIC 107 // 108 // Simple 3D API (don't ship this, but it's fine for tools and quick start) 109 // stbtt_BakeFontBitmap() -- bake a font to a bitmap for use as texture 110 // stbtt_GetBakedQuad() -- compute quad to draw for a given char 111 // 112 // Improved 3D API (more shippable): 113 // #include "stb_rect_pack.h" -- optional, but you really want it 114 // stbtt_PackBegin() 115 // stbtt_PackSetOversampling() -- for improved quality on small fonts 116 // stbtt_PackFontRanges() -- pack and renders 117 // stbtt_PackEnd() 118 // stbtt_GetPackedQuad() 119 // 120 // "Load" a font file from a memory buffer (you have to keep the buffer loaded) 121 // stbtt_InitFont() 122 // stbtt_GetFontOffsetForIndex() -- indexing for TTC font collections 123 // stbtt_GetNumberOfFonts() -- number of fonts for TTC font collections 124 // 125 // Render a unicode codepoint to a bitmap 126 // stbtt_GetCodepointBitmap() -- allocates and returns a bitmap 127 // stbtt_MakeCodepointBitmap() -- renders into bitmap you provide 128 // stbtt_GetCodepointBitmapBox() -- how big the bitmap must be 129 // 130 // Character advance/positioning 131 // stbtt_GetCodepointHMetrics() 132 // stbtt_GetFontVMetrics() 133 // stbtt_GetFontVMetricsOS2() 134 // stbtt_GetCodepointKernAdvance() 135 // 136 // Starting with version 1.06, the rasterizer was replaced with a new, 137 // faster and generally-more-precise rasterizer. The new rasterizer more 138 // accurately measures pixel coverage for anti-aliasing, except in the case 139 // where multiple shapes overlap, in which case it overestimates the AA pixel 140 // coverage. Thus, anti-aliasing of intersecting shapes may look wrong. If 141 // this turns out to be a problem, you can re-enable the old rasterizer with 142 // #define STBTT_RASTERIZER_VERSION 1 143 // which will incur about a 15% speed hit. 144 // 145 // ADDITIONAL DOCUMENTATION 146 // 147 // Immediately after this block comment are a series of sample programs. 148 // 149 // After the sample programs is the "header file" section. This section 150 // includes documentation for each API function. 151 // 152 // Some important concepts to understand to use this library: 153 // 154 // Codepoint 155 // Characters are defined by unicode codepoints, e.g. 65 is 156 // uppercase A, 231 is lowercase c with a cedilla, 0x7e30 is 157 // the hiragana for "ma". 158 // 159 // Glyph 160 // A visual character shape (every codepoint is rendered as 161 // some glyph) 162 // 163 // Glyph index 164 // A font-specific integer ID representing a glyph 165 // 166 // Baseline 167 // Glyph shapes are defined relative to a baseline, which is the 168 // bottom of uppercase characters. Characters extend both above 169 // and below the baseline. 170 // 171 // Current Point 172 // As you draw text to the screen, you keep track of a "current point" 173 // which is the origin of each character. The current point's vertical 174 // position is the baseline. Even "baked fonts" use this model. 175 // 176 // Vertical Font Metrics 177 // The vertical qualities of the font, used to vertically position 178 // and space the characters. See docs for stbtt_GetFontVMetrics. 179 // 180 // Font Size in Pixels or Points 181 // The preferred interface for specifying font sizes in stb_truetype 182 // is to specify how tall the font's vertical extent should be in pixels. 183 // If that sounds good enough, skip the next paragraph. 184 // 185 // Most font APIs instead use "points", which are a common typographic 186 // measurement for describing font size, defined as 72 points per inch. 187 // stb_truetype provides a point API for compatibility. However, true 188 // "per inch" conventions don't make much sense on computer displays 189 // since different monitors have different number of pixels per 190 // inch. For example, Windows traditionally uses a convention that 191 // there are 96 pixels per inch, thus making 'inch' measurements have 192 // nothing to do with inches, and thus effectively defining a point to 193 // be 1.333 pixels. Additionally, the TrueType font data provides 194 // an explicit scale factor to scale a given font's glyphs to points, 195 // but the author has observed that this scale factor is often wrong 196 // for non-commercial fonts, thus making fonts scaled in points 197 // according to the TrueType spec incoherently sized in practice. 198 // 199 // DETAILED USAGE: 200 // 201 // Scale: 202 // Select how high you want the font to be, in points or pixels. 203 // Call ScaleForPixelHeight or ScaleForMappingEmToPixels to compute 204 // a scale factor SF that will be used by all other functions. 205 // 206 // Baseline: 207 // You need to select a y-coordinate that is the baseline of where 208 // your text will appear. Call GetFontBoundingBox to get the baseline-relative 209 // bounding box for all characters. SF*-y0 will be the distance in pixels 210 // that the worst-case character could extend above the baseline, so if 211 // you want the top edge of characters to appear at the top of the 212 // screen where y=0, then you would set the baseline to SF*-y0. 213 // 214 // Current point: 215 // Set the current point where the first character will appear. The 216 // first character could extend left of the current point; this is font 217 // dependent. You can either choose a current point that is the leftmost 218 // point and hope, or add some padding, or check the bounding box or 219 // left-side-bearing of the first character to be displayed and set 220 // the current point based on that. 221 // 222 // Displaying a character: 223 // Compute the bounding box of the character. It will contain signed values 224 // relative to <current_point, baseline>. I.e. if it returns x0,y0,x1,y1, 225 // then the character should be displayed in the rectangle from 226 // <current_point+SF*x0, baseline+SF*y0> to <current_point+SF*x1,baseline+SF*y1). 227 // 228 // Advancing for the next character: 229 // Call GlyphHMetrics, and compute 'current_point += SF * advance'. 230 // 231 // 232 // ADVANCED USAGE 233 // 234 // Quality: 235 // 236 // - Use the functions with Subpixel at the end to allow your characters 237 // to have subpixel positioning. Since the font is anti-aliased, not 238 // hinted, this is very import for quality. (This is not possible with 239 // baked fonts.) 240 // 241 // - Kerning is now supported, and if you're supporting subpixel rendering 242 // then kerning is worth using to give your text a polished look. 243 // 244 // Performance: 245 // 246 // - Convert Unicode codepoints to glyph indexes and operate on the glyphs; 247 // if you don't do this, stb_truetype is forced to do the conversion on 248 // every call. 249 // 250 // - There are a lot of memory allocations. We should modify it to take 251 // a temp buffer and allocate from the temp buffer (without freeing), 252 // should help performance a lot. 253 // 254 // NOTES 255 // 256 // The system uses the raw data found in the .ttf file without changing it 257 // and without building auxiliary data structures. This is a bit inefficient 258 // on little-endian systems (the data is big-endian), but assuming you're 259 // caching the bitmaps or glyph shapes this shouldn't be a big deal. 260 // 261 // It appears to be very hard to programmatically determine what font a 262 // given file is in a general way. I provide an API for this, but I don't 263 // recommend it. 264 // 265 // 266 // PERFORMANCE MEASUREMENTS FOR 1.06: 267 // 268 // 32-bit 64-bit 269 // Previous release: 8.83 s 7.68 s 270 // Pool allocations: 7.72 s 6.34 s 271 // Inline sort : 6.54 s 5.65 s 272 // New rasterizer : 5.63 s 5.00 s 273 274 ////////////////////////////////////////////////////////////////////////////// 275 ////////////////////////////////////////////////////////////////////////////// 276 //// 277 //// SAMPLE PROGRAMS 278 //// 279 // 280 // Incomplete text-in-3d-api example, which draws quads properly aligned to be lossless. 281 // See "tests/truetype_demo_win32.c" for a complete version. 282 #if 0 283 #define STB_TRUETYPE_IMPLEMENTATION // force following include to generate implementation 284 #include "stb_truetype.h" 285 286 unsigned char ttf_buffer[1<<20]; 287 unsigned char temp_bitmap[512*512]; 288 289 stbtt_bakedchar cdata[96]; // ASCII 32..126 is 95 glyphs 290 GLuint ftex; 291 292 void my_stbtt_initfont(void) 293 { 294 fread(ttf_buffer, 1, 1<<20, fopen("c:/windows/fonts/times.ttf", "rb")); 295 stbtt_BakeFontBitmap(ttf_buffer,0, 32.0, temp_bitmap,512,512, 32,96, cdata); // no guarantee this fits! 296 // can free ttf_buffer at this point 297 glGenTextures(1, &ftex); 298 glBindTexture(GL_TEXTURE_2D, ftex); 299 glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, 512,512, 0, GL_ALPHA, GL_UNSIGNED_BYTE, temp_bitmap); 300 // can free temp_bitmap at this point 301 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 302 } 303 304 void my_stbtt_print(float x, float y, char *text) 305 { 306 // assume orthographic projection with units = screen pixels, origin at top left 307 glEnable(GL_BLEND); 308 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 309 glEnable(GL_TEXTURE_2D); 310 glBindTexture(GL_TEXTURE_2D, ftex); 311 glBegin(GL_QUADS); 312 while (*text) { 313 if (*text >= 32 && *text < 128) { 314 stbtt_aligned_quad q; 315 stbtt_GetBakedQuad(cdata, 512,512, *text-32, &x,&y,&q,1);//1=opengl & d3d10+,0=d3d9 316 glTexCoord2f(q.s0,q.t0); glVertex2f(q.x0,q.y0); 317 glTexCoord2f(q.s1,q.t0); glVertex2f(q.x1,q.y0); 318 glTexCoord2f(q.s1,q.t1); glVertex2f(q.x1,q.y1); 319 glTexCoord2f(q.s0,q.t1); glVertex2f(q.x0,q.y1); 320 } 321 ++text; 322 } 323 glEnd(); 324 } 325 #endif 326 // 327 // 328 ////////////////////////////////////////////////////////////////////////////// 329 // 330 // Complete program (this compiles): get a single bitmap, print as ASCII art 331 // 332 #if 0 333 #include <stdio.h> 334 #define STB_TRUETYPE_IMPLEMENTATION // force following include to generate implementation 335 #include "stb_truetype.h" 336 337 char ttf_buffer[1<<25]; 338 339 int main(int argc, char **argv) 340 { 341 stbtt_fontinfo font; 342 unsigned char *bitmap; 343 int w,h,i,j,c = (argc > 1 ? atoi(argv[1]) : 'a'), s = (argc > 2 ? atoi(argv[2]) : 20); 344 345 fread(ttf_buffer, 1, 1<<25, fopen(argc > 3 ? argv[3] : "c:/windows/fonts/arialbd.ttf", "rb")); 346 347 stbtt_InitFont(&font, ttf_buffer, stbtt_GetFontOffsetForIndex(ttf_buffer,0)); 348 bitmap = stbtt_GetCodepointBitmap(&font, 0,stbtt_ScaleForPixelHeight(&font, s), c, &w, &h, 0,0); 349 350 for (j=0; j < h; ++j) { 351 for (i=0; i < w; ++i) 352 putchar(" .:ioVM@"[bitmap[j*w+i]>>5]); 353 putchar('\n'); 354 } 355 return 0; 356 } 357 #endif 358 // 359 // Output: 360 // 361 // .ii. 362 // @@@@@@. 363 // V@Mio@@o 364 // :i. V@V 365 // :oM@@M 366 // :@@@MM@M 367 // @@o o@M 368 // :@@. M@M 369 // @@@o@@@@ 370 // :M@@V:@@. 371 // 372 ////////////////////////////////////////////////////////////////////////////// 373 // 374 // Complete program: print "Hello World!" banner, with bugs 375 // 376 #if 0 377 char buffer[24<<20]; 378 unsigned char screen[20][79]; 379 380 int main(int arg, char **argv) 381 { 382 stbtt_fontinfo font; 383 int i,j,ascent,baseline,ch=0; 384 float scale, xpos=2; // leave a little padding in case the character extends left 385 char *text = "Heljo World!"; // intentionally misspelled to show 'lj' brokenness 386 387 fread(buffer, 1, 1000000, fopen("c:/windows/fonts/arialbd.ttf", "rb")); 388 stbtt_InitFont(&font, buffer, 0); 389 390 scale = stbtt_ScaleForPixelHeight(&font, 15); 391 stbtt_GetFontVMetrics(&font, &ascent,0,0); 392 baseline = (int) (ascent*scale); 393 394 while (text[ch]) { 395 int advance,lsb,x0,y0,x1,y1; 396 float x_shift = xpos - (float) floor(xpos); 397 stbtt_GetCodepointHMetrics(&font, text[ch], &advance, &lsb); 398 stbtt_GetCodepointBitmapBoxSubpixel(&font, text[ch], scale,scale,x_shift,0, &x0,&y0,&x1,&y1); 399 stbtt_MakeCodepointBitmapSubpixel(&font, &screen[baseline + y0][(int) xpos + x0], x1-x0,y1-y0, 79, scale,scale,x_shift,0, text[ch]); 400 // note that this stomps the old data, so where character boxes overlap (e.g. 'lj') it's wrong 401 // because this API is really for baking character bitmaps into textures. if you want to render 402 // a sequence of characters, you really need to render each bitmap to a temp buffer, then 403 // "alpha blend" that into the working buffer 404 xpos += (advance * scale); 405 if (text[ch+1]) 406 xpos += scale*stbtt_GetCodepointKernAdvance(&font, text[ch],text[ch+1]); 407 ++ch; 408 } 409 410 for (j=0; j < 20; ++j) { 411 for (i=0; i < 78; ++i) 412 putchar(" .:ioVM@"[screen[j][i]>>5]); 413 putchar('\n'); 414 } 415 416 return 0; 417 } 418 #endif 419 420 421 ////////////////////////////////////////////////////////////////////////////// 422 ////////////////////////////////////////////////////////////////////////////// 423 //// 424 //// INTEGRATION WITH YOUR CODEBASE 425 //// 426 //// The following sections allow you to supply alternate definitions 427 //// of C library functions used by stb_truetype, e.g. if you don't 428 //// link with the C runtime library. 429 430 #ifdef STB_TRUETYPE_IMPLEMENTATION 431 // #define your own (u)stbtt_int8/16/32 before including to override this 432 #ifndef stbtt_uint8 433 typedef unsigned char stbtt_uint8; 434 typedef signed char stbtt_int8; 435 typedef unsigned short stbtt_uint16; 436 typedef signed short stbtt_int16; 437 typedef unsigned int stbtt_uint32; 438 typedef signed int stbtt_int32; 439 #endif 440 441 typedef char stbtt__check_size32[sizeof(stbtt_int32)==4 ? 1 : -1]; 442 typedef char stbtt__check_size16[sizeof(stbtt_int16)==2 ? 1 : -1]; 443 444 // e.g. #define your own STBTT_ifloor/STBTT_iceil() to avoid math.h 445 #ifndef STBTT_ifloor 446 #include <math.h> 447 #define STBTT_ifloor(x) ((int) floor(x)) 448 #define STBTT_iceil(x) ((int) ceil(x)) 449 #endif 450 451 #ifndef STBTT_sqrt 452 #include <math.h> 453 #define STBTT_sqrt(x) sqrt(x) 454 #define STBTT_pow(x,y) pow(x,y) 455 #endif 456 457 #ifndef STBTT_fmod 458 #include <math.h> 459 #define STBTT_fmod(x,y) fmod(x,y) 460 #endif 461 462 #ifndef STBTT_cos 463 #include <math.h> 464 #define STBTT_cos(x) cos(x) 465 #define STBTT_acos(x) acos(x) 466 #endif 467 468 #ifndef STBTT_fabs 469 #include <math.h> 470 #define STBTT_fabs(x) fabs(x) 471 #endif 472 473 // #define your own functions "STBTT_malloc" / "STBTT_free" to avoid malloc.h 474 #ifndef STBTT_malloc 475 #include <stdlib.h> 476 #define STBTT_malloc(x,u) ((void)(u),malloc(x)) 477 #define STBTT_free(x,u) ((void)(u),free(x)) 478 #endif 479 480 #ifndef STBTT_assert 481 #include <assert.h> 482 #define STBTT_assert(x) assert(x) 483 #endif 484 485 #ifndef STBTT_strlen 486 #include <string.h> 487 #define STBTT_strlen(x) strlen(x) 488 #endif 489 490 #ifndef STBTT_memcpy 491 #include <string.h> 492 #define STBTT_memcpy memcpy 493 #define STBTT_memset memset 494 #endif 495 #endif 496 497 /////////////////////////////////////////////////////////////////////////////// 498 /////////////////////////////////////////////////////////////////////////////// 499 //// 500 //// INTERFACE 501 //// 502 //// 503 504 #ifndef __STB_INCLUDE_STB_TRUETYPE_H__ 505 #define __STB_INCLUDE_STB_TRUETYPE_H__ 506 507 #ifdef STBTT_STATIC 508 #define STBTT_DEF static 509 #else 510 #define STBTT_DEF extern 511 #endif 512 513 #ifdef __cplusplus 514 extern "C" { 515 #endif 516 517 // private structure 518 typedef struct 519 { 520 unsigned char *data; 521 int cursor; 522 int size; 523 } stbtt__buf; 524 525 ////////////////////////////////////////////////////////////////////////////// 526 // 527 // TEXTURE BAKING API 528 // 529 // If you use this API, you only have to call two functions ever. 530 // 531 532 typedef struct 533 { 534 unsigned short x0,y0,x1,y1; // coordinates of bbox in bitmap 535 float xoff,yoff,xadvance; 536 } stbtt_bakedchar; 537 538 STBTT_DEF int stbtt_BakeFontBitmap(const unsigned char *data, int offset, // font location (use offset=0 for plain .ttf) 539 float pixel_height, // height of font in pixels 540 unsigned char *pixels, int pw, int ph, // bitmap to be filled in 541 int first_char, int num_chars, // characters to bake 542 stbtt_bakedchar *chardata); // you allocate this, it's num_chars long 543 // if return is positive, the first unused row of the bitmap 544 // if return is negative, returns the negative of the number of characters that fit 545 // if return is 0, no characters fit and no rows were used 546 // This uses a very crappy packing. 547 548 typedef struct 549 { 550 float x0,y0,s0,t0; // top-left 551 float x1,y1,s1,t1; // bottom-right 552 } stbtt_aligned_quad; 553 554 STBTT_DEF void stbtt_GetBakedQuad(const stbtt_bakedchar *chardata, int pw, int ph, // same data as above 555 int char_index, // character to display 556 float *xpos, float *ypos, // pointers to current position in screen pixel space 557 stbtt_aligned_quad *q, // output: quad to draw 558 int opengl_fillrule); // true if opengl fill rule; false if DX9 or earlier 559 // Call GetBakedQuad with char_index = 'character - first_char', and it 560 // creates the quad you need to draw and advances the current position. 561 // 562 // The coordinate system used assumes y increases downwards. 563 // 564 // Characters will extend both above and below the current position; 565 // see discussion of "BASELINE" above. 566 // 567 // It's inefficient; you might want to c&p it and optimize it. 568 569 STBTT_DEF void stbtt_GetScaledFontVMetrics(const unsigned char *fontdata, int index, float size, float *ascent, float *descent, float *lineGap); 570 // Query the font vertical metrics without having to create a font first. 571 572 573 ////////////////////////////////////////////////////////////////////////////// 574 // 575 // NEW TEXTURE BAKING API 576 // 577 // This provides options for packing multiple fonts into one atlas, not 578 // perfectly but better than nothing. 579 580 typedef struct 581 { 582 unsigned short x0,y0,x1,y1; // coordinates of bbox in bitmap 583 float xoff,yoff,xadvance; 584 float xoff2,yoff2; 585 } stbtt_packedchar; 586 587 typedef struct stbtt_pack_context stbtt_pack_context; 588 typedef struct stbtt_fontinfo stbtt_fontinfo; 589 #ifndef STB_RECT_PACK_VERSION 590 typedef struct stbrp_rect stbrp_rect; 591 #endif 592 593 STBTT_DEF int stbtt_PackBegin(stbtt_pack_context *spc, unsigned char *pixels, int width, int height, int stride_in_bytes, int padding, void *alloc_context); 594 // Initializes a packing context stored in the passed-in stbtt_pack_context. 595 // Future calls using this context will pack characters into the bitmap passed 596 // in here: a 1-channel bitmap that is width * height. stride_in_bytes is 597 // the distance from one row to the next (or 0 to mean they are packed tightly 598 // together). "padding" is the amount of padding to leave between each 599 // character (normally you want '1' for bitmaps you'll use as textures with 600 // bilinear filtering). 601 // 602 // Returns 0 on failure, 1 on success. 603 604 STBTT_DEF void stbtt_PackEnd (stbtt_pack_context *spc); 605 // Cleans up the packing context and frees all memory. 606 607 #define STBTT_POINT_SIZE(x) (-(x)) 608 609 STBTT_DEF int stbtt_PackFontRange(stbtt_pack_context *spc, const unsigned char *fontdata, int font_index, float font_size, 610 int first_unicode_char_in_range, int num_chars_in_range, stbtt_packedchar *chardata_for_range); 611 // Creates character bitmaps from the font_index'th font found in fontdata (use 612 // font_index=0 if you don't know what that is). It creates num_chars_in_range 613 // bitmaps for characters with unicode values starting at first_unicode_char_in_range 614 // and increasing. Data for how to render them is stored in chardata_for_range; 615 // pass these to stbtt_GetPackedQuad to get back renderable quads. 616 // 617 // font_size is the full height of the character from ascender to descender, 618 // as computed by stbtt_ScaleForPixelHeight. To use a point size as computed 619 // by stbtt_ScaleForMappingEmToPixels, wrap the point size in STBTT_POINT_SIZE() 620 // and pass that result as 'font_size': 621 // ..., 20 , ... // font max minus min y is 20 pixels tall 622 // ..., STBTT_POINT_SIZE(20), ... // 'M' is 20 pixels tall 623 624 typedef struct 625 { 626 float font_size; 627 int first_unicode_codepoint_in_range; // if non-zero, then the chars are continuous, and this is the first codepoint 628 int *array_of_unicode_codepoints; // if non-zero, then this is an array of unicode codepoints 629 int num_chars; 630 stbtt_packedchar *chardata_for_range; // output 631 unsigned char h_oversample, v_oversample; // don't set these, they're used internally 632 } stbtt_pack_range; 633 634 STBTT_DEF int stbtt_PackFontRanges(stbtt_pack_context *spc, const unsigned char *fontdata, int font_index, stbtt_pack_range *ranges, int num_ranges); 635 // Creates character bitmaps from multiple ranges of characters stored in 636 // ranges. This will usually create a better-packed bitmap than multiple 637 // calls to stbtt_PackFontRange. Note that you can call this multiple 638 // times within a single PackBegin/PackEnd. 639 640 STBTT_DEF void stbtt_PackSetOversampling(stbtt_pack_context *spc, unsigned int h_oversample, unsigned int v_oversample); 641 // Oversampling a font increases the quality by allowing higher-quality subpixel 642 // positioning, and is especially valuable at smaller text sizes. 643 // 644 // This function sets the amount of oversampling for all following calls to 645 // stbtt_PackFontRange(s) or stbtt_PackFontRangesGatherRects for a given 646 // pack context. The default (no oversampling) is achieved by h_oversample=1 647 // and v_oversample=1. The total number of pixels required is 648 // h_oversample*v_oversample larger than the default; for example, 2x2 649 // oversampling requires 4x the storage of 1x1. For best results, render 650 // oversampled textures with bilinear filtering. Look at the readme in 651 // stb/tests/oversample for information about oversampled fonts 652 // 653 // To use with PackFontRangesGather etc., you must set it before calls 654 // call to PackFontRangesGatherRects. 655 656 STBTT_DEF void stbtt_PackSetSkipMissingCodepoints(stbtt_pack_context *spc, int skip); 657 // If skip != 0, this tells stb_truetype to skip any codepoints for which 658 // there is no corresponding glyph. If skip=0, which is the default, then 659 // codepoints without a glyph received the font's "missing character" glyph, 660 // typically an empty box by convention. 661 662 STBTT_DEF void stbtt_GetPackedQuad(const stbtt_packedchar *chardata, int pw, int ph, // same data as above 663 int char_index, // character to display 664 float *xpos, float *ypos, // pointers to current position in screen pixel space 665 stbtt_aligned_quad *q, // output: quad to draw 666 int align_to_integer); 667 668 STBTT_DEF int stbtt_PackFontRangesGatherRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects); 669 STBTT_DEF void stbtt_PackFontRangesPackRects(stbtt_pack_context *spc, stbrp_rect *rects, int num_rects); 670 STBTT_DEF int stbtt_PackFontRangesRenderIntoRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects); 671 // Calling these functions in sequence is roughly equivalent to calling 672 // stbtt_PackFontRanges(). If you more control over the packing of multiple 673 // fonts, or if you want to pack custom data into a font texture, take a look 674 // at the source to of stbtt_PackFontRanges() and create a custom version 675 // using these functions, e.g. call GatherRects multiple times, 676 // building up a single array of rects, then call PackRects once, 677 // then call RenderIntoRects repeatedly. This may result in a 678 // better packing than calling PackFontRanges multiple times 679 // (or it may not). 680 681 // this is an opaque structure that you shouldn't mess with which holds 682 // all the context needed from PackBegin to PackEnd. 683 struct stbtt_pack_context { 684 void *user_allocator_context; 685 void *pack_info; 686 int width; 687 int height; 688 int stride_in_bytes; 689 int padding; 690 int skip_missing; 691 unsigned int h_oversample, v_oversample; 692 unsigned char *pixels; 693 void *nodes; 694 }; 695 696 ////////////////////////////////////////////////////////////////////////////// 697 // 698 // FONT LOADING 699 // 700 // 701 702 STBTT_DEF int stbtt_GetNumberOfFonts(const unsigned char *data); 703 // This function will determine the number of fonts in a font file. TrueType 704 // collection (.ttc) files may contain multiple fonts, while TrueType font 705 // (.ttf) files only contain one font. The number of fonts can be used for 706 // indexing with the previous function where the index is between zero and one 707 // less than the total fonts. If an error occurs, -1 is returned. 708 709 STBTT_DEF int stbtt_GetFontOffsetForIndex(const unsigned char *data, int index); 710 // Each .ttf/.ttc file may have more than one font. Each font has a sequential 711 // index number starting from 0. Call this function to get the font offset for 712 // a given index; it returns -1 if the index is out of range. A regular .ttf 713 // file will only define one font and it always be at offset 0, so it will 714 // return '0' for index 0, and -1 for all other indices. 715 716 // The following structure is defined publicly so you can declare one on 717 // the stack or as a global or etc, but you should treat it as opaque. 718 struct stbtt_fontinfo 719 { 720 void * userdata; 721 unsigned char * data; // pointer to .ttf file 722 int fontstart; // offset of start of font 723 724 int numGlyphs; // number of glyphs, needed for range checking 725 726 int loca,head,glyf,hhea,hmtx,kern,gpos,svg; // table locations as offset from start of .ttf 727 int index_map; // a cmap mapping for our chosen character encoding 728 int indexToLocFormat; // format needed to map from glyph index to glyph 729 730 stbtt__buf cff; // cff font data 731 stbtt__buf charstrings; // the charstring index 732 stbtt__buf gsubrs; // global charstring subroutines index 733 stbtt__buf subrs; // private charstring subroutines index 734 stbtt__buf fontdicts; // array of font dicts 735 stbtt__buf fdselect; // map from glyph to fontdict 736 }; 737 738 STBTT_DEF int stbtt_InitFont(stbtt_fontinfo *info, const unsigned char *data, int offset); 739 // Given an offset into the file that defines a font, this function builds 740 // the necessary cached info for the rest of the system. You must allocate 741 // the stbtt_fontinfo yourself, and stbtt_InitFont will fill it out. You don't 742 // need to do anything special to free it, because the contents are pure 743 // value data with no additional data structures. Returns 0 on failure. 744 745 746 ////////////////////////////////////////////////////////////////////////////// 747 // 748 // CHARACTER TO GLYPH-INDEX CONVERSIOn 749 750 STBTT_DEF int stbtt_FindGlyphIndex(const stbtt_fontinfo *info, int unicode_codepoint); 751 // If you're going to perform multiple operations on the same character 752 // and you want a speed-up, call this function with the character you're 753 // going to process, then use glyph-based functions instead of the 754 // codepoint-based functions. 755 // Returns 0 if the character codepoint is not defined in the font. 756 757 758 ////////////////////////////////////////////////////////////////////////////// 759 // 760 // CHARACTER PROPERTIES 761 // 762 763 STBTT_DEF float stbtt_ScaleForPixelHeight(const stbtt_fontinfo *info, float pixels); 764 // computes a scale factor to produce a font whose "height" is 'pixels' tall. 765 // Height is measured as the distance from the highest ascender to the lowest 766 // descender; in other words, it's equivalent to calling stbtt_GetFontVMetrics 767 // and computing: 768 // scale = pixels / (ascent - descent) 769 // so if you prefer to measure height by the ascent only, use a similar calculation. 770 771 STBTT_DEF float stbtt_ScaleForMappingEmToPixels(const stbtt_fontinfo *info, float pixels); 772 // computes a scale factor to produce a font whose EM size is mapped to 773 // 'pixels' tall. This is probably what traditional APIs compute, but 774 // I'm not positive. 775 776 STBTT_DEF void stbtt_GetFontVMetrics(const stbtt_fontinfo *info, int *ascent, int *descent, int *lineGap); 777 // ascent is the coordinate above the baseline the font extends; descent 778 // is the coordinate below the baseline the font extends (i.e. it is typically negative) 779 // lineGap is the spacing between one row's descent and the next row's ascent... 780 // so you should advance the vertical position by "*ascent - *descent + *lineGap" 781 // these are expressed in unscaled coordinates, so you must multiply by 782 // the scale factor for a given size 783 784 STBTT_DEF int stbtt_GetFontVMetricsOS2(const stbtt_fontinfo *info, int *typoAscent, int *typoDescent, int *typoLineGap); 785 // analogous to GetFontVMetrics, but returns the "typographic" values from the OS/2 786 // table (specific to MS/Windows TTF files). 787 // 788 // Returns 1 on success (table present), 0 on failure. 789 790 STBTT_DEF void stbtt_GetFontBoundingBox(const stbtt_fontinfo *info, int *x0, int *y0, int *x1, int *y1); 791 // the bounding box around all possible characters 792 793 STBTT_DEF void stbtt_GetCodepointHMetrics(const stbtt_fontinfo *info, int codepoint, int *advanceWidth, int *leftSideBearing); 794 // leftSideBearing is the offset from the current horizontal position to the left edge of the character 795 // advanceWidth is the offset from the current horizontal position to the next horizontal position 796 // these are expressed in unscaled coordinates 797 798 STBTT_DEF int stbtt_GetCodepointKernAdvance(const stbtt_fontinfo *info, int ch1, int ch2); 799 // an additional amount to add to the 'advance' value between ch1 and ch2 800 801 STBTT_DEF int stbtt_GetCodepointBox(const stbtt_fontinfo *info, int codepoint, int *x0, int *y0, int *x1, int *y1); 802 // Gets the bounding box of the visible part of the glyph, in unscaled coordinates 803 804 STBTT_DEF void stbtt_GetGlyphHMetrics(const stbtt_fontinfo *info, int glyph_index, int *advanceWidth, int *leftSideBearing); 805 STBTT_DEF int stbtt_GetGlyphKernAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2); 806 STBTT_DEF int stbtt_GetGlyphBox(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1); 807 // as above, but takes one or more glyph indices for greater efficiency 808 809 typedef struct stbtt_kerningentry 810 { 811 int glyph1; // use stbtt_FindGlyphIndex 812 int glyph2; 813 int advance; 814 } stbtt_kerningentry; 815 816 STBTT_DEF int stbtt_GetKerningTableLength(const stbtt_fontinfo *info); 817 STBTT_DEF int stbtt_GetKerningTable(const stbtt_fontinfo *info, stbtt_kerningentry* table, int table_length); 818 // Retrieves a complete list of all of the kerning pairs provided by the font 819 // stbtt_GetKerningTable never writes more than table_length entries and returns how many entries it did write. 820 // The table will be sorted by (a.glyph1 == b.glyph1)?(a.glyph2 < b.glyph2):(a.glyph1 < b.glyph1) 821 822 ////////////////////////////////////////////////////////////////////////////// 823 // 824 // GLYPH SHAPES (you probably don't need these, but they have to go before 825 // the bitmaps for C declaration-order reasons) 826 // 827 828 #ifndef STBTT_vmove // you can predefine these to use different values (but why?) 829 enum { 830 STBTT_vmove=1, 831 STBTT_vline, 832 STBTT_vcurve, 833 STBTT_vcubic 834 }; 835 #endif 836 837 #ifndef stbtt_vertex // you can predefine this to use different values 838 // (we share this with other code at RAD) 839 #define stbtt_vertex_type short // can't use stbtt_int16 because that's not visible in the header file 840 typedef struct 841 { 842 stbtt_vertex_type x,y,cx,cy,cx1,cy1; 843 unsigned char type,padding; 844 } stbtt_vertex; 845 #endif 846 847 STBTT_DEF int stbtt_IsGlyphEmpty(const stbtt_fontinfo *info, int glyph_index); 848 // returns non-zero if nothing is drawn for this glyph 849 850 STBTT_DEF int stbtt_GetCodepointShape(const stbtt_fontinfo *info, int unicode_codepoint, stbtt_vertex **vertices); 851 STBTT_DEF int stbtt_GetGlyphShape(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **vertices); 852 // returns # of vertices and fills *vertices with the pointer to them 853 // these are expressed in "unscaled" coordinates 854 // 855 // The shape is a series of contours. Each one starts with 856 // a STBTT_moveto, then consists of a series of mixed 857 // STBTT_lineto and STBTT_curveto segments. A lineto 858 // draws a line from previous endpoint to its x,y; a curveto 859 // draws a quadratic bezier from previous endpoint to 860 // its x,y, using cx,cy as the bezier control point. 861 862 STBTT_DEF void stbtt_FreeShape(const stbtt_fontinfo *info, stbtt_vertex *vertices); 863 // frees the data allocated above 864 865 STBTT_DEF unsigned char *stbtt_FindSVGDoc(const stbtt_fontinfo *info, int gl); 866 STBTT_DEF int stbtt_GetCodepointSVG(const stbtt_fontinfo *info, int unicode_codepoint, const char **svg); 867 STBTT_DEF int stbtt_GetGlyphSVG(const stbtt_fontinfo *info, int gl, const char **svg); 868 // fills svg with the character's SVG data. 869 // returns data size or 0 if SVG not found. 870 871 ////////////////////////////////////////////////////////////////////////////// 872 // 873 // BITMAP RENDERING 874 // 875 876 STBTT_DEF void stbtt_FreeBitmap(unsigned char *bitmap, void *userdata); 877 // frees the bitmap allocated below 878 879 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); 880 // allocates a large-enough single-channel 8bpp bitmap and renders the 881 // specified character/glyph at the specified scale into it, with 882 // antialiasing. 0 is no coverage (transparent), 255 is fully covered (opaque). 883 // *width & *height are filled out with the width & height of the bitmap, 884 // which is stored left-to-right, top-to-bottom. 885 // 886 // xoff/yoff are the offset it pixel space from the glyph origin to the top-left of the bitmap 887 888 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); 889 // the same as stbtt_GetCodepoitnBitmap, but you can specify a subpixel 890 // shift for the character 891 892 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); 893 // the same as stbtt_GetCodepointBitmap, but you pass in storage for the bitmap 894 // in the form of 'output', with row spacing of 'out_stride' bytes. the bitmap 895 // is clipped to out_w/out_h bytes. Call stbtt_GetCodepointBitmapBox to get the 896 // width and height and positioning info for it first. 897 898 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); 899 // same as stbtt_MakeCodepointBitmap, but you can specify a subpixel 900 // shift for the character 901 902 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); 903 // same as stbtt_MakeCodepointBitmapSubpixel, but prefiltering 904 // is performed (see stbtt_PackSetOversampling) 905 906 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); 907 // get the bbox of the bitmap centered around the glyph origin; so the 908 // bitmap width is ix1-ix0, height is iy1-iy0, and location to place 909 // the bitmap top left is (leftSideBearing*scale,iy0). 910 // (Note that the bitmap uses y-increases-down, but the shape uses 911 // y-increases-up, so CodepointBitmapBox and CodepointBox are inverted.) 912 913 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); 914 // same as stbtt_GetCodepointBitmapBox, but you can specify a subpixel 915 // shift for the character 916 917 // the following functions are equivalent to the above functions, but operate 918 // on glyph indices instead of Unicode codepoints (for efficiency) 919 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); 920 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); 921 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); 922 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); 923 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 oversample_x, int oversample_y, float *sub_x, float *sub_y, int glyph); 924 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); 925 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); 926 927 928 // @TODO: don't expose this structure 929 typedef struct 930 { 931 int w,h,stride; 932 unsigned char *pixels; 933 } stbtt__bitmap; 934 935 // rasterize a shape with quadratic beziers into a bitmap 936 STBTT_DEF void stbtt_Rasterize(stbtt__bitmap *result, // 1-channel bitmap to draw into 937 float flatness_in_pixels, // allowable error of curve in pixels 938 stbtt_vertex *vertices, // array of vertices defining shape 939 int num_verts, // number of vertices in above array 940 float scale_x, float scale_y, // scale applied to input vertices 941 float shift_x, float shift_y, // translation applied to input vertices 942 int x_off, int y_off, // another translation applied to input 943 int invert, // if non-zero, vertically flip shape 944 void *userdata); // context for to STBTT_MALLOC 945 946 ////////////////////////////////////////////////////////////////////////////// 947 // 948 // Signed Distance Function (or Field) rendering 949 950 STBTT_DEF void stbtt_FreeSDF(unsigned char *bitmap, void *userdata); 951 // frees the SDF bitmap allocated below 952 953 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); 954 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); 955 // These functions compute a discretized SDF field for a single character, suitable for storing 956 // in a single-channel texture, sampling with bilinear filtering, and testing against 957 // larger than some threshold to produce scalable fonts. 958 // info -- the font 959 // scale -- controls the size of the resulting SDF bitmap, same as it would be creating a regular bitmap 960 // glyph/codepoint -- the character to generate the SDF for 961 // padding -- extra "pixels" around the character which are filled with the distance to the character (not 0), 962 // which allows effects like bit outlines 963 // onedge_value -- value 0-255 to test the SDF against to reconstruct the character (i.e. the isocontour of the character) 964 // pixel_dist_scale -- what value the SDF should increase by when moving one SDF "pixel" away from the edge (on the 0..255 scale) 965 // if positive, > onedge_value is inside; if negative, < onedge_value is inside 966 // width,height -- output height & width of the SDF bitmap (including padding) 967 // xoff,yoff -- output origin of the character 968 // return value -- a 2D array of bytes 0..255, width*height in size 969 // 970 // pixel_dist_scale & onedge_value are a scale & bias that allows you to make 971 // optimal use of the limited 0..255 for your application, trading off precision 972 // and special effects. SDF values outside the range 0..255 are clamped to 0..255. 973 // 974 // Example: 975 // scale = stbtt_ScaleForPixelHeight(22) 976 // padding = 5 977 // onedge_value = 180 978 // pixel_dist_scale = 180/5.0 = 36.0 979 // 980 // This will create an SDF bitmap in which the character is about 22 pixels 981 // high but the whole bitmap is about 22+5+5=32 pixels high. To produce a filled 982 // shape, sample the SDF at each pixel and fill the pixel if the SDF value 983 // is greater than or equal to 180/255. (You'll actually want to antialias, 984 // which is beyond the scope of this example.) Additionally, you can compute 985 // offset outlines (e.g. to stroke the character border inside & outside, 986 // or only outside). For example, to fill outside the character up to 3 SDF 987 // pixels, you would compare against (180-36.0*3)/255 = 72/255. The above 988 // choice of variables maps a range from 5 pixels outside the shape to 989 // 2 pixels inside the shape to 0..255; this is intended primarily for apply 990 // outside effects only (the interior range is needed to allow proper 991 // antialiasing of the font at *smaller* sizes) 992 // 993 // The function computes the SDF analytically at each SDF pixel, not by e.g. 994 // building a higher-res bitmap and approximating it. In theory the quality 995 // should be as high as possible for an SDF of this size & representation, but 996 // unclear if this is true in practice (perhaps building a higher-res bitmap 997 // and computing from that can allow drop-out prevention). 998 // 999 // The algorithm has not been optimized at all, so expect it to be slow 1000 // if computing lots of characters or very large sizes. 1001 1002 1003 1004 ////////////////////////////////////////////////////////////////////////////// 1005 // 1006 // Finding the right font... 1007 // 1008 // You should really just solve this offline, keep your own tables 1009 // of what font is what, and don't try to get it out of the .ttf file. 1010 // That's because getting it out of the .ttf file is really hard, because 1011 // the names in the file can appear in many possible encodings, in many 1012 // possible languages, and e.g. if you need a case-insensitive comparison, 1013 // the details of that depend on the encoding & language in a complex way 1014 // (actually underspecified in truetype, but also gigantic). 1015 // 1016 // But you can use the provided functions in two possible ways: 1017 // stbtt_FindMatchingFont() will use *case-sensitive* comparisons on 1018 // unicode-encoded names to try to find the font you want; 1019 // you can run this before calling stbtt_InitFont() 1020 // 1021 // stbtt_GetFontNameString() lets you get any of the various strings 1022 // from the file yourself and do your own comparisons on them. 1023 // You have to have called stbtt_InitFont() first. 1024 1025 1026 STBTT_DEF int stbtt_FindMatchingFont(const unsigned char *fontdata, const char *name, int flags); 1027 // returns the offset (not index) of the font that matches, or -1 if none 1028 // if you use STBTT_MACSTYLE_DONTCARE, use a font name like "Arial Bold". 1029 // if you use any other flag, use a font name like "Arial"; this checks 1030 // the 'macStyle' header field; i don't know if fonts set this consistently 1031 #define STBTT_MACSTYLE_DONTCARE 0 1032 #define STBTT_MACSTYLE_BOLD 1 1033 #define STBTT_MACSTYLE_ITALIC 2 1034 #define STBTT_MACSTYLE_UNDERSCORE 4 1035 #define STBTT_MACSTYLE_NONE 8 // <= not same as 0, this makes us check the bitfield is 0 1036 1037 STBTT_DEF int stbtt_CompareUTF8toUTF16_bigendian(const char *s1, int len1, const char *s2, int len2); 1038 // returns 1/0 whether the first string interpreted as utf8 is identical to 1039 // the second string interpreted as big-endian utf16... useful for strings from next func 1040 1041 STBTT_DEF const char *stbtt_GetFontNameString(const stbtt_fontinfo *font, int *length, int platformID, int encodingID, int languageID, int nameID); 1042 // returns the string (which may be big-endian double byte, e.g. for unicode) 1043 // and puts the length in bytes in *length. 1044 // 1045 // some of the values for the IDs are below; for more see the truetype spec: 1046 // http://developer.apple.com/textfonts/TTRefMan/RM06/Chap6name.html 1047 // http://www.microsoft.com/typography/otspec/name.htm 1048 1049 enum { // platformID 1050 STBTT_PLATFORM_ID_UNICODE =0, 1051 STBTT_PLATFORM_ID_MAC =1, 1052 STBTT_PLATFORM_ID_ISO =2, 1053 STBTT_PLATFORM_ID_MICROSOFT =3 1054 }; 1055 1056 enum { // encodingID for STBTT_PLATFORM_ID_UNICODE 1057 STBTT_UNICODE_EID_UNICODE_1_0 =0, 1058 STBTT_UNICODE_EID_UNICODE_1_1 =1, 1059 STBTT_UNICODE_EID_ISO_10646 =2, 1060 STBTT_UNICODE_EID_UNICODE_2_0_BMP=3, 1061 STBTT_UNICODE_EID_UNICODE_2_0_FULL=4 1062 }; 1063 1064 enum { // encodingID for STBTT_PLATFORM_ID_MICROSOFT 1065 STBTT_MS_EID_SYMBOL =0, 1066 STBTT_MS_EID_UNICODE_BMP =1, 1067 STBTT_MS_EID_SHIFTJIS =2, 1068 STBTT_MS_EID_UNICODE_FULL =10 1069 }; 1070 1071 enum { // encodingID for STBTT_PLATFORM_ID_MAC; same as Script Manager codes 1072 STBTT_MAC_EID_ROMAN =0, STBTT_MAC_EID_ARABIC =4, 1073 STBTT_MAC_EID_JAPANESE =1, STBTT_MAC_EID_HEBREW =5, 1074 STBTT_MAC_EID_CHINESE_TRAD =2, STBTT_MAC_EID_GREEK =6, 1075 STBTT_MAC_EID_KOREAN =3, STBTT_MAC_EID_RUSSIAN =7 1076 }; 1077 1078 enum { // languageID for STBTT_PLATFORM_ID_MICROSOFT; same as LCID... 1079 // problematic because there are e.g. 16 english LCIDs and 16 arabic LCIDs 1080 STBTT_MS_LANG_ENGLISH =0x0409, STBTT_MS_LANG_ITALIAN =0x0410, 1081 STBTT_MS_LANG_CHINESE =0x0804, STBTT_MS_LANG_JAPANESE =0x0411, 1082 STBTT_MS_LANG_DUTCH =0x0413, STBTT_MS_LANG_KOREAN =0x0412, 1083 STBTT_MS_LANG_FRENCH =0x040c, STBTT_MS_LANG_RUSSIAN =0x0419, 1084 STBTT_MS_LANG_GERMAN =0x0407, STBTT_MS_LANG_SPANISH =0x0409, 1085 STBTT_MS_LANG_HEBREW =0x040d, STBTT_MS_LANG_SWEDISH =0x041D 1086 }; 1087 1088 enum { // languageID for STBTT_PLATFORM_ID_MAC 1089 STBTT_MAC_LANG_ENGLISH =0 , STBTT_MAC_LANG_JAPANESE =11, 1090 STBTT_MAC_LANG_ARABIC =12, STBTT_MAC_LANG_KOREAN =23, 1091 STBTT_MAC_LANG_DUTCH =4 , STBTT_MAC_LANG_RUSSIAN =32, 1092 STBTT_MAC_LANG_FRENCH =1 , STBTT_MAC_LANG_SPANISH =6 , 1093 STBTT_MAC_LANG_GERMAN =2 , STBTT_MAC_LANG_SWEDISH =5 , 1094 STBTT_MAC_LANG_HEBREW =10, STBTT_MAC_LANG_CHINESE_SIMPLIFIED =33, 1095 STBTT_MAC_LANG_ITALIAN =3 , STBTT_MAC_LANG_CHINESE_TRAD =19 1096 }; 1097 1098 #ifdef __cplusplus 1099 } 1100 #endif 1101 1102 #endif // __STB_INCLUDE_STB_TRUETYPE_H__ 1103 1104 /////////////////////////////////////////////////////////////////////////////// 1105 /////////////////////////////////////////////////////////////////////////////// 1106 //// 1107 //// IMPLEMENTATION 1108 //// 1109 //// 1110 1111 #ifdef STB_TRUETYPE_IMPLEMENTATION 1112 1113 #ifndef STBTT_MAX_OVERSAMPLE 1114 #define STBTT_MAX_OVERSAMPLE 8 1115 #endif 1116 1117 #if STBTT_MAX_OVERSAMPLE > 255 1118 #error "STBTT_MAX_OVERSAMPLE cannot be > 255" 1119 #endif 1120 1121 typedef int stbtt__test_oversample_pow2[(STBTT_MAX_OVERSAMPLE & (STBTT_MAX_OVERSAMPLE-1)) == 0 ? 1 : -1]; 1122 1123 #ifndef STBTT_RASTERIZER_VERSION 1124 #define STBTT_RASTERIZER_VERSION 2 1125 #endif 1126 1127 #ifdef _MSC_VER 1128 #define STBTT__NOTUSED(v) (void)(v) 1129 #else 1130 #define STBTT__NOTUSED(v) (void)sizeof(v) 1131 #endif 1132 1133 ////////////////////////////////////////////////////////////////////////// 1134 // 1135 // stbtt__buf helpers to parse data from file 1136 // 1137 1138 static stbtt_uint8 stbtt__buf_get8(stbtt__buf *b) 1139 { 1140 if (b->cursor >= b->size) 1141 return 0; 1142 return b->data[b->cursor++]; 1143 } 1144 1145 static stbtt_uint8 stbtt__buf_peek8(stbtt__buf *b) 1146 { 1147 if (b->cursor >= b->size) 1148 return 0; 1149 return b->data[b->cursor]; 1150 } 1151 1152 static void stbtt__buf_seek(stbtt__buf *b, int o) 1153 { 1154 STBTT_assert(!(o > b->size || o < 0)); 1155 b->cursor = (o > b->size || o < 0) ? b->size : o; 1156 } 1157 1158 static void stbtt__buf_skip(stbtt__buf *b, int o) 1159 { 1160 stbtt__buf_seek(b, b->cursor + o); 1161 } 1162 1163 static stbtt_uint32 stbtt__buf_get(stbtt__buf *b, int n) 1164 { 1165 stbtt_uint32 v = 0; 1166 int i; 1167 STBTT_assert(n >= 1 && n <= 4); 1168 for (i = 0; i < n; i++) 1169 v = (v << 8) | stbtt__buf_get8(b); 1170 return v; 1171 } 1172 1173 static stbtt__buf stbtt__new_buf(const void *p, size_t size) 1174 { 1175 stbtt__buf r; 1176 STBTT_assert(size < 0x40000000); 1177 r.data = (stbtt_uint8*) p; 1178 r.size = (int) size; 1179 r.cursor = 0; 1180 return r; 1181 } 1182 1183 #define stbtt__buf_get16(b) stbtt__buf_get((b), 2) 1184 #define stbtt__buf_get32(b) stbtt__buf_get((b), 4) 1185 1186 static stbtt__buf stbtt__buf_range(const stbtt__buf *b, int o, int s) 1187 { 1188 stbtt__buf r = stbtt__new_buf(NULL, 0); 1189 if (o < 0 || s < 0 || o > b->size || s > b->size - o) return r; 1190 r.data = b->data + o; 1191 r.size = s; 1192 return r; 1193 } 1194 1195 static stbtt__buf stbtt__cff_get_index(stbtt__buf *b) 1196 { 1197 int count, start, offsize; 1198 start = b->cursor; 1199 count = stbtt__buf_get16(b); 1200 if (count) { 1201 offsize = stbtt__buf_get8(b); 1202 STBTT_assert(offsize >= 1 && offsize <= 4); 1203 stbtt__buf_skip(b, offsize * count); 1204 stbtt__buf_skip(b, stbtt__buf_get(b, offsize) - 1); 1205 } 1206 return stbtt__buf_range(b, start, b->cursor - start); 1207 } 1208 1209 static stbtt_uint32 stbtt__cff_int(stbtt__buf *b) 1210 { 1211 int b0 = stbtt__buf_get8(b); 1212 if (b0 >= 32 && b0 <= 246) return b0 - 139; 1213 else if (b0 >= 247 && b0 <= 250) return (b0 - 247)*256 + stbtt__buf_get8(b) + 108; 1214 else if (b0 >= 251 && b0 <= 254) return -(b0 - 251)*256 - stbtt__buf_get8(b) - 108; 1215 else if (b0 == 28) return stbtt__buf_get16(b); 1216 else if (b0 == 29) return stbtt__buf_get32(b); 1217 STBTT_assert(0); 1218 return 0; 1219 } 1220 1221 static void stbtt__cff_skip_operand(stbtt__buf *b) { 1222 int v, b0 = stbtt__buf_peek8(b); 1223 STBTT_assert(b0 >= 28); 1224 if (b0 == 30) { 1225 stbtt__buf_skip(b, 1); 1226 while (b->cursor < b->size) { 1227 v = stbtt__buf_get8(b); 1228 if ((v & 0xF) == 0xF || (v >> 4) == 0xF) 1229 break; 1230 } 1231 } else { 1232 stbtt__cff_int(b); 1233 } 1234 } 1235 1236 static stbtt__buf stbtt__dict_get(stbtt__buf *b, int key) 1237 { 1238 stbtt__buf_seek(b, 0); 1239 while (b->cursor < b->size) { 1240 int start = b->cursor, end, op; 1241 while (stbtt__buf_peek8(b) >= 28) 1242 stbtt__cff_skip_operand(b); 1243 end = b->cursor; 1244 op = stbtt__buf_get8(b); 1245 if (op == 12) op = stbtt__buf_get8(b) | 0x100; 1246 if (op == key) return stbtt__buf_range(b, start, end-start); 1247 } 1248 return stbtt__buf_range(b, 0, 0); 1249 } 1250 1251 static void stbtt__dict_get_ints(stbtt__buf *b, int key, int outcount, stbtt_uint32 *out) 1252 { 1253 int i; 1254 stbtt__buf operands = stbtt__dict_get(b, key); 1255 for (i = 0; i < outcount && operands.cursor < operands.size; i++) 1256 out[i] = stbtt__cff_int(&operands); 1257 } 1258 1259 static int stbtt__cff_index_count(stbtt__buf *b) 1260 { 1261 stbtt__buf_seek(b, 0); 1262 return stbtt__buf_get16(b); 1263 } 1264 1265 static stbtt__buf stbtt__cff_index_get(stbtt__buf b, int i) 1266 { 1267 int count, offsize, start, end; 1268 stbtt__buf_seek(&b, 0); 1269 count = stbtt__buf_get16(&b); 1270 offsize = stbtt__buf_get8(&b); 1271 STBTT_assert(i >= 0 && i < count); 1272 STBTT_assert(offsize >= 1 && offsize <= 4); 1273 stbtt__buf_skip(&b, i*offsize); 1274 start = stbtt__buf_get(&b, offsize); 1275 end = stbtt__buf_get(&b, offsize); 1276 return stbtt__buf_range(&b, 2+(count+1)*offsize+start, end - start); 1277 } 1278 1279 ////////////////////////////////////////////////////////////////////////// 1280 // 1281 // accessors to parse data from file 1282 // 1283 1284 // on platforms that don't allow misaligned reads, if we want to allow 1285 // truetype fonts that aren't padded to alignment, define ALLOW_UNALIGNED_TRUETYPE 1286 1287 #define ttBYTE(p) (* (stbtt_uint8 *) (p)) 1288 #define ttCHAR(p) (* (stbtt_int8 *) (p)) 1289 #define ttFixed(p) ttLONG(p) 1290 1291 static stbtt_uint16 ttUSHORT(stbtt_uint8 *p) { return p[0]*256 + p[1]; } 1292 static stbtt_int16 ttSHORT(stbtt_uint8 *p) { return p[0]*256 + p[1]; } 1293 static stbtt_uint32 ttULONG(stbtt_uint8 *p) { return (p[0]<<24) + (p[1]<<16) + (p[2]<<8) + p[3]; } 1294 static stbtt_int32 ttLONG(stbtt_uint8 *p) { return (p[0]<<24) + (p[1]<<16) + (p[2]<<8) + p[3]; } 1295 1296 #define stbtt_tag4(p,c0,c1,c2,c3) ((p)[0] == (c0) && (p)[1] == (c1) && (p)[2] == (c2) && (p)[3] == (c3)) 1297 #define stbtt_tag(p,str) stbtt_tag4(p,str[0],str[1],str[2],str[3]) 1298 1299 static int stbtt__isfont(stbtt_uint8 *font) 1300 { 1301 // check the version number 1302 if (stbtt_tag4(font, '1',0,0,0)) return 1; // TrueType 1 1303 if (stbtt_tag(font, "typ1")) return 1; // TrueType with type 1 font -- we don't support this! 1304 if (stbtt_tag(font, "OTTO")) return 1; // OpenType with CFF 1305 if (stbtt_tag4(font, 0,1,0,0)) return 1; // OpenType 1.0 1306 if (stbtt_tag(font, "true")) return 1; // Apple specification for TrueType fonts 1307 return 0; 1308 } 1309 1310 // @OPTIMIZE: binary search 1311 static stbtt_uint32 stbtt__find_table(stbtt_uint8 *data, stbtt_uint32 fontstart, const char *tag) 1312 { 1313 stbtt_int32 num_tables = ttUSHORT(data+fontstart+4); 1314 stbtt_uint32 tabledir = fontstart + 12; 1315 stbtt_int32 i; 1316 for (i=0; i < num_tables; ++i) { 1317 stbtt_uint32 loc = tabledir + 16*i; 1318 if (stbtt_tag(data+loc+0, tag)) 1319 return ttULONG(data+loc+8); 1320 } 1321 return 0; 1322 } 1323 1324 static int stbtt_GetFontOffsetForIndex_internal(unsigned char *font_collection, int index) 1325 { 1326 // if it's just a font, there's only one valid index 1327 if (stbtt__isfont(font_collection)) 1328 return index == 0 ? 0 : -1; 1329 1330 // check if it's a TTC 1331 if (stbtt_tag(font_collection, "ttcf")) { 1332 // version 1? 1333 if (ttULONG(font_collection+4) == 0x00010000 || ttULONG(font_collection+4) == 0x00020000) { 1334 stbtt_int32 n = ttLONG(font_collection+8); 1335 if (index >= n) 1336 return -1; 1337 return ttULONG(font_collection+12+index*4); 1338 } 1339 } 1340 return -1; 1341 } 1342 1343 static int stbtt_GetNumberOfFonts_internal(unsigned char *font_collection) 1344 { 1345 // if it's just a font, there's only one valid font 1346 if (stbtt__isfont(font_collection)) 1347 return 1; 1348 1349 // check if it's a TTC 1350 if (stbtt_tag(font_collection, "ttcf")) { 1351 // version 1? 1352 if (ttULONG(font_collection+4) == 0x00010000 || ttULONG(font_collection+4) == 0x00020000) { 1353 return ttLONG(font_collection+8); 1354 } 1355 } 1356 return 0; 1357 } 1358 1359 static stbtt__buf stbtt__get_subrs(stbtt__buf cff, stbtt__buf fontdict) 1360 { 1361 stbtt_uint32 subrsoff = 0, private_loc[2] = { 0, 0 }; 1362 stbtt__buf pdict; 1363 stbtt__dict_get_ints(&fontdict, 18, 2, private_loc); 1364 if (!private_loc[1] || !private_loc[0]) return stbtt__new_buf(NULL, 0); 1365 pdict = stbtt__buf_range(&cff, private_loc[1], private_loc[0]); 1366 stbtt__dict_get_ints(&pdict, 19, 1, &subrsoff); 1367 if (!subrsoff) return stbtt__new_buf(NULL, 0); 1368 stbtt__buf_seek(&cff, private_loc[1]+subrsoff); 1369 return stbtt__cff_get_index(&cff); 1370 } 1371 1372 // since most people won't use this, find this table the first time it's needed 1373 static int stbtt__get_svg(stbtt_fontinfo *info) 1374 { 1375 stbtt_uint32 t; 1376 if (info->svg < 0) { 1377 t = stbtt__find_table(info->data, info->fontstart, "SVG "); 1378 if (t) { 1379 stbtt_uint32 offset = ttULONG(info->data + t + 2); 1380 info->svg = t + offset; 1381 } else { 1382 info->svg = 0; 1383 } 1384 } 1385 return info->svg; 1386 } 1387 1388 static int stbtt_InitFont_internal(stbtt_fontinfo *info, unsigned char *data, int fontstart) 1389 { 1390 stbtt_uint32 cmap, t; 1391 stbtt_int32 i,numTables; 1392 1393 info->data = data; 1394 info->fontstart = fontstart; 1395 info->cff = stbtt__new_buf(NULL, 0); 1396 1397 cmap = stbtt__find_table(data, fontstart, "cmap"); // required 1398 info->loca = stbtt__find_table(data, fontstart, "loca"); // required 1399 info->head = stbtt__find_table(data, fontstart, "head"); // required 1400 info->glyf = stbtt__find_table(data, fontstart, "glyf"); // required 1401 info->hhea = stbtt__find_table(data, fontstart, "hhea"); // required 1402 info->hmtx = stbtt__find_table(data, fontstart, "hmtx"); // required 1403 info->kern = stbtt__find_table(data, fontstart, "kern"); // not required 1404 info->gpos = stbtt__find_table(data, fontstart, "GPOS"); // not required 1405 1406 if (!cmap || !info->head || !info->hhea || !info->hmtx) 1407 return 0; 1408 if (info->glyf) { 1409 // required for truetype 1410 if (!info->loca) return 0; 1411 } else { 1412 // initialization for CFF / Type2 fonts (OTF) 1413 stbtt__buf b, topdict, topdictidx; 1414 stbtt_uint32 cstype = 2, charstrings = 0, fdarrayoff = 0, fdselectoff = 0; 1415 stbtt_uint32 cff; 1416 1417 cff = stbtt__find_table(data, fontstart, "CFF "); 1418 if (!cff) return 0; 1419 1420 info->fontdicts = stbtt__new_buf(NULL, 0); 1421 info->fdselect = stbtt__new_buf(NULL, 0); 1422 1423 // @TODO this should use size from table (not 512MB) 1424 info->cff = stbtt__new_buf(data+cff, 512*1024*1024); 1425 b = info->cff; 1426 1427 // read the header 1428 stbtt__buf_skip(&b, 2); 1429 stbtt__buf_seek(&b, stbtt__buf_get8(&b)); // hdrsize 1430 1431 // @TODO the name INDEX could list multiple fonts, 1432 // but we just use the first one. 1433 stbtt__cff_get_index(&b); // name INDEX 1434 topdictidx = stbtt__cff_get_index(&b); 1435 topdict = stbtt__cff_index_get(topdictidx, 0); 1436 stbtt__cff_get_index(&b); // string INDEX 1437 info->gsubrs = stbtt__cff_get_index(&b); 1438 1439 stbtt__dict_get_ints(&topdict, 17, 1, &charstrings); 1440 stbtt__dict_get_ints(&topdict, 0x100 | 6, 1, &cstype); 1441 stbtt__dict_get_ints(&topdict, 0x100 | 36, 1, &fdarrayoff); 1442 stbtt__dict_get_ints(&topdict, 0x100 | 37, 1, &fdselectoff); 1443 info->subrs = stbtt__get_subrs(b, topdict); 1444 1445 // we only support Type 2 charstrings 1446 if (cstype != 2) return 0; 1447 if (charstrings == 0) return 0; 1448 1449 if (fdarrayoff) { 1450 // looks like a CID font 1451 if (!fdselectoff) return 0; 1452 stbtt__buf_seek(&b, fdarrayoff); 1453 info->fontdicts = stbtt__cff_get_index(&b); 1454 info->fdselect = stbtt__buf_range(&b, fdselectoff, b.size-fdselectoff); 1455 } 1456 1457 stbtt__buf_seek(&b, charstrings); 1458 info->charstrings = stbtt__cff_get_index(&b); 1459 } 1460 1461 t = stbtt__find_table(data, fontstart, "maxp"); 1462 if (t) 1463 info->numGlyphs = ttUSHORT(data+t+4); 1464 else 1465 info->numGlyphs = 0xffff; 1466 1467 info->svg = -1; 1468 1469 // find a cmap encoding table we understand *now* to avoid searching 1470 // later. (todo: could make this installable) 1471 // the same regardless of glyph. 1472 numTables = ttUSHORT(data + cmap + 2); 1473 info->index_map = 0; 1474 for (i=0; i < numTables; ++i) { 1475 stbtt_uint32 encoding_record = cmap + 4 + 8 * i; 1476 // find an encoding we understand: 1477 switch(ttUSHORT(data+encoding_record)) { 1478 case STBTT_PLATFORM_ID_MICROSOFT: 1479 switch (ttUSHORT(data+encoding_record+2)) { 1480 case STBTT_MS_EID_UNICODE_BMP: 1481 case STBTT_MS_EID_UNICODE_FULL: 1482 // MS/Unicode 1483 info->index_map = cmap + ttULONG(data+encoding_record+4); 1484 break; 1485 } 1486 break; 1487 case STBTT_PLATFORM_ID_UNICODE: 1488 // Mac/iOS has these 1489 // all the encodingIDs are unicode, so we don't bother to check it 1490 info->index_map = cmap + ttULONG(data+encoding_record+4); 1491 break; 1492 } 1493 } 1494 if (info->index_map == 0) 1495 return 0; 1496 1497 info->indexToLocFormat = ttUSHORT(data+info->head + 50); 1498 return 1; 1499 } 1500 1501 STBTT_DEF int stbtt_FindGlyphIndex(const stbtt_fontinfo *info, int unicode_codepoint) 1502 { 1503 stbtt_uint8 *data = info->data; 1504 stbtt_uint32 index_map = info->index_map; 1505 1506 stbtt_uint16 format = ttUSHORT(data + index_map + 0); 1507 if (format == 0) { // apple byte encoding 1508 stbtt_int32 bytes = ttUSHORT(data + index_map + 2); 1509 if (unicode_codepoint < bytes-6) 1510 return ttBYTE(data + index_map + 6 + unicode_codepoint); 1511 return 0; 1512 } else if (format == 6) { 1513 stbtt_uint32 first = ttUSHORT(data + index_map + 6); 1514 stbtt_uint32 count = ttUSHORT(data + index_map + 8); 1515 if ((stbtt_uint32) unicode_codepoint >= first && (stbtt_uint32) unicode_codepoint < first+count) 1516 return ttUSHORT(data + index_map + 10 + (unicode_codepoint - first)*2); 1517 return 0; 1518 } else if (format == 2) { 1519 STBTT_assert(0); // @TODO: high-byte mapping for japanese/chinese/korean 1520 return 0; 1521 } else if (format == 4) { // standard mapping for windows fonts: binary search collection of ranges 1522 stbtt_uint16 segcount = ttUSHORT(data+index_map+6) >> 1; 1523 stbtt_uint16 searchRange = ttUSHORT(data+index_map+8) >> 1; 1524 stbtt_uint16 entrySelector = ttUSHORT(data+index_map+10); 1525 stbtt_uint16 rangeShift = ttUSHORT(data+index_map+12) >> 1; 1526 1527 // do a binary search of the segments 1528 stbtt_uint32 endCount = index_map + 14; 1529 stbtt_uint32 search = endCount; 1530 1531 if (unicode_codepoint > 0xffff) 1532 return 0; 1533 1534 // they lie from endCount .. endCount + segCount 1535 // but searchRange is the nearest power of two, so... 1536 if (unicode_codepoint >= ttUSHORT(data + search + rangeShift*2)) 1537 search += rangeShift*2; 1538 1539 // now decrement to bias correctly to find smallest 1540 search -= 2; 1541 while (entrySelector) { 1542 stbtt_uint16 end; 1543 searchRange >>= 1; 1544 end = ttUSHORT(data + search + searchRange*2); 1545 if (unicode_codepoint > end) 1546 search += searchRange*2; 1547 --entrySelector; 1548 } 1549 search += 2; 1550 1551 { 1552 stbtt_uint16 offset, start, last; 1553 stbtt_uint16 item = (stbtt_uint16) ((search - endCount) >> 1); 1554 1555 start = ttUSHORT(data + index_map + 14 + segcount*2 + 2 + 2*item); 1556 last = ttUSHORT(data + endCount + 2*item); 1557 if (unicode_codepoint < start || unicode_codepoint > last) 1558 return 0; 1559 1560 offset = ttUSHORT(data + index_map + 14 + segcount*6 + 2 + 2*item); 1561 if (offset == 0) 1562 return (stbtt_uint16) (unicode_codepoint + ttSHORT(data + index_map + 14 + segcount*4 + 2 + 2*item)); 1563 1564 return ttUSHORT(data + offset + (unicode_codepoint-start)*2 + index_map + 14 + segcount*6 + 2 + 2*item); 1565 } 1566 } else if (format == 12 || format == 13) { 1567 stbtt_uint32 ngroups = ttULONG(data+index_map+12); 1568 stbtt_int32 low,high; 1569 low = 0; high = (stbtt_int32)ngroups; 1570 // Binary search the right group. 1571 while (low < high) { 1572 stbtt_int32 mid = low + ((high-low) >> 1); // rounds down, so low <= mid < high 1573 stbtt_uint32 start_char = ttULONG(data+index_map+16+mid*12); 1574 stbtt_uint32 end_char = ttULONG(data+index_map+16+mid*12+4); 1575 if ((stbtt_uint32) unicode_codepoint < start_char) 1576 high = mid; 1577 else if ((stbtt_uint32) unicode_codepoint > end_char) 1578 low = mid+1; 1579 else { 1580 stbtt_uint32 start_glyph = ttULONG(data+index_map+16+mid*12+8); 1581 if (format == 12) 1582 return start_glyph + unicode_codepoint-start_char; 1583 else // format == 13 1584 return start_glyph; 1585 } 1586 } 1587 return 0; // not found 1588 } 1589 // @TODO 1590 STBTT_assert(0); 1591 return 0; 1592 } 1593 1594 STBTT_DEF int stbtt_GetCodepointShape(const stbtt_fontinfo *info, int unicode_codepoint, stbtt_vertex **vertices) 1595 { 1596 return stbtt_GetGlyphShape(info, stbtt_FindGlyphIndex(info, unicode_codepoint), vertices); 1597 } 1598 1599 static void stbtt_setvertex(stbtt_vertex *v, stbtt_uint8 type, stbtt_int32 x, stbtt_int32 y, stbtt_int32 cx, stbtt_int32 cy) 1600 { 1601 v->type = type; 1602 v->x = (stbtt_int16) x; 1603 v->y = (stbtt_int16) y; 1604 v->cx = (stbtt_int16) cx; 1605 v->cy = (stbtt_int16) cy; 1606 } 1607 1608 static int stbtt__GetGlyfOffset(const stbtt_fontinfo *info, int glyph_index) 1609 { 1610 int g1,g2; 1611 1612 STBTT_assert(!info->cff.size); 1613 1614 if (glyph_index >= info->numGlyphs) return -1; // glyph index out of range 1615 if (info->indexToLocFormat >= 2) return -1; // unknown index->glyph map format 1616 1617 if (info->indexToLocFormat == 0) { 1618 g1 = info->glyf + ttUSHORT(info->data + info->loca + glyph_index * 2) * 2; 1619 g2 = info->glyf + ttUSHORT(info->data + info->loca + glyph_index * 2 + 2) * 2; 1620 } else { 1621 g1 = info->glyf + ttULONG (info->data + info->loca + glyph_index * 4); 1622 g2 = info->glyf + ttULONG (info->data + info->loca + glyph_index * 4 + 4); 1623 } 1624 1625 return g1==g2 ? -1 : g1; // if length is 0, return -1 1626 } 1627 1628 static int stbtt__GetGlyphInfoT2(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1); 1629 1630 STBTT_DEF int stbtt_GetGlyphBox(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1) 1631 { 1632 if (info->cff.size) { 1633 stbtt__GetGlyphInfoT2(info, glyph_index, x0, y0, x1, y1); 1634 } else { 1635 int g = stbtt__GetGlyfOffset(info, glyph_index); 1636 if (g < 0) return 0; 1637 1638 if (x0) *x0 = ttSHORT(info->data + g + 2); 1639 if (y0) *y0 = ttSHORT(info->data + g + 4); 1640 if (x1) *x1 = ttSHORT(info->data + g + 6); 1641 if (y1) *y1 = ttSHORT(info->data + g + 8); 1642 } 1643 return 1; 1644 } 1645 1646 STBTT_DEF int stbtt_GetCodepointBox(const stbtt_fontinfo *info, int codepoint, int *x0, int *y0, int *x1, int *y1) 1647 { 1648 return stbtt_GetGlyphBox(info, stbtt_FindGlyphIndex(info,codepoint), x0,y0,x1,y1); 1649 } 1650 1651 STBTT_DEF int stbtt_IsGlyphEmpty(const stbtt_fontinfo *info, int glyph_index) 1652 { 1653 stbtt_int16 numberOfContours; 1654 int g; 1655 if (info->cff.size) 1656 return stbtt__GetGlyphInfoT2(info, glyph_index, NULL, NULL, NULL, NULL) == 0; 1657 g = stbtt__GetGlyfOffset(info, glyph_index); 1658 if (g < 0) return 1; 1659 numberOfContours = ttSHORT(info->data + g); 1660 return numberOfContours == 0; 1661 } 1662 1663 static int stbtt__close_shape(stbtt_vertex *vertices, int num_vertices, int was_off, int start_off, 1664 stbtt_int32 sx, stbtt_int32 sy, stbtt_int32 scx, stbtt_int32 scy, stbtt_int32 cx, stbtt_int32 cy) 1665 { 1666 if (start_off) { 1667 if (was_off) 1668 stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, (cx+scx)>>1, (cy+scy)>>1, cx,cy); 1669 stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, sx,sy,scx,scy); 1670 } else { 1671 if (was_off) 1672 stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve,sx,sy,cx,cy); 1673 else 1674 stbtt_setvertex(&vertices[num_vertices++], STBTT_vline,sx,sy,0,0); 1675 } 1676 return num_vertices; 1677 } 1678 1679 static int stbtt__GetGlyphShapeTT(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **pvertices) 1680 { 1681 stbtt_int16 numberOfContours; 1682 stbtt_uint8 *endPtsOfContours; 1683 stbtt_uint8 *data = info->data; 1684 stbtt_vertex *vertices=0; 1685 int num_vertices=0; 1686 int g = stbtt__GetGlyfOffset(info, glyph_index); 1687 1688 *pvertices = NULL; 1689 1690 if (g < 0) return 0; 1691 1692 numberOfContours = ttSHORT(data + g); 1693 1694 if (numberOfContours > 0) { 1695 stbtt_uint8 flags=0,flagcount; 1696 stbtt_int32 ins, i,j=0,m,n, next_move, was_off=0, off, start_off=0; 1697 stbtt_int32 x,y,cx,cy,sx,sy, scx,scy; 1698 stbtt_uint8 *points; 1699 endPtsOfContours = (data + g + 10); 1700 ins = ttUSHORT(data + g + 10 + numberOfContours * 2); 1701 points = data + g + 10 + numberOfContours * 2 + 2 + ins; 1702 1703 n = 1+ttUSHORT(endPtsOfContours + numberOfContours*2-2); 1704 1705 m = n + 2*numberOfContours; // a loose bound on how many vertices we might need 1706 vertices = (stbtt_vertex *) STBTT_malloc(m * sizeof(vertices[0]), info->userdata); 1707 if (vertices == 0) 1708 return 0; 1709 1710 next_move = 0; 1711 flagcount=0; 1712 1713 // in first pass, we load uninterpreted data into the allocated array 1714 // above, shifted to the end of the array so we won't overwrite it when 1715 // we create our final data starting from the front 1716 1717 off = m - n; // starting offset for uninterpreted data, regardless of how m ends up being calculated 1718 1719 // first load flags 1720 1721 for (i=0; i < n; ++i) { 1722 if (flagcount == 0) { 1723 flags = *points++; 1724 if (flags & 8) 1725 flagcount = *points++; 1726 } else 1727 --flagcount; 1728 vertices[off+i].type = flags; 1729 } 1730 1731 // now load x coordinates 1732 x=0; 1733 for (i=0; i < n; ++i) { 1734 flags = vertices[off+i].type; 1735 if (flags & 2) { 1736 stbtt_int16 dx = *points++; 1737 x += (flags & 16) ? dx : -dx; // ??? 1738 } else { 1739 if (!(flags & 16)) { 1740 x = x + (stbtt_int16) (points[0]*256 + points[1]); 1741 points += 2; 1742 } 1743 } 1744 vertices[off+i].x = (stbtt_int16) x; 1745 } 1746 1747 // now load y coordinates 1748 y=0; 1749 for (i=0; i < n; ++i) { 1750 flags = vertices[off+i].type; 1751 if (flags & 4) { 1752 stbtt_int16 dy = *points++; 1753 y += (flags & 32) ? dy : -dy; // ??? 1754 } else { 1755 if (!(flags & 32)) { 1756 y = y + (stbtt_int16) (points[0]*256 + points[1]); 1757 points += 2; 1758 } 1759 } 1760 vertices[off+i].y = (stbtt_int16) y; 1761 } 1762 1763 // now convert them to our format 1764 num_vertices=0; 1765 sx = sy = cx = cy = scx = scy = 0; 1766 for (i=0; i < n; ++i) { 1767 flags = vertices[off+i].type; 1768 x = (stbtt_int16) vertices[off+i].x; 1769 y = (stbtt_int16) vertices[off+i].y; 1770 1771 if (next_move == i) { 1772 if (i != 0) 1773 num_vertices = stbtt__close_shape(vertices, num_vertices, was_off, start_off, sx,sy,scx,scy,cx,cy); 1774 1775 // now start the new one 1776 start_off = !(flags & 1); 1777 if (start_off) { 1778 // if we start off with an off-curve point, then when we need to find a point on the curve 1779 // where we can start, and we need to save some state for when we wraparound. 1780 scx = x; 1781 scy = y; 1782 if (!(vertices[off+i+1].type & 1)) { 1783 // next point is also a curve point, so interpolate an on-point curve 1784 sx = (x + (stbtt_int32) vertices[off+i+1].x) >> 1; 1785 sy = (y + (stbtt_int32) vertices[off+i+1].y) >> 1; 1786 } else { 1787 // otherwise just use the next point as our start point 1788 sx = (stbtt_int32) vertices[off+i+1].x; 1789 sy = (stbtt_int32) vertices[off+i+1].y; 1790 ++i; // we're using point i+1 as the starting point, so skip it 1791 } 1792 } else { 1793 sx = x; 1794 sy = y; 1795 } 1796 stbtt_setvertex(&vertices[num_vertices++], STBTT_vmove,sx,sy,0,0); 1797 was_off = 0; 1798 next_move = 1 + ttUSHORT(endPtsOfContours+j*2); 1799 ++j; 1800 } else { 1801 if (!(flags & 1)) { // if it's a curve 1802 if (was_off) // two off-curve control points in a row means interpolate an on-curve midpoint 1803 stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, (cx+x)>>1, (cy+y)>>1, cx, cy); 1804 cx = x; 1805 cy = y; 1806 was_off = 1; 1807 } else { 1808 if (was_off) 1809 stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, x,y, cx, cy); 1810 else 1811 stbtt_setvertex(&vertices[num_vertices++], STBTT_vline, x,y,0,0); 1812 was_off = 0; 1813 } 1814 } 1815 } 1816 num_vertices = stbtt__close_shape(vertices, num_vertices, was_off, start_off, sx,sy,scx,scy,cx,cy); 1817 } else if (numberOfContours < 0) { 1818 // Compound shapes. 1819 int more = 1; 1820 stbtt_uint8 *comp = data + g + 10; 1821 num_vertices = 0; 1822 vertices = 0; 1823 while (more) { 1824 stbtt_uint16 flags, gidx; 1825 int comp_num_verts = 0, i; 1826 stbtt_vertex *comp_verts = 0, *tmp = 0; 1827 float mtx[6] = {1,0,0,1,0,0}, m, n; 1828 1829 flags = ttSHORT(comp); comp+=2; 1830 gidx = ttSHORT(comp); comp+=2; 1831 1832 if (flags & 2) { // XY values 1833 if (flags & 1) { // shorts 1834 mtx[4] = ttSHORT(comp); comp+=2; 1835 mtx[5] = ttSHORT(comp); comp+=2; 1836 } else { 1837 mtx[4] = ttCHAR(comp); comp+=1; 1838 mtx[5] = ttCHAR(comp); comp+=1; 1839 } 1840 } 1841 else { 1842 // @TODO handle matching point 1843 STBTT_assert(0); 1844 } 1845 if (flags & (1<<3)) { // WE_HAVE_A_SCALE 1846 mtx[0] = mtx[3] = ttSHORT(comp)/16384.0f; comp+=2; 1847 mtx[1] = mtx[2] = 0; 1848 } else if (flags & (1<<6)) { // WE_HAVE_AN_X_AND_YSCALE 1849 mtx[0] = ttSHORT(comp)/16384.0f; comp+=2; 1850 mtx[1] = mtx[2] = 0; 1851 mtx[3] = ttSHORT(comp)/16384.0f; comp+=2; 1852 } else if (flags & (1<<7)) { // WE_HAVE_A_TWO_BY_TWO 1853 mtx[0] = ttSHORT(comp)/16384.0f; comp+=2; 1854 mtx[1] = ttSHORT(comp)/16384.0f; comp+=2; 1855 mtx[2] = ttSHORT(comp)/16384.0f; comp+=2; 1856 mtx[3] = ttSHORT(comp)/16384.0f; comp+=2; 1857 } 1858 1859 // Find transformation scales. 1860 m = (float) STBTT_sqrt(mtx[0]*mtx[0] + mtx[1]*mtx[1]); 1861 n = (float) STBTT_sqrt(mtx[2]*mtx[2] + mtx[3]*mtx[3]); 1862 1863 // Get indexed glyph. 1864 comp_num_verts = stbtt_GetGlyphShape(info, gidx, &comp_verts); 1865 if (comp_num_verts > 0) { 1866 // Transform vertices. 1867 for (i = 0; i < comp_num_verts; ++i) { 1868 stbtt_vertex* v = &comp_verts[i]; 1869 stbtt_vertex_type x,y; 1870 x=v->x; y=v->y; 1871 v->x = (stbtt_vertex_type)(m * (mtx[0]*x + mtx[2]*y + mtx[4])); 1872 v->y = (stbtt_vertex_type)(n * (mtx[1]*x + mtx[3]*y + mtx[5])); 1873 x=v->cx; y=v->cy; 1874 v->cx = (stbtt_vertex_type)(m * (mtx[0]*x + mtx[2]*y + mtx[4])); 1875 v->cy = (stbtt_vertex_type)(n * (mtx[1]*x + mtx[3]*y + mtx[5])); 1876 } 1877 // Append vertices. 1878 tmp = (stbtt_vertex*)STBTT_malloc((num_vertices+comp_num_verts)*sizeof(stbtt_vertex), info->userdata); 1879 if (!tmp) { 1880 if (vertices) STBTT_free(vertices, info->userdata); 1881 if (comp_verts) STBTT_free(comp_verts, info->userdata); 1882 return 0; 1883 } 1884 if (num_vertices > 0 && vertices) STBTT_memcpy(tmp, vertices, num_vertices*sizeof(stbtt_vertex)); 1885 STBTT_memcpy(tmp+num_vertices, comp_verts, comp_num_verts*sizeof(stbtt_vertex)); 1886 if (vertices) STBTT_free(vertices, info->userdata); 1887 vertices = tmp; 1888 STBTT_free(comp_verts, info->userdata); 1889 num_vertices += comp_num_verts; 1890 } 1891 // More components ? 1892 more = flags & (1<<5); 1893 } 1894 } else { 1895 // numberOfCounters == 0, do nothing 1896 } 1897 1898 *pvertices = vertices; 1899 return num_vertices; 1900 } 1901 1902 typedef struct 1903 { 1904 int bounds; 1905 int started; 1906 float first_x, first_y; 1907 float x, y; 1908 stbtt_int32 min_x, max_x, min_y, max_y; 1909 1910 stbtt_vertex *pvertices; 1911 int num_vertices; 1912 } stbtt__csctx; 1913 1914 #define STBTT__CSCTX_INIT(bounds) {bounds,0, 0,0, 0,0, 0,0,0,0, NULL, 0} 1915 1916 static void stbtt__track_vertex(stbtt__csctx *c, stbtt_int32 x, stbtt_int32 y) 1917 { 1918 if (x > c->max_x || !c->started) c->max_x = x; 1919 if (y > c->max_y || !c->started) c->max_y = y; 1920 if (x < c->min_x || !c->started) c->min_x = x; 1921 if (y < c->min_y || !c->started) c->min_y = y; 1922 c->started = 1; 1923 } 1924 1925 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) 1926 { 1927 if (c->bounds) { 1928 stbtt__track_vertex(c, x, y); 1929 if (type == STBTT_vcubic) { 1930 stbtt__track_vertex(c, cx, cy); 1931 stbtt__track_vertex(c, cx1, cy1); 1932 } 1933 } else { 1934 stbtt_setvertex(&c->pvertices[c->num_vertices], type, x, y, cx, cy); 1935 c->pvertices[c->num_vertices].cx1 = (stbtt_int16) cx1; 1936 c->pvertices[c->num_vertices].cy1 = (stbtt_int16) cy1; 1937 } 1938 c->num_vertices++; 1939 } 1940 1941 static void stbtt__csctx_close_shape(stbtt__csctx *ctx) 1942 { 1943 if (ctx->first_x != ctx->x || ctx->first_y != ctx->y) 1944 stbtt__csctx_v(ctx, STBTT_vline, (int)ctx->first_x, (int)ctx->first_y, 0, 0, 0, 0); 1945 } 1946 1947 static void stbtt__csctx_rmove_to(stbtt__csctx *ctx, float dx, float dy) 1948 { 1949 stbtt__csctx_close_shape(ctx); 1950 ctx->first_x = ctx->x = ctx->x + dx; 1951 ctx->first_y = ctx->y = ctx->y + dy; 1952 stbtt__csctx_v(ctx, STBTT_vmove, (int)ctx->x, (int)ctx->y, 0, 0, 0, 0); 1953 } 1954 1955 static void stbtt__csctx_rline_to(stbtt__csctx *ctx, float dx, float dy) 1956 { 1957 ctx->x += dx; 1958 ctx->y += dy; 1959 stbtt__csctx_v(ctx, STBTT_vline, (int)ctx->x, (int)ctx->y, 0, 0, 0, 0); 1960 } 1961 1962 static void stbtt__csctx_rccurve_to(stbtt__csctx *ctx, float dx1, float dy1, float dx2, float dy2, float dx3, float dy3) 1963 { 1964 float cx1 = ctx->x + dx1; 1965 float cy1 = ctx->y + dy1; 1966 float cx2 = cx1 + dx2; 1967 float cy2 = cy1 + dy2; 1968 ctx->x = cx2 + dx3; 1969 ctx->y = cy2 + dy3; 1970 stbtt__csctx_v(ctx, STBTT_vcubic, (int)ctx->x, (int)ctx->y, (int)cx1, (int)cy1, (int)cx2, (int)cy2); 1971 } 1972 1973 static stbtt__buf stbtt__get_subr(stbtt__buf idx, int n) 1974 { 1975 int count = stbtt__cff_index_count(&idx); 1976 int bias = 107; 1977 if (count >= 33900) 1978 bias = 32768; 1979 else if (count >= 1240) 1980 bias = 1131; 1981 n += bias; 1982 if (n < 0 || n >= count) 1983 return stbtt__new_buf(NULL, 0); 1984 return stbtt__cff_index_get(idx, n); 1985 } 1986 1987 static stbtt__buf stbtt__cid_get_glyph_subrs(const stbtt_fontinfo *info, int glyph_index) 1988 { 1989 stbtt__buf fdselect = info->fdselect; 1990 int nranges, start, end, v, fmt, fdselector = -1, i; 1991 1992 stbtt__buf_seek(&fdselect, 0); 1993 fmt = stbtt__buf_get8(&fdselect); 1994 if (fmt == 0) { 1995 // untested 1996 stbtt__buf_skip(&fdselect, glyph_index); 1997 fdselector = stbtt__buf_get8(&fdselect); 1998 } else if (fmt == 3) { 1999 nranges = stbtt__buf_get16(&fdselect); 2000 start = stbtt__buf_get16(&fdselect); 2001 for (i = 0; i < nranges; i++) { 2002 v = stbtt__buf_get8(&fdselect); 2003 end = stbtt__buf_get16(&fdselect); 2004 if (glyph_index >= start && glyph_index < end) { 2005 fdselector = v; 2006 break; 2007 } 2008 start = end; 2009 } 2010 } 2011 if (fdselector == -1) return stbtt__new_buf(NULL, 0); // [DEAR IMGUI] fixed, see #6007 and nothings/stb#1422 2012 return stbtt__get_subrs(info->cff, stbtt__cff_index_get(info->fontdicts, fdselector)); 2013 } 2014 2015 static int stbtt__run_charstring(const stbtt_fontinfo *info, int glyph_index, stbtt__csctx *c) 2016 { 2017 int in_header = 1, maskbits = 0, subr_stack_height = 0, sp = 0, v, i, b0; 2018 int has_subrs = 0, clear_stack; 2019 float s[48]; 2020 stbtt__buf subr_stack[10], subrs = info->subrs, b; 2021 float f; 2022 2023 #define STBTT__CSERR(s) (0) 2024 2025 // this currently ignores the initial width value, which isn't needed if we have hmtx 2026 b = stbtt__cff_index_get(info->charstrings, glyph_index); 2027 while (b.cursor < b.size) { 2028 i = 0; 2029 clear_stack = 1; 2030 b0 = stbtt__buf_get8(&b); 2031 switch (b0) { 2032 // @TODO implement hinting 2033 case 0x13: // hintmask 2034 case 0x14: // cntrmask 2035 if (in_header) 2036 maskbits += (sp / 2); // implicit "vstem" 2037 in_header = 0; 2038 stbtt__buf_skip(&b, (maskbits + 7) / 8); 2039 break; 2040 2041 case 0x01: // hstem 2042 case 0x03: // vstem 2043 case 0x12: // hstemhm 2044 case 0x17: // vstemhm 2045 maskbits += (sp / 2); 2046 break; 2047 2048 case 0x15: // rmoveto 2049 in_header = 0; 2050 if (sp < 2) return STBTT__CSERR("rmoveto stack"); 2051 stbtt__csctx_rmove_to(c, s[sp-2], s[sp-1]); 2052 break; 2053 case 0x04: // vmoveto 2054 in_header = 0; 2055 if (sp < 1) return STBTT__CSERR("vmoveto stack"); 2056 stbtt__csctx_rmove_to(c, 0, s[sp-1]); 2057 break; 2058 case 0x16: // hmoveto 2059 in_header = 0; 2060 if (sp < 1) return STBTT__CSERR("hmoveto stack"); 2061 stbtt__csctx_rmove_to(c, s[sp-1], 0); 2062 break; 2063 2064 case 0x05: // rlineto 2065 if (sp < 2) return STBTT__CSERR("rlineto stack"); 2066 for (; i + 1 < sp; i += 2) 2067 stbtt__csctx_rline_to(c, s[i], s[i+1]); 2068 break; 2069 2070 // hlineto/vlineto and vhcurveto/hvcurveto alternate horizontal and vertical 2071 // starting from a different place. 2072 2073 case 0x07: // vlineto 2074 if (sp < 1) return STBTT__CSERR("vlineto stack"); 2075 goto vlineto; 2076 case 0x06: // hlineto 2077 if (sp < 1) return STBTT__CSERR("hlineto stack"); 2078 for (;;) { 2079 if (i >= sp) break; 2080 stbtt__csctx_rline_to(c, s[i], 0); 2081 i++; 2082 vlineto: 2083 if (i >= sp) break; 2084 stbtt__csctx_rline_to(c, 0, s[i]); 2085 i++; 2086 } 2087 break; 2088 2089 case 0x1F: // hvcurveto 2090 if (sp < 4) return STBTT__CSERR("hvcurveto stack"); 2091 goto hvcurveto; 2092 case 0x1E: // vhcurveto 2093 if (sp < 4) return STBTT__CSERR("vhcurveto stack"); 2094 for (;;) { 2095 if (i + 3 >= sp) break; 2096 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); 2097 i += 4; 2098 hvcurveto: 2099 if (i + 3 >= sp) break; 2100 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]); 2101 i += 4; 2102 } 2103 break; 2104 2105 case 0x08: // rrcurveto 2106 if (sp < 6) return STBTT__CSERR("rcurveline stack"); 2107 for (; i + 5 < sp; i += 6) 2108 stbtt__csctx_rccurve_to(c, s[i], s[i+1], s[i+2], s[i+3], s[i+4], s[i+5]); 2109 break; 2110 2111 case 0x18: // rcurveline 2112 if (sp < 8) return STBTT__CSERR("rcurveline stack"); 2113 for (; i + 5 < sp - 2; i += 6) 2114 stbtt__csctx_rccurve_to(c, s[i], s[i+1], s[i+2], s[i+3], s[i+4], s[i+5]); 2115 if (i + 1 >= sp) return STBTT__CSERR("rcurveline stack"); 2116 stbtt__csctx_rline_to(c, s[i], s[i+1]); 2117 break; 2118 2119 case 0x19: // rlinecurve 2120 if (sp < 8) return STBTT__CSERR("rlinecurve stack"); 2121 for (; i + 1 < sp - 6; i += 2) 2122 stbtt__csctx_rline_to(c, s[i], s[i+1]); 2123 if (i + 5 >= sp) return STBTT__CSERR("rlinecurve stack"); 2124 stbtt__csctx_rccurve_to(c, s[i], s[i+1], s[i+2], s[i+3], s[i+4], s[i+5]); 2125 break; 2126 2127 case 0x1A: // vvcurveto 2128 case 0x1B: // hhcurveto 2129 if (sp < 4) return STBTT__CSERR("(vv|hh)curveto stack"); 2130 f = 0.0; 2131 if (sp & 1) { f = s[i]; i++; } 2132 for (; i + 3 < sp; i += 4) { 2133 if (b0 == 0x1B) 2134 stbtt__csctx_rccurve_to(c, s[i], f, s[i+1], s[i+2], s[i+3], 0.0); 2135 else 2136 stbtt__csctx_rccurve_to(c, f, s[i], s[i+1], s[i+2], 0.0, s[i+3]); 2137 f = 0.0; 2138 } 2139 break; 2140 2141 case 0x0A: // callsubr 2142 if (!has_subrs) { 2143 if (info->fdselect.size) 2144 subrs = stbtt__cid_get_glyph_subrs(info, glyph_index); 2145 has_subrs = 1; 2146 } 2147 // FALLTHROUGH 2148 case 0x1D: // callgsubr 2149 if (sp < 1) return STBTT__CSERR("call(g|)subr stack"); 2150 v = (int) s[--sp]; 2151 if (subr_stack_height >= 10) return STBTT__CSERR("recursion limit"); 2152 subr_stack[subr_stack_height++] = b; 2153 b = stbtt__get_subr(b0 == 0x0A ? subrs : info->gsubrs, v); 2154 if (b.size == 0) return STBTT__CSERR("subr not found"); 2155 b.cursor = 0; 2156 clear_stack = 0; 2157 break; 2158 2159 case 0x0B: // return 2160 if (subr_stack_height <= 0) return STBTT__CSERR("return outside subr"); 2161 b = subr_stack[--subr_stack_height]; 2162 clear_stack = 0; 2163 break; 2164 2165 case 0x0E: // endchar 2166 stbtt__csctx_close_shape(c); 2167 return 1; 2168 2169 case 0x0C: { // two-byte escape 2170 float dx1, dx2, dx3, dx4, dx5, dx6, dy1, dy2, dy3, dy4, dy5, dy6; 2171 float dx, dy; 2172 int b1 = stbtt__buf_get8(&b); 2173 switch (b1) { 2174 // @TODO These "flex" implementations ignore the flex-depth and resolution, 2175 // and always draw beziers. 2176 case 0x22: // hflex 2177 if (sp < 7) return STBTT__CSERR("hflex stack"); 2178 dx1 = s[0]; 2179 dx2 = s[1]; 2180 dy2 = s[2]; 2181 dx3 = s[3]; 2182 dx4 = s[4]; 2183 dx5 = s[5]; 2184 dx6 = s[6]; 2185 stbtt__csctx_rccurve_to(c, dx1, 0, dx2, dy2, dx3, 0); 2186 stbtt__csctx_rccurve_to(c, dx4, 0, dx5, -dy2, dx6, 0); 2187 break; 2188 2189 case 0x23: // flex 2190 if (sp < 13) return STBTT__CSERR("flex stack"); 2191 dx1 = s[0]; 2192 dy1 = s[1]; 2193 dx2 = s[2]; 2194 dy2 = s[3]; 2195 dx3 = s[4]; 2196 dy3 = s[5]; 2197 dx4 = s[6]; 2198 dy4 = s[7]; 2199 dx5 = s[8]; 2200 dy5 = s[9]; 2201 dx6 = s[10]; 2202 dy6 = s[11]; 2203 //fd is s[12] 2204 stbtt__csctx_rccurve_to(c, dx1, dy1, dx2, dy2, dx3, dy3); 2205 stbtt__csctx_rccurve_to(c, dx4, dy4, dx5, dy5, dx6, dy6); 2206 break; 2207 2208 case 0x24: // hflex1 2209 if (sp < 9) return STBTT__CSERR("hflex1 stack"); 2210 dx1 = s[0]; 2211 dy1 = s[1]; 2212 dx2 = s[2]; 2213 dy2 = s[3]; 2214 dx3 = s[4]; 2215 dx4 = s[5]; 2216 dx5 = s[6]; 2217 dy5 = s[7]; 2218 dx6 = s[8]; 2219 stbtt__csctx_rccurve_to(c, dx1, dy1, dx2, dy2, dx3, 0); 2220 stbtt__csctx_rccurve_to(c, dx4, 0, dx5, dy5, dx6, -(dy1+dy2+dy5)); 2221 break; 2222 2223 case 0x25: // flex1 2224 if (sp < 11) return STBTT__CSERR("flex1 stack"); 2225 dx1 = s[0]; 2226 dy1 = s[1]; 2227 dx2 = s[2]; 2228 dy2 = s[3]; 2229 dx3 = s[4]; 2230 dy3 = s[5]; 2231 dx4 = s[6]; 2232 dy4 = s[7]; 2233 dx5 = s[8]; 2234 dy5 = s[9]; 2235 dx6 = dy6 = s[10]; 2236 dx = dx1+dx2+dx3+dx4+dx5; 2237 dy = dy1+dy2+dy3+dy4+dy5; 2238 if (STBTT_fabs(dx) > STBTT_fabs(dy)) 2239 dy6 = -dy; 2240 else 2241 dx6 = -dx; 2242 stbtt__csctx_rccurve_to(c, dx1, dy1, dx2, dy2, dx3, dy3); 2243 stbtt__csctx_rccurve_to(c, dx4, dy4, dx5, dy5, dx6, dy6); 2244 break; 2245 2246 default: 2247 return STBTT__CSERR("unimplemented"); 2248 } 2249 } break; 2250 2251 default: 2252 if (b0 != 255 && b0 != 28 && b0 < 32) 2253 return STBTT__CSERR("reserved operator"); 2254 2255 // push immediate 2256 if (b0 == 255) { 2257 f = (float)(stbtt_int32)stbtt__buf_get32(&b) / 0x10000; 2258 } else { 2259 stbtt__buf_skip(&b, -1); 2260 f = (float)(stbtt_int16)stbtt__cff_int(&b); 2261 } 2262 if (sp >= 48) return STBTT__CSERR("push stack overflow"); 2263 s[sp++] = f; 2264 clear_stack = 0; 2265 break; 2266 } 2267 if (clear_stack) sp = 0; 2268 } 2269 return STBTT__CSERR("no endchar"); 2270 2271 #undef STBTT__CSERR 2272 } 2273 2274 static int stbtt__GetGlyphShapeT2(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **pvertices) 2275 { 2276 // runs the charstring twice, once to count and once to output (to avoid realloc) 2277 stbtt__csctx count_ctx = STBTT__CSCTX_INIT(1); 2278 stbtt__csctx output_ctx = STBTT__CSCTX_INIT(0); 2279 if (stbtt__run_charstring(info, glyph_index, &count_ctx)) { 2280 *pvertices = (stbtt_vertex*)STBTT_malloc(count_ctx.num_vertices*sizeof(stbtt_vertex), info->userdata); 2281 output_ctx.pvertices = *pvertices; 2282 if (stbtt__run_charstring(info, glyph_index, &output_ctx)) { 2283 STBTT_assert(output_ctx.num_vertices == count_ctx.num_vertices); 2284 return output_ctx.num_vertices; 2285 } 2286 } 2287 *pvertices = NULL; 2288 return 0; 2289 } 2290 2291 static int stbtt__GetGlyphInfoT2(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1) 2292 { 2293 stbtt__csctx c = STBTT__CSCTX_INIT(1); 2294 int r = stbtt__run_charstring(info, glyph_index, &c); 2295 if (x0) *x0 = r ? c.min_x : 0; 2296 if (y0) *y0 = r ? c.min_y : 0; 2297 if (x1) *x1 = r ? c.max_x : 0; 2298 if (y1) *y1 = r ? c.max_y : 0; 2299 return r ? c.num_vertices : 0; 2300 } 2301 2302 STBTT_DEF int stbtt_GetGlyphShape(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **pvertices) 2303 { 2304 if (!info->cff.size) 2305 return stbtt__GetGlyphShapeTT(info, glyph_index, pvertices); 2306 else 2307 return stbtt__GetGlyphShapeT2(info, glyph_index, pvertices); 2308 } 2309 2310 STBTT_DEF void stbtt_GetGlyphHMetrics(const stbtt_fontinfo *info, int glyph_index, int *advanceWidth, int *leftSideBearing) 2311 { 2312 stbtt_uint16 numOfLongHorMetrics = ttUSHORT(info->data+info->hhea + 34); 2313 if (glyph_index < numOfLongHorMetrics) { 2314 if (advanceWidth) *advanceWidth = ttSHORT(info->data + info->hmtx + 4*glyph_index); 2315 if (leftSideBearing) *leftSideBearing = ttSHORT(info->data + info->hmtx + 4*glyph_index + 2); 2316 } else { 2317 if (advanceWidth) *advanceWidth = ttSHORT(info->data + info->hmtx + 4*(numOfLongHorMetrics-1)); 2318 if (leftSideBearing) *leftSideBearing = ttSHORT(info->data + info->hmtx + 4*numOfLongHorMetrics + 2*(glyph_index - numOfLongHorMetrics)); 2319 } 2320 } 2321 2322 STBTT_DEF int stbtt_GetKerningTableLength(const stbtt_fontinfo *info) 2323 { 2324 stbtt_uint8 *data = info->data + info->kern; 2325 2326 // we only look at the first table. it must be 'horizontal' and format 0. 2327 if (!info->kern) 2328 return 0; 2329 if (ttUSHORT(data+2) < 1) // number of tables, need at least 1 2330 return 0; 2331 if (ttUSHORT(data+8) != 1) // horizontal flag must be set in format 2332 return 0; 2333 2334 return ttUSHORT(data+10); 2335 } 2336 2337 STBTT_DEF int stbtt_GetKerningTable(const stbtt_fontinfo *info, stbtt_kerningentry* table, int table_length) 2338 { 2339 stbtt_uint8 *data = info->data + info->kern; 2340 int k, length; 2341 2342 // we only look at the first table. it must be 'horizontal' and format 0. 2343 if (!info->kern) 2344 return 0; 2345 if (ttUSHORT(data+2) < 1) // number of tables, need at least 1 2346 return 0; 2347 if (ttUSHORT(data+8) != 1) // horizontal flag must be set in format 2348 return 0; 2349 2350 length = ttUSHORT(data+10); 2351 if (table_length < length) 2352 length = table_length; 2353 2354 for (k = 0; k < length; k++) 2355 { 2356 table[k].glyph1 = ttUSHORT(data+18+(k*6)); 2357 table[k].glyph2 = ttUSHORT(data+20+(k*6)); 2358 table[k].advance = ttSHORT(data+22+(k*6)); 2359 } 2360 2361 return length; 2362 } 2363 2364 static int stbtt__GetGlyphKernInfoAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2) 2365 { 2366 stbtt_uint8 *data = info->data + info->kern; 2367 stbtt_uint32 needle, straw; 2368 int l, r, m; 2369 2370 // we only look at the first table. it must be 'horizontal' and format 0. 2371 if (!info->kern) 2372 return 0; 2373 if (ttUSHORT(data+2) < 1) // number of tables, need at least 1 2374 return 0; 2375 if (ttUSHORT(data+8) != 1) // horizontal flag must be set in format 2376 return 0; 2377 2378 l = 0; 2379 r = ttUSHORT(data+10) - 1; 2380 needle = glyph1 << 16 | glyph2; 2381 while (l <= r) { 2382 m = (l + r) >> 1; 2383 straw = ttULONG(data+18+(m*6)); // note: unaligned read 2384 if (needle < straw) 2385 r = m - 1; 2386 else if (needle > straw) 2387 l = m + 1; 2388 else 2389 return ttSHORT(data+22+(m*6)); 2390 } 2391 return 0; 2392 } 2393 2394 static stbtt_int32 stbtt__GetCoverageIndex(stbtt_uint8 *coverageTable, int glyph) 2395 { 2396 stbtt_uint16 coverageFormat = ttUSHORT(coverageTable); 2397 switch (coverageFormat) { 2398 case 1: { 2399 stbtt_uint16 glyphCount = ttUSHORT(coverageTable + 2); 2400 2401 // Binary search. 2402 stbtt_int32 l=0, r=glyphCount-1, m; 2403 int straw, needle=glyph; 2404 while (l <= r) { 2405 stbtt_uint8 *glyphArray = coverageTable + 4; 2406 stbtt_uint16 glyphID; 2407 m = (l + r) >> 1; 2408 glyphID = ttUSHORT(glyphArray + 2 * m); 2409 straw = glyphID; 2410 if (needle < straw) 2411 r = m - 1; 2412 else if (needle > straw) 2413 l = m + 1; 2414 else { 2415 return m; 2416 } 2417 } 2418 break; 2419 } 2420 2421 case 2: { 2422 stbtt_uint16 rangeCount = ttUSHORT(coverageTable + 2); 2423 stbtt_uint8 *rangeArray = coverageTable + 4; 2424 2425 // Binary search. 2426 stbtt_int32 l=0, r=rangeCount-1, m; 2427 int strawStart, strawEnd, needle=glyph; 2428 while (l <= r) { 2429 stbtt_uint8 *rangeRecord; 2430 m = (l + r) >> 1; 2431 rangeRecord = rangeArray + 6 * m; 2432 strawStart = ttUSHORT(rangeRecord); 2433 strawEnd = ttUSHORT(rangeRecord + 2); 2434 if (needle < strawStart) 2435 r = m - 1; 2436 else if (needle > strawEnd) 2437 l = m + 1; 2438 else { 2439 stbtt_uint16 startCoverageIndex = ttUSHORT(rangeRecord + 4); 2440 return startCoverageIndex + glyph - strawStart; 2441 } 2442 } 2443 break; 2444 } 2445 2446 default: return -1; // unsupported 2447 } 2448 2449 return -1; 2450 } 2451 2452 static stbtt_int32 stbtt__GetGlyphClass(stbtt_uint8 *classDefTable, int glyph) 2453 { 2454 stbtt_uint16 classDefFormat = ttUSHORT(classDefTable); 2455 switch (classDefFormat) 2456 { 2457 case 1: { 2458 stbtt_uint16 startGlyphID = ttUSHORT(classDefTable + 2); 2459 stbtt_uint16 glyphCount = ttUSHORT(classDefTable + 4); 2460 stbtt_uint8 *classDef1ValueArray = classDefTable + 6; 2461 2462 if (glyph >= startGlyphID && glyph < startGlyphID + glyphCount) 2463 return (stbtt_int32)ttUSHORT(classDef1ValueArray + 2 * (glyph - startGlyphID)); 2464 break; 2465 } 2466 2467 case 2: { 2468 stbtt_uint16 classRangeCount = ttUSHORT(classDefTable + 2); 2469 stbtt_uint8 *classRangeRecords = classDefTable + 4; 2470 2471 // Binary search. 2472 stbtt_int32 l=0, r=classRangeCount-1, m; 2473 int strawStart, strawEnd, needle=glyph; 2474 while (l <= r) { 2475 stbtt_uint8 *classRangeRecord; 2476 m = (l + r) >> 1; 2477 classRangeRecord = classRangeRecords + 6 * m; 2478 strawStart = ttUSHORT(classRangeRecord); 2479 strawEnd = ttUSHORT(classRangeRecord + 2); 2480 if (needle < strawStart) 2481 r = m - 1; 2482 else if (needle > strawEnd) 2483 l = m + 1; 2484 else 2485 return (stbtt_int32)ttUSHORT(classRangeRecord + 4); 2486 } 2487 break; 2488 } 2489 2490 default: 2491 return -1; // Unsupported definition type, return an error. 2492 } 2493 2494 // "All glyphs not assigned to a class fall into class 0". (OpenType spec) 2495 return 0; 2496 } 2497 2498 // Define to STBTT_assert(x) if you want to break on unimplemented formats. 2499 #define STBTT_GPOS_TODO_assert(x) 2500 2501 static stbtt_int32 stbtt__GetGlyphGPOSInfoAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2) 2502 { 2503 stbtt_uint16 lookupListOffset; 2504 stbtt_uint8 *lookupList; 2505 stbtt_uint16 lookupCount; 2506 stbtt_uint8 *data; 2507 stbtt_int32 i, sti; 2508 2509 if (!info->gpos) return 0; 2510 2511 data = info->data + info->gpos; 2512 2513 if (ttUSHORT(data+0) != 1) return 0; // Major version 1 2514 if (ttUSHORT(data+2) != 0) return 0; // Minor version 0 2515 2516 lookupListOffset = ttUSHORT(data+8); 2517 lookupList = data + lookupListOffset; 2518 lookupCount = ttUSHORT(lookupList); 2519 2520 for (i=0; i<lookupCount; ++i) { 2521 stbtt_uint16 lookupOffset = ttUSHORT(lookupList + 2 + 2 * i); 2522 stbtt_uint8 *lookupTable = lookupList + lookupOffset; 2523 2524 stbtt_uint16 lookupType = ttUSHORT(lookupTable); 2525 stbtt_uint16 subTableCount = ttUSHORT(lookupTable + 4); 2526 stbtt_uint8 *subTableOffsets = lookupTable + 6; 2527 if (lookupType != 2) // Pair Adjustment Positioning Subtable 2528 continue; 2529 2530 for (sti=0; sti<subTableCount; sti++) { 2531 stbtt_uint16 subtableOffset = ttUSHORT(subTableOffsets + 2 * sti); 2532 stbtt_uint8 *table = lookupTable + subtableOffset; 2533 stbtt_uint16 posFormat = ttUSHORT(table); 2534 stbtt_uint16 coverageOffset = ttUSHORT(table + 2); 2535 stbtt_int32 coverageIndex = stbtt__GetCoverageIndex(table + coverageOffset, glyph1); 2536 if (coverageIndex == -1) continue; 2537 2538 switch (posFormat) { 2539 case 1: { 2540 stbtt_int32 l, r, m; 2541 int straw, needle; 2542 stbtt_uint16 valueFormat1 = ttUSHORT(table + 4); 2543 stbtt_uint16 valueFormat2 = ttUSHORT(table + 6); 2544 if (valueFormat1 == 4 && valueFormat2 == 0) { // Support more formats? 2545 stbtt_int32 valueRecordPairSizeInBytes = 2; 2546 stbtt_uint16 pairSetCount = ttUSHORT(table + 8); 2547 stbtt_uint16 pairPosOffset = ttUSHORT(table + 10 + 2 * coverageIndex); 2548 stbtt_uint8 *pairValueTable = table + pairPosOffset; 2549 stbtt_uint16 pairValueCount = ttUSHORT(pairValueTable); 2550 stbtt_uint8 *pairValueArray = pairValueTable + 2; 2551 2552 if (coverageIndex >= pairSetCount) return 0; 2553 2554 needle=glyph2; 2555 r=pairValueCount-1; 2556 l=0; 2557 2558 // Binary search. 2559 while (l <= r) { 2560 stbtt_uint16 secondGlyph; 2561 stbtt_uint8 *pairValue; 2562 m = (l + r) >> 1; 2563 pairValue = pairValueArray + (2 + valueRecordPairSizeInBytes) * m; 2564 secondGlyph = ttUSHORT(pairValue); 2565 straw = secondGlyph; 2566 if (needle < straw) 2567 r = m - 1; 2568 else if (needle > straw) 2569 l = m + 1; 2570 else { 2571 stbtt_int16 xAdvance = ttSHORT(pairValue + 2); 2572 return xAdvance; 2573 } 2574 } 2575 } else 2576 return 0; 2577 break; 2578 } 2579 2580 case 2: { 2581 stbtt_uint16 valueFormat1 = ttUSHORT(table + 4); 2582 stbtt_uint16 valueFormat2 = ttUSHORT(table + 6); 2583 if (valueFormat1 == 4 && valueFormat2 == 0) { // Support more formats? 2584 stbtt_uint16 classDef1Offset = ttUSHORT(table + 8); 2585 stbtt_uint16 classDef2Offset = ttUSHORT(table + 10); 2586 int glyph1class = stbtt__GetGlyphClass(table + classDef1Offset, glyph1); 2587 int glyph2class = stbtt__GetGlyphClass(table + classDef2Offset, glyph2); 2588 2589 stbtt_uint16 class1Count = ttUSHORT(table + 12); 2590 stbtt_uint16 class2Count = ttUSHORT(table + 14); 2591 stbtt_uint8 *class1Records, *class2Records; 2592 stbtt_int16 xAdvance; 2593 2594 if (glyph1class < 0 || glyph1class >= class1Count) return 0; // malformed 2595 if (glyph2class < 0 || glyph2class >= class2Count) return 0; // malformed 2596 2597 class1Records = table + 16; 2598 class2Records = class1Records + 2 * (glyph1class * class2Count); 2599 xAdvance = ttSHORT(class2Records + 2 * glyph2class); 2600 return xAdvance; 2601 } else 2602 return 0; 2603 break; 2604 } 2605 2606 default: 2607 return 0; // Unsupported position format 2608 } 2609 } 2610 } 2611 2612 return 0; 2613 } 2614 2615 STBTT_DEF int stbtt_GetGlyphKernAdvance(const stbtt_fontinfo *info, int g1, int g2) 2616 { 2617 int xAdvance = 0; 2618 2619 if (info->gpos) 2620 xAdvance += stbtt__GetGlyphGPOSInfoAdvance(info, g1, g2); 2621 else if (info->kern) 2622 xAdvance += stbtt__GetGlyphKernInfoAdvance(info, g1, g2); 2623 2624 return xAdvance; 2625 } 2626 2627 STBTT_DEF int stbtt_GetCodepointKernAdvance(const stbtt_fontinfo *info, int ch1, int ch2) 2628 { 2629 if (!info->kern && !info->gpos) // if no kerning table, don't waste time looking up both codepoint->glyphs 2630 return 0; 2631 return stbtt_GetGlyphKernAdvance(info, stbtt_FindGlyphIndex(info,ch1), stbtt_FindGlyphIndex(info,ch2)); 2632 } 2633 2634 STBTT_DEF void stbtt_GetCodepointHMetrics(const stbtt_fontinfo *info, int codepoint, int *advanceWidth, int *leftSideBearing) 2635 { 2636 stbtt_GetGlyphHMetrics(info, stbtt_FindGlyphIndex(info,codepoint), advanceWidth, leftSideBearing); 2637 } 2638 2639 STBTT_DEF void stbtt_GetFontVMetrics(const stbtt_fontinfo *info, int *ascent, int *descent, int *lineGap) 2640 { 2641 if (ascent ) *ascent = ttSHORT(info->data+info->hhea + 4); 2642 if (descent) *descent = ttSHORT(info->data+info->hhea + 6); 2643 if (lineGap) *lineGap = ttSHORT(info->data+info->hhea + 8); 2644 } 2645 2646 STBTT_DEF int stbtt_GetFontVMetricsOS2(const stbtt_fontinfo *info, int *typoAscent, int *typoDescent, int *typoLineGap) 2647 { 2648 int tab = stbtt__find_table(info->data, info->fontstart, "OS/2"); 2649 if (!tab) 2650 return 0; 2651 if (typoAscent ) *typoAscent = ttSHORT(info->data+tab + 68); 2652 if (typoDescent) *typoDescent = ttSHORT(info->data+tab + 70); 2653 if (typoLineGap) *typoLineGap = ttSHORT(info->data+tab + 72); 2654 return 1; 2655 } 2656 2657 STBTT_DEF void stbtt_GetFontBoundingBox(const stbtt_fontinfo *info, int *x0, int *y0, int *x1, int *y1) 2658 { 2659 *x0 = ttSHORT(info->data + info->head + 36); 2660 *y0 = ttSHORT(info->data + info->head + 38); 2661 *x1 = ttSHORT(info->data + info->head + 40); 2662 *y1 = ttSHORT(info->data + info->head + 42); 2663 } 2664 2665 STBTT_DEF float stbtt_ScaleForPixelHeight(const stbtt_fontinfo *info, float height) 2666 { 2667 int fheight = ttSHORT(info->data + info->hhea + 4) - ttSHORT(info->data + info->hhea + 6); 2668 return (float) height / fheight; 2669 } 2670 2671 STBTT_DEF float stbtt_ScaleForMappingEmToPixels(const stbtt_fontinfo *info, float pixels) 2672 { 2673 int unitsPerEm = ttUSHORT(info->data + info->head + 18); 2674 return pixels / unitsPerEm; 2675 } 2676 2677 STBTT_DEF void stbtt_FreeShape(const stbtt_fontinfo *info, stbtt_vertex *v) 2678 { 2679 STBTT_free(v, info->userdata); 2680 } 2681 2682 STBTT_DEF stbtt_uint8 *stbtt_FindSVGDoc(const stbtt_fontinfo *info, int gl) 2683 { 2684 int i; 2685 stbtt_uint8 *data = info->data; 2686 stbtt_uint8 *svg_doc_list = data + stbtt__get_svg((stbtt_fontinfo *) info); 2687 2688 int numEntries = ttUSHORT(svg_doc_list); 2689 stbtt_uint8 *svg_docs = svg_doc_list + 2; 2690 2691 for(i=0; i<numEntries; i++) { 2692 stbtt_uint8 *svg_doc = svg_docs + (12 * i); 2693 if ((gl >= ttUSHORT(svg_doc)) && (gl <= ttUSHORT(svg_doc + 2))) 2694 return svg_doc; 2695 } 2696 return 0; 2697 } 2698 2699 STBTT_DEF int stbtt_GetGlyphSVG(const stbtt_fontinfo *info, int gl, const char **svg) 2700 { 2701 stbtt_uint8 *data = info->data; 2702 stbtt_uint8 *svg_doc; 2703 2704 if (info->svg == 0) 2705 return 0; 2706 2707 svg_doc = stbtt_FindSVGDoc(info, gl); 2708 if (svg_doc != NULL) { 2709 *svg = (char *) data + info->svg + ttULONG(svg_doc + 4); 2710 return ttULONG(svg_doc + 8); 2711 } else { 2712 return 0; 2713 } 2714 } 2715 2716 STBTT_DEF int stbtt_GetCodepointSVG(const stbtt_fontinfo *info, int unicode_codepoint, const char **svg) 2717 { 2718 return stbtt_GetGlyphSVG(info, stbtt_FindGlyphIndex(info, unicode_codepoint), svg); 2719 } 2720 2721 ////////////////////////////////////////////////////////////////////////////// 2722 // 2723 // antialiasing software rasterizer 2724 // 2725 2726 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) 2727 { 2728 int x0=0,y0=0,x1,y1; // =0 suppresses compiler warning 2729 if (!stbtt_GetGlyphBox(font, glyph, &x0,&y0,&x1,&y1)) { 2730 // e.g. space character 2731 if (ix0) *ix0 = 0; 2732 if (iy0) *iy0 = 0; 2733 if (ix1) *ix1 = 0; 2734 if (iy1) *iy1 = 0; 2735 } else { 2736 // move to integral bboxes (treating pixels as little squares, what pixels get touched)? 2737 if (ix0) *ix0 = STBTT_ifloor( x0 * scale_x + shift_x); 2738 if (iy0) *iy0 = STBTT_ifloor(-y1 * scale_y + shift_y); 2739 if (ix1) *ix1 = STBTT_iceil ( x1 * scale_x + shift_x); 2740 if (iy1) *iy1 = STBTT_iceil (-y0 * scale_y + shift_y); 2741 } 2742 } 2743 2744 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) 2745 { 2746 stbtt_GetGlyphBitmapBoxSubpixel(font, glyph, scale_x, scale_y,0.0f,0.0f, ix0, iy0, ix1, iy1); 2747 } 2748 2749 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) 2750 { 2751 stbtt_GetGlyphBitmapBoxSubpixel(font, stbtt_FindGlyphIndex(font,codepoint), scale_x, scale_y,shift_x,shift_y, ix0,iy0,ix1,iy1); 2752 } 2753 2754 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) 2755 { 2756 stbtt_GetCodepointBitmapBoxSubpixel(font, codepoint, scale_x, scale_y,0.0f,0.0f, ix0,iy0,ix1,iy1); 2757 } 2758 2759 ////////////////////////////////////////////////////////////////////////////// 2760 // 2761 // Rasterizer 2762 2763 typedef struct stbtt__hheap_chunk 2764 { 2765 struct stbtt__hheap_chunk *next; 2766 } stbtt__hheap_chunk; 2767 2768 typedef struct stbtt__hheap 2769 { 2770 struct stbtt__hheap_chunk *head; 2771 void *first_free; 2772 int num_remaining_in_head_chunk; 2773 } stbtt__hheap; 2774 2775 static void *stbtt__hheap_alloc(stbtt__hheap *hh, size_t size, void *userdata) 2776 { 2777 if (hh->first_free) { 2778 void *p = hh->first_free; 2779 hh->first_free = * (void **) p; 2780 return p; 2781 } else { 2782 if (hh->num_remaining_in_head_chunk == 0) { 2783 int count = (size < 32 ? 2000 : size < 128 ? 800 : 100); 2784 stbtt__hheap_chunk *c = (stbtt__hheap_chunk *) STBTT_malloc(sizeof(stbtt__hheap_chunk) + size * count, userdata); 2785 if (c == NULL) 2786 return NULL; 2787 c->next = hh->head; 2788 hh->head = c; 2789 hh->num_remaining_in_head_chunk = count; 2790 } 2791 --hh->num_remaining_in_head_chunk; 2792 return (char *) (hh->head) + sizeof(stbtt__hheap_chunk) + size * hh->num_remaining_in_head_chunk; 2793 } 2794 } 2795 2796 static void stbtt__hheap_free(stbtt__hheap *hh, void *p) 2797 { 2798 *(void **) p = hh->first_free; 2799 hh->first_free = p; 2800 } 2801 2802 static void stbtt__hheap_cleanup(stbtt__hheap *hh, void *userdata) 2803 { 2804 stbtt__hheap_chunk *c = hh->head; 2805 while (c) { 2806 stbtt__hheap_chunk *n = c->next; 2807 STBTT_free(c, userdata); 2808 c = n; 2809 } 2810 } 2811 2812 typedef struct stbtt__edge { 2813 float x0,y0, x1,y1; 2814 int invert; 2815 } stbtt__edge; 2816 2817 2818 typedef struct stbtt__active_edge 2819 { 2820 struct stbtt__active_edge *next; 2821 #if STBTT_RASTERIZER_VERSION==1 2822 int x,dx; 2823 float ey; 2824 int direction; 2825 #elif STBTT_RASTERIZER_VERSION==2 2826 float fx,fdx,fdy; 2827 float direction; 2828 float sy; 2829 float ey; 2830 #else 2831 #error "Unrecognized value of STBTT_RASTERIZER_VERSION" 2832 #endif 2833 } stbtt__active_edge; 2834 2835 #if STBTT_RASTERIZER_VERSION == 1 2836 #define STBTT_FIXSHIFT 10 2837 #define STBTT_FIX (1 << STBTT_FIXSHIFT) 2838 #define STBTT_FIXMASK (STBTT_FIX-1) 2839 2840 static stbtt__active_edge *stbtt__new_active(stbtt__hheap *hh, stbtt__edge *e, int off_x, float start_point, void *userdata) 2841 { 2842 stbtt__active_edge *z = (stbtt__active_edge *) stbtt__hheap_alloc(hh, sizeof(*z), userdata); 2843 float dxdy = (e->x1 - e->x0) / (e->y1 - e->y0); 2844 STBTT_assert(z != NULL); 2845 if (!z) return z; 2846 2847 // round dx down to avoid overshooting 2848 if (dxdy < 0) 2849 z->dx = -STBTT_ifloor(STBTT_FIX * -dxdy); 2850 else 2851 z->dx = STBTT_ifloor(STBTT_FIX * dxdy); 2852 2853 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 2854 z->x -= off_x * STBTT_FIX; 2855 2856 z->ey = e->y1; 2857 z->next = 0; 2858 z->direction = e->invert ? 1 : -1; 2859 return z; 2860 } 2861 #elif STBTT_RASTERIZER_VERSION == 2 2862 static stbtt__active_edge *stbtt__new_active(stbtt__hheap *hh, stbtt__edge *e, int off_x, float start_point, void *userdata) 2863 { 2864 stbtt__active_edge *z = (stbtt__active_edge *) stbtt__hheap_alloc(hh, sizeof(*z), userdata); 2865 float dxdy = (e->x1 - e->x0) / (e->y1 - e->y0); 2866 STBTT_assert(z != NULL); 2867 //STBTT_assert(e->y0 <= start_point); 2868 if (!z) return z; 2869 z->fdx = dxdy; 2870 z->fdy = dxdy != 0.0f ? (1.0f/dxdy) : 0.0f; 2871 z->fx = e->x0 + dxdy * (start_point - e->y0); 2872 z->fx -= off_x; 2873 z->direction = e->invert ? 1.0f : -1.0f; 2874 z->sy = e->y0; 2875 z->ey = e->y1; 2876 z->next = 0; 2877 return z; 2878 } 2879 #else 2880 #error "Unrecognized value of STBTT_RASTERIZER_VERSION" 2881 #endif 2882 2883 #if STBTT_RASTERIZER_VERSION == 1 2884 // note: this routine clips fills that extend off the edges... ideally this 2885 // wouldn't happen, but it could happen if the truetype glyph bounding boxes 2886 // are wrong, or if the user supplies a too-small bitmap 2887 static void stbtt__fill_active_edges(unsigned char *scanline, int len, stbtt__active_edge *e, int max_weight) 2888 { 2889 // non-zero winding fill 2890 int x0=0, w=0; 2891 2892 while (e) { 2893 if (w == 0) { 2894 // if we're currently at zero, we need to record the edge start point 2895 x0 = e->x; w += e->direction; 2896 } else { 2897 int x1 = e->x; w += e->direction; 2898 // if we went to zero, we need to draw 2899 if (w == 0) { 2900 int i = x0 >> STBTT_FIXSHIFT; 2901 int j = x1 >> STBTT_FIXSHIFT; 2902 2903 if (i < len && j >= 0) { 2904 if (i == j) { 2905 // x0,x1 are the same pixel, so compute combined coverage 2906 scanline[i] = scanline[i] + (stbtt_uint8) ((x1 - x0) * max_weight >> STBTT_FIXSHIFT); 2907 } else { 2908 if (i >= 0) // add antialiasing for x0 2909 scanline[i] = scanline[i] + (stbtt_uint8) (((STBTT_FIX - (x0 & STBTT_FIXMASK)) * max_weight) >> STBTT_FIXSHIFT); 2910 else 2911 i = -1; // clip 2912 2913 if (j < len) // add antialiasing for x1 2914 scanline[j] = scanline[j] + (stbtt_uint8) (((x1 & STBTT_FIXMASK) * max_weight) >> STBTT_FIXSHIFT); 2915 else 2916 j = len; // clip 2917 2918 for (++i; i < j; ++i) // fill pixels between x0 and x1 2919 scanline[i] = scanline[i] + (stbtt_uint8) max_weight; 2920 } 2921 } 2922 } 2923 } 2924 2925 e = e->next; 2926 } 2927 } 2928 2929 static void stbtt__rasterize_sorted_edges(stbtt__bitmap *result, stbtt__edge *e, int n, int vsubsample, int off_x, int off_y, void *userdata) 2930 { 2931 stbtt__hheap hh = { 0, 0, 0 }; 2932 stbtt__active_edge *active = NULL; 2933 int y,j=0; 2934 int max_weight = (255 / vsubsample); // weight per vertical scanline 2935 int s; // vertical subsample index 2936 unsigned char scanline_data[512], *scanline; 2937 2938 if (result->w > 512) 2939 scanline = (unsigned char *) STBTT_malloc(result->w, userdata); 2940 else 2941 scanline = scanline_data; 2942 2943 y = off_y * vsubsample; 2944 e[n].y0 = (off_y + result->h) * (float) vsubsample + 1; 2945 2946 while (j < result->h) { 2947 STBTT_memset(scanline, 0, result->w); 2948 for (s=0; s < vsubsample; ++s) { 2949 // find center of pixel for this scanline 2950 float scan_y = y + 0.5f; 2951 stbtt__active_edge **step = &active; 2952 2953 // update all active edges; 2954 // remove all active edges that terminate before the center of this scanline 2955 while (*step) { 2956 stbtt__active_edge * z = *step; 2957 if (z->ey <= scan_y) { 2958 *step = z->next; // delete from list 2959 STBTT_assert(z->direction); 2960 z->direction = 0; 2961 stbtt__hheap_free(&hh, z); 2962 } else { 2963 z->x += z->dx; // advance to position for current scanline 2964 step = &((*step)->next); // advance through list 2965 } 2966 } 2967 2968 // resort the list if needed 2969 for(;;) { 2970 int changed=0; 2971 step = &active; 2972 while (*step && (*step)->next) { 2973 if ((*step)->x > (*step)->next->x) { 2974 stbtt__active_edge *t = *step; 2975 stbtt__active_edge *q = t->next; 2976 2977 t->next = q->next; 2978 q->next = t; 2979 *step = q; 2980 changed = 1; 2981 } 2982 step = &(*step)->next; 2983 } 2984 if (!changed) break; 2985 } 2986 2987 // insert all edges that start before the center of this scanline -- omit ones that also end on this scanline 2988 while (e->y0 <= scan_y) { 2989 if (e->y1 > scan_y) { 2990 stbtt__active_edge *z = stbtt__new_active(&hh, e, off_x, scan_y, userdata); 2991 if (z != NULL) { 2992 // find insertion point 2993 if (active == NULL) 2994 active = z; 2995 else if (z->x < active->x) { 2996 // insert at front 2997 z->next = active; 2998 active = z; 2999 } else { 3000 // find thing to insert AFTER 3001 stbtt__active_edge *p = active; 3002 while (p->next && p->next->x < z->x) 3003 p = p->next; 3004 // at this point, p->next->x is NOT < z->x 3005 z->next = p->next; 3006 p->next = z; 3007 } 3008 } 3009 } 3010 ++e; 3011 } 3012 3013 // now process all active edges in XOR fashion 3014 if (active) 3015 stbtt__fill_active_edges(scanline, result->w, active, max_weight); 3016 3017 ++y; 3018 } 3019 STBTT_memcpy(result->pixels + j * result->stride, scanline, result->w); 3020 ++j; 3021 } 3022 3023 stbtt__hheap_cleanup(&hh, userdata); 3024 3025 if (scanline != scanline_data) 3026 STBTT_free(scanline, userdata); 3027 } 3028 3029 #elif STBTT_RASTERIZER_VERSION == 2 3030 3031 // the edge passed in here does not cross the vertical line at x or the vertical line at x+1 3032 // (i.e. it has already been clipped to those) 3033 static void stbtt__handle_clipped_edge(float *scanline, int x, stbtt__active_edge *e, float x0, float y0, float x1, float y1) 3034 { 3035 if (y0 == y1) return; 3036 STBTT_assert(y0 < y1); 3037 STBTT_assert(e->sy <= e->ey); 3038 if (y0 > e->ey) return; 3039 if (y1 < e->sy) return; 3040 if (y0 < e->sy) { 3041 x0 += (x1-x0) * (e->sy - y0) / (y1-y0); 3042 y0 = e->sy; 3043 } 3044 if (y1 > e->ey) { 3045 x1 += (x1-x0) * (e->ey - y1) / (y1-y0); 3046 y1 = e->ey; 3047 } 3048 3049 if (x0 == x) 3050 STBTT_assert(x1 <= x+1); 3051 else if (x0 == x+1) 3052 STBTT_assert(x1 >= x); 3053 else if (x0 <= x) 3054 STBTT_assert(x1 <= x); 3055 else if (x0 >= x+1) 3056 STBTT_assert(x1 >= x+1); 3057 else 3058 STBTT_assert(x1 >= x && x1 <= x+1); 3059 3060 if (x0 <= x && x1 <= x) 3061 scanline[x] += e->direction * (y1-y0); 3062 else if (x0 >= x+1 && x1 >= x+1) 3063 ; 3064 else { 3065 STBTT_assert(x0 >= x && x0 <= x+1 && x1 >= x && x1 <= x+1); 3066 scanline[x] += e->direction * (y1-y0) * (1-((x0-x)+(x1-x))/2); // coverage = 1 - average x position 3067 } 3068 } 3069 3070 static float stbtt__sized_trapezoid_area(float height, float top_width, float bottom_width) 3071 { 3072 STBTT_assert(top_width >= 0); 3073 STBTT_assert(bottom_width >= 0); 3074 return (top_width + bottom_width) / 2.0f * height; 3075 } 3076 3077 static float stbtt__position_trapezoid_area(float height, float tx0, float tx1, float bx0, float bx1) 3078 { 3079 return stbtt__sized_trapezoid_area(height, tx1 - tx0, bx1 - bx0); 3080 } 3081 3082 static float stbtt__sized_triangle_area(float height, float width) 3083 { 3084 return height * width / 2; 3085 } 3086 3087 static void stbtt__fill_active_edges_new(float *scanline, float *scanline_fill, int len, stbtt__active_edge *e, float y_top) 3088 { 3089 float y_bottom = y_top+1; 3090 3091 while (e) { 3092 // brute force every pixel 3093 3094 // compute intersection points with top & bottom 3095 STBTT_assert(e->ey >= y_top); 3096 3097 if (e->fdx == 0) { 3098 float x0 = e->fx; 3099 if (x0 < len) { 3100 if (x0 >= 0) { 3101 stbtt__handle_clipped_edge(scanline,(int) x0,e, x0,y_top, x0,y_bottom); 3102 stbtt__handle_clipped_edge(scanline_fill-1,(int) x0+1,e, x0,y_top, x0,y_bottom); 3103 } else { 3104 stbtt__handle_clipped_edge(scanline_fill-1,0,e, x0,y_top, x0,y_bottom); 3105 } 3106 } 3107 } else { 3108 float x0 = e->fx; 3109 float dx = e->fdx; 3110 float xb = x0 + dx; 3111 float x_top, x_bottom; 3112 float sy0,sy1; 3113 float dy = e->fdy; 3114 STBTT_assert(e->sy <= y_bottom && e->ey >= y_top); 3115 3116 // compute endpoints of line segment clipped to this scanline (if the 3117 // line segment starts on this scanline. x0 is the intersection of the 3118 // line with y_top, but that may be off the line segment. 3119 if (e->sy > y_top) { 3120 x_top = x0 + dx * (e->sy - y_top); 3121 sy0 = e->sy; 3122 } else { 3123 x_top = x0; 3124 sy0 = y_top; 3125 } 3126 if (e->ey < y_bottom) { 3127 x_bottom = x0 + dx * (e->ey - y_top); 3128 sy1 = e->ey; 3129 } else { 3130 x_bottom = xb; 3131 sy1 = y_bottom; 3132 } 3133 3134 if (x_top >= 0 && x_bottom >= 0 && x_top < len && x_bottom < len) { 3135 // from here on, we don't have to range check x values 3136 3137 if ((int) x_top == (int) x_bottom) { 3138 float height; 3139 // simple case, only spans one pixel 3140 int x = (int) x_top; 3141 height = (sy1 - sy0) * e->direction; 3142 STBTT_assert(x >= 0 && x < len); 3143 scanline[x] += stbtt__position_trapezoid_area(height, x_top, x+1.0f, x_bottom, x+1.0f); 3144 scanline_fill[x] += height; // everything right of this pixel is filled 3145 } else { 3146 int x,x1,x2; 3147 float y_crossing, y_final, step, sign, area; 3148 // covers 2+ pixels 3149 if (x_top > x_bottom) { 3150 // flip scanline vertically; signed area is the same 3151 float t; 3152 sy0 = y_bottom - (sy0 - y_top); 3153 sy1 = y_bottom - (sy1 - y_top); 3154 t = sy0, sy0 = sy1, sy1 = t; 3155 t = x_bottom, x_bottom = x_top, x_top = t; 3156 dx = -dx; 3157 dy = -dy; 3158 t = x0, x0 = xb, xb = t; 3159 } 3160 STBTT_assert(dy >= 0); 3161 STBTT_assert(dx >= 0); 3162 3163 x1 = (int) x_top; 3164 x2 = (int) x_bottom; 3165 // compute intersection with y axis at x1+1 3166 y_crossing = y_top + dy * (x1+1 - x0); 3167 3168 // compute intersection with y axis at x2 3169 y_final = y_top + dy * (x2 - x0); 3170 3171 // x1 x_top x2 x_bottom 3172 // y_top +------|-----+------------+------------+--------|---+------------+ 3173 // | | | | | | 3174 // | | | | | | 3175 // sy0 | Txxxxx|............|............|............|............| 3176 // y_crossing | *xxxxx.......|............|............|............| 3177 // | | xxxxx..|............|............|............| 3178 // | | /- xx*xxxx........|............|............| 3179 // | | dy < | xxxxxx..|............|............| 3180 // y_final | | \- | xx*xxx.........|............| 3181 // sy1 | | | | xxxxxB...|............| 3182 // | | | | | | 3183 // | | | | | | 3184 // y_bottom +------------+------------+------------+------------+------------+ 3185 // 3186 // goal is to measure the area covered by '.' in each pixel 3187 3188 // if x2 is right at the right edge of x1, y_crossing can blow up, github #1057 3189 // @TODO: maybe test against sy1 rather than y_bottom? 3190 if (y_crossing > y_bottom) 3191 y_crossing = y_bottom; 3192 3193 sign = e->direction; 3194 3195 // area of the rectangle covered from sy0..y_crossing 3196 area = sign * (y_crossing-sy0); 3197 3198 // area of the triangle (x_top,sy0), (x1+1,sy0), (x1+1,y_crossing) 3199 scanline[x1] += stbtt__sized_triangle_area(area, x1+1 - x_top); 3200 3201 // check if final y_crossing is blown up; no test case for this 3202 if (y_final > y_bottom) { 3203 int denom = (x2 - (x1+1)); 3204 y_final = y_bottom; 3205 if (denom != 0) { // [DEAR IMGUI] Avoid div by zero (https://github.com/nothings/stb/issues/1316) 3206 dy = (y_final - y_crossing ) / denom; // if denom=0, y_final = y_crossing, so y_final <= y_bottom 3207 } 3208 } 3209 3210 // in second pixel, area covered by line segment found in first pixel 3211 // is always a rectangle 1 wide * the height of that line segment; this 3212 // is exactly what the variable 'area' stores. it also gets a contribution 3213 // from the line segment within it. the THIRD pixel will get the first 3214 // pixel's rectangle contribution, the second pixel's rectangle contribution, 3215 // and its own contribution. the 'own contribution' is the same in every pixel except 3216 // the leftmost and rightmost, a trapezoid that slides down in each pixel. 3217 // the second pixel's contribution to the third pixel will be the 3218 // rectangle 1 wide times the height change in the second pixel, which is dy. 3219 3220 step = sign * dy * 1; // dy is dy/dx, change in y for every 1 change in x, 3221 // which multiplied by 1-pixel-width is how much pixel area changes for each step in x 3222 // so the area advances by 'step' every time 3223 3224 for (x = x1+1; x < x2; ++x) { 3225 scanline[x] += area + step/2; // area of trapezoid is 1*step/2 3226 area += step; 3227 } 3228 STBTT_assert(STBTT_fabs(area) <= 1.01f); // accumulated error from area += step unless we round step down 3229 STBTT_assert(sy1 > y_final-0.01f); 3230 3231 // area covered in the last pixel is the rectangle from all the pixels to the left, 3232 // plus the trapezoid filled by the line segment in this pixel all the way to the right edge 3233 scanline[x2] += area + sign * stbtt__position_trapezoid_area(sy1-y_final, (float) x2, x2+1.0f, x_bottom, x2+1.0f); 3234 3235 // the rest of the line is filled based on the total height of the line segment in this pixel 3236 scanline_fill[x2] += sign * (sy1-sy0); 3237 } 3238 } else { 3239 // if edge goes outside of box we're drawing, we require 3240 // clipping logic. since this does not match the intended use 3241 // of this library, we use a different, very slow brute 3242 // force implementation 3243 // note though that this does happen some of the time because 3244 // x_top and x_bottom can be extrapolated at the top & bottom of 3245 // the shape and actually lie outside the bounding box 3246 int x; 3247 for (x=0; x < len; ++x) { 3248 // cases: 3249 // 3250 // there can be up to two intersections with the pixel. any intersection 3251 // with left or right edges can be handled by splitting into two (or three) 3252 // regions. intersections with top & bottom do not necessitate case-wise logic. 3253 // 3254 // the old way of doing this found the intersections with the left & right edges, 3255 // then used some simple logic to produce up to three segments in sorted order 3256 // from top-to-bottom. however, this had a problem: if an x edge was epsilon 3257 // across the x border, then the corresponding y position might not be distinct 3258 // from the other y segment, and it might ignored as an empty segment. to avoid 3259 // that, we need to explicitly produce segments based on x positions. 3260 3261 // rename variables to clearly-defined pairs 3262 float y0 = y_top; 3263 float x1 = (float) (x); 3264 float x2 = (float) (x+1); 3265 float x3 = xb; 3266 float y3 = y_bottom; 3267 3268 // x = e->x + e->dx * (y-y_top) 3269 // (y-y_top) = (x - e->x) / e->dx 3270 // y = (x - e->x) / e->dx + y_top 3271 float y1 = (x - x0) / dx + y_top; 3272 float y2 = (x+1 - x0) / dx + y_top; 3273 3274 if (x0 < x1 && x3 > x2) { // three segments descending down-right 3275 stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x1,y1); 3276 stbtt__handle_clipped_edge(scanline,x,e, x1,y1, x2,y2); 3277 stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x3,y3); 3278 } else if (x3 < x1 && x0 > x2) { // three segments descending down-left 3279 stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x2,y2); 3280 stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x1,y1); 3281 stbtt__handle_clipped_edge(scanline,x,e, x1,y1, x3,y3); 3282 } else if (x0 < x1 && x3 > x1) { // two segments across x, down-right 3283 stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x1,y1); 3284 stbtt__handle_clipped_edge(scanline,x,e, x1,y1, x3,y3); 3285 } else if (x3 < x1 && x0 > x1) { // two segments across x, down-left 3286 stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x1,y1); 3287 stbtt__handle_clipped_edge(scanline,x,e, x1,y1, x3,y3); 3288 } else if (x0 < x2 && x3 > x2) { // two segments across x+1, down-right 3289 stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x2,y2); 3290 stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x3,y3); 3291 } else if (x3 < x2 && x0 > x2) { // two segments across x+1, down-left 3292 stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x2,y2); 3293 stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x3,y3); 3294 } else { // one segment 3295 stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x3,y3); 3296 } 3297 } 3298 } 3299 } 3300 e = e->next; 3301 } 3302 } 3303 3304 // directly AA rasterize edges w/o supersampling 3305 static void stbtt__rasterize_sorted_edges(stbtt__bitmap *result, stbtt__edge *e, int n, int vsubsample, int off_x, int off_y, void *userdata) 3306 { 3307 stbtt__hheap hh = { 0, 0, 0 }; 3308 stbtt__active_edge *active = NULL; 3309 int y,j=0, i; 3310 float scanline_data[129], *scanline, *scanline2; 3311 3312 STBTT__NOTUSED(vsubsample); 3313 3314 if (result->w > 64) 3315 scanline = (float *) STBTT_malloc((result->w*2+1) * sizeof(float), userdata); 3316 else 3317 scanline = scanline_data; 3318 3319 scanline2 = scanline + result->w; 3320 3321 y = off_y; 3322 e[n].y0 = (float) (off_y + result->h) + 1; 3323 3324 while (j < result->h) { 3325 // find center of pixel for this scanline 3326 float scan_y_top = y + 0.0f; 3327 float scan_y_bottom = y + 1.0f; 3328 stbtt__active_edge **step = &active; 3329 3330 STBTT_memset(scanline , 0, result->w*sizeof(scanline[0])); 3331 STBTT_memset(scanline2, 0, (result->w+1)*sizeof(scanline[0])); 3332 3333 // update all active edges; 3334 // remove all active edges that terminate before the top of this scanline 3335 while (*step) { 3336 stbtt__active_edge * z = *step; 3337 if (z->ey <= scan_y_top) { 3338 *step = z->next; // delete from list 3339 STBTT_assert(z->direction); 3340 z->direction = 0; 3341 stbtt__hheap_free(&hh, z); 3342 } else { 3343 step = &((*step)->next); // advance through list 3344 } 3345 } 3346 3347 // insert all edges that start before the bottom of this scanline 3348 while (e->y0 <= scan_y_bottom) { 3349 if (e->y0 != e->y1) { 3350 stbtt__active_edge *z = stbtt__new_active(&hh, e, off_x, scan_y_top, userdata); 3351 if (z != NULL) { 3352 if (j == 0 && off_y != 0) { 3353 if (z->ey < scan_y_top) { 3354 // this can happen due to subpixel positioning and some kind of fp rounding error i think 3355 z->ey = scan_y_top; 3356 } 3357 } 3358 STBTT_assert(z->ey >= scan_y_top); // if we get really unlucky a tiny bit of an edge can be out of bounds 3359 // insert at front 3360 z->next = active; 3361 active = z; 3362 } 3363 } 3364 ++e; 3365 } 3366 3367 // now process all active edges 3368 if (active) 3369 stbtt__fill_active_edges_new(scanline, scanline2+1, result->w, active, scan_y_top); 3370 3371 { 3372 float sum = 0; 3373 for (i=0; i < result->w; ++i) { 3374 float k; 3375 int m; 3376 sum += scanline2[i]; 3377 k = scanline[i] + sum; 3378 k = (float) STBTT_fabs(k)*255 + 0.5f; 3379 m = (int) k; 3380 if (m > 255) m = 255; 3381 result->pixels[j*result->stride + i] = (unsigned char) m; 3382 } 3383 } 3384 // advance all the edges 3385 step = &active; 3386 while (*step) { 3387 stbtt__active_edge *z = *step; 3388 z->fx += z->fdx; // advance to position for current scanline 3389 step = &((*step)->next); // advance through list 3390 } 3391 3392 ++y; 3393 ++j; 3394 } 3395 3396 stbtt__hheap_cleanup(&hh, userdata); 3397 3398 if (scanline != scanline_data) 3399 STBTT_free(scanline, userdata); 3400 } 3401 #else 3402 #error "Unrecognized value of STBTT_RASTERIZER_VERSION" 3403 #endif 3404 3405 #define STBTT__COMPARE(a,b) ((a)->y0 < (b)->y0) 3406 3407 static void stbtt__sort_edges_ins_sort(stbtt__edge *p, int n) 3408 { 3409 int i,j; 3410 for (i=1; i < n; ++i) { 3411 stbtt__edge t = p[i], *a = &t; 3412 j = i; 3413 while (j > 0) { 3414 stbtt__edge *b = &p[j-1]; 3415 int c = STBTT__COMPARE(a,b); 3416 if (!c) break; 3417 p[j] = p[j-1]; 3418 --j; 3419 } 3420 if (i != j) 3421 p[j] = t; 3422 } 3423 } 3424 3425 static void stbtt__sort_edges_quicksort(stbtt__edge *p, int n) 3426 { 3427 /* threshold for transitioning to insertion sort */ 3428 while (n > 12) { 3429 stbtt__edge t; 3430 int c01,c12,c,m,i,j; 3431 3432 /* compute median of three */ 3433 m = n >> 1; 3434 c01 = STBTT__COMPARE(&p[0],&p[m]); 3435 c12 = STBTT__COMPARE(&p[m],&p[n-1]); 3436 /* if 0 >= mid >= end, or 0 < mid < end, then use mid */ 3437 if (c01 != c12) { 3438 /* otherwise, we'll need to swap something else to middle */ 3439 int z; 3440 c = STBTT__COMPARE(&p[0],&p[n-1]); 3441 /* 0>mid && mid<n: 0>n => n; 0<n => 0 */ 3442 /* 0<mid && mid>n: 0>n => 0; 0<n => n */ 3443 z = (c == c12) ? 0 : n-1; 3444 t = p[z]; 3445 p[z] = p[m]; 3446 p[m] = t; 3447 } 3448 /* now p[m] is the median-of-three */ 3449 /* swap it to the beginning so it won't move around */ 3450 t = p[0]; 3451 p[0] = p[m]; 3452 p[m] = t; 3453 3454 /* partition loop */ 3455 i=1; 3456 j=n-1; 3457 for(;;) { 3458 /* handling of equality is crucial here */ 3459 /* for sentinels & efficiency with duplicates */ 3460 for (;;++i) { 3461 if (!STBTT__COMPARE(&p[i], &p[0])) break; 3462 } 3463 for (;;--j) { 3464 if (!STBTT__COMPARE(&p[0], &p[j])) break; 3465 } 3466 /* make sure we haven't crossed */ 3467 if (i >= j) break; 3468 t = p[i]; 3469 p[i] = p[j]; 3470 p[j] = t; 3471 3472 ++i; 3473 --j; 3474 } 3475 /* recurse on smaller side, iterate on larger */ 3476 if (j < (n-i)) { 3477 stbtt__sort_edges_quicksort(p,j); 3478 p = p+i; 3479 n = n-i; 3480 } else { 3481 stbtt__sort_edges_quicksort(p+i, n-i); 3482 n = j; 3483 } 3484 } 3485 } 3486 3487 static void stbtt__sort_edges(stbtt__edge *p, int n) 3488 { 3489 stbtt__sort_edges_quicksort(p, n); 3490 stbtt__sort_edges_ins_sort(p, n); 3491 } 3492 3493 typedef struct 3494 { 3495 float x,y; 3496 } stbtt__point; 3497 3498 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) 3499 { 3500 float y_scale_inv = invert ? -scale_y : scale_y; 3501 stbtt__edge *e; 3502 int n,i,j,k,m; 3503 #if STBTT_RASTERIZER_VERSION == 1 3504 int vsubsample = result->h < 8 ? 15 : 5; 3505 #elif STBTT_RASTERIZER_VERSION == 2 3506 int vsubsample = 1; 3507 #else 3508 #error "Unrecognized value of STBTT_RASTERIZER_VERSION" 3509 #endif 3510 // vsubsample should divide 255 evenly; otherwise we won't reach full opacity 3511 3512 // now we have to blow out the windings into explicit edge lists 3513 n = 0; 3514 for (i=0; i < windings; ++i) 3515 n += wcount[i]; 3516 3517 e = (stbtt__edge *) STBTT_malloc(sizeof(*e) * (n+1), userdata); // add an extra one as a sentinel 3518 if (e == 0) return; 3519 n = 0; 3520 3521 m=0; 3522 for (i=0; i < windings; ++i) { 3523 stbtt__point *p = pts + m; 3524 m += wcount[i]; 3525 j = wcount[i]-1; 3526 for (k=0; k < wcount[i]; j=k++) { 3527 int a=k,b=j; 3528 // skip the edge if horizontal 3529 if (p[j].y == p[k].y) 3530 continue; 3531 // add edge from j to k to the list 3532 e[n].invert = 0; 3533 if (invert ? p[j].y > p[k].y : p[j].y < p[k].y) { 3534 e[n].invert = 1; 3535 a=j,b=k; 3536 } 3537 e[n].x0 = p[a].x * scale_x + shift_x; 3538 e[n].y0 = (p[a].y * y_scale_inv + shift_y) * vsubsample; 3539 e[n].x1 = p[b].x * scale_x + shift_x; 3540 e[n].y1 = (p[b].y * y_scale_inv + shift_y) * vsubsample; 3541 ++n; 3542 } 3543 } 3544 3545 // now sort the edges by their highest point (should snap to integer, and then by x) 3546 //STBTT_sort(e, n, sizeof(e[0]), stbtt__edge_compare); 3547 stbtt__sort_edges(e, n); 3548 3549 // now, traverse the scanlines and find the intersections on each scanline, use xor winding rule 3550 stbtt__rasterize_sorted_edges(result, e, n, vsubsample, off_x, off_y, userdata); 3551 3552 STBTT_free(e, userdata); 3553 } 3554 3555 static void stbtt__add_point(stbtt__point *points, int n, float x, float y) 3556 { 3557 if (!points) return; // during first pass, it's unallocated 3558 points[n].x = x; 3559 points[n].y = y; 3560 } 3561 3562 // tessellate until threshold p is happy... @TODO warped to compensate for non-linear stretching 3563 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) 3564 { 3565 // midpoint 3566 float mx = (x0 + 2*x1 + x2)/4; 3567 float my = (y0 + 2*y1 + y2)/4; 3568 // versus directly drawn line 3569 float dx = (x0+x2)/2 - mx; 3570 float dy = (y0+y2)/2 - my; 3571 if (n > 16) // 65536 segments on one curve better be enough! 3572 return 1; 3573 if (dx*dx+dy*dy > objspace_flatness_squared) { // half-pixel error allowed... need to be smaller if AA 3574 stbtt__tesselate_curve(points, num_points, x0,y0, (x0+x1)/2.0f,(y0+y1)/2.0f, mx,my, objspace_flatness_squared,n+1); 3575 stbtt__tesselate_curve(points, num_points, mx,my, (x1+x2)/2.0f,(y1+y2)/2.0f, x2,y2, objspace_flatness_squared,n+1); 3576 } else { 3577 stbtt__add_point(points, *num_points,x2,y2); 3578 *num_points = *num_points+1; 3579 } 3580 return 1; 3581 } 3582 3583 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) 3584 { 3585 // @TODO this "flatness" calculation is just made-up nonsense that seems to work well enough 3586 float dx0 = x1-x0; 3587 float dy0 = y1-y0; 3588 float dx1 = x2-x1; 3589 float dy1 = y2-y1; 3590 float dx2 = x3-x2; 3591 float dy2 = y3-y2; 3592 float dx = x3-x0; 3593 float dy = y3-y0; 3594 float longlen = (float) (STBTT_sqrt(dx0*dx0+dy0*dy0)+STBTT_sqrt(dx1*dx1+dy1*dy1)+STBTT_sqrt(dx2*dx2+dy2*dy2)); 3595 float shortlen = (float) STBTT_sqrt(dx*dx+dy*dy); 3596 float flatness_squared = longlen*longlen-shortlen*shortlen; 3597 3598 if (n > 16) // 65536 segments on one curve better be enough! 3599 return; 3600 3601 if (flatness_squared > objspace_flatness_squared) { 3602 float x01 = (x0+x1)/2; 3603 float y01 = (y0+y1)/2; 3604 float x12 = (x1+x2)/2; 3605 float y12 = (y1+y2)/2; 3606 float x23 = (x2+x3)/2; 3607 float y23 = (y2+y3)/2; 3608 3609 float xa = (x01+x12)/2; 3610 float ya = (y01+y12)/2; 3611 float xb = (x12+x23)/2; 3612 float yb = (y12+y23)/2; 3613 3614 float mx = (xa+xb)/2; 3615 float my = (ya+yb)/2; 3616 3617 stbtt__tesselate_cubic(points, num_points, x0,y0, x01,y01, xa,ya, mx,my, objspace_flatness_squared,n+1); 3618 stbtt__tesselate_cubic(points, num_points, mx,my, xb,yb, x23,y23, x3,y3, objspace_flatness_squared,n+1); 3619 } else { 3620 stbtt__add_point(points, *num_points,x3,y3); 3621 *num_points = *num_points+1; 3622 } 3623 } 3624 3625 // returns number of contours 3626 static stbtt__point *stbtt_FlattenCurves(stbtt_vertex *vertices, int num_verts, float objspace_flatness, int **contour_lengths, int *num_contours, void *userdata) 3627 { 3628 stbtt__point *points=0; 3629 int num_points=0; 3630 3631 float objspace_flatness_squared = objspace_flatness * objspace_flatness; 3632 int i,n=0,start=0, pass; 3633 3634 // count how many "moves" there are to get the contour count 3635 for (i=0; i < num_verts; ++i) 3636 if (vertices[i].type == STBTT_vmove) 3637 ++n; 3638 3639 *num_contours = n; 3640 if (n == 0) return 0; 3641 3642 *contour_lengths = (int *) STBTT_malloc(sizeof(**contour_lengths) * n, userdata); 3643 3644 if (*contour_lengths == 0) { 3645 *num_contours = 0; 3646 return 0; 3647 } 3648 3649 // make two passes through the points so we don't need to realloc 3650 for (pass=0; pass < 2; ++pass) { 3651 float x=0,y=0; 3652 if (pass == 1) { 3653 points = (stbtt__point *) STBTT_malloc(num_points * sizeof(points[0]), userdata); 3654 if (points == NULL) goto error; 3655 } 3656 num_points = 0; 3657 n= -1; 3658 for (i=0; i < num_verts; ++i) { 3659 switch (vertices[i].type) { 3660 case STBTT_vmove: 3661 // start the next contour 3662 if (n >= 0) 3663 (*contour_lengths)[n] = num_points - start; 3664 ++n; 3665 start = num_points; 3666 3667 x = vertices[i].x, y = vertices[i].y; 3668 stbtt__add_point(points, num_points++, x,y); 3669 break; 3670 case STBTT_vline: 3671 x = vertices[i].x, y = vertices[i].y; 3672 stbtt__add_point(points, num_points++, x, y); 3673 break; 3674 case STBTT_vcurve: 3675 stbtt__tesselate_curve(points, &num_points, x,y, 3676 vertices[i].cx, vertices[i].cy, 3677 vertices[i].x, vertices[i].y, 3678 objspace_flatness_squared, 0); 3679 x = vertices[i].x, y = vertices[i].y; 3680 break; 3681 case STBTT_vcubic: 3682 stbtt__tesselate_cubic(points, &num_points, x,y, 3683 vertices[i].cx, vertices[i].cy, 3684 vertices[i].cx1, vertices[i].cy1, 3685 vertices[i].x, vertices[i].y, 3686 objspace_flatness_squared, 0); 3687 x = vertices[i].x, y = vertices[i].y; 3688 break; 3689 } 3690 } 3691 (*contour_lengths)[n] = num_points - start; 3692 } 3693 3694 return points; 3695 error: 3696 STBTT_free(points, userdata); 3697 STBTT_free(*contour_lengths, userdata); 3698 *contour_lengths = 0; 3699 *num_contours = 0; 3700 return NULL; 3701 } 3702 3703 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) 3704 { 3705 float scale = scale_x > scale_y ? scale_y : scale_x; 3706 int winding_count = 0; 3707 int *winding_lengths = NULL; 3708 stbtt__point *windings = stbtt_FlattenCurves(vertices, num_verts, flatness_in_pixels / scale, &winding_lengths, &winding_count, userdata); 3709 if (windings) { 3710 stbtt__rasterize(result, windings, winding_lengths, winding_count, scale_x, scale_y, shift_x, shift_y, x_off, y_off, invert, userdata); 3711 STBTT_free(winding_lengths, userdata); 3712 STBTT_free(windings, userdata); 3713 } 3714 } 3715 3716 STBTT_DEF void stbtt_FreeBitmap(unsigned char *bitmap, void *userdata) 3717 { 3718 STBTT_free(bitmap, userdata); 3719 } 3720 3721 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) 3722 { 3723 int ix0,iy0,ix1,iy1; 3724 stbtt__bitmap gbm; 3725 stbtt_vertex *vertices; 3726 int num_verts = stbtt_GetGlyphShape(info, glyph, &vertices); 3727 3728 if (scale_x == 0) scale_x = scale_y; 3729 if (scale_y == 0) { 3730 if (scale_x == 0) { 3731 STBTT_free(vertices, info->userdata); 3732 return NULL; 3733 } 3734 scale_y = scale_x; 3735 } 3736 3737 stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale_x, scale_y, shift_x, shift_y, &ix0,&iy0,&ix1,&iy1); 3738 3739 // now we get the size 3740 gbm.w = (ix1 - ix0); 3741 gbm.h = (iy1 - iy0); 3742 gbm.pixels = NULL; // in case we error 3743 3744 if (width ) *width = gbm.w; 3745 if (height) *height = gbm.h; 3746 if (xoff ) *xoff = ix0; 3747 if (yoff ) *yoff = iy0; 3748 3749 if (gbm.w && gbm.h) { 3750 gbm.pixels = (unsigned char *) STBTT_malloc(gbm.w * gbm.h, info->userdata); 3751 if (gbm.pixels) { 3752 gbm.stride = gbm.w; 3753 3754 stbtt_Rasterize(&gbm, 0.35f, vertices, num_verts, scale_x, scale_y, shift_x, shift_y, ix0, iy0, 1, info->userdata); 3755 } 3756 } 3757 STBTT_free(vertices, info->userdata); 3758 return gbm.pixels; 3759 } 3760 3761 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) 3762 { 3763 return stbtt_GetGlyphBitmapSubpixel(info, scale_x, scale_y, 0.0f, 0.0f, glyph, width, height, xoff, yoff); 3764 } 3765 3766 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) 3767 { 3768 int ix0,iy0; 3769 stbtt_vertex *vertices; 3770 int num_verts = stbtt_GetGlyphShape(info, glyph, &vertices); 3771 stbtt__bitmap gbm; 3772 3773 stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale_x, scale_y, shift_x, shift_y, &ix0,&iy0,0,0); 3774 gbm.pixels = output; 3775 gbm.w = out_w; 3776 gbm.h = out_h; 3777 gbm.stride = out_stride; 3778 3779 if (gbm.w && gbm.h) 3780 stbtt_Rasterize(&gbm, 0.35f, vertices, num_verts, scale_x, scale_y, shift_x, shift_y, ix0,iy0, 1, info->userdata); 3781 3782 STBTT_free(vertices, info->userdata); 3783 } 3784 3785 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) 3786 { 3787 stbtt_MakeGlyphBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, scale_y, 0.0f,0.0f, glyph); 3788 } 3789 3790 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) 3791 { 3792 return stbtt_GetGlyphBitmapSubpixel(info, scale_x, scale_y,shift_x,shift_y, stbtt_FindGlyphIndex(info,codepoint), width,height,xoff,yoff); 3793 } 3794 3795 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) 3796 { 3797 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)); 3798 } 3799 3800 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) 3801 { 3802 stbtt_MakeGlyphBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, scale_y, shift_x, shift_y, stbtt_FindGlyphIndex(info,codepoint)); 3803 } 3804 3805 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) 3806 { 3807 return stbtt_GetCodepointBitmapSubpixel(info, scale_x, scale_y, 0.0f,0.0f, codepoint, width,height,xoff,yoff); 3808 } 3809 3810 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) 3811 { 3812 stbtt_MakeCodepointBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, scale_y, 0.0f,0.0f, codepoint); 3813 } 3814 3815 ////////////////////////////////////////////////////////////////////////////// 3816 // 3817 // bitmap baking 3818 // 3819 // This is SUPER-CRAPPY packing to keep source code small 3820 3821 static int stbtt_BakeFontBitmap_internal(unsigned char *data, int offset, // font location (use offset=0 for plain .ttf) 3822 float pixel_height, // height of font in pixels 3823 unsigned char *pixels, int pw, int ph, // bitmap to be filled in 3824 int first_char, int num_chars, // characters to bake 3825 stbtt_bakedchar *chardata) 3826 { 3827 float scale; 3828 int x,y,bottom_y, i; 3829 stbtt_fontinfo f; 3830 f.userdata = NULL; 3831 if (!stbtt_InitFont(&f, data, offset)) 3832 return -1; 3833 STBTT_memset(pixels, 0, pw*ph); // background of 0 around pixels 3834 x=y=1; 3835 bottom_y = 1; 3836 3837 scale = stbtt_ScaleForPixelHeight(&f, pixel_height); 3838 3839 for (i=0; i < num_chars; ++i) { 3840 int advance, lsb, x0,y0,x1,y1,gw,gh; 3841 int g = stbtt_FindGlyphIndex(&f, first_char + i); 3842 stbtt_GetGlyphHMetrics(&f, g, &advance, &lsb); 3843 stbtt_GetGlyphBitmapBox(&f, g, scale,scale, &x0,&y0,&x1,&y1); 3844 gw = x1-x0; 3845 gh = y1-y0; 3846 if (x + gw + 1 >= pw) 3847 y = bottom_y, x = 1; // advance to next row 3848 if (y + gh + 1 >= ph) // check if it fits vertically AFTER potentially moving to next row 3849 return -i; 3850 STBTT_assert(x+gw < pw); 3851 STBTT_assert(y+gh < ph); 3852 stbtt_MakeGlyphBitmap(&f, pixels+x+y*pw, gw,gh,pw, scale,scale, g); 3853 chardata[i].x0 = (stbtt_int16) x; 3854 chardata[i].y0 = (stbtt_int16) y; 3855 chardata[i].x1 = (stbtt_int16) (x + gw); 3856 chardata[i].y1 = (stbtt_int16) (y + gh); 3857 chardata[i].xadvance = scale * advance; 3858 chardata[i].xoff = (float) x0; 3859 chardata[i].yoff = (float) y0; 3860 x = x + gw + 1; 3861 if (y+gh+1 > bottom_y) 3862 bottom_y = y+gh+1; 3863 } 3864 return bottom_y; 3865 } 3866 3867 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) 3868 { 3869 float d3d_bias = opengl_fillrule ? 0 : -0.5f; 3870 float ipw = 1.0f / pw, iph = 1.0f / ph; 3871 const stbtt_bakedchar *b = chardata + char_index; 3872 int round_x = STBTT_ifloor((*xpos + b->xoff) + 0.5f); 3873 int round_y = STBTT_ifloor((*ypos + b->yoff) + 0.5f); 3874 3875 q->x0 = round_x + d3d_bias; 3876 q->y0 = round_y + d3d_bias; 3877 q->x1 = round_x + b->x1 - b->x0 + d3d_bias; 3878 q->y1 = round_y + b->y1 - b->y0 + d3d_bias; 3879 3880 q->s0 = b->x0 * ipw; 3881 q->t0 = b->y0 * iph; 3882 q->s1 = b->x1 * ipw; 3883 q->t1 = b->y1 * iph; 3884 3885 *xpos += b->xadvance; 3886 } 3887 3888 ////////////////////////////////////////////////////////////////////////////// 3889 // 3890 // rectangle packing replacement routines if you don't have stb_rect_pack.h 3891 // 3892 3893 #ifndef STB_RECT_PACK_VERSION 3894 3895 typedef int stbrp_coord; 3896 3897 //////////////////////////////////////////////////////////////////////////////////// 3898 // // 3899 // // 3900 // COMPILER WARNING ?!?!? // 3901 // // 3902 // // 3903 // if you get a compile warning due to these symbols being defined more than // 3904 // once, move #include "stb_rect_pack.h" before #include "stb_truetype.h" // 3905 // // 3906 //////////////////////////////////////////////////////////////////////////////////// 3907 3908 typedef struct 3909 { 3910 int width,height; 3911 int x,y,bottom_y; 3912 } stbrp_context; 3913 3914 typedef struct 3915 { 3916 unsigned char x; 3917 } stbrp_node; 3918 3919 struct stbrp_rect 3920 { 3921 stbrp_coord x,y; 3922 int id,w,h,was_packed; 3923 }; 3924 3925 static void stbrp_init_target(stbrp_context *con, int pw, int ph, stbrp_node *nodes, int num_nodes) 3926 { 3927 con->width = pw; 3928 con->height = ph; 3929 con->x = 0; 3930 con->y = 0; 3931 con->bottom_y = 0; 3932 STBTT__NOTUSED(nodes); 3933 STBTT__NOTUSED(num_nodes); 3934 } 3935 3936 static void stbrp_pack_rects(stbrp_context *con, stbrp_rect *rects, int num_rects) 3937 { 3938 int i; 3939 for (i=0; i < num_rects; ++i) { 3940 if (con->x + rects[i].w > con->width) { 3941 con->x = 0; 3942 con->y = con->bottom_y; 3943 } 3944 if (con->y + rects[i].h > con->height) 3945 break; 3946 rects[i].x = con->x; 3947 rects[i].y = con->y; 3948 rects[i].was_packed = 1; 3949 con->x += rects[i].w; 3950 if (con->y + rects[i].h > con->bottom_y) 3951 con->bottom_y = con->y + rects[i].h; 3952 } 3953 for ( ; i < num_rects; ++i) 3954 rects[i].was_packed = 0; 3955 } 3956 #endif 3957 3958 ////////////////////////////////////////////////////////////////////////////// 3959 // 3960 // bitmap baking 3961 // 3962 // This is SUPER-AWESOME (tm Ryan Gordon) packing using stb_rect_pack.h. If 3963 // stb_rect_pack.h isn't available, it uses the BakeFontBitmap strategy. 3964 3965 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) 3966 { 3967 stbrp_context *context = (stbrp_context *) STBTT_malloc(sizeof(*context) ,alloc_context); 3968 int num_nodes = pw - padding; 3969 stbrp_node *nodes = (stbrp_node *) STBTT_malloc(sizeof(*nodes ) * num_nodes,alloc_context); 3970 3971 if (context == NULL || nodes == NULL) { 3972 if (context != NULL) STBTT_free(context, alloc_context); 3973 if (nodes != NULL) STBTT_free(nodes , alloc_context); 3974 return 0; 3975 } 3976 3977 spc->user_allocator_context = alloc_context; 3978 spc->width = pw; 3979 spc->height = ph; 3980 spc->pixels = pixels; 3981 spc->pack_info = context; 3982 spc->nodes = nodes; 3983 spc->padding = padding; 3984 spc->stride_in_bytes = stride_in_bytes != 0 ? stride_in_bytes : pw; 3985 spc->h_oversample = 1; 3986 spc->v_oversample = 1; 3987 spc->skip_missing = 0; 3988 3989 stbrp_init_target(context, pw-padding, ph-padding, nodes, num_nodes); 3990 3991 if (pixels) 3992 STBTT_memset(pixels, 0, pw*ph); // background of 0 around pixels 3993 3994 return 1; 3995 } 3996 3997 STBTT_DEF void stbtt_PackEnd (stbtt_pack_context *spc) 3998 { 3999 STBTT_free(spc->nodes , spc->user_allocator_context); 4000 STBTT_free(spc->pack_info, spc->user_allocator_context); 4001 } 4002 4003 STBTT_DEF void stbtt_PackSetOversampling(stbtt_pack_context *spc, unsigned int h_oversample, unsigned int v_oversample) 4004 { 4005 STBTT_assert(h_oversample <= STBTT_MAX_OVERSAMPLE); 4006 STBTT_assert(v_oversample <= STBTT_MAX_OVERSAMPLE); 4007 if (h_oversample <= STBTT_MAX_OVERSAMPLE) 4008 spc->h_oversample = h_oversample; 4009 if (v_oversample <= STBTT_MAX_OVERSAMPLE) 4010 spc->v_oversample = v_oversample; 4011 } 4012 4013 STBTT_DEF void stbtt_PackSetSkipMissingCodepoints(stbtt_pack_context *spc, int skip) 4014 { 4015 spc->skip_missing = skip; 4016 } 4017 4018 #define STBTT__OVER_MASK (STBTT_MAX_OVERSAMPLE-1) 4019 4020 static void stbtt__h_prefilter(unsigned char *pixels, int w, int h, int stride_in_bytes, unsigned int kernel_width) 4021 { 4022 unsigned char buffer[STBTT_MAX_OVERSAMPLE]; 4023 int safe_w = w - kernel_width; 4024 int j; 4025 STBTT_memset(buffer, 0, STBTT_MAX_OVERSAMPLE); // suppress bogus warning from VS2013 -analyze 4026 for (j=0; j < h; ++j) { 4027 int i; 4028 unsigned int total; 4029 STBTT_memset(buffer, 0, kernel_width); 4030 4031 total = 0; 4032 4033 // make kernel_width a constant in common cases so compiler can optimize out the divide 4034 switch (kernel_width) { 4035 case 2: 4036 for (i=0; i <= safe_w; ++i) { 4037 total += pixels[i] - buffer[i & STBTT__OVER_MASK]; 4038 buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i]; 4039 pixels[i] = (unsigned char) (total / 2); 4040 } 4041 break; 4042 case 3: 4043 for (i=0; i <= safe_w; ++i) { 4044 total += pixels[i] - buffer[i & STBTT__OVER_MASK]; 4045 buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i]; 4046 pixels[i] = (unsigned char) (total / 3); 4047 } 4048 break; 4049 case 4: 4050 for (i=0; i <= safe_w; ++i) { 4051 total += pixels[i] - buffer[i & STBTT__OVER_MASK]; 4052 buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i]; 4053 pixels[i] = (unsigned char) (total / 4); 4054 } 4055 break; 4056 case 5: 4057 for (i=0; i <= safe_w; ++i) { 4058 total += pixels[i] - buffer[i & STBTT__OVER_MASK]; 4059 buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i]; 4060 pixels[i] = (unsigned char) (total / 5); 4061 } 4062 break; 4063 default: 4064 for (i=0; i <= safe_w; ++i) { 4065 total += pixels[i] - buffer[i & STBTT__OVER_MASK]; 4066 buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i]; 4067 pixels[i] = (unsigned char) (total / kernel_width); 4068 } 4069 break; 4070 } 4071 4072 for (; i < w; ++i) { 4073 STBTT_assert(pixels[i] == 0); 4074 total -= buffer[i & STBTT__OVER_MASK]; 4075 pixels[i] = (unsigned char) (total / kernel_width); 4076 } 4077 4078 pixels += stride_in_bytes; 4079 } 4080 } 4081 4082 static void stbtt__v_prefilter(unsigned char *pixels, int w, int h, int stride_in_bytes, unsigned int kernel_width) 4083 { 4084 unsigned char buffer[STBTT_MAX_OVERSAMPLE]; 4085 int safe_h = h - kernel_width; 4086 int j; 4087 STBTT_memset(buffer, 0, STBTT_MAX_OVERSAMPLE); // suppress bogus warning from VS2013 -analyze 4088 for (j=0; j < w; ++j) { 4089 int i; 4090 unsigned int total; 4091 STBTT_memset(buffer, 0, kernel_width); 4092 4093 total = 0; 4094 4095 // make kernel_width a constant in common cases so compiler can optimize out the divide 4096 switch (kernel_width) { 4097 case 2: 4098 for (i=0; i <= safe_h; ++i) { 4099 total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK]; 4100 buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes]; 4101 pixels[i*stride_in_bytes] = (unsigned char) (total / 2); 4102 } 4103 break; 4104 case 3: 4105 for (i=0; i <= safe_h; ++i) { 4106 total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK]; 4107 buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes]; 4108 pixels[i*stride_in_bytes] = (unsigned char) (total / 3); 4109 } 4110 break; 4111 case 4: 4112 for (i=0; i <= safe_h; ++i) { 4113 total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK]; 4114 buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes]; 4115 pixels[i*stride_in_bytes] = (unsigned char) (total / 4); 4116 } 4117 break; 4118 case 5: 4119 for (i=0; i <= safe_h; ++i) { 4120 total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK]; 4121 buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes]; 4122 pixels[i*stride_in_bytes] = (unsigned char) (total / 5); 4123 } 4124 break; 4125 default: 4126 for (i=0; i <= safe_h; ++i) { 4127 total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK]; 4128 buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes]; 4129 pixels[i*stride_in_bytes] = (unsigned char) (total / kernel_width); 4130 } 4131 break; 4132 } 4133 4134 for (; i < h; ++i) { 4135 STBTT_assert(pixels[i*stride_in_bytes] == 0); 4136 total -= buffer[i & STBTT__OVER_MASK]; 4137 pixels[i*stride_in_bytes] = (unsigned char) (total / kernel_width); 4138 } 4139 4140 pixels += 1; 4141 } 4142 } 4143 4144 static float stbtt__oversample_shift(int oversample) 4145 { 4146 if (!oversample) 4147 return 0.0f; 4148 4149 // The prefilter is a box filter of width "oversample", 4150 // which shifts phase by (oversample - 1)/2 pixels in 4151 // oversampled space. We want to shift in the opposite 4152 // direction to counter this. 4153 return (float)-(oversample - 1) / (2.0f * (float)oversample); 4154 } 4155 4156 // rects array must be big enough to accommodate all characters in the given ranges 4157 STBTT_DEF int stbtt_PackFontRangesGatherRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects) 4158 { 4159 int i,j,k; 4160 int missing_glyph_added = 0; 4161 4162 k=0; 4163 for (i=0; i < num_ranges; ++i) { 4164 float fh = ranges[i].font_size; 4165 float scale = fh > 0 ? stbtt_ScaleForPixelHeight(info, fh) : stbtt_ScaleForMappingEmToPixels(info, -fh); 4166 ranges[i].h_oversample = (unsigned char) spc->h_oversample; 4167 ranges[i].v_oversample = (unsigned char) spc->v_oversample; 4168 for (j=0; j < ranges[i].num_chars; ++j) { 4169 int x0,y0,x1,y1; 4170 int codepoint = ranges[i].array_of_unicode_codepoints == NULL ? ranges[i].first_unicode_codepoint_in_range + j : ranges[i].array_of_unicode_codepoints[j]; 4171 int glyph = stbtt_FindGlyphIndex(info, codepoint); 4172 if (glyph == 0 && (spc->skip_missing || missing_glyph_added)) { 4173 rects[k].w = rects[k].h = 0; 4174 } else { 4175 stbtt_GetGlyphBitmapBoxSubpixel(info,glyph, 4176 scale * spc->h_oversample, 4177 scale * spc->v_oversample, 4178 0,0, 4179 &x0,&y0,&x1,&y1); 4180 rects[k].w = (stbrp_coord) (x1-x0 + spc->padding + spc->h_oversample-1); 4181 rects[k].h = (stbrp_coord) (y1-y0 + spc->padding + spc->v_oversample-1); 4182 if (glyph == 0) 4183 missing_glyph_added = 1; 4184 } 4185 ++k; 4186 } 4187 } 4188 4189 return k; 4190 } 4191 4192 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) 4193 { 4194 stbtt_MakeGlyphBitmapSubpixel(info, 4195 output, 4196 out_w - (prefilter_x - 1), 4197 out_h - (prefilter_y - 1), 4198 out_stride, 4199 scale_x, 4200 scale_y, 4201 shift_x, 4202 shift_y, 4203 glyph); 4204 4205 if (prefilter_x > 1) 4206 stbtt__h_prefilter(output, out_w, out_h, out_stride, prefilter_x); 4207 4208 if (prefilter_y > 1) 4209 stbtt__v_prefilter(output, out_w, out_h, out_stride, prefilter_y); 4210 4211 *sub_x = stbtt__oversample_shift(prefilter_x); 4212 *sub_y = stbtt__oversample_shift(prefilter_y); 4213 } 4214 4215 // rects array must be big enough to accommodate all characters in the given ranges 4216 STBTT_DEF int stbtt_PackFontRangesRenderIntoRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects) 4217 { 4218 int i,j,k, missing_glyph = -1, return_value = 1; 4219 4220 // save current values 4221 int old_h_over = spc->h_oversample; 4222 int old_v_over = spc->v_oversample; 4223 4224 k = 0; 4225 for (i=0; i < num_ranges; ++i) { 4226 float fh = ranges[i].font_size; 4227 float scale = fh > 0 ? stbtt_ScaleForPixelHeight(info, fh) : stbtt_ScaleForMappingEmToPixels(info, -fh); 4228 float recip_h,recip_v,sub_x,sub_y; 4229 spc->h_oversample = ranges[i].h_oversample; 4230 spc->v_oversample = ranges[i].v_oversample; 4231 recip_h = 1.0f / spc->h_oversample; 4232 recip_v = 1.0f / spc->v_oversample; 4233 sub_x = stbtt__oversample_shift(spc->h_oversample); 4234 sub_y = stbtt__oversample_shift(spc->v_oversample); 4235 for (j=0; j < ranges[i].num_chars; ++j) { 4236 stbrp_rect *r = &rects[k]; 4237 if (r->was_packed && r->w != 0 && r->h != 0) { 4238 stbtt_packedchar *bc = &ranges[i].chardata_for_range[j]; 4239 int advance, lsb, x0,y0,x1,y1; 4240 int codepoint = ranges[i].array_of_unicode_codepoints == NULL ? ranges[i].first_unicode_codepoint_in_range + j : ranges[i].array_of_unicode_codepoints[j]; 4241 int glyph = stbtt_FindGlyphIndex(info, codepoint); 4242 stbrp_coord pad = (stbrp_coord) spc->padding; 4243 4244 // pad on left and top 4245 r->x += pad; 4246 r->y += pad; 4247 r->w -= pad; 4248 r->h -= pad; 4249 stbtt_GetGlyphHMetrics(info, glyph, &advance, &lsb); 4250 stbtt_GetGlyphBitmapBox(info, glyph, 4251 scale * spc->h_oversample, 4252 scale * spc->v_oversample, 4253 &x0,&y0,&x1,&y1); 4254 stbtt_MakeGlyphBitmapSubpixel(info, 4255 spc->pixels + r->x + r->y*spc->stride_in_bytes, 4256 r->w - spc->h_oversample+1, 4257 r->h - spc->v_oversample+1, 4258 spc->stride_in_bytes, 4259 scale * spc->h_oversample, 4260 scale * spc->v_oversample, 4261 0,0, 4262 glyph); 4263 4264 if (spc->h_oversample > 1) 4265 stbtt__h_prefilter(spc->pixels + r->x + r->y*spc->stride_in_bytes, 4266 r->w, r->h, spc->stride_in_bytes, 4267 spc->h_oversample); 4268 4269 if (spc->v_oversample > 1) 4270 stbtt__v_prefilter(spc->pixels + r->x + r->y*spc->stride_in_bytes, 4271 r->w, r->h, spc->stride_in_bytes, 4272 spc->v_oversample); 4273 4274 bc->x0 = (stbtt_int16) r->x; 4275 bc->y0 = (stbtt_int16) r->y; 4276 bc->x1 = (stbtt_int16) (r->x + r->w); 4277 bc->y1 = (stbtt_int16) (r->y + r->h); 4278 bc->xadvance = scale * advance; 4279 bc->xoff = (float) x0 * recip_h + sub_x; 4280 bc->yoff = (float) y0 * recip_v + sub_y; 4281 bc->xoff2 = (x0 + r->w) * recip_h + sub_x; 4282 bc->yoff2 = (y0 + r->h) * recip_v + sub_y; 4283 4284 if (glyph == 0) 4285 missing_glyph = j; 4286 } else if (spc->skip_missing) { 4287 return_value = 0; 4288 } else if (r->was_packed && r->w == 0 && r->h == 0 && missing_glyph >= 0) { 4289 ranges[i].chardata_for_range[j] = ranges[i].chardata_for_range[missing_glyph]; 4290 } else { 4291 return_value = 0; // if any fail, report failure 4292 } 4293 4294 ++k; 4295 } 4296 } 4297 4298 // restore original values 4299 spc->h_oversample = old_h_over; 4300 spc->v_oversample = old_v_over; 4301 4302 return return_value; 4303 } 4304 4305 STBTT_DEF void stbtt_PackFontRangesPackRects(stbtt_pack_context *spc, stbrp_rect *rects, int num_rects) 4306 { 4307 stbrp_pack_rects((stbrp_context *) spc->pack_info, rects, num_rects); 4308 } 4309 4310 STBTT_DEF int stbtt_PackFontRanges(stbtt_pack_context *spc, const unsigned char *fontdata, int font_index, stbtt_pack_range *ranges, int num_ranges) 4311 { 4312 stbtt_fontinfo info; 4313 int i, j, n, return_value; // [DEAR IMGUI] removed = 1; 4314 //stbrp_context *context = (stbrp_context *) spc->pack_info; 4315 stbrp_rect *rects; 4316 4317 // flag all characters as NOT packed 4318 for (i=0; i < num_ranges; ++i) 4319 for (j=0; j < ranges[i].num_chars; ++j) 4320 ranges[i].chardata_for_range[j].x0 = 4321 ranges[i].chardata_for_range[j].y0 = 4322 ranges[i].chardata_for_range[j].x1 = 4323 ranges[i].chardata_for_range[j].y1 = 0; 4324 4325 n = 0; 4326 for (i=0; i < num_ranges; ++i) 4327 n += ranges[i].num_chars; 4328 4329 rects = (stbrp_rect *) STBTT_malloc(sizeof(*rects) * n, spc->user_allocator_context); 4330 if (rects == NULL) 4331 return 0; 4332 4333 info.userdata = spc->user_allocator_context; 4334 stbtt_InitFont(&info, fontdata, stbtt_GetFontOffsetForIndex(fontdata,font_index)); 4335 4336 n = stbtt_PackFontRangesGatherRects(spc, &info, ranges, num_ranges, rects); 4337 4338 stbtt_PackFontRangesPackRects(spc, rects, n); 4339 4340 return_value = stbtt_PackFontRangesRenderIntoRects(spc, &info, ranges, num_ranges, rects); 4341 4342 STBTT_free(rects, spc->user_allocator_context); 4343 return return_value; 4344 } 4345 4346 STBTT_DEF int stbtt_PackFontRange(stbtt_pack_context *spc, const unsigned char *fontdata, int font_index, float font_size, 4347 int first_unicode_codepoint_in_range, int num_chars_in_range, stbtt_packedchar *chardata_for_range) 4348 { 4349 stbtt_pack_range range; 4350 range.first_unicode_codepoint_in_range = first_unicode_codepoint_in_range; 4351 range.array_of_unicode_codepoints = NULL; 4352 range.num_chars = num_chars_in_range; 4353 range.chardata_for_range = chardata_for_range; 4354 range.font_size = font_size; 4355 return stbtt_PackFontRanges(spc, fontdata, font_index, &range, 1); 4356 } 4357 4358 STBTT_DEF void stbtt_GetScaledFontVMetrics(const unsigned char *fontdata, int index, float size, float *ascent, float *descent, float *lineGap) 4359 { 4360 int i_ascent, i_descent, i_lineGap; 4361 float scale; 4362 stbtt_fontinfo info; 4363 stbtt_InitFont(&info, fontdata, stbtt_GetFontOffsetForIndex(fontdata, index)); 4364 scale = size > 0 ? stbtt_ScaleForPixelHeight(&info, size) : stbtt_ScaleForMappingEmToPixels(&info, -size); 4365 stbtt_GetFontVMetrics(&info, &i_ascent, &i_descent, &i_lineGap); 4366 *ascent = (float) i_ascent * scale; 4367 *descent = (float) i_descent * scale; 4368 *lineGap = (float) i_lineGap * scale; 4369 } 4370 4371 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) 4372 { 4373 float ipw = 1.0f / pw, iph = 1.0f / ph; 4374 const stbtt_packedchar *b = chardata + char_index; 4375 4376 if (align_to_integer) { 4377 float x = (float) STBTT_ifloor((*xpos + b->xoff) + 0.5f); 4378 float y = (float) STBTT_ifloor((*ypos + b->yoff) + 0.5f); 4379 q->x0 = x; 4380 q->y0 = y; 4381 q->x1 = x + b->xoff2 - b->xoff; 4382 q->y1 = y + b->yoff2 - b->yoff; 4383 } else { 4384 q->x0 = *xpos + b->xoff; 4385 q->y0 = *ypos + b->yoff; 4386 q->x1 = *xpos + b->xoff2; 4387 q->y1 = *ypos + b->yoff2; 4388 } 4389 4390 q->s0 = b->x0 * ipw; 4391 q->t0 = b->y0 * iph; 4392 q->s1 = b->x1 * ipw; 4393 q->t1 = b->y1 * iph; 4394 4395 *xpos += b->xadvance; 4396 } 4397 4398 ////////////////////////////////////////////////////////////////////////////// 4399 // 4400 // sdf computation 4401 // 4402 4403 #define STBTT_min(a,b) ((a) < (b) ? (a) : (b)) 4404 #define STBTT_max(a,b) ((a) < (b) ? (b) : (a)) 4405 4406 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]) 4407 { 4408 float q0perp = q0[1]*ray[0] - q0[0]*ray[1]; 4409 float q1perp = q1[1]*ray[0] - q1[0]*ray[1]; 4410 float q2perp = q2[1]*ray[0] - q2[0]*ray[1]; 4411 float roperp = orig[1]*ray[0] - orig[0]*ray[1]; 4412 4413 float a = q0perp - 2*q1perp + q2perp; 4414 float b = q1perp - q0perp; 4415 float c = q0perp - roperp; 4416 4417 float s0 = 0., s1 = 0.; 4418 int num_s = 0; 4419 4420 if (a != 0.0) { 4421 float discr = b*b - a*c; 4422 if (discr > 0.0) { 4423 float rcpna = -1 / a; 4424 float d = (float) STBTT_sqrt(discr); 4425 s0 = (b+d) * rcpna; 4426 s1 = (b-d) * rcpna; 4427 if (s0 >= 0.0 && s0 <= 1.0) 4428 num_s = 1; 4429 if (d > 0.0 && s1 >= 0.0 && s1 <= 1.0) { 4430 if (num_s == 0) s0 = s1; 4431 ++num_s; 4432 } 4433 } 4434 } else { 4435 // 2*b*s + c = 0 4436 // s = -c / (2*b) 4437 s0 = c / (-2 * b); 4438 if (s0 >= 0.0 && s0 <= 1.0) 4439 num_s = 1; 4440 } 4441 4442 if (num_s == 0) 4443 return 0; 4444 else { 4445 float rcp_len2 = 1 / (ray[0]*ray[0] + ray[1]*ray[1]); 4446 float rayn_x = ray[0] * rcp_len2, rayn_y = ray[1] * rcp_len2; 4447 4448 float q0d = q0[0]*rayn_x + q0[1]*rayn_y; 4449 float q1d = q1[0]*rayn_x + q1[1]*rayn_y; 4450 float q2d = q2[0]*rayn_x + q2[1]*rayn_y; 4451 float rod = orig[0]*rayn_x + orig[1]*rayn_y; 4452 4453 float q10d = q1d - q0d; 4454 float q20d = q2d - q0d; 4455 float q0rd = q0d - rod; 4456 4457 hits[0][0] = q0rd + s0*(2.0f - 2.0f*s0)*q10d + s0*s0*q20d; 4458 hits[0][1] = a*s0+b; 4459 4460 if (num_s > 1) { 4461 hits[1][0] = q0rd + s1*(2.0f - 2.0f*s1)*q10d + s1*s1*q20d; 4462 hits[1][1] = a*s1+b; 4463 return 2; 4464 } else { 4465 return 1; 4466 } 4467 } 4468 } 4469 4470 static int equal(float *a, float *b) 4471 { 4472 return (a[0] == b[0] && a[1] == b[1]); 4473 } 4474 4475 static int stbtt__compute_crossings_x(float x, float y, int nverts, stbtt_vertex *verts) 4476 { 4477 int i; 4478 float orig[2], ray[2] = { 1, 0 }; 4479 float y_frac; 4480 int winding = 0; 4481 4482 // make sure y never passes through a vertex of the shape 4483 y_frac = (float) STBTT_fmod(y, 1.0f); 4484 if (y_frac < 0.01f) 4485 y += 0.01f; 4486 else if (y_frac > 0.99f) 4487 y -= 0.01f; 4488 4489 orig[0] = x; 4490 orig[1] = y; 4491 4492 // test a ray from (-infinity,y) to (x,y) 4493 for (i=0; i < nverts; ++i) { 4494 if (verts[i].type == STBTT_vline) { 4495 int x0 = (int) verts[i-1].x, y0 = (int) verts[i-1].y; 4496 int x1 = (int) verts[i ].x, y1 = (int) verts[i ].y; 4497 if (y > STBTT_min(y0,y1) && y < STBTT_max(y0,y1) && x > STBTT_min(x0,x1)) { 4498 float x_inter = (y - y0) / (y1 - y0) * (x1-x0) + x0; 4499 if (x_inter < x) 4500 winding += (y0 < y1) ? 1 : -1; 4501 } 4502 } 4503 if (verts[i].type == STBTT_vcurve) { 4504 int x0 = (int) verts[i-1].x , y0 = (int) verts[i-1].y ; 4505 int x1 = (int) verts[i ].cx, y1 = (int) verts[i ].cy; 4506 int x2 = (int) verts[i ].x , y2 = (int) verts[i ].y ; 4507 int ax = STBTT_min(x0,STBTT_min(x1,x2)), ay = STBTT_min(y0,STBTT_min(y1,y2)); 4508 int by = STBTT_max(y0,STBTT_max(y1,y2)); 4509 if (y > ay && y < by && x > ax) { 4510 float q0[2],q1[2],q2[2]; 4511 float hits[2][2]; 4512 q0[0] = (float)x0; 4513 q0[1] = (float)y0; 4514 q1[0] = (float)x1; 4515 q1[1] = (float)y1; 4516 q2[0] = (float)x2; 4517 q2[1] = (float)y2; 4518 if (equal(q0,q1) || equal(q1,q2)) { 4519 x0 = (int)verts[i-1].x; 4520 y0 = (int)verts[i-1].y; 4521 x1 = (int)verts[i ].x; 4522 y1 = (int)verts[i ].y; 4523 if (y > STBTT_min(y0,y1) && y < STBTT_max(y0,y1) && x > STBTT_min(x0,x1)) { 4524 float x_inter = (y - y0) / (y1 - y0) * (x1-x0) + x0; 4525 if (x_inter < x) 4526 winding += (y0 < y1) ? 1 : -1; 4527 } 4528 } else { 4529 int num_hits = stbtt__ray_intersect_bezier(orig, ray, q0, q1, q2, hits); 4530 if (num_hits >= 1) 4531 if (hits[0][0] < 0) 4532 winding += (hits[0][1] < 0 ? -1 : 1); 4533 if (num_hits >= 2) 4534 if (hits[1][0] < 0) 4535 winding += (hits[1][1] < 0 ? -1 : 1); 4536 } 4537 } 4538 } 4539 } 4540 return winding; 4541 } 4542 4543 static float stbtt__cuberoot( float x ) 4544 { 4545 if (x<0) 4546 return -(float) STBTT_pow(-x,1.0f/3.0f); 4547 else 4548 return (float) STBTT_pow( x,1.0f/3.0f); 4549 } 4550 4551 // x^3 + a*x^2 + b*x + c = 0 4552 static int stbtt__solve_cubic(float a, float b, float c, float* r) 4553 { 4554 float s = -a / 3; 4555 float p = b - a*a / 3; 4556 float q = a * (2*a*a - 9*b) / 27 + c; 4557 float p3 = p*p*p; 4558 float d = q*q + 4*p3 / 27; 4559 if (d >= 0) { 4560 float z = (float) STBTT_sqrt(d); 4561 float u = (-q + z) / 2; 4562 float v = (-q - z) / 2; 4563 u = stbtt__cuberoot(u); 4564 v = stbtt__cuberoot(v); 4565 r[0] = s + u + v; 4566 return 1; 4567 } else { 4568 float u = (float) STBTT_sqrt(-p/3); 4569 float v = (float) STBTT_acos(-STBTT_sqrt(-27/p3) * q / 2) / 3; // p3 must be negative, since d is negative 4570 float m = (float) STBTT_cos(v); 4571 float n = (float) STBTT_cos(v-3.141592/2)*1.732050808f; 4572 r[0] = s + u * 2 * m; 4573 r[1] = s - u * (m + n); 4574 r[2] = s - u * (m - n); 4575 4576 //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? 4577 //STBTT_assert( STBTT_fabs(((r[1]+a)*r[1]+b)*r[1]+c) < 0.05f); 4578 //STBTT_assert( STBTT_fabs(((r[2]+a)*r[2]+b)*r[2]+c) < 0.05f); 4579 return 3; 4580 } 4581 } 4582 4583 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) 4584 { 4585 float scale_x = scale, scale_y = scale; 4586 int ix0,iy0,ix1,iy1; 4587 int w,h; 4588 unsigned char *data; 4589 4590 if (scale == 0) return NULL; 4591 4592 stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale, scale, 0.0f,0.0f, &ix0,&iy0,&ix1,&iy1); 4593 4594 // if empty, return NULL 4595 if (ix0 == ix1 || iy0 == iy1) 4596 return NULL; 4597 4598 ix0 -= padding; 4599 iy0 -= padding; 4600 ix1 += padding; 4601 iy1 += padding; 4602 4603 w = (ix1 - ix0); 4604 h = (iy1 - iy0); 4605 4606 if (width ) *width = w; 4607 if (height) *height = h; 4608 if (xoff ) *xoff = ix0; 4609 if (yoff ) *yoff = iy0; 4610 4611 // invert for y-downwards bitmaps 4612 scale_y = -scale_y; 4613 4614 { 4615 int x,y,i,j; 4616 float *precompute; 4617 stbtt_vertex *verts; 4618 int num_verts = stbtt_GetGlyphShape(info, glyph, &verts); 4619 data = (unsigned char *) STBTT_malloc(w * h, info->userdata); 4620 precompute = (float *) STBTT_malloc(num_verts * sizeof(float), info->userdata); 4621 4622 for (i=0,j=num_verts-1; i < num_verts; j=i++) { 4623 if (verts[i].type == STBTT_vline) { 4624 float x0 = verts[i].x*scale_x, y0 = verts[i].y*scale_y; 4625 float x1 = verts[j].x*scale_x, y1 = verts[j].y*scale_y; 4626 float dist = (float) STBTT_sqrt((x1-x0)*(x1-x0) + (y1-y0)*(y1-y0)); 4627 precompute[i] = (dist == 0) ? 0.0f : 1.0f / dist; 4628 } else if (verts[i].type == STBTT_vcurve) { 4629 float x2 = verts[j].x *scale_x, y2 = verts[j].y *scale_y; 4630 float x1 = verts[i].cx*scale_x, y1 = verts[i].cy*scale_y; 4631 float x0 = verts[i].x *scale_x, y0 = verts[i].y *scale_y; 4632 float bx = x0 - 2*x1 + x2, by = y0 - 2*y1 + y2; 4633 float len2 = bx*bx + by*by; 4634 if (len2 != 0.0f) 4635 precompute[i] = 1.0f / (bx*bx + by*by); 4636 else 4637 precompute[i] = 0.0f; 4638 } else 4639 precompute[i] = 0.0f; 4640 } 4641 4642 for (y=iy0; y < iy1; ++y) { 4643 for (x=ix0; x < ix1; ++x) { 4644 float val; 4645 float min_dist = 999999.0f; 4646 float sx = (float) x + 0.5f; 4647 float sy = (float) y + 0.5f; 4648 float x_gspace = (sx / scale_x); 4649 float y_gspace = (sy / scale_y); 4650 4651 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 4652 4653 for (i=0; i < num_verts; ++i) { 4654 float x0 = verts[i].x*scale_x, y0 = verts[i].y*scale_y; 4655 4656 if (verts[i].type == STBTT_vline && precompute[i] != 0.0f) { 4657 float x1 = verts[i-1].x*scale_x, y1 = verts[i-1].y*scale_y; 4658 4659 float dist,dist2 = (x0-sx)*(x0-sx) + (y0-sy)*(y0-sy); 4660 if (dist2 < min_dist*min_dist) 4661 min_dist = (float) STBTT_sqrt(dist2); 4662 4663 // coarse culling against bbox 4664 //if (sx > STBTT_min(x0,x1)-min_dist && sx < STBTT_max(x0,x1)+min_dist && 4665 // sy > STBTT_min(y0,y1)-min_dist && sy < STBTT_max(y0,y1)+min_dist) 4666 dist = (float) STBTT_fabs((x1-x0)*(y0-sy) - (y1-y0)*(x0-sx)) * precompute[i]; 4667 STBTT_assert(i != 0); 4668 if (dist < min_dist) { 4669 // check position along line 4670 // x' = x0 + t*(x1-x0), y' = y0 + t*(y1-y0) 4671 // minimize (x'-sx)*(x'-sx)+(y'-sy)*(y'-sy) 4672 float dx = x1-x0, dy = y1-y0; 4673 float px = x0-sx, py = y0-sy; 4674 // 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 4675 // derivative: 2*px*dx + 2*py*dy + (2*dx*dx+2*dy*dy)*t, set to 0 and solve 4676 float t = -(px*dx + py*dy) / (dx*dx + dy*dy); 4677 if (t >= 0.0f && t <= 1.0f) 4678 min_dist = dist; 4679 } 4680 } else if (verts[i].type == STBTT_vcurve) { 4681 float x2 = verts[i-1].x *scale_x, y2 = verts[i-1].y *scale_y; 4682 float x1 = verts[i ].cx*scale_x, y1 = verts[i ].cy*scale_y; 4683 float box_x0 = STBTT_min(STBTT_min(x0,x1),x2); 4684 float box_y0 = STBTT_min(STBTT_min(y0,y1),y2); 4685 float box_x1 = STBTT_max(STBTT_max(x0,x1),x2); 4686 float box_y1 = STBTT_max(STBTT_max(y0,y1),y2); 4687 // coarse culling against bbox to avoid computing cubic unnecessarily 4688 if (sx > box_x0-min_dist && sx < box_x1+min_dist && sy > box_y0-min_dist && sy < box_y1+min_dist) { 4689 int num=0; 4690 float ax = x1-x0, ay = y1-y0; 4691 float bx = x0 - 2*x1 + x2, by = y0 - 2*y1 + y2; 4692 float mx = x0 - sx, my = y0 - sy; 4693 float res[3] = {0.f,0.f,0.f}; 4694 float px,py,t,it,dist2; 4695 float a_inv = precompute[i]; 4696 if (a_inv == 0.0) { // if a_inv is 0, it's 2nd degree so use quadratic formula 4697 float a = 3*(ax*bx + ay*by); 4698 float b = 2*(ax*ax + ay*ay) + (mx*bx+my*by); 4699 float c = mx*ax+my*ay; 4700 if (a == 0.0) { // if a is 0, it's linear 4701 if (b != 0.0) { 4702 res[num++] = -c/b; 4703 } 4704 } else { 4705 float discriminant = b*b - 4*a*c; 4706 if (discriminant < 0) 4707 num = 0; 4708 else { 4709 float root = (float) STBTT_sqrt(discriminant); 4710 res[0] = (-b - root)/(2*a); 4711 res[1] = (-b + root)/(2*a); 4712 num = 2; // don't bother distinguishing 1-solution case, as code below will still work 4713 } 4714 } 4715 } else { 4716 float b = 3*(ax*bx + ay*by) * a_inv; // could precompute this as it doesn't depend on sample point 4717 float c = (2*(ax*ax + ay*ay) + (mx*bx+my*by)) * a_inv; 4718 float d = (mx*ax+my*ay) * a_inv; 4719 num = stbtt__solve_cubic(b, c, d, res); 4720 } 4721 dist2 = (x0-sx)*(x0-sx) + (y0-sy)*(y0-sy); 4722 if (dist2 < min_dist*min_dist) 4723 min_dist = (float) STBTT_sqrt(dist2); 4724 4725 if (num >= 1 && res[0] >= 0.0f && res[0] <= 1.0f) { 4726 t = res[0], it = 1.0f - t; 4727 px = it*it*x0 + 2*t*it*x1 + t*t*x2; 4728 py = it*it*y0 + 2*t*it*y1 + t*t*y2; 4729 dist2 = (px-sx)*(px-sx) + (py-sy)*(py-sy); 4730 if (dist2 < min_dist * min_dist) 4731 min_dist = (float) STBTT_sqrt(dist2); 4732 } 4733 if (num >= 2 && res[1] >= 0.0f && res[1] <= 1.0f) { 4734 t = res[1], it = 1.0f - t; 4735 px = it*it*x0 + 2*t*it*x1 + t*t*x2; 4736 py = it*it*y0 + 2*t*it*y1 + t*t*y2; 4737 dist2 = (px-sx)*(px-sx) + (py-sy)*(py-sy); 4738 if (dist2 < min_dist * min_dist) 4739 min_dist = (float) STBTT_sqrt(dist2); 4740 } 4741 if (num >= 3 && res[2] >= 0.0f && res[2] <= 1.0f) { 4742 t = res[2], it = 1.0f - t; 4743 px = it*it*x0 + 2*t*it*x1 + t*t*x2; 4744 py = it*it*y0 + 2*t*it*y1 + t*t*y2; 4745 dist2 = (px-sx)*(px-sx) + (py-sy)*(py-sy); 4746 if (dist2 < min_dist * min_dist) 4747 min_dist = (float) STBTT_sqrt(dist2); 4748 } 4749 } 4750 } 4751 } 4752 if (winding == 0) 4753 min_dist = -min_dist; // if outside the shape, value is negative 4754 val = onedge_value + pixel_dist_scale * min_dist; 4755 if (val < 0) 4756 val = 0; 4757 else if (val > 255) 4758 val = 255; 4759 data[(y-iy0)*w+(x-ix0)] = (unsigned char) val; 4760 } 4761 } 4762 STBTT_free(precompute, info->userdata); 4763 STBTT_free(verts, info->userdata); 4764 } 4765 return data; 4766 } 4767 4768 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) 4769 { 4770 return stbtt_GetGlyphSDF(info, scale, stbtt_FindGlyphIndex(info, codepoint), padding, onedge_value, pixel_dist_scale, width, height, xoff, yoff); 4771 } 4772 4773 STBTT_DEF void stbtt_FreeSDF(unsigned char *bitmap, void *userdata) 4774 { 4775 STBTT_free(bitmap, userdata); 4776 } 4777 4778 ////////////////////////////////////////////////////////////////////////////// 4779 // 4780 // font name matching -- recommended not to use this 4781 // 4782 4783 // check if a utf8 string contains a prefix which is the utf16 string; if so return length of matching utf8 string 4784 static stbtt_int32 stbtt__CompareUTF8toUTF16_bigendian_prefix(stbtt_uint8 *s1, stbtt_int32 len1, stbtt_uint8 *s2, stbtt_int32 len2) 4785 { 4786 stbtt_int32 i=0; 4787 4788 // convert utf16 to utf8 and compare the results while converting 4789 while (len2) { 4790 stbtt_uint16 ch = s2[0]*256 + s2[1]; 4791 if (ch < 0x80) { 4792 if (i >= len1) return -1; 4793 if (s1[i++] != ch) return -1; 4794 } else if (ch < 0x800) { 4795 if (i+1 >= len1) return -1; 4796 if (s1[i++] != 0xc0 + (ch >> 6)) return -1; 4797 if (s1[i++] != 0x80 + (ch & 0x3f)) return -1; 4798 } else if (ch >= 0xd800 && ch < 0xdc00) { 4799 stbtt_uint32 c; 4800 stbtt_uint16 ch2 = s2[2]*256 + s2[3]; 4801 if (i+3 >= len1) return -1; 4802 c = ((ch - 0xd800) << 10) + (ch2 - 0xdc00) + 0x10000; 4803 if (s1[i++] != 0xf0 + (c >> 18)) return -1; 4804 if (s1[i++] != 0x80 + ((c >> 12) & 0x3f)) return -1; 4805 if (s1[i++] != 0x80 + ((c >> 6) & 0x3f)) return -1; 4806 if (s1[i++] != 0x80 + ((c ) & 0x3f)) return -1; 4807 s2 += 2; // plus another 2 below 4808 len2 -= 2; 4809 } else if (ch >= 0xdc00 && ch < 0xe000) { 4810 return -1; 4811 } else { 4812 if (i+2 >= len1) return -1; 4813 if (s1[i++] != 0xe0 + (ch >> 12)) return -1; 4814 if (s1[i++] != 0x80 + ((ch >> 6) & 0x3f)) return -1; 4815 if (s1[i++] != 0x80 + ((ch ) & 0x3f)) return -1; 4816 } 4817 s2 += 2; 4818 len2 -= 2; 4819 } 4820 return i; 4821 } 4822 4823 static int stbtt_CompareUTF8toUTF16_bigendian_internal(char *s1, int len1, char *s2, int len2) 4824 { 4825 return len1 == stbtt__CompareUTF8toUTF16_bigendian_prefix((stbtt_uint8*) s1, len1, (stbtt_uint8*) s2, len2); 4826 } 4827 4828 // returns results in whatever encoding you request... but note that 2-byte encodings 4829 // will be BIG-ENDIAN... use stbtt_CompareUTF8toUTF16_bigendian() to compare 4830 STBTT_DEF const char *stbtt_GetFontNameString(const stbtt_fontinfo *font, int *length, int platformID, int encodingID, int languageID, int nameID) 4831 { 4832 stbtt_int32 i,count,stringOffset; 4833 stbtt_uint8 *fc = font->data; 4834 stbtt_uint32 offset = font->fontstart; 4835 stbtt_uint32 nm = stbtt__find_table(fc, offset, "name"); 4836 if (!nm) return NULL; 4837 4838 count = ttUSHORT(fc+nm+2); 4839 stringOffset = nm + ttUSHORT(fc+nm+4); 4840 for (i=0; i < count; ++i) { 4841 stbtt_uint32 loc = nm + 6 + 12 * i; 4842 if (platformID == ttUSHORT(fc+loc+0) && encodingID == ttUSHORT(fc+loc+2) 4843 && languageID == ttUSHORT(fc+loc+4) && nameID == ttUSHORT(fc+loc+6)) { 4844 *length = ttUSHORT(fc+loc+8); 4845 return (const char *) (fc+stringOffset+ttUSHORT(fc+loc+10)); 4846 } 4847 } 4848 return NULL; 4849 } 4850 4851 static int stbtt__matchpair(stbtt_uint8 *fc, stbtt_uint32 nm, stbtt_uint8 *name, stbtt_int32 nlen, stbtt_int32 target_id, stbtt_int32 next_id) 4852 { 4853 stbtt_int32 i; 4854 stbtt_int32 count = ttUSHORT(fc+nm+2); 4855 stbtt_int32 stringOffset = nm + ttUSHORT(fc+nm+4); 4856 4857 for (i=0; i < count; ++i) { 4858 stbtt_uint32 loc = nm + 6 + 12 * i; 4859 stbtt_int32 id = ttUSHORT(fc+loc+6); 4860 if (id == target_id) { 4861 // find the encoding 4862 stbtt_int32 platform = ttUSHORT(fc+loc+0), encoding = ttUSHORT(fc+loc+2), language = ttUSHORT(fc+loc+4); 4863 4864 // is this a Unicode encoding? 4865 if (platform == 0 || (platform == 3 && encoding == 1) || (platform == 3 && encoding == 10)) { 4866 stbtt_int32 slen = ttUSHORT(fc+loc+8); 4867 stbtt_int32 off = ttUSHORT(fc+loc+10); 4868 4869 // check if there's a prefix match 4870 stbtt_int32 matchlen = stbtt__CompareUTF8toUTF16_bigendian_prefix(name, nlen, fc+stringOffset+off,slen); 4871 if (matchlen >= 0) { 4872 // check for target_id+1 immediately following, with same encoding & language 4873 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) { 4874 slen = ttUSHORT(fc+loc+12+8); 4875 off = ttUSHORT(fc+loc+12+10); 4876 if (slen == 0) { 4877 if (matchlen == nlen) 4878 return 1; 4879 } else if (matchlen < nlen && name[matchlen] == ' ') { 4880 ++matchlen; 4881 if (stbtt_CompareUTF8toUTF16_bigendian_internal((char*) (name+matchlen), nlen-matchlen, (char*)(fc+stringOffset+off),slen)) 4882 return 1; 4883 } 4884 } else { 4885 // if nothing immediately following 4886 if (matchlen == nlen) 4887 return 1; 4888 } 4889 } 4890 } 4891 4892 // @TODO handle other encodings 4893 } 4894 } 4895 return 0; 4896 } 4897 4898 static int stbtt__matches(stbtt_uint8 *fc, stbtt_uint32 offset, stbtt_uint8 *name, stbtt_int32 flags) 4899 { 4900 stbtt_int32 nlen = (stbtt_int32) STBTT_strlen((char *) name); 4901 stbtt_uint32 nm,hd; 4902 if (!stbtt__isfont(fc+offset)) return 0; 4903 4904 // check italics/bold/underline flags in macStyle... 4905 if (flags) { 4906 hd = stbtt__find_table(fc, offset, "head"); 4907 if ((ttUSHORT(fc+hd+44) & 7) != (flags & 7)) return 0; 4908 } 4909 4910 nm = stbtt__find_table(fc, offset, "name"); 4911 if (!nm) return 0; 4912 4913 if (flags) { 4914 // if we checked the macStyle flags, then just check the family and ignore the subfamily 4915 if (stbtt__matchpair(fc, nm, name, nlen, 16, -1)) return 1; 4916 if (stbtt__matchpair(fc, nm, name, nlen, 1, -1)) return 1; 4917 if (stbtt__matchpair(fc, nm, name, nlen, 3, -1)) return 1; 4918 } else { 4919 if (stbtt__matchpair(fc, nm, name, nlen, 16, 17)) return 1; 4920 if (stbtt__matchpair(fc, nm, name, nlen, 1, 2)) return 1; 4921 if (stbtt__matchpair(fc, nm, name, nlen, 3, -1)) return 1; 4922 } 4923 4924 return 0; 4925 } 4926 4927 static int stbtt_FindMatchingFont_internal(unsigned char *font_collection, char *name_utf8, stbtt_int32 flags) 4928 { 4929 stbtt_int32 i; 4930 for (i=0;;++i) { 4931 stbtt_int32 off = stbtt_GetFontOffsetForIndex(font_collection, i); 4932 if (off < 0) return off; 4933 if (stbtt__matches((stbtt_uint8 *) font_collection, off, (stbtt_uint8*) name_utf8, flags)) 4934 return off; 4935 } 4936 } 4937 4938 #if defined(__GNUC__) || defined(__clang__) 4939 #pragma GCC diagnostic push 4940 #pragma GCC diagnostic ignored "-Wcast-qual" 4941 #endif 4942 4943 STBTT_DEF int stbtt_BakeFontBitmap(const unsigned char *data, int offset, 4944 float pixel_height, unsigned char *pixels, int pw, int ph, 4945 int first_char, int num_chars, stbtt_bakedchar *chardata) 4946 { 4947 return stbtt_BakeFontBitmap_internal((unsigned char *) data, offset, pixel_height, pixels, pw, ph, first_char, num_chars, chardata); 4948 } 4949 4950 STBTT_DEF int stbtt_GetFontOffsetForIndex(const unsigned char *data, int index) 4951 { 4952 return stbtt_GetFontOffsetForIndex_internal((unsigned char *) data, index); 4953 } 4954 4955 STBTT_DEF int stbtt_GetNumberOfFonts(const unsigned char *data) 4956 { 4957 return stbtt_GetNumberOfFonts_internal((unsigned char *) data); 4958 } 4959 4960 STBTT_DEF int stbtt_InitFont(stbtt_fontinfo *info, const unsigned char *data, int offset) 4961 { 4962 return stbtt_InitFont_internal(info, (unsigned char *) data, offset); 4963 } 4964 4965 STBTT_DEF int stbtt_FindMatchingFont(const unsigned char *fontdata, const char *name, int flags) 4966 { 4967 return stbtt_FindMatchingFont_internal((unsigned char *) fontdata, (char *) name, flags); 4968 } 4969 4970 STBTT_DEF int stbtt_CompareUTF8toUTF16_bigendian(const char *s1, int len1, const char *s2, int len2) 4971 { 4972 return stbtt_CompareUTF8toUTF16_bigendian_internal((char *) s1, len1, (char *) s2, len2); 4973 } 4974 4975 #if defined(__GNUC__) || defined(__clang__) 4976 #pragma GCC diagnostic pop 4977 #endif 4978 4979 #endif // STB_TRUETYPE_IMPLEMENTATION 4980 4981 4982 // FULL VERSION HISTORY 4983 // 4984 // 1.25 (2021-07-11) many fixes 4985 // 1.24 (2020-02-05) fix warning 4986 // 1.23 (2020-02-02) query SVG data for glyphs; query whole kerning table (but only kern not GPOS) 4987 // 1.22 (2019-08-11) minimize missing-glyph duplication; fix kerning if both 'GPOS' and 'kern' are defined 4988 // 1.21 (2019-02-25) fix warning 4989 // 1.20 (2019-02-07) PackFontRange skips missing codepoints; GetScaleFontVMetrics() 4990 // 1.19 (2018-02-11) OpenType GPOS kerning (horizontal only), STBTT_fmod 4991 // 1.18 (2018-01-29) add missing function 4992 // 1.17 (2017-07-23) make more arguments const; doc fix 4993 // 1.16 (2017-07-12) SDF support 4994 // 1.15 (2017-03-03) make more arguments const 4995 // 1.14 (2017-01-16) num-fonts-in-TTC function 4996 // 1.13 (2017-01-02) support OpenType fonts, certain Apple fonts 4997 // 1.12 (2016-10-25) suppress warnings about casting away const with -Wcast-qual 4998 // 1.11 (2016-04-02) fix unused-variable warning 4999 // 1.10 (2016-04-02) allow user-defined fabs() replacement 5000 // fix memory leak if fontsize=0.0 5001 // fix warning from duplicate typedef 5002 // 1.09 (2016-01-16) warning fix; avoid crash on outofmem; use alloc userdata for PackFontRanges 5003 // 1.08 (2015-09-13) document stbtt_Rasterize(); fixes for vertical & horizontal edges 5004 // 1.07 (2015-08-01) allow PackFontRanges to accept arrays of sparse codepoints; 5005 // allow PackFontRanges to pack and render in separate phases; 5006 // fix stbtt_GetFontOFfsetForIndex (never worked for non-0 input?); 5007 // fixed an assert() bug in the new rasterizer 5008 // replace assert() with STBTT_assert() in new rasterizer 5009 // 1.06 (2015-07-14) performance improvements (~35% faster on x86 and x64 on test machine) 5010 // also more precise AA rasterizer, except if shapes overlap 5011 // remove need for STBTT_sort 5012 // 1.05 (2015-04-15) fix misplaced definitions for STBTT_STATIC 5013 // 1.04 (2015-04-15) typo in example 5014 // 1.03 (2015-04-12) STBTT_STATIC, fix memory leak in new packing, various fixes 5015 // 1.02 (2014-12-10) fix various warnings & compile issues w/ stb_rect_pack, C++ 5016 // 1.01 (2014-12-08) fix subpixel position when oversampling to exactly match 5017 // non-oversampled; STBTT_POINT_SIZE for packed case only 5018 // 1.00 (2014-12-06) add new PackBegin etc. API, w/ support for oversampling 5019 // 0.99 (2014-09-18) fix multiple bugs with subpixel rendering (ryg) 5020 // 0.9 (2014-08-07) support certain mac/iOS fonts without an MS platformID 5021 // 0.8b (2014-07-07) fix a warning 5022 // 0.8 (2014-05-25) fix a few more warnings 5023 // 0.7 (2013-09-25) bugfix: subpixel glyph bug fixed in 0.5 had come back 5024 // 0.6c (2012-07-24) improve documentation 5025 // 0.6b (2012-07-20) fix a few more warnings 5026 // 0.6 (2012-07-17) fix warnings; added stbtt_ScaleForMappingEmToPixels, 5027 // stbtt_GetFontBoundingBox, stbtt_IsGlyphEmpty 5028 // 0.5 (2011-12-09) bugfixes: 5029 // subpixel glyph renderer computed wrong bounding box 5030 // first vertex of shape can be off-curve (FreeSans) 5031 // 0.4b (2011-12-03) fixed an error in the font baking example 5032 // 0.4 (2011-12-01) kerning, subpixel rendering (tor) 5033 // bugfixes for: 5034 // codepoint-to-glyph conversion using table fmt=12 5035 // codepoint-to-glyph conversion using table fmt=4 5036 // stbtt_GetBakedQuad with non-square texture (Zer) 5037 // updated Hello World! sample to use kerning and subpixel 5038 // fixed some warnings 5039 // 0.3 (2009-06-24) cmap fmt=12, compound shapes (MM) 5040 // userdata, malloc-from-userdata, non-zero fill (stb) 5041 // 0.2 (2009-03-11) Fix unsigned/signed char warnings 5042 // 0.1 (2009-03-09) First public release 5043 // 5044 5045 /* 5046 ------------------------------------------------------------------------------ 5047 This software is available under 2 licenses -- choose whichever you prefer. 5048 ------------------------------------------------------------------------------ 5049 ALTERNATIVE A - MIT License 5050 Copyright (c) 2017 Sean Barrett 5051 Permission is hereby granted, free of charge, to any person obtaining a copy of 5052 this software and associated documentation files (the "Software"), to deal in 5053 the Software without restriction, including without limitation the rights to 5054 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 5055 of the Software, and to permit persons to whom the Software is furnished to do 5056 so, subject to the following conditions: 5057 The above copyright notice and this permission notice shall be included in all 5058 copies or substantial portions of the Software. 5059 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 5060 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 5061 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 5062 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 5063 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 5064 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 5065 SOFTWARE. 5066 ------------------------------------------------------------------------------ 5067 ALTERNATIVE B - Public Domain (www.unlicense.org) 5068 This is free and unencumbered software released into the public domain. 5069 Anyone is free to copy, modify, publish, use, compile, sell, or distribute this 5070 software, either in source code form or as a compiled binary, for any purpose, 5071 commercial or non-commercial, and by any means. 5072 In jurisdictions that recognize copyright laws, the author or authors of this 5073 software dedicate any and all copyright interest in the software to the public 5074 domain. We make this dedication for the benefit of the public at large and to 5075 the detriment of our heirs and successors. We intend this dedication to be an 5076 overt act of relinquishment in perpetuity of all present and future rights to 5077 this software under copyright law. 5078 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 5079 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 5080 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 5081 AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 5082 ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 5083 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 5084 ------------------------------------------------------------------------------ 5085 */