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