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 }