egra: post rebuild event on minimisation (because minimised windows won't do it)
[iv.d.git] / stb / ttf.d
blob9e8f5fd0d37482aa2ee8cb41cb5852620f0ce3d8
1 // stb_truetype.h - v1.19 - public domain
2 // authored from 2009-2016 by Sean Barrett / RAD Game Tools
3 //
4 // This library processes TrueType files:
5 // parse files
6 // extract glyph metrics
7 // extract glyph shapes
8 // render glyphs to one-channel bitmaps with antialiasing (box filter)
9 // render glyphs to one-channel SDF bitmaps (signed-distance field/function)
11 // Todo:
12 // non-MS cmaps
13 // crashproof on bad data
14 // hinting? (no longer patented)
15 // cleartype-style AA?
16 // optimize: use simple memory allocator for intermediates
17 // optimize: build edge-list directly from curves
18 // optimize: rasterize directly from curves?
20 // ADDITIONAL CONTRIBUTORS
22 // Mikko Mononen: compound shape support, more cmap formats
23 // Tor Andersson: kerning, subpixel rendering
24 // Dougall Johnson: OpenType / Type 2 font handling
25 // Daniel Ribeiro Maciel: basic GPOS-based kerning
27 // Misc other:
28 // Ryan Gordon
29 // Simon Glass
30 // github:IntellectualKitty
31 // Imanol Celaya
32 // Daniel Ribeiro Maciel
34 // Bug/warning reports/fixes:
35 // "Zer" on mollyrocket Fabian "ryg" Giesen
36 // Cass Everitt Martins Mozeiko
37 // stoiko (Haemimont Games) Cap Petschulat
38 // Brian Hook Omar Cornut
39 // Walter van Niftrik github:aloucks
40 // David Gow Peter LaValle
41 // David Given Sergey Popov
42 // Ivan-Assen Ivanov Giumo X. Clanjor
43 // Anthony Pesch Higor Euripedes
44 // Johan Duparc Thomas Fields
45 // Hou Qiming Derek Vinyard
46 // Rob Loach Cort Stratton
47 // Kenney Phillis Jr. github:oyvindjam
48 // Brian Costabile github:vassvik
50 // VERSION HISTORY
52 // 1.19 (2018-02-11) GPOS kerning, STBTT_fmod
53 // 1.18 (2018-01-29) add missing function
54 // 1.17 (2017-07-23) make more arguments const; doc fix
55 // 1.16 (2017-07-12) SDF support
56 // 1.15 (2017-03-03) make more arguments const
57 // 1.14 (2017-01-16) num-fonts-in-TTC function
58 // 1.13 (2017-01-02) support OpenType fonts, certain Apple fonts
59 // 1.12 (2016-10-25) suppress warnings about casting away const with -Wcast-qual
60 // 1.11 (2016-04-02) fix unused-variable warning
61 // 1.10 (2016-04-02) user-defined fabs(); rare memory leak; remove duplicate typedef
62 // 1.09 (2016-01-16) warning fix; avoid crash on outofmem; use allocation userdata properly
63 // 1.08 (2015-09-13) document stbtt_Rasterize(); fixes for vertical & horizontal edges
64 // 1.07 (2015-08-01) allow PackFontRanges to accept arrays of sparse codepoints;
65 // variant PackFontRanges to pack and render in separate phases;
66 // fix stbtt_GetFontOFfsetForIndex (never worked for non-0 input?);
67 // fixed an assert() bug in the new rasterizer
68 // replace assert() with STBTT_assert() in new rasterizer
70 // Full history can be found at the end of this file.
72 // LICENSE
74 // See end of file for license information.
76 // USAGE
78 // Include this file in whatever places neeed to refer to it. In ONE C/C++
79 // file, write:
80 // #define STB_TRUETYPE_IMPLEMENTATION
81 // before the #include of this file. This expands out the actual
82 // implementation into that C/C++ file.
84 // To make the implementation private to the file that generates the implementation,
85 // #define STBTT_STATIC
87 // Simple 3D API (don't ship this, but it's fine for tools and quick start)
88 // stbtt_BakeFontBitmap() -- bake a font to a bitmap for use as texture
89 // stbtt_GetBakedQuad() -- compute quad to draw for a given char
91 // Improved 3D API (more shippable):
92 // #include "stb_rect_pack.h" -- optional, but you really want it
93 // stbtt_PackBegin()
94 // stbtt_PackSetOversampling() -- for improved quality on small fonts
95 // stbtt_PackFontRanges() -- pack and renders
96 // stbtt_PackEnd()
97 // stbtt_GetPackedQuad()
99 // "Load" a font file from a memory buffer (you have to keep the buffer loaded)
100 // stbtt_InitFont()
101 // stbtt_GetFontOffsetForIndex() -- indexing for TTC font collections
102 // stbtt_GetNumberOfFonts() -- number of fonts for TTC font collections
104 // Render a unicode codepoint to a bitmap
105 // stbtt_GetCodepointBitmap() -- allocates and returns a bitmap
106 // stbtt_MakeCodepointBitmap() -- renders into bitmap you provide
107 // stbtt_GetCodepointBitmapBox() -- how big the bitmap must be
109 // Character advance/positioning
110 // stbtt_GetCodepointHMetrics()
111 // stbtt_GetFontVMetrics()
112 // stbtt_GetFontVMetricsOS2()
113 // stbtt_GetCodepointKernAdvance()
115 // Starting with version 1.06, the rasterizer was replaced with a new,
116 // faster and generally-more-precise rasterizer. The new rasterizer more
117 // accurately measures pixel coverage for anti-aliasing, except in the case
118 // where multiple shapes overlap, in which case it overestimates the AA pixel
119 // coverage. Thus, anti-aliasing of intersecting shapes may look wrong. If
120 // this turns out to be a problem, you can re-enable the old rasterizer with
121 // #define STBTT_RASTERIZER_VERSION 1
122 // which will incur about a 15% speed hit.
124 // ADDITIONAL DOCUMENTATION
126 // Immediately after this block comment are a series of sample programs.
128 // After the sample programs is the "header file" section. This section
129 // includes documentation for each API function.
131 // Some important concepts to understand to use this library:
133 // Codepoint
134 // Characters are defined by unicode codepoints, e.g. 65 is
135 // uppercase A, 231 is lowercase c with a cedilla, 0x7e30 is
136 // the hiragana for "ma".
138 // Glyph
139 // A visual character shape (every codepoint is rendered as
140 // some glyph)
142 // Glyph index
143 // A font-specific integer ID representing a glyph
145 // Baseline
146 // Glyph shapes are defined relative to a baseline, which is the
147 // bottom of uppercase characters. Characters extend both above
148 // and below the baseline.
150 // Current Point
151 // As you draw text to the screen, you keep track of a "current point"
152 // which is the origin of each character. The current point's vertical
153 // position is the baseline. Even "baked fonts" use this model.
155 // Vertical Font Metrics
156 // The vertical qualities of the font, used to vertically position
157 // and space the characters. See docs for stbtt_GetFontVMetrics.
159 // Font Size in Pixels or Points
160 // The preferred interface for specifying font sizes in stb_truetype
161 // is to specify how tall the font's vertical extent should be in pixels.
162 // If that sounds good enough, skip the next paragraph.
164 // Most font APIs instead use "points", which are a common typographic
165 // measurement for describing font size, defined as 72 points per inch.
166 // stb_truetype provides a point API for compatibility. However, true
167 // "per inch" conventions don't make much sense on computer displays
168 // since different monitors have different number of pixels per
169 // inch. For example, Windows traditionally uses a convention that
170 // there are 96 pixels per inch, thus making 'inch' measurements have
171 // nothing to do with inches, and thus effectively defining a point to
172 // be 1.333 pixels. Additionally, the TrueType font data provides
173 // an explicit scale factor to scale a given font's glyphs to points,
174 // but the author has observed that this scale factor is often wrong
175 // for non-commercial fonts, thus making fonts scaled in points
176 // according to the TrueType spec incoherently sized in practice.
178 // DETAILED USAGE:
180 // Scale:
181 // Select how high you want the font to be, in points or pixels.
182 // Call ScaleForPixelHeight or ScaleForMappingEmToPixels to compute
183 // a scale factor SF that will be used by all other functions.
185 // Baseline:
186 // You need to select a y-coordinate that is the baseline of where
187 // your text will appear. Call GetFontBoundingBox to get the baseline-relative
188 // bounding box for all characters. SF*-y0 will be the distance in pixels
189 // that the worst-case character could extend above the baseline, so if
190 // you want the top edge of characters to appear at the top of the
191 // screen where y=0, then you would set the baseline to SF*-y0.
193 // Current point:
194 // Set the current point where the first character will appear. The
195 // first character could extend left of the current point; this is font
196 // dependent. You can either choose a current point that is the leftmost
197 // point and hope, or add some padding, or check the bounding box or
198 // left-side-bearing of the first character to be displayed and set
199 // the current point based on that.
201 // Displaying a character:
202 // Compute the bounding box of the character. It will contain signed values
203 // relative to <current_point, baseline>. I.e. if it returns x0,y0,x1,y1,
204 // then the character should be displayed in the rectangle from
205 // <current_point+SF*x0, baseline+SF*y0> to <current_point+SF*x1,baseline+SF*y1).
207 // Advancing for the next character:
208 // Call GlyphHMetrics, and compute 'current_point += SF * advance'.
211 // ADVANCED USAGE
213 // Quality:
215 // - Use the functions with Subpixel at the end to allow your characters
216 // to have subpixel positioning. Since the font is anti-aliased, not
217 // hinted, this is very import for quality. (This is not possible with
218 // baked fonts.)
220 // - Kerning is now supported, and if you're supporting subpixel rendering
221 // then kerning is worth using to give your text a polished look.
223 // Performance:
225 // - Convert Unicode codepoints to glyph indexes and operate on the glyphs;
226 // if you don't do this, stb_truetype is forced to do the conversion on
227 // every call.
229 // - There are a lot of memory allocations. We should modify it to take
230 // a temp buffer and allocate from the temp buffer (without freeing),
231 // should help performance a lot.
233 // NOTES
235 // The system uses the raw data found in the .ttf file without changing it
236 // and without building auxiliary data structures. This is a bit inefficient
237 // on little-endian systems (the data is big-endian), but assuming you're
238 // caching the bitmaps or glyph shapes this shouldn't be a big deal.
240 // It appears to be very hard to programmatically determine what font a
241 // given file is in a general way. I provide an API for this, but I don't
242 // recommend it.
245 // SOURCE STATISTICS (based on v0.6c, 2050 LOC)
247 // Documentation & header file 520 LOC \___ 660 LOC documentation
248 // Sample code 140 LOC /
249 // Truetype parsing 620 LOC ---- 620 LOC TrueType
250 // Software rasterization 240 LOC \ .
251 // Curve tesselation 120 LOC \__ 550 LOC Bitmap creation
252 // Bitmap management 100 LOC /
253 // Baked bitmap interface 70 LOC /
254 // Font name matching & access 150 LOC ---- 150
255 // C runtime library abstraction 60 LOC ---- 60
258 // PERFORMANCE MEASUREMENTS FOR 1.06:
260 // 32-bit 64-bit
261 // Previous release: 8.83 s 7.68 s
262 // Pool allocations: 7.72 s 6.34 s
263 // Inline sort : 6.54 s 5.65 s
264 // New rasterizer : 5.63 s 5.00 s
265 module iv.stb.ttf;
266 import iv.alice;
267 nothrow @trusted @nogc:
269 version = STB_RECT_PACK_VERSION;
271 // ////////////////////////////////////////////////////////////////////////////
272 // ////////////////////////////////////////////////////////////////////////////
273 // //
274 // // SAMPLE PROGRAMS
275 // //
277 // Incomplete text-in-3d-api example, which draws quads properly aligned to be lossless
280 #if 0
281 #define STB_TRUETYPE_IMPLEMENTATION // force following include to generate implementation
282 #include "stb_truetype.h"
284 unsigned char ttf_buffer[1<<20];
285 unsigned char temp_bitmap[512*512];
287 stbtt_bakedchar cdata[96]; // ASCII 32..126 is 95 glyphs
288 GLuint ftex;
290 void my_stbtt_initfont(void)
292 fread(ttf_buffer, 1, 1<<20, fopen("c:/windows/fonts/times.ttf", "rb"));
293 stbtt_BakeFontBitmap(ttf_buffer,0, 32.0, temp_bitmap,512,512, 32,96, cdata); // no guarantee this fits!
294 // can free ttf_buffer at this point
295 glGenTextures(1, &ftex);
296 glBindTexture(GL_TEXTURE_2D, ftex);
297 glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, 512,512, 0, GL_ALPHA, GL_UNSIGNED_BYTE, temp_bitmap);
298 // can free temp_bitmap at this point
299 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
302 void my_stbtt_print(float x, float y, char *text)
304 // assume orthographic projection with units = screen pixels, origin at top left
305 glEnable(GL_TEXTURE_2D);
306 glBindTexture(GL_TEXTURE_2D, ftex);
307 glBegin(GL_QUADS);
308 while (*text) {
309 if (*text >= 32 && *text < 128) {
310 stbtt_aligned_quad q;
311 stbtt_GetBakedQuad(cdata, 512,512, *text-32, &x,&y,&q,1);//1=opengl & d3d10+,0=d3d9
312 glTexCoord2f(q.s0,q.t1); glVertex2f(q.x0,q.y0);
313 glTexCoord2f(q.s1,q.t1); glVertex2f(q.x1,q.y0);
314 glTexCoord2f(q.s1,q.t0); glVertex2f(q.x1,q.y1);
315 glTexCoord2f(q.s0,q.t0); glVertex2f(q.x0,q.y1);
317 ++text;
319 glEnd();
321 #endif
324 // ////////////////////////////////////////////////////////////////////////////
326 // Complete program (this compiles): get a single bitmap, print as ASCII art
328 #if 0
329 #include <stdio.h>
330 #define STB_TRUETYPE_IMPLEMENTATION // force following include to generate implementation
331 #include "stb_truetype.h"
333 char ttf_buffer[1<<25];
335 int main(int argc, char **argv)
337 stbtt_fontinfo font;
338 unsigned char *bitmap;
339 int w,h,i,j,c = (argc > 1 ? atoi(argv[1]) : 'a'), s = (argc > 2 ? atoi(argv[2]) : 20);
341 fread(ttf_buffer, 1, 1<<25, fopen(argc > 3 ? argv[3] : "c:/windows/fonts/arialbd.ttf", "rb"));
343 stbtt_InitFont(&font, ttf_buffer, stbtt_GetFontOffsetForIndex(ttf_buffer,0));
344 bitmap = stbtt_GetCodepointBitmap(&font, 0,stbtt_ScaleForPixelHeight(&font, s), c, &w, &h, 0,0);
346 for (j=0; j < h; ++j) {
347 for (i=0; i < w; ++i)
348 putchar(" .:ioVM@"[bitmap[j*w+i]>>5]);
349 putchar('\n');
351 return 0;
353 #endif
355 // Output:
357 // .ii.
358 // @@@@@@.
359 // V@Mio@@o
360 // :i. V@V
361 // :oM@@M
362 // :@@@MM@M
363 // @@o o@M
364 // :@@. M@M
365 // @@@o@@@@
366 // :M@@V:@@.
368 //////////////////////////////////////////////////////////////////////////////
370 // Complete program: print "Hello World!" banner, with bugs
372 #if 0
373 char buffer[24<<20];
374 unsigned char screen[20][79];
376 int main(int arg, char **argv)
378 stbtt_fontinfo font;
379 int i,j,ascent,baseline,ch=0;
380 float scale, xpos=2; // leave a little padding in case the character extends left
381 char *text = "Heljo World!"; // intentionally misspelled to show 'lj' brokenness
383 fread(buffer, 1, 1000000, fopen("c:/windows/fonts/arialbd.ttf", "rb"));
384 stbtt_InitFont(&font, buffer, 0);
386 scale = stbtt_ScaleForPixelHeight(&font, 15);
387 stbtt_GetFontVMetrics(&font, &ascent,0,0);
388 baseline = (int) (ascent*scale);
390 while (text[ch]) {
391 int advance,lsb,x0,y0,x1,y1;
392 float x_shift = xpos - (float) floor(xpos);
393 stbtt_GetCodepointHMetrics(&font, text[ch], &advance, &lsb);
394 stbtt_GetCodepointBitmapBoxSubpixel(&font, text[ch], scale,scale,x_shift,0, &x0,&y0,&x1,&y1);
395 stbtt_MakeCodepointBitmapSubpixel(&font, &screen[baseline + y0][(int) xpos + x0], x1-x0,y1-y0, 79, scale,scale,x_shift,0, text[ch]);
396 // note that this stomps the old data, so where character boxes overlap (e.g. 'lj') it's wrong
397 // because this API is really for baking character bitmaps into textures. if you want to render
398 // a sequence of characters, you really need to render each bitmap to a temp buffer, then
399 // "alpha blend" that into the working buffer
400 xpos += (advance * scale);
401 if (text[ch+1])
402 xpos += scale*stbtt_GetCodepointKernAdvance(&font, text[ch],text[ch+1]);
403 ++ch;
406 for (j=0; j < 20; ++j) {
407 for (i=0; i < 78; ++i)
408 putchar(" .:ioVM@"[screen[j][i]>>5]);
409 putchar('\n');
412 return 0;
414 #endif
417 // ////////////////////////////////////////////////////////////////////////////
418 // ////////////////////////////////////////////////////////////////////////////
419 // //
420 // // INTEGRATION WITH YOUR CODEBASE
421 // //
422 // // The following sections allow you to supply alternate definitions
423 // // of C library functions used by stb_truetype, e.g. if you don't
424 // // link with the C runtime library.
426 // #define your own (u)stbtt_int8/16/32 before including to override this
427 alias stbtt_uint8 = ubyte;
428 alias stbtt_int8 = byte;
429 alias stbtt_uint16 = ushort;
430 alias stbtt_int16 = short;
431 alias stbtt_uint32 = uint;
432 alias stbtt_int32 = int;
434 //typedef char stbtt__check_size32[sizeof(stbtt_int32)==4 ? 1 : -1];
435 //typedef char stbtt__check_size16[sizeof(stbtt_int16)==2 ? 1 : -1];
437 int STBTT_ifloor(T) (in T x) pure { pragma(inline, true); import std.math : floor; return cast(int)floor(x); }
438 int STBTT_iceil(T) (in T x) pure { pragma(inline, true); import std.math : ceil; return cast(int)ceil(x); }
440 T STBTT_sqrt(T) (in T x) pure { pragma(inline, true); import std.math : sqrt; return sqrt(x); }
441 T STBTT_pow(T) (in T x, in T y) pure { pragma(inline, true); import std.math : pow; return pow(x, y); }
443 T STBTT_fmod(T) (in T x, in T y) { pragma(inline, true); import std.math : fmod; return fmod(x, y); }
445 T STBTT_cos(T) (in T x) pure { pragma(inline, true); import std.math : cos; return cos(x); }
446 T STBTT_acos(T) (in T x) pure { pragma(inline, true); import std.math : acos; return acos(x); }
448 T STBTT_fabs(T) (in T x) pure { pragma(inline, true); import std.math : abs; return abs(x); }
450 // #define your own functions "STBTT_malloc" / "STBTT_free" to avoid malloc.h
451 void* STBTT_malloc (uint size, const(void)* uptr) { pragma(inline, true); import core.stdc.stdlib : malloc; return malloc(size); }
452 void STBTT_free (void *ptr, const(void)* uptr) { pragma(inline, true); import core.stdc.stdlib : free; free(ptr); }
454 #ifndef STBTT_malloc
455 #include <stdlib.h>
456 #define STBTT_malloc(x,u) ((void)(u),malloc(x))
457 #define STBTT_free(x,u) ((void)(u),free(x))
458 #endif
461 //alias STBTT_assert = assert;
463 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); }
464 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); }
465 void STBTT_memset (void* d, uint v, uint count) { pragma(inline, true); import core.stdc.string : memset; if (count > 0) memset(d, v, count); }
468 // /////////////////////////////////////////////////////////////////////////////
469 // /////////////////////////////////////////////////////////////////////////////
470 // //
471 // // INTERFACE
472 // //
473 // //
475 // private structure
476 struct stbtt__buf {
477 ubyte *data;
478 int cursor;
479 int size;
482 //////////////////////////////////////////////////////////////////////////////
484 // TEXTURE BAKING API
486 // If you use this API, you only have to call two functions ever.
489 struct stbtt_bakedchar {
490 ushort x0,y0,x1,y1; // coordinates of bbox in bitmap
491 float xoff,yoff,xadvance;
495 STBTT_DEF int stbtt_BakeFontBitmap(const(ubyte)* data, int offset, // font location (use offset=0 for plain .ttf)
496 float pixel_height, // height of font in pixels
497 ubyte *pixels, int pw, int ph, // bitmap to be filled in
498 int first_char, int num_chars, // characters to bake
499 stbtt_bakedchar *chardata); // you allocate this, it's num_chars long
501 // if return is positive, the first unused row of the bitmap
502 // if return is negative, returns the negative of the number of characters that fit
503 // if return is 0, no characters fit and no rows were used
504 // This uses a very crappy packing.
506 struct stbtt_aligned_quad {
507 float x0,y0,s0,t0; // top-left
508 float x1,y1,s1,t1; // bottom-right
512 STBTT_DEF void stbtt_GetBakedQuad(const(stbtt_bakedchar)* chardata, int pw, int ph, // same data as above
513 int char_index, // character to display
514 float *xpos, float *ypos, // pointers to current position in screen pixel space
515 stbtt_aligned_quad *q, // output: quad to draw
516 int opengl_fillrule); // true if opengl fill rule; false if DX9 or earlier
518 // Call GetBakedQuad with char_index = 'character - first_char', and it
519 // creates the quad you need to draw and advances the current position.
521 // The coordinate system used assumes y increases downwards.
523 // Characters will extend both above and below the current position;
524 // see discussion of "BASELINE" above.
526 // It's inefficient; you might want to c&p it and optimize it.
530 // ////////////////////////////////////////////////////////////////////////////
532 // NEW TEXTURE BAKING API
534 // This provides options for packing multiple fonts into one atlas, not
535 // perfectly but better than nothing.
537 struct stbtt_packedchar {
538 ushort x0,y0,x1,y1; // coordinates of bbox in bitmap
539 float xoff,yoff,xadvance;
540 float xoff2,yoff2;
543 //typedef struct stbtt_pack_context stbtt_pack_context;
544 //typedef struct stbtt_fontinfo stbtt_fontinfo;
545 //#ifndef STB_RECT_PACK_VERSION
546 //typedef struct stbrp_rect stbrp_rect;
547 //#endif
549 //STBTT_DEF int stbtt_PackBegin(stbtt_pack_context *spc, ubyte *pixels, int width, int height, int stride_in_bytes, int padding, void *alloc_context);
550 // Initializes a packing context stored in the passed-in stbtt_pack_context.
551 // Future calls using this context will pack characters into the bitmap passed
552 // in here: a 1-channel bitmap that is width * height. stride_in_bytes is
553 // the distance from one row to the next (or 0 to mean they are packed tightly
554 // together). "padding" is the amount of padding to leave between each
555 // character (normally you want '1' for bitmaps you'll use as textures with
556 // bilinear filtering).
558 // Returns 0 on failure, 1 on success.
560 //STBTT_DEF void stbtt_PackEnd (stbtt_pack_context *spc);
561 // Cleans up the packing context and frees all memory.
563 //#define STBTT_POINT_SIZE(x) (-(x))
566 STBTT_DEF int stbtt_PackFontRange(stbtt_pack_context *spc, const(ubyte)* fontdata, int font_index, float font_size,
567 int first_unicode_char_in_range, int num_chars_in_range, stbtt_packedchar *chardata_for_range);
569 // Creates character bitmaps from the font_index'th font found in fontdata (use
570 // font_index=0 if you don't know what that is). It creates num_chars_in_range
571 // bitmaps for characters with unicode values starting at first_unicode_char_in_range
572 // and increasing. Data for how to render them is stored in chardata_for_range;
573 // pass these to stbtt_GetPackedQuad to get back renderable quads.
575 // font_size is the full height of the character from ascender to descender,
576 // as computed by stbtt_ScaleForPixelHeight. To use a point size as computed
577 // by stbtt_ScaleForMappingEmToPixels, wrap the point size in STBTT_POINT_SIZE()
578 // and pass that result as 'font_size':
579 // ..., 20 , ... // font max minus min y is 20 pixels tall
580 // ..., STBTT_POINT_SIZE(20), ... // 'M' is 20 pixels tall
582 struct stbtt_pack_range {
583 float font_size;
584 int first_unicode_codepoint_in_range; // if non-zero, then the chars are continuous, and this is the first codepoint
585 int *array_of_unicode_codepoints; // if non-zero, then this is an array of unicode codepoints
586 int num_chars;
587 stbtt_packedchar *chardata_for_range; // output
588 ubyte h_oversample, v_oversample; // don't set these, they're used internally
591 //STBTT_DEF int stbtt_PackFontRanges(stbtt_pack_context *spc, const(ubyte)* fontdata, int font_index, stbtt_pack_range *ranges, int num_ranges);
592 // Creates character bitmaps from multiple ranges of characters stored in
593 // ranges. This will usually create a better-packed bitmap than multiple
594 // calls to stbtt_PackFontRange. Note that you can call this multiple
595 // times within a single PackBegin/PackEnd.
597 //STBTT_DEF void stbtt_PackSetOversampling(stbtt_pack_context *spc, unsigned int h_oversample, unsigned int v_oversample);
598 // Oversampling a font increases the quality by allowing higher-quality subpixel
599 // positioning, and is especially valuable at smaller text sizes.
601 // This function sets the amount of oversampling for all following calls to
602 // stbtt_PackFontRange(s) or stbtt_PackFontRangesGatherRects for a given
603 // pack context. The default (no oversampling) is achieved by h_oversample=1
604 // and v_oversample=1. The total number of pixels required is
605 // h_oversample*v_oversample larger than the default; for example, 2x2
606 // oversampling requires 4x the storage of 1x1. For best results, render
607 // oversampled textures with bilinear filtering. Look at the readme in
608 // stb/tests/oversample for information about oversampled fonts
610 // To use with PackFontRangesGather etc., you must set it before calls
611 // call to PackFontRangesGatherRects.
614 STBTT_DEF void stbtt_GetPackedQuad(const(stbtt_packedchar)* chardata, int pw, int ph, // same data as above
615 int char_index, // character to display
616 float *xpos, float *ypos, // pointers to current position in screen pixel space
617 stbtt_aligned_quad *q, // output: quad to draw
618 int align_to_integer);
620 STBTT_DEF int stbtt_PackFontRangesGatherRects(stbtt_pack_context *spc, const(stbtt_fontinfo)* info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects);
621 STBTT_DEF void stbtt_PackFontRangesPackRects(stbtt_pack_context *spc, stbrp_rect *rects, int num_rects);
622 STBTT_DEF int stbtt_PackFontRangesRenderIntoRects(stbtt_pack_context *spc, const(stbtt_fontinfo)* info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects);
624 // Calling these functions in sequence is roughly equivalent to calling
625 // stbtt_PackFontRanges(). If you more control over the packing of multiple
626 // fonts, or if you want to pack custom data into a font texture, take a look
627 // at the source to of stbtt_PackFontRanges() and create a custom version
628 // using these functions, e.g. call GatherRects multiple times,
629 // building up a single array of rects, then call PackRects once,
630 // then call RenderIntoRects repeatedly. This may result in a
631 // better packing than calling PackFontRanges multiple times
632 // (or it may not).
634 // this is an opaque structure that you shouldn't mess with which holds
635 // all the context needed from PackBegin to PackEnd.
636 struct stbtt_pack_context {
637 void *user_allocator_context;
638 void *pack_info;
639 int width;
640 int height;
641 int stride_in_bytes;
642 int padding;
643 uint h_oversample, v_oversample;
644 ubyte *pixels;
645 void *nodes;
648 // ////////////////////////////////////////////////////////////////////////////
650 // FONT LOADING
654 //STBTT_DEF int stbtt_GetNumberOfFonts(const(ubyte)* data);
655 // This function will determine the number of fonts in a font file. TrueType
656 // collection (.ttc) files may contain multiple fonts, while TrueType font
657 // (.ttf) files only contain one font. The number of fonts can be used for
658 // indexing with the previous function where the index is between zero and one
659 // less than the total fonts. If an error occurs, -1 is returned.
661 //STBTT_DEF int stbtt_GetFontOffsetForIndex(const(ubyte)* data, int index);
662 // Each .ttf/.ttc file may have more than one font. Each font has a sequential
663 // index number starting from 0. Call this function to get the font offset for
664 // a given index; it returns -1 if the index is out of range. A regular .ttf
665 // file will only define one font and it always be at offset 0, so it will
666 // return '0' for index 0, and -1 for all other indices.
668 // The following structure is defined publically so you can declare one on
669 // the stack or as a global or etc, but you should treat it as opaque.
670 struct stbtt_fontinfo {
671 void * userdata;
672 ubyte * data; // pointer to .ttf file
673 int fontstart; // offset of start of font
675 int numGlyphs; // number of glyphs, needed for range checking
677 int loca,head,glyf,hhea,hmtx,kern,gpos; // table locations as offset from start of .ttf
678 int index_map; // a cmap mapping for our chosen character encoding
679 int indexToLocFormat; // format needed to map from glyph index to glyph
681 stbtt__buf cff; // cff font data
682 stbtt__buf charstrings; // the charstring index
683 stbtt__buf gsubrs; // global charstring subroutines index
684 stbtt__buf subrs; // private charstring subroutines index
685 stbtt__buf fontdicts; // array of font dicts
686 stbtt__buf fdselect; // map from glyph to fontdict
689 //STBTT_DEF int stbtt_InitFont(stbtt_fontinfo *info, const(ubyte)* data, int offset);
690 // Given an offset into the file that defines a font, this function builds
691 // the necessary cached info for the rest of the system. You must allocate
692 // the stbtt_fontinfo yourself, and stbtt_InitFont will fill it out. You don't
693 // need to do anything special to free it, because the contents are pure
694 // value data with no additional data structures. Returns 0 on failure.
697 // ////////////////////////////////////////////////////////////////////////////
699 // CHARACTER TO GLYPH-INDEX CONVERSIOn
701 //STBTT_DEF int stbtt_FindGlyphIndex(const(stbtt_fontinfo)* info, int unicode_codepoint);
702 // If you're going to perform multiple operations on the same character
703 // and you want a speed-up, call this function with the character you're
704 // going to process, then use glyph-based functions instead of the
705 // codepoint-based functions.
708 // ////////////////////////////////////////////////////////////////////////////
710 // CHARACTER PROPERTIES
713 //STBTT_DEF float stbtt_ScaleForPixelHeight(const(stbtt_fontinfo)* info, float pixels);
714 // computes a scale factor to produce a font whose "height" is 'pixels' tall.
715 // Height is measured as the distance from the highest ascender to the lowest
716 // descender; in other words, it's equivalent to calling stbtt_GetFontVMetrics
717 // and computing:
718 // scale = pixels / (ascent - descent)
719 // so if you prefer to measure height by the ascent only, use a similar calculation.
721 //STBTT_DEF float stbtt_ScaleForMappingEmToPixels(const(stbtt_fontinfo)* info, float pixels);
722 // computes a scale factor to produce a font whose EM size is mapped to
723 // 'pixels' tall. This is probably what traditional APIs compute, but
724 // I'm not positive.
726 //STBTT_DEF void stbtt_GetFontVMetrics(const(stbtt_fontinfo)* info, int *ascent, int *descent, int *lineGap);
727 // ascent is the coordinate above the baseline the font extends; descent
728 // is the coordinate below the baseline the font extends (i.e. it is typically negative)
729 // lineGap is the spacing between one row's descent and the next row's ascent...
730 // so you should advance the vertical position by "*ascent - *descent + *lineGap"
731 // these are expressed in unscaled coordinates, so you must multiply by
732 // the scale factor for a given size
734 //STBTT_DEF int stbtt_GetFontVMetricsOS2(const(stbtt_fontinfo)* info, int *typoAscent, int *typoDescent, int *typoLineGap);
735 // analogous to GetFontVMetrics, but returns the "typographic" values from the OS/2
736 // table (specific to MS/Windows TTF files).
738 // Returns 1 on success (table present), 0 on failure.
740 //STBTT_DEF void stbtt_GetFontBoundingBox(const(stbtt_fontinfo)* info, int *x0, int *y0, int *x1, int *y1);
741 // the bounding box around all possible characters
743 //STBTT_DEF void stbtt_GetCodepointHMetrics(const(stbtt_fontinfo)* info, int codepoint, int *advanceWidth, int *leftSideBearing);
744 // leftSideBearing is the offset from the current horizontal position to the left edge of the character
745 // advanceWidth is the offset from the current horizontal position to the next horizontal position
746 // these are expressed in unscaled coordinates
748 //STBTT_DEF int stbtt_GetCodepointKernAdvance(const(stbtt_fontinfo)* info, int ch1, int ch2);
749 // an additional amount to add to the 'advance' value between ch1 and ch2
751 //STBTT_DEF int stbtt_GetCodepointBox(const(stbtt_fontinfo)* info, int codepoint, int *x0, int *y0, int *x1, int *y1);
752 // Gets the bounding box of the visible part of the glyph, in unscaled coordinates
754 //STBTT_DEF void stbtt_GetGlyphHMetrics(const(stbtt_fontinfo)* info, int glyph_index, int *advanceWidth, int *leftSideBearing);
755 //STBTT_DEF int stbtt_GetGlyphKernAdvance(const(stbtt_fontinfo)* info, int glyph1, int glyph2);
756 //STBTT_DEF int stbtt_GetGlyphBox(const(stbtt_fontinfo)* info, int glyph_index, int *x0, int *y0, int *x1, int *y1);
757 // as above, but takes one or more glyph indices for greater efficiency
760 //////////////////////////////////////////////////////////////////////////////
762 // GLYPH SHAPES (you probably don't need these, but they have to go before
763 // the bitmaps for C declaration-order reasons)
766 //#ifndef STBTT_vmove // you can predefine these to use different values (but why?)
767 enum {
768 STBTT_vmove=1,
769 STBTT_vline,
770 STBTT_vcurve,
771 STBTT_vcubic
774 //#ifndef stbtt_vertex // you can predefine this to use different values (we share this with other code at RAD)
775 alias stbtt_vertex_type = short; // can't use stbtt_int16 because that's not visible in the header file
776 struct stbtt_vertex {
777 stbtt_vertex_type x,y,cx,cy,cx1,cy1;
778 ubyte type,padding;
780 //#endif
782 //STBTT_DEF int stbtt_IsGlyphEmpty(const(stbtt_fontinfo)* info, int glyph_index);
783 // returns non-zero if nothing is drawn for this glyph
785 //STBTT_DEF int stbtt_GetCodepointShape(const(stbtt_fontinfo)* info, int unicode_codepoint, stbtt_vertex **vertices);
786 //STBTT_DEF int stbtt_GetGlyphShape(const(stbtt_fontinfo)* info, int glyph_index, stbtt_vertex **vertices);
787 // returns # of vertices and fills *vertices with the pointer to them
788 // these are expressed in "unscaled" coordinates
790 // The shape is a series of countours. Each one starts with
791 // a STBTT_moveto, then consists of a series of mixed
792 // STBTT_lineto and STBTT_curveto segments. A lineto
793 // draws a line from previous endpoint to its x,y; a curveto
794 // draws a quadratic bezier from previous endpoint to
795 // its x,y, using cx,cy as the bezier control point.
797 //STBTT_DEF void stbtt_FreeShape(const(stbtt_fontinfo)* info, stbtt_vertex *vertices);
798 // frees the data allocated above
800 // ////////////////////////////////////////////////////////////////////////////
802 // BITMAP RENDERING
805 //STBTT_DEF void stbtt_FreeBitmap(ubyte *bitmap, void *userdata);
806 // frees the bitmap allocated below
808 //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);
809 // allocates a large-enough single-channel 8bpp bitmap and renders the
810 // specified character/glyph at the specified scale into it, with
811 // antialiasing. 0 is no coverage (transparent), 255 is fully covered (opaque).
812 // *width & *height are filled out with the width & height of the bitmap,
813 // which is stored left-to-right, top-to-bottom.
815 // xoff/yoff are the offset it pixel space from the glyph origin to the top-left of the bitmap
817 //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);
818 // the same as stbtt_GetCodepoitnBitmap, but you can specify a subpixel
819 // shift for the character
821 //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);
822 // the same as stbtt_GetCodepointBitmap, but you pass in storage for the bitmap
823 // in the form of 'output', with row spacing of 'out_stride' bytes. the bitmap
824 // is clipped to out_w/out_h bytes. Call stbtt_GetCodepointBitmapBox to get the
825 // width and height and positioning info for it first.
827 //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);
828 // same as stbtt_MakeCodepointBitmap, but you can specify a subpixel
829 // shift for the character
831 //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);
832 // same as stbtt_MakeCodepointBitmapSubpixel, but prefiltering
833 // is performed (see stbtt_PackSetOversampling)
835 //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);
836 // get the bbox of the bitmap centered around the glyph origin; so the
837 // bitmap width is ix1-ix0, height is iy1-iy0, and location to place
838 // the bitmap top left is (leftSideBearing*scale,iy0).
839 // (Note that the bitmap uses y-increases-down, but the shape uses
840 // y-increases-up, so CodepointBitmapBox and CodepointBox are inverted.)
842 //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);
843 // same as stbtt_GetCodepointBitmapBox, but you can specify a subpixel
844 // shift for the character
846 // the following functions are equivalent to the above functions, but operate
847 // on glyph indices instead of Unicode codepoints (for efficiency)
848 //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);
849 //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);
850 //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);
851 //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);
852 //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);
853 //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);
854 //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);
857 // @TODO: don't expose this structure
858 struct stbtt__bitmap {
859 int w,h,stride;
860 ubyte *pixels;
863 // rasterize a shape with quadratic beziers into a bitmap
865 STBTT_DEF void stbtt_Rasterize(stbtt__bitmap *result, // 1-channel bitmap to draw into
866 float flatness_in_pixels, // allowable error of curve in pixels
867 stbtt_vertex *vertices, // array of vertices defining shape
868 int num_verts, // number of vertices in above array
869 float scale_x, float scale_y, // scale applied to input vertices
870 float shift_x, float shift_y, // translation applied to input vertices
871 int x_off, int y_off, // another translation applied to input
872 int invert, // if non-zero, vertically flip shape
873 void *userdata); // context for to STBTT_MALLOC
876 // ////////////////////////////////////////////////////////////////////////////
878 // Signed Distance Function (or Field) rendering
880 //STBTT_DEF void stbtt_FreeSDF(ubyte *bitmap, void *userdata);
881 // frees the SDF bitmap allocated below
883 //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);
884 //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);
885 // These functions compute a discretized SDF field for a single character, suitable for storing
886 // in a single-channel texture, sampling with bilinear filtering, and testing against
887 // larger than some threshhold to produce scalable fonts.
888 // info -- the font
889 // scale -- controls the size of the resulting SDF bitmap, same as it would be creating a regular bitmap
890 // glyph/codepoint -- the character to generate the SDF for
891 // padding -- extra "pixels" around the character which are filled with the distance to the character (not 0),
892 // which allows effects like bit outlines
893 // onedge_value -- value 0-255 to test the SDF against to reconstruct the character (i.e. the isocontour of the character)
894 // pixel_dist_scale -- what value the SDF should increase by when moving one SDF "pixel" away from the edge (on the 0..255 scale)
895 // if positive, > onedge_value is inside; if negative, < onedge_value is inside
896 // width,height -- output height & width of the SDF bitmap (including padding)
897 // xoff,yoff -- output origin of the character
898 // return value -- a 2D array of bytes 0..255, width*height in size
900 // pixel_dist_scale & onedge_value are a scale & bias that allows you to make
901 // optimal use of the limited 0..255 for your application, trading off precision
902 // and special effects. SDF values outside the range 0..255 are clamped to 0..255.
904 // Example:
905 // scale = stbtt_ScaleForPixelHeight(22)
906 // padding = 5
907 // onedge_value = 180
908 // pixel_dist_scale = 180/5.0 = 36.0
910 // This will create an SDF bitmap in which the character is about 22 pixels
911 // high but the whole bitmap is about 22+5+5=32 pixels high. To produce a filled
912 // shape, sample the SDF at each pixel and fill the pixel if the SDF value
913 // is greater than or equal to 180/255. (You'll actually want to antialias,
914 // which is beyond the scope of this example.) Additionally, you can compute
915 // offset outlines (e.g. to stroke the character border inside & outside,
916 // or only outside). For example, to fill outside the character up to 3 SDF
917 // pixels, you would compare against (180-36.0*3)/255 = 72/255. The above
918 // choice of variables maps a range from 5 pixels outside the shape to
919 // 2 pixels inside the shape to 0..255; this is intended primarily for apply
920 // outside effects only (the interior range is needed to allow proper
921 // antialiasing of the font at *smaller* sizes)
923 // The function computes the SDF analytically at each SDF pixel, not by e.g.
924 // building a higher-res bitmap and approximating it. In theory the quality
925 // should be as high as possible for an SDF of this size & representation, but
926 // unclear if this is true in practice (perhaps building a higher-res bitmap
927 // and computing from that can allow drop-out prevention).
929 // The algorithm has not been optimized at all, so expect it to be slow
930 // if computing lots of characters or very large sizes.
934 //////////////////////////////////////////////////////////////////////////////
936 // Finding the right font...
938 // You should really just solve this offline, keep your own tables
939 // of what font is what, and don't try to get it out of the .ttf file.
940 // That's because getting it out of the .ttf file is really hard, because
941 // the names in the file can appear in many possible encodings, in many
942 // possible languages, and e.g. if you need a case-insensitive comparison,
943 // the details of that depend on the encoding & language in a complex way
944 // (actually underspecified in truetype, but also gigantic).
946 // But you can use the provided functions in two possible ways:
947 // stbtt_FindMatchingFont() will use *case-sensitive* comparisons on
948 // unicode-encoded names to try to find the font you want;
949 // you can run this before calling stbtt_InitFont()
951 // stbtt_GetFontNameString() lets you get any of the various strings
952 // from the file yourself and do your own comparisons on them.
953 // You have to have called stbtt_InitFont() first.
956 //STBTT_DEF int stbtt_FindMatchingFont(const(ubyte)* fontdata, const(char)* name, int flags);
957 // returns the offset (not index) of the font that matches, or -1 if none
958 // if you use STBTT_MACSTYLE_DONTCARE, use a font name like "Arial Bold".
959 // if you use any other flag, use a font name like "Arial"; this checks
960 // the 'macStyle' header field; i don't know if fonts set this consistently
961 enum {
962 STBTT_MACSTYLE_DONTCARE = 0,
963 STBTT_MACSTYLE_BOLD = 1,
964 STBTT_MACSTYLE_ITALIC = 2,
965 STBTT_MACSTYLE_UNDERSCORE = 4,
966 STBTT_MACSTYLE_NONE = 8, // <= not same as 0, this makes us check the bitfield is 0
969 //STBTT_DEF int stbtt_CompareUTF8toUTF16_bigendian(const(char)* s1, int len1, const(char)* s2, int len2);
970 // returns 1/0 whether the first string interpreted as utf8 is identical to
971 // the second string interpreted as big-endian utf16... useful for strings from next func
973 //STBTT_DEF const(char)* stbtt_GetFontNameString(const(stbtt_fontinfo)* font, int *length, int platformID, int encodingID, int languageID, int nameID);
974 // returns the string (which may be big-endian double byte, e.g. for unicode)
975 // and puts the length in bytes in *length.
977 // some of the values for the IDs are below; for more see the truetype spec:
978 // http://developer.apple.com/textfonts/TTRefMan/RM06/Chap6name.html
979 // http://www.microsoft.com/typography/otspec/name.htm
981 enum { // platformID
982 STBTT_PLATFORM_ID_UNICODE =0,
983 STBTT_PLATFORM_ID_MAC =1,
984 STBTT_PLATFORM_ID_ISO =2,
985 STBTT_PLATFORM_ID_MICROSOFT =3
988 enum { // encodingID for STBTT_PLATFORM_ID_UNICODE
989 STBTT_UNICODE_EID_UNICODE_1_0 =0,
990 STBTT_UNICODE_EID_UNICODE_1_1 =1,
991 STBTT_UNICODE_EID_ISO_10646 =2,
992 STBTT_UNICODE_EID_UNICODE_2_0_BMP=3,
993 STBTT_UNICODE_EID_UNICODE_2_0_FULL=4
996 enum { // encodingID for STBTT_PLATFORM_ID_MICROSOFT
997 STBTT_MS_EID_SYMBOL =0,
998 STBTT_MS_EID_UNICODE_BMP =1,
999 STBTT_MS_EID_SHIFTJIS =2,
1000 STBTT_MS_EID_UNICODE_FULL =10
1003 enum { // encodingID for STBTT_PLATFORM_ID_MAC; same as Script Manager codes
1004 STBTT_MAC_EID_ROMAN =0, STBTT_MAC_EID_ARABIC =4,
1005 STBTT_MAC_EID_JAPANESE =1, STBTT_MAC_EID_HEBREW =5,
1006 STBTT_MAC_EID_CHINESE_TRAD =2, STBTT_MAC_EID_GREEK =6,
1007 STBTT_MAC_EID_KOREAN =3, STBTT_MAC_EID_RUSSIAN =7
1010 enum { // languageID for STBTT_PLATFORM_ID_MICROSOFT; same as LCID...
1011 // problematic because there are e.g. 16 english LCIDs and 16 arabic LCIDs
1012 STBTT_MS_LANG_ENGLISH =0x0409, STBTT_MS_LANG_ITALIAN =0x0410,
1013 STBTT_MS_LANG_CHINESE =0x0804, STBTT_MS_LANG_JAPANESE =0x0411,
1014 STBTT_MS_LANG_DUTCH =0x0413, STBTT_MS_LANG_KOREAN =0x0412,
1015 STBTT_MS_LANG_FRENCH =0x040c, STBTT_MS_LANG_RUSSIAN =0x0419,
1016 STBTT_MS_LANG_GERMAN =0x0407, STBTT_MS_LANG_SPANISH =0x0409,
1017 STBTT_MS_LANG_HEBREW =0x040d, STBTT_MS_LANG_SWEDISH =0x041D
1020 enum { // languageID for STBTT_PLATFORM_ID_MAC
1021 STBTT_MAC_LANG_ENGLISH =0 , STBTT_MAC_LANG_JAPANESE =11,
1022 STBTT_MAC_LANG_ARABIC =12, STBTT_MAC_LANG_KOREAN =23,
1023 STBTT_MAC_LANG_DUTCH =4 , STBTT_MAC_LANG_RUSSIAN =32,
1024 STBTT_MAC_LANG_FRENCH =1 , STBTT_MAC_LANG_SPANISH =6 ,
1025 STBTT_MAC_LANG_GERMAN =2 , STBTT_MAC_LANG_SWEDISH =5 ,
1026 STBTT_MAC_LANG_HEBREW =10, STBTT_MAC_LANG_CHINESE_SIMPLIFIED =33,
1027 STBTT_MAC_LANG_ITALIAN =3 , STBTT_MAC_LANG_CHINESE_TRAD =19
1031 // /////////////////////////////////////////////////////////////////////////////
1032 // /////////////////////////////////////////////////////////////////////////////
1033 // //
1034 // // IMPLEMENTATION
1035 // //
1036 // //
1037 private:
1039 enum STBTT_MAX_OVERSAMPLE = 8; // it also must be POT
1040 static assert(STBTT_MAX_OVERSAMPLE > 0 && STBTT_MAX_OVERSAMPLE <= 255, "STBTT_MAX_OVERSAMPLE cannot be > 255");
1042 //typedef int stbtt__test_oversample_pow2[(STBTT_MAX_OVERSAMPLE & (STBTT_MAX_OVERSAMPLE-1)) == 0 ? 1 : -1];
1044 enum STBTT_RASTERIZER_VERSION = 2;
1047 #ifdef _MSC_VER
1048 #define STBTT__NOTUSED(v) (void)(v)
1049 #else
1050 #define STBTT__NOTUSED(v) (void)sizeof(v)
1051 #endif
1054 // ////////////////////////////////////////////////////////////////////////
1056 // stbtt__buf helpers to parse data from file
1059 private stbtt_uint8 stbtt__buf_get8(stbtt__buf *b)
1061 if (b.cursor >= b.size)
1062 return 0;
1063 return b.data[b.cursor++];
1066 private stbtt_uint8 stbtt__buf_peek8(stbtt__buf *b)
1068 if (b.cursor >= b.size)
1069 return 0;
1070 return b.data[b.cursor];
1073 private void stbtt__buf_seek(stbtt__buf *b, int o)
1075 assert(!(o > b.size || o < 0));
1076 b.cursor = (o > b.size || o < 0) ? b.size : o;
1079 private void stbtt__buf_skip(stbtt__buf *b, int o)
1081 stbtt__buf_seek(b, b.cursor + o);
1084 private stbtt_uint32 stbtt__buf_get(stbtt__buf *b, int n)
1086 stbtt_uint32 v = 0;
1087 int i;
1088 assert(n >= 1 && n <= 4);
1089 for (i = 0; i < n; i++)
1090 v = (v << 8) | stbtt__buf_get8(b);
1091 return v;
1094 private stbtt__buf stbtt__new_buf(const(void)* p, size_t size)
1096 stbtt__buf r;
1097 assert(size < 0x40000000);
1098 r.data = cast(stbtt_uint8*) p;
1099 r.size = cast(int) size;
1100 r.cursor = 0;
1101 return r;
1104 //#define stbtt__buf_get16(b) stbtt__buf_get((b), 2)
1105 //#define stbtt__buf_get32(b) stbtt__buf_get((b), 4)
1106 ushort stbtt__buf_get16 (stbtt__buf *b) { pragma(inline, true); return cast(ushort)stbtt__buf_get(b, 2); }
1107 uint stbtt__buf_get32 (stbtt__buf *b) { pragma(inline, true); return cast(uint)stbtt__buf_get(b, 4); }
1109 private stbtt__buf stbtt__buf_range(const(stbtt__buf)* b, int o, int s)
1111 stbtt__buf r = stbtt__new_buf(null, 0);
1112 if (o < 0 || s < 0 || o > b.size || s > b.size - o) return r;
1113 r.data = cast(ubyte*)b.data + o;
1114 r.size = s;
1115 return r;
1118 private stbtt__buf stbtt__cff_get_index(stbtt__buf *b)
1120 int count, start, offsize;
1121 start = b.cursor;
1122 count = stbtt__buf_get16(b);
1123 if (count) {
1124 offsize = stbtt__buf_get8(b);
1125 assert(offsize >= 1 && offsize <= 4);
1126 stbtt__buf_skip(b, offsize * count);
1127 stbtt__buf_skip(b, stbtt__buf_get(b, offsize) - 1);
1129 return stbtt__buf_range(b, start, b.cursor - start);
1132 private stbtt_uint32 stbtt__cff_int(stbtt__buf *b)
1134 int b0 = stbtt__buf_get8(b);
1135 if (b0 >= 32 && b0 <= 246) return b0 - 139;
1136 else if (b0 >= 247 && b0 <= 250) return (b0 - 247)*256 + stbtt__buf_get8(b) + 108;
1137 else if (b0 >= 251 && b0 <= 254) return -(b0 - 251)*256 - stbtt__buf_get8(b) - 108;
1138 else if (b0 == 28) return stbtt__buf_get16(b);
1139 else if (b0 == 29) return stbtt__buf_get32(b);
1140 assert(0);
1141 return 0;
1144 private void stbtt__cff_skip_operand(stbtt__buf *b) {
1145 int v, b0 = stbtt__buf_peek8(b);
1146 assert(b0 >= 28);
1147 if (b0 == 30) {
1148 stbtt__buf_skip(b, 1);
1149 while (b.cursor < b.size) {
1150 v = stbtt__buf_get8(b);
1151 if ((v & 0xF) == 0xF || (v >> 4) == 0xF)
1152 break;
1154 } else {
1155 stbtt__cff_int(b);
1159 private stbtt__buf stbtt__dict_get(stbtt__buf *b, int key)
1161 stbtt__buf_seek(b, 0);
1162 while (b.cursor < b.size) {
1163 int start = b.cursor, end, op;
1164 while (stbtt__buf_peek8(b) >= 28)
1165 stbtt__cff_skip_operand(b);
1166 end = b.cursor;
1167 op = stbtt__buf_get8(b);
1168 if (op == 12) op = stbtt__buf_get8(b) | 0x100;
1169 if (op == key) return stbtt__buf_range(b, start, end-start);
1171 return stbtt__buf_range(b, 0, 0);
1174 private void stbtt__dict_get_ints(stbtt__buf *b, int key, int outcount, stbtt_uint32 *outstb)
1176 int i;
1177 stbtt__buf operands = stbtt__dict_get(b, key);
1178 for (i = 0; i < outcount && operands.cursor < operands.size; i++)
1179 outstb[i] = stbtt__cff_int(&operands);
1182 private int stbtt__cff_index_count(stbtt__buf *b)
1184 stbtt__buf_seek(b, 0);
1185 return stbtt__buf_get16(b);
1188 private stbtt__buf stbtt__cff_index_get(stbtt__buf b, int i)
1190 int count, offsize, start, end;
1191 stbtt__buf_seek(&b, 0);
1192 count = stbtt__buf_get16(&b);
1193 offsize = stbtt__buf_get8(&b);
1194 assert(i >= 0 && i < count);
1195 assert(offsize >= 1 && offsize <= 4);
1196 stbtt__buf_skip(&b, i*offsize);
1197 start = stbtt__buf_get(&b, offsize);
1198 end = stbtt__buf_get(&b, offsize);
1199 return stbtt__buf_range(&b, 2+(count+1)*offsize+start, end - start);
1202 //////////////////////////////////////////////////////////////////////////
1204 // accessors to parse data from file
1207 // on platforms that don't allow misaligned reads, if we want to allow
1208 // truetype fonts that aren't padded to alignment, define ALLOW_UNALIGNED_TRUETYPE
1210 //#define ttBYTE(p) (* (stbtt_uint8 *) (p))
1211 //#define ttCHAR(p) (* (stbtt_int8 *) (p))
1212 //#define ttFixed(p) ttLONG(p)
1213 stbtt_uint8 ttBYTE (const(void)* p) pure { pragma(inline, true); return *cast(const(stbtt_uint8)*)p; }
1214 stbtt_int8 ttCHAR (const(void)* p) pure { pragma(inline, true); return *cast(const(stbtt_int8)*)p; }
1216 private stbtt_uint16 ttUSHORT(const(stbtt_uint8)* p) { return p[0]*256 + p[1]; }
1217 private stbtt_int16 ttSHORT(const(stbtt_uint8)* p) { return cast(stbtt_int16)(p[0]*256 + p[1]); }
1218 private stbtt_uint32 ttULONG(const(stbtt_uint8)* p) { return (p[0]<<24) + (p[1]<<16) + (p[2]<<8) + p[3]; }
1219 private stbtt_int32 ttLONG(const(stbtt_uint8)* p) { return (p[0]<<24) + (p[1]<<16) + (p[2]<<8) + p[3]; }
1221 //#define stbtt_tag4(p,c0,c1,c2,c3) ((p)[0] == (c0) && (p)[1] == (c1) && (p)[2] == (c2) && (p)[3] == (c3))
1222 //#define stbtt_tag(p,str) stbtt_tag4(p,str[0],str[1],str[2],str[3])
1224 bool stbtt_tag4 (const(void)* p, ubyte c0, ubyte c1, ubyte c2, ubyte c3) pure {
1225 return
1226 (cast(const(ubyte)*)p)[0] == c0 &&
1227 (cast(const(ubyte)*)p)[1] == c1 &&
1228 (cast(const(ubyte)*)p)[2] == c2 &&
1229 (cast(const(ubyte)*)p)[3] == c3;
1232 bool stbtt_tag (const(void)* p, const(void)* str) {
1233 //stbtt_tag4(p,str[0],str[1],str[2],str[3])
1234 import core.stdc.string : memcmp;
1235 return (memcmp(p, str, 4) == 0);
1238 private int stbtt__isfont(stbtt_uint8 *font)
1240 // check the version number
1241 if (stbtt_tag4(font, '1',0,0,0)) return 1; // TrueType 1
1242 if (stbtt_tag(font, "typ1".ptr)) return 1; // TrueType with type 1 font -- we don't support this!
1243 if (stbtt_tag(font, "OTTO".ptr)) return 1; // OpenType with CFF
1244 if (stbtt_tag4(font, 0,1,0,0)) return 1; // OpenType 1.0
1245 if (stbtt_tag(font, "true".ptr)) return 1; // Apple specification for TrueType fonts
1246 return 0;
1249 // @OPTIMIZE: binary search
1250 private stbtt_uint32 stbtt__find_table(stbtt_uint8 *data, stbtt_uint32 fontstart, const(char)* tag)
1252 stbtt_int32 num_tables = ttUSHORT(data+fontstart+4);
1253 stbtt_uint32 tabledir = fontstart + 12;
1254 stbtt_int32 i;
1255 for (i=0; i < num_tables; ++i) {
1256 stbtt_uint32 loc = tabledir + 16*i;
1257 if (stbtt_tag(data+loc+0, tag))
1258 return ttULONG(data+loc+8);
1260 return 0;
1263 private int stbtt_GetFontOffsetForIndex_internal(ubyte *font_collection, int index)
1265 // if it's just a font, there's only one valid index
1266 if (stbtt__isfont(font_collection))
1267 return index == 0 ? 0 : -1;
1269 // check if it's a TTC
1270 if (stbtt_tag(font_collection, "ttcf".ptr)) {
1271 // version 1?
1272 if (ttULONG(font_collection+4) == 0x00010000 || ttULONG(font_collection+4) == 0x00020000) {
1273 stbtt_int32 n = ttLONG(font_collection+8);
1274 if (index >= n)
1275 return -1;
1276 return ttULONG(font_collection+12+index*4);
1279 return -1;
1282 private int stbtt_GetNumberOfFonts_internal(ubyte *font_collection)
1284 // if it's just a font, there's only one valid font
1285 if (stbtt__isfont(font_collection))
1286 return 1;
1288 // check if it's a TTC
1289 if (stbtt_tag(font_collection, "ttcf".ptr)) {
1290 // version 1?
1291 if (ttULONG(font_collection+4) == 0x00010000 || ttULONG(font_collection+4) == 0x00020000) {
1292 return ttLONG(font_collection+8);
1295 return 0;
1298 private stbtt__buf stbtt__get_subrs(stbtt__buf cff, stbtt__buf fontdict)
1300 stbtt_uint32 subrsoff = 0;
1301 stbtt_uint32[2] private_loc = 0;
1302 stbtt__buf pdict;
1303 stbtt__dict_get_ints(&fontdict, 18, 2, private_loc.ptr);
1304 if (!private_loc[1] || !private_loc[0]) return stbtt__new_buf(null, 0);
1305 pdict = stbtt__buf_range(&cff, private_loc[1], private_loc[0]);
1306 stbtt__dict_get_ints(&pdict, 19, 1, &subrsoff);
1307 if (!subrsoff) return stbtt__new_buf(null, 0);
1308 stbtt__buf_seek(&cff, private_loc[1]+subrsoff);
1309 return stbtt__cff_get_index(&cff);
1312 private int stbtt_InitFont_internal(stbtt_fontinfo *info, ubyte *data, int fontstart)
1314 stbtt_uint32 cmap, t;
1315 stbtt_int32 i,numTables;
1317 info.data = data;
1318 info.fontstart = fontstart;
1319 info.cff = stbtt__new_buf(null, 0);
1321 cmap = stbtt__find_table(data, fontstart, "cmap"); // required
1322 info.loca = stbtt__find_table(data, fontstart, "loca"); // required
1323 info.head = stbtt__find_table(data, fontstart, "head"); // required
1324 info.glyf = stbtt__find_table(data, fontstart, "glyf"); // required
1325 info.hhea = stbtt__find_table(data, fontstart, "hhea"); // required
1326 info.hmtx = stbtt__find_table(data, fontstart, "hmtx"); // required
1327 info.kern = stbtt__find_table(data, fontstart, "kern"); // not required
1328 info.gpos = stbtt__find_table(data, fontstart, "GPOS"); // not required
1330 if (!cmap || !info.head || !info.hhea || !info.hmtx)
1331 return 0;
1332 if (info.glyf) {
1333 // required for truetype
1334 if (!info.loca) return 0;
1335 } else {
1336 // initialization for CFF / Type2 fonts (OTF)
1337 stbtt__buf b, topdict, topdictidx;
1338 stbtt_uint32 cstype = 2, charstrings = 0, fdarrayoff = 0, fdselectoff = 0;
1339 stbtt_uint32 cff;
1341 cff = stbtt__find_table(data, fontstart, "CFF ");
1342 if (!cff) return 0;
1344 info.fontdicts = stbtt__new_buf(null, 0);
1345 info.fdselect = stbtt__new_buf(null, 0);
1347 // @TODO this should use size from table (not 512MB)
1348 info.cff = stbtt__new_buf(data+cff, 512*1024*1024);
1349 b = info.cff;
1351 // read the header
1352 stbtt__buf_skip(&b, 2);
1353 stbtt__buf_seek(&b, stbtt__buf_get8(&b)); // hdrsize
1355 // @TODO the name INDEX could list multiple fonts,
1356 // but we just use the first one.
1357 stbtt__cff_get_index(&b); // name INDEX
1358 topdictidx = stbtt__cff_get_index(&b);
1359 topdict = stbtt__cff_index_get(topdictidx, 0);
1360 stbtt__cff_get_index(&b); // string INDEX
1361 info.gsubrs = stbtt__cff_get_index(&b);
1363 stbtt__dict_get_ints(&topdict, 17, 1, &charstrings);
1364 stbtt__dict_get_ints(&topdict, 0x100 | 6, 1, &cstype);
1365 stbtt__dict_get_ints(&topdict, 0x100 | 36, 1, &fdarrayoff);
1366 stbtt__dict_get_ints(&topdict, 0x100 | 37, 1, &fdselectoff);
1367 info.subrs = stbtt__get_subrs(b, topdict);
1369 // we only support Type 2 charstrings
1370 if (cstype != 2) return 0;
1371 if (charstrings == 0) return 0;
1373 if (fdarrayoff) {
1374 // looks like a CID font
1375 if (!fdselectoff) return 0;
1376 stbtt__buf_seek(&b, fdarrayoff);
1377 info.fontdicts = stbtt__cff_get_index(&b);
1378 info.fdselect = stbtt__buf_range(&b, fdselectoff, b.size-fdselectoff);
1381 stbtt__buf_seek(&b, charstrings);
1382 info.charstrings = stbtt__cff_get_index(&b);
1385 t = stbtt__find_table(data, fontstart, "maxp");
1386 if (t)
1387 info.numGlyphs = ttUSHORT(data+t+4);
1388 else
1389 info.numGlyphs = 0xffff;
1391 // find a cmap encoding table we understand *now* to avoid searching
1392 // later. (todo: could make this installable)
1393 // the same regardless of glyph.
1394 numTables = ttUSHORT(data + cmap + 2);
1395 info.index_map = 0;
1396 for (i=0; i < numTables; ++i) {
1397 stbtt_uint32 encoding_record = cmap + 4 + 8 * i;
1398 // find an encoding we understand:
1399 switch(ttUSHORT(data+encoding_record)) {
1400 case STBTT_PLATFORM_ID_MICROSOFT:
1401 switch (ttUSHORT(data+encoding_record+2)) {
1402 case STBTT_MS_EID_UNICODE_BMP:
1403 case STBTT_MS_EID_UNICODE_FULL:
1404 // MS/Unicode
1405 info.index_map = cmap + ttULONG(data+encoding_record+4);
1406 break;
1407 default:
1409 break;
1410 case STBTT_PLATFORM_ID_UNICODE:
1411 // Mac/iOS has these
1412 // all the encodingIDs are unicode, so we don't bother to check it
1413 info.index_map = cmap + ttULONG(data+encoding_record+4);
1414 break;
1415 default:
1418 if (info.index_map == 0)
1419 return 0;
1421 info.indexToLocFormat = ttUSHORT(data+info.head + 50);
1422 return 1;
1425 public int stbtt_FindGlyphIndex(const(stbtt_fontinfo)* info, int unicode_codepoint)
1427 stbtt_uint8 *data = cast(stbtt_uint8*)info.data;
1428 stbtt_uint32 index_map = info.index_map;
1430 stbtt_uint16 format = ttUSHORT(data + index_map + 0);
1431 if (format == 0) { // apple byte encoding
1432 stbtt_int32 bytes = ttUSHORT(data + index_map + 2);
1433 if (unicode_codepoint < bytes-6)
1434 return ttBYTE(data + index_map + 6 + unicode_codepoint);
1435 return 0;
1436 } else if (format == 6) {
1437 stbtt_uint32 first = ttUSHORT(data + index_map + 6);
1438 stbtt_uint32 count = ttUSHORT(data + index_map + 8);
1439 if (cast(stbtt_uint32) unicode_codepoint >= first && cast(stbtt_uint32) unicode_codepoint < first+count)
1440 return ttUSHORT(data + index_map + 10 + (unicode_codepoint - first)*2);
1441 return 0;
1442 } else if (format == 2) {
1443 assert(0); // @TODO: high-byte mapping for japanese/chinese/korean
1444 return 0;
1445 } else if (format == 4) { // standard mapping for windows fonts: binary search collection of ranges
1446 stbtt_uint16 segcount = ttUSHORT(data+index_map+6) >> 1;
1447 stbtt_uint16 searchRange = ttUSHORT(data+index_map+8) >> 1;
1448 stbtt_uint16 entrySelector = ttUSHORT(data+index_map+10);
1449 stbtt_uint16 rangeShift = ttUSHORT(data+index_map+12) >> 1;
1451 // do a binary search of the segments
1452 stbtt_uint32 endCount = index_map + 14;
1453 stbtt_uint32 search = endCount;
1455 if (unicode_codepoint > 0xffff)
1456 return 0;
1458 // they lie from endCount .. endCount + segCount
1459 // but searchRange is the nearest power of two, so...
1460 if (unicode_codepoint >= ttUSHORT(data + search + rangeShift*2))
1461 search += rangeShift*2;
1463 // now decrement to bias correctly to find smallest
1464 search -= 2;
1465 while (entrySelector) {
1466 stbtt_uint16 end;
1467 searchRange >>= 1;
1468 end = ttUSHORT(data + search + searchRange*2);
1469 if (unicode_codepoint > end)
1470 search += searchRange*2;
1471 --entrySelector;
1473 search += 2;
1476 stbtt_uint16 offset, start;
1477 stbtt_uint16 item = cast(stbtt_uint16) ((search - endCount) >> 1);
1479 assert(unicode_codepoint <= ttUSHORT(data + endCount + 2*item));
1480 start = ttUSHORT(data + index_map + 14 + segcount*2 + 2 + 2*item);
1481 if (unicode_codepoint < start)
1482 return 0;
1484 offset = ttUSHORT(data + index_map + 14 + segcount*6 + 2 + 2*item);
1485 if (offset == 0)
1486 return cast(stbtt_uint16) (unicode_codepoint + ttSHORT(data + index_map + 14 + segcount*4 + 2 + 2*item));
1488 return ttUSHORT(data + offset + (unicode_codepoint-start)*2 + index_map + 14 + segcount*6 + 2 + 2*item);
1490 } else if (format == 12 || format == 13) {
1491 stbtt_uint32 ngroups = ttULONG(data+index_map+12);
1492 stbtt_int32 low,high;
1493 low = 0; high = cast(stbtt_int32)ngroups;
1494 // Binary search the right group.
1495 while (low < high) {
1496 stbtt_int32 mid = low + ((high-low) >> 1); // rounds down, so low <= mid < high
1497 stbtt_uint32 start_char = ttULONG(data+index_map+16+mid*12);
1498 stbtt_uint32 end_char = ttULONG(data+index_map+16+mid*12+4);
1499 if (cast(stbtt_uint32) unicode_codepoint < start_char)
1500 high = mid;
1501 else if (cast(stbtt_uint32) unicode_codepoint > end_char)
1502 low = mid+1;
1503 else {
1504 stbtt_uint32 start_glyph = ttULONG(data+index_map+16+mid*12+8);
1505 if (format == 12)
1506 return start_glyph + unicode_codepoint-start_char;
1507 else // format == 13
1508 return start_glyph;
1511 return 0; // not found
1513 // @TODO
1514 assert(0);
1515 return 0;
1518 public int stbtt_GetCodepointShape(stbtt_fontinfo* info, int unicode_codepoint, stbtt_vertex **vertices)
1520 return stbtt_GetGlyphShape(info, stbtt_FindGlyphIndex(info, unicode_codepoint), vertices);
1523 private void stbtt_setvertex(stbtt_vertex *v, stbtt_uint8 type, stbtt_int32 x, stbtt_int32 y, stbtt_int32 cx, stbtt_int32 cy)
1525 v.type = type;
1526 v.x = cast(stbtt_int16) x;
1527 v.y = cast(stbtt_int16) y;
1528 v.cx = cast(stbtt_int16) cx;
1529 v.cy = cast(stbtt_int16) cy;
1532 private int stbtt__GetGlyfOffset(const(stbtt_fontinfo)* info, int glyph_index)
1534 int g1,g2;
1536 assert(!info.cff.size);
1538 if (glyph_index >= info.numGlyphs) return -1; // glyph index out of range
1539 if (info.indexToLocFormat >= 2) return -1; // unknown index->glyph map format
1541 if (info.indexToLocFormat == 0) {
1542 g1 = info.glyf + ttUSHORT(info.data + info.loca + glyph_index * 2) * 2;
1543 g2 = info.glyf + ttUSHORT(info.data + info.loca + glyph_index * 2 + 2) * 2;
1544 } else {
1545 g1 = info.glyf + ttULONG (info.data + info.loca + glyph_index * 4);
1546 g2 = info.glyf + ttULONG (info.data + info.loca + glyph_index * 4 + 4);
1549 return g1==g2 ? -1 : g1; // if length is 0, return -1
1552 //private int stbtt__GetGlyphInfoT2(const(stbtt_fontinfo)* info, int glyph_index, int *x0, int *y0, int *x1, int *y1);
1554 public int stbtt_GetGlyphBox(stbtt_fontinfo* info, int glyph_index, int *x0, int *y0, int *x1, int *y1)
1556 if (info.cff.size) {
1557 stbtt__GetGlyphInfoT2(info, glyph_index, x0, y0, x1, y1);
1558 } else {
1559 int g = stbtt__GetGlyfOffset(info, glyph_index);
1560 if (g < 0) return 0;
1562 if (x0) *x0 = ttSHORT(info.data + g + 2);
1563 if (y0) *y0 = ttSHORT(info.data + g + 4);
1564 if (x1) *x1 = ttSHORT(info.data + g + 6);
1565 if (y1) *y1 = ttSHORT(info.data + g + 8);
1567 return 1;
1570 public int stbtt_GetCodepointBox(stbtt_fontinfo* info, int codepoint, int *x0, int *y0, int *x1, int *y1)
1572 return stbtt_GetGlyphBox(info, stbtt_FindGlyphIndex(info,codepoint), x0,y0,x1,y1);
1575 public int stbtt_IsGlyphEmpty(stbtt_fontinfo* info, int glyph_index)
1577 stbtt_int16 numberOfContours;
1578 int g;
1579 if (info.cff.size)
1580 return stbtt__GetGlyphInfoT2(info, glyph_index, null, null, null, null) == 0;
1581 g = stbtt__GetGlyfOffset(info, glyph_index);
1582 if (g < 0) return 1;
1583 numberOfContours = ttSHORT(info.data + g);
1584 return numberOfContours == 0;
1587 private int stbtt__close_shape(stbtt_vertex *vertices, int num_vertices, int was_off, int start_off,
1588 stbtt_int32 sx, stbtt_int32 sy, stbtt_int32 scx, stbtt_int32 scy, stbtt_int32 cx, stbtt_int32 cy)
1590 if (start_off) {
1591 if (was_off)
1592 stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, (cx+scx)>>1, (cy+scy)>>1, cx,cy);
1593 stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, sx,sy,scx,scy);
1594 } else {
1595 if (was_off)
1596 stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve,sx,sy,cx,cy);
1597 else
1598 stbtt_setvertex(&vertices[num_vertices++], STBTT_vline,sx,sy,0,0);
1600 return num_vertices;
1603 private int stbtt__GetGlyphShapeTT(stbtt_fontinfo* info, int glyph_index, stbtt_vertex **pvertices)
1605 stbtt_int16 numberOfContours;
1606 stbtt_uint8 *endPtsOfContours;
1607 stbtt_uint8 *data = cast(stbtt_uint8*)info.data;
1608 stbtt_vertex *vertices = null;
1609 int num_vertices=0;
1610 int g = stbtt__GetGlyfOffset(info, glyph_index);
1612 *pvertices = null;
1614 if (g < 0) return 0;
1616 numberOfContours = ttSHORT(data + g);
1618 if (numberOfContours > 0) {
1619 stbtt_uint8 flags=0,flagcount;
1620 stbtt_int32 ins, i,j=0,m,n, next_move, was_off=0, off, start_off=0;
1621 stbtt_int32 x,y,cx,cy,sx,sy, scx,scy;
1622 stbtt_uint8 *points;
1623 endPtsOfContours = (data + g + 10);
1624 ins = ttUSHORT(data + g + 10 + numberOfContours * 2);
1625 points = data + g + 10 + numberOfContours * 2 + 2 + ins;
1627 n = 1+ttUSHORT(endPtsOfContours + numberOfContours*2-2);
1629 m = n + 2*numberOfContours; // a loose bound on how many vertices we might need
1630 vertices = cast(stbtt_vertex *) STBTT_malloc(m * cast(uint)vertices[0].sizeof, info.userdata);
1631 if (vertices is null)
1632 return 0;
1634 next_move = 0;
1635 flagcount=0;
1637 // in first pass, we load uninterpreted data into the allocated array
1638 // above, shifted to the end of the array so we won't overwrite it when
1639 // we create our final data starting from the front
1641 off = m - n; // starting offset for uninterpreted data, regardless of how m ends up being calculated
1643 // first load flags
1645 for (i=0; i < n; ++i) {
1646 if (flagcount == 0) {
1647 flags = *points++;
1648 if (flags & 8)
1649 flagcount = *points++;
1650 } else
1651 --flagcount;
1652 vertices[off+i].type = flags;
1655 // now load x coordinates
1656 x=0;
1657 for (i=0; i < n; ++i) {
1658 flags = vertices[off+i].type;
1659 if (flags & 2) {
1660 stbtt_int16 dx = *points++;
1661 x += (flags & 16) ? cast(int)dx : -cast(int)dx; // ???
1662 } else {
1663 if (!(flags & 16)) {
1664 x = x + cast(stbtt_int16) (points[0]*256 + points[1]);
1665 points += 2;
1668 vertices[off+i].x = cast(stbtt_int16) x;
1671 // now load y coordinates
1672 y=0;
1673 for (i=0; i < n; ++i) {
1674 flags = vertices[off+i].type;
1675 if (flags & 4) {
1676 stbtt_int16 dy = *points++;
1677 y += (flags & 32) ? cast(int)dy : -cast(int)dy; // ???
1678 } else {
1679 if (!(flags & 32)) {
1680 y = y + cast(stbtt_int16) (points[0]*256 + points[1]);
1681 points += 2;
1684 vertices[off+i].y = cast(stbtt_int16) y;
1687 // now convert them to our format
1688 num_vertices=0;
1689 sx = sy = cx = cy = scx = scy = 0;
1690 for (i=0; i < n; ++i) {
1691 flags = vertices[off+i].type;
1692 x = cast(stbtt_int16) vertices[off+i].x;
1693 y = cast(stbtt_int16) vertices[off+i].y;
1695 if (next_move == i) {
1696 if (i != 0)
1697 num_vertices = stbtt__close_shape(vertices, num_vertices, was_off, start_off, sx,sy,scx,scy,cx,cy);
1699 // now start the new one
1700 start_off = !(flags & 1);
1701 if (start_off) {
1702 // if we start off with an off-curve point, then when we need to find a point on the curve
1703 // where we can start, and we need to save some state for when we wraparound.
1704 scx = x;
1705 scy = y;
1706 if (!(vertices[off+i+1].type & 1)) {
1707 // next point is also a curve point, so interpolate an on-point curve
1708 sx = (x + cast(stbtt_int32) vertices[off+i+1].x) >> 1;
1709 sy = (y + cast(stbtt_int32) vertices[off+i+1].y) >> 1;
1710 } else {
1711 // otherwise just use the next point as our start point
1712 sx = cast(stbtt_int32) vertices[off+i+1].x;
1713 sy = cast(stbtt_int32) vertices[off+i+1].y;
1714 ++i; // we're using point i+1 as the starting point, so skip it
1716 } else {
1717 sx = x;
1718 sy = y;
1720 stbtt_setvertex(&vertices[num_vertices++], STBTT_vmove,sx,sy,0,0);
1721 was_off = 0;
1722 next_move = 1 + ttUSHORT(endPtsOfContours+j*2);
1723 ++j;
1724 } else {
1725 if (!(flags & 1)) { // if it's a curve
1726 if (was_off) // two off-curve control points in a row means interpolate an on-curve midpoint
1727 stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, (cx+x)>>1, (cy+y)>>1, cx, cy);
1728 cx = x;
1729 cy = y;
1730 was_off = 1;
1731 } else {
1732 if (was_off)
1733 stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, x,y, cx, cy);
1734 else
1735 stbtt_setvertex(&vertices[num_vertices++], STBTT_vline, x,y,0,0);
1736 was_off = 0;
1740 num_vertices = stbtt__close_shape(vertices, num_vertices, was_off, start_off, sx,sy,scx,scy,cx,cy);
1741 } else if (numberOfContours == -1) {
1742 // Compound shapes.
1743 int more = 1;
1744 stbtt_uint8 *comp = data + g + 10;
1745 num_vertices = 0;
1746 vertices = null;
1747 while (more) {
1748 stbtt_uint16 flags, gidx;
1749 int comp_num_verts = 0, i;
1750 stbtt_vertex *comp_verts = null, tmp = null;
1751 float[6] mtx = [1,0,0,1,0,0];
1752 float m, n;
1754 flags = ttSHORT(comp); comp+=2;
1755 gidx = ttSHORT(comp); comp+=2;
1757 if (flags & 2) { // XY values
1758 if (flags & 1) { // shorts
1759 mtx[4] = ttSHORT(comp); comp+=2;
1760 mtx[5] = ttSHORT(comp); comp+=2;
1761 } else {
1762 mtx[4] = ttCHAR(comp); comp+=1;
1763 mtx[5] = ttCHAR(comp); comp+=1;
1766 else {
1767 // @TODO handle matching point
1768 assert(0);
1770 if (flags & (1<<3)) { // WE_HAVE_A_SCALE
1771 mtx[0] = mtx[3] = ttSHORT(comp)/16384.0f; comp+=2;
1772 mtx[1] = mtx[2] = 0;
1773 } else if (flags & (1<<6)) { // WE_HAVE_AN_X_AND_YSCALE
1774 mtx[0] = ttSHORT(comp)/16384.0f; comp+=2;
1775 mtx[1] = mtx[2] = 0;
1776 mtx[3] = ttSHORT(comp)/16384.0f; comp+=2;
1777 } else if (flags & (1<<7)) { // WE_HAVE_A_TWO_BY_TWO
1778 mtx[0] = ttSHORT(comp)/16384.0f; comp+=2;
1779 mtx[1] = ttSHORT(comp)/16384.0f; comp+=2;
1780 mtx[2] = ttSHORT(comp)/16384.0f; comp+=2;
1781 mtx[3] = ttSHORT(comp)/16384.0f; comp+=2;
1784 // Find transformation scales.
1785 m = cast(float) STBTT_sqrt(mtx[0]*mtx[0] + mtx[1]*mtx[1]);
1786 n = cast(float) STBTT_sqrt(mtx[2]*mtx[2] + mtx[3]*mtx[3]);
1788 // Get indexed glyph.
1789 comp_num_verts = stbtt_GetGlyphShape(info, gidx, &comp_verts);
1790 if (comp_num_verts > 0) {
1791 // Transform vertices.
1792 for (i = 0; i < comp_num_verts; ++i) {
1793 stbtt_vertex* v = &comp_verts[i];
1794 stbtt_vertex_type x,y;
1795 x=v.x; y=v.y;
1796 v.x = cast(stbtt_vertex_type)(m * (mtx[0]*x + mtx[2]*y + mtx[4]));
1797 v.y = cast(stbtt_vertex_type)(n * (mtx[1]*x + mtx[3]*y + mtx[5]));
1798 x=v.cx; y=v.cy;
1799 v.cx = cast(stbtt_vertex_type)(m * (mtx[0]*x + mtx[2]*y + mtx[4]));
1800 v.cy = cast(stbtt_vertex_type)(n * (mtx[1]*x + mtx[3]*y + mtx[5]));
1802 // Append vertices.
1803 tmp = cast(stbtt_vertex*)STBTT_malloc((num_vertices+comp_num_verts)*cast(uint)stbtt_vertex.sizeof, info.userdata);
1804 if (!tmp) {
1805 if (vertices) STBTT_free(vertices, info.userdata);
1806 if (comp_verts) STBTT_free(comp_verts, info.userdata);
1807 return 0;
1809 if (num_vertices > 0) STBTT_memcpy(tmp, vertices, num_vertices*cast(uint)stbtt_vertex.sizeof);
1810 STBTT_memcpy(tmp+num_vertices, comp_verts, comp_num_verts*cast(uint)stbtt_vertex.sizeof);
1811 if (vertices) STBTT_free(vertices, info.userdata);
1812 vertices = tmp;
1813 STBTT_free(comp_verts, info.userdata);
1814 num_vertices += comp_num_verts;
1816 // More components ?
1817 more = flags & (1<<5);
1819 } else if (numberOfContours < 0) {
1820 // @TODO other compound variations?
1821 assert(0);
1822 } else {
1823 // numberOfCounters == 0, do nothing
1826 *pvertices = vertices;
1827 return num_vertices;
1830 struct stbtt__csctx {
1831 int bounds;
1832 int started;
1833 float first_x, first_y;
1834 float x, y;
1835 stbtt_int32 min_x, max_x, min_y, max_y;
1837 stbtt_vertex *pvertices;
1838 int num_vertices;
1841 //#define STBTT__CSCTX_INIT(bounds) {bounds,0, 0,0, 0,0, 0,0,0,0, null, 0}
1843 private void stbtt__track_vertex(stbtt__csctx *c, stbtt_int32 x, stbtt_int32 y)
1845 if (x > c.max_x || !c.started) c.max_x = x;
1846 if (y > c.max_y || !c.started) c.max_y = y;
1847 if (x < c.min_x || !c.started) c.min_x = x;
1848 if (y < c.min_y || !c.started) c.min_y = y;
1849 c.started = 1;
1852 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)
1854 if (c.bounds) {
1855 stbtt__track_vertex(c, x, y);
1856 if (type == STBTT_vcubic) {
1857 stbtt__track_vertex(c, cx, cy);
1858 stbtt__track_vertex(c, cx1, cy1);
1860 } else {
1861 stbtt_setvertex(&c.pvertices[c.num_vertices], type, x, y, cx, cy);
1862 c.pvertices[c.num_vertices].cx1 = cast(stbtt_int16) cx1;
1863 c.pvertices[c.num_vertices].cy1 = cast(stbtt_int16) cy1;
1865 c.num_vertices++;
1868 private void stbtt__csctx_close_shape(stbtt__csctx *ctx)
1870 if (ctx.first_x != ctx.x || ctx.first_y != ctx.y)
1871 stbtt__csctx_v(ctx, STBTT_vline, cast(int)ctx.first_x, cast(int)ctx.first_y, 0, 0, 0, 0);
1874 private void stbtt__csctx_rmove_to(stbtt__csctx *ctx, float dx, float dy)
1876 stbtt__csctx_close_shape(ctx);
1877 ctx.first_x = ctx.x = ctx.x + dx;
1878 ctx.first_y = ctx.y = ctx.y + dy;
1879 stbtt__csctx_v(ctx, STBTT_vmove, cast(int)ctx.x, cast(int)ctx.y, 0, 0, 0, 0);
1882 private void stbtt__csctx_rline_to(stbtt__csctx *ctx, float dx, float dy)
1884 ctx.x += dx;
1885 ctx.y += dy;
1886 stbtt__csctx_v(ctx, STBTT_vline, cast(int)ctx.x, cast(int)ctx.y, 0, 0, 0, 0);
1889 private void stbtt__csctx_rccurve_to(stbtt__csctx *ctx, float dx1, float dy1, float dx2, float dy2, float dx3, float dy3)
1891 float cx1 = ctx.x + dx1;
1892 float cy1 = ctx.y + dy1;
1893 float cx2 = cx1 + dx2;
1894 float cy2 = cy1 + dy2;
1895 ctx.x = cx2 + dx3;
1896 ctx.y = cy2 + dy3;
1897 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);
1900 private stbtt__buf stbtt__get_subr(stbtt__buf idx, int n)
1902 int count = stbtt__cff_index_count(&idx);
1903 int bias = 107;
1904 if (count >= 33900)
1905 bias = 32768;
1906 else if (count >= 1240)
1907 bias = 1131;
1908 n += bias;
1909 if (n < 0 || n >= count)
1910 return stbtt__new_buf(null, 0);
1911 return stbtt__cff_index_get(idx, n);
1914 private stbtt__buf stbtt__cid_get_glyph_subrs(stbtt_fontinfo* info, int glyph_index)
1916 stbtt__buf fdselect = info.fdselect;
1917 int nranges, start, end, v, fmt, fdselector = -1, i;
1919 stbtt__buf_seek(&fdselect, 0);
1920 fmt = stbtt__buf_get8(&fdselect);
1921 if (fmt == 0) {
1922 // untested
1923 stbtt__buf_skip(&fdselect, glyph_index);
1924 fdselector = stbtt__buf_get8(&fdselect);
1925 } else if (fmt == 3) {
1926 nranges = stbtt__buf_get16(&fdselect);
1927 start = stbtt__buf_get16(&fdselect);
1928 for (i = 0; i < nranges; i++) {
1929 v = stbtt__buf_get8(&fdselect);
1930 end = stbtt__buf_get16(&fdselect);
1931 if (glyph_index >= start && glyph_index < end) {
1932 fdselector = v;
1933 break;
1935 start = end;
1938 if (fdselector == -1) stbtt__new_buf(null, 0);
1939 return stbtt__get_subrs(info.cff, stbtt__cff_index_get(info.fontdicts, fdselector));
1942 private int stbtt__run_charstring(stbtt_fontinfo* info, int glyph_index, stbtt__csctx *c)
1944 int in_header = 1, maskbits = 0, subr_stack_height = 0, sp = 0, v, i, b0;
1945 int has_subrs = 0, clear_stack;
1946 float[48] s = void;
1947 stbtt__buf[10] subr_stack = void;
1948 stbtt__buf subrs = info.subrs, b;
1949 float f;
1951 static int STBTT__CSERR(string s) { pragma(inline, true); return 0; }
1953 // this currently ignores the initial width value, which isn't needed if we have hmtx
1954 b = stbtt__cff_index_get(info.charstrings, glyph_index);
1955 while (b.cursor < b.size) {
1956 i = 0;
1957 clear_stack = 1;
1958 b0 = stbtt__buf_get8(&b);
1959 switch (b0) {
1960 // @TODO implement hinting
1961 case 0x13: // hintmask
1962 case 0x14: // cntrmask
1963 if (in_header)
1964 maskbits += (sp / 2); // implicit "vstem"
1965 in_header = 0;
1966 stbtt__buf_skip(&b, (maskbits + 7) / 8);
1967 break;
1969 case 0x01: // hstem
1970 case 0x03: // vstem
1971 case 0x12: // hstemhm
1972 case 0x17: // vstemhm
1973 maskbits += (sp / 2);
1974 break;
1976 case 0x15: // rmoveto
1977 in_header = 0;
1978 if (sp < 2) return STBTT__CSERR("rmoveto stack");
1979 stbtt__csctx_rmove_to(c, s[sp-2], s[sp-1]);
1980 break;
1981 case 0x04: // vmoveto
1982 in_header = 0;
1983 if (sp < 1) return STBTT__CSERR("vmoveto stack");
1984 stbtt__csctx_rmove_to(c, 0, s[sp-1]);
1985 break;
1986 case 0x16: // hmoveto
1987 in_header = 0;
1988 if (sp < 1) return STBTT__CSERR("hmoveto stack");
1989 stbtt__csctx_rmove_to(c, s[sp-1], 0);
1990 break;
1992 case 0x05: // rlineto
1993 if (sp < 2) return STBTT__CSERR("rlineto stack");
1994 for (; i + 1 < sp; i += 2)
1995 stbtt__csctx_rline_to(c, s[i], s[i+1]);
1996 break;
1998 // hlineto/vlineto and vhcurveto/hvcurveto alternate horizontal and vertical
1999 // starting from a different place.
2001 case 0x07: // vlineto
2002 if (sp < 1) return STBTT__CSERR("vlineto stack");
2003 goto vlineto;
2004 case 0x06: // hlineto
2005 if (sp < 1) return STBTT__CSERR("hlineto stack");
2006 for (;;) {
2007 if (i >= sp) break;
2008 stbtt__csctx_rline_to(c, s[i], 0);
2009 i++;
2010 vlineto:
2011 if (i >= sp) break;
2012 stbtt__csctx_rline_to(c, 0, s[i]);
2013 i++;
2015 break;
2017 case 0x1F: // hvcurveto
2018 if (sp < 4) return STBTT__CSERR("hvcurveto stack");
2019 goto hvcurveto;
2020 case 0x1E: // vhcurveto
2021 if (sp < 4) return STBTT__CSERR("vhcurveto stack");
2022 for (;;) {
2023 if (i + 3 >= sp) break;
2024 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);
2025 i += 4;
2026 hvcurveto:
2027 if (i + 3 >= sp) break;
2028 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]);
2029 i += 4;
2031 break;
2033 case 0x08: // rrcurveto
2034 if (sp < 6) return STBTT__CSERR("rcurveline stack");
2035 for (; i + 5 < sp; i += 6)
2036 stbtt__csctx_rccurve_to(c, s[i], s[i+1], s[i+2], s[i+3], s[i+4], s[i+5]);
2037 break;
2039 case 0x18: // rcurveline
2040 if (sp < 8) return STBTT__CSERR("rcurveline stack");
2041 for (; i + 5 < sp - 2; i += 6)
2042 stbtt__csctx_rccurve_to(c, s[i], s[i+1], s[i+2], s[i+3], s[i+4], s[i+5]);
2043 if (i + 1 >= sp) return STBTT__CSERR("rcurveline stack");
2044 stbtt__csctx_rline_to(c, s[i], s[i+1]);
2045 break;
2047 case 0x19: // rlinecurve
2048 if (sp < 8) return STBTT__CSERR("rlinecurve stack");
2049 for (; i + 1 < sp - 6; i += 2)
2050 stbtt__csctx_rline_to(c, s[i], s[i+1]);
2051 if (i + 5 >= sp) return STBTT__CSERR("rlinecurve stack");
2052 stbtt__csctx_rccurve_to(c, s[i], s[i+1], s[i+2], s[i+3], s[i+4], s[i+5]);
2053 break;
2055 case 0x1A: // vvcurveto
2056 case 0x1B: // hhcurveto
2057 if (sp < 4) return STBTT__CSERR("(vv|hh)curveto stack");
2058 f = 0.0;
2059 if (sp & 1) { f = s[i]; i++; }
2060 for (; i + 3 < sp; i += 4) {
2061 if (b0 == 0x1B)
2062 stbtt__csctx_rccurve_to(c, s[i], f, s[i+1], s[i+2], s[i+3], 0.0);
2063 else
2064 stbtt__csctx_rccurve_to(c, f, s[i], s[i+1], s[i+2], 0.0, s[i+3]);
2065 f = 0.0;
2067 break;
2069 case 0x0A: // callsubr
2070 if (!has_subrs) {
2071 if (info.fdselect.size)
2072 subrs = stbtt__cid_get_glyph_subrs(info, glyph_index);
2073 has_subrs = 1;
2075 // fallthrough
2076 goto case;
2077 case 0x1D: // callgsubr
2078 if (sp < 1) return STBTT__CSERR("call(g|)subr stack");
2079 v = cast(int) s[--sp];
2080 if (subr_stack_height >= 10) return STBTT__CSERR("recursion limit");
2081 subr_stack[subr_stack_height++] = b;
2082 b = stbtt__get_subr(b0 == 0x0A ? subrs : info.gsubrs, v);
2083 if (b.size == 0) return STBTT__CSERR("subr not found");
2084 b.cursor = 0;
2085 clear_stack = 0;
2086 break;
2088 case 0x0B: // return
2089 if (subr_stack_height <= 0) return STBTT__CSERR("return outside subr");
2090 b = subr_stack[--subr_stack_height];
2091 clear_stack = 0;
2092 break;
2094 case 0x0E: // endchar
2095 stbtt__csctx_close_shape(c);
2096 return 1;
2098 case 0x0C: { // two-byte escape
2099 float dx1, dx2, dx3, dx4, dx5, dx6, dy1, dy2, dy3, dy4, dy5, dy6;
2100 float dx, dy;
2101 int b1 = stbtt__buf_get8(&b);
2102 switch (b1) {
2103 // @TODO These "flex" implementations ignore the flex-depth and resolution,
2104 // and always draw beziers.
2105 case 0x22: // hflex
2106 if (sp < 7) return STBTT__CSERR("hflex stack");
2107 dx1 = s[0];
2108 dx2 = s[1];
2109 dy2 = s[2];
2110 dx3 = s[3];
2111 dx4 = s[4];
2112 dx5 = s[5];
2113 dx6 = s[6];
2114 stbtt__csctx_rccurve_to(c, dx1, 0, dx2, dy2, dx3, 0);
2115 stbtt__csctx_rccurve_to(c, dx4, 0, dx5, -dy2, dx6, 0);
2116 break;
2118 case 0x23: // flex
2119 if (sp < 13) return STBTT__CSERR("flex stack");
2120 dx1 = s[0];
2121 dy1 = s[1];
2122 dx2 = s[2];
2123 dy2 = s[3];
2124 dx3 = s[4];
2125 dy3 = s[5];
2126 dx4 = s[6];
2127 dy4 = s[7];
2128 dx5 = s[8];
2129 dy5 = s[9];
2130 dx6 = s[10];
2131 dy6 = s[11];
2132 //fd is s[12]
2133 stbtt__csctx_rccurve_to(c, dx1, dy1, dx2, dy2, dx3, dy3);
2134 stbtt__csctx_rccurve_to(c, dx4, dy4, dx5, dy5, dx6, dy6);
2135 break;
2137 case 0x24: // hflex1
2138 if (sp < 9) return STBTT__CSERR("hflex1 stack");
2139 dx1 = s[0];
2140 dy1 = s[1];
2141 dx2 = s[2];
2142 dy2 = s[3];
2143 dx3 = s[4];
2144 dx4 = s[5];
2145 dx5 = s[6];
2146 dy5 = s[7];
2147 dx6 = s[8];
2148 stbtt__csctx_rccurve_to(c, dx1, dy1, dx2, dy2, dx3, 0);
2149 stbtt__csctx_rccurve_to(c, dx4, 0, dx5, dy5, dx6, -(dy1+dy2+dy5));
2150 break;
2152 case 0x25: // flex1
2153 if (sp < 11) return STBTT__CSERR("flex1 stack");
2154 dx1 = s[0];
2155 dy1 = s[1];
2156 dx2 = s[2];
2157 dy2 = s[3];
2158 dx3 = s[4];
2159 dy3 = s[5];
2160 dx4 = s[6];
2161 dy4 = s[7];
2162 dx5 = s[8];
2163 dy5 = s[9];
2164 dx6 = dy6 = s[10];
2165 dx = dx1+dx2+dx3+dx4+dx5;
2166 dy = dy1+dy2+dy3+dy4+dy5;
2167 if (STBTT_fabs(dx) > STBTT_fabs(dy))
2168 dy6 = -dy;
2169 else
2170 dx6 = -dx;
2171 stbtt__csctx_rccurve_to(c, dx1, dy1, dx2, dy2, dx3, dy3);
2172 stbtt__csctx_rccurve_to(c, dx4, dy4, dx5, dy5, dx6, dy6);
2173 break;
2175 default:
2176 return STBTT__CSERR("unimplemented");
2178 } break;
2180 default:
2181 if (b0 != 255 && b0 != 28 && (b0 < 32 || b0 > 254))
2182 return STBTT__CSERR("reserved operator");
2184 // push immediate
2185 if (b0 == 255) {
2186 f = cast(float)cast(stbtt_int32)stbtt__buf_get32(&b) / 0x10000;
2187 } else {
2188 stbtt__buf_skip(&b, -1);
2189 f = cast(float)cast(stbtt_int16)stbtt__cff_int(&b);
2191 if (sp >= 48) return STBTT__CSERR("push stack overflow");
2192 s[sp++] = f;
2193 clear_stack = 0;
2194 break;
2196 if (clear_stack) sp = 0;
2198 return STBTT__CSERR("no endchar");
2201 private int stbtt__GetGlyphShapeT2(stbtt_fontinfo* info, int glyph_index, stbtt_vertex **pvertices)
2203 // runs the charstring twice, once to count and once to output (to avoid realloc)
2204 stbtt__csctx count_ctx = stbtt__csctx(1,0, 0,0, 0,0, 0,0,0,0, null, 0); //STBTT__CSCTX_INIT(1);
2205 stbtt__csctx output_ctx = stbtt__csctx(0,0, 0,0, 0,0, 0,0,0,0, null, 0); //STBTT__CSCTX_INIT(0);
2206 if (stbtt__run_charstring(info, glyph_index, &count_ctx)) {
2207 *pvertices = cast(stbtt_vertex*)STBTT_malloc(count_ctx.num_vertices*cast(uint)stbtt_vertex.sizeof, info.userdata);
2208 output_ctx.pvertices = *pvertices;
2209 if (stbtt__run_charstring(info, glyph_index, &output_ctx)) {
2210 assert(output_ctx.num_vertices == count_ctx.num_vertices);
2211 return output_ctx.num_vertices;
2214 *pvertices = null;
2215 return 0;
2218 public int stbtt__GetGlyphInfoT2(stbtt_fontinfo* info, int glyph_index, int *x0, int *y0, int *x1, int *y1)
2220 stbtt__csctx c = stbtt__csctx(1,0, 0,0, 0,0, 0,0,0,0, null, 0); //STBTT__CSCTX_INIT(1);
2221 int r = stbtt__run_charstring(info, glyph_index, &c); //k8: sorry
2222 if (x0) *x0 = r ? c.min_x : 0;
2223 if (y0) *y0 = r ? c.min_y : 0;
2224 if (x1) *x1 = r ? c.max_x : 0;
2225 if (y1) *y1 = r ? c.max_y : 0;
2226 return r ? c.num_vertices : 0;
2229 public int stbtt_GetGlyphShape(stbtt_fontinfo* info, int glyph_index, stbtt_vertex **pvertices)
2231 if (!info.cff.size)
2232 return stbtt__GetGlyphShapeTT(info, glyph_index, pvertices);
2233 else
2234 return stbtt__GetGlyphShapeT2(info, glyph_index, pvertices);
2237 public void stbtt_GetGlyphHMetrics(const(stbtt_fontinfo)* info, int glyph_index, int *advanceWidth, int *leftSideBearing)
2239 stbtt_uint16 numOfLongHorMetrics = ttUSHORT(info.data+info.hhea + 34);
2240 if (glyph_index < numOfLongHorMetrics) {
2241 if (advanceWidth) *advanceWidth = ttSHORT(info.data + info.hmtx + 4*glyph_index);
2242 if (leftSideBearing) *leftSideBearing = ttSHORT(info.data + info.hmtx + 4*glyph_index + 2);
2243 } else {
2244 if (advanceWidth) *advanceWidth = ttSHORT(info.data + info.hmtx + 4*(numOfLongHorMetrics-1));
2245 if (leftSideBearing) *leftSideBearing = ttSHORT(info.data + info.hmtx + 4*numOfLongHorMetrics + 2*(glyph_index - numOfLongHorMetrics));
2249 private int stbtt__GetGlyphKernInfoAdvance(stbtt_fontinfo* info, int glyph1, int glyph2)
2251 stbtt_uint8 *data = info.data + info.kern;
2252 stbtt_uint32 needle, straw;
2253 int l, r, m;
2255 // we only look at the first table. it must be 'horizontal' and format 0.
2256 if (!info.kern)
2257 return 0;
2258 if (ttUSHORT(data+2) < 1) // number of tables, need at least 1
2259 return 0;
2260 if (ttUSHORT(data+8) != 1) // horizontal flag must be set in format
2261 return 0;
2263 l = 0;
2264 r = ttUSHORT(data+10) - 1;
2265 needle = glyph1 << 16 | glyph2;
2266 while (l <= r) {
2267 m = (l + r) >> 1;
2268 straw = ttULONG(data+18+(m*6)); // note: unaligned read
2269 if (needle < straw)
2270 r = m - 1;
2271 else if (needle > straw)
2272 l = m + 1;
2273 else
2274 return ttSHORT(data+22+(m*6));
2276 return 0;
2279 private stbtt_int32 stbtt__GetCoverageIndex(stbtt_uint8 *coverageTable, int glyph)
2281 stbtt_uint16 coverageFormat = ttUSHORT(coverageTable);
2282 switch(coverageFormat) {
2283 case 1: {
2284 stbtt_uint16 glyphCount = ttUSHORT(coverageTable + 2);
2286 // Binary search.
2287 stbtt_int32 l=0, r=glyphCount-1, m;
2288 int straw, needle=glyph;
2289 while (l <= r) {
2290 stbtt_uint8 *glyphArray = coverageTable + 4;
2291 stbtt_uint16 glyphID;
2292 m = (l + r) >> 1;
2293 glyphID = ttUSHORT(glyphArray + 2 * m);
2294 straw = glyphID;
2295 if (needle < straw)
2296 r = m - 1;
2297 else if (needle > straw)
2298 l = m + 1;
2299 else {
2300 return m;
2303 } break;
2305 case 2: {
2306 stbtt_uint16 rangeCount = ttUSHORT(coverageTable + 2);
2307 stbtt_uint8 *rangeArray = coverageTable + 4;
2309 // Binary search.
2310 stbtt_int32 l=0, r=rangeCount-1, m;
2311 int strawStart, strawEnd, needle=glyph;
2312 while (l <= r) {
2313 stbtt_uint8 *rangeRecord;
2314 m = (l + r) >> 1;
2315 rangeRecord = rangeArray + 6 * m;
2316 strawStart = ttUSHORT(rangeRecord);
2317 strawEnd = ttUSHORT(rangeRecord + 2);
2318 if (needle < strawStart)
2319 r = m - 1;
2320 else if (needle > strawEnd)
2321 l = m + 1;
2322 else {
2323 stbtt_uint16 startCoverageIndex = ttUSHORT(rangeRecord + 4);
2324 return startCoverageIndex + glyph - strawStart;
2327 } break;
2329 default: {
2330 // There are no other cases.
2331 assert(0);
2332 } break;
2335 return -1;
2338 private stbtt_int32 stbtt__GetGlyphClass(stbtt_uint8 *classDefTable, int glyph)
2340 stbtt_uint16 classDefFormat = ttUSHORT(classDefTable);
2341 switch(classDefFormat)
2343 case 1: {
2344 stbtt_uint16 startGlyphID = ttUSHORT(classDefTable + 2);
2345 stbtt_uint16 glyphCount = ttUSHORT(classDefTable + 4);
2346 stbtt_uint8 *classDef1ValueArray = classDefTable + 6;
2348 if (glyph >= startGlyphID && glyph < startGlyphID + glyphCount)
2349 return cast(stbtt_int32)ttUSHORT(classDef1ValueArray + 2 * (glyph - startGlyphID));
2351 classDefTable = classDef1ValueArray + 2 * glyphCount;
2352 } break;
2354 case 2: {
2355 stbtt_uint16 classRangeCount = ttUSHORT(classDefTable + 2);
2356 stbtt_uint8 *classRangeRecords = classDefTable + 4;
2358 // Binary search.
2359 stbtt_int32 l=0, r=classRangeCount-1, m;
2360 int strawStart, strawEnd, needle=glyph;
2361 while (l <= r) {
2362 stbtt_uint8 *classRangeRecord;
2363 m = (l + r) >> 1;
2364 classRangeRecord = classRangeRecords + 6 * m;
2365 strawStart = ttUSHORT(classRangeRecord);
2366 strawEnd = ttUSHORT(classRangeRecord + 2);
2367 if (needle < strawStart)
2368 r = m - 1;
2369 else if (needle > strawEnd)
2370 l = m + 1;
2371 else
2372 return cast(stbtt_int32)ttUSHORT(classRangeRecord + 4);
2375 classDefTable = classRangeRecords + 6 * classRangeCount;
2376 } break;
2378 default: {
2379 // There are no other cases.
2380 assert(0);
2381 } break;
2384 return -1;
2387 // Define to STBTT_assert(x) if you want to break on unimplemented formats.
2388 //#define STBTT_GPOS_TODO_assert(x)
2390 private stbtt_int32 stbtt__GetGlyphGPOSInfoAdvance(stbtt_fontinfo* info, int glyph1, int glyph2)
2392 stbtt_uint16 lookupListOffset;
2393 stbtt_uint8 *lookupList;
2394 stbtt_uint16 lookupCount;
2395 stbtt_uint8 *data;
2396 stbtt_int32 i;
2398 if (!info.gpos) return 0;
2400 data = info.data + info.gpos;
2402 if (ttUSHORT(data+0) != 1) return 0; // Major version 1
2403 if (ttUSHORT(data+2) != 0) return 0; // Minor version 0
2405 lookupListOffset = ttUSHORT(data+8);
2406 lookupList = data + lookupListOffset;
2407 lookupCount = ttUSHORT(lookupList);
2409 for (i=0; i<lookupCount; ++i) {
2410 stbtt_uint16 lookupOffset = ttUSHORT(lookupList + 2 + 2 * i);
2411 stbtt_uint8 *lookupTable = lookupList + lookupOffset;
2413 stbtt_uint16 lookupType = ttUSHORT(lookupTable);
2414 stbtt_uint16 subTableCount = ttUSHORT(lookupTable + 4);
2415 stbtt_uint8 *subTableOffsets = lookupTable + 6;
2416 switch(lookupType) {
2417 case 2: { // Pair Adjustment Positioning Subtable
2418 stbtt_int32 sti;
2419 for (sti=0; sti<subTableCount; sti++) {
2420 stbtt_uint16 subtableOffset = ttUSHORT(subTableOffsets + 2 * sti);
2421 stbtt_uint8 *table = lookupTable + subtableOffset;
2422 stbtt_uint16 posFormat = ttUSHORT(table);
2423 stbtt_uint16 coverageOffset = ttUSHORT(table + 2);
2424 stbtt_int32 coverageIndex = stbtt__GetCoverageIndex(table + coverageOffset, glyph1);
2425 if (coverageIndex == -1) continue;
2427 switch (posFormat) {
2428 case 1: {
2429 stbtt_int32 l, r, m;
2430 int straw, needle;
2431 stbtt_uint16 valueFormat1 = ttUSHORT(table + 4);
2432 stbtt_uint16 valueFormat2 = ttUSHORT(table + 6);
2433 stbtt_int32 valueRecordPairSizeInBytes = 2;
2434 stbtt_uint16 pairSetCount = ttUSHORT(table + 8);
2435 stbtt_uint16 pairPosOffset = ttUSHORT(table + 10 + 2 * coverageIndex);
2436 stbtt_uint8 *pairValueTable = table + pairPosOffset;
2437 stbtt_uint16 pairValueCount = ttUSHORT(pairValueTable);
2438 stbtt_uint8 *pairValueArray = pairValueTable + 2;
2439 // TODO: Support more formats.
2440 //!STBTT_GPOS_TODO_assert(valueFormat1 == 4);
2441 if (valueFormat1 != 4) return 0;
2442 //!STBTT_GPOS_TODO_assert(valueFormat2 == 0);
2443 if (valueFormat2 != 0) return 0;
2445 assert(coverageIndex < pairSetCount);
2447 needle=glyph2;
2448 r=pairValueCount-1;
2449 l=0;
2451 // Binary search.
2452 while (l <= r) {
2453 stbtt_uint16 secondGlyph;
2454 stbtt_uint8 *pairValue;
2455 m = (l + r) >> 1;
2456 pairValue = pairValueArray + (2 + valueRecordPairSizeInBytes) * m;
2457 secondGlyph = ttUSHORT(pairValue);
2458 straw = secondGlyph;
2459 if (needle < straw)
2460 r = m - 1;
2461 else if (needle > straw)
2462 l = m + 1;
2463 else {
2464 stbtt_int16 xAdvance = ttSHORT(pairValue + 2);
2465 return xAdvance;
2468 } break;
2470 case 2: {
2471 stbtt_uint16 valueFormat1 = ttUSHORT(table + 4);
2472 stbtt_uint16 valueFormat2 = ttUSHORT(table + 6);
2474 stbtt_uint16 classDef1Offset = ttUSHORT(table + 8);
2475 stbtt_uint16 classDef2Offset = ttUSHORT(table + 10);
2476 int glyph1class = stbtt__GetGlyphClass(table + classDef1Offset, glyph1);
2477 int glyph2class = stbtt__GetGlyphClass(table + classDef2Offset, glyph2);
2479 stbtt_uint16 class1Count = ttUSHORT(table + 12);
2480 stbtt_uint16 class2Count = ttUSHORT(table + 14);
2481 assert(glyph1class < class1Count);
2482 assert(glyph2class < class2Count);
2484 // TODO: Support more formats.
2485 //!STBTT_GPOS_TODO_assert(valueFormat1 == 4);
2486 if (valueFormat1 != 4) return 0;
2487 //!STBTT_GPOS_TODO_assert(valueFormat2 == 0);
2488 if (valueFormat2 != 0) return 0;
2490 if (glyph1class >= 0 && glyph1class < class1Count && glyph2class >= 0 && glyph2class < class2Count) {
2491 stbtt_uint8 *class1Records = table + 16;
2492 stbtt_uint8 *class2Records = class1Records + 2 * (glyph1class * class2Count);
2493 stbtt_int16 xAdvance = ttSHORT(class2Records + 2 * glyph2class);
2494 return xAdvance;
2496 } break;
2498 default: {
2499 // There are no other cases.
2500 assert(0);
2501 break;
2505 break;
2508 default:
2509 // TODO: Implement other stuff.
2510 break;
2514 return 0;
2517 public int stbtt_GetGlyphKernAdvance(stbtt_fontinfo* info, int g1, int g2)
2519 int xAdvance = 0;
2521 if (info.gpos)
2522 xAdvance += stbtt__GetGlyphGPOSInfoAdvance(info, g1, g2);
2524 if (info.kern)
2525 xAdvance += stbtt__GetGlyphKernInfoAdvance(info, g1, g2);
2527 return xAdvance;
2530 public int stbtt_GetCodepointKernAdvance(stbtt_fontinfo* info, int ch1, int ch2)
2532 if (!info.kern && !info.gpos) // if no kerning table, don't waste time looking up both codepoint->glyphs
2533 return 0;
2534 return stbtt_GetGlyphKernAdvance(info, stbtt_FindGlyphIndex(info,ch1), stbtt_FindGlyphIndex(info,ch2));
2537 public void stbtt_GetCodepointHMetrics(const(stbtt_fontinfo)* info, int codepoint, int *advanceWidth, int *leftSideBearing)
2539 stbtt_GetGlyphHMetrics(info, stbtt_FindGlyphIndex(info,codepoint), advanceWidth, leftSideBearing);
2542 public void stbtt_GetFontVMetrics(const(stbtt_fontinfo)* info, int *ascent, int *descent, int *lineGap)
2544 if (ascent ) *ascent = ttSHORT(info.data+info.hhea + 4);
2545 if (descent) *descent = ttSHORT(info.data+info.hhea + 6);
2546 if (lineGap) *lineGap = ttSHORT(info.data+info.hhea + 8);
2549 public int stbtt_GetFontVMetricsOS2(stbtt_fontinfo* info, int *typoAscent, int *typoDescent, int *typoLineGap)
2551 int tab = stbtt__find_table(info.data, info.fontstart, "OS/2");
2552 if (!tab)
2553 return 0;
2554 if (typoAscent ) *typoAscent = ttSHORT(info.data+tab + 68);
2555 if (typoDescent) *typoDescent = ttSHORT(info.data+tab + 70);
2556 if (typoLineGap) *typoLineGap = ttSHORT(info.data+tab + 72);
2557 return 1;
2560 public void stbtt_GetFontBoundingBox(const(stbtt_fontinfo)* info, int *x0, int *y0, int *x1, int *y1)
2562 *x0 = ttSHORT(info.data + info.head + 36);
2563 *y0 = ttSHORT(info.data + info.head + 38);
2564 *x1 = ttSHORT(info.data + info.head + 40);
2565 *y1 = ttSHORT(info.data + info.head + 42);
2568 public float stbtt_ScaleForPixelHeight(const(stbtt_fontinfo)* info, float height)
2570 int fheight = ttSHORT(info.data + info.hhea + 4) - ttSHORT(info.data + info.hhea + 6);
2571 return cast(float) height / fheight;
2574 public float stbtt_ScaleForMappingEmToPixels(const(stbtt_fontinfo)* info, float pixels)
2576 int unitsPerEm = ttUSHORT(info.data + info.head + 18);
2577 return pixels / unitsPerEm;
2580 public void stbtt_FreeShape(const(stbtt_fontinfo)* info, stbtt_vertex *v)
2582 STBTT_free(v, info.userdata);
2585 //////////////////////////////////////////////////////////////////////////////
2587 // antialiasing software rasterizer
2590 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)
2592 int x0=0,y0=0,x1,y1; // =0 suppresses compiler warning
2593 if (!stbtt_GetGlyphBox(font, glyph, &x0,&y0,&x1,&y1)) {
2594 // e.g. space character
2595 if (ix0) *ix0 = 0;
2596 if (iy0) *iy0 = 0;
2597 if (ix1) *ix1 = 0;
2598 if (iy1) *iy1 = 0;
2599 } else {
2600 // move to integral bboxes (treating pixels as little squares, what pixels get touched)?
2601 if (ix0) *ix0 = STBTT_ifloor( x0 * scale_x + shift_x);
2602 if (iy0) *iy0 = STBTT_ifloor(-y1 * scale_y + shift_y);
2603 if (ix1) *ix1 = STBTT_iceil ( x1 * scale_x + shift_x);
2604 if (iy1) *iy1 = STBTT_iceil (-y0 * scale_y + shift_y);
2608 public void stbtt_GetGlyphBitmapBox(stbtt_fontinfo* font, int glyph, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1)
2610 stbtt_GetGlyphBitmapBoxSubpixel(font, glyph, scale_x, scale_y,0.0f,0.0f, ix0, iy0, ix1, iy1);
2613 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)
2615 stbtt_GetGlyphBitmapBoxSubpixel(font, stbtt_FindGlyphIndex(font,codepoint), scale_x, scale_y,shift_x,shift_y, ix0,iy0,ix1,iy1);
2618 public void stbtt_GetCodepointBitmapBox(stbtt_fontinfo* font, int codepoint, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1)
2620 stbtt_GetCodepointBitmapBoxSubpixel(font, codepoint, scale_x, scale_y,0.0f,0.0f, ix0,iy0,ix1,iy1);
2623 //////////////////////////////////////////////////////////////////////////////
2625 // Rasterizer
2627 struct stbtt__hheap_chunk {
2628 stbtt__hheap_chunk *next;
2631 struct stbtt__hheap {
2632 stbtt__hheap_chunk *head;
2633 void *first_free;
2634 int num_remaining_in_head_chunk;
2637 private void *stbtt__hheap_alloc(stbtt__hheap *hh, size_t size, void *userdata)
2639 if (hh.first_free) {
2640 void *p = hh.first_free;
2641 hh.first_free = * cast(void **) p;
2642 return p;
2643 } else {
2644 if (hh.num_remaining_in_head_chunk == 0) {
2645 int count = (size < 32 ? 2000 : size < 128 ? 800 : 100);
2646 stbtt__hheap_chunk *c = cast(stbtt__hheap_chunk *) STBTT_malloc(cast(uint)(stbtt__hheap_chunk.sizeof + size * count), userdata);
2647 if (c == null)
2648 return null;
2649 c.next = hh.head;
2650 hh.head = c;
2651 hh.num_remaining_in_head_chunk = count;
2653 --hh.num_remaining_in_head_chunk;
2654 return cast(char *) (hh.head) + cast(uint)stbtt__hheap_chunk.sizeof + size * hh.num_remaining_in_head_chunk;
2658 private void stbtt__hheap_free(stbtt__hheap *hh, void *p)
2660 *cast(void **) p = hh.first_free;
2661 hh.first_free = p;
2664 private void stbtt__hheap_cleanup(stbtt__hheap *hh, void *userdata)
2666 stbtt__hheap_chunk *c = hh.head;
2667 while (c) {
2668 stbtt__hheap_chunk *n = c.next;
2669 STBTT_free(c, userdata);
2670 c = n;
2674 struct stbtt__edge {
2675 float x0,y0, x1,y1;
2676 int invert;
2680 struct stbtt__active_edge {
2681 stbtt__active_edge *next;
2682 static if (STBTT_RASTERIZER_VERSION == 1) {
2683 int x,dx;
2684 float ey;
2685 int direction;
2686 } else static if (STBTT_RASTERIZER_VERSION == 2) {
2687 float fx,fdx,fdy;
2688 float direction;
2689 float sy;
2690 float ey;
2691 } else {
2692 static assert(0, "Unrecognized value of STBTT_RASTERIZER_VERSION");
2696 static if (STBTT_RASTERIZER_VERSION == 1) {
2697 enum STBTT_FIXSHIFT = 10;
2698 enum STBTT_FIX = (1 << STBTT_FIXSHIFT);
2699 enum STBTT_FIXMASK = (STBTT_FIX-1);
2701 private stbtt__active_edge *stbtt__new_active(stbtt__hheap *hh, stbtt__edge *e, int off_x, float start_point, void *userdata)
2703 stbtt__active_edge *z = void;
2704 z = cast(stbtt__active_edge *) stbtt__hheap_alloc(hh, cast(uint)(*z).sizeof, userdata);
2705 float dxdy = (e.x1 - e.x0) / (e.y1 - e.y0);
2706 assert(z != null);
2707 if (!z) return z;
2709 // round dx down to avoid overshooting
2710 if (dxdy < 0)
2711 z.dx = -STBTT_ifloor(STBTT_FIX * -dxdy);
2712 else
2713 z.dx = STBTT_ifloor(STBTT_FIX * dxdy);
2715 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
2716 z.x -= off_x * STBTT_FIX;
2718 z.ey = e.y1;
2719 z.next = 0;
2720 z.direction = e.invert ? 1 : -1;
2721 return z;
2723 } else static if (STBTT_RASTERIZER_VERSION == 2) {
2724 private stbtt__active_edge *stbtt__new_active(stbtt__hheap *hh, stbtt__edge *e, int off_x, float start_point, void *userdata)
2726 stbtt__active_edge *z = void;
2727 z = cast(stbtt__active_edge *) stbtt__hheap_alloc(hh, cast(uint)(*z).sizeof, userdata);
2728 float dxdy = (e.x1 - e.x0) / (e.y1 - e.y0);
2729 assert(z != null);
2730 //STBTT_assert(e->y0 <= start_point);
2731 if (!z) return z;
2732 z.fdx = dxdy;
2733 z.fdy = dxdy != 0.0f ? (1.0f/dxdy) : 0.0f;
2734 z.fx = e.x0 + dxdy * (start_point - e.y0);
2735 z.fx -= off_x;
2736 z.direction = e.invert ? 1.0f : -1.0f;
2737 z.sy = e.y0;
2738 z.ey = e.y1;
2739 z.next = null;
2740 return z;
2742 } else {
2743 static assert(0, "Unrecognized value of STBTT_RASTERIZER_VERSION");
2746 static if (STBTT_RASTERIZER_VERSION == 1) {
2747 // note: this routine clips fills that extend off the edges... ideally this
2748 // wouldn't happen, but it could happen if the truetype glyph bounding boxes
2749 // are wrong, or if the user supplies a too-small bitmap
2750 private void stbtt__fill_active_edges(ubyte *scanline, int len, stbtt__active_edge *e, int max_weight)
2752 // non-zero winding fill
2753 int x0=0, w=0;
2755 while (e) {
2756 if (w == 0) {
2757 // if we're currently at zero, we need to record the edge start point
2758 x0 = e.x; w += e.direction;
2759 } else {
2760 int x1 = e.x; w += e.direction;
2761 // if we went to zero, we need to draw
2762 if (w == 0) {
2763 int i = x0 >> STBTT_FIXSHIFT;
2764 int j = x1 >> STBTT_FIXSHIFT;
2766 if (i < len && j >= 0) {
2767 if (i == j) {
2768 // x0,x1 are the same pixel, so compute combined coverage
2769 scanline[i] = scanline[i] + cast(stbtt_uint8) ((x1 - x0) * max_weight >> STBTT_FIXSHIFT);
2770 } else {
2771 if (i >= 0) // add antialiasing for x0
2772 scanline[i] = scanline[i] + cast(stbtt_uint8) (((STBTT_FIX - (x0 & STBTT_FIXMASK)) * max_weight) >> STBTT_FIXSHIFT);
2773 else
2774 i = -1; // clip
2776 if (j < len) // add antialiasing for x1
2777 scanline[j] = scanline[j] + cast(stbtt_uint8) (((x1 & STBTT_FIXMASK) * max_weight) >> STBTT_FIXSHIFT);
2778 else
2779 j = len; // clip
2781 for (++i; i < j; ++i) // fill pixels between x0 and x1
2782 scanline[i] = scanline[i] + cast(stbtt_uint8) max_weight;
2788 e = e.next;
2792 private void stbtt__rasterize_sorted_edges(stbtt__bitmap *result, stbtt__edge *e, int n, int vsubsample, int off_x, int off_y, void *userdata)
2794 stbtt__hheap hh = { 0, 0, 0 };
2795 stbtt__active_edge *active = null;
2796 int y,j=0;
2797 int max_weight = (255 / vsubsample); // weight per vertical scanline
2798 int s; // vertical subsample index
2799 ubyte[512] scanline_data = void;
2800 ubyte *scanline;
2802 if (result.w > 512)
2803 scanline = cast(ubyte *) STBTT_malloc(result.w, userdata);
2804 else
2805 scanline = scanline_data;
2807 y = off_y * vsubsample;
2808 e[n].y0 = (off_y + result.h) * cast(float) vsubsample + 1;
2810 while (j < result.h) {
2811 STBTT_memset(scanline, 0, result.w);
2812 for (s=0; s < vsubsample; ++s) {
2813 // find center of pixel for this scanline
2814 float scan_y = y + 0.5f;
2815 stbtt__active_edge **step = &active;
2817 // update all active edges;
2818 // remove all active edges that terminate before the center of this scanline
2819 while (*step) {
2820 stbtt__active_edge * z = *step;
2821 if (z.ey <= scan_y) {
2822 *step = z.next; // delete from list
2823 assert(z.direction);
2824 z.direction = 0;
2825 stbtt__hheap_free(&hh, z);
2826 } else {
2827 z.x += z.dx; // advance to position for current scanline
2828 step = &((*step).next); // advance through list
2832 // resort the list if needed
2833 for(;;) {
2834 int changed=0;
2835 step = &active;
2836 while (*step && (*step).next) {
2837 if ((*step).x > (*step).next.x) {
2838 stbtt__active_edge *t = *step;
2839 stbtt__active_edge *q = t.next;
2841 t.next = q.next;
2842 q.next = t;
2843 *step = q;
2844 changed = 1;
2846 step = &(*step).next;
2848 if (!changed) break;
2851 // insert all edges that start before the center of this scanline -- omit ones that also end on this scanline
2852 while (e.y0 <= scan_y) {
2853 if (e.y1 > scan_y) {
2854 stbtt__active_edge *z = stbtt__new_active(&hh, e, off_x, scan_y, userdata);
2855 if (z != null) {
2856 // find insertion point
2857 if (active == null)
2858 active = z;
2859 else if (z.x < active.x) {
2860 // insert at front
2861 z.next = active;
2862 active = z;
2863 } else {
2864 // find thing to insert AFTER
2865 stbtt__active_edge *p = active;
2866 while (p.next && p.next.x < z.x)
2867 p = p.next;
2868 // at this point, p->next->x is NOT < z->x
2869 z.next = p.next;
2870 p.next = z;
2874 ++e;
2877 // now process all active edges in XOR fashion
2878 if (active)
2879 stbtt__fill_active_edges(scanline, result.w, active, max_weight);
2881 ++y;
2883 STBTT_memcpy(result.pixels + j * result.stride, scanline, result.w);
2884 ++j;
2887 stbtt__hheap_cleanup(&hh, userdata);
2889 if (scanline != scanline_data)
2890 STBTT_free(scanline, userdata);
2893 } else static if (STBTT_RASTERIZER_VERSION == 2) {
2895 // the edge passed in here does not cross the vertical line at x or the vertical line at x+1
2896 // (i.e. it has already been clipped to those)
2897 private void stbtt__handle_clipped_edge(float *scanline, int x, stbtt__active_edge *e, float x0, float y0, float x1, float y1)
2899 if (y0 == y1) return;
2900 assert(y0 < y1);
2901 assert(e.sy <= e.ey);
2902 if (y0 > e.ey) return;
2903 if (y1 < e.sy) return;
2904 if (y0 < e.sy) {
2905 x0 += (x1-x0) * (e.sy - y0) / (y1-y0);
2906 y0 = e.sy;
2908 if (y1 > e.ey) {
2909 x1 += (x1-x0) * (e.ey - y1) / (y1-y0);
2910 y1 = e.ey;
2913 if (x0 == x)
2914 assert(x1 <= x+1);
2915 else if (x0 == x+1)
2916 assert(x1 >= x);
2917 else if (x0 <= x)
2918 assert(x1 <= x);
2919 else if (x0 >= x+1)
2920 assert(x1 >= x+1);
2921 else
2922 assert(x1 >= x && x1 <= x+1);
2924 if (x0 <= x && x1 <= x)
2925 scanline[x] += e.direction * (y1-y0);
2926 else if (x0 >= x+1 && x1 >= x+1)
2928 else {
2929 assert(x0 >= x && x0 <= x+1 && x1 >= x && x1 <= x+1);
2930 scanline[x] += e.direction * (y1-y0) * (1-((x0-x)+(x1-x))/2); // coverage = 1 - average x position
2934 private void stbtt__fill_active_edges_new(float *scanline, float *scanline_fill, int len, stbtt__active_edge *e, float y_top)
2936 float y_bottom = y_top+1;
2938 while (e) {
2939 // brute force every pixel
2941 // compute intersection points with top & bottom
2942 assert(e.ey >= y_top);
2944 if (e.fdx == 0) {
2945 float x0 = e.fx;
2946 if (x0 < len) {
2947 if (x0 >= 0) {
2948 stbtt__handle_clipped_edge(scanline,cast(int) x0,e, x0,y_top, x0,y_bottom);
2949 stbtt__handle_clipped_edge(scanline_fill-1,cast(int) x0+1,e, x0,y_top, x0,y_bottom);
2950 } else {
2951 stbtt__handle_clipped_edge(scanline_fill-1,0,e, x0,y_top, x0,y_bottom);
2954 } else {
2955 float x0 = e.fx;
2956 float dx = e.fdx;
2957 float xb = x0 + dx;
2958 float x_top, x_bottom;
2959 float sy0,sy1;
2960 float dy = e.fdy;
2961 assert(e.sy <= y_bottom && e.ey >= y_top);
2963 // compute endpoints of line segment clipped to this scanline (if the
2964 // line segment starts on this scanline. x0 is the intersection of the
2965 // line with y_top, but that may be off the line segment.
2966 if (e.sy > y_top) {
2967 x_top = x0 + dx * (e.sy - y_top);
2968 sy0 = e.sy;
2969 } else {
2970 x_top = x0;
2971 sy0 = y_top;
2973 if (e.ey < y_bottom) {
2974 x_bottom = x0 + dx * (e.ey - y_top);
2975 sy1 = e.ey;
2976 } else {
2977 x_bottom = xb;
2978 sy1 = y_bottom;
2981 if (x_top >= 0 && x_bottom >= 0 && x_top < len && x_bottom < len) {
2982 // from here on, we don't have to range check x values
2984 if (cast(int) x_top == cast(int) x_bottom) {
2985 float height;
2986 // simple case, only spans one pixel
2987 int x = cast(int) x_top;
2988 height = sy1 - sy0;
2989 assert(x >= 0 && x < len);
2990 scanline[x] += e.direction * (1-((x_top - x) + (x_bottom-x))/2) * height;
2991 scanline_fill[x] += e.direction * height; // everything right of this pixel is filled
2992 } else {
2993 int x,x1,x2;
2994 float y_crossing, step, sign, area;
2995 // covers 2+ pixels
2996 if (x_top > x_bottom) {
2997 // flip scanline vertically; signed area is the same
2998 float t;
2999 sy0 = y_bottom - (sy0 - y_top);
3000 sy1 = y_bottom - (sy1 - y_top);
3001 t = sy0, sy0 = sy1, sy1 = t;
3002 t = x_bottom, x_bottom = x_top, x_top = t;
3003 dx = -dx;
3004 dy = -dy;
3005 t = x0, x0 = xb, xb = t;
3008 x1 = cast(int) x_top;
3009 x2 = cast(int) x_bottom;
3010 // compute intersection with y axis at x1+1
3011 y_crossing = (x1+1 - x0) * dy + y_top;
3013 sign = e.direction;
3014 // area of the rectangle covered from y0..y_crossing
3015 area = sign * (y_crossing-sy0);
3016 // area of the triangle (x_top,y0), (x+1,y0), (x+1,y_crossing)
3017 scanline[x1] += area * (1-((x_top - x1)+(x1+1-x1))/2);
3019 step = sign * dy;
3020 for (x = x1+1; x < x2; ++x) {
3021 scanline[x] += area + step/2;
3022 area += step;
3024 y_crossing += dy * (x2 - (x1+1));
3026 assert(STBTT_fabs(area) <= 1.01f);
3028 scanline[x2] += area + sign * (1-((x2-x2)+(x_bottom-x2))/2) * (sy1-y_crossing);
3030 scanline_fill[x2] += sign * (sy1-sy0);
3032 } else {
3033 // if edge goes outside of box we're drawing, we require
3034 // clipping logic. since this does not match the intended use
3035 // of this library, we use a different, very slow brute
3036 // force implementation
3037 int x;
3038 for (x=0; x < len; ++x) {
3039 // cases:
3041 // there can be up to two intersections with the pixel. any intersection
3042 // with left or right edges can be handled by splitting into two (or three)
3043 // regions. intersections with top & bottom do not necessitate case-wise logic.
3045 // the old way of doing this found the intersections with the left & right edges,
3046 // then used some simple logic to produce up to three segments in sorted order
3047 // from top-to-bottom. however, this had a problem: if an x edge was epsilon
3048 // across the x border, then the corresponding y position might not be distinct
3049 // from the other y segment, and it might ignored as an empty segment. to avoid
3050 // that, we need to explicitly produce segments based on x positions.
3052 // rename variables to clearly-defined pairs
3053 float y0 = y_top;
3054 float x1 = cast(float) (x);
3055 float x2 = cast(float) (x+1);
3056 float x3 = xb;
3057 float y3 = y_bottom;
3059 // x = e->x + e->dx * (y-y_top)
3060 // (y-y_top) = (x - e->x) / e->dx
3061 // y = (x - e->x) / e->dx + y_top
3062 float y1 = (x - x0) / dx + y_top;
3063 float y2 = (x+1 - x0) / dx + y_top;
3065 if (x0 < x1 && x3 > x2) { // three segments descending down-right
3066 stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x1,y1);
3067 stbtt__handle_clipped_edge(scanline,x,e, x1,y1, x2,y2);
3068 stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x3,y3);
3069 } else if (x3 < x1 && x0 > x2) { // three segments descending down-left
3070 stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x2,y2);
3071 stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x1,y1);
3072 stbtt__handle_clipped_edge(scanline,x,e, x1,y1, x3,y3);
3073 } else if (x0 < x1 && x3 > x1) { // two segments across x, down-right
3074 stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x1,y1);
3075 stbtt__handle_clipped_edge(scanline,x,e, x1,y1, x3,y3);
3076 } else if (x3 < x1 && x0 > x1) { // two segments across x, down-left
3077 stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x1,y1);
3078 stbtt__handle_clipped_edge(scanline,x,e, x1,y1, x3,y3);
3079 } else if (x0 < x2 && x3 > x2) { // two segments across x+1, down-right
3080 stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x2,y2);
3081 stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x3,y3);
3082 } else if (x3 < x2 && x0 > x2) { // two segments across x+1, down-left
3083 stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x2,y2);
3084 stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x3,y3);
3085 } else { // one segment
3086 stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x3,y3);
3091 e = e.next;
3095 // directly AA rasterize edges w/o supersampling
3096 private void stbtt__rasterize_sorted_edges(stbtt__bitmap *result, stbtt__edge *e, int n, int vsubsample, int off_x, int off_y, void *userdata)
3098 stbtt__hheap hh = stbtt__hheap( null, null, 0 );
3099 stbtt__active_edge *active = null;
3100 int y,j=0, i;
3101 float[129] scanline_data = void;
3102 float *scanline, scanline2;
3104 //STBTT__NOTUSED(vsubsample);
3106 if (result.w > 64)
3107 scanline = cast(float *) STBTT_malloc((result.w*2+1) * cast(uint)float.sizeof, userdata);
3108 else
3109 scanline = scanline_data.ptr;
3111 scanline2 = scanline + result.w;
3113 y = off_y;
3114 e[n].y0 = cast(float) (off_y + result.h) + 1;
3116 while (j < result.h) {
3117 // find center of pixel for this scanline
3118 float scan_y_top = y + 0.0f;
3119 float scan_y_bottom = y + 1.0f;
3120 stbtt__active_edge **step = &active;
3122 STBTT_memset(scanline , 0, result.w*cast(uint)scanline[0].sizeof);
3123 STBTT_memset(scanline2, 0, (result.w+1)*cast(uint)scanline[0].sizeof);
3125 // update all active edges;
3126 // remove all active edges that terminate before the top of this scanline
3127 while (*step) {
3128 stbtt__active_edge * z = *step;
3129 if (z.ey <= scan_y_top) {
3130 *step = z.next; // delete from list
3131 assert(z.direction);
3132 z.direction = 0;
3133 stbtt__hheap_free(&hh, z);
3134 } else {
3135 step = &((*step).next); // advance through list
3139 // insert all edges that start before the bottom of this scanline
3140 while (e.y0 <= scan_y_bottom) {
3141 if (e.y0 != e.y1) {
3142 stbtt__active_edge *z = stbtt__new_active(&hh, e, off_x, scan_y_top, userdata);
3143 if (z != null) {
3144 assert(z.ey >= scan_y_top);
3145 // insert at front
3146 z.next = active;
3147 active = z;
3150 ++e;
3153 // now process all active edges
3154 if (active)
3155 stbtt__fill_active_edges_new(scanline, scanline2+1, result.w, active, scan_y_top);
3158 float sum = 0;
3159 for (i=0; i < result.w; ++i) {
3160 float k;
3161 int m;
3162 sum += scanline2[i];
3163 k = scanline[i] + sum;
3164 k = cast(float) STBTT_fabs(k)*255 + 0.5f;
3165 m = cast(int) k;
3166 if (m > 255) m = 255;
3167 result.pixels[j*result.stride + i] = cast(ubyte) m;
3170 // advance all the edges
3171 step = &active;
3172 while (*step) {
3173 stbtt__active_edge *z = *step;
3174 z.fx += z.fdx; // advance to position for current scanline
3175 step = &((*step).next); // advance through list
3178 ++y;
3179 ++j;
3182 stbtt__hheap_cleanup(&hh, userdata);
3184 if (scanline !is scanline_data.ptr)
3185 STBTT_free(scanline, userdata);
3187 } else {
3188 static assert(0, "Unrecognized value of STBTT_RASTERIZER_VERSION");
3191 //#define STBTT__COMPARE(a,b) ((a).y0 < (b).y0)
3192 bool STBTT__COMPARE (stbtt__edge *a, stbtt__edge *b) pure { pragma(inline, true); return (a.y0 < b.y0); }
3194 private void stbtt__sort_edges_ins_sort(stbtt__edge *p, int n)
3196 int i,j;
3197 for (i=1; i < n; ++i) {
3198 stbtt__edge t = p[i];
3199 stbtt__edge *a = &t;
3200 j = i;
3201 while (j > 0) {
3202 stbtt__edge *b = &p[j-1];
3203 int c = STBTT__COMPARE(a,b);
3204 if (!c) break;
3205 p[j] = p[j-1];
3206 --j;
3208 if (i != j)
3209 p[j] = t;
3213 private void stbtt__sort_edges_quicksort(stbtt__edge *p, int n)
3215 /* threshhold for transitioning to insertion sort */
3216 while (n > 12) {
3217 stbtt__edge t;
3218 int c01,c12,c,m,i,j;
3220 /* compute median of three */
3221 m = n >> 1;
3222 c01 = STBTT__COMPARE(&p[0],&p[m]);
3223 c12 = STBTT__COMPARE(&p[m],&p[n-1]);
3224 /* if 0 >= mid >= end, or 0 < mid < end, then use mid */
3225 if (c01 != c12) {
3226 /* otherwise, we'll need to swap something else to middle */
3227 int z;
3228 c = STBTT__COMPARE(&p[0],&p[n-1]);
3229 /* 0>mid && mid<n: 0>n => n; 0<n => 0 */
3230 /* 0<mid && mid>n: 0>n => 0; 0<n => n */
3231 z = (c == c12) ? 0 : n-1;
3232 t = p[z];
3233 p[z] = p[m];
3234 p[m] = t;
3236 /* now p[m] is the median-of-three */
3237 /* swap it to the beginning so it won't move around */
3238 t = p[0];
3239 p[0] = p[m];
3240 p[m] = t;
3242 /* partition loop */
3243 i=1;
3244 j=n-1;
3245 for(;;) {
3246 /* handling of equality is crucial here */
3247 /* for sentinels & efficiency with duplicates */
3248 for (;;++i) {
3249 if (!STBTT__COMPARE(&p[i], &p[0])) break;
3251 for (;;--j) {
3252 if (!STBTT__COMPARE(&p[0], &p[j])) break;
3254 /* make sure we haven't crossed */
3255 if (i >= j) break;
3256 t = p[i];
3257 p[i] = p[j];
3258 p[j] = t;
3260 ++i;
3261 --j;
3263 /* recurse on smaller side, iterate on larger */
3264 if (j < (n-i)) {
3265 stbtt__sort_edges_quicksort(p,j);
3266 p = p+i;
3267 n = n-i;
3268 } else {
3269 stbtt__sort_edges_quicksort(p+i, n-i);
3270 n = j;
3275 private void stbtt__sort_edges(stbtt__edge *p, int n)
3277 stbtt__sort_edges_quicksort(p, n);
3278 stbtt__sort_edges_ins_sort(p, n);
3281 struct stbtt__point {
3282 float x,y;
3285 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)
3287 float y_scale_inv = invert ? -scale_y : scale_y;
3288 stbtt__edge *e;
3289 int n,i,j,k,m;
3290 static if (STBTT_RASTERIZER_VERSION == 1) {
3291 int vsubsample = result.h < 8 ? 15 : 5;
3292 } else static if (STBTT_RASTERIZER_VERSION == 2) {
3293 int vsubsample = 1;
3294 } else {
3295 static assert(0, "Unrecognized value of STBTT_RASTERIZER_VERSION");
3297 // vsubsample should divide 255 evenly; otherwise we won't reach full opacity
3299 // now we have to blow out the windings into explicit edge lists
3300 n = 0;
3301 for (i=0; i < windings; ++i)
3302 n += wcount[i];
3304 e = cast(stbtt__edge *) STBTT_malloc(cast(uint)(*e).sizeof * (n+1), userdata); // add an extra one as a sentinel
3305 if (e is null) return;
3306 n = 0;
3308 m=0;
3309 for (i=0; i < windings; ++i) {
3310 stbtt__point *p = pts + m;
3311 m += wcount[i];
3312 j = wcount[i]-1;
3313 for (k=0; k < wcount[i]; j=k++) {
3314 int a=k,b=j;
3315 // skip the edge if horizontal
3316 if (p[j].y == p[k].y)
3317 continue;
3318 // add edge from j to k to the list
3319 e[n].invert = 0;
3320 if (invert ? p[j].y > p[k].y : p[j].y < p[k].y) {
3321 e[n].invert = 1;
3322 a=j,b=k;
3324 e[n].x0 = p[a].x * scale_x + shift_x;
3325 e[n].y0 = (p[a].y * y_scale_inv + shift_y) * vsubsample;
3326 e[n].x1 = p[b].x * scale_x + shift_x;
3327 e[n].y1 = (p[b].y * y_scale_inv + shift_y) * vsubsample;
3328 ++n;
3332 // now sort the edges by their highest point (should snap to integer, and then by x)
3333 //STBTT_sort(e, n, e[0].sizeof, stbtt__edge_compare);
3334 stbtt__sort_edges(e, n);
3336 // now, traverse the scanlines and find the intersections on each scanline, use xor winding rule
3337 stbtt__rasterize_sorted_edges(result, e, n, vsubsample, off_x, off_y, userdata);
3339 STBTT_free(e, userdata);
3342 private void stbtt__add_point(stbtt__point *points, int n, float x, float y)
3344 if (!points) return; // during first pass, it's unallocated
3345 points[n].x = x;
3346 points[n].y = y;
3349 // tesselate until threshhold p is happy... @TODO warped to compensate for non-linear stretching
3350 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)
3352 // midpoint
3353 float mx = (x0 + 2*x1 + x2)/4;
3354 float my = (y0 + 2*y1 + y2)/4;
3355 // versus directly drawn line
3356 float dx = (x0+x2)/2 - mx;
3357 float dy = (y0+y2)/2 - my;
3358 if (n > 16) // 65536 segments on one curve better be enough!
3359 return 1;
3360 if (dx*dx+dy*dy > objspace_flatness_squared) { // half-pixel error allowed... need to be smaller if AA
3361 stbtt__tesselate_curve(points, num_points, x0,y0, (x0+x1)/2.0f,(y0+y1)/2.0f, mx,my, objspace_flatness_squared,n+1);
3362 stbtt__tesselate_curve(points, num_points, mx,my, (x1+x2)/2.0f,(y1+y2)/2.0f, x2,y2, objspace_flatness_squared,n+1);
3363 } else {
3364 stbtt__add_point(points, *num_points,x2,y2);
3365 *num_points = *num_points+1;
3367 return 1;
3370 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)
3372 // @TODO this "flatness" calculation is just made-up nonsense that seems to work well enough
3373 float dx0 = x1-x0;
3374 float dy0 = y1-y0;
3375 float dx1 = x2-x1;
3376 float dy1 = y2-y1;
3377 float dx2 = x3-x2;
3378 float dy2 = y3-y2;
3379 float dx = x3-x0;
3380 float dy = y3-y0;
3381 float longlen = cast(float) (STBTT_sqrt(dx0*dx0+dy0*dy0)+STBTT_sqrt(dx1*dx1+dy1*dy1)+STBTT_sqrt(dx2*dx2+dy2*dy2));
3382 float shortlen = cast(float) STBTT_sqrt(dx*dx+dy*dy);
3383 float flatness_squared = longlen*longlen-shortlen*shortlen;
3385 if (n > 16) // 65536 segments on one curve better be enough!
3386 return;
3388 if (flatness_squared > objspace_flatness_squared) {
3389 float x01 = (x0+x1)/2;
3390 float y01 = (y0+y1)/2;
3391 float x12 = (x1+x2)/2;
3392 float y12 = (y1+y2)/2;
3393 float x23 = (x2+x3)/2;
3394 float y23 = (y2+y3)/2;
3396 float xa = (x01+x12)/2;
3397 float ya = (y01+y12)/2;
3398 float xb = (x12+x23)/2;
3399 float yb = (y12+y23)/2;
3401 float mx = (xa+xb)/2;
3402 float my = (ya+yb)/2;
3404 stbtt__tesselate_cubic(points, num_points, x0,y0, x01,y01, xa,ya, mx,my, objspace_flatness_squared,n+1);
3405 stbtt__tesselate_cubic(points, num_points, mx,my, xb,yb, x23,y23, x3,y3, objspace_flatness_squared,n+1);
3406 } else {
3407 stbtt__add_point(points, *num_points,x3,y3);
3408 *num_points = *num_points+1;
3412 // returns number of contours
3413 private stbtt__point *stbtt_FlattenCurves(stbtt_vertex *vertices, int num_verts, float objspace_flatness, int **contour_lengths, int *num_contours, void *userdata)
3415 stbtt__point *points = null;
3416 int num_points=0;
3418 float objspace_flatness_squared = objspace_flatness * objspace_flatness;
3419 int i,n=0,start=0, pass;
3421 // count how many "moves" there are to get the contour count
3422 for (i=0; i < num_verts; ++i)
3423 if (vertices[i].type == STBTT_vmove)
3424 ++n;
3426 *num_contours = n;
3427 if (n == 0) return null;
3429 *contour_lengths = cast(int *) STBTT_malloc(cast(uint)(**contour_lengths).sizeof * n, userdata);
3431 if (*contour_lengths is null) {
3432 *num_contours = 0;
3433 return null;
3436 // make two passes through the points so we don't need to realloc
3437 for (pass=0; pass < 2; ++pass) {
3438 float x=0,y=0;
3439 if (pass == 1) {
3440 points = cast(stbtt__point *) STBTT_malloc(num_points * cast(uint)points[0].sizeof, userdata);
3441 if (points == null) goto error;
3443 num_points = 0;
3444 n= -1;
3445 for (i=0; i < num_verts; ++i) {
3446 switch (vertices[i].type) {
3447 case STBTT_vmove:
3448 // start the next contour
3449 if (n >= 0)
3450 (*contour_lengths)[n] = num_points - start;
3451 ++n;
3452 start = num_points;
3454 x = vertices[i].x, y = vertices[i].y;
3455 stbtt__add_point(points, num_points++, x,y);
3456 break;
3457 case STBTT_vline:
3458 x = vertices[i].x, y = vertices[i].y;
3459 stbtt__add_point(points, num_points++, x, y);
3460 break;
3461 case STBTT_vcurve:
3462 stbtt__tesselate_curve(points, &num_points, x,y,
3463 vertices[i].cx, vertices[i].cy,
3464 vertices[i].x, vertices[i].y,
3465 objspace_flatness_squared, 0);
3466 x = vertices[i].x, y = vertices[i].y;
3467 break;
3468 case STBTT_vcubic:
3469 stbtt__tesselate_cubic(points, &num_points, x,y,
3470 vertices[i].cx, vertices[i].cy,
3471 vertices[i].cx1, vertices[i].cy1,
3472 vertices[i].x, vertices[i].y,
3473 objspace_flatness_squared, 0);
3474 x = vertices[i].x, y = vertices[i].y;
3475 break;
3476 default:
3479 (*contour_lengths)[n] = num_points - start;
3482 return points;
3483 error:
3484 STBTT_free(points, userdata);
3485 STBTT_free(*contour_lengths, userdata);
3486 *contour_lengths = null;
3487 *num_contours = 0;
3488 return null;
3491 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)
3493 float scale = scale_x > scale_y ? scale_y : scale_x;
3494 int winding_count = 0;
3495 int *winding_lengths = null;
3496 stbtt__point *windings = stbtt_FlattenCurves(vertices, num_verts, flatness_in_pixels / scale, &winding_lengths, &winding_count, userdata);
3497 if (windings) {
3498 stbtt__rasterize(result, windings, winding_lengths, winding_count, scale_x, scale_y, shift_x, shift_y, x_off, y_off, invert, userdata);
3499 STBTT_free(winding_lengths, userdata);
3500 STBTT_free(windings, userdata);
3504 public void stbtt_FreeBitmap(ubyte *bitmap, void *userdata)
3506 STBTT_free(bitmap, userdata);
3509 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)
3511 int ix0,iy0,ix1,iy1;
3512 stbtt__bitmap gbm;
3513 stbtt_vertex *vertices;
3514 int num_verts = stbtt_GetGlyphShape(info, glyph, &vertices);
3516 if (scale_x == 0) scale_x = scale_y;
3517 if (scale_y == 0) {
3518 if (scale_x == 0) {
3519 STBTT_free(vertices, info.userdata);
3520 return null;
3522 scale_y = scale_x;
3525 stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale_x, scale_y, shift_x, shift_y, &ix0,&iy0,&ix1,&iy1);
3527 // now we get the size
3528 gbm.w = (ix1 - ix0);
3529 gbm.h = (iy1 - iy0);
3530 gbm.pixels = null; // in case we error
3532 if (width ) *width = gbm.w;
3533 if (height) *height = gbm.h;
3534 if (xoff ) *xoff = ix0;
3535 if (yoff ) *yoff = iy0;
3537 if (gbm.w && gbm.h) {
3538 gbm.pixels = cast(ubyte *) STBTT_malloc(gbm.w * gbm.h, info.userdata);
3539 if (gbm.pixels) {
3540 gbm.stride = gbm.w;
3542 stbtt_Rasterize(&gbm, 0.35f, vertices, num_verts, scale_x, scale_y, shift_x, shift_y, ix0, iy0, 1, info.userdata);
3545 STBTT_free(vertices, info.userdata);
3546 return gbm.pixels;
3549 public ubyte *stbtt_GetGlyphBitmap(stbtt_fontinfo* info, float scale_x, float scale_y, int glyph, int *width, int *height, int *xoff, int *yoff)
3551 return stbtt_GetGlyphBitmapSubpixel(info, scale_x, scale_y, 0.0f, 0.0f, glyph, width, height, xoff, yoff);
3554 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)
3556 int ix0,iy0;
3557 stbtt_vertex *vertices;
3558 int num_verts = stbtt_GetGlyphShape(info, glyph, &vertices);
3559 stbtt__bitmap gbm;
3561 stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale_x, scale_y, shift_x, shift_y, &ix0,&iy0, null, null);
3562 gbm.pixels = output;
3563 gbm.w = out_w;
3564 gbm.h = out_h;
3565 gbm.stride = out_stride;
3567 if (gbm.w && gbm.h)
3568 stbtt_Rasterize(&gbm, 0.35f, vertices, num_verts, scale_x, scale_y, shift_x, shift_y, ix0,iy0, 1, info.userdata);
3570 STBTT_free(vertices, info.userdata);
3573 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)
3575 stbtt_MakeGlyphBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, scale_y, 0.0f,0.0f, glyph);
3578 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)
3580 return stbtt_GetGlyphBitmapSubpixel(info, scale_x, scale_y,shift_x,shift_y, stbtt_FindGlyphIndex(info,codepoint), width,height,xoff,yoff);
3583 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)
3585 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));
3588 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)
3590 stbtt_MakeGlyphBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, scale_y, shift_x, shift_y, stbtt_FindGlyphIndex(info,codepoint));
3593 public ubyte *stbtt_GetCodepointBitmap(stbtt_fontinfo* info, float scale_x, float scale_y, int codepoint, int *width, int *height, int *xoff, int *yoff)
3595 return stbtt_GetCodepointBitmapSubpixel(info, scale_x, scale_y, 0.0f,0.0f, codepoint, width,height,xoff,yoff);
3598 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)
3600 stbtt_MakeCodepointBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, scale_y, 0.0f,0.0f, codepoint);
3603 //////////////////////////////////////////////////////////////////////////////
3605 // bitmap baking
3607 // This is SUPER-CRAPPY packing to keep source code small
3609 private int stbtt_BakeFontBitmap_internal(ubyte *data, int offset, // font location (use offset=0 for plain .ttf)
3610 float pixel_height, // height of font in pixels
3611 ubyte *pixels, int pw, int ph, // bitmap to be filled in
3612 int first_char, int num_chars, // characters to bake
3613 stbtt_bakedchar *chardata)
3615 float scale;
3616 int x,y,bottom_y, i;
3617 stbtt_fontinfo f;
3618 f.userdata = null;
3619 if (!stbtt_InitFont(&f, data, offset))
3620 return -1;
3621 STBTT_memset(pixels, 0, pw*ph); // background of 0 around pixels
3622 x=y=1;
3623 bottom_y = 1;
3625 scale = stbtt_ScaleForPixelHeight(&f, pixel_height);
3627 for (i=0; i < num_chars; ++i) {
3628 int advance, lsb, x0,y0,x1,y1,gw,gh;
3629 int g = stbtt_FindGlyphIndex(&f, first_char + i);
3630 stbtt_GetGlyphHMetrics(&f, g, &advance, &lsb);
3631 stbtt_GetGlyphBitmapBox(&f, g, scale,scale, &x0,&y0,&x1,&y1);
3632 gw = x1-x0;
3633 gh = y1-y0;
3634 if (x + gw + 1 >= pw)
3635 y = bottom_y, x = 1; // advance to next row
3636 if (y + gh + 1 >= ph) // check if it fits vertically AFTER potentially moving to next row
3637 return -i;
3638 assert(x+gw < pw);
3639 assert(y+gh < ph);
3640 stbtt_MakeGlyphBitmap(&f, pixels+x+y*pw, gw,gh,pw, scale,scale, g);
3641 chardata[i].x0 = cast(stbtt_int16) x;
3642 chardata[i].y0 = cast(stbtt_int16) y;
3643 chardata[i].x1 = cast(stbtt_int16) (x + gw);
3644 chardata[i].y1 = cast(stbtt_int16) (y + gh);
3645 chardata[i].xadvance = scale * advance;
3646 chardata[i].xoff = cast(float) x0;
3647 chardata[i].yoff = cast(float) y0;
3648 x = x + gw + 1;
3649 if (y+gh+1 > bottom_y)
3650 bottom_y = y+gh+1;
3652 return bottom_y;
3655 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)
3657 float d3d_bias = opengl_fillrule ? 0 : -0.5f;
3658 float ipw = 1.0f / pw, iph = 1.0f / ph;
3659 const(stbtt_bakedchar)* b = chardata + char_index;
3660 int round_x = STBTT_ifloor((*xpos + b.xoff) + 0.5f);
3661 int round_y = STBTT_ifloor((*ypos + b.yoff) + 0.5f);
3663 q.x0 = round_x + d3d_bias;
3664 q.y0 = round_y + d3d_bias;
3665 q.x1 = round_x + b.x1 - b.x0 + d3d_bias;
3666 q.y1 = round_y + b.y1 - b.y0 + d3d_bias;
3668 q.s0 = b.x0 * ipw;
3669 q.t0 = b.y0 * iph;
3670 q.s1 = b.x1 * ipw;
3671 q.t1 = b.y1 * iph;
3673 *xpos += b.xadvance;
3676 //////////////////////////////////////////////////////////////////////////////
3678 // rectangle packing replacement routines if you don't have stb_rect_pack.h
3681 version(STB_RECT_PACK_VERSION) {
3683 alias stbrp_coord = int;
3685 // //////////////////////////////////////////////////////////////////////////////////
3686 // //
3687 // //
3688 // COMPILER WARNING ?!?!? //
3689 // //
3690 // //
3691 // if you get a compile warning due to these symbols being defined more than //
3692 // once, move #include "stb_rect_pack.h" before #include "stb_truetype.h" //
3693 // //
3694 // //////////////////////////////////////////////////////////////////////////////////
3696 struct stbrp_context {
3697 int width,height;
3698 int x,y,bottom_y;
3701 struct stbrp_node {
3702 ubyte x;
3705 struct stbrp_rect {
3706 stbrp_coord x,y;
3707 int id,w,h,was_packed;
3710 private void stbrp_init_target(stbrp_context *con, int pw, int ph, stbrp_node *nodes, int num_nodes)
3712 con.width = pw;
3713 con.height = ph;
3714 con.x = 0;
3715 con.y = 0;
3716 con.bottom_y = 0;
3717 //STBTT__NOTUSED(nodes);
3718 //STBTT__NOTUSED(num_nodes);
3721 private void stbrp_pack_rects(stbrp_context *con, stbrp_rect *rects, int num_rects)
3723 int i;
3724 for (i=0; i < num_rects; ++i) {
3725 if (con.x + rects[i].w > con.width) {
3726 con.x = 0;
3727 con.y = con.bottom_y;
3729 if (con.y + rects[i].h > con.height)
3730 break;
3731 rects[i].x = con.x;
3732 rects[i].y = con.y;
3733 rects[i].was_packed = 1;
3734 con.x += rects[i].w;
3735 if (con.y + rects[i].h > con.bottom_y)
3736 con.bottom_y = con.y + rects[i].h;
3738 for ( ; i < num_rects; ++i)
3739 rects[i].was_packed = 0;
3744 // ////////////////////////////////////////////////////////////////////////////
3746 // bitmap baking
3748 // This is SUPER-AWESOME (tm Ryan Gordon) packing using stb_rect_pack.h. If
3749 // stb_rect_pack.h isn't available, it uses the BakeFontBitmap strategy.
3751 public int stbtt_PackBegin(stbtt_pack_context *spc, ubyte *pixels, int pw, int ph, int stride_in_bytes, int padding, void *alloc_context)
3753 stbrp_context *context = void;
3754 context = cast(stbrp_context *) STBTT_malloc(cast(uint)(*context).sizeof ,alloc_context);
3755 int num_nodes = pw - padding;
3756 stbrp_node *nodes = void;
3757 nodes = cast(stbrp_node *) STBTT_malloc(cast(uint)(*nodes ).sizeof * num_nodes,alloc_context);
3759 if (context == null || nodes == null) {
3760 if (context != null) STBTT_free(context, alloc_context);
3761 if (nodes != null) STBTT_free(nodes , alloc_context);
3762 return 0;
3765 spc.user_allocator_context = alloc_context;
3766 spc.width = pw;
3767 spc.height = ph;
3768 spc.pixels = pixels;
3769 spc.pack_info = context;
3770 spc.nodes = nodes;
3771 spc.padding = padding;
3772 spc.stride_in_bytes = stride_in_bytes != 0 ? stride_in_bytes : pw;
3773 spc.h_oversample = 1;
3774 spc.v_oversample = 1;
3776 stbrp_init_target(context, pw-padding, ph-padding, nodes, num_nodes);
3778 if (pixels)
3779 STBTT_memset(pixels, 0, pw*ph); // background of 0 around pixels
3781 return 1;
3784 public void stbtt_PackEnd (stbtt_pack_context *spc)
3786 STBTT_free(spc.nodes , spc.user_allocator_context);
3787 STBTT_free(spc.pack_info, spc.user_allocator_context);
3790 public void stbtt_PackSetOversampling(stbtt_pack_context *spc, uint h_oversample, uint v_oversample)
3792 assert(h_oversample <= STBTT_MAX_OVERSAMPLE);
3793 assert(v_oversample <= STBTT_MAX_OVERSAMPLE);
3794 if (h_oversample <= STBTT_MAX_OVERSAMPLE)
3795 spc.h_oversample = h_oversample;
3796 if (v_oversample <= STBTT_MAX_OVERSAMPLE)
3797 spc.v_oversample = v_oversample;
3800 enum STBTT__OVER_MASK = (STBTT_MAX_OVERSAMPLE-1);
3802 private void stbtt__h_prefilter(ubyte *pixels, int w, int h, int stride_in_bytes, uint kernel_width)
3804 ubyte[STBTT_MAX_OVERSAMPLE] buffer = void;
3805 int safe_w = w - kernel_width;
3806 int j;
3807 STBTT_memset(buffer.ptr, 0, STBTT_MAX_OVERSAMPLE); // suppress bogus warning from VS2013 -analyze
3808 for (j=0; j < h; ++j) {
3809 int i;
3810 uint total;
3811 STBTT_memset(buffer.ptr, 0, kernel_width);
3813 total = 0;
3815 // make kernel_width a constant in common cases so compiler can optimize out the divide
3816 switch (kernel_width) {
3817 case 2:
3818 for (i=0; i <= safe_w; ++i) {
3819 total += pixels[i] - buffer[i & STBTT__OVER_MASK];
3820 buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i];
3821 pixels[i] = cast(ubyte) (total / 2);
3823 break;
3824 case 3:
3825 for (i=0; i <= safe_w; ++i) {
3826 total += pixels[i] - buffer[i & STBTT__OVER_MASK];
3827 buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i];
3828 pixels[i] = cast(ubyte) (total / 3);
3830 break;
3831 case 4:
3832 for (i=0; i <= safe_w; ++i) {
3833 total += pixels[i] - buffer[i & STBTT__OVER_MASK];
3834 buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i];
3835 pixels[i] = cast(ubyte) (total / 4);
3837 break;
3838 case 5:
3839 for (i=0; i <= safe_w; ++i) {
3840 total += pixels[i] - buffer[i & STBTT__OVER_MASK];
3841 buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i];
3842 pixels[i] = cast(ubyte) (total / 5);
3844 break;
3845 default:
3846 for (i=0; i <= safe_w; ++i) {
3847 total += pixels[i] - buffer[i & STBTT__OVER_MASK];
3848 buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i];
3849 pixels[i] = cast(ubyte) (total / kernel_width);
3851 break;
3854 for (; i < w; ++i) {
3855 assert(pixels[i] == 0);
3856 total -= buffer[i & STBTT__OVER_MASK];
3857 pixels[i] = cast(ubyte) (total / kernel_width);
3860 pixels += stride_in_bytes;
3864 private void stbtt__v_prefilter(ubyte *pixels, int w, int h, int stride_in_bytes, uint kernel_width)
3866 ubyte[STBTT_MAX_OVERSAMPLE] buffer = void;
3867 int safe_h = h - kernel_width;
3868 int j;
3869 STBTT_memset(buffer.ptr, 0, STBTT_MAX_OVERSAMPLE); // suppress bogus warning from VS2013 -analyze
3870 for (j=0; j < w; ++j) {
3871 int i;
3872 uint total;
3873 STBTT_memset(buffer.ptr, 0, kernel_width);
3875 total = 0;
3877 // make kernel_width a constant in common cases so compiler can optimize out the divide
3878 switch (kernel_width) {
3879 case 2:
3880 for (i=0; i <= safe_h; ++i) {
3881 total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK];
3882 buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes];
3883 pixels[i*stride_in_bytes] = cast(ubyte) (total / 2);
3885 break;
3886 case 3:
3887 for (i=0; i <= safe_h; ++i) {
3888 total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK];
3889 buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes];
3890 pixels[i*stride_in_bytes] = cast(ubyte) (total / 3);
3892 break;
3893 case 4:
3894 for (i=0; i <= safe_h; ++i) {
3895 total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK];
3896 buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes];
3897 pixels[i*stride_in_bytes] = cast(ubyte) (total / 4);
3899 break;
3900 case 5:
3901 for (i=0; i <= safe_h; ++i) {
3902 total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK];
3903 buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes];
3904 pixels[i*stride_in_bytes] = cast(ubyte) (total / 5);
3906 break;
3907 default:
3908 for (i=0; i <= safe_h; ++i) {
3909 total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK];
3910 buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes];
3911 pixels[i*stride_in_bytes] = cast(ubyte) (total / kernel_width);
3913 break;
3916 for (; i < h; ++i) {
3917 assert(pixels[i*stride_in_bytes] == 0);
3918 total -= buffer[i & STBTT__OVER_MASK];
3919 pixels[i*stride_in_bytes] = cast(ubyte) (total / kernel_width);
3922 pixels += 1;
3926 private float stbtt__oversample_shift(int oversample)
3928 if (!oversample)
3929 return 0.0f;
3931 // The prefilter is a box filter of width "oversample",
3932 // which shifts phase by (oversample - 1)/2 pixels in
3933 // oversampled space. We want to shift in the opposite
3934 // direction to counter this.
3935 return cast(float)-(oversample - 1) / (2.0f * cast(float)oversample);
3938 // rects array must be big enough to accommodate all characters in the given ranges
3939 public int stbtt_PackFontRangesGatherRects(stbtt_pack_context *spc, stbtt_fontinfo* info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects)
3941 int i,j,k;
3943 k=0;
3944 for (i=0; i < num_ranges; ++i) {
3945 float fh = ranges[i].font_size;
3946 float scale = fh > 0 ? stbtt_ScaleForPixelHeight(info, fh) : stbtt_ScaleForMappingEmToPixels(info, -fh);
3947 ranges[i].h_oversample = cast(ubyte) spc.h_oversample;
3948 ranges[i].v_oversample = cast(ubyte) spc.v_oversample;
3949 for (j=0; j < ranges[i].num_chars; ++j) {
3950 int x0,y0,x1,y1;
3951 int codepoint = ranges[i].array_of_unicode_codepoints == null ? ranges[i].first_unicode_codepoint_in_range + j : ranges[i].array_of_unicode_codepoints[j];
3952 int glyph = stbtt_FindGlyphIndex(info, codepoint);
3953 stbtt_GetGlyphBitmapBoxSubpixel(info,glyph,
3954 scale * spc.h_oversample,
3955 scale * spc.v_oversample,
3956 0,0,
3957 &x0,&y0,&x1,&y1);
3958 rects[k].w = cast(stbrp_coord) (x1-x0 + spc.padding + spc.h_oversample-1);
3959 rects[k].h = cast(stbrp_coord) (y1-y0 + spc.padding + spc.v_oversample-1);
3960 ++k;
3964 return k;
3967 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)
3969 stbtt_MakeGlyphBitmapSubpixel(info,
3970 output,
3971 out_w - (prefilter_x - 1),
3972 out_h - (prefilter_y - 1),
3973 out_stride,
3974 scale_x,
3975 scale_y,
3976 shift_x,
3977 shift_y,
3978 glyph);
3980 if (prefilter_x > 1)
3981 stbtt__h_prefilter(output, out_w, out_h, out_stride, prefilter_x);
3983 if (prefilter_y > 1)
3984 stbtt__v_prefilter(output, out_w, out_h, out_stride, prefilter_y);
3986 *sub_x = stbtt__oversample_shift(prefilter_x);
3987 *sub_y = stbtt__oversample_shift(prefilter_y);
3990 // rects array must be big enough to accommodate all characters in the given ranges
3991 public int stbtt_PackFontRangesRenderIntoRects(stbtt_pack_context *spc, stbtt_fontinfo* info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects)
3993 int i,j,k, return_value = 1;
3995 // save current values
3996 int old_h_over = spc.h_oversample;
3997 int old_v_over = spc.v_oversample;
3999 k = 0;
4000 for (i=0; i < num_ranges; ++i) {
4001 float fh = ranges[i].font_size;
4002 float scale = fh > 0 ? stbtt_ScaleForPixelHeight(info, fh) : stbtt_ScaleForMappingEmToPixels(info, -fh);
4003 float recip_h,recip_v,sub_x,sub_y;
4004 spc.h_oversample = ranges[i].h_oversample;
4005 spc.v_oversample = ranges[i].v_oversample;
4006 recip_h = 1.0f / spc.h_oversample;
4007 recip_v = 1.0f / spc.v_oversample;
4008 sub_x = stbtt__oversample_shift(spc.h_oversample);
4009 sub_y = stbtt__oversample_shift(spc.v_oversample);
4010 for (j=0; j < ranges[i].num_chars; ++j) {
4011 stbrp_rect *r = &rects[k];
4012 if (r.was_packed) {
4013 stbtt_packedchar *bc = &ranges[i].chardata_for_range[j];
4014 int advance, lsb, x0,y0,x1,y1;
4015 int codepoint = ranges[i].array_of_unicode_codepoints == null ? ranges[i].first_unicode_codepoint_in_range + j : ranges[i].array_of_unicode_codepoints[j];
4016 int glyph = stbtt_FindGlyphIndex(info, codepoint);
4017 stbrp_coord pad = cast(stbrp_coord) spc.padding;
4019 // pad on left and top
4020 r.x += pad;
4021 r.y += pad;
4022 r.w -= pad;
4023 r.h -= pad;
4024 stbtt_GetGlyphHMetrics(info, glyph, &advance, &lsb);
4025 stbtt_GetGlyphBitmapBox(info, glyph,
4026 scale * spc.h_oversample,
4027 scale * spc.v_oversample,
4028 &x0,&y0,&x1,&y1);
4029 stbtt_MakeGlyphBitmapSubpixel(info,
4030 spc.pixels + r.x + r.y*spc.stride_in_bytes,
4031 r.w - spc.h_oversample+1,
4032 r.h - spc.v_oversample+1,
4033 spc.stride_in_bytes,
4034 scale * spc.h_oversample,
4035 scale * spc.v_oversample,
4036 0,0,
4037 glyph);
4039 if (spc.h_oversample > 1)
4040 stbtt__h_prefilter(spc.pixels + r.x + r.y*spc.stride_in_bytes,
4041 r.w, r.h, spc.stride_in_bytes,
4042 spc.h_oversample);
4044 if (spc.v_oversample > 1)
4045 stbtt__v_prefilter(spc.pixels + r.x + r.y*spc.stride_in_bytes,
4046 r.w, r.h, spc.stride_in_bytes,
4047 spc.v_oversample);
4049 bc.x0 = cast(stbtt_int16) r.x;
4050 bc.y0 = cast(stbtt_int16) r.y;
4051 bc.x1 = cast(stbtt_int16) (r.x + r.w);
4052 bc.y1 = cast(stbtt_int16) (r.y + r.h);
4053 bc.xadvance = scale * advance;
4054 bc.xoff = cast(float) x0 * recip_h + sub_x;
4055 bc.yoff = cast(float) y0 * recip_v + sub_y;
4056 bc.xoff2 = (x0 + r.w) * recip_h + sub_x;
4057 bc.yoff2 = (y0 + r.h) * recip_v + sub_y;
4058 } else {
4059 return_value = 0; // if any fail, report failure
4062 ++k;
4066 // restore original values
4067 spc.h_oversample = old_h_over;
4068 spc.v_oversample = old_v_over;
4070 return return_value;
4073 public void stbtt_PackFontRangesPackRects(stbtt_pack_context *spc, stbrp_rect *rects, int num_rects)
4075 stbrp_pack_rects(cast(stbrp_context *) spc.pack_info, rects, num_rects);
4078 public int stbtt_PackFontRanges(stbtt_pack_context *spc, const(ubyte)* fontdata, int font_index, stbtt_pack_range *ranges, int num_ranges)
4080 stbtt_fontinfo info;
4081 int i,j,n, return_value = 1;
4082 //stbrp_context *context = (stbrp_context *) spc->pack_info;
4083 stbrp_rect *rects;
4085 // flag all characters as NOT packed
4086 for (i=0; i < num_ranges; ++i)
4087 for (j=0; j < ranges[i].num_chars; ++j)
4088 ranges[i].chardata_for_range[j].x0 =
4089 ranges[i].chardata_for_range[j].y0 =
4090 ranges[i].chardata_for_range[j].x1 =
4091 ranges[i].chardata_for_range[j].y1 = 0;
4093 n = 0;
4094 for (i=0; i < num_ranges; ++i)
4095 n += ranges[i].num_chars;
4097 rects = cast(stbrp_rect *) STBTT_malloc(cast(uint)(*rects).sizeof * n, spc.user_allocator_context);
4098 if (rects == null)
4099 return 0;
4101 info.userdata = spc.user_allocator_context;
4102 stbtt_InitFont(&info, fontdata, stbtt_GetFontOffsetForIndex(fontdata,font_index));
4104 n = stbtt_PackFontRangesGatherRects(spc, &info, ranges, num_ranges, rects);
4106 stbtt_PackFontRangesPackRects(spc, rects, n);
4108 return_value = stbtt_PackFontRangesRenderIntoRects(spc, &info, ranges, num_ranges, rects);
4110 STBTT_free(rects, spc.user_allocator_context);
4111 return return_value;
4114 public int stbtt_PackFontRange(stbtt_pack_context *spc, const(ubyte)* fontdata, int font_index, float font_size,
4115 int first_unicode_codepoint_in_range, int num_chars_in_range, stbtt_packedchar *chardata_for_range)
4117 stbtt_pack_range range;
4118 range.first_unicode_codepoint_in_range = first_unicode_codepoint_in_range;
4119 range.array_of_unicode_codepoints = null;
4120 range.num_chars = num_chars_in_range;
4121 range.chardata_for_range = chardata_for_range;
4122 range.font_size = font_size;
4123 return stbtt_PackFontRanges(spc, fontdata, font_index, &range, 1);
4126 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)
4128 float ipw = 1.0f / pw, iph = 1.0f / ph;
4129 const(stbtt_packedchar)* b = chardata + char_index;
4131 if (align_to_integer) {
4132 float x = cast(float) STBTT_ifloor((*xpos + b.xoff) + 0.5f);
4133 float y = cast(float) STBTT_ifloor((*ypos + b.yoff) + 0.5f);
4134 q.x0 = x;
4135 q.y0 = y;
4136 q.x1 = x + b.xoff2 - b.xoff;
4137 q.y1 = y + b.yoff2 - b.yoff;
4138 } else {
4139 q.x0 = *xpos + b.xoff;
4140 q.y0 = *ypos + b.yoff;
4141 q.x1 = *xpos + b.xoff2;
4142 q.y1 = *ypos + b.yoff2;
4145 q.s0 = b.x0 * ipw;
4146 q.t0 = b.y0 * iph;
4147 q.s1 = b.x1 * ipw;
4148 q.t1 = b.y1 * iph;
4150 *xpos += b.xadvance;
4153 //////////////////////////////////////////////////////////////////////////////
4155 // sdf computation
4158 //#define STBTT_min(a,b) ((a) < (b) ? (a) : (b))
4159 //#define STBTT_max(a,b) ((a) < (b) ? (b) : (a))
4160 T STBTT_min(T) (in T a, in T b) pure { pragma(inline, true); return (a < b ? a : b); }
4161 T STBTT_max(T) (in T a, in T b) pure { pragma(inline, true); return (a < b ? b : a); }
4163 private int stbtt__ray_intersect_bezier(in ref float[2] orig, in ref float[2] ray, in ref float[2] q0, in ref float[2] q1, in ref float[2] q2, ref float[2][2] hits)
4165 float q0perp = q0[1]*ray[0] - q0[0]*ray[1];
4166 float q1perp = q1[1]*ray[0] - q1[0]*ray[1];
4167 float q2perp = q2[1]*ray[0] - q2[0]*ray[1];
4168 float roperp = orig[1]*ray[0] - orig[0]*ray[1];
4170 float a = q0perp - 2*q1perp + q2perp;
4171 float b = q1perp - q0perp;
4172 float c = q0perp - roperp;
4174 float s0 = 0., s1 = 0.;
4175 int num_s = 0;
4177 if (a != 0.0) {
4178 float discr = b*b - a*c;
4179 if (discr > 0.0) {
4180 float rcpna = -1 / a;
4181 float d = cast(float) STBTT_sqrt(discr);
4182 s0 = (b+d) * rcpna;
4183 s1 = (b-d) * rcpna;
4184 if (s0 >= 0.0 && s0 <= 1.0)
4185 num_s = 1;
4186 if (d > 0.0 && s1 >= 0.0 && s1 <= 1.0) {
4187 if (num_s == 0) s0 = s1;
4188 ++num_s;
4191 } else {
4192 // 2*b*s + c = 0
4193 // s = -c / (2*b)
4194 s0 = c / (-2 * b);
4195 if (s0 >= 0.0 && s0 <= 1.0)
4196 num_s = 1;
4199 if (num_s == 0)
4200 return 0;
4201 else {
4202 float rcp_len2 = 1 / (ray[0]*ray[0] + ray[1]*ray[1]);
4203 float rayn_x = ray[0] * rcp_len2, rayn_y = ray[1] * rcp_len2;
4205 float q0d = q0[0]*rayn_x + q0[1]*rayn_y;
4206 float q1d = q1[0]*rayn_x + q1[1]*rayn_y;
4207 float q2d = q2[0]*rayn_x + q2[1]*rayn_y;
4208 float rod = orig[0]*rayn_x + orig[1]*rayn_y;
4210 float q10d = q1d - q0d;
4211 float q20d = q2d - q0d;
4212 float q0rd = q0d - rod;
4214 hits[0][0] = q0rd + s0*(2.0f - 2.0f*s0)*q10d + s0*s0*q20d;
4215 hits[0][1] = a*s0+b;
4217 if (num_s > 1) {
4218 hits[1][0] = q0rd + s1*(2.0f - 2.0f*s1)*q10d + s1*s1*q20d;
4219 hits[1][1] = a*s1+b;
4220 return 2;
4221 } else {
4222 return 1;
4227 private int equal(float *a, float *b)
4229 return (a[0] == b[0] && a[1] == b[1]);
4232 private int stbtt__compute_crossings_x(float x, float y, int nverts, stbtt_vertex *verts)
4234 int i;
4235 float[2] orig = void;
4236 float[2] ray = [ 1, 0 ];
4237 float y_frac;
4238 int winding = 0;
4240 orig[0] = x;
4241 orig[1] = y;
4243 // make sure y never passes through a vertex of the shape
4244 y_frac = cast(float) STBTT_fmod(y, 1.0f);
4245 if (y_frac < 0.01f)
4246 y += 0.01f;
4247 else if (y_frac > 0.99f)
4248 y -= 0.01f;
4249 orig[1] = y;
4251 // test a ray from (-infinity,y) to (x,y)
4252 for (i=0; i < nverts; ++i) {
4253 if (verts[i].type == STBTT_vline) {
4254 int x0 = cast(int) verts[i-1].x, y0 = cast(int) verts[i-1].y;
4255 int x1 = cast(int) verts[i ].x, y1 = cast(int) verts[i ].y;
4256 if (y > STBTT_min(y0,y1) && y < STBTT_max(y0,y1) && x > STBTT_min(x0,x1)) {
4257 float x_inter = (y - y0) / (y1 - y0) * (x1-x0) + x0;
4258 if (x_inter < x)
4259 winding += (y0 < y1) ? 1 : -1;
4262 if (verts[i].type == STBTT_vcurve) {
4263 int x0 = cast(int) verts[i-1].x , y0 = cast(int) verts[i-1].y ;
4264 int x1 = cast(int) verts[i ].cx, y1 = cast(int) verts[i ].cy;
4265 int x2 = cast(int) verts[i ].x , y2 = cast(int) verts[i ].y ;
4266 int ax = STBTT_min(x0,STBTT_min(x1,x2)), ay = STBTT_min(y0,STBTT_min(y1,y2));
4267 int by = STBTT_max(y0,STBTT_max(y1,y2));
4268 if (y > ay && y < by && x > ax) {
4269 float[2] q0, q1, q2;
4270 float[2][2] hits;
4271 q0[0] = cast(float)x0;
4272 q0[1] = cast(float)y0;
4273 q1[0] = cast(float)x1;
4274 q1[1] = cast(float)y1;
4275 q2[0] = cast(float)x2;
4276 q2[1] = cast(float)y2;
4277 if (equal(q0.ptr,q1.ptr) || equal(q1.ptr,q2.ptr)) {
4278 x0 = cast(int)verts[i-1].x;
4279 y0 = cast(int)verts[i-1].y;
4280 x1 = cast(int)verts[i ].x;
4281 y1 = cast(int)verts[i ].y;
4282 if (y > STBTT_min(y0,y1) && y < STBTT_max(y0,y1) && x > STBTT_min(x0,x1)) {
4283 float x_inter = (y - y0) / (y1 - y0) * (x1-x0) + x0;
4284 if (x_inter < x)
4285 winding += (y0 < y1) ? 1 : -1;
4287 } else {
4288 int num_hits = stbtt__ray_intersect_bezier(orig, ray, q0, q1, q2, hits);
4289 if (num_hits >= 1)
4290 if (hits[0][0] < 0)
4291 winding += (hits[0][1] < 0 ? -1 : 1);
4292 if (num_hits >= 2)
4293 if (hits[1][0] < 0)
4294 winding += (hits[1][1] < 0 ? -1 : 1);
4299 return winding;
4302 private float stbtt__cuberoot( float x )
4304 if (x<0)
4305 return -cast(float) STBTT_pow(-x,1.0f/3.0f);
4306 else
4307 return cast(float) STBTT_pow( x,1.0f/3.0f);
4310 // x^3 + c*x^2 + b*x + a = 0
4311 private int stbtt__solve_cubic(float a, float b, float c, float* r)
4313 float s = -a / 3;
4314 float p = b - a*a / 3;
4315 float q = a * (2*a*a - 9*b) / 27 + c;
4316 float p3 = p*p*p;
4317 float d = q*q + 4*p3 / 27;
4318 if (d >= 0) {
4319 float z = cast(float) STBTT_sqrt(d);
4320 float u = (-q + z) / 2;
4321 float v = (-q - z) / 2;
4322 u = stbtt__cuberoot(u);
4323 v = stbtt__cuberoot(v);
4324 r[0] = s + u + v;
4325 return 1;
4326 } else {
4327 float u = cast(float) STBTT_sqrt(-p/3);
4328 float v = cast(float) STBTT_acos(-STBTT_sqrt(-27/p3) * q / 2) / 3; // p3 must be negative, since d is negative
4329 float m = cast(float) STBTT_cos(v);
4330 float n = cast(float) STBTT_cos(v-3.141592/2)*1.732050808f;
4331 r[0] = s + u * 2 * m;
4332 r[1] = s - u * (m + n);
4333 r[2] = s - u * (m - n);
4335 //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?
4336 //STBTT_assert( STBTT_fabs(((r[1]+a)*r[1]+b)*r[1]+c) < 0.05f);
4337 //STBTT_assert( STBTT_fabs(((r[2]+a)*r[2]+b)*r[2]+c) < 0.05f);
4338 return 3;
4342 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)
4344 float scale_x = scale, scale_y = scale;
4345 int ix0,iy0,ix1,iy1;
4346 int w,h;
4347 ubyte *data;
4349 // if one scale is 0, use same scale for both
4350 if (scale_x == 0) scale_x = scale_y;
4351 if (scale_y == 0) {
4352 if (scale_x == 0) return null; // if both scales are 0, return NULL
4353 scale_y = scale_x;
4356 stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale, scale, 0.0f,0.0f, &ix0,&iy0,&ix1,&iy1);
4358 // if empty, return NULL
4359 if (ix0 == ix1 || iy0 == iy1)
4360 return null;
4362 ix0 -= padding;
4363 iy0 -= padding;
4364 ix1 += padding;
4365 iy1 += padding;
4367 w = (ix1 - ix0);
4368 h = (iy1 - iy0);
4370 if (width ) *width = w;
4371 if (height) *height = h;
4372 if (xoff ) *xoff = ix0;
4373 if (yoff ) *yoff = iy0;
4375 // invert for y-downwards bitmaps
4376 scale_y = -scale_y;
4379 int x,y,i,j;
4380 float *precompute;
4381 stbtt_vertex *verts;
4382 int num_verts = stbtt_GetGlyphShape(info, glyph, &verts);
4383 data = cast(ubyte *) STBTT_malloc(w * h, info.userdata);
4384 precompute = cast(float *) STBTT_malloc(num_verts * cast(uint)float.sizeof, info.userdata);
4386 for (i=0,j=num_verts-1; i < num_verts; j=i++) {
4387 if (verts[i].type == STBTT_vline) {
4388 float x0 = verts[i].x*scale_x, y0 = verts[i].y*scale_y;
4389 float x1 = verts[j].x*scale_x, y1 = verts[j].y*scale_y;
4390 float dist = cast(float) STBTT_sqrt((x1-x0)*(x1-x0) + (y1-y0)*(y1-y0));
4391 precompute[i] = (dist == 0) ? 0.0f : 1.0f / dist;
4392 } else if (verts[i].type == STBTT_vcurve) {
4393 float x2 = verts[j].x *scale_x, y2 = verts[j].y *scale_y;
4394 float x1 = verts[i].cx*scale_x, y1 = verts[i].cy*scale_y;
4395 float x0 = verts[i].x *scale_x, y0 = verts[i].y *scale_y;
4396 float bx = x0 - 2*x1 + x2, by = y0 - 2*y1 + y2;
4397 float len2 = bx*bx + by*by;
4398 if (len2 != 0.0f)
4399 precompute[i] = 1.0f / (bx*bx + by*by);
4400 else
4401 precompute[i] = 0.0f;
4402 } else
4403 precompute[i] = 0.0f;
4406 for (y=iy0; y < iy1; ++y) {
4407 for (x=ix0; x < ix1; ++x) {
4408 float val;
4409 float min_dist = 999999.0f;
4410 float sx = cast(float) x + 0.5f;
4411 float sy = cast(float) y + 0.5f;
4412 float x_gspace = (sx / scale_x);
4413 float y_gspace = (sy / scale_y);
4415 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
4417 for (i=0; i < num_verts; ++i) {
4418 float x0 = verts[i].x*scale_x, y0 = verts[i].y*scale_y;
4420 // 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
4421 float dist2 = (x0-sx)*(x0-sx) + (y0-sy)*(y0-sy);
4422 if (dist2 < min_dist*min_dist)
4423 min_dist = cast(float) STBTT_sqrt(dist2);
4425 if (verts[i].type == STBTT_vline) {
4426 float x1 = verts[i-1].x*scale_x, y1 = verts[i-1].y*scale_y;
4428 // coarse culling against bbox
4429 //if (sx > STBTT_min(x0,x1)-min_dist && sx < STBTT_max(x0,x1)+min_dist &&
4430 // sy > STBTT_min(y0,y1)-min_dist && sy < STBTT_max(y0,y1)+min_dist)
4431 float dist = cast(float) STBTT_fabs((x1-x0)*(y0-sy) - (y1-y0)*(x0-sx)) * precompute[i];
4432 assert(i != 0);
4433 if (dist < min_dist) {
4434 // check position along line
4435 // x' = x0 + t*(x1-x0), y' = y0 + t*(y1-y0)
4436 // minimize (x'-sx)*(x'-sx)+(y'-sy)*(y'-sy)
4437 float dx = x1-x0, dy = y1-y0;
4438 float px = x0-sx, py = y0-sy;
4439 // 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
4440 // derivative: 2*px*dx + 2*py*dy + (2*dx*dx+2*dy*dy)*t, set to 0 and solve
4441 float t = -(px*dx + py*dy) / (dx*dx + dy*dy);
4442 if (t >= 0.0f && t <= 1.0f)
4443 min_dist = dist;
4445 } else if (verts[i].type == STBTT_vcurve) {
4446 float x2 = verts[i-1].x *scale_x, y2 = verts[i-1].y *scale_y;
4447 float x1 = verts[i ].cx*scale_x, y1 = verts[i ].cy*scale_y;
4448 float box_x0 = STBTT_min(STBTT_min(x0,x1),x2);
4449 float box_y0 = STBTT_min(STBTT_min(y0,y1),y2);
4450 float box_x1 = STBTT_max(STBTT_max(x0,x1),x2);
4451 float box_y1 = STBTT_max(STBTT_max(y0,y1),y2);
4452 // coarse culling against bbox to avoid computing cubic unnecessarily
4453 if (sx > box_x0-min_dist && sx < box_x1+min_dist && sy > box_y0-min_dist && sy < box_y1+min_dist) {
4454 int num=0;
4455 float ax = x1-x0, ay = y1-y0;
4456 float bx = x0 - 2*x1 + x2, by = y0 - 2*y1 + y2;
4457 float mx = x0 - sx, my = y0 - sy;
4458 float[3] res;
4459 float px,py,t,it;
4460 float a_inv = precompute[i];
4461 if (a_inv == 0.0) { // if a_inv is 0, it's 2nd degree so use quadratic formula
4462 float a = 3*(ax*bx + ay*by);
4463 float b = 2*(ax*ax + ay*ay) + (mx*bx+my*by);
4464 float c = mx*ax+my*ay;
4465 if (a == 0.0) { // if a is 0, it's linear
4466 if (b != 0.0) {
4467 res[num++] = -c/b;
4469 } else {
4470 float discriminant = b*b - 4*a*c;
4471 if (discriminant < 0)
4472 num = 0;
4473 else {
4474 float root = cast(float) STBTT_sqrt(discriminant);
4475 res[0] = (-b - root)/(2*a);
4476 res[1] = (-b + root)/(2*a);
4477 num = 2; // don't bother distinguishing 1-solution case, as code below will still work
4480 } else {
4481 float b = 3*(ax*bx + ay*by) * a_inv; // could precompute this as it doesn't depend on sample point
4482 float c = (2*(ax*ax + ay*ay) + (mx*bx+my*by)) * a_inv;
4483 float d = (mx*ax+my*ay) * a_inv;
4484 num = stbtt__solve_cubic(b, c, d, res.ptr);
4486 if (num >= 1 && res[0] >= 0.0f && res[0] <= 1.0f) {
4487 t = res[0], it = 1.0f - t;
4488 px = it*it*x0 + 2*t*it*x1 + t*t*x2;
4489 py = it*it*y0 + 2*t*it*y1 + t*t*y2;
4490 dist2 = (px-sx)*(px-sx) + (py-sy)*(py-sy);
4491 if (dist2 < min_dist * min_dist)
4492 min_dist = cast(float) STBTT_sqrt(dist2);
4494 if (num >= 2 && res[1] >= 0.0f && res[1] <= 1.0f) {
4495 t = res[1], it = 1.0f - t;
4496 px = it*it*x0 + 2*t*it*x1 + t*t*x2;
4497 py = it*it*y0 + 2*t*it*y1 + t*t*y2;
4498 dist2 = (px-sx)*(px-sx) + (py-sy)*(py-sy);
4499 if (dist2 < min_dist * min_dist)
4500 min_dist = cast(float) STBTT_sqrt(dist2);
4502 if (num >= 3 && res[2] >= 0.0f && res[2] <= 1.0f) {
4503 t = res[2], it = 1.0f - t;
4504 px = it*it*x0 + 2*t*it*x1 + t*t*x2;
4505 py = it*it*y0 + 2*t*it*y1 + t*t*y2;
4506 dist2 = (px-sx)*(px-sx) + (py-sy)*(py-sy);
4507 if (dist2 < min_dist * min_dist)
4508 min_dist = cast(float) STBTT_sqrt(dist2);
4513 if (winding == 0)
4514 min_dist = -min_dist; // if outside the shape, value is negative
4515 val = onedge_value + pixel_dist_scale * min_dist;
4516 if (val < 0)
4517 val = 0;
4518 else if (val > 255)
4519 val = 255;
4520 data[(y-iy0)*w+(x-ix0)] = cast(ubyte) val;
4523 STBTT_free(precompute, info.userdata);
4524 STBTT_free(verts, info.userdata);
4526 return data;
4529 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)
4531 return stbtt_GetGlyphSDF(info, scale, stbtt_FindGlyphIndex(info, codepoint), padding, onedge_value, pixel_dist_scale, width, height, xoff, yoff);
4534 public void stbtt_FreeSDF(ubyte *bitmap, void *userdata)
4536 STBTT_free(bitmap, userdata);
4539 //////////////////////////////////////////////////////////////////////////////
4541 // font name matching -- recommended not to use this
4544 // check if a utf8 string contains a prefix which is the utf16 string; if so return length of matching utf8 string
4545 private stbtt_int32 stbtt__CompareUTF8toUTF16_bigendian_prefix(stbtt_uint8 *s1, stbtt_int32 len1, stbtt_uint8 *s2, stbtt_int32 len2)
4547 stbtt_int32 i=0;
4549 // convert utf16 to utf8 and compare the results while converting
4550 while (len2) {
4551 stbtt_uint16 ch = s2[0]*256 + s2[1];
4552 if (ch < 0x80) {
4553 if (i >= len1) return -1;
4554 if (s1[i++] != ch) return -1;
4555 } else if (ch < 0x800) {
4556 if (i+1 >= len1) return -1;
4557 if (s1[i++] != 0xc0 + (ch >> 6)) return -1;
4558 if (s1[i++] != 0x80 + (ch & 0x3f)) return -1;
4559 } else if (ch >= 0xd800 && ch < 0xdc00) {
4560 stbtt_uint32 c;
4561 stbtt_uint16 ch2 = s2[2]*256 + s2[3];
4562 if (i+3 >= len1) return -1;
4563 c = ((ch - 0xd800) << 10) + (ch2 - 0xdc00) + 0x10000;
4564 if (s1[i++] != 0xf0 + (c >> 18)) return -1;
4565 if (s1[i++] != 0x80 + ((c >> 12) & 0x3f)) return -1;
4566 if (s1[i++] != 0x80 + ((c >> 6) & 0x3f)) return -1;
4567 if (s1[i++] != 0x80 + ((c ) & 0x3f)) return -1;
4568 s2 += 2; // plus another 2 below
4569 len2 -= 2;
4570 } else if (ch >= 0xdc00 && ch < 0xe000) {
4571 return -1;
4572 } else {
4573 if (i+2 >= len1) return -1;
4574 if (s1[i++] != 0xe0 + (ch >> 12)) return -1;
4575 if (s1[i++] != 0x80 + ((ch >> 6) & 0x3f)) return -1;
4576 if (s1[i++] != 0x80 + ((ch ) & 0x3f)) return -1;
4578 s2 += 2;
4579 len2 -= 2;
4581 return i;
4584 private int stbtt_CompareUTF8toUTF16_bigendian_internal(char *s1, int len1, char *s2, int len2)
4586 return len1 == stbtt__CompareUTF8toUTF16_bigendian_prefix(cast(stbtt_uint8*) s1, len1, cast(stbtt_uint8*) s2, len2);
4589 // returns results in whatever encoding you request... but note that 2-byte encodings
4590 // will be BIG-ENDIAN... use stbtt_CompareUTF8toUTF16_bigendian() to compare
4591 public const(char)* stbtt_GetFontNameString(stbtt_fontinfo* font, int *length, int platformID, int encodingID, int languageID, int nameID)
4593 stbtt_int32 i,count,stringOffset;
4594 stbtt_uint8 *fc = font.data;
4595 stbtt_uint32 offset = font.fontstart;
4596 stbtt_uint32 nm = stbtt__find_table(fc, offset, "name");
4597 if (!nm) return null;
4599 count = ttUSHORT(fc+nm+2);
4600 stringOffset = nm + ttUSHORT(fc+nm+4);
4601 for (i=0; i < count; ++i) {
4602 stbtt_uint32 loc = nm + 6 + 12 * i;
4603 if (platformID == ttUSHORT(fc+loc+0) && encodingID == ttUSHORT(fc+loc+2)
4604 && languageID == ttUSHORT(fc+loc+4) && nameID == ttUSHORT(fc+loc+6)) {
4605 *length = ttUSHORT(fc+loc+8);
4606 return cast(const(char)* ) (fc+stringOffset+ttUSHORT(fc+loc+10));
4609 return null;
4612 private int stbtt__matchpair(stbtt_uint8 *fc, stbtt_uint32 nm, stbtt_uint8 *name, stbtt_int32 nlen, stbtt_int32 target_id, stbtt_int32 next_id)
4614 stbtt_int32 i;
4615 stbtt_int32 count = ttUSHORT(fc+nm+2);
4616 stbtt_int32 stringOffset = nm + ttUSHORT(fc+nm+4);
4618 for (i=0; i < count; ++i) {
4619 stbtt_uint32 loc = nm + 6 + 12 * i;
4620 stbtt_int32 id = ttUSHORT(fc+loc+6);
4621 if (id == target_id) {
4622 // find the encoding
4623 stbtt_int32 platform = ttUSHORT(fc+loc+0), encoding = ttUSHORT(fc+loc+2), language = ttUSHORT(fc+loc+4);
4625 // is this a Unicode encoding?
4626 if (platform == 0 || (platform == 3 && encoding == 1) || (platform == 3 && encoding == 10)) {
4627 stbtt_int32 slen = ttUSHORT(fc+loc+8);
4628 stbtt_int32 off = ttUSHORT(fc+loc+10);
4630 // check if there's a prefix match
4631 stbtt_int32 matchlen = stbtt__CompareUTF8toUTF16_bigendian_prefix(name, nlen, fc+stringOffset+off,slen);
4632 if (matchlen >= 0) {
4633 // check for target_id+1 immediately following, with same encoding & language
4634 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) {
4635 slen = ttUSHORT(fc+loc+12+8);
4636 off = ttUSHORT(fc+loc+12+10);
4637 if (slen == 0) {
4638 if (matchlen == nlen)
4639 return 1;
4640 } else if (matchlen < nlen && name[matchlen] == ' ') {
4641 ++matchlen;
4642 if (stbtt_CompareUTF8toUTF16_bigendian_internal(cast(char*) (name+matchlen), nlen-matchlen, cast(char*)(fc+stringOffset+off),slen))
4643 return 1;
4645 } else {
4646 // if nothing immediately following
4647 if (matchlen == nlen)
4648 return 1;
4653 // @TODO handle other encodings
4656 return 0;
4659 private int stbtt__matches(stbtt_uint8 *fc, stbtt_uint32 offset, stbtt_uint8 *name, stbtt_int32 flags)
4661 stbtt_int32 nlen = cast(stbtt_int32) STBTT_strlen(cast(char *) name);
4662 stbtt_uint32 nm,hd;
4663 if (!stbtt__isfont(fc+offset)) return 0;
4665 // check italics/bold/underline flags in macStyle...
4666 if (flags) {
4667 hd = stbtt__find_table(fc, offset, "head");
4668 if ((ttUSHORT(fc+hd+44) & 7) != (flags & 7)) return 0;
4671 nm = stbtt__find_table(fc, offset, "name");
4672 if (!nm) return 0;
4674 if (flags) {
4675 // if we checked the macStyle flags, then just check the family and ignore the subfamily
4676 if (stbtt__matchpair(fc, nm, name, nlen, 16, -1)) return 1;
4677 if (stbtt__matchpair(fc, nm, name, nlen, 1, -1)) return 1;
4678 if (stbtt__matchpair(fc, nm, name, nlen, 3, -1)) return 1;
4679 } else {
4680 if (stbtt__matchpair(fc, nm, name, nlen, 16, 17)) return 1;
4681 if (stbtt__matchpair(fc, nm, name, nlen, 1, 2)) return 1;
4682 if (stbtt__matchpair(fc, nm, name, nlen, 3, -1)) return 1;
4685 return 0;
4688 private int stbtt_FindMatchingFont_internal(ubyte *font_collection, char *name_utf8, stbtt_int32 flags)
4690 stbtt_int32 i;
4691 for (i=0;;++i) {
4692 stbtt_int32 off = stbtt_GetFontOffsetForIndex(font_collection, i);
4693 if (off < 0) return off;
4694 if (stbtt__matches(cast(stbtt_uint8 *) font_collection, off, cast(stbtt_uint8*) name_utf8, flags))
4695 return off;
4699 public int stbtt_BakeFontBitmap(const(ubyte)* data, int offset,
4700 float pixel_height, ubyte *pixels, int pw, int ph,
4701 int first_char, int num_chars, stbtt_bakedchar *chardata)
4703 return stbtt_BakeFontBitmap_internal(cast(ubyte *) data, offset, pixel_height, pixels, pw, ph, first_char, num_chars, chardata);
4706 public int stbtt_GetFontOffsetForIndex(const(ubyte)* data, int index)
4708 return stbtt_GetFontOffsetForIndex_internal(cast(ubyte *) data, index);
4711 public int stbtt_GetNumberOfFonts(const(ubyte)* data)
4713 return stbtt_GetNumberOfFonts_internal(cast(ubyte *) data);
4716 public int stbtt_InitFont(stbtt_fontinfo *info, const(ubyte)* data, int offset)
4718 return stbtt_InitFont_internal(info, cast(ubyte *) data, offset);
4721 public int stbtt_FindMatchingFont(const(ubyte)* fontdata, const(char)* name, int flags)
4723 return stbtt_FindMatchingFont_internal(cast(ubyte *) fontdata, cast(char *) name, flags);
4726 public int stbtt_CompareUTF8toUTF16_bigendian(const(char)* s1, int len1, const(char)* s2, int len2)
4728 return stbtt_CompareUTF8toUTF16_bigendian_internal(cast(char *) s1, len1, cast(char *) s2, len2);
4732 // FULL VERSION HISTORY
4734 // 1.19 (2018-02-11) OpenType GPOS kerning (horizontal only), STBTT_fmod
4735 // 1.18 (2018-01-29) add missing function
4736 // 1.17 (2017-07-23) make more arguments const; doc fix
4737 // 1.16 (2017-07-12) SDF support
4738 // 1.15 (2017-03-03) make more arguments const
4739 // 1.14 (2017-01-16) num-fonts-in-TTC function
4740 // 1.13 (2017-01-02) support OpenType fonts, certain Apple fonts
4741 // 1.12 (2016-10-25) suppress warnings about casting away const with -Wcast-qual
4742 // 1.11 (2016-04-02) fix unused-variable warning
4743 // 1.10 (2016-04-02) allow user-defined fabs() replacement
4744 // fix memory leak if fontsize=0.0
4745 // fix warning from duplicate typedef
4746 // 1.09 (2016-01-16) warning fix; avoid crash on outofmem; use alloc userdata for PackFontRanges
4747 // 1.08 (2015-09-13) document stbtt_Rasterize(); fixes for vertical & horizontal edges
4748 // 1.07 (2015-08-01) allow PackFontRanges to accept arrays of sparse codepoints;
4749 // allow PackFontRanges to pack and render in separate phases;
4750 // fix stbtt_GetFontOFfsetForIndex (never worked for non-0 input?);
4751 // fixed an assert() bug in the new rasterizer
4752 // replace assert() with STBTT_assert() in new rasterizer
4753 // 1.06 (2015-07-14) performance improvements (~35% faster on x86 and x64 on test machine)
4754 // also more precise AA rasterizer, except if shapes overlap
4755 // remove need for STBTT_sort
4756 // 1.05 (2015-04-15) fix misplaced definitions for STBTT_STATIC
4757 // 1.04 (2015-04-15) typo in example
4758 // 1.03 (2015-04-12) STBTT_STATIC, fix memory leak in new packing, various fixes
4759 // 1.02 (2014-12-10) fix various warnings & compile issues w/ stb_rect_pack, C++
4760 // 1.01 (2014-12-08) fix subpixel position when oversampling to exactly match
4761 // non-oversampled; STBTT_POINT_SIZE for packed case only
4762 // 1.00 (2014-12-06) add new PackBegin etc. API, w/ support for oversampling
4763 // 0.99 (2014-09-18) fix multiple bugs with subpixel rendering (ryg)
4764 // 0.9 (2014-08-07) support certain mac/iOS fonts without an MS platformID
4765 // 0.8b (2014-07-07) fix a warning
4766 // 0.8 (2014-05-25) fix a few more warnings
4767 // 0.7 (2013-09-25) bugfix: subpixel glyph bug fixed in 0.5 had come back
4768 // 0.6c (2012-07-24) improve documentation
4769 // 0.6b (2012-07-20) fix a few more warnings
4770 // 0.6 (2012-07-17) fix warnings; added stbtt_ScaleForMappingEmToPixels,
4771 // stbtt_GetFontBoundingBox, stbtt_IsGlyphEmpty
4772 // 0.5 (2011-12-09) bugfixes:
4773 // subpixel glyph renderer computed wrong bounding box
4774 // first vertex of shape can be off-curve (FreeSans)
4775 // 0.4b (2011-12-03) fixed an error in the font baking example
4776 // 0.4 (2011-12-01) kerning, subpixel rendering (tor)
4777 // bugfixes for:
4778 // codepoint-to-glyph conversion using table fmt=12
4779 // codepoint-to-glyph conversion using table fmt=4
4780 // stbtt_GetBakedQuad with non-square texture (Zer)
4781 // updated Hello World! sample to use kerning and subpixel
4782 // fixed some warnings
4783 // 0.3 (2009-06-24) cmap fmt=12, compound shapes (MM)
4784 // userdata, malloc-from-userdata, non-zero fill (stb)
4785 // 0.2 (2009-03-11) Fix unsigned/signed char warnings
4786 // 0.1 (2009-03-09) First public release
4790 ------------------------------------------------------------------------------
4791 This software is available under 2 licenses -- choose whichever you prefer.
4792 ------------------------------------------------------------------------------
4793 ALTERNATIVE A - MIT License
4794 Copyright (c) 2017 Sean Barrett
4795 Permission is hereby granted, free of charge, to any person obtaining a copy of
4796 this software and associated documentation files (the "Software"), to deal in
4797 the Software without restriction, including without limitation the rights to
4798 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
4799 of the Software, and to permit persons to whom the Software is furnished to do
4800 so, subject to the following conditions:
4801 The above copyright notice and this permission notice shall be included in all
4802 copies or substantial portions of the Software.
4803 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
4804 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
4805 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
4806 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
4807 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
4808 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
4809 SOFTWARE.
4810 ------------------------------------------------------------------------------
4811 ALTERNATIVE B - Public Domain (www.unlicense.org)
4812 This is free and unencumbered software released into the public domain.
4813 Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
4814 software, either in source code form or as a compiled binary, for any purpose,
4815 commercial or non-commercial, and by any means.
4816 In jurisdictions that recognize copyright laws, the author or authors of this
4817 software dedicate any and all copyright interest in the software to the public
4818 domain. We make this dedication for the benefit of the public at large and to
4819 the detriment of our heirs and successors. We intend this dedication to be an
4820 overt act of relinquishment in perpetuity of all present and future rights to
4821 this software under copyright law.
4822 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
4823 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
4824 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
4825 AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
4826 ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
4827 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
4828 ------------------------------------------------------------------------------