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