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