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