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