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