1 /// D translation of stb_truetype v0.7 by Sean Barrett
2 /// More information on http://nothings.org/stb/stb_truetype.h
3 /// Removed:
4 /// - texture baking API
5 /// - font finding in the TTF itself. Make sure there is only one font in the TTF.
6 module dplug.graphics.stb_truetype;
7 
8 import core.stdc.stdlib : malloc, free, qsort;
9 import core.stdc..string : memcpy, memset;
10 
11 import std.math : ceil, floor, sqrt;
12 
13 import dplug.core.nogc;
14 
15 int ifloor(float x) nothrow @nogc
16 {
17    return cast(int)(floor(x));
18 }
19 
20 int iceil(float x) nothrow @nogc
21 {
22    return cast(int)(ceil(x));
23 }
24 
25 /// The following structure is defined publically so you can declare one on
26 /// the stack or as a global or etc, but you should treat it as opaque.
27 struct stbtt_fontinfo
28 {
29    const(ubyte)   * data;             // pointer to .ttf file
30    int              fontstart;        // offset of start of font
31    int numGlyphs;                     // number of glyphs, needed for range checking
32    int loca,head,glyf,hhea,hmtx,kern; // table locations as offset from start of .ttf
33    int index_map;                     // a cmap mapping for our chosen character encoding
34    int indexToLocFormat;              // format needed to map from glyph index to glyph
35 }
36 
37 
38 enum STBTT_vmove = 1,
39      STBTT_vline = 2,
40      STBTT_vcurve = 3;
41 
42 alias stbtt_vertex_type = short;
43 struct stbtt_vertex
44 {
45    stbtt_vertex_type x,y,cx,cy;
46    ubyte type, padding;
47 }
48 
49 struct stbtt__bitmap
50 {
51    int w,h,stride;
52    ubyte *pixels;
53 }
54 enum   // platformID
55    STBTT_PLATFORM_ID_UNICODE   =0,
56    STBTT_PLATFORM_ID_MAC       =1,
57    STBTT_PLATFORM_ID_ISO       =2,
58    STBTT_PLATFORM_ID_MICROSOFT =3;
59 
60 enum   // encodingID for STBTT_PLATFORM_ID_MICROSOFT
61    STBTT_MS_EID_SYMBOL        =0,
62    STBTT_MS_EID_UNICODE_BMP   =1,
63    STBTT_MS_EID_SHIFTJIS      =2,
64    STBTT_MS_EID_UNICODE_FULL  =10;
65 
66 // Accessors to parse data from file
67 
68 ubyte ttBYTE(const(ubyte)* p) nothrow @nogc
69 {
70    return *p;
71 }
72 
73 byte ttCHAR(const(ubyte)* p) nothrow @nogc
74 {
75    return *p;
76 }
77 
78 int ttFixed(const(ubyte)* p) nothrow @nogc
79 {
80    return ttLONG(p);
81 }
82 
83 ushort ttUSHORT(const(ubyte) *p) nothrow @nogc
84 {
85     return p[0]*256 + p[1];
86 }
87 
88 short ttSHORT(const(ubyte) *p) nothrow @nogc
89 {
90     return cast(short)(p[0]*256 + p[1]);
91 }
92 
93 uint ttULONG(const(ubyte) *p) nothrow @nogc
94 {
95     return (p[0]<<24) + (p[1]<<16) + (p[2]<<8) + p[3];
96 }
97 
98 int ttLONG(const(ubyte) *p) nothrow @nogc
99 {
100     return (p[0]<<24) + (p[1]<<16) + (p[2]<<8) + p[3];
101 }
102 
103 bool stbtt_tag4(const(ubyte) *p, ubyte c0, ubyte c1, ubyte c2, ubyte c3) nothrow @nogc
104 {
105     return (p[0] == c0 && p[1] == c1 && p[2] == c2 && p[3] == c3);
106 }
107 
108 bool stbtt_tag(const(ubyte) *p, string s) nothrow @nogc
109 {
110     return stbtt_tag4(p, s[0], s[1], s[2], s[3]);
111 }
112 
113 bool stbtt__isfont(const(ubyte) *font) nothrow @nogc
114 {
115    // check the version number
116    if (stbtt_tag4(font, '1',0,0,0))
117        return true; // TrueType 1
118    if (stbtt_tag(font, "typ1"))
119        return true; // TrueType with type 1 font -- we don't support this!
120    if (stbtt_tag(font, "OTTO"))
121        return true; // OpenType with CFF
122    if (stbtt_tag4(font, 0,1,0,0))
123        return true; // OpenType 1.0
124    return false;
125 }
126 
127 // @OPTIMIZE: binary search
128 uint stbtt__find_table(const(ubyte)* data, uint fontstart, string tag) nothrow @nogc
129 {
130    int num_tables = ttUSHORT(data+fontstart+4);
131    uint tabledir = fontstart + 12;
132    for (int i=0; i < num_tables; ++i) {
133       uint loc = tabledir + 16*i;
134       if (stbtt_tag(data+loc+0, tag))
135          return ttULONG(data+loc+8);
136    }
137    return 0;
138 }
139 
140 /// Each .ttf/.ttc file may have more than one font. Each font has a sequential
141 /// index number starting from 0. Call this function to get the font offset for
142 /// a given index; it returns -1 if the index is out of range. A regular .ttf
143 /// file will only define one font and it always be at offset 0, so it will
144 /// return '0' for index 0, and -1 for all other indices. You can just skip
145 /// this step if you know it's that kind of font.
146 int stbtt_GetFontOffsetForIndex(const(ubyte)* font_collection, int index) nothrow @nogc
147 {
148    // if it's just a font, there's only one valid index
149    if (stbtt__isfont(font_collection))
150       return index == 0 ? 0 : -1;
151 
152    // check if it's a TTC
153    if (stbtt_tag(font_collection, "ttcf")) {
154       // version 1?
155       if (ttULONG(font_collection+4) == 0x00010000 || ttULONG(font_collection+4) == 0x00020000) {
156          int n = ttLONG(font_collection+8);
157          if (index >= n)
158             return -1;
159          return ttULONG(font_collection+12+index*14);
160       }
161    }
162    return -1;
163 }
164 
165 /// Given an offset into the file that defines a font, this function builds
166 /// the necessary cached info for the rest of the system. You must allocate
167 /// the stbtt_fontinfo yourself, and stbtt_InitFont will fill it out. You don't
168 /// need to do anything special to free it, because the contents are pure
169 /// value data with no additional data structures. Returns 0 on failure.
170 int stbtt_InitFont(stbtt_fontinfo* info, const(ubyte)* data2, int fontstart) nothrow @nogc
171 {
172    const(ubyte) *data = data2;
173    uint cmap, t;
174    int i,numTables;
175 
176    info.data = data;
177    info.fontstart = fontstart;
178 
179    cmap = stbtt__find_table(data, fontstart, "cmap");       // required
180    info.loca = stbtt__find_table(data, fontstart, "loca"); // required
181    info.head = stbtt__find_table(data, fontstart, "head"); // required
182    info.glyf = stbtt__find_table(data, fontstart, "glyf"); // required
183    info.hhea = stbtt__find_table(data, fontstart, "hhea"); // required
184    info.hmtx = stbtt__find_table(data, fontstart, "hmtx"); // required
185    info.kern = stbtt__find_table(data, fontstart, "kern"); // not required
186    if (!cmap || !info.loca || !info.head || !info.glyf || !info.hhea || !info.hmtx)
187       return 0;
188 
189    t = stbtt__find_table(data, fontstart, "maxp");
190    if (t)
191       info.numGlyphs = ttUSHORT(data+t+4);
192    else
193       info.numGlyphs = 0xffff;
194 
195    // find a cmap encoding table we understand *now* to avoid searching
196    // later. (todo: could make this installable)
197    // the same regardless of glyph.
198    numTables = ttUSHORT(data + cmap + 2);
199    info.index_map = 0;
200    for (i=0; i < numTables; ++i) {
201       uint encoding_record = cmap + 4 + 8 * i;
202       // find an encoding we understand:
203       switch(ttUSHORT(data+encoding_record))
204       {
205          case STBTT_PLATFORM_ID_MICROSOFT:
206             switch (ttUSHORT(data+encoding_record+2))
207             {
208                case STBTT_MS_EID_UNICODE_BMP:
209                case STBTT_MS_EID_UNICODE_FULL:
210                   // MS/Unicode
211                   info.index_map = cmap + ttULONG(data+encoding_record+4);
212                   break;
213                default:
214                   assert(0);
215             }
216             break;
217             default:
218                break;
219       }
220    }
221    if (info.index_map == 0)
222       return 0;
223 
224    info.indexToLocFormat = ttUSHORT(data+info.head + 50);
225    return 1;
226 }
227 
228 /// If you're going to perform multiple operations on the same character
229 /// and you want a speed-up, call this function with the character you're
230 /// going to process, then use glyph-based functions instead of the
231 /// codepoint-based functions.
232 int stbtt_FindGlyphIndex(const(stbtt_fontinfo) *info, int unicode_codepoint) nothrow @nogc
233 {
234    const(ubyte)* data = info.data;
235    uint index_map = info.index_map;
236 
237    ushort format = ttUSHORT(data + index_map + 0);
238    if (format == 0) { // apple byte encoding
239       int bytes = ttUSHORT(data + index_map + 2);
240       if (unicode_codepoint < bytes-6)
241          return ttBYTE(data + index_map + 6 + unicode_codepoint);
242       return 0;
243    } else if (format == 6) {
244       uint first = ttUSHORT(data + index_map + 6);
245       uint count = ttUSHORT(data + index_map + 8);
246       if (cast(uint) unicode_codepoint >= first && cast(uint)unicode_codepoint < first+count)
247          return ttUSHORT(data + index_map + 10 + (unicode_codepoint - first)*2);
248       return 0;
249    } else if (format == 2) {
250       assert(0); // @TODO: high-byte mapping for japanese/chinese/korean
251    } else if (format == 4) { // standard mapping for windows fonts: binary search collection of ranges
252       ushort segcount = ttUSHORT(data+index_map+6) >> 1;
253       ushort searchRange = ttUSHORT(data+index_map+8) >> 1;
254       ushort entrySelector = ttUSHORT(data+index_map+10);
255       ushort rangeShift = ttUSHORT(data+index_map+12) >> 1;
256       ushort item, offset, start, end;
257 
258       // do a binary search of the segments
259       uint endCount = index_map + 14;
260       uint search = endCount;
261 
262       if (unicode_codepoint > 0xffff)
263          return 0;
264 
265       // they lie from endCount .. endCount + segCount
266       // but searchRange is the nearest power of two, so...
267       if (unicode_codepoint >= ttUSHORT(data + search + rangeShift*2))
268          search += rangeShift*2;
269 
270       // now decrement to bias correctly to find smallest
271       search -= 2;
272       while (entrySelector) {
273          ushort start2, end2;
274          searchRange >>= 1;
275          start2 = ttUSHORT(data + search + 2 + segcount*2 + 2);
276          end2 = ttUSHORT(data + search + 2);
277          start2 = ttUSHORT(data + search + searchRange*2 + segcount*2 + 2);
278          end2 = ttUSHORT(data + search + searchRange*2);
279          if (unicode_codepoint > end2)
280             search += searchRange*2;
281          --entrySelector;
282       }
283       search += 2;
284 
285       item = cast(ushort) ((search - endCount) >> 1);
286 
287       assert(unicode_codepoint <= ttUSHORT(data + endCount + 2*item));
288       start = ttUSHORT(data + index_map + 14 + segcount*2 + 2 + 2*item);
289       end = ttUSHORT(data + index_map + 14 + 2 + 2*item);
290       if (unicode_codepoint < start)
291          return 0;
292 
293       offset = ttUSHORT(data + index_map + 14 + segcount*6 + 2 + 2*item);
294       if (offset == 0)
295          return cast(ushort) (unicode_codepoint + ttSHORT(data + index_map + 14 + segcount*4 + 2 + 2*item));
296 
297       return ttUSHORT(data + offset + (unicode_codepoint-start)*2 + index_map + 14 + segcount*6 + 2 + 2*item);
298    } else if (format == 12 || format == 13) {
299       uint ngroups = ttULONG(data+index_map+12);
300       int low,high;
301       low = 0;
302       high = ngroups;
303       // Binary search the right group.
304       while (low < high) {
305          int mid = low + ((high-low) >> 1); // rounds down, so low <= mid < high
306          uint start_char = ttULONG(data+index_map+16+mid*12);
307          uint end_char = ttULONG(data+index_map+16+mid*12+4);
308          if (unicode_codepoint < start_char)
309             high = mid;
310          else if (unicode_codepoint > end_char)
311             low = mid+1;
312          else {
313             uint start_glyph = ttULONG(data+index_map+16+mid*12+8);
314             if (format == 12)
315                return start_glyph + unicode_codepoint-start_char;
316             else // format == 13
317                return start_glyph;
318          }
319       }
320       return 0; // not found
321    }
322    // @TODO
323    assert(0);
324 }
325 
326 /// Returns: Number of vertices and fills *vertices with the pointer to them.
327 ///          These are expressed in "unscaled" coordinates.
328 int stbtt_GetCodepointShape(const stbtt_fontinfo *info, int unicode_codepoint, stbtt_vertex **vertices) nothrow @nogc
329 {
330    return stbtt_GetGlyphShape(info, stbtt_FindGlyphIndex(info, unicode_codepoint), vertices);
331 }
332 
333 void stbtt_setvertex(stbtt_vertex *v, ubyte type, int x, int y, int cx, int cy) nothrow @nogc
334 {
335    v.type = type;
336    v.x = cast(short) x;
337    v.y = cast(short) y;
338    v.cx = cast(short) cx;
339    v.cy = cast(short) cy;
340 }
341 
342 int stbtt__GetGlyfOffset(const stbtt_fontinfo *info, int glyph_index) nothrow @nogc
343 {
344    int g1,g2;
345 
346    if (glyph_index >= info.numGlyphs) return -1; // glyph index out of range
347    if (info.indexToLocFormat >= 2)    return -1; // unknown index.glyph map format
348 
349    if (info.indexToLocFormat == 0) {
350       g1 = info.glyf + ttUSHORT(info.data + info.loca + glyph_index * 2) * 2;
351       g2 = info.glyf + ttUSHORT(info.data + info.loca + glyph_index * 2 + 2) * 2;
352    } else {
353       g1 = info.glyf + ttULONG (info.data + info.loca + glyph_index * 4);
354       g2 = info.glyf + ttULONG (info.data + info.loca + glyph_index * 4 + 4);
355    }
356 
357    return g1==g2 ? -1 : g1; // if length is 0, return -1
358 }
359 
360 /// As above, but takes one or more glyph indices for greater efficiency
361 int stbtt_GetGlyphBox(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1) nothrow @nogc
362 {
363    int g = stbtt__GetGlyfOffset(info, glyph_index);
364    if (g < 0) return 0;
365 
366    if (x0) *x0 = ttSHORT(info.data + g + 2);
367    if (y0) *y0 = ttSHORT(info.data + g + 4);
368    if (x1) *x1 = ttSHORT(info.data + g + 6);
369    if (y1) *y1 = ttSHORT(info.data + g + 8);
370    return 1;
371 }
372 
373 /// Gets the bounding box of the visible part of the glyph, in unscaled coordinates
374 int stbtt_GetCodepointBox(const stbtt_fontinfo *info, int codepoint, int *x0, int *y0, int *x1, int *y1) nothrow @nogc
375 {
376    return stbtt_GetGlyphBox(info, stbtt_FindGlyphIndex(info,codepoint), x0,y0,x1,y1);
377 }
378 
379 /// Returns: non-zero if nothing is drawn for this glyph
380 int stbtt_IsGlyphEmpty(const stbtt_fontinfo *info, int glyph_index) nothrow @nogc
381 {
382    short numberOfContours;
383    int g = stbtt__GetGlyfOffset(info, glyph_index);
384    if (g < 0) return 1;
385    numberOfContours = ttSHORT(info.data + g);
386    return numberOfContours == 0;
387 }
388 
389 int stbtt__close_shape(stbtt_vertex *vertices, int num_vertices, int was_off, int start_off,
390     int sx, int sy, int scx, int scy, int cx, int cy) nothrow @nogc
391 {
392    if (start_off) {
393       if (was_off)
394          stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, (cx+scx)>>1, (cy+scy)>>1, cx,cy);
395       stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, sx,sy,scx,scy);
396    } else {
397       if (was_off)
398          stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve,sx,sy,cx,cy);
399       else
400          stbtt_setvertex(&vertices[num_vertices++], STBTT_vline,sx,sy,0,0);
401    }
402    return num_vertices;
403 }
404 
405 /// Returns: Number of vertices and fills *vertices with the pointer to them.
406 ///          These are expressed in "unscaled" coordinates.
407 int stbtt_GetGlyphShape(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **pvertices) nothrow @nogc
408 {
409    short numberOfContours;
410    const(ubyte)* endPtsOfContours;
411    const(ubyte)* data = info.data;
412    stbtt_vertex* vertices = null;
413    int num_vertices=0;
414    int g = stbtt__GetGlyfOffset(info, glyph_index);
415 
416    *pvertices = null;
417 
418    if (g < 0) return 0;
419 
420    numberOfContours = ttSHORT(data + g);
421 
422    if (numberOfContours > 0) {
423       ubyte flags=0,flagcount;
424       int ins, i,j=0,m,n, next_move, was_off=0, off, start_off=0;
425       int x,y,cx,cy,sx,sy, scx,scy;
426       const(ubyte)* points;
427       endPtsOfContours = (data + g + 10);
428       ins = ttUSHORT(data + g + 10 + numberOfContours * 2);
429       points = data + g + 10 + numberOfContours * 2 + 2 + ins;
430 
431       n = 1+ttUSHORT(endPtsOfContours + numberOfContours*2-2);
432 
433       m = n + 2*numberOfContours;  // a loose bound on how many vertices we might need
434       vertices = cast(stbtt_vertex *) malloc(m * stbtt_vertex.sizeof);
435       if (vertices == null)
436          return 0;
437 
438       next_move = 0;
439       flagcount=0;
440 
441       // in first pass, we load uninterpreted data into the allocated array
442       // above, shifted to the end of the array so we won't overwrite it when
443       // we create our final data starting from the front
444 
445       off = m - n; // starting offset for uninterpreted data, regardless of how m ends up being calculated
446 
447       // first load flags
448 
449       for (i=0; i < n; ++i) {
450          if (flagcount == 0) {
451             flags = *points++;
452             if (flags & 8)
453                flagcount = *points++;
454          } else
455             --flagcount;
456          vertices[off+i].type = flags;
457       }
458 
459       // now load x coordinates
460       x=0;
461       for (i=0; i < n; ++i) {
462          flags = vertices[off+i].type;
463          if (flags & 2) {
464             short dx = *points++;
465             x += (flags & 16) ? dx : -dx;
466          } else {
467             if (!(flags & 16)) {
468                x = x + cast(short) (points[0]*256 + points[1]);
469                points += 2;
470             }
471          }
472          vertices[off+i].x = cast(short) x;
473       }
474 
475       // now load y coordinates
476       y=0;
477       for (i=0; i < n; ++i) {
478          flags = vertices[off+i].type;
479          if (flags & 4) {
480             short dy = *points++;
481             y += (flags & 32) ? dy : -dy;
482          } else {
483             if (!(flags & 32)) {
484                y = y + cast(short) (points[0]*256 + points[1]);
485                points += 2;
486             }
487          }
488          vertices[off+i].y = cast(short) y;
489       }
490 
491       // now convert them to our format
492       num_vertices=0;
493       sx = sy = cx = cy = scx = scy = 0;
494       for (i=0; i < n; ++i) {
495          flags = vertices[off+i].type;
496          x     = cast(short) vertices[off+i].x;
497          y     = cast(short) vertices[off+i].y;
498 
499          if (next_move == i) {
500             if (i != 0)
501                num_vertices = stbtt__close_shape(vertices, num_vertices, was_off, start_off, sx,sy,scx,scy,cx,cy);
502 
503             // now start the new one
504             start_off = !(flags & 1);
505             if (start_off) {
506                // if we start off with an off-curve point, then when we need to find a point on the curve
507                // where we can start, and we need to save some state for when we wraparound.
508                scx = x;
509                scy = y;
510                if (!(vertices[off+i+1].type & 1)) {
511                   // next point is also a curve point, so interpolate an on-point curve
512                   sx = (x + cast(int) vertices[off+i+1].x) >> 1;
513                   sy = (y + cast(int) vertices[off+i+1].y) >> 1;
514                } else {
515                   // otherwise just use the next point as our start point
516                   sx = cast(int) vertices[off+i+1].x;
517                   sy = cast(int) vertices[off+i+1].y;
518                   ++i; // we're using point i+1 as the starting point, so skip it
519                }
520             } else {
521                sx = x;
522                sy = y;
523             }
524             stbtt_setvertex(&vertices[num_vertices++], STBTT_vmove,sx,sy,0,0);
525             was_off = 0;
526             next_move = 1 + ttUSHORT(endPtsOfContours+j*2);
527             ++j;
528          } else {
529             if (!(flags & 1)) { // if it's a curve
530                if (was_off) // two off-curve control points in a row means interpolate an on-curve midpoint
531                   stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, (cx+x)>>1, (cy+y)>>1, cx, cy);
532                cx = x;
533                cy = y;
534                was_off = 1;
535             } else {
536                if (was_off)
537                   stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, x,y, cx, cy);
538                else
539                   stbtt_setvertex(&vertices[num_vertices++], STBTT_vline, x,y,0,0);
540                was_off = 0;
541             }
542          }
543       }
544       num_vertices = stbtt__close_shape(vertices, num_vertices, was_off, start_off, sx,sy,scx,scy,cx,cy);
545    } else if (numberOfContours == -1) {
546       // Compound shapes.
547       int more = 1;
548       const(ubyte)* comp = data + g + 10;
549       num_vertices = 0;
550       vertices = null;
551       while (more) {
552          ushort flags, gidx;
553          int comp_num_verts = 0, i;
554          stbtt_vertex* comp_verts = null,
555                        tmp = null;
556          float[6] mtx = [1,0,0,1,0,0];
557          float m, n;
558 
559          flags = ttSHORT(comp); comp+=2;
560          gidx = ttSHORT(comp); comp+=2;
561 
562          if (flags & 2) { // XY values
563             if (flags & 1) { // shorts
564                mtx[4] = ttSHORT(comp); comp+=2;
565                mtx[5] = ttSHORT(comp); comp+=2;
566             } else {
567                mtx[4] = ttCHAR(comp); comp+=1;
568                mtx[5] = ttCHAR(comp); comp+=1;
569             }
570          }
571          else {
572             // @TODO handle matching point
573             assert(0);
574          }
575          if (flags & (1<<3)) { // WE_HAVE_A_SCALE
576             mtx[0] = mtx[3] = ttSHORT(comp)/16384.0f; comp+=2;
577             mtx[1] = mtx[2] = 0;
578          } else if (flags & (1<<6)) { // WE_HAVE_AN_X_AND_YSCALE
579             mtx[0] = ttSHORT(comp)/16384.0f; comp+=2;
580             mtx[1] = mtx[2] = 0;
581             mtx[3] = ttSHORT(comp)/16384.0f; comp+=2;
582          } else if (flags & (1<<7)) { // WE_HAVE_A_TWO_BY_TWO
583             mtx[0] = ttSHORT(comp)/16384.0f; comp+=2;
584             mtx[1] = ttSHORT(comp)/16384.0f; comp+=2;
585             mtx[2] = ttSHORT(comp)/16384.0f; comp+=2;
586             mtx[3] = ttSHORT(comp)/16384.0f; comp+=2;
587          }
588 
589          // Find transformation scales.
590          m = cast(float) sqrt(mtx[0]*mtx[0] + mtx[1]*mtx[1]);
591          n = cast(float) sqrt(mtx[2]*mtx[2] + mtx[3]*mtx[3]);
592 
593          // Get indexed glyph.
594          comp_num_verts = stbtt_GetGlyphShape(info, gidx, &comp_verts);
595          if (comp_num_verts > 0) {
596             // Transform vertices.
597             for (i = 0; i < comp_num_verts; ++i) {
598                stbtt_vertex* v = &comp_verts[i];
599                stbtt_vertex_type x,y;
600                x=v.x; y=v.y;
601                v.x = cast(stbtt_vertex_type)(m * (mtx[0]*x + mtx[2]*y + mtx[4]));
602                v.y = cast(stbtt_vertex_type)(n * (mtx[1]*x + mtx[3]*y + mtx[5]));
603                x=v.cx; y=v.cy;
604                v.cx = cast(stbtt_vertex_type)(m * (mtx[0]*x + mtx[2]*y + mtx[4]));
605                v.cy = cast(stbtt_vertex_type)(n * (mtx[1]*x + mtx[3]*y + mtx[5]));
606             }
607             // Append vertices.
608             tmp = cast(stbtt_vertex*) malloc((num_vertices+comp_num_verts)*stbtt_vertex.sizeof);
609             if (!tmp) {
610                if (vertices) free(vertices);
611                if (comp_verts) free(comp_verts);
612                return 0;
613             }
614             if (num_vertices > 0) memcpy(tmp, vertices, num_vertices*stbtt_vertex.sizeof);
615             memcpy(tmp+num_vertices, comp_verts, comp_num_verts*stbtt_vertex.sizeof);
616             if (vertices) free(vertices);
617             vertices = tmp;
618             free(comp_verts);
619             num_vertices += comp_num_verts;
620          }
621          // More components ?
622          more = flags & (1<<5);
623       }
624    } else if (numberOfContours < 0) {
625       // @TODO other compound variations?
626       assert(0);
627    } else {
628       // numberOfCounters == 0, do nothing
629    }
630 
631    *pvertices = vertices;
632    return num_vertices;
633 }
634 
635 void stbtt_GetGlyphHMetrics(const stbtt_fontinfo *info, int glyph_index, int *advanceWidth, int *leftSideBearing) nothrow @nogc
636 {
637    ushort numOfLongHorMetrics = ttUSHORT(info.data+info.hhea + 34);
638    if (glyph_index < numOfLongHorMetrics) {
639       if (advanceWidth)     *advanceWidth    = ttSHORT(info.data + info.hmtx + 4*glyph_index);
640       if (leftSideBearing)  *leftSideBearing = ttSHORT(info.data + info.hmtx + 4*glyph_index + 2);
641    } else {
642       if (advanceWidth)     *advanceWidth    = ttSHORT(info.data + info.hmtx + 4*(numOfLongHorMetrics-1));
643       if (leftSideBearing)  *leftSideBearing = ttSHORT(info.data + info.hmtx + 4*numOfLongHorMetrics + 2*(glyph_index - numOfLongHorMetrics));
644    }
645 }
646 
647 int  stbtt_GetGlyphKernAdvance(const(stbtt_fontinfo)* info, int glyph1, int glyph2) nothrow @nogc
648 {
649    const(ubyte)* data = info.data + info.kern;
650    uint needle, straw;
651    int l, r, m;
652 
653    // we only look at the first table. it must be 'horizontal' and format 0.
654    if (!info.kern)
655       return 0;
656    if (ttUSHORT(data+2) < 1) // number of tables, need at least 1
657       return 0;
658    if (ttUSHORT(data+8) != 1) // horizontal flag must be set in format
659       return 0;
660 
661    l = 0;
662    r = ttUSHORT(data+10) - 1;
663    needle = glyph1 << 16 | glyph2;
664    while (l <= r) {
665       m = (l + r) >> 1;
666       straw = ttULONG(data+18+(m*6)); // note: unaligned read
667       if (needle < straw)
668          r = m - 1;
669       else if (needle > straw)
670          l = m + 1;
671       else
672          return ttSHORT(data+22+(m*6));
673    }
674    return 0;
675 }
676 
677 /// an additional amount to add to the 'advance' value between ch1 and ch2
678 /// @TODO; for now always returns 0!
679 int  stbtt_GetCodepointKernAdvance(const stbtt_fontinfo *info, int ch1, int ch2) nothrow @nogc
680 {
681    if (!info.kern) // if no kerning table, don't waste time looking up both codepoint.glyphs
682       return 0;
683    return stbtt_GetGlyphKernAdvance(info, stbtt_FindGlyphIndex(info,ch1), stbtt_FindGlyphIndex(info,ch2));
684 }
685 
686 /// leftSideBearing is the offset from the current horizontal position to the left edge of the character
687 /// advanceWidth is the offset from the current horizontal position to the next horizontal position
688 ///   these are expressed in unscaled coordinates
689 void stbtt_GetCodepointHMetrics(const stbtt_fontinfo *info, int codepoint, int *advanceWidth, int *leftSideBearing) nothrow @nogc
690 {
691    stbtt_GetGlyphHMetrics(info, stbtt_FindGlyphIndex(info,codepoint), advanceWidth, leftSideBearing);
692 }
693 
694 /// Ascent is the coordinate above the baseline the font extends; descent
695 /// is the coordinate below the baseline the font extends (i.e. it is typically negative)
696 /// lineGap is the spacing between one row's descent and the next row's ascent...
697 /// so you should advance the vertical position by "*ascent - *descent + *lineGap"
698 ///   these are expressed in unscaled coordinates, so you must multiply by
699 ///   the scale factor for a given size
700 void stbtt_GetFontVMetrics(const stbtt_fontinfo *info, int *ascent, int *descent, int *lineGap) nothrow @nogc
701 {
702    if (ascent ) *ascent  = ttSHORT(info.data+info.hhea + 4);
703    if (descent) *descent = ttSHORT(info.data+info.hhea + 6);
704    if (lineGap) *lineGap = ttSHORT(info.data+info.hhea + 8);
705 }
706 
707 /// the bounding box around all possible characters
708 void stbtt_GetFontBoundingBox(const stbtt_fontinfo *info, int *x0, int *y0, int *x1, int *y1) nothrow @nogc
709 {
710    *x0 = ttSHORT(info.data + info.head + 36);
711    *y0 = ttSHORT(info.data + info.head + 38);
712    *x1 = ttSHORT(info.data + info.head + 40);
713    *y1 = ttSHORT(info.data + info.head + 42);
714 }
715 
716 /// Computes a scale factor to produce a font whose "height" is 'pixels' tall.
717 /// Height is measured as the distance from the highest ascender to the lowest
718 /// descender; in other words, it's equivalent to calling stbtt_GetFontVMetrics
719 /// and computing:
720 ///       scale = pixels / (ascent - descent)
721 /// so if you prefer to measure height by the ascent only, use a similar calculation.
722 float stbtt_ScaleForPixelHeight(const stbtt_fontinfo *info, float height) nothrow @nogc
723 {
724    int fheight = ttSHORT(info.data + info.hhea + 4) - ttSHORT(info.data + info.hhea + 6);
725    return cast(float) height / fheight;
726 }
727 
728 /// computes a scale factor to produce a font whose EM size is mapped to
729 /// 'pixels' tall. This is probably what traditional APIs compute, but
730 /// I'm not positive.
731 float stbtt_ScaleForMappingEmToPixels(const stbtt_fontinfo *info, float pixels) nothrow @nogc
732 {
733    int unitsPerEm = ttUSHORT(info.data + info.head + 18);
734    return pixels / unitsPerEm;
735 }
736 
737 ///
738 void stbtt_FreeShape(const stbtt_fontinfo *info, stbtt_vertex *v) nothrow @nogc
739 {
740    free(v);
741 }
742 
743 //////////////////////////////////////////////////////////////////////////////
744 //
745 // antialiasing software rasterizer
746 //
747 
748 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) nothrow @nogc
749 {
750     int x0, y0, x1, y1;
751     if (!stbtt_GetGlyphBox(font, glyph, &x0, &y0, &x1, &y1))
752     {
753         // e.g. space character
754         if (ix0) *ix0 = 0;
755         if (iy0) *iy0 = 0;
756         if (ix1) *ix1 = 0;
757         if (iy1) *iy1 = 0;
758     }
759     else
760     {
761         // move to integral bboxes (treating pixels as little squares, what pixels get touched)?
762         if (ix0) *ix0 = ifloor( x0 * scale_x + shift_x);
763         if (iy0) *iy0 = ifloor(-y1 * scale_y + shift_y);
764         if (ix1) *ix1 = iceil( x1 * scale_x + shift_x);
765         if (iy1) *iy1 = iceil(-y0 * scale_y + shift_y);
766     }
767 }
768 
769 void stbtt_GetGlyphBitmapBox(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1) nothrow @nogc
770 {
771    stbtt_GetGlyphBitmapBoxSubpixel(font, glyph, scale_x, scale_y,0.0f,0.0f, ix0, iy0, ix1, iy1);
772 }
773 
774 /// Same as stbtt_GetCodepointBitmapBox, but you can specify a subpixel
775 /// shift for the character.
776 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) nothrow @nogc
777 {
778    stbtt_GetGlyphBitmapBoxSubpixel(font, stbtt_FindGlyphIndex(font,codepoint), scale_x, scale_y,shift_x,shift_y, ix0,iy0,ix1,iy1);
779 }
780 
781 /// Gets the bbox of the bitmap centered around the glyph origin; so the
782 /// bitmap width is ix1-ix0, height is iy1-iy0, and location to place
783 /// the bitmap top left is (leftSideBearing*scale,iy0).
784 /// (Note that the bitmap uses y-increases-down, but the shape uses
785 /// y-increases-up, so CodepointBitmapBox and CodepointBox are inverted.)
786 void stbtt_GetCodepointBitmapBox(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1) nothrow @nogc
787 {
788    stbtt_GetCodepointBitmapBoxSubpixel(font, codepoint, scale_x, scale_y,0.0f,0.0f, ix0,iy0,ix1,iy1);
789 }
790 
791 struct stbtt__edge
792 {
793    float x0,y0, x1,y1;
794    int invert;
795 }
796 
797 struct stbtt__active_edge
798 {
799    int x,dx;
800    float ey;
801    stbtt__active_edge* next;
802    int valid;
803 }
804 
805 enum FIXSHIFT   = 10;
806 enum FIX        = (1 << FIXSHIFT);
807 enum FIXMASK    = (FIX-1);
808 
809 stbtt__active_edge *new_active(stbtt__edge *e, int off_x, float start_point) nothrow @nogc
810 {
811    stbtt__active_edge *z = cast(stbtt__active_edge *) malloc(stbtt__active_edge.sizeof); // @TODO: make a pool of these!!!
812    float dxdy = (e.x1 - e.x0) / (e.y1 - e.y0);
813    assert(e.y0 <= start_point);
814    if (!z) return z;
815    // round dx down to avoid going too far
816    if (dxdy < 0)
817       z.dx = -ifloor(FIX * -dxdy);
818    else
819       z.dx = ifloor(FIX * dxdy);
820    z.x = ifloor(FIX * (e.x0 + dxdy * (start_point - e.y0)));
821    z.x -= off_x * FIX;
822    z.ey = e.y1;
823    z.next = null;
824    z.valid = e.invert ? 1 : -1;
825    return z;
826 }
827 
828 // note: this routine clips fills that extend off the edges... ideally this
829 // wouldn't happen, but it could happen if the truetype glyph bounding boxes
830 // are wrong, or if the user supplies a too-small bitmap
831 void stbtt__fill_active_edges(ubyte *scanline, int len, stbtt__active_edge *e, int max_weight) nothrow @nogc
832 {
833    // non-zero winding fill
834    int x0=0, w=0;
835 
836    while (e) {
837       if (w == 0) {
838          // if we're currently at zero, we need to record the edge start point
839          x0 = e.x; w += e.valid;
840       } else {
841          int x1 = e.x; w += e.valid;
842          // if we went to zero, we need to draw
843          if (w == 0) {
844             int i = x0 >> FIXSHIFT;
845             int j = x1 >> FIXSHIFT;
846 
847             if (i < len && j >= 0) {
848                if (i == j) {
849                   // x0,x1 are the same pixel, so compute combined coverage
850                   scanline[i] = cast(ubyte)( scanline[i] + ((x1 - x0) * max_weight >> FIXSHIFT) );
851                } else {
852                   if (i >= 0) // add antialiasing for x0
853                      scanline[i] = cast(ubyte)( scanline[i] + (((FIX - (x0 & FIXMASK)) * max_weight) >> FIXSHIFT) ) ;
854                   else
855                      i = -1; // clip
856 
857                   if (j < len) // add antialiasing for x1
858                      scanline[j] = cast(ubyte)( scanline[j] + (((x1 & FIXMASK) * max_weight) >> FIXSHIFT) );
859                   else
860                      j = len; // clip
861 
862                   for (++i; i < j; ++i) // fill pixels between x0 and x1
863                      scanline[i] = cast(ubyte)( scanline[i] +  max_weight );
864                }
865             }
866          }
867       }
868 
869       e = e.next;
870    }
871 }
872 
873 void stbtt__rasterize_sorted_edges(stbtt__bitmap *result, stbtt__edge *e, int n, int vsubsample, int off_x, int off_y) nothrow @nogc
874 {
875    stbtt__active_edge* active = null;
876    int y,j=0;
877    int max_weight = (255 / vsubsample);  // weight per vertical scanline
878    int s; // vertical subsample index
879    ubyte[512] scanline_data;
880    ubyte* scanline;
881 
882    if (result.w > 512)
883       scanline = cast(ubyte *) malloc(result.w);
884    else
885       scanline = scanline_data.ptr;
886 
887    y = off_y * vsubsample;
888    e[n].y0 = (off_y + result.h) * cast(float) vsubsample + 1;
889 
890    while (j < result.h) {
891       memset(scanline, 0, result.w);
892       for (s=0; s < vsubsample; ++s) {
893          // find center of pixel for this scanline
894          float scan_y = y + 0.5f;
895          stbtt__active_edge **step = &active;
896 
897          // update all active edges;
898          // remove all active edges that terminate before the center of this scanline
899          while (*step) {
900             stbtt__active_edge * z = *step;
901             if (z.ey <= scan_y) {
902                *step = z.next; // delete from list
903                assert(z.valid);
904                z.valid = 0;
905                free(z);
906             } else {
907                z.x += z.dx; // advance to position for current scanline
908                step = &((*step).next); // advance through list
909             }
910          }
911 
912          // resort the list if needed
913          for(;;) {
914             int changed=0;
915             step = &active;
916             while (*step && (*step).next) {
917                if ((*step).x > (*step).next.x) {
918                   stbtt__active_edge *t = *step;
919                   stbtt__active_edge *q = t.next;
920 
921                   t.next = q.next;
922                   q.next = t;
923                   *step = q;
924                   changed = 1;
925                }
926                step = &(*step).next;
927             }
928             if (!changed) break;
929          }
930 
931          // insert all edges that start before the center of this scanline -- omit ones that also end on this scanline
932          while (e.y0 <= scan_y) {
933             if (e.y1 > scan_y) {
934                stbtt__active_edge *z = new_active(e, off_x, scan_y);
935                // find insertion point
936                if (active == null)
937                   active = z;
938                else if (z.x < active.x) {
939                   // insert at front
940                   z.next = active;
941                   active = z;
942                } else {
943                   // find thing to insert AFTER
944                   stbtt__active_edge *p = active;
945                   while (p.next && p.next.x < z.x)
946                      p = p.next;
947                   // at this point, p.next.x is NOT < z.x
948                   z.next = p.next;
949                   p.next = z;
950                }
951             }
952             ++e;
953          }
954 
955          // now process all active edges in XOR fashion
956          if (active)
957             stbtt__fill_active_edges(scanline, result.w, active, max_weight);
958 
959          ++y;
960       }
961       memcpy(result.pixels + j * result.stride, scanline, result.w);
962       ++j;
963    }
964 
965    while (active) {
966       stbtt__active_edge *z = active;
967       active = active.next;
968       free(z);
969    }
970 
971    if (scanline != scanline_data.ptr)
972       free(scanline);
973 }
974 
975 
976 struct stbtt__point
977 {
978    float x,y;
979 }
980 
981 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) nothrow @nogc
982 {
983    float y_scale_inv = invert ? -scale_y : scale_y;
984    stbtt__edge *e;
985    int n,i,j,k,m;
986    int vsubsample = result.h < 8 ? 15 : 5;
987    // vsubsample should divide 255 evenly; otherwise we won't reach full opacity
988 
989    // now we have to blow out the windings into explicit edge lists
990    n = 0;
991    for (i=0; i < windings; ++i)
992       n += wcount[i];
993 
994    e = cast(stbtt__edge *) malloc(stbtt__edge.sizeof * (n+1)); // add an extra one as a sentinel
995    if (e == null) return;
996    n = 0;
997 
998    m=0;
999    for (i=0; i < windings; ++i) {
1000       stbtt__point *p = pts + m;
1001       m += wcount[i];
1002       j = wcount[i]-1;
1003       for (k=0; k < wcount[i]; j=k++) {
1004          int a=k,b=j;
1005          // skip the edge if horizontal
1006          if (p[j].y == p[k].y)
1007             continue;
1008          // add edge from j to k to the list
1009          e[n].invert = 0;
1010          if (invert ? p[j].y > p[k].y : p[j].y < p[k].y) {
1011             e[n].invert = 1;
1012             a=j,b=k;
1013          }
1014          e[n].x0 = p[a].x * scale_x + shift_x;
1015          e[n].y0 = (p[a].y * y_scale_inv + shift_y) * vsubsample;
1016          e[n].x1 = p[b].x * scale_x + shift_x;
1017          e[n].y1 = (p[b].y * y_scale_inv + shift_y) * vsubsample;
1018          ++n;
1019       }
1020    }
1021 
1022    int edgeCompare(const(stbtt__edge) a, const(stbtt__edge) b) nothrow @nogc
1023    {
1024        if (a.y0 < b.y0) return -1;
1025        if (a.y0 > b.y0) return  1;
1026        return 0;
1027    }
1028 
1029    // now sort the edges by their highest point (should snap to integer, and then by x)
1030    grailSort!stbtt__edge(e[0..n], &edgeCompare);
1031 
1032    // now, traverse the scanlines and find the intersections on each scanline, use xor winding rule
1033    stbtt__rasterize_sorted_edges(result, e, n, vsubsample, off_x, off_y);
1034 
1035    free(e);
1036 }
1037 
1038 void stbtt__add_point(stbtt__point *points, int n, float x, float y) nothrow @nogc
1039 {
1040    if (!points) return; // during first pass, it's unallocated
1041    points[n].x = x;
1042    points[n].y = y;
1043 }
1044 
1045 // tesselate until threshhold p is happy... @TODO warped to compensate for non-linear stretching
1046 int stbtt__tesselate_curve(stbtt__point *points, int *num_points, double x0, double y0, double x1, double y1, double x2, double y2, double objspace_flatness_squared, int n) nothrow @nogc
1047 {
1048     bool stopSubdiv = (n > 16);
1049 
1050     // midpoint
1051     double mx = (x0 + 2*x1 + x2)*0.25f;
1052     double my = (y0 + 2*y1 + y2)*0.25f;
1053     // versus directly drawn line
1054     double dx = (x0+x2)*0.5f - mx;
1055     double dy = (y0+y2)*0.5f - my;
1056     double squarexy = dx*dx+dy*dy;
1057 
1058     bool addThisPoint = true;
1059 
1060     if (squarexy > objspace_flatness_squared && !stopSubdiv)
1061     {
1062         // half-pixel error allowed... need to be smaller if AA
1063         int res1, res2;
1064         {
1065             double x01h = (x0 + x1) * 0.5f;
1066             double y01h = (y0 + y1) * 0.5f;
1067             res1 = stbtt__tesselate_curve(points, num_points, x0, y0, x01h, y01h, mx,my, objspace_flatness_squared,n+1);
1068         }
1069 
1070         {
1071             double x12h = (x1 + x2) * 0.5f;
1072             double y12h = (y1 + y2) * 0.5f;
1073             res2 = stbtt__tesselate_curve(points, num_points, mx, my, x12h, y12h, x2,y2, objspace_flatness_squared,n+1);
1074         }
1075 
1076         addThisPoint = false;
1077     }
1078 
1079     if (addThisPoint) // do stuff here even in subdivided case to avoid TCO
1080     {
1081         stbtt__add_point(points, *num_points,x2,y2);
1082         *num_points = *num_points+1;
1083     }
1084     return 1;
1085 }
1086 
1087 // returns number of contours
1088 stbtt__point *stbtt_FlattenCurves(stbtt_vertex *vertices, int num_verts, float objspace_flatness, int **contour_lengths, int *num_contours) nothrow @nogc
1089 {
1090    stbtt__point* points = null;
1091    int num_points=0;
1092 
1093    float objspace_flatness_squared = objspace_flatness * objspace_flatness;
1094    int i,n=0,start=0, pass;
1095 
1096    // count how many "moves" there are to get the contour count
1097    for (i=0; i < num_verts; ++i)
1098       if (vertices[i].type == STBTT_vmove)
1099          ++n;
1100 
1101    *num_contours = n;
1102    if (n == 0) return null;
1103 
1104    *contour_lengths = cast(int *) malloc(int.sizeof * n);
1105 
1106    if (*contour_lengths == null) {
1107       *num_contours = 0;
1108       return null;
1109    }
1110 
1111    // make two passes through the points so we don't need to realloc
1112    for (pass=0; pass < 2; ++pass) {
1113       float x=0,y=0;
1114       if (pass == 1) {
1115          points = cast(stbtt__point *) malloc(num_points * stbtt__point.sizeof);
1116          if (points == null) goto error;
1117       }
1118       num_points = 0;
1119       n= -1;
1120       for (i=0; i < num_verts; ++i) {
1121          switch (vertices[i].type) {
1122             case STBTT_vmove:
1123                // start the next contour
1124                if (n >= 0)
1125                   (*contour_lengths)[n] = num_points - start;
1126                ++n;
1127                start = num_points;
1128 
1129                x = vertices[i].x, y = vertices[i].y;
1130                stbtt__add_point(points, num_points++, x,y);
1131                break;
1132             case STBTT_vline:
1133                x = vertices[i].x, y = vertices[i].y;
1134                stbtt__add_point(points, num_points++, x, y);
1135                break;
1136             case STBTT_vcurve:
1137                stbtt__tesselate_curve(points, &num_points, x,y,
1138                                         vertices[i].cx, vertices[i].cy,
1139                                         vertices[i].x,  vertices[i].y,
1140                                         objspace_flatness_squared, 0);
1141                x = vertices[i].x, y = vertices[i].y;
1142                break;
1143             default:
1144                assert(0);
1145          }
1146       }
1147       (*contour_lengths)[n] = num_points - start;
1148    }
1149 
1150    return points;
1151 error:
1152    free(points);
1153    free(*contour_lengths);
1154    *contour_lengths = null;
1155    *num_contours = 0;
1156    return null;
1157 }
1158 
1159 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) nothrow @nogc
1160 {
1161    float scale = scale_x > scale_y ? scale_y : scale_x;
1162    int winding_count;
1163    int* winding_lengths;
1164    stbtt__point *windings = stbtt_FlattenCurves(vertices, num_verts, flatness_in_pixels / scale, &winding_lengths, &winding_count);
1165    if (windings) {
1166       stbtt__rasterize(result, windings, winding_lengths, winding_count, scale_x, scale_y, shift_x, shift_y, x_off, y_off, invert);
1167       free(winding_lengths);
1168       free(windings);
1169    }
1170 }
1171 
1172 /// Frees the allocated bitmap.
1173 void stbtt_FreeBitmap(ubyte *bitmap) nothrow @nogc
1174 {
1175    free(bitmap);
1176 }
1177 
1178 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) nothrow @nogc
1179 {
1180    int ix0,iy0,ix1,iy1;
1181    stbtt__bitmap gbm;
1182    stbtt_vertex *vertices;
1183    int num_verts = stbtt_GetGlyphShape(info, glyph, &vertices);
1184 
1185    if (scale_x == 0) scale_x = scale_y;
1186    if (scale_y == 0) {
1187       if (scale_x == 0) return null;
1188       scale_y = scale_x;
1189    }
1190 
1191    stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale_x, scale_y, shift_x, shift_y, &ix0,&iy0,&ix1,&iy1);
1192 
1193    // now we get the size
1194    gbm.w = (ix1 - ix0);
1195    gbm.h = (iy1 - iy0);
1196    gbm.pixels = null; // in case we error
1197 
1198    if (width ) *width  = gbm.w;
1199    if (height) *height = gbm.h;
1200    if (xoff  ) *xoff   = ix0;
1201    if (yoff  ) *yoff   = iy0;
1202 
1203    if (gbm.w && gbm.h) {
1204       gbm.pixels = cast(ubyte *) malloc(gbm.w * gbm.h);
1205       if (gbm.pixels) {
1206          gbm.stride = gbm.w;
1207 
1208          stbtt_Rasterize(&gbm, 0.35f, vertices, num_verts, scale_x, scale_y, shift_x, shift_y, ix0, iy0, 1);
1209       }
1210    }
1211    free(vertices);
1212    return gbm.pixels;
1213 }
1214 
1215 ubyte *stbtt_GetGlyphBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int glyph, int *width, int *height, int *xoff, int *yoff) nothrow @nogc
1216 {
1217    return stbtt_GetGlyphBitmapSubpixel(info, scale_x, scale_y, 0.0f, 0.0f, glyph, width, height, xoff, yoff);
1218 }
1219 
1220 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) nothrow @nogc
1221 {
1222    int ix0,iy0;
1223    stbtt_vertex *vertices;
1224    int num_verts = stbtt_GetGlyphShape(info, glyph, &vertices);
1225    stbtt__bitmap gbm;
1226 
1227    stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale_x, scale_y, shift_x, shift_y, &ix0,&iy0,null,null);
1228    gbm.pixels = output;
1229    gbm.w = out_w;
1230    gbm.h = out_h;
1231    gbm.stride = out_stride;
1232 
1233    if (gbm.w && gbm.h)
1234       stbtt_Rasterize(&gbm, 0.35f, vertices, num_verts, scale_x, scale_y, shift_x, shift_y, ix0,iy0, 1);
1235 
1236    free(vertices);
1237 }
1238 
1239 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) nothrow @nogc
1240 {
1241    stbtt_MakeGlyphBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, scale_y, 0.0f,0.0f, glyph);
1242 }
1243 
1244 /// The same as stbtt_GetCodepoitnBitmap, but you can specify a subpixel
1245 /// shift for the character.
1246 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) nothrow @nogc
1247 {
1248    return stbtt_GetGlyphBitmapSubpixel(info, scale_x, scale_y,shift_x,shift_y, stbtt_FindGlyphIndex(info,codepoint), width,height,xoff,yoff);
1249 }
1250 
1251 /// Same as stbtt_MakeCodepointBitmap, but you can specify a subpixel
1252 /// shift for the character.
1253 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) nothrow @nogc
1254 {
1255    stbtt_MakeGlyphBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, scale_y, shift_x, shift_y, stbtt_FindGlyphIndex(info,codepoint));
1256 }
1257 
1258 /// Allocates a large-enough single-channel 8bpp bitmap and renders the
1259 /// specified character/glyph at the specified scale into it, with
1260 /// antialiasing. 0 is no coverage (transparent), 255 is fully covered (opaque).
1261 /// *width & *height are filled out with the width & height of the bitmap,
1262 /// which is stored left-to-right, top-to-bottom.
1263 ///
1264 /// xoff/yoff are the offset it pixel space from the glyph origin to the top-left of the bitmap
1265 ubyte *stbtt_GetCodepointBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int codepoint, int *width, int *height, int *xoff, int *yoff) nothrow @nogc
1266 {
1267    return stbtt_GetCodepointBitmapSubpixel(info, scale_x, scale_y, 0.0f,0.0f, codepoint, width,height,xoff,yoff);
1268 }
1269 
1270 /// The same as stbtt_GetCodepointBitmap, but you pass in storage for the bitmap
1271 /// in the form of 'output', with row spacing of 'out_stride' bytes. the bitmap
1272 /// is clipped to out_w/out_h bytes. Call stbtt_GetCodepointBitmapBox to get the
1273 /// width and height and positioning info for it first.
1274 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) nothrow @nogc
1275 {
1276    stbtt_MakeCodepointBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, scale_y, 0.0f,0.0f, codepoint);
1277 }
1278