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