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