1 /++
2 	TrueType Font rendering. Meant to be used with [arsd.simpledisplay], but it doesn't actually require that. Port of stb_truetype plus D wrappers for convenience.
3 
4 
5 	Credits: Started as a copy of stb_truetype by Sean Barrett and ketmar helped
6 	with expansions.
7 +/
8 module arsd.ttf;
9 
10 // stb_truetype.h - v1.19 - public domain
11 // authored from 2009-2016 by Sean Barrett / RAD Game Tools
12 //
13 // http://nothings.org/stb/stb_truetype.h
14 //
15 // port to D by adam d. ruppe (v.6) and massively updated ketmar. see the link above for more info about the lib and real author.
16 
17 // here's some D convenience functions
18 
19 // need to do some print glyphs t it....
20 
21 
22 ///
23 struct TtfFont {
24 	stbtt_fontinfo font;
25 	///
26 	this(in ubyte[] data) {
27 		load(data);
28 	}
29 
30 	///
31 	void load(in ubyte[] data) {
32    		if(stbtt_InitFont(&font, data.ptr, stbtt_GetFontOffsetForIndex(data.ptr, 0)) == 0)
33 			throw new Exception("load font problem");
34 	}
35 
36 	/// Note that you must stbtt_FreeBitmap(returnValue.ptr, null); this thing or it will leak!!!!
37 	ubyte[] renderCharacter(dchar c, int size, out int width, out int height, float shift_x = 0.0, float shift_y = 0.0) {
38    		auto ptr = stbtt_GetCodepointBitmapSubpixel(&font, 0.0,stbtt_ScaleForPixelHeight(&font, size),
39 			shift_x, shift_y, c, &width, &height, null,null);
40 		return ptr[0 .. width * height];
41 	}
42 
43 	///
44 	void getStringSize(in char[] s, int size, out int width, out int height) {
45 		float xpos=0;
46 
47 		auto scale = stbtt_ScaleForPixelHeight(&font, size);
48 		int ascent, descent, line_gap;
49 		stbtt_GetFontVMetrics(&font, &ascent,&descent,&line_gap);
50 		auto baseline = cast(int) (ascent*scale);
51 
52 		import std.math;
53 
54 		int maxWidth;
55 
56 		foreach(i, dchar ch; s) {
57 			int advance,lsb;
58 			auto x_shift = xpos - floor(xpos);
59 			stbtt_GetCodepointHMetrics(&font, ch, &advance, &lsb);
60 
61 			int x0, y0, x1, y1;
62 			stbtt_GetCodepointBitmapBoxSubpixel(&font, ch, scale,scale,x_shift,0, &x0,&y0,&x1,&y1);
63 
64 			maxWidth = cast(int)(xpos + x1);
65 
66 			xpos += (advance * scale);
67 			if (i + 1 < s.length)
68 				xpos += scale*stbtt_GetCodepointKernAdvance(&font, ch,s[i+1]);
69 		}
70 
71    		width = maxWidth;
72 		height = size;
73 	}
74 
75 	///
76 	ubyte[] renderString(in char[] s, int size, out int width, out int height) {
77 		float xpos=0;
78 
79 		auto scale = stbtt_ScaleForPixelHeight(&font, size);
80 		int ascent, descent, line_gap;
81 		stbtt_GetFontVMetrics(&font, &ascent,&descent,&line_gap);
82 		auto baseline = cast(int) (ascent*scale);
83 
84 		import std.math;
85 
86 		int swidth;
87 		int sheight;
88 		getStringSize(s, size, swidth, sheight);
89 		auto screen = new ubyte[](swidth * sheight);
90 
91 		foreach(i, dchar ch; s) {
92 			int advance,lsb;
93 			auto x_shift = xpos - floor(xpos);
94 			stbtt_GetCodepointHMetrics(&font, ch, &advance, &lsb);
95 			int cw, cheight;
96 			auto c = renderCharacter(ch, size, cw, cheight, x_shift, 0.0);
97 			scope(exit) stbtt_FreeBitmap(c.ptr, null);
98 
99 			int x0, y0, x1, y1;
100 			stbtt_GetCodepointBitmapBoxSubpixel(&font, ch, scale,scale,x_shift,0, &x0,&y0,&x1,&y1);
101 
102 			int x = cast(int) xpos + x0;
103 			int y = baseline + y0;
104 			int cx = 0;
105 			foreach(index, pixel; c) {
106 				if(cx == cw) {
107 					cx = 0;
108 					y++;
109 					x = cast(int) xpos + x0;
110 				}
111 				auto offset = swidth * y + x;
112 				if(offset >= screen.length)
113 					break;
114 				int val = (cast(int) pixel * (255 - screen[offset]) / 255);
115 				if(val > 255)
116 					val = 255;
117 				screen[offset] += cast(ubyte)(val);
118 				x++;
119 				cx++;
120 			}
121 
122 			//stbtt_MakeCodepointBitmapSubpixel(&font, &screen[(baseline + y0) * swidth + cast(int) xpos + x0], x1-x0,y1-y0, 79, scale,scale,      x_shift,0, ch);
123 			// note that this stomps the old data, so where character boxes overlap (e.g. 'lj') it's wrong
124 			// because this API is really for baking character bitmaps into textures. if you want to render
125 			// a sequence of characters, you really need to render each bitmap to a temp buffer, then
126 			// "alpha blend" that into the working buffer
127 			xpos += (advance * scale);
128 			if (i + 1 < s.length)
129 				xpos += scale*stbtt_GetCodepointKernAdvance(&font, ch,s[i+1]);
130 		}
131 
132    		width = swidth;
133 		height = sheight;
134 
135 		return screen;
136 	}
137 
138 	// ~this() {}
139 }
140 
141 /// Version of OpenGL you want it to use. Currently only one option.
142 enum OpenGlFontGLVersion {
143 	old /// old style glBegin/glEnd stuff
144 }
145 
146 /+
147 	This is mostly there if you want to draw different pieces together in
148 	different colors or across different boxes (see what text didn't fit, etc.).
149 
150 	Used only with [OpenGlLimitedFont] right now.
151 +/
152 struct DrawingTextContext {
153 	const(char)[] text; /// remaining text
154 	float x; /// current position of the baseline
155 	float y; /// ditto
156 
157 	const int left; /// bounding box, if applicable
158 	const int top; /// ditto
159 	const int right; /// ditto
160 	const int bottom; /// ditto
161 }
162 
163 /++
164 	Note that the constructor calls OpenGL functions and thus this must be called AFTER
165 	the context creation, e.g. on simpledisplay's window first visible delegate.
166 
167 	Any text with characters outside the range you bake in the constructor are simply
168 	ignored - that's why it is called "limited" font. The [TtfFont] struct can generate
169 	any string on-demand which is more flexible, and even faster for strings repeated
170 	frequently, but slower for frequently-changing or one-off strings. That's what this
171 	class is made for.
172 
173 	History:
174 		Added April 24, 2020
175 +/
176 class OpenGlLimitedFont(OpenGlFontGLVersion ver = OpenGlFontGLVersion.old) {
177 // FIXME: does this kern?
178 // FIXME: it would be cool if it did per-letter transforms too like word art. make it tangent to some baseline
179 
180 	import arsd.simpledisplay;
181 
182 	static private int nextPowerOfTwo(int v) {
183 		v--;
184 		v |= v >> 1;
185 		v |= v >> 2;
186 		v |= v >> 4;
187 		v |= v >> 8;
188 		v |= v >> 16;
189 		v++;
190 		return v;
191 	}
192 
193 	uint _tex;
194 	stbtt_bakedchar[] charInfo;
195 
196 	import arsd.color;
197 
198 	/++
199 
200 		Tip: if color == Color.transparent, it will not actually attempt to draw to OpenGL. You can use this
201 		to help plan pagination inside the bounding box.
202 
203 	+/
204 	public final DrawingTextContext drawString(int x, int y, in char[] text, Color color = Color.white, Rectangle boundingBox = Rectangle.init) {
205 		if(boundingBox == Rectangle.init) {
206 			// if you hit a newline, at least keep it aligned here if something wasn't
207 			// explicitly given.
208 			boundingBox.left = x;
209 			boundingBox.top = y;
210 			boundingBox.right = int.max;
211 			boundingBox.bottom = int.max;
212 		}
213 		DrawingTextContext dtc = DrawingTextContext(text, x, y, boundingBox.tupleof);
214 		drawString(dtc, color);
215 		return dtc;
216 	}
217 
218 	/++
219 		It won't attempt to draw partial characters if it butts up against the bounding box, unless
220 		word wrap was impossible. Use clipping if you need to cover that up and guarantee it never goes
221 		outside the bounding box ever.
222 
223 	+/
224 	public final void drawString(ref DrawingTextContext context, Color color = Color.white) {
225 		bool actuallyDraw = color != Color.transparent;
226 
227 		if(actuallyDraw) {
228 			glBindTexture(GL_TEXTURE_2D, _tex);
229 
230 			glColor4f(cast(float)color.r/255.0, cast(float)color.g/255.0, cast(float)color.b/255.0, cast(float)color.a / 255.0);
231 		}
232 
233 		bool newWord = true;
234 		bool atStartOfLine = true;
235 		float currentWordLength;
236 		int currentWordCharsRemaining;
237 
238 		void calculateWordInfo() {
239 			const(char)[] copy = context.text;
240 			currentWordLength = 0.0;
241 			currentWordCharsRemaining = 0;
242 
243 			while(copy.length) {
244 				auto ch = copy[0];
245 				copy = copy[1 .. $];
246 
247 				currentWordCharsRemaining++;
248 
249 				if(ch <= 32)
250 					break; // not in a word anymore
251 
252 				if(ch < firstChar || ch > lastChar)
253 					continue;
254 
255 				const b = charInfo[cast(int) ch - cast(int) firstChar];
256 
257 				currentWordLength += b.xadvance;
258 			}
259 		}
260 
261 		bool newline() {
262 			context.x = context.left;
263 			context.y += lineHeight;
264 			atStartOfLine = true;
265 
266 			if(context.y + descent > context.bottom)
267 				return false;
268 
269 			return true;
270 		}
271 
272 		while(context.text.length) {
273 			if(newWord) {
274 				calculateWordInfo();
275 				newWord = false;
276 
277 				if(context.x + currentWordLength > context.right) {
278 					if(!newline())
279 						break; // ran out of space
280 				}
281 			}
282 
283 			// FIXME i should prolly UTF-8 decode....
284 			dchar ch = context.text[0];
285 			context.text = context.text[1 .. $];
286 
287 			if(currentWordCharsRemaining) {
288 				currentWordCharsRemaining--;
289 
290 				if(currentWordCharsRemaining == 0)
291 					newWord = true;
292 			}
293 
294 			if(ch == '\t') {
295 				context.x += 20;
296 				continue;
297 			}
298 			if(ch == '\n') {
299 				if(newline())
300 					continue;
301 				else
302 					break;
303 			}
304 
305 			if(ch < firstChar || ch > lastChar) {
306 				if(ch == ' ')
307 					context.x += lineHeight / 4; // fake space if not available in formal font (I recommend you do include it though)
308 				continue;
309 			}
310 
311 			const b = charInfo[cast(int) ch - cast(int) firstChar];
312 
313 			int round_x = STBTT_ifloor((context.x + b.xoff) + 0.5f);
314 			int round_y = STBTT_ifloor((context.y + b.yoff) + 0.5f);
315 
316 			// box to draw on the screen
317 			auto x0 = round_x;
318 			auto y0 = round_y;
319 			auto x1 = round_x + b.x1 - b.x0;
320 			auto y1 = round_y + b.y1 - b.y0;
321 
322 			// is that outside the bounding box we should draw in?
323 			// if so on x, wordwrap to the next line. if so on y,
324 			// return prematurely and let the user context handle it if needed.
325 
326 			// box to fetch off the surface
327 			auto s0 = b.x0 * ipw;
328 			auto t0 = b.y0 * iph;
329 			auto s1 = b.x1 * ipw;
330 			auto t1 = b.y1 * iph;
331 
332 			if(actuallyDraw) {
333 				glBegin(GL_QUADS); 
334 					glTexCoord2f(s0, t0); 		glVertex2i(x0, y0);
335 					glTexCoord2f(s1, t0); 		glVertex2i(x1, y0); 
336 					glTexCoord2f(s1, t1); 		glVertex2i(x1, y1); 
337 					glTexCoord2f(s0, t1); 		glVertex2i(x0, y1); 
338 				glEnd();
339 			}
340 
341 			context.x += b.xadvance;
342 		}
343 
344 		if(actuallyDraw)
345 		glBindTexture(GL_TEXTURE_2D, 0); // unbind the texture
346 	}
347 
348 	private {
349 		const dchar firstChar;
350 		const dchar lastChar;
351 		const int pw;
352 		const int ph;
353 		const float ipw;
354 		const float iph;
355 	}
356 
357 	public const int lineHeight; /// metrics
358 
359 	public const int ascent; /// ditto
360 	public const int descent; /// ditto
361 	public const int line_gap; /// ditto;
362 
363 	/++
364 
365 	+/
366 	public this(const ubyte[] ttfData, float fontPixelHeight, dchar firstChar = 32, dchar lastChar = 127) {
367 
368 		assert(lastChar > firstChar);
369 		assert(fontPixelHeight > 0);
370 
371 		this.firstChar = firstChar;
372 		this.lastChar = lastChar;
373 
374 		int numChars = 1 + cast(int) lastChar - cast(int) firstChar;
375 
376 		lineHeight = cast(int) (fontPixelHeight + 0.5);
377 
378 		import std.math;
379 		// will most likely be 512x512ish; about 256k likely
380 		int height = cast(int) (fontPixelHeight + 1) * cast(int) (sqrt(cast(float) numChars) + 1);
381 		height = nextPowerOfTwo(height);
382 		int width = height;
383 
384 		this.pw = width;
385 		this.ph = height;
386 
387 		ipw = 1.0f / pw;
388 		iph = 1.0f / ph;
389 
390 		int len = width * height;
391 
392 		//import std.stdio; writeln(len);
393 
394 		import core.stdc.stdlib;
395 		ubyte[] buffer = (cast(ubyte*) malloc(len))[0 .. len];
396 		if(buffer is null) assert(0);
397 		scope(exit) free(buffer.ptr);
398 
399 		charInfo.length = numChars;
400 
401 		int ascent, descent, line_gap;
402 
403 		if(stbtt_BakeFontBitmap(
404 			ttfData.ptr, 0,
405 			fontPixelHeight,
406 			buffer.ptr, width, height,
407 			cast(int) firstChar, numChars,
408 			charInfo.ptr,
409 			&ascent, &descent, &line_gap
410 		) == 0)
411 			throw new Exception("bake font didn't work");
412 
413 		this.ascent = ascent;
414 		this.descent = descent;
415 		this.line_gap = line_gap;
416 
417 		glGenTextures(1, &_tex);
418 		glBindTexture(GL_TEXTURE_2D, _tex);
419 		glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
420 
421 		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
422 		
423 		glTexImage2D(
424 			GL_TEXTURE_2D,
425 			0,
426 			GL_ALPHA,
427 			width,
428 			height,
429 			0,
430 			GL_ALPHA,
431 			GL_UNSIGNED_BYTE,
432 			buffer.ptr);
433 
434 		assert(!glGetError());
435 
436 		glBindTexture(GL_TEXTURE_2D, 0);
437 	}
438 }
439 
440 
441 // test program
442 /+
443 int main(string[] args)
444 {
445 import std.conv;
446 import arsd.simpledisplay;
447    int c = (args.length > 1 ? to!int(args[1]) : 'a'), s = (args.length > 2 ? to!int(args[2]) : 20);
448 import std.file;
449 
450    auto font = TtfFont(cast(ubyte[]) /*import("sans-serif.ttf"));//*/std.file.read(args.length > 3 ? args[3] : "sans-serif.ttf"));
451 
452    int w, h;
453    auto bitmap = font.renderString("Hejlqo, world!qMpj", s, w, h);
454 	auto img = new Image(w, h);
455 
456    for (int j=0; j < h; ++j) {
457       for (int i=0; i < w; ++i)
458       	img.putPixel(i, j, Color(0, (bitmap[j*w+i] > 128) ? 255 : 0, 0));
459    }
460    img.displayImage();
461    return 0;
462 }
463 +/
464 
465 
466 
467 
468 // STB_TTF FOLLOWS
469 
470 
471 nothrow @trusted @nogc:
472 
473 version = STB_RECT_PACK_VERSION;
474 
475 // ////////////////////////////////////////////////////////////////////////////
476 // ////////////////////////////////////////////////////////////////////////////
477 // //
478 // //  SAMPLE PROGRAMS
479 // //
480 //
481 //  Incomplete text-in-3d-api example, which draws quads properly aligned to be lossless
482 //
483 /+
484 #if 0
485 #define STB_TRUETYPE_IMPLEMENTATION  // force following include to generate implementation
486 #include "stb_truetype.h"
487 
488 unsigned char ttf_buffer[1<<20];
489 unsigned char temp_bitmap[512*512];
490 
491 stbtt_bakedchar cdata[96]; // ASCII 32..126 is 95 glyphs
492 GLuint ftex;
493 
494 void my_stbtt_initfont(void)
495 {
496    fread(ttf_buffer, 1, 1<<20, fopen("c:/windows/fonts/times.ttf", "rb"));
497    stbtt_BakeFontBitmap(ttf_buffer,0, 32.0, temp_bitmap,512,512, 32,96, cdata); // no guarantee this fits!
498    // can free ttf_buffer at this point
499    glGenTextures(1, &ftex);
500    glBindTexture(GL_TEXTURE_2D, ftex);
501    glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, 512,512, 0, GL_ALPHA, GL_UNSIGNED_BYTE, temp_bitmap);
502    // can free temp_bitmap at this point
503    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
504 }
505 
506 void my_stbtt_print(float x, float y, char *text)
507 {
508    // assume orthographic projection with units = screen pixels, origin at top left
509    glEnable(GL_TEXTURE_2D);
510    glBindTexture(GL_TEXTURE_2D, ftex);
511    glBegin(GL_QUADS);
512    while (*text) {
513       if (*text >= 32 && *text < 128) {
514          stbtt_aligned_quad q;
515          stbtt_GetBakedQuad(cdata, 512,512, *text-32, &x,&y,&q,1);//1=opengl & d3d10+,0=d3d9
516          glTexCoord2f(q.s0,q.t1); glVertex2f(q.x0,q.y0);
517          glTexCoord2f(q.s1,q.t1); glVertex2f(q.x1,q.y0);
518          glTexCoord2f(q.s1,q.t0); glVertex2f(q.x1,q.y1);
519          glTexCoord2f(q.s0,q.t0); glVertex2f(q.x0,q.y1);
520       }
521       ++text;
522    }
523    glEnd();
524 }
525 #endif
526 //
527 //
528 // ////////////////////////////////////////////////////////////////////////////
529 //
530 // Complete program (this compiles): get a single bitmap, print as ASCII art
531 //
532 #if 0
533 #include <stdio.h>
534 #define STB_TRUETYPE_IMPLEMENTATION  // force following include to generate implementation
535 #include "stb_truetype.h"
536 
537 char ttf_buffer[1<<25];
538 
539 int main(int argc, char **argv)
540 {
541    stbtt_fontinfo font;
542    unsigned char *bitmap;
543    int w,h,i,j,c = (argc > 1 ? atoi(argv[1]) : 'a'), s = (argc > 2 ? atoi(argv[2]) : 20);
544 
545    fread(ttf_buffer, 1, 1<<25, fopen(argc > 3 ? argv[3] : "c:/windows/fonts/arialbd.ttf", "rb"));
546 
547    stbtt_InitFont(&font, ttf_buffer, stbtt_GetFontOffsetForIndex(ttf_buffer,0));
548    bitmap = stbtt_GetCodepointBitmap(&font, 0,stbtt_ScaleForPixelHeight(&font, s), c, &w, &h, 0,0);
549 
550    for (j=0; j < h; ++j) {
551       for (i=0; i < w; ++i)
552          putchar(" .:ioVM@"[bitmap[j*w+i]>>5]);
553       putchar('\n');
554    }
555    return 0;
556 }
557 #endif
558 //
559 // Output:
560 //
561 //     .ii.
562 //    @@@@@@.
563 //   V@Mio@@o
564 //   :i.  V@V
565 //     :oM@@M
566 //   :@@@MM@M
567 //   @@o  o@M
568 //  :@@.  M@M
569 //   @@@o@@@@
570 //   :M@@V:@@.
571 //
572 //////////////////////////////////////////////////////////////////////////////
573 //
574 // Complete program: print "Hello World!" banner, with bugs
575 //
576 #if 0
577 char buffer[24<<20];
578 unsigned char screen[20][79];
579 
580 int main(int arg, char **argv)
581 {
582    stbtt_fontinfo font;
583    int i,j,ascent,baseline,ch=0;
584    float scale, xpos=2; // leave a little padding in case the character extends left
585    char *text = "Heljo World!"; // intentionally misspelled to show 'lj' brokenness
586 
587    fread(buffer, 1, 1000000, fopen("c:/windows/fonts/arialbd.ttf", "rb"));
588    stbtt_InitFont(&font, buffer, 0);
589 
590    scale = stbtt_ScaleForPixelHeight(&font, 15);
591    stbtt_GetFontVMetrics(&font, &ascent,0,0);
592    baseline = (int) (ascent*scale);
593 
594    while (text[ch]) {
595       int advance,lsb,x0,y0,x1,y1;
596       float x_shift = xpos - (float) floor(xpos);
597       stbtt_GetCodepointHMetrics(&font, text[ch], &advance, &lsb);
598       stbtt_GetCodepointBitmapBoxSubpixel(&font, text[ch], scale,scale,x_shift,0, &x0,&y0,&x1,&y1);
599       stbtt_MakeCodepointBitmapSubpixel(&font, &screen[baseline + y0][(int) xpos + x0], x1-x0,y1-y0, 79, scale,scale,x_shift,0, text[ch]);
600       // note that this stomps the old data, so where character boxes overlap (e.g. 'lj') it's wrong
601       // because this API is really for baking character bitmaps into textures. if you want to render
602       // a sequence of characters, you really need to render each bitmap to a temp buffer, then
603       // "alpha blend" that into the working buffer
604       xpos += (advance * scale);
605       if (text[ch+1])
606          xpos += scale*stbtt_GetCodepointKernAdvance(&font, text[ch],text[ch+1]);
607       ++ch;
608    }
609 
610    for (j=0; j < 20; ++j) {
611       for (i=0; i < 78; ++i)
612          putchar(" .:ioVM@"[screen[j][i]>>5]);
613       putchar('\n');
614    }
615 
616    return 0;
617 }
618 #endif
619 +/
620 
621 // ////////////////////////////////////////////////////////////////////////////
622 // ////////////////////////////////////////////////////////////////////////////
623 // //
624 // //   INTEGRATION WITH YOUR CODEBASE
625 // //
626 // //   The following sections allow you to supply alternate definitions
627 // //   of C library functions used by stb_truetype, e.g. if you don't
628 // //   link with the C runtime library.
629 
630 // #define your own (u)stbtt_int8/16/32 before including to override this
631 alias stbtt_uint8 = ubyte;
632 alias stbtt_int8 = byte;
633 alias stbtt_uint16 = ushort;
634 alias stbtt_int16 = short;
635 alias stbtt_uint32 = uint;
636 alias stbtt_int32 = int;
637 
638 //typedef char stbtt__check_size32[sizeof(stbtt_int32)==4 ? 1 : -1];
639 //typedef char stbtt__check_size16[sizeof(stbtt_int16)==2 ? 1 : -1];
640 
641 int STBTT_ifloor(T) (in T x) pure { pragma(inline, true); import std.math : floor; return cast(int)floor(x); }
642 int STBTT_iceil(T) (in T x) pure { pragma(inline, true); import std.math : ceil; return cast(int)ceil(x); }
643 
644 T STBTT_sqrt(T) (in T x) pure { pragma(inline, true); import std.math : sqrt; return sqrt(x); }
645 T STBTT_pow(T) (in T x, in T y) pure { pragma(inline, true); import std.math : pow; return pow(x, y); }
646 
647 T STBTT_fmod(T) (in T x, in T y) { pragma(inline, true); import std.math : fmod; return fmod(x, y); }
648 
649 T STBTT_cos(T) (in T x) pure { pragma(inline, true); import std.math : cos; return cos(x); }
650 T STBTT_acos(T) (in T x) pure { pragma(inline, true); import std.math : acos; return acos(x); }
651 
652 T STBTT_fabs(T) (in T x) pure { pragma(inline, true); import std.math : abs; return abs(x); }
653 
654 // #define your own functions "STBTT_malloc" / "STBTT_free" to avoid malloc.h
655 void* STBTT_malloc (uint size, const(void)* uptr) { pragma(inline, true); import core.stdc.stdlib : malloc; return malloc(size); }
656 void STBTT_free (void *ptr, const(void)* uptr) { pragma(inline, true); import core.stdc.stdlib : free; free(ptr); }
657 /*
658 #ifndef STBTT_malloc
659 #include <stdlib.h>
660 #define STBTT_malloc(x,u)  ((void)(u),malloc(x))
661 #define STBTT_free(x,u)    ((void)(u),free(x))
662 #endif
663 */
664 
665 //alias STBTT_assert = assert;
666 
667 uint STBTT_strlen (const(void)* p) { pragma(inline, true); import core.stdc.string : strlen; return (p !is null ? cast(uint)strlen(cast(const(char)*)p) : 0); }
668 void STBTT_memcpy (void* d, const(void)* s, uint count) { pragma(inline, true); import core.stdc.string : memcpy; if (count > 0) memcpy(d, s, count); }
669 void STBTT_memset (void* d, uint v, uint count) { pragma(inline, true); import core.stdc.string : memset; if (count > 0) memset(d, v, count); }
670 
671 
672 // /////////////////////////////////////////////////////////////////////////////
673 // /////////////////////////////////////////////////////////////////////////////
674 // //
675 // //   INTERFACE
676 // //
677 // //
678 
679 // private structure
680 struct stbtt__buf {
681    ubyte *data;
682    int cursor;
683    int size;
684 }
685 
686 //////////////////////////////////////////////////////////////////////////////
687 //
688 // TEXTURE BAKING API
689 //
690 // If you use this API, you only have to call two functions ever.
691 //
692 
693 struct stbtt_bakedchar {
694    ushort x0,y0,x1,y1; // coordinates of bbox in bitmap
695    float xoff,yoff,xadvance;
696 }
697 
698 /+
699 STBTT_DEF int stbtt_BakeFontBitmap(const(ubyte)* data, int offset,  // font location (use offset=0 for plain .ttf)
700                                 float pixel_height,                     // height of font in pixels
701                                 ubyte *pixels, int pw, int ph,  // bitmap to be filled in
702                                 int first_char, int num_chars,          // characters to bake
703                                 stbtt_bakedchar *chardata,           // you allocate this, it's num_chars long
704 				int* ascent, int * descent, int* line_gap); // metrics for use later too
705 +/
706 // if return is positive, the first unused row of the bitmap
707 // if return is negative, returns the negative of the number of characters that fit
708 // if return is 0, no characters fit and no rows were used
709 // This uses a very crappy packing.
710 
711 struct stbtt_aligned_quad {
712    float x0,y0,s0,t0; // top-left
713    float x1,y1,s1,t1; // bottom-right
714 }
715 
716 /+
717 STBTT_DEF void stbtt_GetBakedQuad(const(stbtt_bakedchar)* chardata, int pw, int ph,  // same data as above
718                                int char_index,             // character to display
719                                float *xpos, float *ypos,   // pointers to current position in screen pixel space
720                                stbtt_aligned_quad *q,      // output: quad to draw
721                                int opengl_fillrule);       // true if opengl fill rule; false if DX9 or earlier
722 +/
723 // Call GetBakedQuad with char_index = 'character - first_char', and it
724 // creates the quad you need to draw and advances the current position.
725 //
726 // The coordinate system used assumes y increases downwards.
727 //
728 // Characters will extend both above and below the current position;
729 // see discussion of "BASELINE" above.
730 //
731 // It's inefficient; you might want to c&p it and optimize it.
732 
733 
734 
735 // ////////////////////////////////////////////////////////////////////////////
736 //
737 // NEW TEXTURE BAKING API
738 //
739 // This provides options for packing multiple fonts into one atlas, not
740 // perfectly but better than nothing.
741 
742 struct stbtt_packedchar {
743    ushort x0,y0,x1,y1; // coordinates of bbox in bitmap
744    float xoff,yoff,xadvance;
745    float xoff2,yoff2;
746 }
747 
748 //typedef struct stbtt_pack_context stbtt_pack_context;
749 //typedef struct stbtt_fontinfo stbtt_fontinfo;
750 //#ifndef STB_RECT_PACK_VERSION
751 //typedef struct stbrp_rect stbrp_rect;
752 //#endif
753 
754 //STBTT_DEF int  stbtt_PackBegin(stbtt_pack_context *spc, ubyte *pixels, int width, int height, int stride_in_bytes, int padding, void *alloc_context);
755 // Initializes a packing context stored in the passed-in stbtt_pack_context.
756 // Future calls using this context will pack characters into the bitmap passed
757 // in here: a 1-channel bitmap that is width * height. stride_in_bytes is
758 // the distance from one row to the next (or 0 to mean they are packed tightly
759 // together). "padding" is the amount of padding to leave between each
760 // character (normally you want '1' for bitmaps you'll use as textures with
761 // bilinear filtering).
762 //
763 // Returns 0 on failure, 1 on success.
764 
765 //STBTT_DEF void stbtt_PackEnd  (stbtt_pack_context *spc);
766 // Cleans up the packing context and frees all memory.
767 
768 //#define STBTT_POINT_SIZE(x)   (-(x))
769 
770 /+
771 STBTT_DEF int  stbtt_PackFontRange(stbtt_pack_context *spc, const(ubyte)* fontdata, int font_index, float font_size,
772                                 int first_unicode_char_in_range, int num_chars_in_range, stbtt_packedchar *chardata_for_range);
773 +/
774 // Creates character bitmaps from the font_index'th font found in fontdata (use
775 // font_index=0 if you don't know what that is). It creates num_chars_in_range
776 // bitmaps for characters with unicode values starting at first_unicode_char_in_range
777 // and increasing. Data for how to render them is stored in chardata_for_range;
778 // pass these to stbtt_GetPackedQuad to get back renderable quads.
779 //
780 // font_size is the full height of the character from ascender to descender,
781 // as computed by stbtt_ScaleForPixelHeight. To use a point size as computed
782 // by stbtt_ScaleForMappingEmToPixels, wrap the point size in STBTT_POINT_SIZE()
783 // and pass that result as 'font_size':
784 //       ...,                  20 , ... // font max minus min y is 20 pixels tall
785 //       ..., STBTT_POINT_SIZE(20), ... // 'M' is 20 pixels tall
786 
787 struct stbtt_pack_range {
788    float font_size;
789    int first_unicode_codepoint_in_range;  // if non-zero, then the chars are continuous, and this is the first codepoint
790    int *array_of_unicode_codepoints;       // if non-zero, then this is an array of unicode codepoints
791    int num_chars;
792    stbtt_packedchar *chardata_for_range; // output
793    ubyte h_oversample, v_oversample; // don't set these, they're used internally
794 }
795 
796 //STBTT_DEF int  stbtt_PackFontRanges(stbtt_pack_context *spc, const(ubyte)* fontdata, int font_index, stbtt_pack_range *ranges, int num_ranges);
797 // Creates character bitmaps from multiple ranges of characters stored in
798 // ranges. This will usually create a better-packed bitmap than multiple
799 // calls to stbtt_PackFontRange. Note that you can call this multiple
800 // times within a single PackBegin/PackEnd.
801 
802 //STBTT_DEF void stbtt_PackSetOversampling(stbtt_pack_context *spc, unsigned int h_oversample, unsigned int v_oversample);
803 // Oversampling a font increases the quality by allowing higher-quality subpixel
804 // positioning, and is especially valuable at smaller text sizes.
805 //
806 // This function sets the amount of oversampling for all following calls to
807 // stbtt_PackFontRange(s) or stbtt_PackFontRangesGatherRects for a given
808 // pack context. The default (no oversampling) is achieved by h_oversample=1
809 // and v_oversample=1. The total number of pixels required is
810 // h_oversample*v_oversample larger than the default; for example, 2x2
811 // oversampling requires 4x the storage of 1x1. For best results, render
812 // oversampled textures with bilinear filtering. Look at the readme in
813 // stb/tests/oversample for information about oversampled fonts
814 //
815 // To use with PackFontRangesGather etc., you must set it before calls
816 // call to PackFontRangesGatherRects.
817 
818 /+
819 STBTT_DEF void stbtt_GetPackedQuad(const(stbtt_packedchar)* chardata, int pw, int ph,  // same data as above
820                                int char_index,             // character to display
821                                float *xpos, float *ypos,   // pointers to current position in screen pixel space
822                                stbtt_aligned_quad *q,      // output: quad to draw
823                                int align_to_integer);
824 
825 STBTT_DEF int  stbtt_PackFontRangesGatherRects(stbtt_pack_context *spc, const(stbtt_fontinfo)* info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects);
826 STBTT_DEF void stbtt_PackFontRangesPackRects(stbtt_pack_context *spc, stbrp_rect *rects, int num_rects);
827 STBTT_DEF int  stbtt_PackFontRangesRenderIntoRects(stbtt_pack_context *spc, const(stbtt_fontinfo)* info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects);
828 +/
829 // Calling these functions in sequence is roughly equivalent to calling
830 // stbtt_PackFontRanges(). If you more control over the packing of multiple
831 // fonts, or if you want to pack custom data into a font texture, take a look
832 // at the source to of stbtt_PackFontRanges() and create a custom version
833 // using these functions, e.g. call GatherRects multiple times,
834 // building up a single array of rects, then call PackRects once,
835 // then call RenderIntoRects repeatedly. This may result in a
836 // better packing than calling PackFontRanges multiple times
837 // (or it may not).
838 
839 // this is an opaque structure that you shouldn't mess with which holds
840 // all the context needed from PackBegin to PackEnd.
841 struct stbtt_pack_context {
842    void *user_allocator_context;
843    void *pack_info;
844    int   width;
845    int   height;
846    int   stride_in_bytes;
847    int   padding;
848    uint   h_oversample, v_oversample;
849    ubyte *pixels;
850    void  *nodes;
851 }
852 
853 // ////////////////////////////////////////////////////////////////////////////
854 //
855 // FONT LOADING
856 //
857 //
858 
859 //STBTT_DEF int stbtt_GetNumberOfFonts(const(ubyte)* data);
860 // This function will determine the number of fonts in a font file.  TrueType
861 // collection (.ttc) files may contain multiple fonts, while TrueType font
862 // (.ttf) files only contain one font. The number of fonts can be used for
863 // indexing with the previous function where the index is between zero and one
864 // less than the total fonts. If an error occurs, -1 is returned.
865 
866 //STBTT_DEF int stbtt_GetFontOffsetForIndex(const(ubyte)* data, int index);
867 // Each .ttf/.ttc file may have more than one font. Each font has a sequential
868 // index number starting from 0. Call this function to get the font offset for
869 // a given index; it returns -1 if the index is out of range. A regular .ttf
870 // file will only define one font and it always be at offset 0, so it will
871 // return '0' for index 0, and -1 for all other indices.
872 
873 // The following structure is defined publically so you can declare one on
874 // the stack or as a global or etc, but you should treat it as opaque.
875 struct stbtt_fontinfo {
876    void           * userdata;
877    ubyte  * data;              // pointer to .ttf file
878    int              fontstart;         // offset of start of font
879 
880    int numGlyphs;                     // number of glyphs, needed for range checking
881 
882    int loca,head,glyf,hhea,hmtx,kern,gpos; // table locations as offset from start of .ttf
883    int index_map;                     // a cmap mapping for our chosen character encoding
884    int indexToLocFormat;              // format needed to map from glyph index to glyph
885 
886    stbtt__buf cff;                    // cff font data
887    stbtt__buf charstrings;            // the charstring index
888    stbtt__buf gsubrs;                 // global charstring subroutines index
889    stbtt__buf subrs;                  // private charstring subroutines index
890    stbtt__buf fontdicts;              // array of font dicts
891    stbtt__buf fdselect;               // map from glyph to fontdict
892 }
893 
894 //STBTT_DEF int stbtt_InitFont(stbtt_fontinfo *info, const(ubyte)* data, int offset);
895 // Given an offset into the file that defines a font, this function builds
896 // the necessary cached info for the rest of the system. You must allocate
897 // the stbtt_fontinfo yourself, and stbtt_InitFont will fill it out. You don't
898 // need to do anything special to free it, because the contents are pure
899 // value data with no additional data structures. Returns 0 on failure.
900 
901 
902 // ////////////////////////////////////////////////////////////////////////////
903 //
904 // CHARACTER TO GLYPH-INDEX CONVERSIOn
905 
906 //STBTT_DEF int stbtt_FindGlyphIndex(const(stbtt_fontinfo)* info, int unicode_codepoint);
907 // If you're going to perform multiple operations on the same character
908 // and you want a speed-up, call this function with the character you're
909 // going to process, then use glyph-based functions instead of the
910 // codepoint-based functions.
911 
912 
913 // ////////////////////////////////////////////////////////////////////////////
914 //
915 // CHARACTER PROPERTIES
916 //
917 
918 //STBTT_DEF float stbtt_ScaleForPixelHeight(const(stbtt_fontinfo)* info, float pixels);
919 // computes a scale factor to produce a font whose "height" is 'pixels' tall.
920 // Height is measured as the distance from the highest ascender to the lowest
921 // descender; in other words, it's equivalent to calling stbtt_GetFontVMetrics
922 // and computing:
923 //       scale = pixels / (ascent - descent)
924 // so if you prefer to measure height by the ascent only, use a similar calculation.
925 
926 //STBTT_DEF float stbtt_ScaleForMappingEmToPixels(const(stbtt_fontinfo)* info, float pixels);
927 // computes a scale factor to produce a font whose EM size is mapped to
928 // 'pixels' tall. This is probably what traditional APIs compute, but
929 // I'm not positive.
930 
931 //STBTT_DEF void stbtt_GetFontVMetrics(const(stbtt_fontinfo)* info, int *ascent, int *descent, int *lineGap);
932 // ascent is the coordinate above the baseline the font extends; descent
933 // is the coordinate below the baseline the font extends (i.e. it is typically negative)
934 // lineGap is the spacing between one row's descent and the next row's ascent...
935 // so you should advance the vertical position by "*ascent - *descent + *lineGap"
936 //   these are expressed in unscaled coordinates, so you must multiply by
937 //   the scale factor for a given size
938 
939 //STBTT_DEF int  stbtt_GetFontVMetricsOS2(const(stbtt_fontinfo)* info, int *typoAscent, int *typoDescent, int *typoLineGap);
940 // analogous to GetFontVMetrics, but returns the "typographic" values from the OS/2
941 // table (specific to MS/Windows TTF files).
942 //
943 // Returns 1 on success (table present), 0 on failure.
944 
945 //STBTT_DEF void stbtt_GetFontBoundingBox(const(stbtt_fontinfo)* info, int *x0, int *y0, int *x1, int *y1);
946 // the bounding box around all possible characters
947 
948 //STBTT_DEF void stbtt_GetCodepointHMetrics(const(stbtt_fontinfo)* info, int codepoint, int *advanceWidth, int *leftSideBearing);
949 // leftSideBearing is the offset from the current horizontal position to the left edge of the character
950 // advanceWidth is the offset from the current horizontal position to the next horizontal position
951 //   these are expressed in unscaled coordinates
952 
953 //STBTT_DEF int  stbtt_GetCodepointKernAdvance(const(stbtt_fontinfo)* info, int ch1, int ch2);
954 // an additional amount to add to the 'advance' value between ch1 and ch2
955 
956 //STBTT_DEF int stbtt_GetCodepointBox(const(stbtt_fontinfo)* info, int codepoint, int *x0, int *y0, int *x1, int *y1);
957 // Gets the bounding box of the visible part of the glyph, in unscaled coordinates
958 
959 //STBTT_DEF void stbtt_GetGlyphHMetrics(const(stbtt_fontinfo)* info, int glyph_index, int *advanceWidth, int *leftSideBearing);
960 //STBTT_DEF int  stbtt_GetGlyphKernAdvance(const(stbtt_fontinfo)* info, int glyph1, int glyph2);
961 //STBTT_DEF int  stbtt_GetGlyphBox(const(stbtt_fontinfo)* info, int glyph_index, int *x0, int *y0, int *x1, int *y1);
962 // as above, but takes one or more glyph indices for greater efficiency
963 
964 
965 //////////////////////////////////////////////////////////////////////////////
966 //
967 // GLYPH SHAPES (you probably don't need these, but they have to go before
968 // the bitmaps for C declaration-order reasons)
969 //
970 
971 //#ifndef STBTT_vmove // you can predefine these to use different values (but why?)
972 enum {
973   STBTT_vmove=1,
974   STBTT_vline,
975   STBTT_vcurve,
976   STBTT_vcubic
977 }
978 
979 //#ifndef stbtt_vertex // you can predefine this to use different values (we share this with other code at RAD)
980 alias stbtt_vertex_type = short; // can't use stbtt_int16 because that's not visible in the header file
981 struct stbtt_vertex {
982   stbtt_vertex_type x,y,cx,cy,cx1,cy1;
983   ubyte type,padding;
984 }
985 //#endif
986 
987 //STBTT_DEF int stbtt_IsGlyphEmpty(const(stbtt_fontinfo)* info, int glyph_index);
988 // returns non-zero if nothing is drawn for this glyph
989 
990 //STBTT_DEF int stbtt_GetCodepointShape(const(stbtt_fontinfo)* info, int unicode_codepoint, stbtt_vertex **vertices);
991 //STBTT_DEF int stbtt_GetGlyphShape(const(stbtt_fontinfo)* info, int glyph_index, stbtt_vertex **vertices);
992 // returns # of vertices and fills *vertices with the pointer to them
993 //   these are expressed in "unscaled" coordinates
994 //
995 // The shape is a series of countours. Each one starts with
996 // a STBTT_moveto, then consists of a series of mixed
997 // STBTT_lineto and STBTT_curveto segments. A lineto
998 // draws a line from previous endpoint to its x,y; a curveto
999 // draws a quadratic bezier from previous endpoint to
1000 // its x,y, using cx,cy as the bezier control point.
1001 
1002 //STBTT_DEF void stbtt_FreeShape(const(stbtt_fontinfo)* info, stbtt_vertex *vertices);
1003 // frees the data allocated above
1004 
1005 // ////////////////////////////////////////////////////////////////////////////
1006 //
1007 // BITMAP RENDERING
1008 //
1009 
1010 //STBTT_DEF void stbtt_FreeBitmap(ubyte *bitmap, void *userdata);
1011 // frees the bitmap allocated below
1012 
1013 //STBTT_DEF ubyte *stbtt_GetCodepointBitmap(const(stbtt_fontinfo)* info, float scale_x, float scale_y, int codepoint, int *width, int *height, int *xoff, int *yoff);
1014 // allocates a large-enough single-channel 8bpp bitmap and renders the
1015 // specified character/glyph at the specified scale into it, with
1016 // antialiasing. 0 is no coverage (transparent), 255 is fully covered (opaque).
1017 // *width & *height are filled out with the width & height of the bitmap,
1018 // which is stored left-to-right, top-to-bottom.
1019 //
1020 // xoff/yoff are the offset it pixel space from the glyph origin to the top-left of the bitmap
1021 
1022 //STBTT_DEF 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);
1023 // the same as stbtt_GetCodepoitnBitmap, but you can specify a subpixel
1024 // shift for the character
1025 
1026 //STBTT_DEF 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);
1027 // the same as stbtt_GetCodepointBitmap, but you pass in storage for the bitmap
1028 // in the form of 'output', with row spacing of 'out_stride' bytes. the bitmap
1029 // is clipped to out_w/out_h bytes. Call stbtt_GetCodepointBitmapBox to get the
1030 // width and height and positioning info for it first.
1031 
1032 //STBTT_DEF 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);
1033 // same as stbtt_MakeCodepointBitmap, but you can specify a subpixel
1034 // shift for the character
1035 
1036 //STBTT_DEF void stbtt_MakeCodepointBitmapSubpixelPrefilter(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 oversample_x, int oversample_y, float *sub_x, float *sub_y, int codepoint);
1037 // same as stbtt_MakeCodepointBitmapSubpixel, but prefiltering
1038 // is performed (see stbtt_PackSetOversampling)
1039 
1040 //STBTT_DEF void stbtt_GetCodepointBitmapBox(const(stbtt_fontinfo)* font, int codepoint, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1);
1041 // get the bbox of the bitmap centered around the glyph origin; so the
1042 // bitmap width is ix1-ix0, height is iy1-iy0, and location to place
1043 // the bitmap top left is (leftSideBearing*scale,iy0).
1044 // (Note that the bitmap uses y-increases-down, but the shape uses
1045 // y-increases-up, so CodepointBitmapBox and CodepointBox are inverted.)
1046 
1047 //STBTT_DEF 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);
1048 // same as stbtt_GetCodepointBitmapBox, but you can specify a subpixel
1049 // shift for the character
1050 
1051 // the following functions are equivalent to the above functions, but operate
1052 // on glyph indices instead of Unicode codepoints (for efficiency)
1053 //STBTT_DEF ubyte *stbtt_GetGlyphBitmap(const(stbtt_fontinfo)* info, float scale_x, float scale_y, int glyph, int *width, int *height, int *xoff, int *yoff);
1054 //STBTT_DEF 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);
1055 //STBTT_DEF 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);
1056 //STBTT_DEF 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);
1057 //STBTT_DEF void stbtt_MakeGlyphBitmapSubpixelPrefilter(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 oversample_x, int oversample_y, float *sub_x, float *sub_y, int glyph);
1058 //STBTT_DEF void stbtt_GetGlyphBitmapBox(const(stbtt_fontinfo)* font, int glyph, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1);
1059 //STBTT_DEF 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);
1060 
1061 
1062 // @TODO: don't expose this structure
1063 struct stbtt__bitmap {
1064    int w,h,stride;
1065    ubyte *pixels;
1066 }
1067 
1068 // rasterize a shape with quadratic beziers into a bitmap
1069 /+
1070 STBTT_DEF void stbtt_Rasterize(stbtt__bitmap *result,        // 1-channel bitmap to draw into
1071                                float flatness_in_pixels,     // allowable error of curve in pixels
1072                                stbtt_vertex *vertices,       // array of vertices defining shape
1073                                int num_verts,                // number of vertices in above array
1074                                float scale_x, float scale_y, // scale applied to input vertices
1075                                float shift_x, float shift_y, // translation applied to input vertices
1076                                int x_off, int y_off,         // another translation applied to input
1077                                int invert,                   // if non-zero, vertically flip shape
1078                                void *userdata);              // context for to STBTT_MALLOC
1079 +/
1080 
1081 // ////////////////////////////////////////////////////////////////////////////
1082 //
1083 // Signed Distance Function (or Field) rendering
1084 
1085 //STBTT_DEF void stbtt_FreeSDF(ubyte *bitmap, void *userdata);
1086 // frees the SDF bitmap allocated below
1087 
1088 //STBTT_DEF ubyte * stbtt_GetGlyphSDF(const(stbtt_fontinfo)* info, float scale, int glyph, int padding, ubyte onedge_value, float pixel_dist_scale, int *width, int *height, int *xoff, int *yoff);
1089 //STBTT_DEF ubyte * stbtt_GetCodepointSDF(const(stbtt_fontinfo)* info, float scale, int codepoint, int padding, ubyte onedge_value, float pixel_dist_scale, int *width, int *height, int *xoff, int *yoff);
1090 // These functions compute a discretized SDF field for a single character, suitable for storing
1091 // in a single-channel texture, sampling with bilinear filtering, and testing against
1092 // larger than some threshhold to produce scalable fonts.
1093 //        info              --  the font
1094 //        scale             --  controls the size of the resulting SDF bitmap, same as it would be creating a regular bitmap
1095 //        glyph/codepoint   --  the character to generate the SDF for
1096 //        padding           --  extra "pixels" around the character which are filled with the distance to the character (not 0),
1097 //                                 which allows effects like bit outlines
1098 //        onedge_value      --  value 0-255 to test the SDF against to reconstruct the character (i.e. the isocontour of the character)
1099 //        pixel_dist_scale  --  what value the SDF should increase by when moving one SDF "pixel" away from the edge (on the 0..255 scale)
1100 //                                 if positive, > onedge_value is inside; if negative, < onedge_value is inside
1101 //        width,height      --  output height & width of the SDF bitmap (including padding)
1102 //        xoff,yoff         --  output origin of the character
1103 //        return value      --  a 2D array of bytes 0..255, width*height in size
1104 //
1105 // pixel_dist_scale & onedge_value are a scale & bias that allows you to make
1106 // optimal use of the limited 0..255 for your application, trading off precision
1107 // and special effects. SDF values outside the range 0..255 are clamped to 0..255.
1108 //
1109 // Example:
1110 //      scale = stbtt_ScaleForPixelHeight(22)
1111 //      padding = 5
1112 //      onedge_value = 180
1113 //      pixel_dist_scale = 180/5.0 = 36.0
1114 //
1115 //      This will create an SDF bitmap in which the character is about 22 pixels
1116 //      high but the whole bitmap is about 22+5+5=32 pixels high. To produce a filled
1117 //      shape, sample the SDF at each pixel and fill the pixel if the SDF value
1118 //      is greater than or equal to 180/255. (You'll actually want to antialias,
1119 //      which is beyond the scope of this example.) Additionally, you can compute
1120 //      offset outlines (e.g. to stroke the character border inside & outside,
1121 //      or only outside). For example, to fill outside the character up to 3 SDF
1122 //      pixels, you would compare against (180-36.0*3)/255 = 72/255. The above
1123 //      choice of variables maps a range from 5 pixels outside the shape to
1124 //      2 pixels inside the shape to 0..255; this is intended primarily for apply
1125 //      outside effects only (the interior range is needed to allow proper
1126 //      antialiasing of the font at *smaller* sizes)
1127 //
1128 // The function computes the SDF analytically at each SDF pixel, not by e.g.
1129 // building a higher-res bitmap and approximating it. In theory the quality
1130 // should be as high as possible for an SDF of this size & representation, but
1131 // unclear if this is true in practice (perhaps building a higher-res bitmap
1132 // and computing from that can allow drop-out prevention).
1133 //
1134 // The algorithm has not been optimized at all, so expect it to be slow
1135 // if computing lots of characters or very large sizes.
1136 
1137 
1138 
1139 //////////////////////////////////////////////////////////////////////////////
1140 //
1141 // Finding the right font...
1142 //
1143 // You should really just solve this offline, keep your own tables
1144 // of what font is what, and don't try to get it out of the .ttf file.
1145 // That's because getting it out of the .ttf file is really hard, because
1146 // the names in the file can appear in many possible encodings, in many
1147 // possible languages, and e.g. if you need a case-insensitive comparison,
1148 // the details of that depend on the encoding & language in a complex way
1149 // (actually underspecified in truetype, but also gigantic).
1150 //
1151 // But you can use the provided functions in two possible ways:
1152 //     stbtt_FindMatchingFont() will use *case-sensitive* comparisons on
1153 //             unicode-encoded names to try to find the font you want;
1154 //             you can run this before calling stbtt_InitFont()
1155 //
1156 //     stbtt_GetFontNameString() lets you get any of the various strings
1157 //             from the file yourself and do your own comparisons on them.
1158 //             You have to have called stbtt_InitFont() first.
1159 
1160 
1161 //STBTT_DEF int stbtt_FindMatchingFont(const(ubyte)* fontdata, const(char)* name, int flags);
1162 // returns the offset (not index) of the font that matches, or -1 if none
1163 //   if you use STBTT_MACSTYLE_DONTCARE, use a font name like "Arial Bold".
1164 //   if you use any other flag, use a font name like "Arial"; this checks
1165 //     the 'macStyle' header field; i don't know if fonts set this consistently
1166 enum {
1167   STBTT_MACSTYLE_DONTCARE   = 0,
1168   STBTT_MACSTYLE_BOLD       = 1,
1169   STBTT_MACSTYLE_ITALIC     = 2,
1170   STBTT_MACSTYLE_UNDERSCORE = 4,
1171   STBTT_MACSTYLE_NONE       = 8,   // <= not same as 0, this makes us check the bitfield is 0
1172 }
1173 
1174 //STBTT_DEF int stbtt_CompareUTF8toUTF16_bigendian(const(char)* s1, int len1, const(char)* s2, int len2);
1175 // returns 1/0 whether the first string interpreted as utf8 is identical to
1176 // the second string interpreted as big-endian utf16... useful for strings from next func
1177 
1178 //STBTT_DEF const(char)* stbtt_GetFontNameString(const(stbtt_fontinfo)* font, int *length, int platformID, int encodingID, int languageID, int nameID);
1179 // returns the string (which may be big-endian double byte, e.g. for unicode)
1180 // and puts the length in bytes in *length.
1181 //
1182 // some of the values for the IDs are below; for more see the truetype spec:
1183 //     http://developer.apple.com/textfonts/TTRefMan/RM06/Chap6name.html
1184 //     http://www.microsoft.com/typography/otspec/name.htm
1185 
1186 enum { // platformID
1187    STBTT_PLATFORM_ID_UNICODE   =0,
1188    STBTT_PLATFORM_ID_MAC       =1,
1189    STBTT_PLATFORM_ID_ISO       =2,
1190    STBTT_PLATFORM_ID_MICROSOFT =3
1191 }
1192 
1193 enum { // encodingID for STBTT_PLATFORM_ID_UNICODE
1194    STBTT_UNICODE_EID_UNICODE_1_0    =0,
1195    STBTT_UNICODE_EID_UNICODE_1_1    =1,
1196    STBTT_UNICODE_EID_ISO_10646      =2,
1197    STBTT_UNICODE_EID_UNICODE_2_0_BMP=3,
1198    STBTT_UNICODE_EID_UNICODE_2_0_FULL=4
1199 }
1200 
1201 enum { // encodingID for STBTT_PLATFORM_ID_MICROSOFT
1202    STBTT_MS_EID_SYMBOL        =0,
1203    STBTT_MS_EID_UNICODE_BMP   =1,
1204    STBTT_MS_EID_SHIFTJIS      =2,
1205    STBTT_MS_EID_UNICODE_FULL  =10
1206 }
1207 
1208 enum { // encodingID for STBTT_PLATFORM_ID_MAC; same as Script Manager codes
1209    STBTT_MAC_EID_ROMAN        =0,   STBTT_MAC_EID_ARABIC       =4,
1210    STBTT_MAC_EID_JAPANESE     =1,   STBTT_MAC_EID_HEBREW       =5,
1211    STBTT_MAC_EID_CHINESE_TRAD =2,   STBTT_MAC_EID_GREEK        =6,
1212    STBTT_MAC_EID_KOREAN       =3,   STBTT_MAC_EID_RUSSIAN      =7
1213 }
1214 
1215 enum { // languageID for STBTT_PLATFORM_ID_MICROSOFT; same as LCID...
1216        // problematic because there are e.g. 16 english LCIDs and 16 arabic LCIDs
1217    STBTT_MS_LANG_ENGLISH     =0x0409,   STBTT_MS_LANG_ITALIAN     =0x0410,
1218    STBTT_MS_LANG_CHINESE     =0x0804,   STBTT_MS_LANG_JAPANESE    =0x0411,
1219    STBTT_MS_LANG_DUTCH       =0x0413,   STBTT_MS_LANG_KOREAN      =0x0412,
1220    STBTT_MS_LANG_FRENCH      =0x040c,   STBTT_MS_LANG_RUSSIAN     =0x0419,
1221    STBTT_MS_LANG_GERMAN      =0x0407,   STBTT_MS_LANG_SPANISH     =0x0409,
1222    STBTT_MS_LANG_HEBREW      =0x040d,   STBTT_MS_LANG_SWEDISH     =0x041D
1223 }
1224 
1225 enum { // languageID for STBTT_PLATFORM_ID_MAC
1226    STBTT_MAC_LANG_ENGLISH      =0 ,   STBTT_MAC_LANG_JAPANESE     =11,
1227    STBTT_MAC_LANG_ARABIC       =12,   STBTT_MAC_LANG_KOREAN       =23,
1228    STBTT_MAC_LANG_DUTCH        =4 ,   STBTT_MAC_LANG_RUSSIAN      =32,
1229    STBTT_MAC_LANG_FRENCH       =1 ,   STBTT_MAC_LANG_SPANISH      =6 ,
1230    STBTT_MAC_LANG_GERMAN       =2 ,   STBTT_MAC_LANG_SWEDISH      =5 ,
1231    STBTT_MAC_LANG_HEBREW       =10,   STBTT_MAC_LANG_CHINESE_SIMPLIFIED =33,
1232    STBTT_MAC_LANG_ITALIAN      =3 ,   STBTT_MAC_LANG_CHINESE_TRAD =19
1233 }
1234 
1235 
1236 // /////////////////////////////////////////////////////////////////////////////
1237 // /////////////////////////////////////////////////////////////////////////////
1238 // //
1239 // //   IMPLEMENTATION
1240 // //
1241 // //
1242 private:
1243 
1244 enum STBTT_MAX_OVERSAMPLE = 8; // it also must be POT
1245 static assert(STBTT_MAX_OVERSAMPLE > 0 && STBTT_MAX_OVERSAMPLE <= 255, "STBTT_MAX_OVERSAMPLE cannot be > 255");
1246 
1247 //typedef int stbtt__test_oversample_pow2[(STBTT_MAX_OVERSAMPLE & (STBTT_MAX_OVERSAMPLE-1)) == 0 ? 1 : -1];
1248 
1249 enum STBTT_RASTERIZER_VERSION = 2;
1250 
1251 /*
1252 #ifdef _MSC_VER
1253 #define STBTT__NOTUSED(v)  (void)(v)
1254 #else
1255 #define STBTT__NOTUSED(v)  (void)sizeof(v)
1256 #endif
1257 */
1258 
1259 // ////////////////////////////////////////////////////////////////////////
1260 //
1261 // stbtt__buf helpers to parse data from file
1262 //
1263 
1264 private stbtt_uint8 stbtt__buf_get8(stbtt__buf *b)
1265 {
1266    if (b.cursor >= b.size)
1267       return 0;
1268    return b.data[b.cursor++];
1269 }
1270 
1271 private stbtt_uint8 stbtt__buf_peek8(stbtt__buf *b)
1272 {
1273    if (b.cursor >= b.size)
1274       return 0;
1275    return b.data[b.cursor];
1276 }
1277 
1278 private void stbtt__buf_seek(stbtt__buf *b, int o)
1279 {
1280    assert(!(o > b.size || o < 0));
1281    b.cursor = (o > b.size || o < 0) ? b.size : o;
1282 }
1283 
1284 private void stbtt__buf_skip(stbtt__buf *b, int o)
1285 {
1286    stbtt__buf_seek(b, b.cursor + o);
1287 }
1288 
1289 private stbtt_uint32 stbtt__buf_get(stbtt__buf *b, int n)
1290 {
1291    stbtt_uint32 v = 0;
1292    int i;
1293    assert(n >= 1 && n <= 4);
1294    for (i = 0; i < n; i++)
1295       v = (v << 8) | stbtt__buf_get8(b);
1296    return v;
1297 }
1298 
1299 private stbtt__buf stbtt__new_buf(const(void)* p, size_t size)
1300 {
1301    stbtt__buf r;
1302    assert(size < 0x40000000);
1303    r.data = cast(stbtt_uint8*) p;
1304    r.size = cast(int) size;
1305    r.cursor = 0;
1306    return r;
1307 }
1308 
1309 //#define stbtt__buf_get16(b)  stbtt__buf_get((b), 2)
1310 //#define stbtt__buf_get32(b)  stbtt__buf_get((b), 4)
1311 ushort stbtt__buf_get16 (stbtt__buf *b) { pragma(inline, true); return cast(ushort)stbtt__buf_get(b, 2); }
1312 uint stbtt__buf_get32 (stbtt__buf *b) { pragma(inline, true); return cast(uint)stbtt__buf_get(b, 4); }
1313 
1314 private stbtt__buf stbtt__buf_range(const(stbtt__buf)* b, int o, int s)
1315 {
1316    stbtt__buf r = stbtt__new_buf(null, 0);
1317    if (o < 0 || s < 0 || o > b.size || s > b.size - o) return r;
1318    r.data = cast(ubyte*)b.data + o;
1319    r.size = s;
1320    return r;
1321 }
1322 
1323 private stbtt__buf stbtt__cff_get_index(stbtt__buf *b)
1324 {
1325    int count, start, offsize;
1326    start = b.cursor;
1327    count = stbtt__buf_get16(b);
1328    if (count) {
1329       offsize = stbtt__buf_get8(b);
1330       assert(offsize >= 1 && offsize <= 4);
1331       stbtt__buf_skip(b, offsize * count);
1332       stbtt__buf_skip(b, stbtt__buf_get(b, offsize) - 1);
1333    }
1334    return stbtt__buf_range(b, start, b.cursor - start);
1335 }
1336 
1337 private stbtt_uint32 stbtt__cff_int(stbtt__buf *b)
1338 {
1339    int b0 = stbtt__buf_get8(b);
1340    if (b0 >= 32 && b0 <= 246)       return b0 - 139;
1341    else if (b0 >= 247 && b0 <= 250) return (b0 - 247)*256 + stbtt__buf_get8(b) + 108;
1342    else if (b0 >= 251 && b0 <= 254) return -(b0 - 251)*256 - stbtt__buf_get8(b) - 108;
1343    else if (b0 == 28)               return stbtt__buf_get16(b);
1344    else if (b0 == 29)               return stbtt__buf_get32(b);
1345    assert(0);
1346 }
1347 
1348 private void stbtt__cff_skip_operand(stbtt__buf *b) {
1349    int v, b0 = stbtt__buf_peek8(b);
1350    assert(b0 >= 28);
1351    if (b0 == 30) {
1352       stbtt__buf_skip(b, 1);
1353       while (b.cursor < b.size) {
1354          v = stbtt__buf_get8(b);
1355          if ((v & 0xF) == 0xF || (v >> 4) == 0xF)
1356             break;
1357       }
1358    } else {
1359       stbtt__cff_int(b);
1360    }
1361 }
1362 
1363 private stbtt__buf stbtt__dict_get(stbtt__buf *b, int key)
1364 {
1365    stbtt__buf_seek(b, 0);
1366    while (b.cursor < b.size) {
1367       int start = b.cursor, end, op;
1368       while (stbtt__buf_peek8(b) >= 28)
1369          stbtt__cff_skip_operand(b);
1370       end = b.cursor;
1371       op = stbtt__buf_get8(b);
1372       if (op == 12)  op = stbtt__buf_get8(b) | 0x100;
1373       if (op == key) return stbtt__buf_range(b, start, end-start);
1374    }
1375    return stbtt__buf_range(b, 0, 0);
1376 }
1377 
1378 private void stbtt__dict_get_ints(stbtt__buf *b, int key, int outcount, stbtt_uint32 *outstb)
1379 {
1380    int i;
1381    stbtt__buf operands = stbtt__dict_get(b, key);
1382    for (i = 0; i < outcount && operands.cursor < operands.size; i++)
1383       outstb[i] = stbtt__cff_int(&operands);
1384 }
1385 
1386 private int stbtt__cff_index_count(stbtt__buf *b)
1387 {
1388    stbtt__buf_seek(b, 0);
1389    return stbtt__buf_get16(b);
1390 }
1391 
1392 private stbtt__buf stbtt__cff_index_get(stbtt__buf b, int i)
1393 {
1394    int count, offsize, start, end;
1395    stbtt__buf_seek(&b, 0);
1396    count = stbtt__buf_get16(&b);
1397    offsize = stbtt__buf_get8(&b);
1398    assert(i >= 0 && i < count);
1399    assert(offsize >= 1 && offsize <= 4);
1400    stbtt__buf_skip(&b, i*offsize);
1401    start = stbtt__buf_get(&b, offsize);
1402    end = stbtt__buf_get(&b, offsize);
1403    return stbtt__buf_range(&b, 2+(count+1)*offsize+start, end - start);
1404 }
1405 
1406 //////////////////////////////////////////////////////////////////////////
1407 //
1408 // accessors to parse data from file
1409 //
1410 
1411 // on platforms that don't allow misaligned reads, if we want to allow
1412 // truetype fonts that aren't padded to alignment, define ALLOW_UNALIGNED_TRUETYPE
1413 
1414 //#define ttBYTE(p)     (* (stbtt_uint8 *) (p))
1415 //#define ttCHAR(p)     (* (stbtt_int8 *) (p))
1416 //#define ttFixed(p)    ttLONG(p)
1417 stbtt_uint8 ttBYTE (const(void)* p) pure { pragma(inline, true); return *cast(const(stbtt_uint8)*)p; }
1418 stbtt_int8 ttCHAR (const(void)* p) pure { pragma(inline, true); return *cast(const(stbtt_int8)*)p; }
1419 
1420 private stbtt_uint16 ttUSHORT(const(stbtt_uint8)* p) { return p[0]*256 + p[1]; }
1421 private stbtt_int16 ttSHORT(const(stbtt_uint8)* p)   { return cast(stbtt_int16)(p[0]*256 + p[1]); }
1422 private stbtt_uint32 ttULONG(const(stbtt_uint8)* p)  { return (p[0]<<24) + (p[1]<<16) + (p[2]<<8) + p[3]; }
1423 private stbtt_int32 ttLONG(const(stbtt_uint8)* p)    { return (p[0]<<24) + (p[1]<<16) + (p[2]<<8) + p[3]; }
1424 
1425 //#define stbtt_tag4(p,c0,c1,c2,c3) ((p)[0] == (c0) && (p)[1] == (c1) && (p)[2] == (c2) && (p)[3] == (c3))
1426 //#define stbtt_tag(p,str)           stbtt_tag4(p,str[0],str[1],str[2],str[3])
1427 
1428 bool stbtt_tag4 (const(void)* p, ubyte c0, ubyte c1, ubyte c2, ubyte c3) pure {
1429   return
1430     (cast(const(ubyte)*)p)[0] == c0 &&
1431     (cast(const(ubyte)*)p)[1] == c1 &&
1432     (cast(const(ubyte)*)p)[2] == c2 &&
1433     (cast(const(ubyte)*)p)[3] == c3;
1434 }
1435 
1436 bool stbtt_tag (const(void)* p, const(void)* str) {
1437   //stbtt_tag4(p,str[0],str[1],str[2],str[3])
1438   import core.stdc.string : memcmp;
1439   return (memcmp(p, str, 4) == 0);
1440 }
1441 
1442 private int stbtt__isfont(stbtt_uint8 *font)
1443 {
1444    // check the version number
1445    if (stbtt_tag4(font, '1',0,0,0))  return 1; // TrueType 1
1446    if (stbtt_tag(font, "typ1".ptr))   return 1; // TrueType with type 1 font -- we don't support this!
1447    if (stbtt_tag(font, "OTTO".ptr))   return 1; // OpenType with CFF
1448    if (stbtt_tag4(font, 0,1,0,0)) return 1; // OpenType 1.0
1449    if (stbtt_tag(font, "true".ptr))   return 1; // Apple specification for TrueType fonts
1450    return 0;
1451 }
1452 
1453 // @OPTIMIZE: binary search
1454 private stbtt_uint32 stbtt__find_table(stbtt_uint8 *data, stbtt_uint32 fontstart, const(char)* tag)
1455 {
1456    stbtt_int32 num_tables = ttUSHORT(data+fontstart+4);
1457    stbtt_uint32 tabledir = fontstart + 12;
1458    stbtt_int32 i;
1459    for (i=0; i < num_tables; ++i) {
1460       stbtt_uint32 loc = tabledir + 16*i;
1461       if (stbtt_tag(data+loc+0, tag))
1462          return ttULONG(data+loc+8);
1463    }
1464    return 0;
1465 }
1466 
1467 private int stbtt_GetFontOffsetForIndex_internal(ubyte *font_collection, int index)
1468 {
1469    // if it's just a font, there's only one valid index
1470    if (stbtt__isfont(font_collection))
1471       return index == 0 ? 0 : -1;
1472 
1473    // check if it's a TTC
1474    if (stbtt_tag(font_collection, "ttcf".ptr)) {
1475       // version 1?
1476       if (ttULONG(font_collection+4) == 0x00010000 || ttULONG(font_collection+4) == 0x00020000) {
1477          stbtt_int32 n = ttLONG(font_collection+8);
1478          if (index >= n)
1479             return -1;
1480          return ttULONG(font_collection+12+index*4);
1481       }
1482    }
1483    return -1;
1484 }
1485 
1486 private int stbtt_GetNumberOfFonts_internal(ubyte *font_collection)
1487 {
1488    // if it's just a font, there's only one valid font
1489    if (stbtt__isfont(font_collection))
1490       return 1;
1491 
1492    // check if it's a TTC
1493    if (stbtt_tag(font_collection, "ttcf".ptr)) {
1494       // version 1?
1495       if (ttULONG(font_collection+4) == 0x00010000 || ttULONG(font_collection+4) == 0x00020000) {
1496          return ttLONG(font_collection+8);
1497       }
1498    }
1499    return 0;
1500 }
1501 
1502 private stbtt__buf stbtt__get_subrs(stbtt__buf cff, stbtt__buf fontdict)
1503 {
1504    stbtt_uint32 subrsoff = 0;
1505    stbtt_uint32[2] private_loc = 0;
1506    stbtt__buf pdict;
1507    stbtt__dict_get_ints(&fontdict, 18, 2, private_loc.ptr);
1508    if (!private_loc[1] || !private_loc[0]) return stbtt__new_buf(null, 0);
1509    pdict = stbtt__buf_range(&cff, private_loc[1], private_loc[0]);
1510    stbtt__dict_get_ints(&pdict, 19, 1, &subrsoff);
1511    if (!subrsoff) return stbtt__new_buf(null, 0);
1512    stbtt__buf_seek(&cff, private_loc[1]+subrsoff);
1513    return stbtt__cff_get_index(&cff);
1514 }
1515 
1516 private int stbtt_InitFont_internal(stbtt_fontinfo *info, ubyte *data, int fontstart)
1517 {
1518    stbtt_uint32 cmap, t;
1519    stbtt_int32 i,numTables;
1520 
1521    info.data = data;
1522    info.fontstart = fontstart;
1523    info.cff = stbtt__new_buf(null, 0);
1524 
1525    cmap = stbtt__find_table(data, fontstart, "cmap");       // required
1526    info.loca = stbtt__find_table(data, fontstart, "loca"); // required
1527    info.head = stbtt__find_table(data, fontstart, "head"); // required
1528    info.glyf = stbtt__find_table(data, fontstart, "glyf"); // required
1529    info.hhea = stbtt__find_table(data, fontstart, "hhea"); // required
1530    info.hmtx = stbtt__find_table(data, fontstart, "hmtx"); // required
1531    info.kern = stbtt__find_table(data, fontstart, "kern"); // not required
1532    info.gpos = stbtt__find_table(data, fontstart, "GPOS"); // not required
1533 
1534    if (!cmap || !info.head || !info.hhea || !info.hmtx)
1535       return 0;
1536    if (info.glyf) {
1537       // required for truetype
1538       if (!info.loca) return 0;
1539    } else {
1540       // initialization for CFF / Type2 fonts (OTF)
1541       stbtt__buf b, topdict, topdictidx;
1542       stbtt_uint32 cstype = 2, charstrings = 0, fdarrayoff = 0, fdselectoff = 0;
1543       stbtt_uint32 cff;
1544 
1545       cff = stbtt__find_table(data, fontstart, "CFF ");
1546       if (!cff) return 0;
1547 
1548       info.fontdicts = stbtt__new_buf(null, 0);
1549       info.fdselect = stbtt__new_buf(null, 0);
1550 
1551       // @TODO this should use size from table (not 512MB)
1552       info.cff = stbtt__new_buf(data+cff, 512*1024*1024);
1553       b = info.cff;
1554 
1555       // read the header
1556       stbtt__buf_skip(&b, 2);
1557       stbtt__buf_seek(&b, stbtt__buf_get8(&b)); // hdrsize
1558 
1559       // @TODO the name INDEX could list multiple fonts,
1560       // but we just use the first one.
1561       stbtt__cff_get_index(&b);  // name INDEX
1562       topdictidx = stbtt__cff_get_index(&b);
1563       topdict = stbtt__cff_index_get(topdictidx, 0);
1564       stbtt__cff_get_index(&b);  // string INDEX
1565       info.gsubrs = stbtt__cff_get_index(&b);
1566 
1567       stbtt__dict_get_ints(&topdict, 17, 1, &charstrings);
1568       stbtt__dict_get_ints(&topdict, 0x100 | 6, 1, &cstype);
1569       stbtt__dict_get_ints(&topdict, 0x100 | 36, 1, &fdarrayoff);
1570       stbtt__dict_get_ints(&topdict, 0x100 | 37, 1, &fdselectoff);
1571       info.subrs = stbtt__get_subrs(b, topdict);
1572 
1573       // we only support Type 2 charstrings
1574       if (cstype != 2) return 0;
1575       if (charstrings == 0) return 0;
1576 
1577       if (fdarrayoff) {
1578          // looks like a CID font
1579          if (!fdselectoff) return 0;
1580          stbtt__buf_seek(&b, fdarrayoff);
1581          info.fontdicts = stbtt__cff_get_index(&b);
1582          info.fdselect = stbtt__buf_range(&b, fdselectoff, b.size-fdselectoff);
1583       }
1584 
1585       stbtt__buf_seek(&b, charstrings);
1586       info.charstrings = stbtt__cff_get_index(&b);
1587    }
1588 
1589    t = stbtt__find_table(data, fontstart, "maxp");
1590    if (t)
1591       info.numGlyphs = ttUSHORT(data+t+4);
1592    else
1593       info.numGlyphs = 0xffff;
1594 
1595    // find a cmap encoding table we understand *now* to avoid searching
1596    // later. (todo: could make this installable)
1597    // the same regardless of glyph.
1598    numTables = ttUSHORT(data + cmap + 2);
1599    info.index_map = 0;
1600    for (i=0; i < numTables; ++i) {
1601       stbtt_uint32 encoding_record = cmap + 4 + 8 * i;
1602       // find an encoding we understand:
1603       switch(ttUSHORT(data+encoding_record)) {
1604          case STBTT_PLATFORM_ID_MICROSOFT:
1605             switch (ttUSHORT(data+encoding_record+2)) {
1606                case STBTT_MS_EID_UNICODE_BMP:
1607                case STBTT_MS_EID_UNICODE_FULL:
1608                   // MS/Unicode
1609                   info.index_map = cmap + ttULONG(data+encoding_record+4);
1610                   break;
1611                default:
1612             }
1613             break;
1614         case STBTT_PLATFORM_ID_UNICODE:
1615             // Mac/iOS has these
1616             // all the encodingIDs are unicode, so we don't bother to check it
1617             info.index_map = cmap + ttULONG(data+encoding_record+4);
1618             break;
1619         default:
1620       }
1621    }
1622    if (info.index_map == 0)
1623       return 0;
1624 
1625    info.indexToLocFormat = ttUSHORT(data+info.head + 50);
1626    return 1;
1627 }
1628 
1629 public int stbtt_FindGlyphIndex(const(stbtt_fontinfo)* info, int unicode_codepoint)
1630 {
1631    stbtt_uint8 *data = cast(stbtt_uint8*)info.data;
1632    stbtt_uint32 index_map = info.index_map;
1633 
1634    stbtt_uint16 format = ttUSHORT(data + index_map + 0);
1635    if (format == 0) { // apple byte encoding
1636       stbtt_int32 bytes = ttUSHORT(data + index_map + 2);
1637       if (unicode_codepoint < bytes-6)
1638          return ttBYTE(data + index_map + 6 + unicode_codepoint);
1639       return 0;
1640    } else if (format == 6) {
1641       stbtt_uint32 first = ttUSHORT(data + index_map + 6);
1642       stbtt_uint32 count = ttUSHORT(data + index_map + 8);
1643       if (cast(stbtt_uint32) unicode_codepoint >= first && cast(stbtt_uint32) unicode_codepoint < first+count)
1644          return ttUSHORT(data + index_map + 10 + (unicode_codepoint - first)*2);
1645       return 0;
1646    } else if (format == 2) {
1647       assert(0); // @TODO: high-byte mapping for japanese/chinese/korean
1648    } else if (format == 4) { // standard mapping for windows fonts: binary search collection of ranges
1649       stbtt_uint16 segcount = ttUSHORT(data+index_map+6) >> 1;
1650       stbtt_uint16 searchRange = ttUSHORT(data+index_map+8) >> 1;
1651       stbtt_uint16 entrySelector = ttUSHORT(data+index_map+10);
1652       stbtt_uint16 rangeShift = ttUSHORT(data+index_map+12) >> 1;
1653 
1654       // do a binary search of the segments
1655       stbtt_uint32 endCount = index_map + 14;
1656       stbtt_uint32 search = endCount;
1657 
1658       if (unicode_codepoint > 0xffff)
1659          return 0;
1660 
1661       // they lie from endCount .. endCount + segCount
1662       // but searchRange is the nearest power of two, so...
1663       if (unicode_codepoint >= ttUSHORT(data + search + rangeShift*2))
1664          search += rangeShift*2;
1665 
1666       // now decrement to bias correctly to find smallest
1667       search -= 2;
1668       while (entrySelector) {
1669          stbtt_uint16 end;
1670          searchRange >>= 1;
1671          end = ttUSHORT(data + search + searchRange*2);
1672          if (unicode_codepoint > end)
1673             search += searchRange*2;
1674          --entrySelector;
1675       }
1676       search += 2;
1677 
1678       {
1679          stbtt_uint16 offset, start;
1680          stbtt_uint16 item = cast(stbtt_uint16) ((search - endCount) >> 1);
1681 
1682          assert(unicode_codepoint <= ttUSHORT(data + endCount + 2*item));
1683          start = ttUSHORT(data + index_map + 14 + segcount*2 + 2 + 2*item);
1684          if (unicode_codepoint < start)
1685             return 0;
1686 
1687          offset = ttUSHORT(data + index_map + 14 + segcount*6 + 2 + 2*item);
1688          if (offset == 0)
1689             return cast(stbtt_uint16) (unicode_codepoint + ttSHORT(data + index_map + 14 + segcount*4 + 2 + 2*item));
1690 
1691          return ttUSHORT(data + offset + (unicode_codepoint-start)*2 + index_map + 14 + segcount*6 + 2 + 2*item);
1692       }
1693    } else if (format == 12 || format == 13) {
1694       stbtt_uint32 ngroups = ttULONG(data+index_map+12);
1695       stbtt_int32 low,high;
1696       low = 0; high = cast(stbtt_int32)ngroups;
1697       // Binary search the right group.
1698       while (low < high) {
1699          stbtt_int32 mid = low + ((high-low) >> 1); // rounds down, so low <= mid < high
1700          stbtt_uint32 start_char = ttULONG(data+index_map+16+mid*12);
1701          stbtt_uint32 end_char = ttULONG(data+index_map+16+mid*12+4);
1702          if (cast(stbtt_uint32) unicode_codepoint < start_char)
1703             high = mid;
1704          else if (cast(stbtt_uint32) unicode_codepoint > end_char)
1705             low = mid+1;
1706          else {
1707             stbtt_uint32 start_glyph = ttULONG(data+index_map+16+mid*12+8);
1708             if (format == 12)
1709                return start_glyph + unicode_codepoint-start_char;
1710             else // format == 13
1711                return start_glyph;
1712          }
1713       }
1714       return 0; // not found
1715    }
1716    // @TODO
1717    assert(0);
1718 }
1719 
1720 public int stbtt_GetCodepointShape(stbtt_fontinfo* info, int unicode_codepoint, stbtt_vertex **vertices)
1721 {
1722    return stbtt_GetGlyphShape(info, stbtt_FindGlyphIndex(info, unicode_codepoint), vertices);
1723 }
1724 
1725 private void stbtt_setvertex(stbtt_vertex *v, stbtt_uint8 type, stbtt_int32 x, stbtt_int32 y, stbtt_int32 cx, stbtt_int32 cy)
1726 {
1727    v.type = type;
1728    v.x = cast(stbtt_int16) x;
1729    v.y = cast(stbtt_int16) y;
1730    v.cx = cast(stbtt_int16) cx;
1731    v.cy = cast(stbtt_int16) cy;
1732 }
1733 
1734 private int stbtt__GetGlyfOffset(const(stbtt_fontinfo)* info, int glyph_index)
1735 {
1736    int g1,g2;
1737 
1738    assert(!info.cff.size);
1739 
1740    if (glyph_index >= info.numGlyphs) return -1; // glyph index out of range
1741    if (info.indexToLocFormat >= 2)    return -1; // unknown index->glyph map format
1742 
1743    if (info.indexToLocFormat == 0) {
1744       g1 = info.glyf + ttUSHORT(info.data + info.loca + glyph_index * 2) * 2;
1745       g2 = info.glyf + ttUSHORT(info.data + info.loca + glyph_index * 2 + 2) * 2;
1746    } else {
1747       g1 = info.glyf + ttULONG (info.data + info.loca + glyph_index * 4);
1748       g2 = info.glyf + ttULONG (info.data + info.loca + glyph_index * 4 + 4);
1749    }
1750 
1751    return g1==g2 ? -1 : g1; // if length is 0, return -1
1752 }
1753 
1754 //private int stbtt__GetGlyphInfoT2(const(stbtt_fontinfo)* info, int glyph_index, int *x0, int *y0, int *x1, int *y1);
1755 
1756 public int stbtt_GetGlyphBox(stbtt_fontinfo* info, int glyph_index, int *x0, int *y0, int *x1, int *y1)
1757 {
1758    if (info.cff.size) {
1759       stbtt__GetGlyphInfoT2(info, glyph_index, x0, y0, x1, y1);
1760    } else {
1761       int g = stbtt__GetGlyfOffset(info, glyph_index);
1762       if (g < 0) return 0;
1763 
1764       if (x0) *x0 = ttSHORT(info.data + g + 2);
1765       if (y0) *y0 = ttSHORT(info.data + g + 4);
1766       if (x1) *x1 = ttSHORT(info.data + g + 6);
1767       if (y1) *y1 = ttSHORT(info.data + g + 8);
1768    }
1769    return 1;
1770 }
1771 
1772 public int stbtt_GetCodepointBox(stbtt_fontinfo* info, int codepoint, int *x0, int *y0, int *x1, int *y1)
1773 {
1774    return stbtt_GetGlyphBox(info, stbtt_FindGlyphIndex(info,codepoint), x0,y0,x1,y1);
1775 }
1776 
1777 public int stbtt_IsGlyphEmpty(stbtt_fontinfo* info, int glyph_index)
1778 {
1779    stbtt_int16 numberOfContours;
1780    int g;
1781    if (info.cff.size)
1782       return stbtt__GetGlyphInfoT2(info, glyph_index, null, null, null, null) == 0;
1783    g = stbtt__GetGlyfOffset(info, glyph_index);
1784    if (g < 0) return 1;
1785    numberOfContours = ttSHORT(info.data + g);
1786    return numberOfContours == 0;
1787 }
1788 
1789 private int stbtt__close_shape(stbtt_vertex *vertices, int num_vertices, int was_off, int start_off,
1790     stbtt_int32 sx, stbtt_int32 sy, stbtt_int32 scx, stbtt_int32 scy, stbtt_int32 cx, stbtt_int32 cy)
1791 {
1792    if (start_off) {
1793       if (was_off)
1794          stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, (cx+scx)>>1, (cy+scy)>>1, cx,cy);
1795       stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, sx,sy,scx,scy);
1796    } else {
1797       if (was_off)
1798          stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve,sx,sy,cx,cy);
1799       else
1800          stbtt_setvertex(&vertices[num_vertices++], STBTT_vline,sx,sy,0,0);
1801    }
1802    return num_vertices;
1803 }
1804 
1805 private int stbtt__GetGlyphShapeTT(stbtt_fontinfo* info, int glyph_index, stbtt_vertex **pvertices)
1806 {
1807    stbtt_int16 numberOfContours;
1808    stbtt_uint8 *endPtsOfContours;
1809    stbtt_uint8 *data = cast(stbtt_uint8*)info.data;
1810    stbtt_vertex *vertices = null;
1811    int num_vertices=0;
1812    int g = stbtt__GetGlyfOffset(info, glyph_index);
1813 
1814    *pvertices = null;
1815 
1816    if (g < 0) return 0;
1817 
1818    numberOfContours = ttSHORT(data + g);
1819 
1820    if (numberOfContours > 0) {
1821       stbtt_uint8 flags=0,flagcount;
1822       stbtt_int32 ins, i,j=0,m,n, next_move, was_off=0, off, start_off=0;
1823       stbtt_int32 x,y,cx,cy,sx,sy, scx,scy;
1824       stbtt_uint8 *points;
1825       endPtsOfContours = (data + g + 10);
1826       ins = ttUSHORT(data + g + 10 + numberOfContours * 2);
1827       points = data + g + 10 + numberOfContours * 2 + 2 + ins;
1828 
1829       n = 1+ttUSHORT(endPtsOfContours + numberOfContours*2-2);
1830 
1831       m = n + 2*numberOfContours;  // a loose bound on how many vertices we might need
1832       vertices = cast(stbtt_vertex *) STBTT_malloc(m * cast(uint)vertices[0].sizeof, info.userdata);
1833       if (vertices is null)
1834          return 0;
1835 
1836       next_move = 0;
1837       flagcount=0;
1838 
1839       // in first pass, we load uninterpreted data into the allocated array
1840       // above, shifted to the end of the array so we won't overwrite it when
1841       // we create our final data starting from the front
1842 
1843       off = m - n; // starting offset for uninterpreted data, regardless of how m ends up being calculated
1844 
1845       // first load flags
1846 
1847       for (i=0; i < n; ++i) {
1848          if (flagcount == 0) {
1849             flags = *points++;
1850             if (flags & 8)
1851                flagcount = *points++;
1852          } else
1853             --flagcount;
1854          vertices[off+i].type = flags;
1855       }
1856 
1857       // now load x coordinates
1858       x=0;
1859       for (i=0; i < n; ++i) {
1860          flags = vertices[off+i].type;
1861          if (flags & 2) {
1862             stbtt_int16 dx = *points++;
1863             x += (flags & 16) ? cast(int)dx : -cast(int)dx; // ???
1864          } else {
1865             if (!(flags & 16)) {
1866                x = x + cast(stbtt_int16) (points[0]*256 + points[1]);
1867                points += 2;
1868             }
1869          }
1870          vertices[off+i].x = cast(stbtt_int16) x;
1871       }
1872 
1873       // now load y coordinates
1874       y=0;
1875       for (i=0; i < n; ++i) {
1876          flags = vertices[off+i].type;
1877          if (flags & 4) {
1878             stbtt_int16 dy = *points++;
1879             y += (flags & 32) ? cast(int)dy : -cast(int)dy; // ???
1880          } else {
1881             if (!(flags & 32)) {
1882                y = y + cast(stbtt_int16) (points[0]*256 + points[1]);
1883                points += 2;
1884             }
1885          }
1886          vertices[off+i].y = cast(stbtt_int16) y;
1887       }
1888 
1889       // now convert them to our format
1890       num_vertices=0;
1891       sx = sy = cx = cy = scx = scy = 0;
1892       for (i=0; i < n; ++i) {
1893          flags = vertices[off+i].type;
1894          x     = cast(stbtt_int16) vertices[off+i].x;
1895          y     = cast(stbtt_int16) vertices[off+i].y;
1896 
1897          if (next_move == i) {
1898             if (i != 0)
1899                num_vertices = stbtt__close_shape(vertices, num_vertices, was_off, start_off, sx,sy,scx,scy,cx,cy);
1900 
1901             // now start the new one
1902             start_off = !(flags & 1);
1903             if (start_off) {
1904                // if we start off with an off-curve point, then when we need to find a point on the curve
1905                // where we can start, and we need to save some state for when we wraparound.
1906                scx = x;
1907                scy = y;
1908                if (!(vertices[off+i+1].type & 1)) {
1909                   // next point is also a curve point, so interpolate an on-point curve
1910                   sx = (x + cast(stbtt_int32) vertices[off+i+1].x) >> 1;
1911                   sy = (y + cast(stbtt_int32) vertices[off+i+1].y) >> 1;
1912                } else {
1913                   // otherwise just use the next point as our start point
1914                   sx = cast(stbtt_int32) vertices[off+i+1].x;
1915                   sy = cast(stbtt_int32) vertices[off+i+1].y;
1916                   ++i; // we're using point i+1 as the starting point, so skip it
1917                }
1918             } else {
1919                sx = x;
1920                sy = y;
1921             }
1922             stbtt_setvertex(&vertices[num_vertices++], STBTT_vmove,sx,sy,0,0);
1923             was_off = 0;
1924             next_move = 1 + ttUSHORT(endPtsOfContours+j*2);
1925             ++j;
1926          } else {
1927             if (!(flags & 1)) { // if it's a curve
1928                if (was_off) // two off-curve control points in a row means interpolate an on-curve midpoint
1929                   stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, (cx+x)>>1, (cy+y)>>1, cx, cy);
1930                cx = x;
1931                cy = y;
1932                was_off = 1;
1933             } else {
1934                if (was_off)
1935                   stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, x,y, cx, cy);
1936                else
1937                   stbtt_setvertex(&vertices[num_vertices++], STBTT_vline, x,y,0,0);
1938                was_off = 0;
1939             }
1940          }
1941       }
1942       num_vertices = stbtt__close_shape(vertices, num_vertices, was_off, start_off, sx,sy,scx,scy,cx,cy);
1943    } else if (numberOfContours == -1) {
1944       // Compound shapes.
1945       int more = 1;
1946       stbtt_uint8 *comp = data + g + 10;
1947       num_vertices = 0;
1948       vertices = null;
1949       while (more) {
1950          stbtt_uint16 flags, gidx;
1951          int comp_num_verts = 0, i;
1952          stbtt_vertex *comp_verts = null, tmp = null;
1953          float[6] mtx = [1,0,0,1,0,0];
1954          float m, n;
1955 
1956          flags = ttSHORT(comp); comp+=2;
1957          gidx = ttSHORT(comp); comp+=2;
1958 
1959          if (flags & 2) { // XY values
1960             if (flags & 1) { // shorts
1961                mtx[4] = ttSHORT(comp); comp+=2;
1962                mtx[5] = ttSHORT(comp); comp+=2;
1963             } else {
1964                mtx[4] = ttCHAR(comp); comp+=1;
1965                mtx[5] = ttCHAR(comp); comp+=1;
1966             }
1967          }
1968          else {
1969             // @TODO handle matching point
1970             assert(0);
1971          }
1972          if (flags & (1<<3)) { // WE_HAVE_A_SCALE
1973             mtx[0] = mtx[3] = ttSHORT(comp)/16384.0f; comp+=2;
1974             mtx[1] = mtx[2] = 0;
1975          } else if (flags & (1<<6)) { // WE_HAVE_AN_X_AND_YSCALE
1976             mtx[0] = ttSHORT(comp)/16384.0f; comp+=2;
1977             mtx[1] = mtx[2] = 0;
1978             mtx[3] = ttSHORT(comp)/16384.0f; comp+=2;
1979          } else if (flags & (1<<7)) { // WE_HAVE_A_TWO_BY_TWO
1980             mtx[0] = ttSHORT(comp)/16384.0f; comp+=2;
1981             mtx[1] = ttSHORT(comp)/16384.0f; comp+=2;
1982             mtx[2] = ttSHORT(comp)/16384.0f; comp+=2;
1983             mtx[3] = ttSHORT(comp)/16384.0f; comp+=2;
1984          }
1985 
1986          // Find transformation scales.
1987          m = cast(float) STBTT_sqrt(mtx[0]*mtx[0] + mtx[1]*mtx[1]);
1988          n = cast(float) STBTT_sqrt(mtx[2]*mtx[2] + mtx[3]*mtx[3]);
1989 
1990          // Get indexed glyph.
1991          comp_num_verts = stbtt_GetGlyphShape(info, gidx, &comp_verts);
1992          if (comp_num_verts > 0) {
1993             // Transform vertices.
1994             for (i = 0; i < comp_num_verts; ++i) {
1995                stbtt_vertex* v = &comp_verts[i];
1996                stbtt_vertex_type x,y;
1997                x=v.x; y=v.y;
1998                v.x = cast(stbtt_vertex_type)(m * (mtx[0]*x + mtx[2]*y + mtx[4]));
1999                v.y = cast(stbtt_vertex_type)(n * (mtx[1]*x + mtx[3]*y + mtx[5]));
2000                x=v.cx; y=v.cy;
2001                v.cx = cast(stbtt_vertex_type)(m * (mtx[0]*x + mtx[2]*y + mtx[4]));
2002                v.cy = cast(stbtt_vertex_type)(n * (mtx[1]*x + mtx[3]*y + mtx[5]));
2003             }
2004             // Append vertices.
2005             tmp = cast(stbtt_vertex*)STBTT_malloc((num_vertices+comp_num_verts)*cast(uint)stbtt_vertex.sizeof, info.userdata);
2006             if (!tmp) {
2007                if (vertices) STBTT_free(vertices, info.userdata);
2008                if (comp_verts) STBTT_free(comp_verts, info.userdata);
2009                return 0;
2010             }
2011             if (num_vertices > 0) STBTT_memcpy(tmp, vertices, num_vertices*cast(uint)stbtt_vertex.sizeof);
2012             STBTT_memcpy(tmp+num_vertices, comp_verts, comp_num_verts*cast(uint)stbtt_vertex.sizeof);
2013             if (vertices) STBTT_free(vertices, info.userdata);
2014             vertices = tmp;
2015             STBTT_free(comp_verts, info.userdata);
2016             num_vertices += comp_num_verts;
2017          }
2018          // More components ?
2019          more = flags & (1<<5);
2020       }
2021    } else if (numberOfContours < 0) {
2022       // @TODO other compound variations?
2023       assert(0);
2024    } else {
2025       // numberOfCounters == 0, do nothing
2026    }
2027 
2028    *pvertices = vertices;
2029    return num_vertices;
2030 }
2031 
2032 struct stbtt__csctx {
2033    int bounds;
2034    int started;
2035    float first_x, first_y;
2036    float x, y;
2037    stbtt_int32 min_x, max_x, min_y, max_y;
2038 
2039    stbtt_vertex *pvertices;
2040    int num_vertices;
2041 }
2042 
2043 //#define STBTT__CSCTX_INIT(bounds) {bounds,0, 0,0, 0,0, 0,0,0,0, null, 0}
2044 
2045 private void stbtt__track_vertex(stbtt__csctx *c, stbtt_int32 x, stbtt_int32 y)
2046 {
2047    if (x > c.max_x || !c.started) c.max_x = x;
2048    if (y > c.max_y || !c.started) c.max_y = y;
2049    if (x < c.min_x || !c.started) c.min_x = x;
2050    if (y < c.min_y || !c.started) c.min_y = y;
2051    c.started = 1;
2052 }
2053 
2054 private void stbtt__csctx_v(stbtt__csctx *c, stbtt_uint8 type, stbtt_int32 x, stbtt_int32 y, stbtt_int32 cx, stbtt_int32 cy, stbtt_int32 cx1, stbtt_int32 cy1)
2055 {
2056    if (c.bounds) {
2057       stbtt__track_vertex(c, x, y);
2058       if (type == STBTT_vcubic) {
2059          stbtt__track_vertex(c, cx, cy);
2060          stbtt__track_vertex(c, cx1, cy1);
2061       }
2062    } else {
2063       stbtt_setvertex(&c.pvertices[c.num_vertices], type, x, y, cx, cy);
2064       c.pvertices[c.num_vertices].cx1 = cast(stbtt_int16) cx1;
2065       c.pvertices[c.num_vertices].cy1 = cast(stbtt_int16) cy1;
2066    }
2067    c.num_vertices++;
2068 }
2069 
2070 private void stbtt__csctx_close_shape(stbtt__csctx *ctx)
2071 {
2072    if (ctx.first_x != ctx.x || ctx.first_y != ctx.y)
2073       stbtt__csctx_v(ctx, STBTT_vline, cast(int)ctx.first_x, cast(int)ctx.first_y, 0, 0, 0, 0);
2074 }
2075 
2076 private void stbtt__csctx_rmove_to(stbtt__csctx *ctx, float dx, float dy)
2077 {
2078    stbtt__csctx_close_shape(ctx);
2079    ctx.first_x = ctx.x = ctx.x + dx;
2080    ctx.first_y = ctx.y = ctx.y + dy;
2081    stbtt__csctx_v(ctx, STBTT_vmove, cast(int)ctx.x, cast(int)ctx.y, 0, 0, 0, 0);
2082 }
2083 
2084 private void stbtt__csctx_rline_to(stbtt__csctx *ctx, float dx, float dy)
2085 {
2086    ctx.x += dx;
2087    ctx.y += dy;
2088    stbtt__csctx_v(ctx, STBTT_vline, cast(int)ctx.x, cast(int)ctx.y, 0, 0, 0, 0);
2089 }
2090 
2091 private void stbtt__csctx_rccurve_to(stbtt__csctx *ctx, float dx1, float dy1, float dx2, float dy2, float dx3, float dy3)
2092 {
2093    float cx1 = ctx.x + dx1;
2094    float cy1 = ctx.y + dy1;
2095    float cx2 = cx1 + dx2;
2096    float cy2 = cy1 + dy2;
2097    ctx.x = cx2 + dx3;
2098    ctx.y = cy2 + dy3;
2099    stbtt__csctx_v(ctx, STBTT_vcubic, cast(int)ctx.x, cast(int)ctx.y, cast(int)cx1, cast(int)cy1, cast(int)cx2, cast(int)cy2);
2100 }
2101 
2102 private stbtt__buf stbtt__get_subr(stbtt__buf idx, int n)
2103 {
2104    int count = stbtt__cff_index_count(&idx);
2105    int bias = 107;
2106    if (count >= 33900)
2107       bias = 32768;
2108    else if (count >= 1240)
2109       bias = 1131;
2110    n += bias;
2111    if (n < 0 || n >= count)
2112       return stbtt__new_buf(null, 0);
2113    return stbtt__cff_index_get(idx, n);
2114 }
2115 
2116 private stbtt__buf stbtt__cid_get_glyph_subrs(stbtt_fontinfo* info, int glyph_index)
2117 {
2118    stbtt__buf fdselect = info.fdselect;
2119    int nranges, start, end, v, fmt, fdselector = -1, i;
2120 
2121    stbtt__buf_seek(&fdselect, 0);
2122    fmt = stbtt__buf_get8(&fdselect);
2123    if (fmt == 0) {
2124       // untested
2125       stbtt__buf_skip(&fdselect, glyph_index);
2126       fdselector = stbtt__buf_get8(&fdselect);
2127    } else if (fmt == 3) {
2128       nranges = stbtt__buf_get16(&fdselect);
2129       start = stbtt__buf_get16(&fdselect);
2130       for (i = 0; i < nranges; i++) {
2131          v = stbtt__buf_get8(&fdselect);
2132          end = stbtt__buf_get16(&fdselect);
2133          if (glyph_index >= start && glyph_index < end) {
2134             fdselector = v;
2135             break;
2136          }
2137          start = end;
2138       }
2139    }
2140    if (fdselector == -1) stbtt__new_buf(null, 0);
2141    return stbtt__get_subrs(info.cff, stbtt__cff_index_get(info.fontdicts, fdselector));
2142 }
2143 
2144 private int stbtt__run_charstring(stbtt_fontinfo* info, int glyph_index, stbtt__csctx *c)
2145 {
2146    int in_header = 1, maskbits = 0, subr_stack_height = 0, sp = 0, v, i, b0;
2147    int has_subrs = 0, clear_stack;
2148    float[48] s = void;
2149    stbtt__buf[10] subr_stack = void;
2150    stbtt__buf subrs = info.subrs, b;
2151    float f;
2152 
2153    static int STBTT__CSERR(string s) { pragma(inline, true); return 0; }
2154 
2155    // this currently ignores the initial width value, which isn't needed if we have hmtx
2156    b = stbtt__cff_index_get(info.charstrings, glyph_index);
2157    while (b.cursor < b.size) {
2158       i = 0;
2159       clear_stack = 1;
2160       b0 = stbtt__buf_get8(&b);
2161       switch (b0) {
2162       // @TODO implement hinting
2163       case 0x13: // hintmask
2164       case 0x14: // cntrmask
2165          if (in_header)
2166             maskbits += (sp / 2); // implicit "vstem"
2167          in_header = 0;
2168          stbtt__buf_skip(&b, (maskbits + 7) / 8);
2169          break;
2170 
2171       case 0x01: // hstem
2172       case 0x03: // vstem
2173       case 0x12: // hstemhm
2174       case 0x17: // vstemhm
2175          maskbits += (sp / 2);
2176          break;
2177 
2178       case 0x15: // rmoveto
2179          in_header = 0;
2180          if (sp < 2) return STBTT__CSERR("rmoveto stack");
2181          stbtt__csctx_rmove_to(c, s[sp-2], s[sp-1]);
2182          break;
2183       case 0x04: // vmoveto
2184          in_header = 0;
2185          if (sp < 1) return STBTT__CSERR("vmoveto stack");
2186          stbtt__csctx_rmove_to(c, 0, s[sp-1]);
2187          break;
2188       case 0x16: // hmoveto
2189          in_header = 0;
2190          if (sp < 1) return STBTT__CSERR("hmoveto stack");
2191          stbtt__csctx_rmove_to(c, s[sp-1], 0);
2192          break;
2193 
2194       case 0x05: // rlineto
2195          if (sp < 2) return STBTT__CSERR("rlineto stack");
2196          for (; i + 1 < sp; i += 2)
2197             stbtt__csctx_rline_to(c, s[i], s[i+1]);
2198          break;
2199 
2200       // hlineto/vlineto and vhcurveto/hvcurveto alternate horizontal and vertical
2201       // starting from a different place.
2202 
2203       case 0x07: // vlineto
2204          if (sp < 1) return STBTT__CSERR("vlineto stack");
2205          goto vlineto;
2206       case 0x06: // hlineto
2207          if (sp < 1) return STBTT__CSERR("hlineto stack");
2208          for (;;) {
2209             if (i >= sp) break;
2210             stbtt__csctx_rline_to(c, s[i], 0);
2211             i++;
2212       vlineto:
2213             if (i >= sp) break;
2214             stbtt__csctx_rline_to(c, 0, s[i]);
2215             i++;
2216          }
2217          break;
2218 
2219       case 0x1F: // hvcurveto
2220          if (sp < 4) return STBTT__CSERR("hvcurveto stack");
2221          goto hvcurveto;
2222       case 0x1E: // vhcurveto
2223          if (sp < 4) return STBTT__CSERR("vhcurveto stack");
2224          for (;;) {
2225             if (i + 3 >= sp) break;
2226             stbtt__csctx_rccurve_to(c, 0, s[i], s[i+1], s[i+2], s[i+3], (sp - i == 5) ? s[i + 4] : 0.0f);
2227             i += 4;
2228       hvcurveto:
2229             if (i + 3 >= sp) break;
2230             stbtt__csctx_rccurve_to(c, s[i], 0, s[i+1], s[i+2], (sp - i == 5) ? s[i+4] : 0.0f, s[i+3]);
2231             i += 4;
2232          }
2233          break;
2234 
2235       case 0x08: // rrcurveto
2236          if (sp < 6) return STBTT__CSERR("rcurveline stack");
2237          for (; i + 5 < sp; i += 6)
2238             stbtt__csctx_rccurve_to(c, s[i], s[i+1], s[i+2], s[i+3], s[i+4], s[i+5]);
2239          break;
2240 
2241       case 0x18: // rcurveline
2242          if (sp < 8) return STBTT__CSERR("rcurveline stack");
2243          for (; i + 5 < sp - 2; i += 6)
2244             stbtt__csctx_rccurve_to(c, s[i], s[i+1], s[i+2], s[i+3], s[i+4], s[i+5]);
2245          if (i + 1 >= sp) return STBTT__CSERR("rcurveline stack");
2246          stbtt__csctx_rline_to(c, s[i], s[i+1]);
2247          break;
2248 
2249       case 0x19: // rlinecurve
2250          if (sp < 8) return STBTT__CSERR("rlinecurve stack");
2251          for (; i + 1 < sp - 6; i += 2)
2252             stbtt__csctx_rline_to(c, s[i], s[i+1]);
2253          if (i + 5 >= sp) return STBTT__CSERR("rlinecurve stack");
2254          stbtt__csctx_rccurve_to(c, s[i], s[i+1], s[i+2], s[i+3], s[i+4], s[i+5]);
2255          break;
2256 
2257       case 0x1A: // vvcurveto
2258       case 0x1B: // hhcurveto
2259          if (sp < 4) return STBTT__CSERR("(vv|hh)curveto stack");
2260          f = 0.0;
2261          if (sp & 1) { f = s[i]; i++; }
2262          for (; i + 3 < sp; i += 4) {
2263             if (b0 == 0x1B)
2264                stbtt__csctx_rccurve_to(c, s[i], f, s[i+1], s[i+2], s[i+3], 0.0);
2265             else
2266                stbtt__csctx_rccurve_to(c, f, s[i], s[i+1], s[i+2], 0.0, s[i+3]);
2267             f = 0.0;
2268          }
2269          break;
2270 
2271       case 0x0A: // callsubr
2272          if (!has_subrs) {
2273             if (info.fdselect.size)
2274                subrs = stbtt__cid_get_glyph_subrs(info, glyph_index);
2275             has_subrs = 1;
2276          }
2277          // fallthrough
2278          goto case;
2279       case 0x1D: // callgsubr
2280          if (sp < 1) return STBTT__CSERR("call(g|)subr stack");
2281          v = cast(int) s[--sp];
2282          if (subr_stack_height >= 10) return STBTT__CSERR("recursion limit");
2283          subr_stack[subr_stack_height++] = b;
2284          b = stbtt__get_subr(b0 == 0x0A ? subrs : info.gsubrs, v);
2285          if (b.size == 0) return STBTT__CSERR("subr not found");
2286          b.cursor = 0;
2287          clear_stack = 0;
2288          break;
2289 
2290       case 0x0B: // return
2291          if (subr_stack_height <= 0) return STBTT__CSERR("return outside subr");
2292          b = subr_stack[--subr_stack_height];
2293          clear_stack = 0;
2294          break;
2295 
2296       case 0x0E: // endchar
2297          stbtt__csctx_close_shape(c);
2298          return 1;
2299 
2300       case 0x0C: { // two-byte escape
2301          float dx1, dx2, dx3, dx4, dx5, dx6, dy1, dy2, dy3, dy4, dy5, dy6;
2302          float dx, dy;
2303          int b1 = stbtt__buf_get8(&b);
2304          switch (b1) {
2305          // @TODO These "flex" implementations ignore the flex-depth and resolution,
2306          // and always draw beziers.
2307          case 0x22: // hflex
2308             if (sp < 7) return STBTT__CSERR("hflex stack");
2309             dx1 = s[0];
2310             dx2 = s[1];
2311             dy2 = s[2];
2312             dx3 = s[3];
2313             dx4 = s[4];
2314             dx5 = s[5];
2315             dx6 = s[6];
2316             stbtt__csctx_rccurve_to(c, dx1, 0, dx2, dy2, dx3, 0);
2317             stbtt__csctx_rccurve_to(c, dx4, 0, dx5, -dy2, dx6, 0);
2318             break;
2319 
2320          case 0x23: // flex
2321             if (sp < 13) return STBTT__CSERR("flex stack");
2322             dx1 = s[0];
2323             dy1 = s[1];
2324             dx2 = s[2];
2325             dy2 = s[3];
2326             dx3 = s[4];
2327             dy3 = s[5];
2328             dx4 = s[6];
2329             dy4 = s[7];
2330             dx5 = s[8];
2331             dy5 = s[9];
2332             dx6 = s[10];
2333             dy6 = s[11];
2334             //fd is s[12]
2335             stbtt__csctx_rccurve_to(c, dx1, dy1, dx2, dy2, dx3, dy3);
2336             stbtt__csctx_rccurve_to(c, dx4, dy4, dx5, dy5, dx6, dy6);
2337             break;
2338 
2339          case 0x24: // hflex1
2340             if (sp < 9) return STBTT__CSERR("hflex1 stack");
2341             dx1 = s[0];
2342             dy1 = s[1];
2343             dx2 = s[2];
2344             dy2 = s[3];
2345             dx3 = s[4];
2346             dx4 = s[5];
2347             dx5 = s[6];
2348             dy5 = s[7];
2349             dx6 = s[8];
2350             stbtt__csctx_rccurve_to(c, dx1, dy1, dx2, dy2, dx3, 0);
2351             stbtt__csctx_rccurve_to(c, dx4, 0, dx5, dy5, dx6, -(dy1+dy2+dy5));
2352             break;
2353 
2354          case 0x25: // flex1
2355             if (sp < 11) return STBTT__CSERR("flex1 stack");
2356             dx1 = s[0];
2357             dy1 = s[1];
2358             dx2 = s[2];
2359             dy2 = s[3];
2360             dx3 = s[4];
2361             dy3 = s[5];
2362             dx4 = s[6];
2363             dy4 = s[7];
2364             dx5 = s[8];
2365             dy5 = s[9];
2366             dx6 = dy6 = s[10];
2367             dx = dx1+dx2+dx3+dx4+dx5;
2368             dy = dy1+dy2+dy3+dy4+dy5;
2369             if (STBTT_fabs(dx) > STBTT_fabs(dy))
2370                dy6 = -dy;
2371             else
2372                dx6 = -dx;
2373             stbtt__csctx_rccurve_to(c, dx1, dy1, dx2, dy2, dx3, dy3);
2374             stbtt__csctx_rccurve_to(c, dx4, dy4, dx5, dy5, dx6, dy6);
2375             break;
2376 
2377          default:
2378             return STBTT__CSERR("unimplemented");
2379          }
2380       } break;
2381 
2382       default:
2383          if (b0 != 255 && b0 != 28 && (b0 < 32 || b0 > 254))
2384             return STBTT__CSERR("reserved operator");
2385 
2386          // push immediate
2387          if (b0 == 255) {
2388             f = cast(float)cast(stbtt_int32)stbtt__buf_get32(&b) / 0x10000;
2389          } else {
2390             stbtt__buf_skip(&b, -1);
2391             f = cast(float)cast(stbtt_int16)stbtt__cff_int(&b);
2392          }
2393          if (sp >= 48) return STBTT__CSERR("push stack overflow");
2394          s[sp++] = f;
2395          clear_stack = 0;
2396          break;
2397       }
2398       if (clear_stack) sp = 0;
2399    }
2400    return STBTT__CSERR("no endchar");
2401 }
2402 
2403 private int stbtt__GetGlyphShapeT2(stbtt_fontinfo* info, int glyph_index, stbtt_vertex **pvertices)
2404 {
2405    // runs the charstring twice, once to count and once to output (to avoid realloc)
2406    stbtt__csctx count_ctx = stbtt__csctx(1,0, 0,0, 0,0, 0,0,0,0, null, 0); //STBTT__CSCTX_INIT(1);
2407    stbtt__csctx output_ctx = stbtt__csctx(0,0, 0,0, 0,0, 0,0,0,0, null, 0); //STBTT__CSCTX_INIT(0);
2408    if (stbtt__run_charstring(info, glyph_index, &count_ctx)) {
2409       *pvertices = cast(stbtt_vertex*)STBTT_malloc(count_ctx.num_vertices*cast(uint)stbtt_vertex.sizeof, info.userdata);
2410       output_ctx.pvertices = *pvertices;
2411       if (stbtt__run_charstring(info, glyph_index, &output_ctx)) {
2412          assert(output_ctx.num_vertices == count_ctx.num_vertices);
2413          return output_ctx.num_vertices;
2414       }
2415    }
2416    *pvertices = null;
2417    return 0;
2418 }
2419 
2420 public int stbtt__GetGlyphInfoT2(stbtt_fontinfo* info, int glyph_index, int *x0, int *y0, int *x1, int *y1)
2421 {
2422    stbtt__csctx c = stbtt__csctx(1,0, 0,0, 0,0, 0,0,0,0, null, 0); //STBTT__CSCTX_INIT(1);
2423    int r = stbtt__run_charstring(info, glyph_index, &c); //k8: sorry
2424    if (x0)  *x0 = r ? c.min_x : 0;
2425    if (y0)  *y0 = r ? c.min_y : 0;
2426    if (x1)  *x1 = r ? c.max_x : 0;
2427    if (y1)  *y1 = r ? c.max_y : 0;
2428    return r ? c.num_vertices : 0;
2429 }
2430 
2431 public int stbtt_GetGlyphShape(stbtt_fontinfo* info, int glyph_index, stbtt_vertex **pvertices)
2432 {
2433    if (!info.cff.size)
2434       return stbtt__GetGlyphShapeTT(info, glyph_index, pvertices);
2435    else
2436       return stbtt__GetGlyphShapeT2(info, glyph_index, pvertices);
2437 }
2438 
2439 public void stbtt_GetGlyphHMetrics(const(stbtt_fontinfo)* info, int glyph_index, int *advanceWidth, int *leftSideBearing)
2440 {
2441    stbtt_uint16 numOfLongHorMetrics = ttUSHORT(info.data+info.hhea + 34);
2442    if (glyph_index < numOfLongHorMetrics) {
2443       if (advanceWidth)     *advanceWidth    = ttSHORT(info.data + info.hmtx + 4*glyph_index);
2444       if (leftSideBearing)  *leftSideBearing = ttSHORT(info.data + info.hmtx + 4*glyph_index + 2);
2445    } else {
2446       if (advanceWidth)     *advanceWidth    = ttSHORT(info.data + info.hmtx + 4*(numOfLongHorMetrics-1));
2447       if (leftSideBearing)  *leftSideBearing = ttSHORT(info.data + info.hmtx + 4*numOfLongHorMetrics + 2*(glyph_index - numOfLongHorMetrics));
2448    }
2449 }
2450 
2451 private int  stbtt__GetGlyphKernInfoAdvance(stbtt_fontinfo* info, int glyph1, int glyph2)
2452 {
2453    stbtt_uint8 *data = info.data + info.kern;
2454    stbtt_uint32 needle, straw;
2455    int l, r, m;
2456 
2457    // we only look at the first table. it must be 'horizontal' and format 0.
2458    if (!info.kern)
2459       return 0;
2460    if (ttUSHORT(data+2) < 1) // number of tables, need at least 1
2461       return 0;
2462    if (ttUSHORT(data+8) != 1) // horizontal flag must be set in format
2463       return 0;
2464 
2465    l = 0;
2466    r = ttUSHORT(data+10) - 1;
2467    needle = glyph1 << 16 | glyph2;
2468    while (l <= r) {
2469       m = (l + r) >> 1;
2470       straw = ttULONG(data+18+(m*6)); // note: unaligned read
2471       if (needle < straw)
2472          r = m - 1;
2473       else if (needle > straw)
2474          l = m + 1;
2475       else
2476          return ttSHORT(data+22+(m*6));
2477    }
2478    return 0;
2479 }
2480 
2481 private stbtt_int32  stbtt__GetCoverageIndex(stbtt_uint8 *coverageTable, int glyph)
2482 {
2483     stbtt_uint16 coverageFormat = ttUSHORT(coverageTable);
2484     switch(coverageFormat) {
2485         case 1: {
2486             stbtt_uint16 glyphCount = ttUSHORT(coverageTable + 2);
2487 
2488             // Binary search.
2489             stbtt_int32 l=0, r=glyphCount-1, m;
2490             int straw, needle=glyph;
2491             while (l <= r) {
2492                 stbtt_uint8 *glyphArray = coverageTable + 4;
2493                 stbtt_uint16 glyphID;
2494                 m = (l + r) >> 1;
2495                 glyphID = ttUSHORT(glyphArray + 2 * m);
2496                 straw = glyphID;
2497                 if (needle < straw)
2498                     r = m - 1;
2499                 else if (needle > straw)
2500                     l = m + 1;
2501                 else {
2502                      return m;
2503                 }
2504             }
2505         } break;
2506 
2507         case 2: {
2508             stbtt_uint16 rangeCount = ttUSHORT(coverageTable + 2);
2509             stbtt_uint8 *rangeArray = coverageTable + 4;
2510 
2511             // Binary search.
2512             stbtt_int32 l=0, r=rangeCount-1, m;
2513             int strawStart, strawEnd, needle=glyph;
2514             while (l <= r) {
2515                 stbtt_uint8 *rangeRecord;
2516                 m = (l + r) >> 1;
2517                 rangeRecord = rangeArray + 6 * m;
2518                 strawStart = ttUSHORT(rangeRecord);
2519                 strawEnd = ttUSHORT(rangeRecord + 2);
2520                 if (needle < strawStart)
2521                     r = m - 1;
2522                 else if (needle > strawEnd)
2523                     l = m + 1;
2524                 else {
2525                     stbtt_uint16 startCoverageIndex = ttUSHORT(rangeRecord + 4);
2526                     return startCoverageIndex + glyph - strawStart;
2527                 }
2528             }
2529         } break;
2530 
2531         default: {
2532             // There are no other cases.
2533             assert(0);
2534         }
2535     }
2536 
2537     return -1;
2538 }
2539 
2540 private stbtt_int32  stbtt__GetGlyphClass(stbtt_uint8 *classDefTable, int glyph)
2541 {
2542     stbtt_uint16 classDefFormat = ttUSHORT(classDefTable);
2543     switch(classDefFormat)
2544     {
2545         case 1: {
2546             stbtt_uint16 startGlyphID = ttUSHORT(classDefTable + 2);
2547             stbtt_uint16 glyphCount = ttUSHORT(classDefTable + 4);
2548             stbtt_uint8 *classDef1ValueArray = classDefTable + 6;
2549 
2550             if (glyph >= startGlyphID && glyph < startGlyphID + glyphCount)
2551                 return cast(stbtt_int32)ttUSHORT(classDef1ValueArray + 2 * (glyph - startGlyphID));
2552 
2553             classDefTable = classDef1ValueArray + 2 * glyphCount;
2554         } break;
2555 
2556         case 2: {
2557             stbtt_uint16 classRangeCount = ttUSHORT(classDefTable + 2);
2558             stbtt_uint8 *classRangeRecords = classDefTable + 4;
2559 
2560             // Binary search.
2561             stbtt_int32 l=0, r=classRangeCount-1, m;
2562             int strawStart, strawEnd, needle=glyph;
2563             while (l <= r) {
2564                 stbtt_uint8 *classRangeRecord;
2565                 m = (l + r) >> 1;
2566                 classRangeRecord = classRangeRecords + 6 * m;
2567                 strawStart = ttUSHORT(classRangeRecord);
2568                 strawEnd = ttUSHORT(classRangeRecord + 2);
2569                 if (needle < strawStart)
2570                     r = m - 1;
2571                 else if (needle > strawEnd)
2572                     l = m + 1;
2573                 else
2574                     return cast(stbtt_int32)ttUSHORT(classRangeRecord + 4);
2575             }
2576 
2577             classDefTable = classRangeRecords + 6 * classRangeCount;
2578         } break;
2579 
2580         default: {
2581             // There are no other cases.
2582             assert(0);
2583         }
2584     }
2585 
2586     return -1;
2587 }
2588 
2589 // Define to STBTT_assert(x) if you want to break on unimplemented formats.
2590 //#define STBTT_GPOS_TODO_assert(x)
2591 
2592 private stbtt_int32  stbtt__GetGlyphGPOSInfoAdvance(stbtt_fontinfo* info, int glyph1, int glyph2)
2593 {
2594     stbtt_uint16 lookupListOffset;
2595     stbtt_uint8 *lookupList;
2596     stbtt_uint16 lookupCount;
2597     stbtt_uint8 *data;
2598     stbtt_int32 i;
2599 
2600     if (!info.gpos) return 0;
2601 
2602     data = info.data + info.gpos;
2603 
2604     if (ttUSHORT(data+0) != 1) return 0; // Major version 1
2605     if (ttUSHORT(data+2) != 0) return 0; // Minor version 0
2606 
2607     lookupListOffset = ttUSHORT(data+8);
2608     lookupList = data + lookupListOffset;
2609     lookupCount = ttUSHORT(lookupList);
2610 
2611     for (i=0; i<lookupCount; ++i) {
2612         stbtt_uint16 lookupOffset = ttUSHORT(lookupList + 2 + 2 * i);
2613         stbtt_uint8 *lookupTable = lookupList + lookupOffset;
2614 
2615         stbtt_uint16 lookupType = ttUSHORT(lookupTable);
2616         stbtt_uint16 subTableCount = ttUSHORT(lookupTable + 4);
2617         stbtt_uint8 *subTableOffsets = lookupTable + 6;
2618         switch(lookupType) {
2619             case 2: { // Pair Adjustment Positioning Subtable
2620                 stbtt_int32 sti;
2621                 for (sti=0; sti<subTableCount; sti++) {
2622                     stbtt_uint16 subtableOffset = ttUSHORT(subTableOffsets + 2 * sti);
2623                     stbtt_uint8 *table = lookupTable + subtableOffset;
2624                     stbtt_uint16 posFormat = ttUSHORT(table);
2625                     stbtt_uint16 coverageOffset = ttUSHORT(table + 2);
2626                     stbtt_int32 coverageIndex = stbtt__GetCoverageIndex(table + coverageOffset, glyph1);
2627                     if (coverageIndex == -1) continue;
2628 
2629                     switch (posFormat) {
2630                         case 1: {
2631                             stbtt_int32 l, r, m;
2632                             int straw, needle;
2633                             stbtt_uint16 valueFormat1 = ttUSHORT(table + 4);
2634                             stbtt_uint16 valueFormat2 = ttUSHORT(table + 6);
2635                             stbtt_int32 valueRecordPairSizeInBytes = 2;
2636                             stbtt_uint16 pairSetCount = ttUSHORT(table + 8);
2637                             stbtt_uint16 pairPosOffset = ttUSHORT(table + 10 + 2 * coverageIndex);
2638                             stbtt_uint8 *pairValueTable = table + pairPosOffset;
2639                             stbtt_uint16 pairValueCount = ttUSHORT(pairValueTable);
2640                             stbtt_uint8 *pairValueArray = pairValueTable + 2;
2641                             // TODO: Support more formats.
2642                             //!STBTT_GPOS_TODO_assert(valueFormat1 == 4);
2643                             if (valueFormat1 != 4) return 0;
2644                             //!STBTT_GPOS_TODO_assert(valueFormat2 == 0);
2645                             if (valueFormat2 != 0) return 0;
2646 
2647                             assert(coverageIndex < pairSetCount);
2648 
2649                             needle=glyph2;
2650                             r=pairValueCount-1;
2651                             l=0;
2652 
2653                             // Binary search.
2654                             while (l <= r) {
2655                                 stbtt_uint16 secondGlyph;
2656                                 stbtt_uint8 *pairValue;
2657                                 m = (l + r) >> 1;
2658                                 pairValue = pairValueArray + (2 + valueRecordPairSizeInBytes) * m;
2659                                 secondGlyph = ttUSHORT(pairValue);
2660                                 straw = secondGlyph;
2661                                 if (needle < straw)
2662                                     r = m - 1;
2663                                 else if (needle > straw)
2664                                     l = m + 1;
2665                                 else {
2666                                     stbtt_int16 xAdvance = ttSHORT(pairValue + 2);
2667                                     return xAdvance;
2668                                 }
2669                             }
2670                         } break;
2671 
2672                         case 2: {
2673                             stbtt_uint16 valueFormat1 = ttUSHORT(table + 4);
2674                             stbtt_uint16 valueFormat2 = ttUSHORT(table + 6);
2675 
2676                             stbtt_uint16 classDef1Offset = ttUSHORT(table + 8);
2677                             stbtt_uint16 classDef2Offset = ttUSHORT(table + 10);
2678                             int glyph1class = stbtt__GetGlyphClass(table + classDef1Offset, glyph1);
2679                             int glyph2class = stbtt__GetGlyphClass(table + classDef2Offset, glyph2);
2680 
2681                             stbtt_uint16 class1Count = ttUSHORT(table + 12);
2682                             stbtt_uint16 class2Count = ttUSHORT(table + 14);
2683                             assert(glyph1class < class1Count);
2684                             assert(glyph2class < class2Count);
2685 
2686                             // TODO: Support more formats.
2687                             //!STBTT_GPOS_TODO_assert(valueFormat1 == 4);
2688                             if (valueFormat1 != 4) return 0;
2689                             //!STBTT_GPOS_TODO_assert(valueFormat2 == 0);
2690                             if (valueFormat2 != 0) return 0;
2691 
2692                             if (glyph1class >= 0 && glyph1class < class1Count && glyph2class >= 0 && glyph2class < class2Count) {
2693                                 stbtt_uint8 *class1Records = table + 16;
2694                                 stbtt_uint8 *class2Records = class1Records + 2 * (glyph1class * class2Count);
2695                                 stbtt_int16 xAdvance = ttSHORT(class2Records + 2 * glyph2class);
2696                                 return xAdvance;
2697                             }
2698                         } break;
2699 
2700                         default: {
2701                             // There are no other cases.
2702                             assert(0);
2703                         }
2704                     }
2705                 }
2706                 break;
2707             }
2708 
2709             default:
2710                 // TODO: Implement other stuff.
2711                 break;
2712         }
2713     }
2714 
2715     return 0;
2716 }
2717 
2718 public int  stbtt_GetGlyphKernAdvance(stbtt_fontinfo* info, int g1, int g2)
2719 {
2720    int xAdvance = 0;
2721 
2722    if (info.gpos)
2723       xAdvance += stbtt__GetGlyphGPOSInfoAdvance(info, g1, g2);
2724 
2725    if (info.kern)
2726       xAdvance += stbtt__GetGlyphKernInfoAdvance(info, g1, g2);
2727 
2728    return xAdvance;
2729 }
2730 
2731 public int  stbtt_GetCodepointKernAdvance(stbtt_fontinfo* info, int ch1, int ch2)
2732 {
2733    if (!info.kern && !info.gpos) // if no kerning table, don't waste time looking up both codepoint->glyphs
2734       return 0;
2735    return stbtt_GetGlyphKernAdvance(info, stbtt_FindGlyphIndex(info,ch1), stbtt_FindGlyphIndex(info,ch2));
2736 }
2737 
2738 public void stbtt_GetCodepointHMetrics(const(stbtt_fontinfo)* info, int codepoint, int *advanceWidth, int *leftSideBearing)
2739 {
2740    stbtt_GetGlyphHMetrics(info, stbtt_FindGlyphIndex(info,codepoint), advanceWidth, leftSideBearing);
2741 }
2742 
2743 public void stbtt_GetFontVMetrics(const(stbtt_fontinfo)* info, int *ascent, int *descent, int *lineGap)
2744 {
2745    if (ascent ) *ascent  = ttSHORT(info.data+info.hhea + 4);
2746    if (descent) *descent = ttSHORT(info.data+info.hhea + 6);
2747    if (lineGap) *lineGap = ttSHORT(info.data+info.hhea + 8);
2748 }
2749 
2750 public int  stbtt_GetFontVMetricsOS2(stbtt_fontinfo* info, int *typoAscent, int *typoDescent, int *typoLineGap)
2751 {
2752    int tab = stbtt__find_table(info.data, info.fontstart, "OS/2");
2753    if (!tab)
2754       return 0;
2755    if (typoAscent ) *typoAscent  = ttSHORT(info.data+tab + 68);
2756    if (typoDescent) *typoDescent = ttSHORT(info.data+tab + 70);
2757    if (typoLineGap) *typoLineGap = ttSHORT(info.data+tab + 72);
2758    return 1;
2759 }
2760 
2761 public int  stbtt_GetFontXHeight(stbtt_fontinfo* info, int *xHeight)
2762 {
2763    int tab = stbtt__find_table(info.data, info.fontstart, "OS/2");
2764    if (!tab)
2765       return 0;
2766    if (xHeight) {
2767       auto height = ttSHORT(info.data+tab + 86);
2768       if (height == 0) height = ttSHORT(info.data+tab + 2);
2769       *xHeight = height;
2770    }
2771    return 1;
2772 }
2773 
2774 public void stbtt_GetFontBoundingBox(const(stbtt_fontinfo)* info, int *x0, int *y0, int *x1, int *y1)
2775 {
2776    *x0 = ttSHORT(info.data + info.head + 36);
2777    *y0 = ttSHORT(info.data + info.head + 38);
2778    *x1 = ttSHORT(info.data + info.head + 40);
2779    *y1 = ttSHORT(info.data + info.head + 42);
2780 }
2781 
2782 public float stbtt_ScaleForPixelHeight(const(stbtt_fontinfo)* info, float height)
2783 {
2784    int fheight = ttSHORT(info.data + info.hhea + 4) - ttSHORT(info.data + info.hhea + 6);
2785    return cast(float) height / fheight;
2786 }
2787 
2788 public float stbtt_ScaleForMappingEmToPixels(const(stbtt_fontinfo)* info, float pixels)
2789 {
2790    int unitsPerEm = ttUSHORT(info.data + info.head + 18);
2791    return pixels / unitsPerEm;
2792 }
2793 
2794 public void stbtt_FreeShape(const(stbtt_fontinfo)* info, stbtt_vertex *v)
2795 {
2796    STBTT_free(v, info.userdata);
2797 }
2798 
2799 //////////////////////////////////////////////////////////////////////////////
2800 //
2801 // antialiasing software rasterizer
2802 //
2803 
2804 public void stbtt_GetGlyphBitmapBoxSubpixel(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)
2805 {
2806    int x0=0,y0=0,x1,y1; // =0 suppresses compiler warning
2807    if (!stbtt_GetGlyphBox(font, glyph, &x0,&y0,&x1,&y1)) {
2808       // e.g. space character
2809       if (ix0) *ix0 = 0;
2810       if (iy0) *iy0 = 0;
2811       if (ix1) *ix1 = 0;
2812       if (iy1) *iy1 = 0;
2813    } else {
2814       // move to integral bboxes (treating pixels as little squares, what pixels get touched)?
2815       if (ix0) *ix0 = STBTT_ifloor( x0 * scale_x + shift_x);
2816       if (iy0) *iy0 = STBTT_ifloor(-y1 * scale_y + shift_y);
2817       if (ix1) *ix1 = STBTT_iceil ( x1 * scale_x + shift_x);
2818       if (iy1) *iy1 = STBTT_iceil (-y0 * scale_y + shift_y);
2819    }
2820 }
2821 
2822 public void stbtt_GetGlyphBitmapBox(stbtt_fontinfo* font, int glyph, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1)
2823 {
2824    stbtt_GetGlyphBitmapBoxSubpixel(font, glyph, scale_x, scale_y,0.0f,0.0f, ix0, iy0, ix1, iy1);
2825 }
2826 
2827 public void stbtt_GetCodepointBitmapBoxSubpixel(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)
2828 {
2829    stbtt_GetGlyphBitmapBoxSubpixel(font, stbtt_FindGlyphIndex(font,codepoint), scale_x, scale_y,shift_x,shift_y, ix0,iy0,ix1,iy1);
2830 }
2831 
2832 public void stbtt_GetCodepointBitmapBox(stbtt_fontinfo* font, int codepoint, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1)
2833 {
2834    stbtt_GetCodepointBitmapBoxSubpixel(font, codepoint, scale_x, scale_y,0.0f,0.0f, ix0,iy0,ix1,iy1);
2835 }
2836 
2837 //////////////////////////////////////////////////////////////////////////////
2838 //
2839 //  Rasterizer
2840 
2841 struct stbtt__hheap_chunk {
2842    stbtt__hheap_chunk *next;
2843 }
2844 
2845 struct stbtt__hheap {
2846    stbtt__hheap_chunk *head;
2847    void   *first_free;
2848    int    num_remaining_in_head_chunk;
2849 }
2850 
2851 private void *stbtt__hheap_alloc(stbtt__hheap *hh, size_t size, void *userdata)
2852 {
2853    if (hh.first_free) {
2854       void *p = hh.first_free;
2855       hh.first_free = * cast(void **) p;
2856       return p;
2857    } else {
2858       if (hh.num_remaining_in_head_chunk == 0) {
2859          int count = (size < 32 ? 2000 : size < 128 ? 800 : 100);
2860          stbtt__hheap_chunk *c = cast(stbtt__hheap_chunk *) STBTT_malloc(cast(uint)(stbtt__hheap_chunk.sizeof + size * count), userdata);
2861          if (c == null)
2862             return null;
2863          c.next = hh.head;
2864          hh.head = c;
2865          hh.num_remaining_in_head_chunk = count;
2866       }
2867       --hh.num_remaining_in_head_chunk;
2868       return cast(char *) (hh.head) + cast(uint)stbtt__hheap_chunk.sizeof + size * hh.num_remaining_in_head_chunk;
2869    }
2870 }
2871 
2872 private void stbtt__hheap_free(stbtt__hheap *hh, void *p)
2873 {
2874    *cast(void **) p = hh.first_free;
2875    hh.first_free = p;
2876 }
2877 
2878 private void stbtt__hheap_cleanup(stbtt__hheap *hh, void *userdata)
2879 {
2880    stbtt__hheap_chunk *c = hh.head;
2881    while (c) {
2882       stbtt__hheap_chunk *n = c.next;
2883       STBTT_free(c, userdata);
2884       c = n;
2885    }
2886 }
2887 
2888 struct stbtt__edge {
2889    float x0,y0, x1,y1;
2890    int invert;
2891 }
2892 
2893 
2894 struct stbtt__active_edge {
2895    stbtt__active_edge *next;
2896    static if (STBTT_RASTERIZER_VERSION == 1) {
2897      int x,dx;
2898      float ey;
2899      int direction;
2900    } else static if (STBTT_RASTERIZER_VERSION == 2) {
2901      float fx,fdx,fdy;
2902      float direction;
2903      float sy;
2904      float ey;
2905    } else {
2906      static assert(0, "Unrecognized value of STBTT_RASTERIZER_VERSION");
2907    }
2908 }
2909 
2910 static if (STBTT_RASTERIZER_VERSION == 1) {
2911 enum STBTT_FIXSHIFT   = 10;
2912 enum STBTT_FIX        = (1 << STBTT_FIXSHIFT);
2913 enum STBTT_FIXMASK    = (STBTT_FIX-1);
2914 
2915 private stbtt__active_edge *stbtt__new_active(stbtt__hheap *hh, stbtt__edge *e, int off_x, float start_point, void *userdata)
2916 {
2917    stbtt__active_edge *z = void;
2918    z = cast(stbtt__active_edge *) stbtt__hheap_alloc(hh, cast(uint)(*z).sizeof, userdata);
2919    float dxdy = (e.x1 - e.x0) / (e.y1 - e.y0);
2920    assert(z != null);
2921    if (!z) return z;
2922 
2923    // round dx down to avoid overshooting
2924    if (dxdy < 0)
2925       z.dx = -STBTT_ifloor(STBTT_FIX * -dxdy);
2926    else
2927       z.dx = STBTT_ifloor(STBTT_FIX * dxdy);
2928 
2929    z.x = STBTT_ifloor(STBTT_FIX * e.x0 + z.dx * (start_point - e.y0)); // use z->dx so when we offset later it's by the same amount
2930    z.x -= off_x * STBTT_FIX;
2931 
2932    z.ey = e.y1;
2933    z.next = 0;
2934    z.direction = e.invert ? 1 : -1;
2935    return z;
2936 }
2937 } else static if (STBTT_RASTERIZER_VERSION == 2) {
2938 private stbtt__active_edge *stbtt__new_active(stbtt__hheap *hh, stbtt__edge *e, int off_x, float start_point, void *userdata)
2939 {
2940    stbtt__active_edge *z = void;
2941    z = cast(stbtt__active_edge *) stbtt__hheap_alloc(hh, cast(uint)(*z).sizeof, userdata);
2942    float dxdy = (e.x1 - e.x0) / (e.y1 - e.y0);
2943    assert(z != null);
2944    //STBTT_assert(e->y0 <= start_point);
2945    if (!z) return z;
2946    z.fdx = dxdy;
2947    z.fdy = dxdy != 0.0f ? (1.0f/dxdy) : 0.0f;
2948    z.fx = e.x0 + dxdy * (start_point - e.y0);
2949    z.fx -= off_x;
2950    z.direction = e.invert ? 1.0f : -1.0f;
2951    z.sy = e.y0;
2952    z.ey = e.y1;
2953    z.next = null;
2954    return z;
2955 }
2956 } else {
2957   static assert(0, "Unrecognized value of STBTT_RASTERIZER_VERSION");
2958 }
2959 
2960 static if (STBTT_RASTERIZER_VERSION == 1) {
2961 // note: this routine clips fills that extend off the edges... ideally this
2962 // wouldn't happen, but it could happen if the truetype glyph bounding boxes
2963 // are wrong, or if the user supplies a too-small bitmap
2964 private void stbtt__fill_active_edges(ubyte *scanline, int len, stbtt__active_edge *e, int max_weight)
2965 {
2966    // non-zero winding fill
2967    int x0=0, w=0;
2968 
2969    while (e) {
2970       if (w == 0) {
2971          // if we're currently at zero, we need to record the edge start point
2972          x0 = e.x; w += e.direction;
2973       } else {
2974          int x1 = e.x; w += e.direction;
2975          // if we went to zero, we need to draw
2976          if (w == 0) {
2977             int i = x0 >> STBTT_FIXSHIFT;
2978             int j = x1 >> STBTT_FIXSHIFT;
2979 
2980             if (i < len && j >= 0) {
2981                if (i == j) {
2982                   // x0,x1 are the same pixel, so compute combined coverage
2983                   scanline[i] = scanline[i] + cast(stbtt_uint8) ((x1 - x0) * max_weight >> STBTT_FIXSHIFT);
2984                } else {
2985                   if (i >= 0) // add antialiasing for x0
2986                      scanline[i] = scanline[i] + cast(stbtt_uint8) (((STBTT_FIX - (x0 & STBTT_FIXMASK)) * max_weight) >> STBTT_FIXSHIFT);
2987                   else
2988                      i = -1; // clip
2989 
2990                   if (j < len) // add antialiasing for x1
2991                      scanline[j] = scanline[j] + cast(stbtt_uint8) (((x1 & STBTT_FIXMASK) * max_weight) >> STBTT_FIXSHIFT);
2992                   else
2993                      j = len; // clip
2994 
2995                   for (++i; i < j; ++i) // fill pixels between x0 and x1
2996                      scanline[i] = scanline[i] + cast(stbtt_uint8) max_weight;
2997                }
2998             }
2999          }
3000       }
3001 
3002       e = e.next;
3003    }
3004 }
3005 
3006 private void stbtt__rasterize_sorted_edges(stbtt__bitmap *result, stbtt__edge *e, int n, int vsubsample, int off_x, int off_y, void *userdata)
3007 {
3008    stbtt__hheap hh = { 0, 0, 0 };
3009    stbtt__active_edge *active = null;
3010    int y,j=0;
3011    int max_weight = (255 / vsubsample);  // weight per vertical scanline
3012    int s; // vertical subsample index
3013    ubyte[512] scanline_data = void;
3014    ubyte *scanline;
3015 
3016    if (result.w > 512)
3017       scanline = cast(ubyte *) STBTT_malloc(result.w, userdata);
3018    else
3019       scanline = scanline_data;
3020 
3021    y = off_y * vsubsample;
3022    e[n].y0 = (off_y + result.h) * cast(float) vsubsample + 1;
3023 
3024    while (j < result.h) {
3025       STBTT_memset(scanline, 0, result.w);
3026       for (s=0; s < vsubsample; ++s) {
3027          // find center of pixel for this scanline
3028          float scan_y = y + 0.5f;
3029          stbtt__active_edge **step = &active;
3030 
3031          // update all active edges;
3032          // remove all active edges that terminate before the center of this scanline
3033          while (*step) {
3034             stbtt__active_edge * z = *step;
3035             if (z.ey <= scan_y) {
3036                *step = z.next; // delete from list
3037                assert(z.direction);
3038                z.direction = 0;
3039                stbtt__hheap_free(&hh, z);
3040             } else {
3041                z.x += z.dx; // advance to position for current scanline
3042                step = &((*step).next); // advance through list
3043             }
3044          }
3045 
3046          // resort the list if needed
3047          for(;;) {
3048             int changed=0;
3049             step = &active;
3050             while (*step && (*step).next) {
3051                if ((*step).x > (*step).next.x) {
3052                   stbtt__active_edge *t = *step;
3053                   stbtt__active_edge *q = t.next;
3054 
3055                   t.next = q.next;
3056                   q.next = t;
3057                   *step = q;
3058                   changed = 1;
3059                }
3060                step = &(*step).next;
3061             }
3062             if (!changed) break;
3063          }
3064 
3065          // insert all edges that start before the center of this scanline -- omit ones that also end on this scanline
3066          while (e.y0 <= scan_y) {
3067             if (e.y1 > scan_y) {
3068                stbtt__active_edge *z = stbtt__new_active(&hh, e, off_x, scan_y, userdata);
3069                if (z != null) {
3070                   // find insertion point
3071                   if (active == null)
3072                      active = z;
3073                   else if (z.x < active.x) {
3074                      // insert at front
3075                      z.next = active;
3076                      active = z;
3077                   } else {
3078                      // find thing to insert AFTER
3079                      stbtt__active_edge *p = active;
3080                      while (p.next && p.next.x < z.x)
3081                         p = p.next;
3082                      // at this point, p->next->x is NOT < z->x
3083                      z.next = p.next;
3084                      p.next = z;
3085                   }
3086                }
3087             }
3088             ++e;
3089          }
3090 
3091          // now process all active edges in XOR fashion
3092          if (active)
3093             stbtt__fill_active_edges(scanline, result.w, active, max_weight);
3094 
3095          ++y;
3096       }
3097       STBTT_memcpy(result.pixels + j * result.stride, scanline, result.w);
3098       ++j;
3099    }
3100 
3101    stbtt__hheap_cleanup(&hh, userdata);
3102 
3103    if (scanline != scanline_data)
3104       STBTT_free(scanline, userdata);
3105 }
3106 
3107 } else static if (STBTT_RASTERIZER_VERSION == 2) {
3108 
3109 // the edge passed in here does not cross the vertical line at x or the vertical line at x+1
3110 // (i.e. it has already been clipped to those)
3111 private void stbtt__handle_clipped_edge(float *scanline, int x, stbtt__active_edge *e, float x0, float y0, float x1, float y1)
3112 {
3113    if (y0 == y1) return;
3114    assert(y0 < y1);
3115    assert(e.sy <= e.ey);
3116    if (y0 > e.ey) return;
3117    if (y1 < e.sy) return;
3118    if (y0 < e.sy) {
3119       x0 += (x1-x0) * (e.sy - y0) / (y1-y0);
3120       y0 = e.sy;
3121    }
3122    if (y1 > e.ey) {
3123       x1 += (x1-x0) * (e.ey - y1) / (y1-y0);
3124       y1 = e.ey;
3125    }
3126 
3127    if (x0 == x)
3128       assert(x1 <= x+1);
3129    else if (x0 == x+1)
3130       assert(x1 >= x);
3131    else if (x0 <= x)
3132       assert(x1 <= x);
3133    else if (x0 >= x+1)
3134       assert(x1 >= x+1);
3135    else
3136       assert(x1 >= x && x1 <= x+1);
3137 
3138    if (x0 <= x && x1 <= x)
3139       scanline[x] += e.direction * (y1-y0);
3140    else if (x0 >= x+1 && x1 >= x+1)
3141       {}
3142    else {
3143       assert(x0 >= x && x0 <= x+1 && x1 >= x && x1 <= x+1);
3144       scanline[x] += e.direction * (y1-y0) * (1-((x0-x)+(x1-x))/2); // coverage = 1 - average x position
3145    }
3146 }
3147 
3148 private void stbtt__fill_active_edges_new(float *scanline, float *scanline_fill, int len, stbtt__active_edge *e, float y_top)
3149 {
3150    float y_bottom = y_top+1;
3151 
3152    while (e) {
3153       // brute force every pixel
3154 
3155       // compute intersection points with top & bottom
3156       assert(e.ey >= y_top);
3157 
3158       if (e.fdx == 0) {
3159          float x0 = e.fx;
3160          if (x0 < len) {
3161             if (x0 >= 0) {
3162                stbtt__handle_clipped_edge(scanline,cast(int) x0,e, x0,y_top, x0,y_bottom);
3163                stbtt__handle_clipped_edge(scanline_fill-1,cast(int) x0+1,e, x0,y_top, x0,y_bottom);
3164             } else {
3165                stbtt__handle_clipped_edge(scanline_fill-1,0,e, x0,y_top, x0,y_bottom);
3166             }
3167          }
3168       } else {
3169          float x0 = e.fx;
3170          float dx = e.fdx;
3171          float xb = x0 + dx;
3172          float x_top, x_bottom;
3173          float sy0,sy1;
3174          float dy = e.fdy;
3175          assert(e.sy <= y_bottom && e.ey >= y_top);
3176 
3177          // compute endpoints of line segment clipped to this scanline (if the
3178          // line segment starts on this scanline. x0 is the intersection of the
3179          // line with y_top, but that may be off the line segment.
3180          if (e.sy > y_top) {
3181             x_top = x0 + dx * (e.sy - y_top);
3182             sy0 = e.sy;
3183          } else {
3184             x_top = x0;
3185             sy0 = y_top;
3186          }
3187          if (e.ey < y_bottom) {
3188             x_bottom = x0 + dx * (e.ey - y_top);
3189             sy1 = e.ey;
3190          } else {
3191             x_bottom = xb;
3192             sy1 = y_bottom;
3193          }
3194 
3195          if (x_top >= 0 && x_bottom >= 0 && x_top < len && x_bottom < len) {
3196             // from here on, we don't have to range check x values
3197 
3198             if (cast(int) x_top == cast(int) x_bottom) {
3199                float height;
3200                // simple case, only spans one pixel
3201                int x = cast(int) x_top;
3202                height = sy1 - sy0;
3203                assert(x >= 0 && x < len);
3204                scanline[x] += e.direction * (1-((x_top - x) + (x_bottom-x))/2)  * height;
3205                scanline_fill[x] += e.direction * height; // everything right of this pixel is filled
3206             } else {
3207                int x,x1,x2;
3208                float y_crossing, step, sign, area;
3209                // covers 2+ pixels
3210                if (x_top > x_bottom) {
3211                   // flip scanline vertically; signed area is the same
3212                   float t;
3213                   sy0 = y_bottom - (sy0 - y_top);
3214                   sy1 = y_bottom - (sy1 - y_top);
3215                   t = sy0, sy0 = sy1, sy1 = t;
3216                   t = x_bottom, x_bottom = x_top, x_top = t;
3217                   dx = -dx;
3218                   dy = -dy;
3219                   t = x0, x0 = xb, xb = t;
3220                }
3221 
3222                x1 = cast(int) x_top;
3223                x2 = cast(int) x_bottom;
3224                // compute intersection with y axis at x1+1
3225                y_crossing = (x1+1 - x0) * dy + y_top;
3226 
3227                sign = e.direction;
3228                // area of the rectangle covered from y0..y_crossing
3229                area = sign * (y_crossing-sy0);
3230                // area of the triangle (x_top,y0), (x+1,y0), (x+1,y_crossing)
3231                scanline[x1] += area * (1-((x_top - x1)+(x1+1-x1))/2);
3232 
3233                step = sign * dy;
3234                for (x = x1+1; x < x2; ++x) {
3235                   scanline[x] += area + step/2;
3236                   area += step;
3237                }
3238                y_crossing += dy * (x2 - (x1+1));
3239 
3240                assert(STBTT_fabs(area) <= 1.01f);
3241 
3242                scanline[x2] += area + sign * (1-((x2-x2)+(x_bottom-x2))/2) * (sy1-y_crossing);
3243 
3244                scanline_fill[x2] += sign * (sy1-sy0);
3245             }
3246          } else {
3247             // if edge goes outside of box we're drawing, we require
3248             // clipping logic. since this does not match the intended use
3249             // of this library, we use a different, very slow brute
3250             // force implementation
3251             int x;
3252             for (x=0; x < len; ++x) {
3253                // cases:
3254                //
3255                // there can be up to two intersections with the pixel. any intersection
3256                // with left or right edges can be handled by splitting into two (or three)
3257                // regions. intersections with top & bottom do not necessitate case-wise logic.
3258                //
3259                // the old way of doing this found the intersections with the left & right edges,
3260                // then used some simple logic to produce up to three segments in sorted order
3261                // from top-to-bottom. however, this had a problem: if an x edge was epsilon
3262                // across the x border, then the corresponding y position might not be distinct
3263                // from the other y segment, and it might ignored as an empty segment. to avoid
3264                // that, we need to explicitly produce segments based on x positions.
3265 
3266                // rename variables to clearly-defined pairs
3267                float y0 = y_top;
3268                float x1 = cast(float) (x);
3269                float x2 = cast(float) (x+1);
3270                float x3 = xb;
3271                float y3 = y_bottom;
3272 
3273                // x = e->x + e->dx * (y-y_top)
3274                // (y-y_top) = (x - e->x) / e->dx
3275                // y = (x - e->x) / e->dx + y_top
3276                float y1 = (x - x0) / dx + y_top;
3277                float y2 = (x+1 - x0) / dx + y_top;
3278 
3279                if (x0 < x1 && x3 > x2) {         // three segments descending down-right
3280                   stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x1,y1);
3281                   stbtt__handle_clipped_edge(scanline,x,e, x1,y1, x2,y2);
3282                   stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x3,y3);
3283                } else if (x3 < x1 && x0 > x2) {  // three segments descending down-left
3284                   stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x2,y2);
3285                   stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x1,y1);
3286                   stbtt__handle_clipped_edge(scanline,x,e, x1,y1, x3,y3);
3287                } else if (x0 < x1 && x3 > x1) {  // two segments across x, down-right
3288                   stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x1,y1);
3289                   stbtt__handle_clipped_edge(scanline,x,e, x1,y1, x3,y3);
3290                } else if (x3 < x1 && x0 > x1) {  // two segments across x, down-left
3291                   stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x1,y1);
3292                   stbtt__handle_clipped_edge(scanline,x,e, x1,y1, x3,y3);
3293                } else if (x0 < x2 && x3 > x2) {  // two segments across x+1, down-right
3294                   stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x2,y2);
3295                   stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x3,y3);
3296                } else if (x3 < x2 && x0 > x2) {  // two segments across x+1, down-left
3297                   stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x2,y2);
3298                   stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x3,y3);
3299                } else {  // one segment
3300                   stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x3,y3);
3301                }
3302             }
3303          }
3304       }
3305       e = e.next;
3306    }
3307 }
3308 
3309 // directly AA rasterize edges w/o supersampling
3310 private void stbtt__rasterize_sorted_edges(stbtt__bitmap *result, stbtt__edge *e, int n, int vsubsample, int off_x, int off_y, void *userdata)
3311 {
3312    stbtt__hheap hh = stbtt__hheap( null, null, 0 );
3313    stbtt__active_edge *active = null;
3314    int y,j=0, i;
3315    float[129] scanline_data = void;
3316    float *scanline, scanline2;
3317 
3318    //STBTT__NOTUSED(vsubsample);
3319 
3320    if (result.w > 64)
3321       scanline = cast(float *) STBTT_malloc((result.w*2+1) * cast(uint)float.sizeof, userdata);
3322    else
3323       scanline = scanline_data.ptr;
3324 
3325    scanline2 = scanline + result.w;
3326 
3327    y = off_y;
3328    e[n].y0 = cast(float) (off_y + result.h) + 1;
3329 
3330    while (j < result.h) {
3331       // find center of pixel for this scanline
3332       float scan_y_top    = y + 0.0f;
3333       float scan_y_bottom = y + 1.0f;
3334       stbtt__active_edge **step = &active;
3335 
3336       STBTT_memset(scanline , 0, result.w*cast(uint)scanline[0].sizeof);
3337       STBTT_memset(scanline2, 0, (result.w+1)*cast(uint)scanline[0].sizeof);
3338 
3339       // update all active edges;
3340       // remove all active edges that terminate before the top of this scanline
3341       while (*step) {
3342          stbtt__active_edge * z = *step;
3343          if (z.ey <= scan_y_top) {
3344             *step = z.next; // delete from list
3345             assert(z.direction);
3346             z.direction = 0;
3347             stbtt__hheap_free(&hh, z);
3348          } else {
3349             step = &((*step).next); // advance through list
3350          }
3351       }
3352 
3353       // insert all edges that start before the bottom of this scanline
3354       while (e.y0 <= scan_y_bottom) {
3355          if (e.y0 != e.y1) {
3356             stbtt__active_edge *z = stbtt__new_active(&hh, e, off_x, scan_y_top, userdata);
3357             if (z != null) {
3358                assert(z.ey >= scan_y_top);
3359                // insert at front
3360                z.next = active;
3361                active = z;
3362             }
3363          }
3364          ++e;
3365       }
3366 
3367       // now process all active edges
3368       if (active)
3369          stbtt__fill_active_edges_new(scanline, scanline2+1, result.w, active, scan_y_top);
3370 
3371       {
3372          float sum = 0;
3373          for (i=0; i < result.w; ++i) {
3374             float k;
3375             int m;
3376             sum += scanline2[i];
3377             k = scanline[i] + sum;
3378             k = cast(float) STBTT_fabs(k)*255 + 0.5f;
3379             m = cast(int) k;
3380             if (m > 255) m = 255;
3381             result.pixels[j*result.stride + i] = cast(ubyte) m;
3382          }
3383       }
3384       // advance all the edges
3385       step = &active;
3386       while (*step) {
3387          stbtt__active_edge *z = *step;
3388          z.fx += z.fdx; // advance to position for current scanline
3389          step = &((*step).next); // advance through list
3390       }
3391 
3392       ++y;
3393       ++j;
3394    }
3395 
3396    stbtt__hheap_cleanup(&hh, userdata);
3397 
3398    if (scanline !is scanline_data.ptr)
3399       STBTT_free(scanline, userdata);
3400 }
3401 } else {
3402   static assert(0, "Unrecognized value of STBTT_RASTERIZER_VERSION");
3403 }
3404 
3405 //#define STBTT__COMPARE(a,b)  ((a).y0 < (b).y0)
3406 bool STBTT__COMPARE (stbtt__edge *a, stbtt__edge *b) pure { pragma(inline, true); return (a.y0 < b.y0); }
3407 
3408 private void stbtt__sort_edges_ins_sort(stbtt__edge *p, int n)
3409 {
3410    int i,j;
3411    for (i=1; i < n; ++i) {
3412       stbtt__edge t = p[i];
3413       stbtt__edge *a = &t;
3414       j = i;
3415       while (j > 0) {
3416          stbtt__edge *b = &p[j-1];
3417          int c = STBTT__COMPARE(a,b);
3418          if (!c) break;
3419          p[j] = p[j-1];
3420          --j;
3421       }
3422       if (i != j)
3423          p[j] = t;
3424    }
3425 }
3426 
3427 private void stbtt__sort_edges_quicksort(stbtt__edge *p, int n)
3428 {
3429    /* threshhold for transitioning to insertion sort */
3430    while (n > 12) {
3431       stbtt__edge t;
3432       int c01,c12,c,m,i,j;
3433 
3434       /* compute median of three */
3435       m = n >> 1;
3436       c01 = STBTT__COMPARE(&p[0],&p[m]);
3437       c12 = STBTT__COMPARE(&p[m],&p[n-1]);
3438       /* if 0 >= mid >= end, or 0 < mid < end, then use mid */
3439       if (c01 != c12) {
3440          /* otherwise, we'll need to swap something else to middle */
3441          int z;
3442          c = STBTT__COMPARE(&p[0],&p[n-1]);
3443          /* 0>mid && mid<n:  0>n => n; 0<n => 0 */
3444          /* 0<mid && mid>n:  0>n => 0; 0<n => n */
3445          z = (c == c12) ? 0 : n-1;
3446          t = p[z];
3447          p[z] = p[m];
3448          p[m] = t;
3449       }
3450       /* now p[m] is the median-of-three */
3451       /* swap it to the beginning so it won't move around */
3452       t = p[0];
3453       p[0] = p[m];
3454       p[m] = t;
3455 
3456       /* partition loop */
3457       i=1;
3458       j=n-1;
3459       for(;;) {
3460          /* handling of equality is crucial here */
3461          /* for sentinels & efficiency with duplicates */
3462          for (;;++i) {
3463             if (!STBTT__COMPARE(&p[i], &p[0])) break;
3464          }
3465          for (;;--j) {
3466             if (!STBTT__COMPARE(&p[0], &p[j])) break;
3467          }
3468          /* make sure we haven't crossed */
3469          if (i >= j) break;
3470          t = p[i];
3471          p[i] = p[j];
3472          p[j] = t;
3473 
3474          ++i;
3475          --j;
3476       }
3477       /* recurse on smaller side, iterate on larger */
3478       if (j < (n-i)) {
3479          stbtt__sort_edges_quicksort(p,j);
3480          p = p+i;
3481          n = n-i;
3482       } else {
3483          stbtt__sort_edges_quicksort(p+i, n-i);
3484          n = j;
3485       }
3486    }
3487 }
3488 
3489 private void stbtt__sort_edges(stbtt__edge *p, int n)
3490 {
3491    stbtt__sort_edges_quicksort(p, n);
3492    stbtt__sort_edges_ins_sort(p, n);
3493 }
3494 
3495 struct stbtt__point {
3496    float x,y;
3497 }
3498 
3499 private void stbtt__rasterize(stbtt__bitmap *result, stbtt__point *pts, int *wcount, int windings, float scale_x, float scale_y, float shift_x, float shift_y, int off_x, int off_y, int invert, void *userdata)
3500 {
3501    float y_scale_inv = invert ? -scale_y : scale_y;
3502    stbtt__edge *e;
3503    int n,i,j,k,m;
3504 static if (STBTT_RASTERIZER_VERSION == 1) {
3505    int vsubsample = result.h < 8 ? 15 : 5;
3506 } else static if (STBTT_RASTERIZER_VERSION == 2) {
3507    int vsubsample = 1;
3508 } else {
3509   static assert(0, "Unrecognized value of STBTT_RASTERIZER_VERSION");
3510 }
3511    // vsubsample should divide 255 evenly; otherwise we won't reach full opacity
3512 
3513    // now we have to blow out the windings into explicit edge lists
3514    n = 0;
3515    for (i=0; i < windings; ++i)
3516       n += wcount[i];
3517 
3518    e = cast(stbtt__edge *) STBTT_malloc(cast(uint)(*e).sizeof * (n+1), userdata); // add an extra one as a sentinel
3519    if (e is null) return;
3520    n = 0;
3521 
3522    m=0;
3523    for (i=0; i < windings; ++i) {
3524       stbtt__point *p = pts + m;
3525       m += wcount[i];
3526       j = wcount[i]-1;
3527       for (k=0; k < wcount[i]; j=k++) {
3528          int a=k,b=j;
3529          // skip the edge if horizontal
3530          if (p[j].y == p[k].y)
3531             continue;
3532          // add edge from j to k to the list
3533          e[n].invert = 0;
3534          if (invert ? p[j].y > p[k].y : p[j].y < p[k].y) {
3535             e[n].invert = 1;
3536             a=j,b=k;
3537          }
3538          e[n].x0 = p[a].x * scale_x + shift_x;
3539          e[n].y0 = (p[a].y * y_scale_inv + shift_y) * vsubsample;
3540          e[n].x1 = p[b].x * scale_x + shift_x;
3541          e[n].y1 = (p[b].y * y_scale_inv + shift_y) * vsubsample;
3542          ++n;
3543       }
3544    }
3545 
3546    // now sort the edges by their highest point (should snap to integer, and then by x)
3547    //STBTT_sort(e, n, e[0].sizeof, stbtt__edge_compare);
3548    stbtt__sort_edges(e, n);
3549 
3550    // now, traverse the scanlines and find the intersections on each scanline, use xor winding rule
3551    stbtt__rasterize_sorted_edges(result, e, n, vsubsample, off_x, off_y, userdata);
3552 
3553    STBTT_free(e, userdata);
3554 }
3555 
3556 private void stbtt__add_point(stbtt__point *points, int n, float x, float y)
3557 {
3558    if (!points) return; // during first pass, it's unallocated
3559    points[n].x = x;
3560    points[n].y = y;
3561 }
3562 
3563 // tesselate until threshhold p is happy... @TODO warped to compensate for non-linear stretching
3564 private 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)
3565 {
3566    // midpoint
3567    float mx = (x0 + 2*x1 + x2)/4;
3568    float my = (y0 + 2*y1 + y2)/4;
3569    // versus directly drawn line
3570    float dx = (x0+x2)/2 - mx;
3571    float dy = (y0+y2)/2 - my;
3572    if (n > 16) // 65536 segments on one curve better be enough!
3573       return 1;
3574    if (dx*dx+dy*dy > objspace_flatness_squared) { // half-pixel error allowed... need to be smaller if AA
3575       stbtt__tesselate_curve(points, num_points, x0,y0, (x0+x1)/2.0f,(y0+y1)/2.0f, mx,my, objspace_flatness_squared,n+1);
3576       stbtt__tesselate_curve(points, num_points, mx,my, (x1+x2)/2.0f,(y1+y2)/2.0f, x2,y2, objspace_flatness_squared,n+1);
3577    } else {
3578       stbtt__add_point(points, *num_points,x2,y2);
3579       *num_points = *num_points+1;
3580    }
3581    return 1;
3582 }
3583 
3584 private void stbtt__tesselate_cubic(stbtt__point *points, int *num_points, float x0, float y0, float x1, float y1, float x2, float y2, float x3, float y3, float objspace_flatness_squared, int n)
3585 {
3586    // @TODO this "flatness" calculation is just made-up nonsense that seems to work well enough
3587    float dx0 = x1-x0;
3588    float dy0 = y1-y0;
3589    float dx1 = x2-x1;
3590    float dy1 = y2-y1;
3591    float dx2 = x3-x2;
3592    float dy2 = y3-y2;
3593    float dx = x3-x0;
3594    float dy = y3-y0;
3595    float longlen = cast(float) (STBTT_sqrt(dx0*dx0+dy0*dy0)+STBTT_sqrt(dx1*dx1+dy1*dy1)+STBTT_sqrt(dx2*dx2+dy2*dy2));
3596    float shortlen = cast(float) STBTT_sqrt(dx*dx+dy*dy);
3597    float flatness_squared = longlen*longlen-shortlen*shortlen;
3598 
3599    if (n > 16) // 65536 segments on one curve better be enough!
3600       return;
3601 
3602    if (flatness_squared > objspace_flatness_squared) {
3603       float x01 = (x0+x1)/2;
3604       float y01 = (y0+y1)/2;
3605       float x12 = (x1+x2)/2;
3606       float y12 = (y1+y2)/2;
3607       float x23 = (x2+x3)/2;
3608       float y23 = (y2+y3)/2;
3609 
3610       float xa = (x01+x12)/2;
3611       float ya = (y01+y12)/2;
3612       float xb = (x12+x23)/2;
3613       float yb = (y12+y23)/2;
3614 
3615       float mx = (xa+xb)/2;
3616       float my = (ya+yb)/2;
3617 
3618       stbtt__tesselate_cubic(points, num_points, x0,y0, x01,y01, xa,ya, mx,my, objspace_flatness_squared,n+1);
3619       stbtt__tesselate_cubic(points, num_points, mx,my, xb,yb, x23,y23, x3,y3, objspace_flatness_squared,n+1);
3620    } else {
3621       stbtt__add_point(points, *num_points,x3,y3);
3622       *num_points = *num_points+1;
3623    }
3624 }
3625 
3626 // returns number of contours
3627 private stbtt__point *stbtt_FlattenCurves(stbtt_vertex *vertices, int num_verts, float objspace_flatness, int **contour_lengths, int *num_contours, void *userdata)
3628 {
3629    stbtt__point *points = null;
3630    int num_points=0;
3631 
3632    float objspace_flatness_squared = objspace_flatness * objspace_flatness;
3633    int i,n=0,start=0, pass;
3634 
3635    // count how many "moves" there are to get the contour count
3636    for (i=0; i < num_verts; ++i)
3637       if (vertices[i].type == STBTT_vmove)
3638          ++n;
3639 
3640    *num_contours = n;
3641    if (n == 0) return null;
3642 
3643    *contour_lengths = cast(int *) STBTT_malloc(cast(uint)(**contour_lengths).sizeof * n, userdata);
3644 
3645    if (*contour_lengths is null) {
3646       *num_contours = 0;
3647       return null;
3648    }
3649 
3650    // make two passes through the points so we don't need to realloc
3651    for (pass=0; pass < 2; ++pass) {
3652       float x=0,y=0;
3653       if (pass == 1) {
3654          points = cast(stbtt__point *) STBTT_malloc(num_points * cast(uint)points[0].sizeof, userdata);
3655          if (points == null) goto error;
3656       }
3657       num_points = 0;
3658       n= -1;
3659       for (i=0; i < num_verts; ++i) {
3660          switch (vertices[i].type) {
3661             case STBTT_vmove:
3662                // start the next contour
3663                if (n >= 0)
3664                   (*contour_lengths)[n] = num_points - start;
3665                ++n;
3666                start = num_points;
3667 
3668                x = vertices[i].x, y = vertices[i].y;
3669                stbtt__add_point(points, num_points++, x,y);
3670                break;
3671             case STBTT_vline:
3672                x = vertices[i].x, y = vertices[i].y;
3673                stbtt__add_point(points, num_points++, x, y);
3674                break;
3675             case STBTT_vcurve:
3676                stbtt__tesselate_curve(points, &num_points, x,y,
3677                                         vertices[i].cx, vertices[i].cy,
3678                                         vertices[i].x,  vertices[i].y,
3679                                         objspace_flatness_squared, 0);
3680                x = vertices[i].x, y = vertices[i].y;
3681                break;
3682             case STBTT_vcubic:
3683                stbtt__tesselate_cubic(points, &num_points, x,y,
3684                                         vertices[i].cx, vertices[i].cy,
3685                                         vertices[i].cx1, vertices[i].cy1,
3686                                         vertices[i].x,  vertices[i].y,
3687                                         objspace_flatness_squared, 0);
3688                x = vertices[i].x, y = vertices[i].y;
3689                break;
3690            default:
3691          }
3692       }
3693       (*contour_lengths)[n] = num_points - start;
3694    }
3695 
3696    return points;
3697 error:
3698    STBTT_free(points, userdata);
3699    STBTT_free(*contour_lengths, userdata);
3700    *contour_lengths = null;
3701    *num_contours = 0;
3702    return null;
3703 }
3704 
3705 public void stbtt_Rasterize(stbtt__bitmap *result, float flatness_in_pixels, stbtt_vertex *vertices, int num_verts, float scale_x, float scale_y, float shift_x, float shift_y, int x_off, int y_off, int invert, void *userdata)
3706 {
3707    float scale            = scale_x > scale_y ? scale_y : scale_x;
3708    int winding_count      = 0;
3709    int *winding_lengths   = null;
3710    stbtt__point *windings = stbtt_FlattenCurves(vertices, num_verts, flatness_in_pixels / scale, &winding_lengths, &winding_count, userdata);
3711    if (windings) {
3712       stbtt__rasterize(result, windings, winding_lengths, winding_count, scale_x, scale_y, shift_x, shift_y, x_off, y_off, invert, userdata);
3713       STBTT_free(winding_lengths, userdata);
3714       STBTT_free(windings, userdata);
3715    }
3716 }
3717 
3718 public void stbtt_FreeBitmap(ubyte *bitmap, void *userdata)
3719 {
3720    STBTT_free(bitmap, userdata);
3721 }
3722 
3723 public ubyte *stbtt_GetGlyphBitmapSubpixel(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)
3724 {
3725    int ix0,iy0,ix1,iy1;
3726    stbtt__bitmap gbm;
3727    stbtt_vertex *vertices;
3728    int num_verts = stbtt_GetGlyphShape(info, glyph, &vertices);
3729 
3730    if (scale_x == 0) scale_x = scale_y;
3731    if (scale_y == 0) {
3732       if (scale_x == 0) {
3733          STBTT_free(vertices, info.userdata);
3734          return null;
3735       }
3736       scale_y = scale_x;
3737    }
3738 
3739    stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale_x, scale_y, shift_x, shift_y, &ix0,&iy0,&ix1,&iy1);
3740 
3741    // now we get the size
3742    gbm.w = (ix1 - ix0);
3743    gbm.h = (iy1 - iy0);
3744    gbm.pixels = null; // in case we error
3745 
3746    if (width ) *width  = gbm.w;
3747    if (height) *height = gbm.h;
3748    if (xoff  ) *xoff   = ix0;
3749    if (yoff  ) *yoff   = iy0;
3750 
3751    if (gbm.w && gbm.h) {
3752       gbm.pixels = cast(ubyte *) STBTT_malloc(gbm.w * gbm.h, info.userdata);
3753       if (gbm.pixels) {
3754          gbm.stride = gbm.w;
3755 
3756          stbtt_Rasterize(&gbm, 0.35f, vertices, num_verts, scale_x, scale_y, shift_x, shift_y, ix0, iy0, 1, info.userdata);
3757       }
3758    }
3759    STBTT_free(vertices, info.userdata);
3760    return gbm.pixels;
3761 }
3762 
3763 public ubyte *stbtt_GetGlyphBitmap(stbtt_fontinfo* info, float scale_x, float scale_y, int glyph, int *width, int *height, int *xoff, int *yoff)
3764 {
3765    return stbtt_GetGlyphBitmapSubpixel(info, scale_x, scale_y, 0.0f, 0.0f, glyph, width, height, xoff, yoff);
3766 }
3767 
3768 public 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)
3769 {
3770    int ix0,iy0;
3771    stbtt_vertex *vertices;
3772    int num_verts = stbtt_GetGlyphShape(info, glyph, &vertices);
3773    stbtt__bitmap gbm;
3774 
3775    stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale_x, scale_y, shift_x, shift_y, &ix0,&iy0, null, null);
3776    gbm.pixels = output;
3777    gbm.w = out_w;
3778    gbm.h = out_h;
3779    gbm.stride = out_stride;
3780 
3781    if (gbm.w && gbm.h)
3782       stbtt_Rasterize(&gbm, 0.35f, vertices, num_verts, scale_x, scale_y, shift_x, shift_y, ix0,iy0, 1, info.userdata);
3783 
3784    STBTT_free(vertices, info.userdata);
3785 }
3786 
3787 public 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)
3788 {
3789    stbtt_MakeGlyphBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, scale_y, 0.0f,0.0f, glyph);
3790 }
3791 
3792 public ubyte *stbtt_GetCodepointBitmapSubpixel(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)
3793 {
3794    return stbtt_GetGlyphBitmapSubpixel(info, scale_x, scale_y,shift_x,shift_y, stbtt_FindGlyphIndex(info,codepoint), width,height,xoff,yoff);
3795 }
3796 
3797 public void stbtt_MakeCodepointBitmapSubpixelPrefilter(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 oversample_x, int oversample_y, float *sub_x, float *sub_y, int codepoint)
3798 {
3799    stbtt_MakeGlyphBitmapSubpixelPrefilter(info, output, out_w, out_h, out_stride, scale_x, scale_y, shift_x, shift_y, oversample_x, oversample_y, sub_x, sub_y, stbtt_FindGlyphIndex(info,codepoint));
3800 }
3801 
3802 public 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)
3803 {
3804    stbtt_MakeGlyphBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, scale_y, shift_x, shift_y, stbtt_FindGlyphIndex(info,codepoint));
3805 }
3806 
3807 public ubyte *stbtt_GetCodepointBitmap(stbtt_fontinfo* info, float scale_x, float scale_y, int codepoint, int *width, int *height, int *xoff, int *yoff)
3808 {
3809    return stbtt_GetCodepointBitmapSubpixel(info, scale_x, scale_y, 0.0f,0.0f, codepoint, width,height,xoff,yoff);
3810 }
3811 
3812 public void stbtt_MakeCodepointBitmap(stbtt_fontinfo* info, ubyte *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int codepoint)
3813 {
3814    stbtt_MakeCodepointBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, scale_y, 0.0f,0.0f, codepoint);
3815 }
3816 
3817 //////////////////////////////////////////////////////////////////////////////
3818 //
3819 // bitmap baking
3820 //
3821 // This is SUPER-CRAPPY packing to keep source code small
3822 
3823 private int stbtt_BakeFontBitmap_internal(ubyte *data, int offset,  // font location (use offset=0 for plain .ttf)
3824                                 float pixel_height,                     // height of font in pixels
3825                                 ubyte *pixels, int pw, int ph,  // bitmap to be filled in
3826                                 int first_char, int num_chars,          // characters to bake
3827                                 stbtt_bakedchar *chardata,
3828 				int* ascent, int* descent, int* line_gap
3829 				)
3830 {
3831    float scale;
3832    int x,y,bottom_y, i;
3833    stbtt_fontinfo f;
3834    f.userdata = null;
3835    if (!stbtt_InitFont(&f, data, offset))
3836       return -1;
3837    STBTT_memset(pixels, 0, pw*ph); // background of 0 around pixels
3838    x=y=1;
3839    bottom_y = 1;
3840 
3841    scale = stbtt_ScaleForPixelHeight(&f, pixel_height);
3842 
3843    stbtt_GetFontVMetrics(&f, ascent, descent, line_gap);
3844 
3845    if(ascent) *ascent = cast(int) (*ascent * scale);
3846    if(descent) *descent = cast(int) (*descent * scale);
3847    if(line_gap) *line_gap = cast(int) (*line_gap * scale);
3848 
3849    for (i=0; i < num_chars; ++i) {
3850       int advance, lsb, x0,y0,x1,y1,gw,gh;
3851       int g = stbtt_FindGlyphIndex(&f, first_char + i);
3852       stbtt_GetGlyphHMetrics(&f, g, &advance, &lsb);
3853       stbtt_GetGlyphBitmapBox(&f, g, scale,scale, &x0,&y0,&x1,&y1);
3854       gw = x1-x0;
3855       gh = y1-y0;
3856       if (x + gw + 1 >= pw)
3857          y = bottom_y, x = 1; // advance to next row
3858       if (y + gh + 1 >= ph) // check if it fits vertically AFTER potentially moving to next row
3859          return -i;
3860       assert(x+gw < pw);
3861       assert(y+gh < ph);
3862       stbtt_MakeGlyphBitmap(&f, pixels+x+y*pw, gw,gh,pw, scale,scale, g);
3863       chardata[i].x0 = cast(stbtt_int16) x;
3864       chardata[i].y0 = cast(stbtt_int16) y;
3865       chardata[i].x1 = cast(stbtt_int16) (x + gw);
3866       chardata[i].y1 = cast(stbtt_int16) (y + gh);
3867       chardata[i].xadvance = scale * advance;
3868       chardata[i].xoff     = cast(float) x0;
3869       chardata[i].yoff     = cast(float) y0;
3870       x = x + gw + 1;
3871       if (y+gh+1 > bottom_y)
3872          bottom_y = y+gh+1;
3873    }
3874    return bottom_y;
3875 }
3876 
3877 public void stbtt_GetBakedQuad(const(stbtt_bakedchar)* chardata, int pw, int ph, int char_index, float *xpos, float *ypos, stbtt_aligned_quad *q, int opengl_fillrule)
3878 {
3879    float d3d_bias = opengl_fillrule ? 0 : -0.5f;
3880    float ipw = 1.0f / pw, iph = 1.0f / ph;
3881    const(stbtt_bakedchar)* b = chardata + char_index;
3882    int round_x = STBTT_ifloor((*xpos + b.xoff) + 0.5f);
3883    int round_y = STBTT_ifloor((*ypos + b.yoff) + 0.5f);
3884 
3885    q.x0 = round_x + d3d_bias;
3886    q.y0 = round_y + d3d_bias;
3887    q.x1 = round_x + b.x1 - b.x0 + d3d_bias;
3888    q.y1 = round_y + b.y1 - b.y0 + d3d_bias;
3889 
3890    q.s0 = b.x0 * ipw;
3891    q.t0 = b.y0 * iph;
3892    q.s1 = b.x1 * ipw;
3893    q.t1 = b.y1 * iph;
3894 
3895    *xpos += b.xadvance;
3896 }
3897 
3898 //////////////////////////////////////////////////////////////////////////////
3899 //
3900 // rectangle packing replacement routines if you don't have stb_rect_pack.h
3901 //
3902 
3903 version(STB_RECT_PACK_VERSION) {
3904 
3905 alias stbrp_coord = int;
3906 
3907 // //////////////////////////////////////////////////////////////////////////////////
3908 //                                                                                //
3909 //                                                                                //
3910 // COMPILER WARNING ?!?!?                                                         //
3911 //                                                                                //
3912 //                                                                                //
3913 // if you get a compile warning due to these symbols being defined more than      //
3914 // once, move #include "stb_rect_pack.h" before #include "stb_truetype.h"         //
3915 //                                                                                //
3916 // //////////////////////////////////////////////////////////////////////////////////
3917 
3918 struct stbrp_context {
3919    int width,height;
3920    int x,y,bottom_y;
3921 }
3922 
3923 struct stbrp_node {
3924    ubyte x;
3925 }
3926 
3927 struct stbrp_rect {
3928    stbrp_coord x,y;
3929    int id,w,h,was_packed;
3930 }
3931 
3932 private void stbrp_init_target(stbrp_context *con, int pw, int ph, stbrp_node *nodes, int num_nodes)
3933 {
3934    con.width  = pw;
3935    con.height = ph;
3936    con.x = 0;
3937    con.y = 0;
3938    con.bottom_y = 0;
3939    //STBTT__NOTUSED(nodes);
3940    //STBTT__NOTUSED(num_nodes);
3941 }
3942 
3943 private void stbrp_pack_rects(stbrp_context *con, stbrp_rect *rects, int num_rects)
3944 {
3945    int i;
3946    for (i=0; i < num_rects; ++i) {
3947       if (con.x + rects[i].w > con.width) {
3948          con.x = 0;
3949          con.y = con.bottom_y;
3950       }
3951       if (con.y + rects[i].h > con.height)
3952          break;
3953       rects[i].x = con.x;
3954       rects[i].y = con.y;
3955       rects[i].was_packed = 1;
3956       con.x += rects[i].w;
3957       if (con.y + rects[i].h > con.bottom_y)
3958          con.bottom_y = con.y + rects[i].h;
3959    }
3960    for (   ; i < num_rects; ++i)
3961       rects[i].was_packed = 0;
3962 }
3963 }
3964 
3965 
3966 // ////////////////////////////////////////////////////////////////////////////
3967 //
3968 // bitmap baking
3969 //
3970 // This is SUPER-AWESOME (tm Ryan Gordon) packing using stb_rect_pack.h. If
3971 // stb_rect_pack.h isn't available, it uses the BakeFontBitmap strategy.
3972 
3973 public int stbtt_PackBegin(stbtt_pack_context *spc, ubyte *pixels, int pw, int ph, int stride_in_bytes, int padding, void *alloc_context)
3974 {
3975    stbrp_context *context = void;
3976    context = cast(stbrp_context *) STBTT_malloc(cast(uint)(*context).sizeof            ,alloc_context);
3977    int            num_nodes = pw - padding;
3978    stbrp_node    *nodes   = void;
3979    nodes = cast(stbrp_node    *) STBTT_malloc(cast(uint)(*nodes  ).sizeof * num_nodes,alloc_context);
3980 
3981    if (context == null || nodes == null) {
3982       if (context != null) STBTT_free(context, alloc_context);
3983       if (nodes   != null) STBTT_free(nodes  , alloc_context);
3984       return 0;
3985    }
3986 
3987    spc.user_allocator_context = alloc_context;
3988    spc.width = pw;
3989    spc.height = ph;
3990    spc.pixels = pixels;
3991    spc.pack_info = context;
3992    spc.nodes = nodes;
3993    spc.padding = padding;
3994    spc.stride_in_bytes = stride_in_bytes != 0 ? stride_in_bytes : pw;
3995    spc.h_oversample = 1;
3996    spc.v_oversample = 1;
3997 
3998    stbrp_init_target(context, pw-padding, ph-padding, nodes, num_nodes);
3999 
4000    if (pixels)
4001       STBTT_memset(pixels, 0, pw*ph); // background of 0 around pixels
4002 
4003    return 1;
4004 }
4005 
4006 public void stbtt_PackEnd  (stbtt_pack_context *spc)
4007 {
4008    STBTT_free(spc.nodes    , spc.user_allocator_context);
4009    STBTT_free(spc.pack_info, spc.user_allocator_context);
4010 }
4011 
4012 public void stbtt_PackSetOversampling(stbtt_pack_context *spc, uint h_oversample, uint v_oversample)
4013 {
4014    assert(h_oversample <= STBTT_MAX_OVERSAMPLE);
4015    assert(v_oversample <= STBTT_MAX_OVERSAMPLE);
4016    if (h_oversample <= STBTT_MAX_OVERSAMPLE)
4017       spc.h_oversample = h_oversample;
4018    if (v_oversample <= STBTT_MAX_OVERSAMPLE)
4019       spc.v_oversample = v_oversample;
4020 }
4021 
4022 enum STBTT__OVER_MASK = (STBTT_MAX_OVERSAMPLE-1);
4023 
4024 private void stbtt__h_prefilter(ubyte *pixels, int w, int h, int stride_in_bytes, uint kernel_width)
4025 {
4026    ubyte[STBTT_MAX_OVERSAMPLE] buffer = void;
4027    int safe_w = w - kernel_width;
4028    int j;
4029    STBTT_memset(buffer.ptr, 0, STBTT_MAX_OVERSAMPLE); // suppress bogus warning from VS2013 -analyze
4030    for (j=0; j < h; ++j) {
4031       int i;
4032       uint total;
4033       STBTT_memset(buffer.ptr, 0, kernel_width);
4034 
4035       total = 0;
4036 
4037       // make kernel_width a constant in common cases so compiler can optimize out the divide
4038       switch (kernel_width) {
4039          case 2:
4040             for (i=0; i <= safe_w; ++i) {
4041                total += pixels[i] - buffer[i & STBTT__OVER_MASK];
4042                buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i];
4043                pixels[i] = cast(ubyte) (total / 2);
4044             }
4045             break;
4046          case 3:
4047             for (i=0; i <= safe_w; ++i) {
4048                total += pixels[i] - buffer[i & STBTT__OVER_MASK];
4049                buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i];
4050                pixels[i] = cast(ubyte) (total / 3);
4051             }
4052             break;
4053          case 4:
4054             for (i=0; i <= safe_w; ++i) {
4055                total += pixels[i] - buffer[i & STBTT__OVER_MASK];
4056                buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i];
4057                pixels[i] = cast(ubyte) (total / 4);
4058             }
4059             break;
4060          case 5:
4061             for (i=0; i <= safe_w; ++i) {
4062                total += pixels[i] - buffer[i & STBTT__OVER_MASK];
4063                buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i];
4064                pixels[i] = cast(ubyte) (total / 5);
4065             }
4066             break;
4067          default:
4068             for (i=0; i <= safe_w; ++i) {
4069                total += pixels[i] - buffer[i & STBTT__OVER_MASK];
4070                buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i];
4071                pixels[i] = cast(ubyte) (total / kernel_width);
4072             }
4073             break;
4074       }
4075 
4076       for (; i < w; ++i) {
4077          assert(pixels[i] == 0);
4078          total -= buffer[i & STBTT__OVER_MASK];
4079          pixels[i] = cast(ubyte) (total / kernel_width);
4080       }
4081 
4082       pixels += stride_in_bytes;
4083    }
4084 }
4085 
4086 private void stbtt__v_prefilter(ubyte *pixels, int w, int h, int stride_in_bytes, uint kernel_width)
4087 {
4088    ubyte[STBTT_MAX_OVERSAMPLE] buffer = void;
4089    int safe_h = h - kernel_width;
4090    int j;
4091    STBTT_memset(buffer.ptr, 0, STBTT_MAX_OVERSAMPLE); // suppress bogus warning from VS2013 -analyze
4092    for (j=0; j < w; ++j) {
4093       int i;
4094       uint total;
4095       STBTT_memset(buffer.ptr, 0, kernel_width);
4096 
4097       total = 0;
4098 
4099       // make kernel_width a constant in common cases so compiler can optimize out the divide
4100       switch (kernel_width) {
4101          case 2:
4102             for (i=0; i <= safe_h; ++i) {
4103                total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK];
4104                buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes];
4105                pixels[i*stride_in_bytes] = cast(ubyte) (total / 2);
4106             }
4107             break;
4108          case 3:
4109             for (i=0; i <= safe_h; ++i) {
4110                total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK];
4111                buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes];
4112                pixels[i*stride_in_bytes] = cast(ubyte) (total / 3);
4113             }
4114             break;
4115          case 4:
4116             for (i=0; i <= safe_h; ++i) {
4117                total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK];
4118                buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes];
4119                pixels[i*stride_in_bytes] = cast(ubyte) (total / 4);
4120             }
4121             break;
4122          case 5:
4123             for (i=0; i <= safe_h; ++i) {
4124                total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK];
4125                buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes];
4126                pixels[i*stride_in_bytes] = cast(ubyte) (total / 5);
4127             }
4128             break;
4129          default:
4130             for (i=0; i <= safe_h; ++i) {
4131                total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK];
4132                buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes];
4133                pixels[i*stride_in_bytes] = cast(ubyte) (total / kernel_width);
4134             }
4135             break;
4136       }
4137 
4138       for (; i < h; ++i) {
4139          assert(pixels[i*stride_in_bytes] == 0);
4140          total -= buffer[i & STBTT__OVER_MASK];
4141          pixels[i*stride_in_bytes] = cast(ubyte) (total / kernel_width);
4142       }
4143 
4144       pixels += 1;
4145    }
4146 }
4147 
4148 private float stbtt__oversample_shift(int oversample)
4149 {
4150    if (!oversample)
4151       return 0.0f;
4152 
4153    // The prefilter is a box filter of width "oversample",
4154    // which shifts phase by (oversample - 1)/2 pixels in
4155    // oversampled space. We want to shift in the opposite
4156    // direction to counter this.
4157    return cast(float)-(oversample - 1) / (2.0f * cast(float)oversample);
4158 }
4159 
4160 // rects array must be big enough to accommodate all characters in the given ranges
4161 public int stbtt_PackFontRangesGatherRects(stbtt_pack_context *spc, stbtt_fontinfo* info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects)
4162 {
4163    int i,j,k;
4164 
4165    k=0;
4166    for (i=0; i < num_ranges; ++i) {
4167       float fh = ranges[i].font_size;
4168       float scale = fh > 0 ? stbtt_ScaleForPixelHeight(info, fh) : stbtt_ScaleForMappingEmToPixels(info, -fh);
4169       ranges[i].h_oversample = cast(ubyte) spc.h_oversample;
4170       ranges[i].v_oversample = cast(ubyte) spc.v_oversample;
4171       for (j=0; j < ranges[i].num_chars; ++j) {
4172          int x0,y0,x1,y1;
4173          int codepoint = ranges[i].array_of_unicode_codepoints == null ? ranges[i].first_unicode_codepoint_in_range + j : ranges[i].array_of_unicode_codepoints[j];
4174          int glyph = stbtt_FindGlyphIndex(info, codepoint);
4175          stbtt_GetGlyphBitmapBoxSubpixel(info,glyph,
4176                                          scale * spc.h_oversample,
4177                                          scale * spc.v_oversample,
4178                                          0,0,
4179                                          &x0,&y0,&x1,&y1);
4180          rects[k].w = cast(stbrp_coord) (x1-x0 + spc.padding + spc.h_oversample-1);
4181          rects[k].h = cast(stbrp_coord) (y1-y0 + spc.padding + spc.v_oversample-1);
4182          ++k;
4183       }
4184    }
4185 
4186    return k;
4187 }
4188 
4189 public void stbtt_MakeGlyphBitmapSubpixelPrefilter(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 prefilter_x, int prefilter_y, float *sub_x, float *sub_y, int glyph)
4190 {
4191    stbtt_MakeGlyphBitmapSubpixel(info,
4192                                  output,
4193                                  out_w - (prefilter_x - 1),
4194                                  out_h - (prefilter_y - 1),
4195                                  out_stride,
4196                                  scale_x,
4197                                  scale_y,
4198                                  shift_x,
4199                                  shift_y,
4200                                  glyph);
4201 
4202    if (prefilter_x > 1)
4203       stbtt__h_prefilter(output, out_w, out_h, out_stride, prefilter_x);
4204 
4205    if (prefilter_y > 1)
4206       stbtt__v_prefilter(output, out_w, out_h, out_stride, prefilter_y);
4207 
4208    *sub_x = stbtt__oversample_shift(prefilter_x);
4209    *sub_y = stbtt__oversample_shift(prefilter_y);
4210 }
4211 
4212 // rects array must be big enough to accommodate all characters in the given ranges
4213 public int stbtt_PackFontRangesRenderIntoRects(stbtt_pack_context *spc, stbtt_fontinfo* info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects)
4214 {
4215    int i,j,k, return_value = 1;
4216 
4217    // save current values
4218    int old_h_over = spc.h_oversample;
4219    int old_v_over = spc.v_oversample;
4220 
4221    k = 0;
4222    for (i=0; i < num_ranges; ++i) {
4223       float fh = ranges[i].font_size;
4224       float scale = fh > 0 ? stbtt_ScaleForPixelHeight(info, fh) : stbtt_ScaleForMappingEmToPixels(info, -fh);
4225       float recip_h,recip_v,sub_x,sub_y;
4226       spc.h_oversample = ranges[i].h_oversample;
4227       spc.v_oversample = ranges[i].v_oversample;
4228       recip_h = 1.0f / spc.h_oversample;
4229       recip_v = 1.0f / spc.v_oversample;
4230       sub_x = stbtt__oversample_shift(spc.h_oversample);
4231       sub_y = stbtt__oversample_shift(spc.v_oversample);
4232       for (j=0; j < ranges[i].num_chars; ++j) {
4233          stbrp_rect *r = &rects[k];
4234          if (r.was_packed) {
4235             stbtt_packedchar *bc = &ranges[i].chardata_for_range[j];
4236             int advance, lsb, x0,y0,x1,y1;
4237             int codepoint = ranges[i].array_of_unicode_codepoints == null ? ranges[i].first_unicode_codepoint_in_range + j : ranges[i].array_of_unicode_codepoints[j];
4238             int glyph = stbtt_FindGlyphIndex(info, codepoint);
4239             stbrp_coord pad = cast(stbrp_coord) spc.padding;
4240 
4241             // pad on left and top
4242             r.x += pad;
4243             r.y += pad;
4244             r.w -= pad;
4245             r.h -= pad;
4246             stbtt_GetGlyphHMetrics(info, glyph, &advance, &lsb);
4247             stbtt_GetGlyphBitmapBox(info, glyph,
4248                                     scale * spc.h_oversample,
4249                                     scale * spc.v_oversample,
4250                                     &x0,&y0,&x1,&y1);
4251             stbtt_MakeGlyphBitmapSubpixel(info,
4252                                           spc.pixels + r.x + r.y*spc.stride_in_bytes,
4253                                           r.w - spc.h_oversample+1,
4254                                           r.h - spc.v_oversample+1,
4255                                           spc.stride_in_bytes,
4256                                           scale * spc.h_oversample,
4257                                           scale * spc.v_oversample,
4258                                           0,0,
4259                                           glyph);
4260 
4261             if (spc.h_oversample > 1)
4262                stbtt__h_prefilter(spc.pixels + r.x + r.y*spc.stride_in_bytes,
4263                                   r.w, r.h, spc.stride_in_bytes,
4264                                   spc.h_oversample);
4265 
4266             if (spc.v_oversample > 1)
4267                stbtt__v_prefilter(spc.pixels + r.x + r.y*spc.stride_in_bytes,
4268                                   r.w, r.h, spc.stride_in_bytes,
4269                                   spc.v_oversample);
4270 
4271             bc.x0       = cast(stbtt_int16)  r.x;
4272             bc.y0       = cast(stbtt_int16)  r.y;
4273             bc.x1       = cast(stbtt_int16) (r.x + r.w);
4274             bc.y1       = cast(stbtt_int16) (r.y + r.h);
4275             bc.xadvance =                scale * advance;
4276             bc.xoff     =       cast(float)  x0 * recip_h + sub_x;
4277             bc.yoff     =       cast(float)  y0 * recip_v + sub_y;
4278             bc.xoff2    =                (x0 + r.w) * recip_h + sub_x;
4279             bc.yoff2    =                (y0 + r.h) * recip_v + sub_y;
4280          } else {
4281             return_value = 0; // if any fail, report failure
4282          }
4283 
4284          ++k;
4285       }
4286    }
4287 
4288    // restore original values
4289    spc.h_oversample = old_h_over;
4290    spc.v_oversample = old_v_over;
4291 
4292    return return_value;
4293 }
4294 
4295 public void stbtt_PackFontRangesPackRects(stbtt_pack_context *spc, stbrp_rect *rects, int num_rects)
4296 {
4297    stbrp_pack_rects(cast(stbrp_context *) spc.pack_info, rects, num_rects);
4298 }
4299 
4300 public int stbtt_PackFontRanges(stbtt_pack_context *spc, const(ubyte)* fontdata, int font_index, stbtt_pack_range *ranges, int num_ranges)
4301 {
4302    stbtt_fontinfo info;
4303    int i,j,n, return_value = 1;
4304    //stbrp_context *context = (stbrp_context *) spc->pack_info;
4305    stbrp_rect    *rects;
4306 
4307    // flag all characters as NOT packed
4308    for (i=0; i < num_ranges; ++i)
4309       for (j=0; j < ranges[i].num_chars; ++j)
4310          ranges[i].chardata_for_range[j].x0 =
4311          ranges[i].chardata_for_range[j].y0 =
4312          ranges[i].chardata_for_range[j].x1 =
4313          ranges[i].chardata_for_range[j].y1 = 0;
4314 
4315    n = 0;
4316    for (i=0; i < num_ranges; ++i)
4317       n += ranges[i].num_chars;
4318 
4319    rects = cast(stbrp_rect *) STBTT_malloc(cast(uint)(*rects).sizeof * n, spc.user_allocator_context);
4320    if (rects == null)
4321       return 0;
4322 
4323    info.userdata = spc.user_allocator_context;
4324    stbtt_InitFont(&info, fontdata, stbtt_GetFontOffsetForIndex(fontdata,font_index));
4325 
4326    n = stbtt_PackFontRangesGatherRects(spc, &info, ranges, num_ranges, rects);
4327 
4328    stbtt_PackFontRangesPackRects(spc, rects, n);
4329 
4330    return_value = stbtt_PackFontRangesRenderIntoRects(spc, &info, ranges, num_ranges, rects);
4331 
4332    STBTT_free(rects, spc.user_allocator_context);
4333    return return_value;
4334 }
4335 
4336 public int stbtt_PackFontRange(stbtt_pack_context *spc, const(ubyte)* fontdata, int font_index, float font_size,
4337             int first_unicode_codepoint_in_range, int num_chars_in_range, stbtt_packedchar *chardata_for_range)
4338 {
4339    stbtt_pack_range range;
4340    range.first_unicode_codepoint_in_range = first_unicode_codepoint_in_range;
4341    range.array_of_unicode_codepoints = null;
4342    range.num_chars                   = num_chars_in_range;
4343    range.chardata_for_range          = chardata_for_range;
4344    range.font_size                   = font_size;
4345    return stbtt_PackFontRanges(spc, fontdata, font_index, &range, 1);
4346 }
4347 
4348 public void stbtt_GetPackedQuad(const(stbtt_packedchar)* chardata, int pw, int ph, int char_index, float *xpos, float *ypos, stbtt_aligned_quad *q, int align_to_integer)
4349 {
4350    float ipw = 1.0f / pw, iph = 1.0f / ph;
4351    const(stbtt_packedchar)* b = chardata + char_index;
4352 
4353    if (align_to_integer) {
4354       float x = cast(float) STBTT_ifloor((*xpos + b.xoff) + 0.5f);
4355       float y = cast(float) STBTT_ifloor((*ypos + b.yoff) + 0.5f);
4356       q.x0 = x;
4357       q.y0 = y;
4358       q.x1 = x + b.xoff2 - b.xoff;
4359       q.y1 = y + b.yoff2 - b.yoff;
4360    } else {
4361       q.x0 = *xpos + b.xoff;
4362       q.y0 = *ypos + b.yoff;
4363       q.x1 = *xpos + b.xoff2;
4364       q.y1 = *ypos + b.yoff2;
4365    }
4366 
4367    q.s0 = b.x0 * ipw;
4368    q.t0 = b.y0 * iph;
4369    q.s1 = b.x1 * ipw;
4370    q.t1 = b.y1 * iph;
4371 
4372    *xpos += b.xadvance;
4373 }
4374 
4375 //////////////////////////////////////////////////////////////////////////////
4376 //
4377 // sdf computation
4378 //
4379 
4380 //#define STBTT_min(a,b)  ((a) < (b) ? (a) : (b))
4381 //#define STBTT_max(a,b)  ((a) < (b) ? (b) : (a))
4382 T STBTT_min(T) (in T a, in T b) pure { pragma(inline, true); return (a < b ? a : b); }
4383 T STBTT_max(T) (in T a, in T b) pure { pragma(inline, true); return (a < b ? b : a); }
4384 
4385 private int stbtt__ray_intersect_bezier(const scope ref float[2] orig, const scope ref float[2] ray, const scope ref float[2] q0, const scope ref float[2] q1, const scope ref float[2] q2, ref float[2][2] hits)
4386 {
4387    float q0perp = q0[1]*ray[0] - q0[0]*ray[1];
4388    float q1perp = q1[1]*ray[0] - q1[0]*ray[1];
4389    float q2perp = q2[1]*ray[0] - q2[0]*ray[1];
4390    float roperp = orig[1]*ray[0] - orig[0]*ray[1];
4391 
4392    float a = q0perp - 2*q1perp + q2perp;
4393    float b = q1perp - q0perp;
4394    float c = q0perp - roperp;
4395 
4396    float s0 = 0., s1 = 0.;
4397    int num_s = 0;
4398 
4399    if (a != 0.0) {
4400       float discr = b*b - a*c;
4401       if (discr > 0.0) {
4402          float rcpna = -1 / a;
4403          float d = cast(float) STBTT_sqrt(discr);
4404          s0 = (b+d) * rcpna;
4405          s1 = (b-d) * rcpna;
4406          if (s0 >= 0.0 && s0 <= 1.0)
4407             num_s = 1;
4408          if (d > 0.0 && s1 >= 0.0 && s1 <= 1.0) {
4409             if (num_s == 0) s0 = s1;
4410             ++num_s;
4411          }
4412       }
4413    } else {
4414       // 2*b*s + c = 0
4415       // s = -c / (2*b)
4416       s0 = c / (-2 * b);
4417       if (s0 >= 0.0 && s0 <= 1.0)
4418          num_s = 1;
4419    }
4420 
4421    if (num_s == 0)
4422       return 0;
4423    else {
4424       float rcp_len2 = 1 / (ray[0]*ray[0] + ray[1]*ray[1]);
4425       float rayn_x = ray[0] * rcp_len2, rayn_y = ray[1] * rcp_len2;
4426 
4427       float q0d =   q0[0]*rayn_x +   q0[1]*rayn_y;
4428       float q1d =   q1[0]*rayn_x +   q1[1]*rayn_y;
4429       float q2d =   q2[0]*rayn_x +   q2[1]*rayn_y;
4430       float rod = orig[0]*rayn_x + orig[1]*rayn_y;
4431 
4432       float q10d = q1d - q0d;
4433       float q20d = q2d - q0d;
4434       float q0rd = q0d - rod;
4435 
4436       hits[0][0] = q0rd + s0*(2.0f - 2.0f*s0)*q10d + s0*s0*q20d;
4437       hits[0][1] = a*s0+b;
4438 
4439       if (num_s > 1) {
4440          hits[1][0] = q0rd + s1*(2.0f - 2.0f*s1)*q10d + s1*s1*q20d;
4441          hits[1][1] = a*s1+b;
4442          return 2;
4443       } else {
4444          return 1;
4445       }
4446    }
4447 }
4448 
4449 private int equal(float *a, float *b)
4450 {
4451    return (a[0] == b[0] && a[1] == b[1]);
4452 }
4453 
4454 private int stbtt__compute_crossings_x(float x, float y, int nverts, stbtt_vertex *verts)
4455 {
4456    int i;
4457    float[2] orig = void;
4458    float[2] ray = [ 1, 0 ];
4459    float y_frac;
4460    int winding = 0;
4461 
4462    orig[0] = x;
4463    orig[1] = y;
4464 
4465    // make sure y never passes through a vertex of the shape
4466    y_frac = cast(float) STBTT_fmod(y, 1.0f);
4467    if (y_frac < 0.01f)
4468       y += 0.01f;
4469    else if (y_frac > 0.99f)
4470       y -= 0.01f;
4471    orig[1] = y;
4472 
4473    // test a ray from (-infinity,y) to (x,y)
4474    for (i=0; i < nverts; ++i) {
4475       if (verts[i].type == STBTT_vline) {
4476          int x0 = cast(int) verts[i-1].x, y0 = cast(int) verts[i-1].y;
4477          int x1 = cast(int) verts[i  ].x, y1 = cast(int) verts[i  ].y;
4478          if (y > STBTT_min(y0,y1) && y < STBTT_max(y0,y1) && x > STBTT_min(x0,x1)) {
4479             float x_inter = (y - y0) / (y1 - y0) * (x1-x0) + x0;
4480             if (x_inter < x)
4481                winding += (y0 < y1) ? 1 : -1;
4482          }
4483       }
4484       if (verts[i].type == STBTT_vcurve) {
4485          int x0 = cast(int) verts[i-1].x , y0 = cast(int) verts[i-1].y ;
4486          int x1 = cast(int) verts[i  ].cx, y1 = cast(int) verts[i  ].cy;
4487          int x2 = cast(int) verts[i  ].x , y2 = cast(int) verts[i  ].y ;
4488          int ax = STBTT_min(x0,STBTT_min(x1,x2)), ay = STBTT_min(y0,STBTT_min(y1,y2));
4489          int by = STBTT_max(y0,STBTT_max(y1,y2));
4490          if (y > ay && y < by && x > ax) {
4491             float[2] q0, q1, q2;
4492             float[2][2] hits;
4493             q0[0] = cast(float)x0;
4494             q0[1] = cast(float)y0;
4495             q1[0] = cast(float)x1;
4496             q1[1] = cast(float)y1;
4497             q2[0] = cast(float)x2;
4498             q2[1] = cast(float)y2;
4499             if (equal(q0.ptr,q1.ptr) || equal(q1.ptr,q2.ptr)) {
4500                x0 = cast(int)verts[i-1].x;
4501                y0 = cast(int)verts[i-1].y;
4502                x1 = cast(int)verts[i  ].x;
4503                y1 = cast(int)verts[i  ].y;
4504                if (y > STBTT_min(y0,y1) && y < STBTT_max(y0,y1) && x > STBTT_min(x0,x1)) {
4505                   float x_inter = (y - y0) / (y1 - y0) * (x1-x0) + x0;
4506                   if (x_inter < x)
4507                      winding += (y0 < y1) ? 1 : -1;
4508                }
4509             } else {
4510                int num_hits = stbtt__ray_intersect_bezier(orig, ray, q0, q1, q2, hits);
4511                if (num_hits >= 1)
4512                   if (hits[0][0] < 0)
4513                      winding += (hits[0][1] < 0 ? -1 : 1);
4514                if (num_hits >= 2)
4515                   if (hits[1][0] < 0)
4516                      winding += (hits[1][1] < 0 ? -1 : 1);
4517             }
4518          }
4519       }
4520    }
4521    return winding;
4522 }
4523 
4524 private float stbtt__cuberoot( float x )
4525 {
4526    if (x<0)
4527       return -cast(float) STBTT_pow(-x,1.0f/3.0f);
4528    else
4529       return  cast(float) STBTT_pow( x,1.0f/3.0f);
4530 }
4531 
4532 // x^3 + c*x^2 + b*x + a = 0
4533 private int stbtt__solve_cubic(float a, float b, float c, float* r)
4534 {
4535   float s = -a / 3;
4536   float p = b - a*a / 3;
4537   float q = a * (2*a*a - 9*b) / 27 + c;
4538   float p3 = p*p*p;
4539   float d = q*q + 4*p3 / 27;
4540   if (d >= 0) {
4541     float z = cast(float) STBTT_sqrt(d);
4542     float u = (-q + z) / 2;
4543     float v = (-q - z) / 2;
4544     u = stbtt__cuberoot(u);
4545     v = stbtt__cuberoot(v);
4546     r[0] = s + u + v;
4547     return 1;
4548   } else {
4549      float u = cast(float) STBTT_sqrt(-p/3);
4550      float v = cast(float) STBTT_acos(-STBTT_sqrt(-27/p3) * q / 2) / 3; // p3 must be negative, since d is negative
4551      float m = cast(float) STBTT_cos(v);
4552       float n = cast(float) STBTT_cos(v-3.141592/2)*1.732050808f;
4553      r[0] = s + u * 2 * m;
4554      r[1] = s - u * (m + n);
4555      r[2] = s - u * (m - n);
4556 
4557       //STBTT_assert( STBTT_fabs(((r[0]+a)*r[0]+b)*r[0]+c) < 0.05f);  // these asserts may not be safe at all scales, though they're in bezier t parameter units so maybe?
4558       //STBTT_assert( STBTT_fabs(((r[1]+a)*r[1]+b)*r[1]+c) < 0.05f);
4559       //STBTT_assert( STBTT_fabs(((r[2]+a)*r[2]+b)*r[2]+c) < 0.05f);
4560     return 3;
4561    }
4562 }
4563 
4564 public ubyte * stbtt_GetGlyphSDF(stbtt_fontinfo* info, float scale, int glyph, int padding, ubyte onedge_value, float pixel_dist_scale, int *width, int *height, int *xoff, int *yoff)
4565 {
4566    float scale_x = scale, scale_y = scale;
4567    int ix0,iy0,ix1,iy1;
4568    int w,h;
4569    ubyte *data;
4570 
4571    // if one scale is 0, use same scale for both
4572    if (scale_x == 0) scale_x = scale_y;
4573    if (scale_y == 0) {
4574       if (scale_x == 0) return null;  // if both scales are 0, return NULL
4575       scale_y = scale_x;
4576    }
4577 
4578    stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale, scale, 0.0f,0.0f, &ix0,&iy0,&ix1,&iy1);
4579 
4580    // if empty, return NULL
4581    if (ix0 == ix1 || iy0 == iy1)
4582       return null;
4583 
4584    ix0 -= padding;
4585    iy0 -= padding;
4586    ix1 += padding;
4587    iy1 += padding;
4588 
4589    w = (ix1 - ix0);
4590    h = (iy1 - iy0);
4591 
4592    if (width ) *width  = w;
4593    if (height) *height = h;
4594    if (xoff  ) *xoff   = ix0;
4595    if (yoff  ) *yoff   = iy0;
4596 
4597    // invert for y-downwards bitmaps
4598    scale_y = -scale_y;
4599 
4600    {
4601       int x,y,i,j;
4602       float *precompute;
4603       stbtt_vertex *verts;
4604       int num_verts = stbtt_GetGlyphShape(info, glyph, &verts);
4605       data = cast(ubyte *) STBTT_malloc(w * h, info.userdata);
4606       precompute = cast(float *) STBTT_malloc(num_verts * cast(uint)float.sizeof, info.userdata);
4607 
4608       for (i=0,j=num_verts-1; i < num_verts; j=i++) {
4609          if (verts[i].type == STBTT_vline) {
4610             float x0 = verts[i].x*scale_x, y0 = verts[i].y*scale_y;
4611             float x1 = verts[j].x*scale_x, y1 = verts[j].y*scale_y;
4612             float dist = cast(float) STBTT_sqrt((x1-x0)*(x1-x0) + (y1-y0)*(y1-y0));
4613             precompute[i] = (dist == 0) ? 0.0f : 1.0f / dist;
4614          } else if (verts[i].type == STBTT_vcurve) {
4615             float x2 = verts[j].x *scale_x, y2 = verts[j].y *scale_y;
4616             float x1 = verts[i].cx*scale_x, y1 = verts[i].cy*scale_y;
4617             float x0 = verts[i].x *scale_x, y0 = verts[i].y *scale_y;
4618             float bx = x0 - 2*x1 + x2, by = y0 - 2*y1 + y2;
4619             float len2 = bx*bx + by*by;
4620             if (len2 != 0.0f)
4621                precompute[i] = 1.0f / (bx*bx + by*by);
4622             else
4623                precompute[i] = 0.0f;
4624          } else
4625             precompute[i] = 0.0f;
4626       }
4627 
4628       for (y=iy0; y < iy1; ++y) {
4629          for (x=ix0; x < ix1; ++x) {
4630             float val;
4631             float min_dist = 999999.0f;
4632             float sx = cast(float) x + 0.5f;
4633             float sy = cast(float) y + 0.5f;
4634             float x_gspace = (sx / scale_x);
4635             float y_gspace = (sy / scale_y);
4636 
4637             int winding = stbtt__compute_crossings_x(x_gspace, y_gspace, num_verts, verts); // @OPTIMIZE: this could just be a rasterization, but needs to be line vs. non-tesselated curves so a new path
4638 
4639             for (i=0; i < num_verts; ++i) {
4640                float x0 = verts[i].x*scale_x, y0 = verts[i].y*scale_y;
4641 
4642                // check against every point here rather than inside line/curve primitives -- @TODO: wrong if multiple 'moves' in a row produce a garbage point, and given culling, probably more efficient to do within line/curve
4643                float dist2 = (x0-sx)*(x0-sx) + (y0-sy)*(y0-sy);
4644                if (dist2 < min_dist*min_dist)
4645                   min_dist = cast(float) STBTT_sqrt(dist2);
4646 
4647                if (verts[i].type == STBTT_vline) {
4648                   float x1 = verts[i-1].x*scale_x, y1 = verts[i-1].y*scale_y;
4649 
4650                   // coarse culling against bbox
4651                   //if (sx > STBTT_min(x0,x1)-min_dist && sx < STBTT_max(x0,x1)+min_dist &&
4652                   //    sy > STBTT_min(y0,y1)-min_dist && sy < STBTT_max(y0,y1)+min_dist)
4653                   float dist = cast(float) STBTT_fabs((x1-x0)*(y0-sy) - (y1-y0)*(x0-sx)) * precompute[i];
4654                   assert(i != 0);
4655                   if (dist < min_dist) {
4656                      // check position along line
4657                      // x' = x0 + t*(x1-x0), y' = y0 + t*(y1-y0)
4658                      // minimize (x'-sx)*(x'-sx)+(y'-sy)*(y'-sy)
4659                      float dx = x1-x0, dy = y1-y0;
4660                      float px = x0-sx, py = y0-sy;
4661                      // minimize (px+t*dx)^2 + (py+t*dy)^2 = px*px + 2*px*dx*t + t^2*dx*dx + py*py + 2*py*dy*t + t^2*dy*dy
4662                      // derivative: 2*px*dx + 2*py*dy + (2*dx*dx+2*dy*dy)*t, set to 0 and solve
4663                      float t = -(px*dx + py*dy) / (dx*dx + dy*dy);
4664                      if (t >= 0.0f && t <= 1.0f)
4665                         min_dist = dist;
4666                   }
4667                } else if (verts[i].type == STBTT_vcurve) {
4668                   float x2 = verts[i-1].x *scale_x, y2 = verts[i-1].y *scale_y;
4669                   float x1 = verts[i  ].cx*scale_x, y1 = verts[i  ].cy*scale_y;
4670                   float box_x0 = STBTT_min(STBTT_min(x0,x1),x2);
4671                   float box_y0 = STBTT_min(STBTT_min(y0,y1),y2);
4672                   float box_x1 = STBTT_max(STBTT_max(x0,x1),x2);
4673                   float box_y1 = STBTT_max(STBTT_max(y0,y1),y2);
4674                   // coarse culling against bbox to avoid computing cubic unnecessarily
4675                   if (sx > box_x0-min_dist && sx < box_x1+min_dist && sy > box_y0-min_dist && sy < box_y1+min_dist) {
4676                      int num=0;
4677                      float ax = x1-x0, ay = y1-y0;
4678                      float bx = x0 - 2*x1 + x2, by = y0 - 2*y1 + y2;
4679                      float mx = x0 - sx, my = y0 - sy;
4680                      float[3] res;
4681                      float px,py,t,it;
4682                      float a_inv = precompute[i];
4683                      if (a_inv == 0.0) { // if a_inv is 0, it's 2nd degree so use quadratic formula
4684                         float a = 3*(ax*bx + ay*by);
4685                         float b = 2*(ax*ax + ay*ay) + (mx*bx+my*by);
4686                         float c = mx*ax+my*ay;
4687                         if (a == 0.0) { // if a is 0, it's linear
4688                            if (b != 0.0) {
4689                               res[num++] = -c/b;
4690                            }
4691                         } else {
4692                            float discriminant = b*b - 4*a*c;
4693                            if (discriminant < 0)
4694                               num = 0;
4695                            else {
4696                               float root = cast(float) STBTT_sqrt(discriminant);
4697                               res[0] = (-b - root)/(2*a);
4698                               res[1] = (-b + root)/(2*a);
4699                               num = 2; // don't bother distinguishing 1-solution case, as code below will still work
4700                            }
4701                         }
4702                      } else {
4703                         float b = 3*(ax*bx + ay*by) * a_inv; // could precompute this as it doesn't depend on sample point
4704                         float c = (2*(ax*ax + ay*ay) + (mx*bx+my*by)) * a_inv;
4705                         float d = (mx*ax+my*ay) * a_inv;
4706                         num = stbtt__solve_cubic(b, c, d, res.ptr);
4707                      }
4708                      if (num >= 1 && res[0] >= 0.0f && res[0] <= 1.0f) {
4709                         t = res[0], it = 1.0f - t;
4710                         px = it*it*x0 + 2*t*it*x1 + t*t*x2;
4711                         py = it*it*y0 + 2*t*it*y1 + t*t*y2;
4712                         dist2 = (px-sx)*(px-sx) + (py-sy)*(py-sy);
4713                         if (dist2 < min_dist * min_dist)
4714                            min_dist = cast(float) STBTT_sqrt(dist2);
4715                      }
4716                      if (num >= 2 && res[1] >= 0.0f && res[1] <= 1.0f) {
4717                         t = res[1], it = 1.0f - t;
4718                         px = it*it*x0 + 2*t*it*x1 + t*t*x2;
4719                         py = it*it*y0 + 2*t*it*y1 + t*t*y2;
4720                         dist2 = (px-sx)*(px-sx) + (py-sy)*(py-sy);
4721                         if (dist2 < min_dist * min_dist)
4722                            min_dist = cast(float) STBTT_sqrt(dist2);
4723                      }
4724                      if (num >= 3 && res[2] >= 0.0f && res[2] <= 1.0f) {
4725                         t = res[2], it = 1.0f - t;
4726                         px = it*it*x0 + 2*t*it*x1 + t*t*x2;
4727                         py = it*it*y0 + 2*t*it*y1 + t*t*y2;
4728                         dist2 = (px-sx)*(px-sx) + (py-sy)*(py-sy);
4729                         if (dist2 < min_dist * min_dist)
4730                            min_dist = cast(float) STBTT_sqrt(dist2);
4731                      }
4732                   }
4733                }
4734             }
4735             if (winding == 0)
4736                min_dist = -min_dist;  // if outside the shape, value is negative
4737             val = onedge_value + pixel_dist_scale * min_dist;
4738             if (val < 0)
4739                val = 0;
4740             else if (val > 255)
4741                val = 255;
4742             data[(y-iy0)*w+(x-ix0)] = cast(ubyte) val;
4743          }
4744       }
4745       STBTT_free(precompute, info.userdata);
4746       STBTT_free(verts, info.userdata);
4747    }
4748    return data;
4749 }
4750 
4751 public ubyte * stbtt_GetCodepointSDF(stbtt_fontinfo* info, float scale, int codepoint, int padding, ubyte onedge_value, float pixel_dist_scale, int *width, int *height, int *xoff, int *yoff)
4752 {
4753    return stbtt_GetGlyphSDF(info, scale, stbtt_FindGlyphIndex(info, codepoint), padding, onedge_value, pixel_dist_scale, width, height, xoff, yoff);
4754 }
4755 
4756 public void stbtt_FreeSDF(ubyte *bitmap, void *userdata)
4757 {
4758    STBTT_free(bitmap, userdata);
4759 }
4760 
4761 //////////////////////////////////////////////////////////////////////////////
4762 //
4763 // font name matching -- recommended not to use this
4764 //
4765 
4766 // check if a utf8 string contains a prefix which is the utf16 string; if so return length of matching utf8 string
4767 private stbtt_int32 stbtt__CompareUTF8toUTF16_bigendian_prefix(stbtt_uint8 *s1, stbtt_int32 len1, stbtt_uint8 *s2, stbtt_int32 len2)
4768 {
4769    stbtt_int32 i=0;
4770 
4771    // convert utf16 to utf8 and compare the results while converting
4772    while (len2) {
4773       stbtt_uint16 ch = s2[0]*256 + s2[1];
4774       if (ch < 0x80) {
4775          if (i >= len1) return -1;
4776          if (s1[i++] != ch) return -1;
4777       } else if (ch < 0x800) {
4778          if (i+1 >= len1) return -1;
4779          if (s1[i++] != 0xc0 + (ch >> 6)) return -1;
4780          if (s1[i++] != 0x80 + (ch & 0x3f)) return -1;
4781       } else if (ch >= 0xd800 && ch < 0xdc00) {
4782          stbtt_uint32 c;
4783          stbtt_uint16 ch2 = s2[2]*256 + s2[3];
4784          if (i+3 >= len1) return -1;
4785          c = ((ch - 0xd800) << 10) + (ch2 - 0xdc00) + 0x10000;
4786          if (s1[i++] != 0xf0 + (c >> 18)) return -1;
4787          if (s1[i++] != 0x80 + ((c >> 12) & 0x3f)) return -1;
4788          if (s1[i++] != 0x80 + ((c >>  6) & 0x3f)) return -1;
4789          if (s1[i++] != 0x80 + ((c      ) & 0x3f)) return -1;
4790          s2 += 2; // plus another 2 below
4791          len2 -= 2;
4792       } else if (ch >= 0xdc00 && ch < 0xe000) {
4793          return -1;
4794       } else {
4795          if (i+2 >= len1) return -1;
4796          if (s1[i++] != 0xe0 + (ch >> 12)) return -1;
4797          if (s1[i++] != 0x80 + ((ch >> 6) & 0x3f)) return -1;
4798          if (s1[i++] != 0x80 + ((ch     ) & 0x3f)) return -1;
4799       }
4800       s2 += 2;
4801       len2 -= 2;
4802    }
4803    return i;
4804 }
4805 
4806 private int stbtt_CompareUTF8toUTF16_bigendian_internal(char *s1, int len1, char *s2, int len2)
4807 {
4808    return len1 == stbtt__CompareUTF8toUTF16_bigendian_prefix(cast(stbtt_uint8*) s1, len1, cast(stbtt_uint8*) s2, len2);
4809 }
4810 
4811 // returns results in whatever encoding you request... but note that 2-byte encodings
4812 // will be BIG-ENDIAN... use stbtt_CompareUTF8toUTF16_bigendian() to compare
4813 public const(char)* stbtt_GetFontNameString(stbtt_fontinfo* font, int *length, int platformID, int encodingID, int languageID, int nameID)
4814 {
4815    stbtt_int32 i,count,stringOffset;
4816    stbtt_uint8 *fc = font.data;
4817    stbtt_uint32 offset = font.fontstart;
4818    stbtt_uint32 nm = stbtt__find_table(fc, offset, "name");
4819    if (!nm) return null;
4820 
4821    count = ttUSHORT(fc+nm+2);
4822    stringOffset = nm + ttUSHORT(fc+nm+4);
4823    for (i=0; i < count; ++i) {
4824       stbtt_uint32 loc = nm + 6 + 12 * i;
4825       if (platformID == ttUSHORT(fc+loc+0) && encodingID == ttUSHORT(fc+loc+2)
4826           && languageID == ttUSHORT(fc+loc+4) && nameID == ttUSHORT(fc+loc+6)) {
4827          *length = ttUSHORT(fc+loc+8);
4828          return cast(const(char)* ) (fc+stringOffset+ttUSHORT(fc+loc+10));
4829       }
4830    }
4831    return null;
4832 }
4833 
4834 private int stbtt__matchpair(stbtt_uint8 *fc, stbtt_uint32 nm, stbtt_uint8 *name, stbtt_int32 nlen, stbtt_int32 target_id, stbtt_int32 next_id)
4835 {
4836    stbtt_int32 i;
4837    stbtt_int32 count = ttUSHORT(fc+nm+2);
4838    stbtt_int32 stringOffset = nm + ttUSHORT(fc+nm+4);
4839 
4840    for (i=0; i < count; ++i) {
4841       stbtt_uint32 loc = nm + 6 + 12 * i;
4842       stbtt_int32 id = ttUSHORT(fc+loc+6);
4843       if (id == target_id) {
4844          // find the encoding
4845          stbtt_int32 platform = ttUSHORT(fc+loc+0), encoding = ttUSHORT(fc+loc+2), language = ttUSHORT(fc+loc+4);
4846 
4847          // is this a Unicode encoding?
4848          if (platform == 0 || (platform == 3 && encoding == 1) || (platform == 3 && encoding == 10)) {
4849             stbtt_int32 slen = ttUSHORT(fc+loc+8);
4850             stbtt_int32 off = ttUSHORT(fc+loc+10);
4851 
4852             // check if there's a prefix match
4853             stbtt_int32 matchlen = stbtt__CompareUTF8toUTF16_bigendian_prefix(name, nlen, fc+stringOffset+off,slen);
4854             if (matchlen >= 0) {
4855                // check for target_id+1 immediately following, with same encoding & language
4856                if (i+1 < count && ttUSHORT(fc+loc+12+6) == next_id && ttUSHORT(fc+loc+12) == platform && ttUSHORT(fc+loc+12+2) == encoding && ttUSHORT(fc+loc+12+4) == language) {
4857                   slen = ttUSHORT(fc+loc+12+8);
4858                   off = ttUSHORT(fc+loc+12+10);
4859                   if (slen == 0) {
4860                      if (matchlen == nlen)
4861                         return 1;
4862                   } else if (matchlen < nlen && name[matchlen] == ' ') {
4863                      ++matchlen;
4864                      if (stbtt_CompareUTF8toUTF16_bigendian_internal(cast(char*) (name+matchlen), nlen-matchlen, cast(char*)(fc+stringOffset+off),slen))
4865                         return 1;
4866                   }
4867                } else {
4868                   // if nothing immediately following
4869                   if (matchlen == nlen)
4870                      return 1;
4871                }
4872             }
4873          }
4874 
4875          // @TODO handle other encodings
4876       }
4877    }
4878    return 0;
4879 }
4880 
4881 private int stbtt__matches(stbtt_uint8 *fc, stbtt_uint32 offset, stbtt_uint8 *name, stbtt_int32 flags)
4882 {
4883    stbtt_int32 nlen = cast(stbtt_int32) STBTT_strlen(cast(char *) name);
4884    stbtt_uint32 nm,hd;
4885    if (!stbtt__isfont(fc+offset)) return 0;
4886 
4887    // check italics/bold/underline flags in macStyle...
4888    if (flags) {
4889       hd = stbtt__find_table(fc, offset, "head");
4890       if ((ttUSHORT(fc+hd+44) & 7) != (flags & 7)) return 0;
4891    }
4892 
4893    nm = stbtt__find_table(fc, offset, "name");
4894    if (!nm) return 0;
4895 
4896    if (flags) {
4897       // if we checked the macStyle flags, then just check the family and ignore the subfamily
4898       if (stbtt__matchpair(fc, nm, name, nlen, 16, -1))  return 1;
4899       if (stbtt__matchpair(fc, nm, name, nlen,  1, -1))  return 1;
4900       if (stbtt__matchpair(fc, nm, name, nlen,  3, -1))  return 1;
4901    } else {
4902       if (stbtt__matchpair(fc, nm, name, nlen, 16, 17))  return 1;
4903       if (stbtt__matchpair(fc, nm, name, nlen,  1,  2))  return 1;
4904       if (stbtt__matchpair(fc, nm, name, nlen,  3, -1))  return 1;
4905    }
4906 
4907    return 0;
4908 }
4909 
4910 private int stbtt_FindMatchingFont_internal(ubyte *font_collection, char *name_utf8, stbtt_int32 flags)
4911 {
4912    stbtt_int32 i;
4913    for (i=0;;++i) {
4914       stbtt_int32 off = stbtt_GetFontOffsetForIndex(font_collection, i);
4915       if (off < 0) return off;
4916       if (stbtt__matches(cast(stbtt_uint8 *) font_collection, off, cast(stbtt_uint8*) name_utf8, flags))
4917          return off;
4918    }
4919 }
4920 
4921 public int stbtt_BakeFontBitmap(const(ubyte)* data, int offset,
4922                                 float pixel_height, ubyte *pixels, int pw, int ph,
4923                                 int first_char, int num_chars, stbtt_bakedchar *chardata,
4924 				int* ascent = null, int* descent = null, int* line_gap = null
4925 				)
4926 {
4927    return stbtt_BakeFontBitmap_internal(cast(ubyte *) data, offset, pixel_height, pixels, pw, ph, first_char, num_chars, chardata, ascent, descent, line_gap);
4928 }
4929 
4930 public int stbtt_GetFontOffsetForIndex(const(ubyte)* data, int index)
4931 {
4932    return stbtt_GetFontOffsetForIndex_internal(cast(ubyte *) data, index);
4933 }
4934 
4935 public int stbtt_GetNumberOfFonts(const(ubyte)* data)
4936 {
4937    return stbtt_GetNumberOfFonts_internal(cast(ubyte *) data);
4938 }
4939 
4940 public int stbtt_InitFont(stbtt_fontinfo *info, const(ubyte)* data, int offset)
4941 {
4942    return stbtt_InitFont_internal(info, cast(ubyte *) data, offset);
4943 }
4944 
4945 public int stbtt_FindMatchingFont(const(ubyte)* fontdata, const(char)* name, int flags)
4946 {
4947    return stbtt_FindMatchingFont_internal(cast(ubyte *) fontdata, cast(char *) name, flags);
4948 }
4949 
4950 public int stbtt_CompareUTF8toUTF16_bigendian(const(char)* s1, int len1, const(char)* s2, int len2)
4951 {
4952    return stbtt_CompareUTF8toUTF16_bigendian_internal(cast(char *) s1, len1, cast(char *) s2, len2);
4953 }
4954 
4955 
4956 // FULL VERSION HISTORY
4957 //
4958 //   1.19 (2018-02-11) OpenType GPOS kerning (horizontal only), STBTT_fmod
4959 //   1.18 (2018-01-29) add missing function
4960 //   1.17 (2017-07-23) make more arguments const; doc fix
4961 //   1.16 (2017-07-12) SDF support
4962 //   1.15 (2017-03-03) make more arguments const
4963 //   1.14 (2017-01-16) num-fonts-in-TTC function
4964 //   1.13 (2017-01-02) support OpenType fonts, certain Apple fonts
4965 //   1.12 (2016-10-25) suppress warnings about casting away const with -Wcast-qual
4966 //   1.11 (2016-04-02) fix unused-variable warning
4967 //   1.10 (2016-04-02) allow user-defined fabs() replacement
4968 //                     fix memory leak if fontsize=0.0
4969 //                     fix warning from duplicate typedef
4970 //   1.09 (2016-01-16) warning fix; avoid crash on outofmem; use alloc userdata for PackFontRanges
4971 //   1.08 (2015-09-13) document stbtt_Rasterize(); fixes for vertical & horizontal edges
4972 //   1.07 (2015-08-01) allow PackFontRanges to accept arrays of sparse codepoints;
4973 //                     allow PackFontRanges to pack and render in separate phases;
4974 //                     fix stbtt_GetFontOFfsetForIndex (never worked for non-0 input?);
4975 //                     fixed an assert() bug in the new rasterizer
4976 //                     replace assert() with STBTT_assert() in new rasterizer
4977 //   1.06 (2015-07-14) performance improvements (~35% faster on x86 and x64 on test machine)
4978 //                     also more precise AA rasterizer, except if shapes overlap
4979 //                     remove need for STBTT_sort
4980 //   1.05 (2015-04-15) fix misplaced definitions for STBTT_STATIC
4981 //   1.04 (2015-04-15) typo in example
4982 //   1.03 (2015-04-12) STBTT_STATIC, fix memory leak in new packing, various fixes
4983 //   1.02 (2014-12-10) fix various warnings & compile issues w/ stb_rect_pack, C++
4984 //   1.01 (2014-12-08) fix subpixel position when oversampling to exactly match
4985 //                        non-oversampled; STBTT_POINT_SIZE for packed case only
4986 //   1.00 (2014-12-06) add new PackBegin etc. API, w/ support for oversampling
4987 //   0.99 (2014-09-18) fix multiple bugs with subpixel rendering (ryg)
4988 //   0.9  (2014-08-07) support certain mac/iOS fonts without an MS platformID
4989 //   0.8b (2014-07-07) fix a warning
4990 //   0.8  (2014-05-25) fix a few more warnings
4991 //   0.7  (2013-09-25) bugfix: subpixel glyph bug fixed in 0.5 had come back
4992 //   0.6c (2012-07-24) improve documentation
4993 //   0.6b (2012-07-20) fix a few more warnings
4994 //   0.6  (2012-07-17) fix warnings; added stbtt_ScaleForMappingEmToPixels,
4995 //                        stbtt_GetFontBoundingBox, stbtt_IsGlyphEmpty
4996 //   0.5  (2011-12-09) bugfixes:
4997 //                        subpixel glyph renderer computed wrong bounding box
4998 //                        first vertex of shape can be off-curve (FreeSans)
4999 //   0.4b (2011-12-03) fixed an error in the font baking example
5000 //   0.4  (2011-12-01) kerning, subpixel rendering (tor)
5001 //                    bugfixes for:
5002 //                        codepoint-to-glyph conversion using table fmt=12
5003 //                        codepoint-to-glyph conversion using table fmt=4
5004 //                        stbtt_GetBakedQuad with non-square texture (Zer)
5005 //                    updated Hello World! sample to use kerning and subpixel
5006 //                    fixed some warnings
5007 //   0.3  (2009-06-24) cmap fmt=12, compound shapes (MM)
5008 //                    userdata, malloc-from-userdata, non-zero fill (stb)
5009 //   0.2  (2009-03-11) Fix unsigned/signed char warnings
5010 //   0.1  (2009-03-09) First public release
5011 //
5012 
5013 /*
5014 ------------------------------------------------------------------------------
5015 This software is available under 2 licenses -- choose whichever you prefer.
5016 ------------------------------------------------------------------------------
5017 ALTERNATIVE A - MIT License
5018 Copyright (c) 2017 Sean Barrett
5019 Permission is hereby granted, free of charge, to any person obtaining a copy of
5020 this software and associated documentation files (the "Software"), to deal in
5021 the Software without restriction, including without limitation the rights to
5022 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
5023 of the Software, and to permit persons to whom the Software is furnished to do
5024 so, subject to the following conditions:
5025 The above copyright notice and this permission notice shall be included in all
5026 copies or substantial portions of the Software.
5027 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
5028 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
5029 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
5030 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
5031 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
5032 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
5033 SOFTWARE.
5034 ------------------------------------------------------------------------------
5035 ALTERNATIVE B - Public Domain (www.unlicense.org)
5036 This is free and unencumbered software released into the public domain.
5037 Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
5038 software, either in source code form or as a compiled binary, for any purpose,
5039 commercial or non-commercial, and by any means.
5040 In jurisdictions that recognize copyright laws, the author or authors of this
5041 software dedicate any and all copyright interest in the software to the public
5042 domain. We make this dedication for the benefit of the public at large and to
5043 the detriment of our heirs and successors. We intend this dedication to be an
5044 overt act of relinquishment in perpetuity of all present and future rights to
5045 this software under copyright law.
5046 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
5047 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
5048 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
5049 AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
5050 ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
5051 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
5052 ------------------------------------------------------------------------------
5053 */