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