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