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