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