1 /* 2 * stb_truetype - v0.6c - Public Domain 3 * 4 * authored from 2009-2012 by Sean Barrett / RAD Game Tools 5 * 6 */ 7 module imgui.stdb_truetype; 8 9 import core.stdc.stdlib; 10 import core.stdc..string; 11 12 import std.exception; 13 import std.math; 14 15 import imgui.engine; 16 import imgui.gl3_renderer; 17 18 package: 19 20 alias ubyte stbtt_uint8; 21 alias byte stbtt_int8; 22 alias ushort stbtt_uint16; 23 alias short stbtt_int16; 24 alias uint stbtt_uint32; 25 alias int stbtt_int32; 26 27 alias STBTT_sort = qsort; 28 29 int STBTT_ifloor(X)(X x) { return cast(int)floor(x); } 30 int STBTT_iceil(X)(X x) { return cast(int)ceil(x); } 31 32 alias STBTT_malloc = imguimalloc; 33 alias STBTT_free = imguifree; 34 35 alias STBTT_assert = enforce; 36 37 alias STBTT_memcpy = memcpy; 38 alias STBTT_memset = memset; 39 40 ////////////////////////////////////////////////////////////////////////////// 41 // 42 // TEXTURE BAKING API 43 // 44 // If you use this API, you only have to call two functions ever. 45 // 46 struct stbtt_bakedchar 47 { 48 ushort x0, y0, x1, y1; // coordinates of bbox in bitmap 49 float xoff, yoff, xadvance; 50 } 51 52 int stbtt_BakeFontBitmap(const(ubyte)* data, int offset, // font location (use offset=0 for plain .ttf) 53 float pixel_height, // height of font in pixels 54 ubyte* pixels, int pw, int ph, // bitmap to be filled in 55 int first_char, int num_chars, // characters to bake 56 stbtt_bakedchar* chardata); // you allocate this, it's num_chars long 57 // if return is positive, the first unused row of the bitmap 58 // if return is negative, returns the negative of the number of characters that fit 59 // if return is 0, no characters fit and no rows were used 60 // This uses a very crappy packing. 61 62 struct stbtt_aligned_quad 63 { 64 float x0, y0, s0, t0; // top-left 65 float x1, y1, s1, t1; // bottom-right 66 } 67 68 void stbtt_GetBakedQuad(stbtt_bakedchar* chardata, int pw, int ph, // same data as above 69 int char_index, // character to display 70 float* xpos, float* ypos, // pointers to current position in screen pixel space 71 stbtt_aligned_quad* q, // output: quad to draw 72 int opengl_fillrule); // true if opengl fill rule; false if DX9 or earlier 73 // Call GetBakedQuad with char_index = 'character - first_char', and it 74 // creates the quad you need to draw and advances the current position. 75 // 76 // The coordinate system used assumes y increases downwards. 77 // 78 // Characters will extend both above and below the current position; 79 // see discussion of "BASELINE" above. 80 // 81 // It's inefficient; you might want to c&p it and optimize it. 82 83 ////////////////////////////////////////////////////////////////////////////// 84 // 85 // FONT LOADING 86 // 87 // 88 89 int stbtt_GetFontOffsetForIndex(const(ubyte)* data, int index); 90 91 // Each .ttf/.ttc file may have more than one font. Each font has a sequential 92 // index number starting from 0. Call this function to get the font offset for 93 // a given index; it returns -1 if the index is out of range. A regular .ttf 94 // file will only define one font and it always be at offset 0, so it will 95 // return '0' for index 0, and -1 for all other indices. You can just skip 96 // this step if you know it's that kind of font. 97 98 // The following structure is defined publically so you can declare one on 99 // the stack or as a global or etc, but you should treat it as opaque. 100 struct stbtt_fontinfo 101 { 102 void* userdata; 103 ubyte* data; // pointer to .ttf file 104 int fontstart; // offset of start of font 105 106 int numGlyphs; // number of glyphs, needed for range checking 107 108 int loca, head, glyf, hhea, hmtx, kern; // table locations as offset from start of .ttf 109 int index_map; // a cmap mapping for our chosen character encoding 110 int indexToLocFormat; // format needed to map from glyph index to glyph 111 } 112 113 int stbtt_InitFont(stbtt_fontinfo* info, const(ubyte)* data, int offset); 114 115 // Given an offset into the file that defines a font, this function builds 116 // the necessary cached info for the rest of the system. You must allocate 117 // the stbtt_fontinfo yourself, and stbtt_InitFont will fill it out. You don't 118 // need to do anything special to free it, because the contents are pure 119 // value data with no additional data structures. Returns 0 on failure. 120 121 ////////////////////////////////////////////////////////////////////////////// 122 // 123 // CHARACTER TO GLYPH-INDEX CONVERSIOn 124 125 int stbtt_FindGlyphIndex(const(stbtt_fontinfo)* info, int unicode_codepoint); 126 127 // If you're going to perform multiple operations on the same character 128 // and you want a speed-up, call this function with the character you're 129 // going to process, then use glyph-based functions instead of the 130 // codepoint-based functions. 131 132 ////////////////////////////////////////////////////////////////////////////// 133 // 134 // CHARACTER PROPERTIES 135 // 136 137 float stbtt_ScaleForPixelHeight(const(stbtt_fontinfo)* info, float pixels); 138 139 // computes a scale factor to produce a font whose "height" is 'pixels' tall. 140 // Height is measured as the distance from the highest ascender to the lowest 141 // descender; in other words, it's equivalent to calling stbtt_GetFontVMetrics 142 // and computing: 143 // scale = pixels / (ascent - descent) 144 // so if you prefer to measure height by the ascent only, use a similar calculation. 145 146 float stbtt_ScaleForMappingEmToPixels(const(stbtt_fontinfo)* info, float pixels); 147 148 // computes a scale factor to produce a font whose EM size is mapped to 149 // 'pixels' tall. This is probably what traditional APIs compute, but 150 // I'm not positive. 151 152 void stbtt_GetFontVMetrics(const(stbtt_fontinfo)* info, int* ascent, int* descent, int* lineGap); 153 154 // ascent is the coordinate above the baseline the font extends; descent 155 // is the coordinate below the baseline the font extends (i.e. it is typically negative) 156 // lineGap is the spacing between one row's descent and the next row's ascent... 157 // so you should advance the vertical position by "*ascent - *descent + *lineGap" 158 // these are expressed in unscaled coordinates, so you must multiply by 159 // the scale factor for a given size 160 161 void stbtt_GetFontBoundingBox(const(stbtt_fontinfo)* info, int* x0, int* y0, int* x1, int* y1); 162 163 // the bounding box around all possible characters 164 165 void stbtt_GetCodepointHMetrics(const(stbtt_fontinfo)* info, int codepoint, int* advanceWidth, int* leftSideBearing); 166 167 // leftSideBearing is the offset from the current horizontal position to the left edge of the character 168 // advanceWidth is the offset from the current horizontal position to the next horizontal position 169 // these are expressed in unscaled coordinates 170 171 int stbtt_GetCodepointKernAdvance(const(stbtt_fontinfo)* info, int ch1, int ch2); 172 173 // an additional amount to add to the 'advance' value between ch1 and ch2 174 // @TODO; for now always returns 0! 175 176 int stbtt_GetCodepointBox(const(stbtt_fontinfo)* info, int codepoint, int* x0, int* y0, int* x1, int* y1); 177 178 // Gets the bounding box of the visible part of the glyph, in unscaled coordinates 179 180 void stbtt_GetGlyphHMetrics(const(stbtt_fontinfo)* info, int glyph_index, int* advanceWidth, int* leftSideBearing); 181 int stbtt_GetGlyphKernAdvance(const(stbtt_fontinfo)* info, int glyph1, int glyph2); 182 int stbtt_GetGlyphBox(const(stbtt_fontinfo)* info, int glyph_index, int* x0, int* y0, int* x1, int* y1); 183 184 // as above, but takes one or more glyph indices for greater efficiency 185 186 // GLYPH SHAPES 187 enum 188 { 189 STBTT_vmove=1, 190 STBTT_vline, 191 STBTT_vcurve 192 } 193 194 // (we share this with other code at RAD) 195 alias stbtt_vertex_type = short; // can't use stbtt_int16 because that's not visible in the header file 196 197 struct stbtt_vertex 198 { 199 stbtt_vertex_type x, y, cx, cy; 200 ubyte type, padding; 201 } 202 203 int stbtt_IsGlyphEmpty(const(stbtt_fontinfo)* info, int glyph_index); 204 205 // returns non-zero if nothing is drawn for this glyph 206 207 int stbtt_GetCodepointShape(const(stbtt_fontinfo)* info, int unicode_codepoint, stbtt_vertex** vertices); 208 int stbtt_GetGlyphShape(const(stbtt_fontinfo)* info, int glyph_index, stbtt_vertex** vertices); 209 210 // returns # of vertices and fills *vertices with the pointer to them 211 // these are expressed in "unscaled" coordinates 212 213 void stbtt_FreeShape(const(stbtt_fontinfo)* info, stbtt_vertex* vertices); 214 215 // frees the data allocated above 216 217 ////////////////////////////////////////////////////////////////////////////// 218 // 219 // BITMAP RENDERING 220 // 221 222 void stbtt_FreeBitmap(ubyte* bitmap, void* userdata); 223 224 // frees the bitmap allocated below 225 226 ubyte* stbtt_GetCodepointBitmap(const(stbtt_fontinfo)* info, float scale_x, float scale_y, int codepoint, int* width, int* height, int* xoff, int* yoff); 227 228 // allocates a large-enough single-channel 8bpp bitmap and renders the 229 // specified character/glyph at the specified scale into it, with 230 // antialiasing. 0 is no coverage (transparent), 255 is fully covered (opaque). 231 // *width & *height are filled out with the width & height of the bitmap, 232 // which is stored left-to-right, top-to-bottom. 233 // 234 // xoff/yoff are the offset it pixel space from the glyph origin to the top-left of the bitmap 235 236 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); 237 238 // the same as stbtt_GetCodepoitnBitmap, but you can specify a subpixel 239 // shift for the character 240 241 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); 242 243 // the same as stbtt_GetCodepointBitmap, but you pass in storage for the bitmap 244 // in the form of 'output', with row spacing of 'out_stride' bytes. the bitmap 245 // is clipped to out_w/out_h bytes. Call stbtt_GetCodepointBitmapBox to get the 246 // width and height and positioning info for it first. 247 248 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); 249 250 // same as stbtt_MakeCodepointBitmap, but you can specify a subpixel 251 // shift for the character 252 253 void stbtt_GetCodepointBitmapBox(const(stbtt_fontinfo)* font, int codepoint, float scale_x, float scale_y, int* ix0, int* iy0, int* ix1, int* iy1); 254 255 // get the bbox of the bitmap centered around the glyph origin; so the 256 // bitmap width is ix1-ix0, height is iy1-iy0, and location to place 257 // the bitmap top left is (leftSideBearing*scale,iy0). 258 // (Note that the bitmap uses y-increases-down, but the shape uses 259 // y-increases-up, so CodepointBitmapBox and CodepointBox are inverted.) 260 261 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); 262 263 // same as stbtt_GetCodepointBitmapBox, but you can specify a subpixel 264 // shift for the character 265 266 // the following functions are equivalent to the above functions, but operate 267 // on glyph indices instead of Unicode codepoints (for efficiency) 268 ubyte* stbtt_GetGlyphBitmap(const(stbtt_fontinfo)* info, float scale_x, float scale_y, int glyph, int* width, int* height, int* xoff, int* yoff); 269 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); 270 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); 271 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); 272 void stbtt_GetGlyphBitmapBox(const(stbtt_fontinfo)* font, int glyph, float scale_x, float scale_y, int* ix0, int* iy0, int* ix1, int* iy1); 273 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); 274 275 // @TODO: don't expose this structure 276 struct stbtt__bitmap 277 { 278 int w, h, stride; 279 ubyte* pixels; 280 } 281 282 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); 283 284 ////////////////////////////////////////////////////////////////////////////// 285 // 286 // Finding the right font... 287 // 288 // You should really just solve this offline, keep your own tables 289 // of what font is what, and don't try to get it out of the .ttf file. 290 // That's because getting it out of the .ttf file is really hard, because 291 // the names in the file can appear in many possible encodings, in many 292 // possible languages, and e.g. if you need a case-insensitive comparison, 293 // the details of that depend on the encoding & language in a complex way 294 // (actually underspecified in truetype, but also gigantic). 295 // 296 // But you can use the provided functions in two possible ways: 297 // stbtt_FindMatchingFont() will use *case-sensitive* comparisons on 298 // unicode-encoded names to try to find the font you want; 299 // you can run this before calling stbtt_InitFont() 300 // 301 // stbtt_GetFontNameString() lets you get any of the various strings 302 // from the file yourself and do your own comparisons on them. 303 // You have to have called stbtt_InitFont() first. 304 305 int stbtt_FindMatchingFont(const(ubyte)* fontdata, const(char)* name, int flags); 306 307 // returns the offset (not index) of the font that matches, or -1 if none 308 // if you use STBTT_MACSTYLE_DONTCARE, use a font name like "Arial Bold". 309 // if you use any other flag, use a font name like "Arial"; this checks 310 // the 'macStyle' header field; i don't know if fonts set this consistently 311 enum STBTT_MACSTYLE_DONTCARE = 0; 312 enum STBTT_MACSTYLE_BOLD = 1; 313 enum STBTT_MACSTYLE_ITALIC = 2; 314 enum STBTT_MACSTYLE_UNDERSCORE = 4; 315 enum STBTT_MACSTYLE_NONE = 8; // <= not same as 0, this makes us check the bitfield is 0 316 317 int stbtt_CompareUTF8toUTF16_bigendian(const(char)* s1, int len1, const(char)* s2, int len2); 318 319 // returns 1/0 whether the first string interpreted as utf8 is identical to 320 // the second string interpreted as big-endian utf16... useful for strings from next func 321 322 const(char)* stbtt_GetFontNameString(const(stbtt_fontinfo)* font, int* length, int platformID, int encodingID, int languageID, int nameID); 323 324 // returns the string (which may be big-endian double byte, e.g. for unicode) 325 // and puts the length in bytes in *length. 326 // 327 // some of the values for the IDs are below; for more see the truetype spec: 328 // http://developer.apple.com/textfonts/TTRefMan/RM06/Chap6name.html 329 // http://www.microsoft.com/typography/otspec/name.htm 330 331 enum // platformID 332 { 333 STBTT_PLATFORM_ID_UNICODE =0, 334 STBTT_PLATFORM_ID_MAC =1, 335 STBTT_PLATFORM_ID_ISO =2, 336 STBTT_PLATFORM_ID_MICROSOFT =3 337 }; 338 339 enum // encodingID for STBTT_PLATFORM_ID_UNICODE 340 { 341 STBTT_UNICODE_EID_UNICODE_1_0 =0, 342 STBTT_UNICODE_EID_UNICODE_1_1 =1, 343 STBTT_UNICODE_EID_ISO_10646 =2, 344 STBTT_UNICODE_EID_UNICODE_2_0_BMP =3, 345 STBTT_UNICODE_EID_UNICODE_2_0_FULL=4 346 }; 347 348 enum // encodingID for STBTT_PLATFORM_ID_MICROSOFT 349 { 350 STBTT_MS_EID_SYMBOL =0, 351 STBTT_MS_EID_UNICODE_BMP =1, 352 STBTT_MS_EID_SHIFTJIS =2, 353 STBTT_MS_EID_UNICODE_FULL =10 354 }; 355 356 enum // encodingID for STBTT_PLATFORM_ID_MAC; same as Script Manager codes 357 { 358 STBTT_MAC_EID_ROMAN =0, STBTT_MAC_EID_ARABIC =4, 359 STBTT_MAC_EID_JAPANESE =1, STBTT_MAC_EID_HEBREW =5, 360 STBTT_MAC_EID_CHINESE_TRAD =2, STBTT_MAC_EID_GREEK =6, 361 STBTT_MAC_EID_KOREAN =3, STBTT_MAC_EID_RUSSIAN =7 362 }; 363 364 enum // languageID for STBTT_PLATFORM_ID_MICROSOFT; same as LCID... 365 { 366 // problematic because there are e.g. 16 english LCIDs and 16 arabic LCIDs 367 STBTT_MS_LANG_ENGLISH =0x0409, STBTT_MS_LANG_ITALIAN =0x0410, 368 STBTT_MS_LANG_CHINESE =0x0804, STBTT_MS_LANG_JAPANESE =0x0411, 369 STBTT_MS_LANG_DUTCH =0x0413, STBTT_MS_LANG_KOREAN =0x0412, 370 STBTT_MS_LANG_FRENCH =0x040c, STBTT_MS_LANG_RUSSIAN =0x0419, 371 STBTT_MS_LANG_GERMAN =0x0407, STBTT_MS_LANG_SPANISH =0x0409, 372 STBTT_MS_LANG_HEBREW =0x040d, STBTT_MS_LANG_SWEDISH =0x041D 373 }; 374 375 enum // languageID for STBTT_PLATFORM_ID_MAC 376 { 377 STBTT_MAC_LANG_ENGLISH =0, STBTT_MAC_LANG_JAPANESE =11, 378 STBTT_MAC_LANG_ARABIC =12, STBTT_MAC_LANG_KOREAN =23, 379 STBTT_MAC_LANG_DUTCH =4, STBTT_MAC_LANG_RUSSIAN =32, 380 STBTT_MAC_LANG_FRENCH =1, STBTT_MAC_LANG_SPANISH =6, 381 STBTT_MAC_LANG_GERMAN =2, STBTT_MAC_LANG_SWEDISH =5, 382 STBTT_MAC_LANG_HEBREW =10, STBTT_MAC_LANG_CHINESE_SIMPLIFIED =33, 383 STBTT_MAC_LANG_ITALIAN =3, STBTT_MAC_LANG_CHINESE_TRAD =19 384 }; 385 386 ////////////////////////////////////////////////////////////////////////// 387 // 388 // accessors to parse data from file 389 // 390 391 // on platforms that don't allow misaligned reads, if we want to allow 392 // truetype fonts that aren't padded to alignment, define ALLOW_UNALIGNED_TRUETYPE 393 394 auto ttBYTE(P)(P p) { return (*cast(stbtt_uint8*)(p)); } 395 auto ttCHAR(P)(P p) { return (*cast(stbtt_int8*)(p)); } 396 auto ttFixed(P)(P p) { return ttLONG(p); } 397 398 version (BigEndian) 399 { 400 auto ttUSHORT(P)(P p) { return (*cast(stbtt_uint16*)(p)); } 401 auto ttSHORT(P)(P p) { return (*cast(stbtt_int16*)(p)); } 402 auto ttULONG(P)(P p) { return (*cast(stbtt_uint32*)(p)); } 403 auto ttLONG(P)(P p) { return (*cast(stbtt_int32*)(p)); } 404 } 405 else 406 { 407 stbtt_uint16 ttUSHORT(const(stbtt_uint8)* p) 408 { 409 return p[0] * 256 + p[1]; 410 } 411 412 stbtt_int16 ttSHORT(const(stbtt_uint8)* p) 413 { 414 return cast(stbtt_int16)(p[0] * 256 + p[1]); 415 } 416 417 stbtt_uint32 ttULONG(const(stbtt_uint8)* p) 418 { 419 return (p[0] << 24) + (p[1] << 16) + (p[2] << 8) + p[3]; 420 } 421 422 stbtt_int32 ttLONG(const(stbtt_uint8)* p) 423 { 424 return (p[0] << 24) + (p[1] << 16) + (p[2] << 8) + p[3]; 425 } 426 } 427 428 auto stbtt_tag4(A, B, C, D, E)(A p, B c0, C c1, D c2, E c3) 429 { 430 return ((p)[0] == (c0) && (p)[1] == (c1) && (p)[2] == (c2) && (p)[3] == (c3)); 431 } 432 433 auto stbtt_tag(P, STR)(P p, STR str) 434 { 435 return stbtt_tag4(p, str[0], str[1], str[2], str[3]); 436 } 437 438 int stbtt__isfont(const(stbtt_uint8)* font) 439 { 440 // check the version number 441 if (stbtt_tag4(font, '1', 0, 0, 0)) 442 return 1; // TrueType 1 443 444 if (stbtt_tag(font, "typ1")) 445 return 1; // TrueType with type 1 font -- we don't support this! 446 447 if (stbtt_tag(font, "OTTO")) 448 return 1; // OpenType with CFF 449 450 if (stbtt_tag4(font, 0, 1, 0, 0)) 451 return 1; // OpenType 1.0 452 return 0; 453 } 454 455 // @OPTIMIZE: binary search 456 stbtt_uint32 stbtt__find_table(stbtt_uint8* data, stbtt_uint32 fontstart, const(char)* tag) 457 { 458 stbtt_int32 num_tables = ttUSHORT(data + fontstart + 4); 459 stbtt_uint32 tabledir = fontstart + 12; 460 stbtt_int32 i; 461 462 for (i = 0; i < num_tables; ++i) 463 { 464 stbtt_uint32 loc = tabledir + 16 * i; 465 466 if (stbtt_tag(data + loc + 0, tag)) 467 return ttULONG(data + loc + 8); 468 } 469 470 return 0; 471 } 472 473 int stbtt_GetFontOffsetForIndex(const(ubyte)* font_collection, int index) 474 { 475 // if it's just a font, there's only one valid index 476 if (stbtt__isfont(font_collection)) 477 return index == 0 ? 0 : -1; 478 479 // check if it's a TTC 480 if (stbtt_tag(font_collection, "ttcf")) 481 { 482 // version 1? 483 if (ttULONG(font_collection + 4) == 0x00010000 || ttULONG(font_collection + 4) == 0x00020000) 484 { 485 stbtt_int32 n = ttLONG(font_collection + 8); 486 487 if (index >= n) 488 return -1; 489 return ttULONG(font_collection + 12 + index * 14); 490 } 491 } 492 return -1; 493 } 494 495 int stbtt_InitFont(stbtt_fontinfo* info, const(ubyte)* data2, int fontstart) 496 { 497 stbtt_uint8* data = cast(stbtt_uint8*)data2; 498 stbtt_uint32 cmap, t; 499 stbtt_int32 i, numTables; 500 501 info.data = data; 502 info.fontstart = fontstart; 503 504 cmap = stbtt__find_table(data, fontstart, "cmap"); // required 505 info.loca = stbtt__find_table(data, fontstart, "loca"); // required 506 info.head = stbtt__find_table(data, fontstart, "head"); // required 507 info.glyf = stbtt__find_table(data, fontstart, "glyf"); // required 508 info.hhea = stbtt__find_table(data, fontstart, "hhea"); // required 509 info.hmtx = stbtt__find_table(data, fontstart, "hmtx"); // required 510 info.kern = stbtt__find_table(data, fontstart, "kern"); // not required 511 512 if (!cmap || !info.loca || !info.head || !info.glyf || !info.hhea || !info.hmtx) 513 return 0; 514 515 t = stbtt__find_table(data, fontstart, "maxp"); 516 517 if (t) 518 info.numGlyphs = ttUSHORT(data + t + 4); 519 else 520 info.numGlyphs = 0xffff; 521 522 // find a cmap encoding table we understand *now* to avoid searching 523 // later. (todo: could make this installable) 524 // the same regardless of glyph. 525 numTables = ttUSHORT(data + cmap + 2); 526 info.index_map = 0; 527 528 for (i = 0; i < numTables; ++i) 529 { 530 stbtt_uint32 encoding_record = cmap + 4 + 8 * i; 531 532 // find an encoding we understand: 533 switch (ttUSHORT(data + encoding_record)) 534 { 535 case STBTT_PLATFORM_ID_MICROSOFT: 536 537 switch (ttUSHORT(data + encoding_record + 2)) 538 { 539 case STBTT_MS_EID_UNICODE_BMP: 540 case STBTT_MS_EID_UNICODE_FULL: 541 542 // MS/Unicode 543 info.index_map = cmap + ttULONG(data + encoding_record + 4); 544 break; 545 546 default: 547 } 548 549 break; 550 551 default: 552 } 553 } 554 555 if (info.index_map == 0) 556 return 0; 557 558 info.indexToLocFormat = ttUSHORT(data + info.head + 50); 559 return 1; 560 } 561 562 int stbtt_FindGlyphIndex(const(stbtt_fontinfo)* info, int unicode_codepoint) 563 { 564 stbtt_uint8* data = cast(ubyte*)info.data; 565 stbtt_uint32 index_map = info.index_map; 566 567 stbtt_uint16 format = ttUSHORT(data + index_map + 0); 568 569 if (format == 0) // apple byte encoding 570 { 571 stbtt_int32 bytes = ttUSHORT(data + index_map + 2); 572 573 if (unicode_codepoint < bytes - 6) 574 return ttBYTE(data + index_map + 6 + unicode_codepoint); 575 return 0; 576 } 577 else if (format == 6) 578 { 579 stbtt_uint32 first = ttUSHORT(data + index_map + 6); 580 stbtt_uint32 count = ttUSHORT(data + index_map + 8); 581 582 if (cast(stbtt_uint32)unicode_codepoint >= first && cast(stbtt_uint32)unicode_codepoint < first + count) 583 return ttUSHORT(data + index_map + 10 + (unicode_codepoint - first) * 2); 584 return 0; 585 } 586 else if (format == 2) 587 { 588 STBTT_assert(0); // @TODO: high-byte mapping for japanese/chinese/korean 589 return 0; 590 } 591 else if (format == 4) // standard mapping for windows fonts: binary search collection of ranges 592 { 593 stbtt_uint16 segcount = ttUSHORT(data + index_map + 6) >> 1; 594 stbtt_uint16 searchRange = ttUSHORT(data + index_map + 8) >> 1; 595 stbtt_uint16 entrySelector = ttUSHORT(data + index_map + 10); 596 stbtt_uint16 rangeShift = ttUSHORT(data + index_map + 12) >> 1; 597 stbtt_uint16 item, offset, start, end; 598 599 // do a binary search of the segments 600 stbtt_uint32 endCount = index_map + 14; 601 stbtt_uint32 search = endCount; 602 603 if (unicode_codepoint > 0xffff) 604 return 0; 605 606 // they lie from endCount .. endCount + segCount 607 // but searchRange is the nearest power of two, so... 608 if (unicode_codepoint >= ttUSHORT(data + search + rangeShift * 2)) 609 search += rangeShift * 2; 610 611 // now decrement to bias correctly to find smallest 612 search -= 2; 613 614 while (entrySelector) 615 { 616 stbtt_uint16 start2, end2; 617 searchRange >>= 1; 618 start2 = ttUSHORT(data + search + 2 + segcount * 2 + 2); 619 end2 = ttUSHORT(data + search + 2); 620 start2 = ttUSHORT(data + search + searchRange * 2 + segcount * 2 + 2); 621 end2 = ttUSHORT(data + search + searchRange * 2); 622 623 if (unicode_codepoint > end2) 624 search += searchRange * 2; 625 --entrySelector; 626 } 627 628 search += 2; 629 630 item = cast(stbtt_uint16)((search - endCount) >> 1); 631 632 STBTT_assert(unicode_codepoint <= ttUSHORT(data + endCount + 2 * item)); 633 start = ttUSHORT(data + index_map + 14 + segcount * 2 + 2 + 2 * item); 634 end = ttUSHORT(data + index_map + 14 + 2 + 2 * item); 635 636 if (unicode_codepoint < start) 637 return 0; 638 639 offset = ttUSHORT(data + index_map + 14 + segcount * 6 + 2 + 2 * item); 640 641 if (offset == 0) 642 return cast(stbtt_uint16)(unicode_codepoint + ttSHORT(data + index_map + 14 + segcount * 4 + 2 + 2 * item)); 643 644 return ttUSHORT(data + offset + (unicode_codepoint - start) * 2 + index_map + 14 + segcount * 6 + 2 + 2 * item); 645 } 646 else if (format == 12 || format == 13) 647 { 648 stbtt_uint32 ngroups = ttULONG(data + index_map + 12); 649 stbtt_int32 low, high; 650 low = 0; 651 high = cast(stbtt_int32)ngroups; 652 653 // Binary search the right group. 654 while (low < high) 655 { 656 stbtt_int32 mid = low + ((high - low) >> 1); // rounds down, so low <= mid < high 657 stbtt_uint32 start_char = ttULONG(data + index_map + 16 + mid * 12); 658 stbtt_uint32 end_char = ttULONG(data + index_map + 16 + mid * 12 + 4); 659 660 if (cast(stbtt_uint32)unicode_codepoint < start_char) 661 high = mid; 662 else if (cast(stbtt_uint32)unicode_codepoint > end_char) 663 low = mid + 1; 664 else 665 { 666 stbtt_uint32 start_glyph = ttULONG(data + index_map + 16 + mid * 12 + 8); 667 668 if (format == 12) 669 return start_glyph + unicode_codepoint - start_char; 670 else // format == 13 671 return start_glyph; 672 } 673 } 674 675 return 0; // not found 676 } 677 678 // @TODO 679 STBTT_assert(0); 680 return 0; 681 } 682 683 int stbtt_GetCodepointShape(const(stbtt_fontinfo)* info, int unicode_codepoint, stbtt_vertex** vertices) 684 { 685 return stbtt_GetGlyphShape(info, stbtt_FindGlyphIndex(info, unicode_codepoint), vertices); 686 } 687 688 void stbtt_setvertex(stbtt_vertex* v, stbtt_uint8 type, stbtt_int32 x, stbtt_int32 y, stbtt_int32 cx, stbtt_int32 cy) 689 { 690 v.type = type; 691 v.x = cast(stbtt_int16)x; 692 v.y = cast(stbtt_int16)y; 693 v.cx = cast(stbtt_int16)cx; 694 v.cy = cast(stbtt_int16)cy; 695 } 696 697 int stbtt__GetGlyfOffset(const(stbtt_fontinfo)* info, int glyph_index) 698 { 699 int g1, g2; 700 701 if (glyph_index >= info.numGlyphs) 702 return -1; // glyph index out of range 703 704 if (info.indexToLocFormat >= 2) 705 return -1; // unknown index.glyph map format 706 707 if (info.indexToLocFormat == 0) 708 { 709 g1 = info.glyf + ttUSHORT(info.data + info.loca + glyph_index * 2) * 2; 710 g2 = info.glyf + ttUSHORT(info.data + info.loca + glyph_index * 2 + 2) * 2; 711 } 712 else 713 { 714 g1 = info.glyf + ttULONG(info.data + info.loca + glyph_index * 4); 715 g2 = info.glyf + ttULONG(info.data + info.loca + glyph_index * 4 + 4); 716 } 717 718 return g1 == g2 ? -1 : g1; // if length is 0, return -1 719 } 720 721 int stbtt_GetGlyphBox(const(stbtt_fontinfo)* info, int glyph_index, int* x0, int* y0, int* x1, int* y1) 722 { 723 int g = stbtt__GetGlyfOffset(info, glyph_index); 724 725 if (g < 0) 726 return 0; 727 728 if (x0) 729 *x0 = ttSHORT(info.data + g + 2); 730 731 if (y0) 732 *y0 = ttSHORT(info.data + g + 4); 733 734 if (x1) 735 *x1 = ttSHORT(info.data + g + 6); 736 737 if (y1) 738 *y1 = ttSHORT(info.data + g + 8); 739 return 1; 740 } 741 742 int stbtt_GetCodepointBox(const(stbtt_fontinfo)* info, int codepoint, int* x0, int* y0, int* x1, int* y1) 743 { 744 return stbtt_GetGlyphBox(info, stbtt_FindGlyphIndex(info, codepoint), x0, y0, x1, y1); 745 } 746 747 int stbtt_IsGlyphEmpty(const(stbtt_fontinfo)* info, int glyph_index) 748 { 749 stbtt_int16 numberOfContours; 750 int g = stbtt__GetGlyfOffset(info, glyph_index); 751 752 if (g < 0) 753 return 1; 754 numberOfContours = ttSHORT(info.data + g); 755 return numberOfContours == 0; 756 } 757 758 int stbtt__close_shape(stbtt_vertex* vertices, int num_vertices, int was_off, int start_off, 759 stbtt_int32 sx, stbtt_int32 sy, stbtt_int32 scx, stbtt_int32 scy, stbtt_int32 cx, stbtt_int32 cy) 760 { 761 if (start_off) 762 { 763 if (was_off) 764 stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, (cx + scx) >> 1, (cy + scy) >> 1, cx, cy); 765 stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, sx, sy, scx, scy); 766 } 767 else 768 { 769 if (was_off) 770 stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, sx, sy, cx, cy); 771 else 772 stbtt_setvertex(&vertices[num_vertices++], STBTT_vline, sx, sy, 0, 0); 773 } 774 return num_vertices; 775 } 776 777 int stbtt_GetGlyphShape(const(stbtt_fontinfo)* info, int glyph_index, stbtt_vertex** pvertices) 778 { 779 stbtt_int16 numberOfContours; 780 stbtt_uint8 * endPtsOfContours; 781 stbtt_uint8 * data = cast(ubyte*)info.data; 782 stbtt_vertex* vertices = null; 783 int num_vertices = 0; 784 int g = stbtt__GetGlyfOffset(info, glyph_index); 785 786 *pvertices = null; 787 788 if (g < 0) 789 return 0; 790 791 numberOfContours = ttSHORT(data + g); 792 793 if (numberOfContours > 0) 794 { 795 stbtt_uint8 flags = 0, flagcount; 796 stbtt_int32 ins, i, j = 0, m, n, next_move, was_off = 0, off, start_off = 0; 797 stbtt_int32 x, y, cx, cy, sx, sy, scx, scy; 798 stbtt_uint8* points; 799 endPtsOfContours = (data + g + 10); 800 ins = ttUSHORT(data + g + 10 + numberOfContours * 2); 801 points = data + g + 10 + numberOfContours * 2 + 2 + ins; 802 803 n = 1 + ttUSHORT(endPtsOfContours + numberOfContours * 2 - 2); 804 805 m = n + 2 * numberOfContours; // a loose bound on how many vertices we might need 806 vertices = cast(stbtt_vertex*)STBTT_malloc(m * typeof(vertices[0]).sizeof, cast(void*)info.userdata); 807 808 if (vertices is null) 809 return 0; 810 811 next_move = 0; 812 flagcount = 0; 813 814 // in first pass, we load uninterpreted data into the allocated array 815 // above, shifted to the end of the array so we won't overwrite it when 816 // we create our final data starting from the front 817 818 off = m - n; // starting offset for uninterpreted data, regardless of how m ends up being calculated 819 820 // first load flags 821 822 for (i = 0; i < n; ++i) 823 { 824 if (flagcount == 0) 825 { 826 flags = *points++; 827 828 if (flags & 8) 829 flagcount = *points++; 830 } 831 else 832 --flagcount; 833 vertices[off + i].type = flags; 834 } 835 836 // now load x coordinates 837 x = 0; 838 839 for (i = 0; i < n; ++i) 840 { 841 flags = vertices[off + i].type; 842 843 if (flags & 2) 844 { 845 stbtt_int16 dx = *points++; 846 x += (flags & 16) ? dx : -dx; // ??? 847 } 848 else 849 { 850 if (!(flags & 16)) 851 { 852 x = x + cast(stbtt_int16)(points[0] * 256 + points[1]); 853 points += 2; 854 } 855 } 856 vertices[off + i].x = cast(stbtt_int16)x; 857 } 858 859 // now load y coordinates 860 y = 0; 861 862 for (i = 0; i < n; ++i) 863 { 864 flags = vertices[off + i].type; 865 866 if (flags & 4) 867 { 868 stbtt_int16 dy = *points++; 869 y += (flags & 32) ? dy : -dy; // ??? 870 } 871 else 872 { 873 if (!(flags & 32)) 874 { 875 y = y + cast(stbtt_int16)(points[0] * 256 + points[1]); 876 points += 2; 877 } 878 } 879 vertices[off + i].y = cast(stbtt_int16)y; 880 } 881 882 // now convert them to our format 883 num_vertices = 0; 884 sx = sy = cx = cy = scx = scy = 0; 885 886 for (i = 0; i < n; ++i) 887 { 888 flags = vertices[off + i].type; 889 x = cast(stbtt_int16)vertices[off + i].x; 890 y = cast(stbtt_int16)vertices[off + i].y; 891 892 if (next_move == i) 893 { 894 if (i != 0) 895 num_vertices = stbtt__close_shape(vertices, num_vertices, was_off, start_off, sx, sy, scx, scy, cx, cy); 896 897 // now start the new one 898 start_off = !(flags & 1); 899 900 if (start_off) 901 { 902 // if we start off with an off-curve point, then when we need to find a point on the curve 903 // where we can start, and we need to save some state for when we wraparound. 904 scx = x; 905 scy = y; 906 907 if (!(vertices[off + i + 1].type & 1)) 908 { 909 // next point is also a curve point, so interpolate an on-point curve 910 sx = (x + cast(stbtt_int32)vertices[off + i + 1].x) >> 1; 911 sy = (y + cast(stbtt_int32)vertices[off + i + 1].y) >> 1; 912 } 913 else 914 { 915 // otherwise just use the next point as our start point 916 sx = cast(stbtt_int32)vertices[off + i + 1].x; 917 sy = cast(stbtt_int32)vertices[off + i + 1].y; 918 ++i; // we're using point i+1 as the starting point, so skip it 919 } 920 } 921 else 922 { 923 sx = x; 924 sy = y; 925 } 926 stbtt_setvertex(&vertices[num_vertices++], STBTT_vmove, sx, sy, 0, 0); 927 was_off = 0; 928 next_move = 1 + ttUSHORT(endPtsOfContours + j * 2); 929 ++j; 930 } 931 else 932 { 933 if (!(flags & 1)) // if it's a curve 934 { 935 if (was_off) // two off-curve control points in a row means interpolate an on-curve midpoint 936 stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, (cx + x) >> 1, (cy + y) >> 1, cx, cy); 937 cx = x; 938 cy = y; 939 was_off = 1; 940 } 941 else 942 { 943 if (was_off) 944 stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, x, y, cx, cy); 945 else 946 stbtt_setvertex(&vertices[num_vertices++], STBTT_vline, x, y, 0, 0); 947 was_off = 0; 948 } 949 } 950 } 951 952 num_vertices = stbtt__close_shape(vertices, num_vertices, was_off, start_off, sx, sy, scx, scy, cx, cy); 953 } 954 else if (numberOfContours == -1) 955 { 956 // Compound shapes. 957 int more = 1; 958 stbtt_uint8* comp = data + g + 10; 959 num_vertices = 0; 960 vertices = null; 961 962 while (more) 963 { 964 stbtt_uint16 flags, gidx; 965 int comp_num_verts = 0, i; 966 stbtt_vertex* comp_verts, tmp; 967 float[6] mtx = [1, 0, 0, 1, 0, 0]; 968 float m, n; 969 970 flags = ttSHORT(comp); 971 comp += 2; 972 gidx = ttSHORT(comp); 973 comp += 2; 974 975 if (flags & 2) // XY values 976 { 977 if (flags & 1) // shorts 978 { 979 mtx[4] = ttSHORT(comp); 980 comp += 2; 981 mtx[5] = ttSHORT(comp); 982 comp += 2; 983 } 984 else 985 { 986 mtx[4] = ttCHAR(comp); 987 comp += 1; 988 mtx[5] = ttCHAR(comp); 989 comp += 1; 990 } 991 } 992 else 993 { 994 // @TODO handle matching point 995 STBTT_assert(0); 996 } 997 998 if (flags & (1 << 3)) // WE_HAVE_A_SCALE 999 { 1000 mtx[0] = mtx[3] = ttSHORT(comp) / 16384.0f; 1001 comp += 2; 1002 mtx[1] = mtx[2] = 0; 1003 } 1004 else if (flags & (1 << 6)) // WE_HAVE_AN_X_AND_YSCALE 1005 { 1006 mtx[0] = ttSHORT(comp) / 16384.0f; 1007 comp += 2; 1008 mtx[1] = mtx[2] = 0; 1009 mtx[3] = ttSHORT(comp) / 16384.0f; 1010 comp += 2; 1011 } 1012 else if (flags & (1 << 7)) // WE_HAVE_A_TWO_BY_TWO 1013 { 1014 mtx[0] = ttSHORT(comp) / 16384.0f; 1015 comp += 2; 1016 mtx[1] = ttSHORT(comp) / 16384.0f; 1017 comp += 2; 1018 mtx[2] = ttSHORT(comp) / 16384.0f; 1019 comp += 2; 1020 mtx[3] = ttSHORT(comp) / 16384.0f; 1021 comp += 2; 1022 } 1023 1024 // Find transformation scales. 1025 m = cast(float)sqrt(mtx[0] * mtx[0] + mtx[1] * mtx[1]); 1026 n = cast(float)sqrt(mtx[2] * mtx[2] + mtx[3] * mtx[3]); 1027 1028 // Get indexed glyph. 1029 comp_num_verts = stbtt_GetGlyphShape(info, gidx, &comp_verts); 1030 1031 if (comp_num_verts > 0) 1032 { 1033 // Transform vertices. 1034 for (i = 0; i < comp_num_verts; ++i) 1035 { 1036 stbtt_vertex* v = &comp_verts[i]; 1037 stbtt_vertex_type x, y; 1038 x = v.x; 1039 y = v.y; 1040 1041 v.x = cast(stbtt_vertex_type)(m * (mtx[0] * x + mtx[2] * y + mtx[4])); 1042 v.y = cast(stbtt_vertex_type)(n * (mtx[1] * x + mtx[3] * y + mtx[5])); 1043 x = v.cx; 1044 y = v.cy; 1045 v.cx = cast(stbtt_vertex_type)(m * (mtx[0] * x + mtx[2] * y + mtx[4])); 1046 v.cy = cast(stbtt_vertex_type)(n * (mtx[1] * x + mtx[3] * y + mtx[5])); 1047 } 1048 1049 // Append vertices. 1050 tmp = cast(stbtt_vertex*)STBTT_malloc((num_vertices + comp_num_verts) *stbtt_vertex.sizeof, cast(void*)info.userdata); 1051 1052 if (!tmp) 1053 { 1054 if (vertices) 1055 STBTT_free(vertices, cast(void*)info.userdata); 1056 1057 if (comp_verts) 1058 STBTT_free(comp_verts, cast(void*)info.userdata); 1059 return 0; 1060 } 1061 1062 if (num_vertices > 0) 1063 memcpy(tmp, vertices, num_vertices *stbtt_vertex.sizeof); 1064 memcpy(tmp + num_vertices, comp_verts, comp_num_verts *stbtt_vertex.sizeof); 1065 1066 if (vertices) 1067 STBTT_free(vertices, cast(void*)info.userdata); 1068 vertices = tmp; 1069 STBTT_free(comp_verts, cast(void*)info.userdata); 1070 num_vertices += comp_num_verts; 1071 } 1072 1073 // More components ? 1074 more = flags & (1 << 5); 1075 } 1076 } 1077 else if (numberOfContours < 0) 1078 { 1079 // @TODO other compound variations? 1080 STBTT_assert(0); 1081 } 1082 else 1083 { 1084 // numberOfCounters == 0, do nothing 1085 } 1086 1087 *pvertices = vertices; 1088 return num_vertices; 1089 } 1090 1091 void stbtt_GetGlyphHMetrics(const(stbtt_fontinfo)* info, int glyph_index, int* advanceWidth, int* leftSideBearing) 1092 { 1093 stbtt_uint16 numOfLongHorMetrics = ttUSHORT(info.data + info.hhea + 34); 1094 1095 if (glyph_index < numOfLongHorMetrics) 1096 { 1097 if (advanceWidth) 1098 *advanceWidth = ttSHORT(info.data + info.hmtx + 4 * glyph_index); 1099 1100 if (leftSideBearing) 1101 *leftSideBearing = ttSHORT(info.data + info.hmtx + 4 * glyph_index + 2); 1102 } 1103 else 1104 { 1105 if (advanceWidth) 1106 *advanceWidth = ttSHORT(info.data + info.hmtx + 4 * (numOfLongHorMetrics - 1)); 1107 1108 if (leftSideBearing) 1109 *leftSideBearing = ttSHORT(info.data + info.hmtx + 4 * numOfLongHorMetrics + 2 * (glyph_index - numOfLongHorMetrics)); 1110 } 1111 } 1112 1113 int stbtt_GetGlyphKernAdvance(const(stbtt_fontinfo)* info, int glyph1, int glyph2) 1114 { 1115 stbtt_uint8* data = cast(stbtt_uint8*)(info.data + info.kern); 1116 stbtt_uint32 needle, straw; 1117 int l, r, m; 1118 1119 // we only look at the first table. it must be 'horizontal' and format 0. 1120 if (!info.kern) 1121 return 0; 1122 1123 if (ttUSHORT(data + 2) < 1) // number of tables, need at least 1 1124 return 0; 1125 1126 if (ttUSHORT(data + 8) != 1) // horizontal flag must be set in format 1127 return 0; 1128 1129 l = 0; 1130 r = ttUSHORT(data + 10) - 1; 1131 needle = glyph1 << 16 | glyph2; 1132 1133 while (l <= r) 1134 { 1135 m = (l + r) >> 1; 1136 straw = ttULONG(data + 18 + (m * 6)); // note: unaligned read 1137 1138 if (needle < straw) 1139 r = m - 1; 1140 else if (needle > straw) 1141 l = m + 1; 1142 else 1143 return ttSHORT(data + 22 + (m * 6)); 1144 } 1145 1146 return 0; 1147 } 1148 1149 int stbtt_GetCodepointKernAdvance(const(stbtt_fontinfo)* info, int ch1, int ch2) 1150 { 1151 if (!info.kern) // if no kerning table, don't waste time looking up both codepoint.glyphs 1152 return 0; 1153 return stbtt_GetGlyphKernAdvance(info, stbtt_FindGlyphIndex(info, ch1), stbtt_FindGlyphIndex(info, ch2)); 1154 } 1155 1156 void stbtt_GetCodepointHMetrics(const(stbtt_fontinfo)* info, int codepoint, int* advanceWidth, int* leftSideBearing) 1157 { 1158 stbtt_GetGlyphHMetrics(info, stbtt_FindGlyphIndex(info, codepoint), advanceWidth, leftSideBearing); 1159 } 1160 1161 void stbtt_GetFontVMetrics(const(stbtt_fontinfo)* info, int* ascent, int* descent, int* lineGap) 1162 { 1163 if (ascent) 1164 *ascent = ttSHORT(info.data + info.hhea + 4); 1165 1166 if (descent) 1167 *descent = ttSHORT(info.data + info.hhea + 6); 1168 1169 if (lineGap) 1170 *lineGap = ttSHORT(info.data + info.hhea + 8); 1171 } 1172 1173 void stbtt_GetFontBoundingBox(const(stbtt_fontinfo)* info, int* x0, int* y0, int* x1, int* y1) 1174 { 1175 *x0 = ttSHORT(info.data + info.head + 36); 1176 *y0 = ttSHORT(info.data + info.head + 38); 1177 *x1 = ttSHORT(info.data + info.head + 40); 1178 *y1 = ttSHORT(info.data + info.head + 42); 1179 } 1180 1181 float stbtt_ScaleForPixelHeight(const(stbtt_fontinfo)* info, float height) 1182 { 1183 int fheight = ttSHORT(info.data + info.hhea + 4) - ttSHORT(info.data + info.hhea + 6); 1184 return cast(float)height / fheight; 1185 } 1186 1187 float stbtt_ScaleForMappingEmToPixels(const(stbtt_fontinfo)* info, float pixels) 1188 { 1189 int unitsPerEm = ttUSHORT(info.data + info.head + 18); 1190 return pixels / unitsPerEm; 1191 } 1192 1193 void stbtt_FreeShape(const(stbtt_fontinfo)* info, stbtt_vertex* v) 1194 { 1195 STBTT_free(v, cast(void*)info.userdata); 1196 } 1197 1198 ////////////////////////////////////////////////////////////////////////////// 1199 // 1200 // antialiasing software rasterizer 1201 // 1202 1203 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) 1204 { 1205 int x0, y0, x1, y1; 1206 1207 if (!stbtt_GetGlyphBox(font, glyph, &x0, &y0, &x1, &y1)) 1208 x0 = y0 = x1 = y1 = 0; // e.g. space character 1209 1210 // now move to integral bboxes (treating pixels as little squares, what pixels get touched)? 1211 if (ix0) 1212 *ix0 = STBTT_ifloor(x0 * scale_x + shift_x); 1213 1214 if (iy0) 1215 *iy0 = -STBTT_iceil(y1 * scale_y + shift_y); 1216 1217 if (ix1) 1218 *ix1 = STBTT_iceil(x1 * scale_x + shift_x); 1219 1220 if (iy1) 1221 *iy1 = -STBTT_ifloor(y0 * scale_y + shift_y); 1222 } 1223 1224 void stbtt_GetGlyphBitmapBox(const(stbtt_fontinfo)* font, int glyph, float scale_x, float scale_y, int* ix0, int* iy0, int* ix1, int* iy1) 1225 { 1226 stbtt_GetGlyphBitmapBoxSubpixel(font, glyph, scale_x, scale_y, 0.0f, 0.0f, ix0, iy0, ix1, iy1); 1227 } 1228 1229 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) 1230 { 1231 stbtt_GetGlyphBitmapBoxSubpixel(font, stbtt_FindGlyphIndex(font, codepoint), scale_x, scale_y, shift_x, shift_y, ix0, iy0, ix1, iy1); 1232 } 1233 1234 void stbtt_GetCodepointBitmapBox(const(stbtt_fontinfo)* font, int codepoint, float scale_x, float scale_y, int* ix0, int* iy0, int* ix1, int* iy1) 1235 { 1236 stbtt_GetCodepointBitmapBoxSubpixel(font, codepoint, scale_x, scale_y, 0.0f, 0.0f, ix0, iy0, ix1, iy1); 1237 } 1238 1239 struct stbtt__edge 1240 { 1241 float x0, y0, x1, y1; 1242 int invert; 1243 } 1244 1245 struct stbtt__active_edge 1246 { 1247 int x, dx; 1248 float ey; 1249 stbtt__active_edge* next; 1250 int valid; 1251 } 1252 1253 enum FIXSHIFT = 10; 1254 enum FIX = (1 << FIXSHIFT); 1255 enum FIXMASK = (FIX - 1); 1256 1257 stbtt__active_edge* new_active(stbtt__edge* e, int off_x, float start_point, void* userdata) 1258 { 1259 stbtt__active_edge* z = cast(stbtt__active_edge*)STBTT_malloc(stbtt__active_edge.sizeof, userdata); // @TODO: make a pool of these!!! 1260 float dxdy = (e.x1 - e.x0) / (e.y1 - e.y0); 1261 STBTT_assert(e.y0 <= start_point); 1262 1263 if (!z) 1264 return z; 1265 1266 // round dx down to avoid going too far 1267 if (dxdy < 0) 1268 z.dx = -STBTT_ifloor(FIX * -dxdy); 1269 else 1270 z.dx = STBTT_ifloor(FIX * dxdy); 1271 z.x = STBTT_ifloor(FIX * (e.x0 + dxdy * (start_point - e.y0))); 1272 z.x -= off_x * FIX; 1273 z.ey = e.y1; 1274 z.next = null; 1275 z.valid = e.invert ? 1 : -1; 1276 return z; 1277 } 1278 1279 // note: this routine clips fills that extend off the edges... ideally this 1280 // wouldn't happen, but it could happen if the truetype glyph bounding boxes 1281 // are wrong, or if the user supplies a too-small bitmap 1282 void stbtt__fill_active_edges(ubyte* scanline, int len, stbtt__active_edge* e, int max_weight) 1283 { 1284 // non-zero winding fill 1285 int x0 = 0, w = 0; 1286 1287 while (e) 1288 { 1289 if (w == 0) 1290 { 1291 // if we're currently at zero, we need to record the edge start point 1292 x0 = e.x; 1293 w += e.valid; 1294 } 1295 else 1296 { 1297 int x1 = e.x; 1298 w += e.valid; 1299 1300 // if we went to zero, we need to draw 1301 if (w == 0) 1302 { 1303 int i = x0 >> FIXSHIFT; 1304 int j = x1 >> FIXSHIFT; 1305 1306 if (i < len && j >= 0) 1307 { 1308 if (i == j) 1309 { 1310 // x0,x1 are the same pixel, so compute combined coverage 1311 scanline[i] = cast(ubyte)(scanline[i] + cast(stbtt_uint8)((x1 - x0) * max_weight >> FIXSHIFT)); 1312 } 1313 else 1314 { 1315 if (i >= 0) // add antialiasing for x0 1316 scanline[i] = cast(ubyte)(scanline[i] + cast(stbtt_uint8)(((FIX - (x0 & FIXMASK)) * max_weight) >> FIXSHIFT)); 1317 else 1318 i = -1; // clip 1319 1320 if (j < len) // add antialiasing for x1 1321 scanline[j] = cast(ubyte)(scanline[j] + cast(stbtt_uint8)(((x1 & FIXMASK) * max_weight) >> FIXSHIFT)); 1322 else 1323 j = len; // clip 1324 1325 for (++i; i < j; ++i) // fill pixels between x0 and x1 1326 scanline[i] = cast(ubyte)(scanline[i] + cast(stbtt_uint8)max_weight); 1327 } 1328 } 1329 } 1330 } 1331 1332 e = e.next; 1333 } 1334 } 1335 1336 void stbtt__rasterize_sorted_edges(stbtt__bitmap* result, stbtt__edge* e, int n, int vsubsample, int off_x, int off_y, void* userdata) 1337 { 1338 stbtt__active_edge* active = null; 1339 int y, j = 0; 1340 int max_weight = (255 / vsubsample); // weight per vertical scanline 1341 int s; // vertical subsample index 1342 ubyte[512] scanline_data; 1343 ubyte* scanline; 1344 1345 if (result.w > 512) 1346 scanline = cast(ubyte*)STBTT_malloc(result.w, userdata); 1347 else 1348 scanline = scanline_data.ptr; 1349 1350 y = off_y * vsubsample; 1351 e[n].y0 = (off_y + result.h) * cast(float)vsubsample + 1; 1352 1353 while (j < result.h) 1354 { 1355 STBTT_memset(scanline, 0, result.w); 1356 1357 for (s = 0; s < vsubsample; ++s) 1358 { 1359 // find center of pixel for this scanline 1360 float scan_y = y + 0.5f; 1361 stbtt__active_edge** step = &active; 1362 1363 // update all active edges; 1364 // remove all active edges that terminate before the center of this scanline 1365 while (*step) 1366 { 1367 stbtt__active_edge* z = *step; 1368 1369 if (z.ey <= scan_y) 1370 { 1371 *step = z.next; // delete from list 1372 STBTT_assert(z.valid); 1373 z.valid = 0; 1374 STBTT_free(z, userdata); 1375 } 1376 else 1377 { 1378 z.x += z.dx; // advance to position for current scanline 1379 step = &((*step).next); // advance through list 1380 } 1381 } 1382 1383 // resort the list if needed 1384 for (;; ) 1385 { 1386 int changed = 0; 1387 step = &active; 1388 1389 while (*step && (*step).next) 1390 { 1391 if ((*step).x > (*step).next.x) 1392 { 1393 stbtt__active_edge* t = *step; 1394 stbtt__active_edge* q = t.next; 1395 1396 t.next = q.next; 1397 q.next = t; 1398 *step = q; 1399 changed = 1; 1400 } 1401 step = &(*step).next; 1402 } 1403 1404 if (!changed) 1405 break; 1406 } 1407 1408 // insert all edges that start before the center of this scanline -- omit ones that also end on this scanline 1409 while (e.y0 <= scan_y) 1410 { 1411 if (e.y1 > scan_y) 1412 { 1413 stbtt__active_edge* z = new_active(e, off_x, scan_y, userdata); 1414 1415 // find insertion point 1416 if (active == null) 1417 active = z; 1418 else if (z.x < active.x) 1419 { 1420 // insert at front 1421 z.next = active; 1422 active = z; 1423 } 1424 else 1425 { 1426 // find thing to insert AFTER 1427 stbtt__active_edge* p = active; 1428 1429 while (p.next && p.next.x < z.x) 1430 p = p.next; 1431 1432 // at this point, p.next.x is NOT < z.x 1433 z.next = p.next; 1434 p.next = z; 1435 } 1436 } 1437 ++e; 1438 } 1439 1440 // now process all active edges in XOR fashion 1441 if (active) 1442 stbtt__fill_active_edges(scanline, result.w, active, max_weight); 1443 1444 ++y; 1445 } 1446 1447 STBTT_memcpy(result.pixels + j * result.stride, scanline, result.w); 1448 ++j; 1449 } 1450 1451 while (active) 1452 { 1453 stbtt__active_edge* z = active; 1454 active = active.next; 1455 STBTT_free(z, userdata); 1456 } 1457 1458 if (scanline != scanline_data.ptr) 1459 STBTT_free(scanline, userdata); 1460 } 1461 1462 extern(C) int stbtt__edge_compare(scope const void* p, scope const void* q) 1463 { 1464 stbtt__edge* a = cast(stbtt__edge*)p; 1465 stbtt__edge* b = cast(stbtt__edge*)q; 1466 1467 if (a.y0 < b.y0) 1468 return -1; 1469 1470 if (a.y0 > b.y0) 1471 return 1; 1472 return 0; 1473 } 1474 1475 struct stbtt__point 1476 { 1477 float x, y; 1478 } 1479 1480 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) 1481 { 1482 float y_scale_inv = invert ? -scale_y : scale_y; 1483 stbtt__edge* e; 1484 int n, i, j, k, m; 1485 int vsubsample = result.h < 8 ? 15 : 5; 1486 1487 // vsubsample should divide 255 evenly; otherwise we won't reach full opacity 1488 1489 // now we have to blow out the windings into explicit edge lists 1490 n = 0; 1491 1492 for (i = 0; i < windings; ++i) 1493 n += wcount[i]; 1494 1495 e = cast(stbtt__edge*)STBTT_malloc(stbtt__edge.sizeof * (n + 1), userdata); // add an extra one as a sentinel 1496 1497 if (e is null) 1498 return; 1499 1500 n = 0; 1501 1502 m = 0; 1503 1504 for (i = 0; i < windings; ++i) 1505 { 1506 stbtt__point* p = pts + m; 1507 m += wcount[i]; 1508 j = wcount[i] - 1; 1509 1510 for (k = 0; k < wcount[i]; j = k++) 1511 { 1512 int a = k, b = j; 1513 1514 // skip the edge if horizontal 1515 if (p[j].y == p[k].y) 1516 continue; 1517 1518 // add edge from j to k to the list 1519 e[n].invert = 0; 1520 1521 if (invert ? p[j].y > p[k].y : p[j].y < p[k].y) 1522 { 1523 e[n].invert = 1; 1524 a = j, b = k; 1525 } 1526 e[n].x0 = p[a].x * scale_x + shift_x; 1527 e[n].y0 = p[a].y * y_scale_inv * vsubsample + shift_y; 1528 e[n].x1 = p[b].x * scale_x + shift_x; 1529 e[n].y1 = p[b].y * y_scale_inv * vsubsample + shift_y; 1530 ++n; 1531 } 1532 } 1533 1534 // now sort the edges by their highest point (should snap to integer, and then by x) 1535 STBTT_sort(e, n, stbtt__edge.sizeof, &stbtt__edge_compare); 1536 1537 // now, traverse the scanlines and find the intersections on each scanline, use xor winding rule 1538 stbtt__rasterize_sorted_edges(result, e, n, vsubsample, off_x, off_y, userdata); 1539 1540 STBTT_free(e, userdata); 1541 } 1542 1543 void stbtt__add_point(stbtt__point* points, int n, float x, float y) 1544 { 1545 if (!points) 1546 return; // during first pass, it's unallocated 1547 points[n].x = x; 1548 points[n].y = y; 1549 } 1550 1551 // tesselate until threshhold p is happy... @TODO warped to compensate for non-linear stretching 1552 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) 1553 { 1554 // midpoint 1555 float mx = (x0 + 2 * x1 + x2) / 4; 1556 float my = (y0 + 2 * y1 + y2) / 4; 1557 1558 // versus directly drawn line 1559 float dx = (x0 + x2) / 2 - mx; 1560 float dy = (y0 + y2) / 2 - my; 1561 1562 if (n > 16) // 65536 segments on one curve better be enough! 1563 return 1; 1564 1565 if (dx * dx + dy * dy > objspace_flatness_squared) // half-pixel error allowed... need to be smaller if AA 1566 { 1567 stbtt__tesselate_curve(points, num_points, x0, y0, (x0 + x1) / 2.0f, (y0 + y1) / 2.0f, mx, my, objspace_flatness_squared, n + 1); 1568 stbtt__tesselate_curve(points, num_points, mx, my, (x1 + x2) / 2.0f, (y1 + y2) / 2.0f, x2, y2, objspace_flatness_squared, n + 1); 1569 } 1570 else 1571 { 1572 stbtt__add_point(points, *num_points, x2, y2); 1573 *num_points = *num_points + 1; 1574 } 1575 return 1; 1576 } 1577 1578 // returns number of contours 1579 stbtt__point* stbtt_FlattenCurves(stbtt_vertex* vertices, int num_verts, float objspace_flatness, int** contour_lengths, int* num_contours, void* userdata) 1580 { 1581 stbtt__point* points; 1582 int num_points = 0; 1583 1584 float objspace_flatness_squared = objspace_flatness * objspace_flatness; 1585 int i, n = 0, start = 0, pass; 1586 1587 // count how many "moves" there are to get the contour count 1588 for (i = 0; i < num_verts; ++i) 1589 if (vertices[i].type == STBTT_vmove) 1590 ++n; 1591 1592 *num_contours = n; 1593 1594 if (n == 0) 1595 return null; 1596 1597 *contour_lengths = cast(int*)STBTT_malloc(int.sizeof * n, userdata); 1598 1599 if (*contour_lengths is null) 1600 { 1601 *num_contours = 0; 1602 return null; 1603 } 1604 1605 // make two passes through the points so we don't need to realloc 1606 for (pass = 0; pass < 2; ++pass) 1607 { 1608 float x = 0, y = 0; 1609 1610 if (pass == 1) 1611 { 1612 points = cast(stbtt__point*)STBTT_malloc(num_points * stbtt__point.sizeof, userdata); 1613 1614 if (points == null) 1615 goto error; 1616 } 1617 num_points = 0; 1618 n = -1; 1619 1620 for (i = 0; i < num_verts; ++i) 1621 { 1622 switch (vertices[i].type) 1623 { 1624 case STBTT_vmove: 1625 1626 // start the next contour 1627 if (n >= 0) 1628 (*contour_lengths)[n] = num_points - start; 1629 ++n; 1630 start = num_points; 1631 1632 x = vertices[i].x, y = vertices[i].y; 1633 stbtt__add_point(points, num_points++, x, y); 1634 break; 1635 1636 case STBTT_vline: 1637 x = vertices[i].x, y = vertices[i].y; 1638 stbtt__add_point(points, num_points++, x, y); 1639 break; 1640 1641 case STBTT_vcurve: 1642 stbtt__tesselate_curve(points, &num_points, x, y, 1643 vertices[i].cx, vertices[i].cy, 1644 vertices[i].x, vertices[i].y, 1645 objspace_flatness_squared, 0); 1646 x = vertices[i].x, y = vertices[i].y; 1647 break; 1648 1649 default: 1650 } 1651 } 1652 1653 (*contour_lengths)[n] = num_points - start; 1654 } 1655 1656 return points; 1657 error: 1658 STBTT_free(points, userdata); 1659 STBTT_free(*contour_lengths, userdata); 1660 *contour_lengths = null; 1661 *num_contours = 0; 1662 return null; 1663 } 1664 1665 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) 1666 { 1667 float scale = scale_x > scale_y ? scale_y : scale_x; 1668 int winding_count; 1669 int* winding_lengths; 1670 stbtt__point* windings = stbtt_FlattenCurves(vertices, num_verts, flatness_in_pixels / scale, &winding_lengths, &winding_count, userdata); 1671 1672 if (windings) 1673 { 1674 stbtt__rasterize(result, windings, winding_lengths, winding_count, scale_x, scale_y, shift_x, shift_y, x_off, y_off, invert, userdata); 1675 STBTT_free(winding_lengths, userdata); 1676 STBTT_free(windings, userdata); 1677 } 1678 } 1679 1680 void stbtt_FreeBitmap(ubyte* bitmap, void* userdata) 1681 { 1682 STBTT_free(bitmap, userdata); 1683 } 1684 1685 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) 1686 { 1687 int ix0, iy0, ix1, iy1; 1688 stbtt__bitmap gbm; 1689 stbtt_vertex* vertices; 1690 int num_verts = stbtt_GetGlyphShape(info, glyph, &vertices); 1691 1692 if (scale_x == 0) 1693 scale_x = scale_y; 1694 1695 if (scale_y == 0) 1696 { 1697 if (scale_x == 0) 1698 return null; 1699 scale_y = scale_x; 1700 } 1701 1702 stbtt_GetGlyphBitmapBox(info, glyph, scale_x, scale_y, &ix0, &iy0, &ix1, &iy1); 1703 1704 // now we get the size 1705 gbm.w = (ix1 - ix0); 1706 gbm.h = (iy1 - iy0); 1707 gbm.pixels = null; // in case we error 1708 1709 if (width) 1710 *width = gbm.w; 1711 1712 if (height) 1713 *height = gbm.h; 1714 1715 if (xoff) 1716 *xoff = ix0; 1717 1718 if (yoff) 1719 *yoff = iy0; 1720 1721 if (gbm.w && gbm.h) 1722 { 1723 gbm.pixels = cast(ubyte*)STBTT_malloc(gbm.w * gbm.h, cast(void*)info.userdata); 1724 1725 if (gbm.pixels) 1726 { 1727 gbm.stride = gbm.w; 1728 1729 stbtt_Rasterize(&gbm, 0.35f, vertices, num_verts, scale_x, scale_y, shift_x, shift_y, ix0, iy0, 1, cast(void*)info.userdata); 1730 } 1731 } 1732 STBTT_free(vertices, cast(void*)info.userdata); 1733 return gbm.pixels; 1734 } 1735 1736 ubyte* stbtt_GetGlyphBitmap(const(stbtt_fontinfo)* info, float scale_x, float scale_y, int glyph, int* width, int* height, int* xoff, int* yoff) 1737 { 1738 return stbtt_GetGlyphBitmapSubpixel(info, scale_x, scale_y, 0.0f, 0.0f, glyph, width, height, xoff, yoff); 1739 } 1740 1741 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) 1742 { 1743 int ix0, iy0; 1744 stbtt_vertex* vertices; 1745 int num_verts = stbtt_GetGlyphShape(info, glyph, &vertices); 1746 stbtt__bitmap gbm; 1747 1748 stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale_x, scale_y, shift_x, shift_y, &ix0, &iy0, null, null); 1749 gbm.pixels = output; 1750 gbm.w = out_w; 1751 gbm.h = out_h; 1752 gbm.stride = out_stride; 1753 1754 if (gbm.w && gbm.h) 1755 stbtt_Rasterize(&gbm, 0.35f, vertices, num_verts, scale_x, scale_y, shift_x, shift_y, ix0, iy0, 1, cast(void*)info.userdata); 1756 1757 STBTT_free(vertices, cast(void*)info.userdata); 1758 } 1759 1760 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) 1761 { 1762 stbtt_MakeGlyphBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, scale_y, 0.0f, 0.0f, glyph); 1763 } 1764 1765 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) 1766 { 1767 return stbtt_GetGlyphBitmapSubpixel(info, scale_x, scale_y, shift_x, shift_y, stbtt_FindGlyphIndex(info, codepoint), width, height, xoff, yoff); 1768 } 1769 1770 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) 1771 { 1772 stbtt_MakeGlyphBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, scale_y, shift_x, shift_y, stbtt_FindGlyphIndex(info, codepoint)); 1773 } 1774 1775 ubyte* stbtt_GetCodepointBitmap(const(stbtt_fontinfo)* info, float scale_x, float scale_y, int codepoint, int* width, int* height, int* xoff, int* yoff) 1776 { 1777 return stbtt_GetCodepointBitmapSubpixel(info, scale_x, scale_y, 0.0f, 0.0f, codepoint, width, height, xoff, yoff); 1778 } 1779 1780 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) 1781 { 1782 stbtt_MakeCodepointBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, scale_y, 0.0f, 0.0f, codepoint); 1783 } 1784 1785 ////////////////////////////////////////////////////////////////////////////// 1786 // 1787 // bitmap baking 1788 // 1789 // This is SUPER-CRAPPY packing to keep source code small 1790 1791 int stbtt_BakeFontBitmap(const(ubyte)* data, int offset, // font location (use offset=0 for plain .ttf) 1792 float pixel_height, // height of font in pixels 1793 ubyte* pixels, int pw, int ph, // bitmap to be filled in 1794 int first_char, int num_chars, // characters to bake 1795 stbtt_bakedchar* chardata) 1796 { 1797 float scale; 1798 int x, y, bottom_y, i; 1799 stbtt_fontinfo f; 1800 stbtt_InitFont(&f, data, offset); 1801 STBTT_memset(pixels, 0, pw * ph); // background of 0 around pixels 1802 x = y = 1; 1803 bottom_y = 1; 1804 1805 scale = stbtt_ScaleForPixelHeight(&f, pixel_height); 1806 1807 bool have_null_glyph = false; 1808 stbtt_bakedchar null_glyph_char_data; 1809 1810 for (i = 0; i < num_chars; ++i) 1811 { 1812 int advance, lsb, x0, y0, x1, y1, gw, gh; 1813 int g = stbtt_FindGlyphIndex(&f, first_char + i); 1814 1815 1816 if(g == 0 && have_null_glyph) 1817 { 1818 // Reuse the texture space for the null glyph instead of reinserting 1819 // it for each character we don't have glyph for. 1820 chardata[i] = null_glyph_char_data; 1821 continue; 1822 } 1823 1824 stbtt_GetGlyphHMetrics(&f, g, &advance, &lsb); 1825 stbtt_GetGlyphBitmapBox(&f, g, scale, scale, &x0, &y0, &x1, &y1); 1826 gw = x1 - x0; 1827 gh = y1 - y0; 1828 1829 if (x + gw + 1 >= pw) 1830 y = bottom_y, x = 1; // advance to next row 1831 1832 if (y + gh + 1 >= ph) // check if it fits vertically AFTER potentially moving to next row 1833 return -i; 1834 STBTT_assert(x + gw < pw); 1835 STBTT_assert(y + gh < ph); 1836 stbtt_MakeGlyphBitmap(&f, pixels + x + y * pw, gw, gh, pw, scale, scale, g); 1837 chardata[i].x0 = cast(stbtt_int16)x; 1838 chardata[i].y0 = cast(stbtt_int16)y; 1839 chardata[i].x1 = cast(stbtt_int16)(x + gw); 1840 chardata[i].y1 = cast(stbtt_int16)(y + gh); 1841 chardata[i].xadvance = scale * advance; 1842 chardata[i].xoff = cast(float)x0; 1843 chardata[i].yoff = cast(float)y0; 1844 if(g == 0 && !have_null_glyph) 1845 { 1846 have_null_glyph = true; 1847 null_glyph_char_data = chardata[i]; 1848 } 1849 x = x + gw + 2; 1850 1851 if (y + gh + 2 > bottom_y) 1852 bottom_y = y + gh + 2; 1853 } 1854 1855 return bottom_y; 1856 } 1857 1858 void stbtt_GetBakedQuad(stbtt_bakedchar* chardata, int pw, int ph, int char_index, float* xpos, float* ypos, stbtt_aligned_quad* q, int opengl_fillrule) 1859 { 1860 float d3d_bias = opengl_fillrule ? 0 : -0.5f; 1861 float ipw = 1.0f / pw, iph = 1.0f / ph; 1862 stbtt_bakedchar* b = chardata + char_index; 1863 int round_x = STBTT_ifloor((*xpos + b.xoff) + 0.5); 1864 int round_y = STBTT_ifloor((*ypos + b.yoff) + 0.5); 1865 1866 q.x0 = round_x + d3d_bias; 1867 q.y0 = round_y + d3d_bias; 1868 q.x1 = round_x + b.x1 - b.x0 + d3d_bias; 1869 q.y1 = round_y + b.y1 - b.y0 + d3d_bias; 1870 1871 q.s0 = b.x0 * ipw; 1872 q.t0 = b.y0 * iph; 1873 q.s1 = b.x1 * ipw; 1874 q.t1 = b.y1 * iph; 1875 1876 *xpos += b.xadvance; 1877 } 1878 1879 ////////////////////////////////////////////////////////////////////////////// 1880 // 1881 // font name matching -- recommended not to use this 1882 // 1883 1884 // check if a utf8 string contains a prefix which is the utf16 string; if so return length of matching utf8 string 1885 stbtt_int32 stbtt__CompareUTF8toUTF16_bigendian_prefix(const(stbtt_uint8)* s1, stbtt_int32 len1, const(stbtt_uint8)* s2, stbtt_int32 len2) 1886 { 1887 stbtt_int32 i = 0; 1888 1889 // convert utf16 to utf8 and compare the results while converting 1890 while (len2) 1891 { 1892 stbtt_uint16 ch = s2[0] * 256 + s2[1]; 1893 1894 if (ch < 0x80) 1895 { 1896 if (i >= len1) 1897 return -1; 1898 1899 if (s1[i++] != ch) 1900 return -1; 1901 } 1902 else if (ch < 0x800) 1903 { 1904 if (i + 1 >= len1) 1905 return -1; 1906 1907 if (s1[i++] != 0xc0 + (ch >> 6)) 1908 return -1; 1909 1910 if (s1[i++] != 0x80 + (ch & 0x3f)) 1911 return -1; 1912 } 1913 else if (ch >= 0xd800 && ch < 0xdc00) 1914 { 1915 stbtt_uint32 c; 1916 stbtt_uint16 ch2 = s2[2] * 256 + s2[3]; 1917 1918 if (i + 3 >= len1) 1919 return -1; 1920 c = ((ch - 0xd800) << 10) + (ch2 - 0xdc00) + 0x10000; 1921 1922 if (s1[i++] != 0xf0 + (c >> 18)) 1923 return -1; 1924 1925 if (s1[i++] != 0x80 + ((c >> 12) & 0x3f)) 1926 return -1; 1927 1928 if (s1[i++] != 0x80 + ((c >> 6) & 0x3f)) 1929 return -1; 1930 1931 if (s1[i++] != 0x80 + ((c) & 0x3f)) 1932 return -1; 1933 s2 += 2; // plus another 2 below 1934 len2 -= 2; 1935 } 1936 else if (ch >= 0xdc00 && ch < 0xe000) 1937 { 1938 return -1; 1939 } 1940 else 1941 { 1942 if (i + 2 >= len1) 1943 return -1; 1944 1945 if (s1[i++] != 0xe0 + (ch >> 12)) 1946 return -1; 1947 1948 if (s1[i++] != 0x80 + ((ch >> 6) & 0x3f)) 1949 return -1; 1950 1951 if (s1[i++] != 0x80 + ((ch) & 0x3f)) 1952 return -1; 1953 } 1954 s2 += 2; 1955 len2 -= 2; 1956 } 1957 1958 return i; 1959 } 1960 1961 int stbtt_CompareUTF8toUTF16_bigendian(const(char)* s1, int len1, const(char)* s2, int len2) 1962 { 1963 return len1 == stbtt__CompareUTF8toUTF16_bigendian_prefix(cast(const(stbtt_uint8)*)s1, len1, cast(const(stbtt_uint8)*)s2, len2); 1964 } 1965 1966 // returns results in whatever encoding you request... but note that 2-byte encodings 1967 // will be BIG-ENDIAN... use stbtt_CompareUTF8toUTF16_bigendian() to compare 1968 const(char)* stbtt_GetFontNameString(const(stbtt_fontinfo)* font, int* length, int platformID, int encodingID, int languageID, int nameID) 1969 { 1970 stbtt_int32 i, count, stringOffset; 1971 stbtt_uint8* fc = cast(ubyte*)font.data; 1972 stbtt_uint32 offset = font.fontstart; 1973 stbtt_uint32 nm = stbtt__find_table(fc, offset, "name"); 1974 1975 if (!nm) 1976 return null; 1977 1978 count = ttUSHORT(fc + nm + 2); 1979 stringOffset = nm + ttUSHORT(fc + nm + 4); 1980 1981 for (i = 0; i < count; ++i) 1982 { 1983 stbtt_uint32 loc = nm + 6 + 12 * i; 1984 1985 if (platformID == ttUSHORT(fc + loc + 0) && encodingID == ttUSHORT(fc + loc + 2) 1986 && languageID == ttUSHORT(fc + loc + 4) && nameID == ttUSHORT(fc + loc + 6)) 1987 { 1988 *length = ttUSHORT(fc + loc + 8); 1989 return cast(const(char)*)(fc + stringOffset + ttUSHORT(fc + loc + 10)); 1990 } 1991 } 1992 1993 return null; 1994 } 1995 1996 int stbtt__matchpair(stbtt_uint8* fc, stbtt_uint32 nm, stbtt_uint8* name, stbtt_int32 nlen, stbtt_int32 target_id, stbtt_int32 next_id) 1997 { 1998 stbtt_int32 i; 1999 stbtt_int32 count = ttUSHORT(fc + nm + 2); 2000 stbtt_int32 stringOffset = nm + ttUSHORT(fc + nm + 4); 2001 2002 for (i = 0; i < count; ++i) 2003 { 2004 stbtt_uint32 loc = nm + 6 + 12 * i; 2005 stbtt_int32 id = ttUSHORT(fc + loc + 6); 2006 2007 if (id == target_id) 2008 { 2009 // find the encoding 2010 stbtt_int32 platform = ttUSHORT(fc + loc + 0), encoding = ttUSHORT(fc + loc + 2), language = ttUSHORT(fc + loc + 4); 2011 2012 // is this a Unicode encoding? 2013 if (platform == 0 || (platform == 3 && encoding == 1) || (platform == 3 && encoding == 10)) 2014 { 2015 stbtt_int32 slen = ttUSHORT(fc + loc + 8), off = ttUSHORT(fc + loc + 10); 2016 2017 // check if there's a prefix match 2018 stbtt_int32 matchlen = stbtt__CompareUTF8toUTF16_bigendian_prefix(name, nlen, fc + stringOffset + off, slen); 2019 2020 if (matchlen >= 0) 2021 { 2022 // check for target_id+1 immediately following, with same encoding & language 2023 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) 2024 { 2025 stbtt_int32 slen2 = ttUSHORT(fc + loc + 12 + 8), off2 = ttUSHORT(fc + loc + 12 + 10); 2026 2027 if (slen2 == 0) 2028 { 2029 if (matchlen == nlen) 2030 return 1; 2031 } 2032 else if (matchlen < nlen && name[matchlen] == ' ') 2033 { 2034 ++matchlen; 2035 2036 if (stbtt_CompareUTF8toUTF16_bigendian(cast(char*)(name + matchlen), nlen - matchlen, cast(char*)(fc + stringOffset + off2), slen2)) 2037 return 1; 2038 } 2039 } 2040 else 2041 { 2042 // if nothing immediately following 2043 if (matchlen == nlen) 2044 return 1; 2045 } 2046 } 2047 } 2048 2049 // @TODO handle other encodings 2050 } 2051 } 2052 2053 return 0; 2054 } 2055 2056 int stbtt__matches(stbtt_uint8* fc, stbtt_uint32 offset, stbtt_uint8* name, stbtt_int32 flags) 2057 { 2058 stbtt_int32 nlen = cast(stbtt_int32)strlen(cast(char*)name); 2059 stbtt_uint32 nm, hd; 2060 2061 if (!stbtt__isfont(fc + offset)) 2062 return 0; 2063 2064 // check italics/bold/underline flags in macStyle... 2065 if (flags) 2066 { 2067 hd = stbtt__find_table(fc, offset, "head"); 2068 2069 if ((ttUSHORT(fc + hd + 44) & 7) != (flags & 7)) 2070 return 0; 2071 } 2072 2073 nm = stbtt__find_table(fc, offset, "name"); 2074 2075 if (!nm) 2076 return 0; 2077 2078 if (flags) 2079 { 2080 // if we checked the macStyle flags, then just check the family and ignore the subfamily 2081 if (stbtt__matchpair(fc, nm, name, nlen, 16, -1)) 2082 return 1; 2083 2084 if (stbtt__matchpair(fc, nm, name, nlen, 1, -1)) 2085 return 1; 2086 2087 if (stbtt__matchpair(fc, nm, name, nlen, 3, -1)) 2088 return 1; 2089 } 2090 else 2091 { 2092 if (stbtt__matchpair(fc, nm, name, nlen, 16, 17)) 2093 return 1; 2094 2095 if (stbtt__matchpair(fc, nm, name, nlen, 1, 2)) 2096 return 1; 2097 2098 if (stbtt__matchpair(fc, nm, name, nlen, 3, -1)) 2099 return 1; 2100 } 2101 2102 return 0; 2103 } 2104 2105 int stbtt_FindMatchingFont(const(ubyte)* font_collection, const(char)* name_utf8, stbtt_int32 flags) 2106 { 2107 stbtt_int32 i; 2108 2109 for (i = 0;; ++i) 2110 { 2111 stbtt_int32 off = stbtt_GetFontOffsetForIndex(font_collection, i); 2112 2113 if (off < 0) 2114 return off; 2115 2116 if (stbtt__matches(cast(stbtt_uint8*)font_collection, off, cast(stbtt_uint8*)name_utf8, flags)) 2117 return off; 2118 } 2119 }