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