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