The OpenD Programming Language

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