NovaSVG 0.10.0
A header-only SVG library
Loading...
Searching...
No Matches
font.h
Go to the documentation of this file.
1#pragma once
2
3#include "private.h"
4#include "utils.h"
5
6#include <stdio.h>
7#include <assert.h>
8
9#define STBTT_STATIC
10#define STB_TRUETYPE_IMPLEMENTATION
11// ---- begin inlined stb_truetype (public domain / MIT -- Sean Barrett) ----
12// Vendored in-place: font.h is its only user. Upstream: https://github.com/nothings/stb
13#pragma once
14
15// stb_truetype.h - v1.26 - public domain
16// authored from 2009-2021 by Sean Barrett / RAD Game Tools
17//
18// =======================================================================
19//
20// NO SECURITY GUARANTEE -- DO NOT USE THIS ON UNTRUSTED FONT FILES
21//
22// This library does no range checking of the offsets found in the file,
23// meaning an attacker can use it to read arbitrary memory.
24//
25// =======================================================================
26//
27// This library processes TrueType files:
28// parse files
29// extract glyph metrics
30// extract glyph shapes
31// render glyphs to one-channel bitmaps with antialiasing (box filter)
32// render glyphs to one-channel SDF bitmaps (signed-distance field/function)
33//
34// Todo:
35// non-MS cmaps
36// crashproof on bad data
37// hinting? (no longer patented)
38// cleartype-style AA?
39// optimize: use simple memory allocator for intermediates
40// optimize: build edge-list directly from curves
41// optimize: rasterize directly from curves?
42//
43// ADDITIONAL CONTRIBUTORS
44//
45// Mikko Mononen: compound shape support, more cmap formats
46// Tor Andersson: kerning, subpixel rendering
47// Dougall Johnson: OpenType / Type 2 font handling
48// Daniel Ribeiro Maciel: basic GPOS-based kerning
49//
50// Misc other:
51// Ryan Gordon
52// Simon Glass
53// github:IntellectualKitty
54// Imanol Celaya
55// Daniel Ribeiro Maciel
56//
57// Bug/warning reports/fixes:
58// "Zer" on mollyrocket Fabian "ryg" Giesen github:NiLuJe
59// Cass Everitt Martins Mozeiko github:aloucks
60// stoiko (Haemimont Games) Cap Petschulat github:oyvindjam
61// Brian Hook Omar Cornut github:vassvik
62// Walter van Niftrik Ryan Griege
63// David Gow Peter LaValle
64// David Given Sergey Popov
65// Ivan-Assen Ivanov Giumo X. Clanjor
66// Anthony Pesch Higor Euripedes
67// Johan Duparc Thomas Fields
68// Hou Qiming Derek Vinyard
69// Rob Loach Cort Stratton
70// Kenney Phillis Jr. Brian Costabile
71// Ken Voskuil (kaesve)
72//
73// VERSION HISTORY
74//
75// 1.26 (2021-08-28) fix broken rasterizer
76// 1.25 (2021-07-11) many fixes
77// 1.24 (2020-02-05) fix warning
78// 1.23 (2020-02-02) query SVG data for glyphs; query whole kerning table (but only kern not GPOS)
79// 1.22 (2019-08-11) minimize missing-glyph duplication; fix kerning if both 'GPOS' and 'kern' are defined
80// 1.21 (2019-02-25) fix warning
81// 1.20 (2019-02-07) PackFontRange skips missing codepoints; GetScaleFontVMetrics()
82// 1.19 (2018-02-11) GPOS kerning, STBTT_fmod
83// 1.18 (2018-01-29) add missing function
84// 1.17 (2017-07-23) make more arguments const; doc fix
85// 1.16 (2017-07-12) SDF support
86// 1.15 (2017-03-03) make more arguments const
87// 1.14 (2017-01-16) num-fonts-in-TTC function
88// 1.13 (2017-01-02) support OpenType fonts, certain Apple fonts
89// 1.12 (2016-10-25) suppress warnings about casting away const with -Wcast-qual
90// 1.11 (2016-04-02) fix unused-variable warning
91// 1.10 (2016-04-02) user-defined fabs(); rare memory leak; remove duplicate typedef
92// 1.09 (2016-01-16) warning fix; avoid crash on outofmem; use allocation userdata properly
93// 1.08 (2015-09-13) document stbtt_Rasterize(); fixes for vertical & horizontal edges
94// 1.07 (2015-08-01) allow PackFontRanges to accept arrays of sparse codepoints;
95// variant PackFontRanges to pack and render in separate phases;
96// fix stbtt_GetFontOFfsetForIndex (never worked for non-0 input?);
97// fixed an assert() bug in the new rasterizer
98// replace assert() with STBTT_assert() in new rasterizer
99//
100// Full history can be found at the end of this file.
101//
102// LICENSE
103//
104// See end of file for license information.
105//
106// USAGE
107//
108// Include this file in whatever places need to refer to it. In ONE C/C++
109// file, write:
110// #define STB_TRUETYPE_IMPLEMENTATION
111// before the #include of this file. This expands out the actual
112// implementation into that C/C++ file.
113//
114// To make the implementation private to the file that generates the implementation,
115// #define STBTT_STATIC
116//
117// Simple 3D API (don't ship this, but it's fine for tools and quick start)
118// stbtt_BakeFontBitmap() -- bake a font to a bitmap for use as texture
119// stbtt_GetBakedQuad() -- compute quad to draw for a given char
120//
121// Improved 3D API (more shippable):
122// #include "stb_rect_pack.h" -- optional, but you really want it
123// stbtt_PackBegin()
124// stbtt_PackSetOversampling() -- for improved quality on small fonts
125// stbtt_PackFontRanges() -- pack and renders
126// stbtt_PackEnd()
127// stbtt_GetPackedQuad()
128//
129// "Load" a font file from a memory buffer (you have to keep the buffer loaded)
130// stbtt_InitFont()
131// stbtt_GetFontOffsetForIndex() -- indexing for TTC font collections
132// stbtt_GetNumberOfFonts() -- number of fonts for TTC font collections
133//
134// Render a unicode codepoint to a bitmap
135// stbtt_GetCodepointBitmap() -- allocates and returns a bitmap
136// stbtt_MakeCodepointBitmap() -- renders into bitmap you provide
137// stbtt_GetCodepointBitmapBox() -- how big the bitmap must be
138//
139// Character advance/positioning
140// stbtt_GetCodepointHMetrics()
141// stbtt_GetFontVMetrics()
142// stbtt_GetFontVMetricsOS2()
143// stbtt_GetCodepointKernAdvance()
144//
145// Starting with version 1.06, the rasterizer was replaced with a new,
146// faster and generally-more-precise rasterizer. The new rasterizer more
147// accurately measures pixel coverage for anti-aliasing, except in the case
148// where multiple shapes overlap, in which case it overestimates the AA pixel
149// coverage. Thus, anti-aliasing of intersecting shapes may look wrong. If
150// this turns out to be a problem, you can re-enable the old rasterizer with
151// #define STBTT_RASTERIZER_VERSION 1
152// which will incur about a 15% speed hit.
153//
154// ADDITIONAL DOCUMENTATION
155//
156// Immediately after this block comment are a series of sample programs.
157//
158// After the sample programs is the "header file" section. This section
159// includes documentation for each API function.
160//
161// Some important concepts to understand to use this library:
162//
163// Codepoint
164// Characters are defined by unicode codepoints, e.g. 65 is
165// uppercase A, 231 is lowercase c with a cedilla, 0x7e30 is
166// the hiragana for "ma".
167//
168// Glyph
169// A visual character shape (every codepoint is rendered as
170// some glyph)
171//
172// Glyph index
173// A font-specific integer ID representing a glyph
174//
175// Baseline
176// Glyph shapes are defined relative to a baseline, which is the
177// bottom of uppercase characters. Characters extend both above
178// and below the baseline.
179//
180// Current Point
181// As you draw text to the screen, you keep track of a "current point"
182// which is the origin of each character. The current point's vertical
183// position is the baseline. Even "baked fonts" use this model.
184//
185// Vertical Font Metrics
186// The vertical qualities of the font, used to vertically position
187// and space the characters. See docs for stbtt_GetFontVMetrics.
188//
189// Font Size in Pixels or Points
190// The preferred interface for specifying font sizes in stb_truetype
191// is to specify how tall the font's vertical extent should be in pixels.
192// If that sounds good enough, skip the next paragraph.
193//
194// Most font APIs instead use "points", which are a common typographic
195// measurement for describing font size, defined as 72 points per inch.
196// stb_truetype provides a point API for compatibility. However, true
197// "per inch" conventions don't make much sense on computer displays
198// since different monitors have different number of pixels per
199// inch. For example, Windows traditionally uses a convention that
200// there are 96 pixels per inch, thus making 'inch' measurements have
201// nothing to do with inches, and thus effectively defining a point to
202// be 1.333 pixels. Additionally, the TrueType font data provides
203// an explicit scale factor to scale a given font's glyphs to points,
204// but the author has observed that this scale factor is often wrong
205// for non-commercial fonts, thus making fonts scaled in points
206// according to the TrueType spec incoherently sized in practice.
207//
208// DETAILED USAGE:
209//
210// Scale:
211// Select how high you want the font to be, in points or pixels.
212// Call ScaleForPixelHeight or ScaleForMappingEmToPixels to compute
213// a scale factor SF that will be used by all other functions.
214//
215// Baseline:
216// You need to select a y-coordinate that is the baseline of where
217// your text will appear. Call GetFontBoundingBox to get the baseline-relative
218// bounding box for all characters. SF*-y0 will be the distance in pixels
219// that the worst-case character could extend above the baseline, so if
220// you want the top edge of characters to appear at the top of the
221// screen where y=0, then you would set the baseline to SF*-y0.
222//
223// Current point:
224// Set the current point where the first character will appear. The
225// first character could extend left of the current point; this is font
226// dependent. You can either choose a current point that is the leftmost
227// point and hope, or add some padding, or check the bounding box or
228// left-side-bearing of the first character to be displayed and set
229// the current point based on that.
230//
231// Displaying a character:
232// Compute the bounding box of the character. It will contain signed values
233// relative to <current_point, baseline>. I.e. if it returns x0,y0,x1,y1,
234// then the character should be displayed in the rectangle from
235// <current_point+SF*x0, baseline+SF*y0> to <current_point+SF*x1,baseline+SF*y1).
236//
237// Advancing for the next character:
238// Call GlyphHMetrics, and compute 'current_point += SF * advance'.
239//
240//
241// ADVANCED USAGE
242//
243// Quality:
244//
245// - Use the functions with Subpixel at the end to allow your characters
246// to have subpixel positioning. Since the font is anti-aliased, not
247// hinted, this is very import for quality. (This is not possible with
248// baked fonts.)
249//
250// - Kerning is now supported, and if you're supporting subpixel rendering
251// then kerning is worth using to give your text a polished look.
252//
253// Performance:
254//
255// - Convert Unicode codepoints to glyph indexes and operate on the glyphs;
256// if you don't do this, stb_truetype is forced to do the conversion on
257// every call.
258//
259// - There are a lot of memory allocations. We should modify it to take
260// a temp buffer and allocate from the temp buffer (without freeing),
261// should help performance a lot.
262//
263// NOTES
264//
265// The system uses the raw data found in the .ttf file without changing it
266// and without building auxiliary data structures. This is a bit inefficient
267// on little-endian systems (the data is big-endian), but assuming you're
268// caching the bitmaps or glyph shapes this shouldn't be a big deal.
269//
270// It appears to be very hard to programmatically determine what font a
271// given file is in a general way. I provide an API for this, but I don't
272// recommend it.
273//
274//
275// PERFORMANCE MEASUREMENTS FOR 1.06:
276//
277// 32-bit 64-bit
278// Previous release: 8.83 s 7.68 s
279// Pool allocations: 7.72 s 6.34 s
280// Inline sort : 6.54 s 5.65 s
281// New rasterizer : 5.63 s 5.00 s
282
283
292
293#ifdef STB_TRUETYPE_IMPLEMENTATION
294 // #define your own (u)stbtt_int8/16/32 before including to override this
295 #ifndef stbtt_uint8
296 typedef unsigned char stbtt_uint8;
297 typedef signed char stbtt_int8;
298 typedef unsigned short stbtt_uint16;
299 typedef signed short stbtt_int16;
300 typedef unsigned int stbtt_uint32;
301 typedef signed int stbtt_int32;
302 #endif
303
304 typedef char stbtt__check_size32[sizeof(stbtt_int32)==4 ? 1 : -1];
305 typedef char stbtt__check_size16[sizeof(stbtt_int16)==2 ? 1 : -1];
306
307 // e.g. #define your own STBTT_ifloor/STBTT_iceil() to avoid math.h
308 #ifndef STBTT_ifloor
309 #include <math.h>
310 #define STBTT_ifloor(x) ((int) floor(x))
311 #define STBTT_iceil(x) ((int) ceil(x))
312 #endif
313
314 #ifndef STBTT_sqrt
315 #include <math.h>
316 #define STBTT_sqrt(x) sqrt(x)
317 #define STBTT_pow(x,y) pow(x,y)
318 #endif
319
320 #ifndef STBTT_fmod
321 #include <math.h>
322 #define STBTT_fmod(x,y) fmod(x,y)
323 #endif
324
325 #ifndef STBTT_cos
326 #include <math.h>
327 #define STBTT_cos(x) cos(x)
328 #define STBTT_acos(x) acos(x)
329 #endif
330
331 #ifndef STBTT_fabs
332 #include <math.h>
333 #define STBTT_fabs(x) fabs(x)
334 #endif
335
336 // #define your own functions "STBTT_malloc" / "STBTT_free" to avoid malloc.h
337 #ifndef STBTT_malloc
338 #include <stdlib.h>
339 #define STBTT_malloc(x,u) ((void)(u),malloc(x))
340 #define STBTT_free(x,u) ((void)(u),free(x))
341 #endif
342
343 #ifndef STBTT_assert
344 #include <assert.h>
345 #define STBTT_assert(x) assert(x)
346 #endif
347
348 #ifndef STBTT_strlen
349 #include <string.h>
350 #define STBTT_strlen(x) strlen(x)
351 #endif
352
353 #ifndef STBTT_memcpy
354 #include <string.h>
355 #define STBTT_memcpy memcpy
356 #define STBTT_memset memset
357 #endif
358#endif
359
366
367#ifndef PLUTOVG_STB_TRUETYPE_H
368#define PLUTOVG_STB_TRUETYPE_H
369
370#ifdef STBTT_STATIC
371#define STBTT_DEF static
372#else
373#define STBTT_DEF extern
374#endif
375
376#ifdef __cplusplus
377extern "C" {
378#endif
379
380// private structure
381typedef struct
382{
383 unsigned char *data;
385 int size;
386} stbtt__buf;
387
389//
390// TEXTURE BAKING API
391//
392// If you use this API, you only have to call two functions ever.
393//
394
395typedef struct
396{
397 unsigned short x0,y0,x1,y1; // coordinates of bbox in bitmap
398 float xoff,yoff,xadvance;
400
401STBTT_DEF int stbtt_BakeFontBitmap(const unsigned char *data, int offset, // font location (use offset=0 for plain .ttf)
402 float pixel_height, // height of font in pixels
403 unsigned char *pixels, int pw, int ph, // bitmap to be filled in
404 int first_char, int num_chars, // characters to bake
405 stbtt_bakedchar *chardata); // you allocate this, it's num_chars long
406// if return is positive, the first unused row of the bitmap
407// if return is negative, returns the negative of the number of characters that fit
408// if return is 0, no characters fit and no rows were used
409// This uses a very crappy packing.
410
411typedef struct
412{
413 float x0,y0,s0,t0; // top-left
414 float x1,y1,s1,t1; // bottom-right
416
417STBTT_DEF void stbtt_GetBakedQuad(const stbtt_bakedchar *chardata, int pw, int ph, // same data as above
418 int char_index, // character to display
419 float *xpos, float *ypos, // pointers to current position in screen pixel space
420 stbtt_aligned_quad *q, // output: quad to draw
421 int opengl_fillrule); // true if opengl fill rule; false if DX9 or earlier
422// Call GetBakedQuad with char_index = 'character - first_char', and it
423// creates the quad you need to draw and advances the current position.
424//
425// The coordinate system used assumes y increases downwards.
426//
427// Characters will extend both above and below the current position;
428// see discussion of "BASELINE" above.
429//
430// It's inefficient; you might want to c&p it and optimize it.
431
432STBTT_DEF void stbtt_GetScaledFontVMetrics(const unsigned char *fontdata, int index, float size, float *ascent, float *descent, float *lineGap);
433// Query the font vertical metrics without having to create a font first.
434
435
437//
438// NEW TEXTURE BAKING API
439//
440// This provides options for packing multiple fonts into one atlas, not
441// perfectly but better than nothing.
442
443typedef struct
444{
445 unsigned short x0,y0,x1,y1; // coordinates of bbox in bitmap
446 float xoff,yoff,xadvance;
447 float xoff2,yoff2;
449
452#ifndef STB_RECT_PACK_VERSION
453typedef struct stbrp_rect stbrp_rect;
454#endif
455
456STBTT_DEF int stbtt_PackBegin(stbtt_pack_context *spc, unsigned char *pixels, int width, int height, int stride_in_bytes, int padding, void *alloc_context);
457// Initializes a packing context stored in the passed-in stbtt_pack_context.
458// Future calls using this context will pack characters into the bitmap passed
459// in here: a 1-channel bitmap that is width * height. stride_in_bytes is
460// the distance from one row to the next (or 0 to mean they are packed tightly
461// together). "padding" is the amount of padding to leave between each
462// character (normally you want '1' for bitmaps you'll use as textures with
463// bilinear filtering).
464//
465// Returns 0 on failure, 1 on success.
466
467STBTT_DEF void stbtt_PackEnd (stbtt_pack_context *spc);
468// Cleans up the packing context and frees all memory.
469
470#define STBTT_POINT_SIZE(x) (-(x))
471
472STBTT_DEF int stbtt_PackFontRange(stbtt_pack_context *spc, const unsigned char *fontdata, int font_index, float font_size,
473 int first_unicode_char_in_range, int num_chars_in_range, stbtt_packedchar *chardata_for_range);
474// Creates character bitmaps from the font_index'th font found in fontdata (use
475// font_index=0 if you don't know what that is). It creates num_chars_in_range
476// bitmaps for characters with unicode values starting at first_unicode_char_in_range
477// and increasing. Data for how to render them is stored in chardata_for_range;
478// pass these to stbtt_GetPackedQuad to get back renderable quads.
479//
480// font_size is the full height of the character from ascender to descender,
481// as computed by stbtt_ScaleForPixelHeight. To use a point size as computed
482// by stbtt_ScaleForMappingEmToPixels, wrap the point size in STBTT_POINT_SIZE()
483// and pass that result as 'font_size':
484// ..., 20 , ... // font max minus min y is 20 pixels tall
485// ..., STBTT_POINT_SIZE(20), ... // 'M' is 20 pixels tall
486
487typedef struct
488{
490 int first_unicode_codepoint_in_range; // if non-zero, then the chars are continuous, and this is the first codepoint
491 int *array_of_unicode_codepoints; // if non-zero, then this is an array of unicode codepoints
494 unsigned char h_oversample, v_oversample; // don't set these, they're used internally
496
497STBTT_DEF int stbtt_PackFontRanges(stbtt_pack_context *spc, const unsigned char *fontdata, int font_index, stbtt_pack_range *ranges, int num_ranges);
498// Creates character bitmaps from multiple ranges of characters stored in
499// ranges. This will usually create a better-packed bitmap than multiple
500// calls to stbtt_PackFontRange. Note that you can call this multiple
501// times within a single PackBegin/PackEnd.
502
503STBTT_DEF void stbtt_PackSetOversampling(stbtt_pack_context *spc, unsigned int h_oversample, unsigned int v_oversample);
504// Oversampling a font increases the quality by allowing higher-quality subpixel
505// positioning, and is especially valuable at smaller text sizes.
506//
507// This function sets the amount of oversampling for all following calls to
508// stbtt_PackFontRange(s) or stbtt_PackFontRangesGatherRects for a given
509// pack context. The default (no oversampling) is achieved by h_oversample=1
510// and v_oversample=1. The total number of pixels required is
511// h_oversample*v_oversample larger than the default; for example, 2x2
512// oversampling requires 4x the storage of 1x1. For best results, render
513// oversampled textures with bilinear filtering. Look at the readme in
514// stb/tests/oversample for information about oversampled fonts
515//
516// To use with PackFontRangesGather etc., you must set it before calls
517// call to PackFontRangesGatherRects.
518
519STBTT_DEF void stbtt_PackSetSkipMissingCodepoints(stbtt_pack_context *spc, int skip);
520// If skip != 0, this tells stb_truetype to skip any codepoints for which
521// there is no corresponding glyph. If skip=0, which is the default, then
522// codepoints without a glyph recived the font's "missing character" glyph,
523// typically an empty box by convention.
524
525STBTT_DEF void stbtt_GetPackedQuad(const stbtt_packedchar *chardata, int pw, int ph, // same data as above
526 int char_index, // character to display
527 float *xpos, float *ypos, // pointers to current position in screen pixel space
528 stbtt_aligned_quad *q, // output: quad to draw
529 int align_to_integer);
530
531STBTT_DEF int stbtt_PackFontRangesGatherRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects);
532STBTT_DEF void stbtt_PackFontRangesPackRects(stbtt_pack_context *spc, stbrp_rect *rects, int num_rects);
533STBTT_DEF int stbtt_PackFontRangesRenderIntoRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects);
534// Calling these functions in sequence is roughly equivalent to calling
535// stbtt_PackFontRanges(). If you more control over the packing of multiple
536// fonts, or if you want to pack custom data into a font texture, take a look
537// at the source to of stbtt_PackFontRanges() and create a custom version
538// using these functions, e.g. call GatherRects multiple times,
539// building up a single array of rects, then call PackRects once,
540// then call RenderIntoRects repeatedly. This may result in a
541// better packing than calling PackFontRanges multiple times
542// (or it may not).
543
544// this is an opaque structure that you shouldn't mess with which holds
545// all the context needed from PackBegin to PackEnd.
558
560//
561// FONT LOADING
562//
563//
564
565STBTT_DEF int stbtt_GetNumberOfFonts(const unsigned char *data);
566// This function will determine the number of fonts in a font file. TrueType
567// collection (.ttc) files may contain multiple fonts, while TrueType font
568// (.ttf) files only contain one font. The number of fonts can be used for
569// indexing with the previous function where the index is between zero and one
570// less than the total fonts. If an error occurs, -1 is returned.
571
572STBTT_DEF int stbtt_GetFontOffsetForIndex(const unsigned char *data, int index);
573// Each .ttf/.ttc file may have more than one font. Each font has a sequential
574// index number starting from 0. Call this function to get the font offset for
575// a given index; it returns -1 if the index is out of range. A regular .ttf
576// file will only define one font and it always be at offset 0, so it will
577// return '0' for index 0, and -1 for all other indices.
578
579// The following structure is defined publicly so you can declare one on
580// the stack or as a global or etc, but you should treat it as opaque.
582{
583 void * userdata;
584 unsigned char * data; // pointer to .ttf file
585 int fontstart; // offset of start of font
586
587 int numGlyphs; // number of glyphs, needed for range checking
588
589 int loca,head,glyf,hhea,hmtx,kern,gpos,gsub,svg; // table locations as offset from start of .ttf
590 int index_map; // a cmap mapping for our chosen character encoding
591 int indexToLocFormat; // format needed to map from glyph index to glyph
592
593 stbtt__buf cff; // cff font data
594 stbtt__buf charstrings; // the charstring index
595 stbtt__buf gsubrs; // global charstring subroutines index
596 stbtt__buf subrs; // private charstring subroutines index
597 stbtt__buf fontdicts; // array of font dicts
598 stbtt__buf fdselect; // map from glyph to fontdict
599};
600
601STBTT_DEF int stbtt_InitFont(stbtt_fontinfo *info, const unsigned char *data, int offset);
602// Given an offset into the file that defines a font, this function builds
603// the necessary cached info for the rest of the system. You must allocate
604// the stbtt_fontinfo yourself, and stbtt_InitFont will fill it out. You don't
605// need to do anything special to free it, because the contents are pure
606// value data with no additional data structures. Returns 0 on failure.
607
608
610//
611// CHARACTER TO GLYPH-INDEX CONVERSIOn
612
613STBTT_DEF int stbtt_FindGlyphIndex(const stbtt_fontinfo *info, int unicode_codepoint);
614// If you're going to perform multiple operations on the same character
615// and you want a speed-up, call this function with the character you're
616// going to process, then use glyph-based functions instead of the
617// codepoint-based functions.
618// Returns 0 if the character codepoint is not defined in the font.
619
620
622//
623// CHARACTER PROPERTIES
624//
625
626STBTT_DEF float stbtt_ScaleForPixelHeight(const stbtt_fontinfo *info, float pixels);
627// computes a scale factor to produce a font whose "height" is 'pixels' tall.
628// Height is measured as the distance from the highest ascender to the lowest
629// descender; in other words, it's equivalent to calling stbtt_GetFontVMetrics
630// and computing:
631// scale = pixels / (ascent - descent)
632// so if you prefer to measure height by the ascent only, use a similar calculation.
633
634STBTT_DEF float stbtt_ScaleForMappingEmToPixels(const stbtt_fontinfo *info, float pixels);
635// computes a scale factor to produce a font whose EM size is mapped to
636// 'pixels' tall. This is probably what traditional APIs compute, but
637// I'm not positive.
638
639STBTT_DEF void stbtt_GetFontVMetrics(const stbtt_fontinfo *info, int *ascent, int *descent, int *lineGap);
640// ascent is the coordinate above the baseline the font extends; descent
641// is the coordinate below the baseline the font extends (i.e. it is typically negative)
642// lineGap is the spacing between one row's descent and the next row's ascent...
643// so you should advance the vertical position by "*ascent - *descent + *lineGap"
644// these are expressed in unscaled coordinates, so you must multiply by
645// the scale factor for a given size
646
647STBTT_DEF int stbtt_GetFontVMetricsOS2(const stbtt_fontinfo *info, int *typoAscent, int *typoDescent, int *typoLineGap);
648// analogous to GetFontVMetrics, but returns the "typographic" values from the OS/2
649// table (specific to MS/Windows TTF files).
650//
651// Returns 1 on success (table present), 0 on failure.
652
653STBTT_DEF void stbtt_GetFontBoundingBox(const stbtt_fontinfo *info, int *x0, int *y0, int *x1, int *y1);
654// the bounding box around all possible characters
655
656STBTT_DEF void stbtt_GetCodepointHMetrics(const stbtt_fontinfo *info, int codepoint, int *advanceWidth, int *leftSideBearing);
657// leftSideBearing is the offset from the current horizontal position to the left edge of the character
658// advanceWidth is the offset from the current horizontal position to the next horizontal position
659// these are expressed in unscaled coordinates
660
661STBTT_DEF int stbtt_GetCodepointKernAdvance(const stbtt_fontinfo *info, int ch1, int ch2);
662// an additional amount to add to the 'advance' value between ch1 and ch2
663
664STBTT_DEF int stbtt_GetCodepointBox(const stbtt_fontinfo *info, int codepoint, int *x0, int *y0, int *x1, int *y1);
665// Gets the bounding box of the visible part of the glyph, in unscaled coordinates
666
667STBTT_DEF void stbtt_GetGlyphHMetrics(const stbtt_fontinfo *info, int glyph_index, int *advanceWidth, int *leftSideBearing);
668STBTT_DEF int stbtt_GetGlyphKernAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2);
669STBTT_DEF int stbtt_GetGlyphBox(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1);
670// as above, but takes one or more glyph indices for greater efficiency
671
672typedef struct stbtt_kerningentry
673{
674 int glyph1; // use stbtt_FindGlyphIndex
678
679STBTT_DEF int stbtt_GetKerningTableLength(const stbtt_fontinfo *info);
680STBTT_DEF int stbtt_GetKerningTable(const stbtt_fontinfo *info, stbtt_kerningentry* table, int table_length);
681// Retrieves a complete list of all of the kerning pairs provided by the font
682// stbtt_GetKerningTable never writes more than table_length entries and returns how many entries it did write.
683// The table will be sorted by (a.glyph1 == b.glyph1)?(a.glyph2 < b.glyph2):(a.glyph1 < b.glyph1)
684
686//
687// GLYPH SHAPES (you probably don't need these, but they have to go before
688// the bitmaps for C declaration-order reasons)
689//
690
691#ifndef STBTT_vmove // you can predefine these to use different values (but why?)
692 enum {
697 };
698#endif
699
700#ifndef stbtt_vertex // you can predefine this to use different values
701 // (we share this with other code at RAD)
702 #define stbtt_vertex_type short // can't use stbtt_int16 because that's not visible in the header file
703 typedef struct
704 {
705 stbtt_vertex_type x,y,cx,cy,cx1,cy1;
706 unsigned char type,padding;
707 } stbtt_vertex;
708#endif
709
710STBTT_DEF int stbtt_IsGlyphEmpty(const stbtt_fontinfo *info, int glyph_index);
711// returns non-zero if nothing is drawn for this glyph
712
713STBTT_DEF int stbtt_GetCodepointShape(const stbtt_fontinfo *info, int unicode_codepoint, stbtt_vertex **vertices);
714STBTT_DEF int stbtt_GetGlyphShape(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **vertices);
715// returns # of vertices and fills *vertices with the pointer to them
716// these are expressed in "unscaled" coordinates
717//
718// The shape is a series of contours. Each one starts with
719// a STBTT_moveto, then consists of a series of mixed
720// STBTT_lineto and STBTT_curveto segments. A lineto
721// draws a line from previous endpoint to its x,y; a curveto
722// draws a quadratic bezier from previous endpoint to
723// its x,y, using cx,cy as the bezier control point.
724
725STBTT_DEF void stbtt_FreeShape(const stbtt_fontinfo *info, stbtt_vertex *vertices);
726// frees the data allocated above
727
728STBTT_DEF unsigned char *stbtt_FindSVGDoc(const stbtt_fontinfo *info, int gl);
729STBTT_DEF int stbtt_GetCodepointSVG(const stbtt_fontinfo *info, int unicode_codepoint, const char **svg);
730STBTT_DEF int stbtt_GetGlyphSVG(const stbtt_fontinfo *info, int gl, const char **svg);
731// fills svg with the character's SVG data.
732// returns data size or 0 if SVG not found.
733
735//
736// BITMAP RENDERING
737//
738
739STBTT_DEF void stbtt_FreeBitmap(unsigned char *bitmap, void *userdata);
740// frees the bitmap allocated below
741
742STBTT_DEF unsigned char *stbtt_GetCodepointBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int codepoint, int *width, int *height, int *xoff, int *yoff);
743// allocates a large-enough single-channel 8bpp bitmap and renders the
744// specified character/glyph at the specified scale into it, with
745// antialiasing. 0 is no coverage (transparent), 255 is fully covered (opaque).
746// *width & *height are filled out with the width & height of the bitmap,
747// which is stored left-to-right, top-to-bottom.
748//
749// xoff/yoff are the offset it pixel space from the glyph origin to the top-left of the bitmap
750
751STBTT_DEF unsigned char *stbtt_GetCodepointBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint, int *width, int *height, int *xoff, int *yoff);
752// the same as stbtt_GetCodepoitnBitmap, but you can specify a subpixel
753// shift for the character
754
755STBTT_DEF void stbtt_MakeCodepointBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int codepoint);
756// the same as stbtt_GetCodepointBitmap, but you pass in storage for the bitmap
757// in the form of 'output', with row spacing of 'out_stride' bytes. the bitmap
758// is clipped to out_w/out_h bytes. Call stbtt_GetCodepointBitmapBox to get the
759// width and height and positioning info for it first.
760
761STBTT_DEF void stbtt_MakeCodepointBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint);
762// same as stbtt_MakeCodepointBitmap, but you can specify a subpixel
763// shift for the character
764
765STBTT_DEF void stbtt_MakeCodepointBitmapSubpixelPrefilter(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int oversample_x, int oversample_y, float *sub_x, float *sub_y, int codepoint);
766// same as stbtt_MakeCodepointBitmapSubpixel, but prefiltering
767// is performed (see stbtt_PackSetOversampling)
768
769STBTT_DEF void stbtt_GetCodepointBitmapBox(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1);
770// get the bbox of the bitmap centered around the glyph origin; so the
771// bitmap width is ix1-ix0, height is iy1-iy0, and location to place
772// the bitmap top left is (leftSideBearing*scale,iy0).
773// (Note that the bitmap uses y-increases-down, but the shape uses
774// y-increases-up, so CodepointBitmapBox and CodepointBox are inverted.)
775
776STBTT_DEF void stbtt_GetCodepointBitmapBoxSubpixel(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1);
777// same as stbtt_GetCodepointBitmapBox, but you can specify a subpixel
778// shift for the character
779
780// the following functions are equivalent to the above functions, but operate
781// on glyph indices instead of Unicode codepoints (for efficiency)
782STBTT_DEF unsigned char *stbtt_GetGlyphBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int glyph, int *width, int *height, int *xoff, int *yoff);
783STBTT_DEF unsigned char *stbtt_GetGlyphBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int glyph, int *width, int *height, int *xoff, int *yoff);
784STBTT_DEF void stbtt_MakeGlyphBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int glyph);
785STBTT_DEF void stbtt_MakeGlyphBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int glyph);
786STBTT_DEF void stbtt_MakeGlyphBitmapSubpixelPrefilter(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int oversample_x, int oversample_y, float *sub_x, float *sub_y, int glyph);
787STBTT_DEF void stbtt_GetGlyphBitmapBox(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1);
788STBTT_DEF void stbtt_GetGlyphBitmapBoxSubpixel(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y,float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1);
789
790
791// @TODO: don't expose this structure
792typedef struct
793{
794 int w,h,stride;
795 unsigned char *pixels;
797
798// rasterize a shape with quadratic beziers into a bitmap
799STBTT_DEF void stbtt_Rasterize(stbtt__bitmap *result, // 1-channel bitmap to draw into
800 float flatness_in_pixels, // allowable error of curve in pixels
801 stbtt_vertex *vertices, // array of vertices defining shape
802 int num_verts, // number of vertices in above array
803 float scale_x, float scale_y, // scale applied to input vertices
804 float shift_x, float shift_y, // translation applied to input vertices
805 int x_off, int y_off, // another translation applied to input
806 int invert, // if non-zero, vertically flip shape
807 void *userdata); // context for to STBTT_MALLOC
808
810//
811// Signed Distance Function (or Field) rendering
812
813STBTT_DEF void stbtt_FreeSDF(unsigned char *bitmap, void *userdata);
814// frees the SDF bitmap allocated below
815
816STBTT_DEF unsigned char * stbtt_GetGlyphSDF(const stbtt_fontinfo *info, float scale, int glyph, int padding, unsigned char onedge_value, float pixel_dist_scale, int *width, int *height, int *xoff, int *yoff);
817STBTT_DEF unsigned char * stbtt_GetCodepointSDF(const stbtt_fontinfo *info, float scale, int codepoint, int padding, unsigned char onedge_value, float pixel_dist_scale, int *width, int *height, int *xoff, int *yoff);
818// These functions compute a discretized SDF field for a single character, suitable for storing
819// in a single-channel texture, sampling with bilinear filtering, and testing against
820// larger than some threshold to produce scalable fonts.
821// info -- the font
822// scale -- controls the size of the resulting SDF bitmap, same as it would be creating a regular bitmap
823// glyph/codepoint -- the character to generate the SDF for
824// padding -- extra "pixels" around the character which are filled with the distance to the character (not 0),
825// which allows effects like bit outlines
826// onedge_value -- value 0-255 to test the SDF against to reconstruct the character (i.e. the isocontour of the character)
827// pixel_dist_scale -- what value the SDF should increase by when moving one SDF "pixel" away from the edge (on the 0..255 scale)
828// if positive, > onedge_value is inside; if negative, < onedge_value is inside
829// width,height -- output height & width of the SDF bitmap (including padding)
830// xoff,yoff -- output origin of the character
831// return value -- a 2D array of bytes 0..255, width*height in size
832//
833// pixel_dist_scale & onedge_value are a scale & bias that allows you to make
834// optimal use of the limited 0..255 for your application, trading off precision
835// and special effects. SDF values outside the range 0..255 are clamped to 0..255.
836//
837// Example:
838// scale = stbtt_ScaleForPixelHeight(22)
839// padding = 5
840// onedge_value = 180
841// pixel_dist_scale = 180/5.0 = 36.0
842//
843// This will create an SDF bitmap in which the character is about 22 pixels
844// high but the whole bitmap is about 22+5+5=32 pixels high. To produce a filled
845// shape, sample the SDF at each pixel and fill the pixel if the SDF value
846// is greater than or equal to 180/255. (You'll actually want to antialias,
847// which is beyond the scope of this example.) Additionally, you can compute
848// offset outlines (e.g. to stroke the character border inside & outside,
849// or only outside). For example, to fill outside the character up to 3 SDF
850// pixels, you would compare against (180-36.0*3)/255 = 72/255. The above
851// choice of variables maps a range from 5 pixels outside the shape to
852// 2 pixels inside the shape to 0..255; this is intended primarily for apply
853// outside effects only (the interior range is needed to allow proper
854// antialiasing of the font at *smaller* sizes)
855//
856// The function computes the SDF analytically at each SDF pixel, not by e.g.
857// building a higher-res bitmap and approximating it. In theory the quality
858// should be as high as possible for an SDF of this size & representation, but
859// unclear if this is true in practice (perhaps building a higher-res bitmap
860// and computing from that can allow drop-out prevention).
861//
862// The algorithm has not been optimized at all, so expect it to be slow
863// if computing lots of characters or very large sizes.
864
865
866
868//
869// Finding the right font...
870//
871// You should really just solve this offline, keep your own tables
872// of what font is what, and don't try to get it out of the .ttf file.
873// That's because getting it out of the .ttf file is really hard, because
874// the names in the file can appear in many possible encodings, in many
875// possible languages, and e.g. if you need a case-insensitive comparison,
876// the details of that depend on the encoding & language in a complex way
877// (actually underspecified in truetype, but also gigantic).
878//
879// But you can use the provided functions in two possible ways:
880// stbtt_FindMatchingFont() will use *case-sensitive* comparisons on
881// unicode-encoded names to try to find the font you want;
882// you can run this before calling stbtt_InitFont()
883//
884// stbtt_GetFontNameString() lets you get any of the various strings
885// from the file yourself and do your own comparisons on them.
886// You have to have called stbtt_InitFont() first.
887
888
889STBTT_DEF int stbtt_FindMatchingFont(const unsigned char *fontdata, const char *name, int flags);
890// returns the offset (not index) of the font that matches, or -1 if none
891// if you use STBTT_MACSTYLE_DONTCARE, use a font name like "Arial Bold".
892// if you use any other flag, use a font name like "Arial"; this checks
893// the 'macStyle' header field; i don't know if fonts set this consistently
894#define STBTT_MACSTYLE_DONTCARE 0
895#define STBTT_MACSTYLE_BOLD 1
896#define STBTT_MACSTYLE_ITALIC 2
897#define STBTT_MACSTYLE_UNDERSCORE 4
898#define STBTT_MACSTYLE_NONE 8 // <= not same as 0, this makes us check the bitfield is 0
899
900STBTT_DEF int stbtt_CompareUTF8toUTF16_bigendian(const char *s1, int len1, const char *s2, int len2);
901// returns 1/0 whether the first string interpreted as utf8 is identical to
902// the second string interpreted as big-endian utf16... useful for strings from next func
903
904STBTT_DEF const char *stbtt_GetFontNameString(const stbtt_fontinfo *font, int *length, int platformID, int encodingID, int languageID, int nameID);
905// returns the string (which may be big-endian double byte, e.g. for unicode)
906// and puts the length in bytes in *length.
907//
908// some of the values for the IDs are below; for more see the truetype spec:
909// http://developer.apple.com/textfonts/TTRefMan/RM06/Chap6name.html
910// http://www.microsoft.com/typography/otspec/name.htm
911
912enum { // platformID
918
919enum { // encodingID for STBTT_PLATFORM_ID_UNICODE
926
927enum { // encodingID for STBTT_PLATFORM_ID_MICROSOFT
933
934enum { // encodingID for STBTT_PLATFORM_ID_MAC; same as Script Manager codes
940
941enum { // languageID for STBTT_PLATFORM_ID_MICROSOFT; same as LCID...
942 // problematic because there are e.g. 16 english LCIDs and 16 arabic LCIDs
950
951enum { // languageID for STBTT_PLATFORM_ID_MAC
960
961#ifdef __cplusplus
962}
963#endif
964
965#endif // PLUTOVG_STB_TRUETYPE_H
966
973
974#ifdef STB_TRUETYPE_IMPLEMENTATION
975
976#ifndef STBTT_MAX_OVERSAMPLE
977#define STBTT_MAX_OVERSAMPLE 8
978#endif
979
980#if STBTT_MAX_OVERSAMPLE > 255
981#error "STBTT_MAX_OVERSAMPLE cannot be > 255"
982#endif
983
985
986#ifndef STBTT_RASTERIZER_VERSION
987#define STBTT_RASTERIZER_VERSION 2
988#endif
989
990#ifdef _MSC_VER
991#define STBTT__NOTUSED(v) (void)(v)
992#else
993#define STBTT__NOTUSED(v) (void)sizeof(v)
994#endif
995
997//
998// stbtt__buf helpers to parse data from file
999//
1000
1001static stbtt_uint8 stbtt__buf_get8(stbtt__buf *b)
1002{
1003 if (b->cursor >= b->size)
1004 return 0;
1005 return b->data[b->cursor++];
1006}
1007
1008static stbtt_uint8 stbtt__buf_peek8(stbtt__buf *b)
1009{
1010 if (b->cursor >= b->size)
1011 return 0;
1012 return b->data[b->cursor];
1013}
1014
1015static void stbtt__buf_seek(stbtt__buf *b, int o)
1016{
1017 STBTT_assert(!(o > b->size || o < 0));
1018 b->cursor = (o > b->size || o < 0) ? b->size : o;
1019}
1020
1021static void stbtt__buf_skip(stbtt__buf *b, int o)
1022{
1023 stbtt__buf_seek(b, b->cursor + o);
1024}
1025
1026static stbtt_uint32 stbtt__buf_get(stbtt__buf *b, int n)
1027{
1028 stbtt_uint32 v = 0;
1029 int i;
1030 STBTT_assert(n >= 1 && n <= 4);
1031 for (i = 0; i < n; i++)
1032 v = (v << 8) | stbtt__buf_get8(b);
1033 return v;
1034}
1035
1036static stbtt__buf stbtt__new_buf(const void *p, size_t size)
1037{
1038 stbtt__buf r;
1039 STBTT_assert(size < 0x40000000);
1040 r.data = (stbtt_uint8*) p;
1041 r.size = (int) size;
1042 r.cursor = 0;
1043 return r;
1044}
1045
1046#define stbtt__buf_get16(b) stbtt__buf_get((b), 2)
1047#define stbtt__buf_get32(b) stbtt__buf_get((b), 4)
1048
1049static stbtt__buf stbtt__buf_range(const stbtt__buf *b, int o, int s)
1050{
1051 stbtt__buf r = stbtt__new_buf(NULL, 0);
1052 if (o < 0 || s < 0 || o > b->size || s > b->size - o) return r;
1053 r.data = b->data + o;
1054 r.size = s;
1055 return r;
1056}
1057
1058static stbtt__buf stbtt__cff_get_index(stbtt__buf *b)
1059{
1060 int count, start, offsize;
1061 start = b->cursor;
1062 count = stbtt__buf_get16(b);
1063 if (count) {
1064 offsize = stbtt__buf_get8(b);
1065 STBTT_assert(offsize >= 1 && offsize <= 4);
1066 stbtt__buf_skip(b, offsize * count);
1067 stbtt__buf_skip(b, stbtt__buf_get(b, offsize) - 1);
1068 }
1069 return stbtt__buf_range(b, start, b->cursor - start);
1070}
1071
1072static stbtt_uint32 stbtt__cff_int(stbtt__buf *b)
1073{
1074 int b0 = stbtt__buf_get8(b);
1075 if (b0 >= 32 && b0 <= 246) return b0 - 139;
1076 else if (b0 >= 247 && b0 <= 250) return (b0 - 247)*256 + stbtt__buf_get8(b) + 108;
1077 else if (b0 >= 251 && b0 <= 254) return -(b0 - 251)*256 - stbtt__buf_get8(b) - 108;
1078 else if (b0 == 28) return stbtt__buf_get16(b);
1079 else if (b0 == 29) return stbtt__buf_get32(b);
1080 STBTT_assert(0);
1081 return 0;
1082}
1083
1084static void stbtt__cff_skip_operand(stbtt__buf *b) {
1085 int v, b0 = stbtt__buf_peek8(b);
1086 STBTT_assert(b0 >= 28);
1087 if (b0 == 30) {
1088 stbtt__buf_skip(b, 1);
1089 while (b->cursor < b->size) {
1090 v = stbtt__buf_get8(b);
1091 if ((v & 0xF) == 0xF || (v >> 4) == 0xF)
1092 break;
1093 }
1094 } else {
1095 stbtt__cff_int(b);
1096 }
1097}
1098
1099static stbtt__buf stbtt__dict_get(stbtt__buf *b, int key)
1100{
1101 stbtt__buf_seek(b, 0);
1102 while (b->cursor < b->size) {
1103 int start = b->cursor, end, op;
1104 while (stbtt__buf_peek8(b) >= 28)
1105 stbtt__cff_skip_operand(b);
1106 end = b->cursor;
1107 op = stbtt__buf_get8(b);
1108 if (op == 12) op = stbtt__buf_get8(b) | 0x100;
1109 if (op == key) return stbtt__buf_range(b, start, end-start);
1110 }
1111 return stbtt__buf_range(b, 0, 0);
1112}
1113
1114static void stbtt__dict_get_ints(stbtt__buf *b, int key, int outcount, stbtt_uint32 *out)
1115{
1116 int i;
1117 stbtt__buf operands = stbtt__dict_get(b, key);
1118 for (i = 0; i < outcount && operands.cursor < operands.size; i++)
1119 out[i] = stbtt__cff_int(&operands);
1120}
1121
1122static int stbtt__cff_index_count(stbtt__buf *b)
1123{
1124 stbtt__buf_seek(b, 0);
1125 return stbtt__buf_get16(b);
1126}
1127
1128static stbtt__buf stbtt__cff_index_get(stbtt__buf b, int i)
1129{
1130 int count, offsize, start, end;
1131 stbtt__buf_seek(&b, 0);
1132 count = stbtt__buf_get16(&b);
1133 offsize = stbtt__buf_get8(&b);
1134 STBTT_assert(i >= 0 && i < count);
1135 STBTT_assert(offsize >= 1 && offsize <= 4);
1136 stbtt__buf_skip(&b, i*offsize);
1137 start = stbtt__buf_get(&b, offsize);
1138 end = stbtt__buf_get(&b, offsize);
1139 return stbtt__buf_range(&b, 2+(count+1)*offsize+start, end - start);
1140}
1141
1143//
1144// accessors to parse data from file
1145//
1146
1147// on platforms that don't allow misaligned reads, if we want to allow
1148// truetype fonts that aren't padded to alignment, define ALLOW_UNALIGNED_TRUETYPE
1149
1150#define ttBYTE(p) (* (stbtt_uint8 *) (p))
1151#define ttCHAR(p) (* (stbtt_int8 *) (p))
1152#define ttFixed(p) ttLONG(p)
1153
1154static stbtt_uint16 ttUSHORT(stbtt_uint8 *p) { return p[0]*256 + p[1]; }
1155static stbtt_int16 ttSHORT(stbtt_uint8 *p) { return p[0]*256 + p[1]; }
1156static stbtt_uint32 ttULONG(stbtt_uint8 *p) { return (p[0]<<24) + (p[1]<<16) + (p[2]<<8) + p[3]; }
1157static stbtt_int32 ttLONG(stbtt_uint8 *p) { return (p[0]<<24) + (p[1]<<16) + (p[2]<<8) + p[3]; }
1158
1159#define stbtt_tag4(p,c0,c1,c2,c3) ((p)[0] == (c0) && (p)[1] == (c1) && (p)[2] == (c2) && (p)[3] == (c3))
1160#define stbtt_tag(p,str) stbtt_tag4(p,str[0],str[1],str[2],str[3])
1161
1162static int stbtt__isfont(stbtt_uint8 *font)
1163{
1164 // check the version number
1165 if (stbtt_tag4(font, '1',0,0,0)) return 1; // TrueType 1
1166 if (stbtt_tag(font, "typ1")) return 1; // TrueType with type 1 font -- we don't support this!
1167 if (stbtt_tag(font, "OTTO")) return 1; // OpenType with CFF
1168 if (stbtt_tag4(font, 0,1,0,0)) return 1; // OpenType 1.0
1169 if (stbtt_tag(font, "true")) return 1; // Apple specification for TrueType fonts
1170 return 0;
1171}
1172
1173// @OPTIMIZE: binary search
1174static stbtt_uint32 stbtt__find_table(stbtt_uint8 *data, stbtt_uint32 fontstart, const char *tag)
1175{
1176 stbtt_int32 num_tables = ttUSHORT(data+fontstart+4);
1177 stbtt_uint32 tabledir = fontstart + 12;
1178 stbtt_int32 i;
1179 for (i=0; i < num_tables; ++i) {
1180 stbtt_uint32 loc = tabledir + 16*i;
1181 if (stbtt_tag(data+loc+0, tag))
1182 return ttULONG(data+loc+8);
1183 }
1184 return 0;
1185}
1186
1187static int stbtt_GetFontOffsetForIndex_internal(unsigned char *font_collection, int index)
1188{
1189 // if it's just a font, there's only one valid index
1190 if (stbtt__isfont(font_collection))
1191 return index == 0 ? 0 : -1;
1192
1193 // check if it's a TTC
1194 if (stbtt_tag(font_collection, "ttcf")) {
1195 // version 1?
1196 if (ttULONG(font_collection+4) == 0x00010000 || ttULONG(font_collection+4) == 0x00020000) {
1197 stbtt_int32 n = ttLONG(font_collection+8);
1198 if (index >= n)
1199 return -1;
1200 return ttULONG(font_collection+12+index*4);
1201 }
1202 }
1203 return -1;
1204}
1205
1206static int stbtt_GetNumberOfFonts_internal(unsigned char *font_collection)
1207{
1208 // if it's just a font, there's only one valid font
1209 if (stbtt__isfont(font_collection))
1210 return 1;
1211
1212 // check if it's a TTC
1213 if (stbtt_tag(font_collection, "ttcf")) {
1214 // version 1?
1215 if (ttULONG(font_collection+4) == 0x00010000 || ttULONG(font_collection+4) == 0x00020000) {
1216 return ttLONG(font_collection+8);
1217 }
1218 }
1219 return 0;
1220}
1221
1222static stbtt__buf stbtt__get_subrs(stbtt__buf cff, stbtt__buf fontdict)
1223{
1224 stbtt_uint32 subrsoff = 0, private_loc[2] = { 0, 0 };
1225 stbtt__buf pdict;
1226 stbtt__dict_get_ints(&fontdict, 18, 2, private_loc);
1227 if (!private_loc[1] || !private_loc[0]) return stbtt__new_buf(NULL, 0);
1228 pdict = stbtt__buf_range(&cff, private_loc[1], private_loc[0]);
1229 stbtt__dict_get_ints(&pdict, 19, 1, &subrsoff);
1230 if (!subrsoff) return stbtt__new_buf(NULL, 0);
1231 stbtt__buf_seek(&cff, private_loc[1]+subrsoff);
1232 return stbtt__cff_get_index(&cff);
1233}
1234
1235// since most people won't use this, find this table the first time it's needed
1236static int stbtt__get_svg(stbtt_fontinfo *info)
1237{
1238 stbtt_uint32 t;
1239 if (info->svg < 0) {
1240 t = stbtt__find_table(info->data, info->fontstart, "SVG ");
1241 if (t) {
1242 stbtt_uint32 offset = ttULONG(info->data + t + 2);
1243 info->svg = t + offset;
1244 } else {
1245 info->svg = 0;
1246 }
1247 }
1248 return info->svg;
1249}
1250
1251static int stbtt_InitFont_internal(stbtt_fontinfo *info, unsigned char *data, int fontstart)
1252{
1253 stbtt_uint32 cmap, t;
1254 stbtt_int32 i,numTables;
1255
1256 info->data = data;
1257 info->fontstart = fontstart;
1258 info->cff = stbtt__new_buf(NULL, 0);
1259
1260 cmap = stbtt__find_table(data, fontstart, "cmap"); // required
1261 info->loca = stbtt__find_table(data, fontstart, "loca"); // required
1262 info->head = stbtt__find_table(data, fontstart, "head"); // required
1263 info->glyf = stbtt__find_table(data, fontstart, "glyf"); // required
1264 info->hhea = stbtt__find_table(data, fontstart, "hhea"); // required
1265 info->hmtx = stbtt__find_table(data, fontstart, "hmtx"); // required
1266 info->kern = stbtt__find_table(data, fontstart, "kern"); // not required
1267 info->gpos = stbtt__find_table(data, fontstart, "GPOS"); // not required
1268 info->gsub = stbtt__find_table(data, fontstart, "GSUB"); // not required
1269
1270 if (!cmap || !info->head || !info->hhea || !info->hmtx)
1271 return 0;
1272 if (info->glyf) {
1273 // required for truetype
1274 if (!info->loca) return 0;
1275 } else {
1276 // initialization for CFF / Type2 fonts (OTF)
1277 stbtt__buf b, topdict, topdictidx;
1278 stbtt_uint32 cstype = 2, charstrings = 0, fdarrayoff = 0, fdselectoff = 0;
1279 stbtt_uint32 cff;
1280
1281 cff = stbtt__find_table(data, fontstart, "CFF ");
1282 if (!cff) return 0;
1283
1284 info->fontdicts = stbtt__new_buf(NULL, 0);
1285 info->fdselect = stbtt__new_buf(NULL, 0);
1286
1287 // @TODO this should use size from table (not 512MB)
1288 info->cff = stbtt__new_buf(data+cff, 512*1024*1024);
1289 b = info->cff;
1290
1291 // read the header
1292 stbtt__buf_skip(&b, 2);
1293 stbtt__buf_seek(&b, stbtt__buf_get8(&b)); // hdrsize
1294
1295 // @TODO the name INDEX could list multiple fonts,
1296 // but we just use the first one.
1297 stbtt__cff_get_index(&b); // name INDEX
1298 topdictidx = stbtt__cff_get_index(&b);
1299 topdict = stbtt__cff_index_get(topdictidx, 0);
1300 stbtt__cff_get_index(&b); // string INDEX
1301 info->gsubrs = stbtt__cff_get_index(&b);
1302
1303 stbtt__dict_get_ints(&topdict, 17, 1, &charstrings);
1304 stbtt__dict_get_ints(&topdict, 0x100 | 6, 1, &cstype);
1305 stbtt__dict_get_ints(&topdict, 0x100 | 36, 1, &fdarrayoff);
1306 stbtt__dict_get_ints(&topdict, 0x100 | 37, 1, &fdselectoff);
1307 info->subrs = stbtt__get_subrs(b, topdict);
1308
1309 // we only support Type 2 charstrings
1310 if (cstype != 2) return 0;
1311 if (charstrings == 0) return 0;
1312
1313 if (fdarrayoff) {
1314 // looks like a CID font
1315 if (!fdselectoff) return 0;
1316 stbtt__buf_seek(&b, fdarrayoff);
1317 info->fontdicts = stbtt__cff_get_index(&b);
1318 info->fdselect = stbtt__buf_range(&b, fdselectoff, b.size-fdselectoff);
1319 }
1320
1321 stbtt__buf_seek(&b, charstrings);
1322 info->charstrings = stbtt__cff_get_index(&b);
1323 }
1324
1325 t = stbtt__find_table(data, fontstart, "maxp");
1326 if (t)
1327 info->numGlyphs = ttUSHORT(data+t+4);
1328 else
1329 info->numGlyphs = 0xffff;
1330
1331 info->svg = -1;
1332
1333 // find a cmap encoding table we understand *now* to avoid searching
1334 // later. (todo: could make this installable)
1335 // the same regardless of glyph.
1336 numTables = ttUSHORT(data + cmap + 2);
1337 info->index_map = 0;
1338 for (i=0; i < numTables; ++i) {
1339 stbtt_uint32 encoding_record = cmap + 4 + 8 * i;
1340 // find an encoding we understand:
1341 switch(ttUSHORT(data+encoding_record)) {
1343 switch (ttUSHORT(data+encoding_record+2)) {
1346 // MS/Unicode
1347 info->index_map = cmap + ttULONG(data+encoding_record+4);
1348 break;
1349 }
1350 break;
1352 // Mac/iOS has these
1353 // all the encodingIDs are unicode, so we don't bother to check it
1354 info->index_map = cmap + ttULONG(data+encoding_record+4);
1355 break;
1356 }
1357 }
1358 if (info->index_map == 0)
1359 return 0;
1360
1361 info->indexToLocFormat = ttUSHORT(data+info->head + 50);
1362 return 1;
1363}
1364
1365STBTT_DEF int stbtt_FindGlyphIndex(const stbtt_fontinfo *info, int unicode_codepoint)
1366{
1367 stbtt_uint8 *data = info->data;
1368 stbtt_uint32 index_map = info->index_map;
1369
1370 stbtt_uint16 format = ttUSHORT(data + index_map + 0);
1371 if (format == 0) { // apple byte encoding
1372 stbtt_int32 bytes = ttUSHORT(data + index_map + 2);
1373 if (unicode_codepoint < bytes-6)
1374 return ttBYTE(data + index_map + 6 + unicode_codepoint);
1375 return 0;
1376 } else if (format == 6) {
1377 stbtt_uint32 first = ttUSHORT(data + index_map + 6);
1378 stbtt_uint32 count = ttUSHORT(data + index_map + 8);
1379 if ((stbtt_uint32) unicode_codepoint >= first && (stbtt_uint32) unicode_codepoint < first+count)
1380 return ttUSHORT(data + index_map + 10 + (unicode_codepoint - first)*2);
1381 return 0;
1382 } else if (format == 2) {
1383 STBTT_assert(0); // @TODO: high-byte mapping for japanese/chinese/korean
1384 return 0;
1385 } else if (format == 4) { // standard mapping for windows fonts: binary search collection of ranges
1386 stbtt_uint16 segcount = ttUSHORT(data+index_map+6) >> 1;
1387 stbtt_uint16 searchRange = ttUSHORT(data+index_map+8) >> 1;
1388 stbtt_uint16 entrySelector = ttUSHORT(data+index_map+10);
1389 stbtt_uint16 rangeShift = ttUSHORT(data+index_map+12) >> 1;
1390
1391 // do a binary search of the segments
1392 stbtt_uint32 endCount = index_map + 14;
1393 stbtt_uint32 search = endCount;
1394
1395 if (unicode_codepoint > 0xffff)
1396 return 0;
1397
1398 // they lie from endCount .. endCount + segCount
1399 // but searchRange is the nearest power of two, so...
1400 if (unicode_codepoint >= ttUSHORT(data + search + rangeShift*2))
1401 search += rangeShift*2;
1402
1403 // now decrement to bias correctly to find smallest
1404 search -= 2;
1405 while (entrySelector) {
1406 stbtt_uint16 end;
1407 searchRange >>= 1;
1408 end = ttUSHORT(data + search + searchRange*2);
1409 if (unicode_codepoint > end)
1410 search += searchRange*2;
1411 --entrySelector;
1412 }
1413 search += 2;
1414
1415 {
1416 stbtt_uint16 offset, start, last;
1417 stbtt_uint16 item = (stbtt_uint16) ((search - endCount) >> 1);
1418
1419 start = ttUSHORT(data + index_map + 14 + segcount*2 + 2 + 2*item);
1420 last = ttUSHORT(data + endCount + 2*item);
1421 if (unicode_codepoint < start || unicode_codepoint > last)
1422 return 0;
1423
1424 offset = ttUSHORT(data + index_map + 14 + segcount*6 + 2 + 2*item);
1425 if (offset == 0)
1426 return (stbtt_uint16) (unicode_codepoint + ttSHORT(data + index_map + 14 + segcount*4 + 2 + 2*item));
1427
1428 return ttUSHORT(data + offset + (unicode_codepoint-start)*2 + index_map + 14 + segcount*6 + 2 + 2*item);
1429 }
1430 } else if (format == 12 || format == 13) {
1431 stbtt_uint32 ngroups = ttULONG(data+index_map+12);
1432 stbtt_int32 low,high;
1433 low = 0; high = (stbtt_int32)ngroups;
1434 // Binary search the right group.
1435 while (low < high) {
1436 stbtt_int32 mid = low + ((high-low) >> 1); // rounds down, so low <= mid < high
1437 stbtt_uint32 start_char = ttULONG(data+index_map+16+mid*12);
1438 stbtt_uint32 end_char = ttULONG(data+index_map+16+mid*12+4);
1439 if ((stbtt_uint32) unicode_codepoint < start_char)
1440 high = mid;
1441 else if ((stbtt_uint32) unicode_codepoint > end_char)
1442 low = mid+1;
1443 else {
1444 stbtt_uint32 start_glyph = ttULONG(data+index_map+16+mid*12+8);
1445 if (format == 12)
1446 return start_glyph + unicode_codepoint-start_char;
1447 else // format == 13
1448 return start_glyph;
1449 }
1450 }
1451 return 0; // not found
1452 }
1453 // @TODO
1454 STBTT_assert(0);
1455 return 0;
1456}
1457
1458STBTT_DEF int stbtt_GetCodepointShape(const stbtt_fontinfo *info, int unicode_codepoint, stbtt_vertex **vertices)
1459{
1460 return stbtt_GetGlyphShape(info, stbtt_FindGlyphIndex(info, unicode_codepoint), vertices);
1461}
1462
1463static void stbtt_setvertex(stbtt_vertex *v, stbtt_uint8 type, stbtt_int32 x, stbtt_int32 y, stbtt_int32 cx, stbtt_int32 cy)
1464{
1465 v->type = type;
1466 v->x = (stbtt_int16) x;
1467 v->y = (stbtt_int16) y;
1468 v->cx = (stbtt_int16) cx;
1469 v->cy = (stbtt_int16) cy;
1470}
1471
1472static int stbtt__GetGlyfOffset(const stbtt_fontinfo *info, int glyph_index)
1473{
1474 int g1,g2;
1475
1476 STBTT_assert(!info->cff.size);
1477
1478 if (glyph_index >= info->numGlyphs) return -1; // glyph index out of range
1479 if (info->indexToLocFormat >= 2) return -1; // unknown index->glyph map format
1480
1481 if (info->indexToLocFormat == 0) {
1482 g1 = info->glyf + ttUSHORT(info->data + info->loca + glyph_index * 2) * 2;
1483 g2 = info->glyf + ttUSHORT(info->data + info->loca + glyph_index * 2 + 2) * 2;
1484 } else {
1485 g1 = info->glyf + ttULONG (info->data + info->loca + glyph_index * 4);
1486 g2 = info->glyf + ttULONG (info->data + info->loca + glyph_index * 4 + 4);
1487 }
1488
1489 return g1==g2 ? -1 : g1; // if length is 0, return -1
1490}
1491
1492static int stbtt__GetGlyphInfoT2(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1);
1493
1494STBTT_DEF int stbtt_GetGlyphBox(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1)
1495{
1496 if (info->cff.size) {
1497 stbtt__GetGlyphInfoT2(info, glyph_index, x0, y0, x1, y1);
1498 } else {
1499 int g = stbtt__GetGlyfOffset(info, glyph_index);
1500 if (g < 0) return 0;
1501
1502 if (x0) *x0 = ttSHORT(info->data + g + 2);
1503 if (y0) *y0 = ttSHORT(info->data + g + 4);
1504 if (x1) *x1 = ttSHORT(info->data + g + 6);
1505 if (y1) *y1 = ttSHORT(info->data + g + 8);
1506 }
1507 return 1;
1508}
1509
1510STBTT_DEF int stbtt_GetCodepointBox(const stbtt_fontinfo *info, int codepoint, int *x0, int *y0, int *x1, int *y1)
1511{
1512 return stbtt_GetGlyphBox(info, stbtt_FindGlyphIndex(info,codepoint), x0,y0,x1,y1);
1513}
1514
1515STBTT_DEF int stbtt_IsGlyphEmpty(const stbtt_fontinfo *info, int glyph_index)
1516{
1517 stbtt_int16 numberOfContours;
1518 int g;
1519 if (info->cff.size)
1520 return stbtt__GetGlyphInfoT2(info, glyph_index, NULL, NULL, NULL, NULL) == 0;
1521 g = stbtt__GetGlyfOffset(info, glyph_index);
1522 if (g < 0) return 1;
1523 numberOfContours = ttSHORT(info->data + g);
1524 return numberOfContours == 0;
1525}
1526
1527static int stbtt__close_shape(stbtt_vertex *vertices, int num_vertices, int was_off, int start_off,
1529{
1530 if (start_off) {
1531 if (was_off)
1532 stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, (cx+scx)>>1, (cy+scy)>>1, cx,cy);
1533 stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, sx,sy,scx,scy);
1534 } else {
1535 if (was_off)
1536 stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve,sx,sy,cx,cy);
1537 else
1538 stbtt_setvertex(&vertices[num_vertices++], STBTT_vline,sx,sy,0,0);
1539 }
1540 return num_vertices;
1541}
1542
1543static int stbtt__GetGlyphShapeTT(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **pvertices)
1544{
1545 stbtt_int16 numberOfContours;
1546 stbtt_uint8 *endPtsOfContours;
1547 stbtt_uint8 *data = info->data;
1548 stbtt_vertex *vertices=0;
1549 int num_vertices=0;
1550 int g = stbtt__GetGlyfOffset(info, glyph_index);
1551
1552 *pvertices = NULL;
1553
1554 if (g < 0) return 0;
1555
1556 numberOfContours = ttSHORT(data + g);
1557
1558 if (numberOfContours > 0) {
1559 stbtt_uint8 flags=0,flagcount;
1560 stbtt_int32 ins, i,j=0,m,n, next_move, was_off=0, off, start_off=0;
1561 stbtt_int32 x,y,cx,cy,sx,sy, scx,scy;
1562 stbtt_uint8 *points;
1563 endPtsOfContours = (data + g + 10);
1564 ins = ttUSHORT(data + g + 10 + numberOfContours * 2);
1565 points = data + g + 10 + numberOfContours * 2 + 2 + ins;
1566
1567 n = 1+ttUSHORT(endPtsOfContours + numberOfContours*2-2);
1568
1569 m = n + 2*numberOfContours; // a loose bound on how many vertices we might need
1570 vertices = (stbtt_vertex *) STBTT_malloc(m * sizeof(vertices[0]), info->userdata);
1571 if (vertices == 0)
1572 return 0;
1573
1574 next_move = 0;
1575 flagcount=0;
1576
1577 // in first pass, we load uninterpreted data into the allocated array
1578 // above, shifted to the end of the array so we won't overwrite it when
1579 // we create our final data starting from the front
1580
1581 off = m - n; // starting offset for uninterpreted data, regardless of how m ends up being calculated
1582
1583 // first load flags
1584
1585 for (i=0; i < n; ++i) {
1586 if (flagcount == 0) {
1587 flags = *points++;
1588 if (flags & 8)
1589 flagcount = *points++;
1590 } else
1591 --flagcount;
1592 vertices[off+i].type = flags;
1593 }
1594
1595 // now load x coordinates
1596 x=0;
1597 for (i=0; i < n; ++i) {
1598 flags = vertices[off+i].type;
1599 if (flags & 2) {
1600 stbtt_int16 dx = *points++;
1601 x += (flags & 16) ? dx : -dx; // ???
1602 } else {
1603 if (!(flags & 16)) {
1604 x = x + (stbtt_int16) (points[0]*256 + points[1]);
1605 points += 2;
1606 }
1607 }
1608 vertices[off+i].x = (stbtt_int16) x;
1609 }
1610
1611 // now load y coordinates
1612 y=0;
1613 for (i=0; i < n; ++i) {
1614 flags = vertices[off+i].type;
1615 if (flags & 4) {
1616 stbtt_int16 dy = *points++;
1617 y += (flags & 32) ? dy : -dy; // ???
1618 } else {
1619 if (!(flags & 32)) {
1620 y = y + (stbtt_int16) (points[0]*256 + points[1]);
1621 points += 2;
1622 }
1623 }
1624 vertices[off+i].y = (stbtt_int16) y;
1625 }
1626
1627 // now convert them to our format
1628 num_vertices=0;
1629 sx = sy = cx = cy = scx = scy = 0;
1630 for (i=0; i < n; ++i) {
1631 flags = vertices[off+i].type;
1632 x = (stbtt_int16) vertices[off+i].x;
1633 y = (stbtt_int16) vertices[off+i].y;
1634
1635 if (next_move == i) {
1636 if (i != 0)
1637 num_vertices = stbtt__close_shape(vertices, num_vertices, was_off, start_off, sx,sy,scx,scy,cx,cy);
1638
1639 // now start the new one
1640 start_off = !(flags & 1);
1641 if (start_off) {
1642 // if we start off with an off-curve point, then when we need to find a point on the curve
1643 // where we can start, and we need to save some state for when we wraparound.
1644 scx = x;
1645 scy = y;
1646 if (!(vertices[off+i+1].type & 1)) {
1647 // next point is also a curve point, so interpolate an on-point curve
1648 sx = (x + (stbtt_int32) vertices[off+i+1].x) >> 1;
1649 sy = (y + (stbtt_int32) vertices[off+i+1].y) >> 1;
1650 } else {
1651 // otherwise just use the next point as our start point
1652 sx = (stbtt_int32) vertices[off+i+1].x;
1653 sy = (stbtt_int32) vertices[off+i+1].y;
1654 ++i; // we're using point i+1 as the starting point, so skip it
1655 }
1656 } else {
1657 sx = x;
1658 sy = y;
1659 }
1660 stbtt_setvertex(&vertices[num_vertices++], STBTT_vmove,sx,sy,0,0);
1661 was_off = 0;
1662 next_move = 1 + ttUSHORT(endPtsOfContours+j*2);
1663 ++j;
1664 } else {
1665 if (!(flags & 1)) { // if it's a curve
1666 if (was_off) // two off-curve control points in a row means interpolate an on-curve midpoint
1667 stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, (cx+x)>>1, (cy+y)>>1, cx, cy);
1668 cx = x;
1669 cy = y;
1670 was_off = 1;
1671 } else {
1672 if (was_off)
1673 stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, x,y, cx, cy);
1674 else
1675 stbtt_setvertex(&vertices[num_vertices++], STBTT_vline, x,y,0,0);
1676 was_off = 0;
1677 }
1678 }
1679 }
1680 num_vertices = stbtt__close_shape(vertices, num_vertices, was_off, start_off, sx,sy,scx,scy,cx,cy);
1681 } else if (numberOfContours < 0) {
1682 // Compound shapes.
1683 int more = 1;
1684 stbtt_uint8 *comp = data + g + 10;
1685 num_vertices = 0;
1686 vertices = 0;
1687 while (more) {
1688 stbtt_uint16 flags, gidx;
1689 int comp_num_verts = 0, i;
1690 stbtt_vertex *comp_verts = 0, *tmp = 0;
1691 float mtx[6] = {1,0,0,1,0,0}, m, n;
1692
1693 flags = ttSHORT(comp); comp+=2;
1694 gidx = ttSHORT(comp); comp+=2;
1695
1696 if (flags & 2) { // XY values
1697 if (flags & 1) { // shorts
1698 mtx[4] = ttSHORT(comp); comp+=2;
1699 mtx[5] = ttSHORT(comp); comp+=2;
1700 } else {
1701 mtx[4] = ttCHAR(comp); comp+=1;
1702 mtx[5] = ttCHAR(comp); comp+=1;
1703 }
1704 }
1705 else {
1706 // @TODO handle matching point
1707 STBTT_assert(0);
1708 }
1709 if (flags & (1<<3)) { // WE_HAVE_A_SCALE
1710 mtx[0] = mtx[3] = ttSHORT(comp)/16384.0f; comp+=2;
1711 mtx[1] = mtx[2] = 0;
1712 } else if (flags & (1<<6)) { // WE_HAVE_AN_X_AND_YSCALE
1713 mtx[0] = ttSHORT(comp)/16384.0f; comp+=2;
1714 mtx[1] = mtx[2] = 0;
1715 mtx[3] = ttSHORT(comp)/16384.0f; comp+=2;
1716 } else if (flags & (1<<7)) { // WE_HAVE_A_TWO_BY_TWO
1717 mtx[0] = ttSHORT(comp)/16384.0f; comp+=2;
1718 mtx[1] = ttSHORT(comp)/16384.0f; comp+=2;
1719 mtx[2] = ttSHORT(comp)/16384.0f; comp+=2;
1720 mtx[3] = ttSHORT(comp)/16384.0f; comp+=2;
1721 }
1722
1723 // Find transformation scales.
1724 m = (float) STBTT_sqrt(mtx[0]*mtx[0] + mtx[1]*mtx[1]);
1725 n = (float) STBTT_sqrt(mtx[2]*mtx[2] + mtx[3]*mtx[3]);
1726
1727 // Get indexed glyph.
1728 comp_num_verts = stbtt_GetGlyphShape(info, gidx, &comp_verts);
1729 if (comp_num_verts > 0) {
1730 // Transform vertices.
1731 for (i = 0; i < comp_num_verts; ++i) {
1732 stbtt_vertex* v = &comp_verts[i];
1734 x=v->x; y=v->y;
1735 v->x = (stbtt_vertex_type)(m * (mtx[0]*x + mtx[2]*y + mtx[4]));
1736 v->y = (stbtt_vertex_type)(n * (mtx[1]*x + mtx[3]*y + mtx[5]));
1737 x=v->cx; y=v->cy;
1738 v->cx = (stbtt_vertex_type)(m * (mtx[0]*x + mtx[2]*y + mtx[4]));
1739 v->cy = (stbtt_vertex_type)(n * (mtx[1]*x + mtx[3]*y + mtx[5]));
1740 }
1741 // Append vertices.
1742 tmp = (stbtt_vertex*)STBTT_malloc((num_vertices+comp_num_verts)*sizeof(stbtt_vertex), info->userdata);
1743 if (!tmp) {
1744 if (vertices) STBTT_free(vertices, info->userdata);
1745 if (comp_verts) STBTT_free(comp_verts, info->userdata);
1746 return 0;
1747 }
1748 if (num_vertices > 0 && vertices) STBTT_memcpy(tmp, vertices, num_vertices*sizeof(stbtt_vertex));
1749 STBTT_memcpy(tmp+num_vertices, comp_verts, comp_num_verts*sizeof(stbtt_vertex));
1750 if (vertices) STBTT_free(vertices, info->userdata);
1751 vertices = tmp;
1752 STBTT_free(comp_verts, info->userdata);
1753 num_vertices += comp_num_verts;
1754 }
1755 // More components ?
1756 more = flags & (1<<5);
1757 }
1758 } else {
1759 // numberOfCounters == 0, do nothing
1760 }
1761
1762 *pvertices = vertices;
1763 return num_vertices;
1764}
1765
1766typedef struct
1767{
1770 float first_x, first_y;
1771 float x, y;
1772 stbtt_int32 min_x, max_x, min_y, max_y;
1773
1776} stbtt__csctx;
1777
1778#define STBTT__CSCTX_INIT(bounds) {bounds,0, 0,0, 0,0, 0,0,0,0, NULL, 0}
1779
1780static void stbtt__track_vertex(stbtt__csctx *c, stbtt_int32 x, stbtt_int32 y)
1781{
1782 if (x > c->max_x || !c->started) c->max_x = x;
1783 if (y > c->max_y || !c->started) c->max_y = y;
1784 if (x < c->min_x || !c->started) c->min_x = x;
1785 if (y < c->min_y || !c->started) c->min_y = y;
1786 c->started = 1;
1787}
1788
1789static 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)
1790{
1791 if (c->bounds) {
1792 stbtt__track_vertex(c, x, y);
1793 if (type == STBTT_vcubic) {
1794 stbtt__track_vertex(c, cx, cy);
1795 stbtt__track_vertex(c, cx1, cy1);
1796 }
1797 } else {
1798 stbtt_setvertex(&c->pvertices[c->num_vertices], type, x, y, cx, cy);
1799 c->pvertices[c->num_vertices].cx1 = (stbtt_int16) cx1;
1800 c->pvertices[c->num_vertices].cy1 = (stbtt_int16) cy1;
1801 }
1802 c->num_vertices++;
1803}
1804
1805static void stbtt__csctx_close_shape(stbtt__csctx *ctx)
1806{
1807 if (ctx->first_x != ctx->x || ctx->first_y != ctx->y)
1808 stbtt__csctx_v(ctx, STBTT_vline, (int)ctx->first_x, (int)ctx->first_y, 0, 0, 0, 0);
1809}
1810
1811static void stbtt__csctx_rmove_to(stbtt__csctx *ctx, float dx, float dy)
1812{
1813 stbtt__csctx_close_shape(ctx);
1814 ctx->first_x = ctx->x = ctx->x + dx;
1815 ctx->first_y = ctx->y = ctx->y + dy;
1816 stbtt__csctx_v(ctx, STBTT_vmove, (int)ctx->x, (int)ctx->y, 0, 0, 0, 0);
1817}
1818
1819static void stbtt__csctx_rline_to(stbtt__csctx *ctx, float dx, float dy)
1820{
1821 ctx->x += dx;
1822 ctx->y += dy;
1823 stbtt__csctx_v(ctx, STBTT_vline, (int)ctx->x, (int)ctx->y, 0, 0, 0, 0);
1824}
1825
1826static void stbtt__csctx_rccurve_to(stbtt__csctx *ctx, float dx1, float dy1, float dx2, float dy2, float dx3, float dy3)
1827{
1828 float cx1 = ctx->x + dx1;
1829 float cy1 = ctx->y + dy1;
1830 float cx2 = cx1 + dx2;
1831 float cy2 = cy1 + dy2;
1832 ctx->x = cx2 + dx3;
1833 ctx->y = cy2 + dy3;
1834 stbtt__csctx_v(ctx, STBTT_vcubic, (int)ctx->x, (int)ctx->y, (int)cx1, (int)cy1, (int)cx2, (int)cy2);
1835}
1836
1837static stbtt__buf stbtt__get_subr(stbtt__buf idx, int n)
1838{
1839 int count = stbtt__cff_index_count(&idx);
1840 int bias = 107;
1841 if (count >= 33900)
1842 bias = 32768;
1843 else if (count >= 1240)
1844 bias = 1131;
1845 n += bias;
1846 if (n < 0 || n >= count)
1847 return stbtt__new_buf(NULL, 0);
1848 return stbtt__cff_index_get(idx, n);
1849}
1850
1851static stbtt__buf stbtt__cid_get_glyph_subrs(const stbtt_fontinfo *info, int glyph_index)
1852{
1853 stbtt__buf fdselect = info->fdselect;
1854 int nranges, start, end, v, fmt, fdselector = -1, i;
1855
1856 stbtt__buf_seek(&fdselect, 0);
1857 fmt = stbtt__buf_get8(&fdselect);
1858 if (fmt == 0) {
1859 // untested
1860 stbtt__buf_skip(&fdselect, glyph_index);
1861 fdselector = stbtt__buf_get8(&fdselect);
1862 } else if (fmt == 3) {
1863 nranges = stbtt__buf_get16(&fdselect);
1864 start = stbtt__buf_get16(&fdselect);
1865 for (i = 0; i < nranges; i++) {
1866 v = stbtt__buf_get8(&fdselect);
1867 end = stbtt__buf_get16(&fdselect);
1868 if (glyph_index >= start && glyph_index < end) {
1869 fdselector = v;
1870 break;
1871 }
1872 start = end;
1873 }
1874 }
1875 if (fdselector == -1) stbtt__new_buf(NULL, 0);
1876 return stbtt__get_subrs(info->cff, stbtt__cff_index_get(info->fontdicts, fdselector));
1877}
1878
1879static int stbtt__run_charstring(const stbtt_fontinfo *info, int glyph_index, stbtt__csctx *c)
1880{
1881 int in_header = 1, maskbits = 0, subr_stack_height = 0, sp = 0, v, i, b0;
1882 int has_subrs = 0, clear_stack;
1883 float s[48];
1884 stbtt__buf subr_stack[10], subrs = info->subrs, b;
1885 float f;
1886
1887#define STBTT__CSERR(s) (0)
1888
1889 // this currently ignores the initial width value, which isn't needed if we have hmtx
1890 b = stbtt__cff_index_get(info->charstrings, glyph_index);
1891 while (b.cursor < b.size) {
1892 i = 0;
1893 clear_stack = 1;
1894 b0 = stbtt__buf_get8(&b);
1895 switch (b0) {
1896 // @TODO implement hinting
1897 case 0x13: // hintmask
1898 case 0x14: // cntrmask
1899 if (in_header)
1900 maskbits += (sp / 2); // implicit "vstem"
1901 in_header = 0;
1902 stbtt__buf_skip(&b, (maskbits + 7) / 8);
1903 break;
1904
1905 case 0x01: // hstem
1906 case 0x03: // vstem
1907 case 0x12: // hstemhm
1908 case 0x17: // vstemhm
1909 maskbits += (sp / 2);
1910 break;
1911
1912 case 0x15: // rmoveto
1913 in_header = 0;
1914 if (sp < 2) return STBTT__CSERR("rmoveto stack");
1915 stbtt__csctx_rmove_to(c, s[sp-2], s[sp-1]);
1916 break;
1917 case 0x04: // vmoveto
1918 in_header = 0;
1919 if (sp < 1) return STBTT__CSERR("vmoveto stack");
1920 stbtt__csctx_rmove_to(c, 0, s[sp-1]);
1921 break;
1922 case 0x16: // hmoveto
1923 in_header = 0;
1924 if (sp < 1) return STBTT__CSERR("hmoveto stack");
1925 stbtt__csctx_rmove_to(c, s[sp-1], 0);
1926 break;
1927
1928 case 0x05: // rlineto
1929 if (sp < 2) return STBTT__CSERR("rlineto stack");
1930 for (; i + 1 < sp; i += 2)
1931 stbtt__csctx_rline_to(c, s[i], s[i+1]);
1932 break;
1933
1934 // hlineto/vlineto and vhcurveto/hvcurveto alternate horizontal and vertical
1935 // starting from a different place.
1936
1937 case 0x07: // vlineto
1938 if (sp < 1) return STBTT__CSERR("vlineto stack");
1939 goto vlineto;
1940 case 0x06: // hlineto
1941 if (sp < 1) return STBTT__CSERR("hlineto stack");
1942 for (;;) {
1943 if (i >= sp) break;
1944 stbtt__csctx_rline_to(c, s[i], 0);
1945 i++;
1946 vlineto:
1947 if (i >= sp) break;
1948 stbtt__csctx_rline_to(c, 0, s[i]);
1949 i++;
1950 }
1951 break;
1952
1953 case 0x1F: // hvcurveto
1954 if (sp < 4) return STBTT__CSERR("hvcurveto stack");
1955 goto hvcurveto;
1956 case 0x1E: // vhcurveto
1957 if (sp < 4) return STBTT__CSERR("vhcurveto stack");
1958 for (;;) {
1959 if (i + 3 >= sp) break;
1960 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);
1961 i += 4;
1962 hvcurveto:
1963 if (i + 3 >= sp) break;
1964 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]);
1965 i += 4;
1966 }
1967 break;
1968
1969 case 0x08: // rrcurveto
1970 if (sp < 6) return STBTT__CSERR("rcurveline stack");
1971 for (; i + 5 < sp; i += 6)
1972 stbtt__csctx_rccurve_to(c, s[i], s[i+1], s[i+2], s[i+3], s[i+4], s[i+5]);
1973 break;
1974
1975 case 0x18: // rcurveline
1976 if (sp < 8) return STBTT__CSERR("rcurveline stack");
1977 for (; i + 5 < sp - 2; i += 6)
1978 stbtt__csctx_rccurve_to(c, s[i], s[i+1], s[i+2], s[i+3], s[i+4], s[i+5]);
1979 if (i + 1 >= sp) return STBTT__CSERR("rcurveline stack");
1980 stbtt__csctx_rline_to(c, s[i], s[i+1]);
1981 break;
1982
1983 case 0x19: // rlinecurve
1984 if (sp < 8) return STBTT__CSERR("rlinecurve stack");
1985 for (; i + 1 < sp - 6; i += 2)
1986 stbtt__csctx_rline_to(c, s[i], s[i+1]);
1987 if (i + 5 >= sp) return STBTT__CSERR("rlinecurve stack");
1988 stbtt__csctx_rccurve_to(c, s[i], s[i+1], s[i+2], s[i+3], s[i+4], s[i+5]);
1989 break;
1990
1991 case 0x1A: // vvcurveto
1992 case 0x1B: // hhcurveto
1993 if (sp < 4) return STBTT__CSERR("(vv|hh)curveto stack");
1994 f = 0.0;
1995 if (sp & 1) { f = s[i]; i++; }
1996 for (; i + 3 < sp; i += 4) {
1997 if (b0 == 0x1B)
1998 stbtt__csctx_rccurve_to(c, s[i], f, s[i+1], s[i+2], s[i+3], 0.0);
1999 else
2000 stbtt__csctx_rccurve_to(c, f, s[i], s[i+1], s[i+2], 0.0, s[i+3]);
2001 f = 0.0;
2002 }
2003 break;
2004
2005 case 0x0A: // callsubr
2006 if (!has_subrs) {
2007 if (info->fdselect.size)
2008 subrs = stbtt__cid_get_glyph_subrs(info, glyph_index);
2009 has_subrs = 1;
2010 }
2011 // FALLTHROUGH
2012 case 0x1D: // callgsubr
2013 if (sp < 1) return STBTT__CSERR("call(g|)subr stack");
2014 v = (int) s[--sp];
2015 if (subr_stack_height >= 10) return STBTT__CSERR("recursion limit");
2016 subr_stack[subr_stack_height++] = b;
2017 b = stbtt__get_subr(b0 == 0x0A ? subrs : info->gsubrs, v);
2018 if (b.size == 0) return STBTT__CSERR("subr not found");
2019 b.cursor = 0;
2020 clear_stack = 0;
2021 break;
2022
2023 case 0x0B: // return
2024 if (subr_stack_height <= 0) return STBTT__CSERR("return outside subr");
2025 b = subr_stack[--subr_stack_height];
2026 clear_stack = 0;
2027 break;
2028
2029 case 0x0E: // endchar
2030 stbtt__csctx_close_shape(c);
2031 return 1;
2032
2033 case 0x0C: { // two-byte escape
2034 float dx1, dx2, dx3, dx4, dx5, dx6, dy1, dy2, dy3, dy4, dy5, dy6;
2035 float dx, dy;
2036 int b1 = stbtt__buf_get8(&b);
2037 switch (b1) {
2038 // @TODO These "flex" implementations ignore the flex-depth and resolution,
2039 // and always draw beziers.
2040 case 0x22: // hflex
2041 if (sp < 7) return STBTT__CSERR("hflex stack");
2042 dx1 = s[0];
2043 dx2 = s[1];
2044 dy2 = s[2];
2045 dx3 = s[3];
2046 dx4 = s[4];
2047 dx5 = s[5];
2048 dx6 = s[6];
2049 stbtt__csctx_rccurve_to(c, dx1, 0, dx2, dy2, dx3, 0);
2050 stbtt__csctx_rccurve_to(c, dx4, 0, dx5, -dy2, dx6, 0);
2051 break;
2052
2053 case 0x23: // flex
2054 if (sp < 13) return STBTT__CSERR("flex stack");
2055 dx1 = s[0];
2056 dy1 = s[1];
2057 dx2 = s[2];
2058 dy2 = s[3];
2059 dx3 = s[4];
2060 dy3 = s[5];
2061 dx4 = s[6];
2062 dy4 = s[7];
2063 dx5 = s[8];
2064 dy5 = s[9];
2065 dx6 = s[10];
2066 dy6 = s[11];
2067 //fd is s[12]
2068 stbtt__csctx_rccurve_to(c, dx1, dy1, dx2, dy2, dx3, dy3);
2069 stbtt__csctx_rccurve_to(c, dx4, dy4, dx5, dy5, dx6, dy6);
2070 break;
2071
2072 case 0x24: // hflex1
2073 if (sp < 9) return STBTT__CSERR("hflex1 stack");
2074 dx1 = s[0];
2075 dy1 = s[1];
2076 dx2 = s[2];
2077 dy2 = s[3];
2078 dx3 = s[4];
2079 dx4 = s[5];
2080 dx5 = s[6];
2081 dy5 = s[7];
2082 dx6 = s[8];
2083 stbtt__csctx_rccurve_to(c, dx1, dy1, dx2, dy2, dx3, 0);
2084 stbtt__csctx_rccurve_to(c, dx4, 0, dx5, dy5, dx6, -(dy1+dy2+dy5));
2085 break;
2086
2087 case 0x25: // flex1
2088 if (sp < 11) return STBTT__CSERR("flex1 stack");
2089 dx1 = s[0];
2090 dy1 = s[1];
2091 dx2 = s[2];
2092 dy2 = s[3];
2093 dx3 = s[4];
2094 dy3 = s[5];
2095 dx4 = s[6];
2096 dy4 = s[7];
2097 dx5 = s[8];
2098 dy5 = s[9];
2099 dx6 = dy6 = s[10];
2100 dx = dx1+dx2+dx3+dx4+dx5;
2101 dy = dy1+dy2+dy3+dy4+dy5;
2102 if (STBTT_fabs(dx) > STBTT_fabs(dy))
2103 dy6 = -dy;
2104 else
2105 dx6 = -dx;
2106 stbtt__csctx_rccurve_to(c, dx1, dy1, dx2, dy2, dx3, dy3);
2107 stbtt__csctx_rccurve_to(c, dx4, dy4, dx5, dy5, dx6, dy6);
2108 break;
2109
2110 default:
2111 return STBTT__CSERR("unimplemented");
2112 }
2113 } break;
2114
2115 default:
2116 if (b0 != 255 && b0 != 28 && b0 < 32)
2117 return STBTT__CSERR("reserved operator");
2118
2119 // push immediate
2120 if (b0 == 255) {
2121 f = (float)(stbtt_int32)stbtt__buf_get32(&b) / 0x10000;
2122 } else {
2123 stbtt__buf_skip(&b, -1);
2124 f = (float)(stbtt_int16)stbtt__cff_int(&b);
2125 }
2126 if (sp >= 48) return STBTT__CSERR("push stack overflow");
2127 s[sp++] = f;
2128 clear_stack = 0;
2129 break;
2130 }
2131 if (clear_stack) sp = 0;
2132 }
2133 return STBTT__CSERR("no endchar");
2134
2135#undef STBTT__CSERR
2136}
2137
2138static int stbtt__GetGlyphShapeT2(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **pvertices)
2139{
2140 // runs the charstring twice, once to count and once to output (to avoid realloc)
2141 stbtt__csctx count_ctx = STBTT__CSCTX_INIT(1);
2142 stbtt__csctx output_ctx = STBTT__CSCTX_INIT(0);
2143 if (stbtt__run_charstring(info, glyph_index, &count_ctx)) {
2144 *pvertices = (stbtt_vertex*)STBTT_malloc(count_ctx.num_vertices*sizeof(stbtt_vertex), info->userdata);
2145 output_ctx.pvertices = *pvertices;
2146 if (stbtt__run_charstring(info, glyph_index, &output_ctx)) {
2147 STBTT_assert(output_ctx.num_vertices == count_ctx.num_vertices);
2148 return output_ctx.num_vertices;
2149 }
2150 }
2151 *pvertices = NULL;
2152 return 0;
2153}
2154
2155static int stbtt__GetGlyphInfoT2(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1)
2156{
2158 int r = stbtt__run_charstring(info, glyph_index, &c);
2159 if (x0) *x0 = r ? c.min_x : 0;
2160 if (y0) *y0 = r ? c.min_y : 0;
2161 if (x1) *x1 = r ? c.max_x : 0;
2162 if (y1) *y1 = r ? c.max_y : 0;
2163 return r ? c.num_vertices : 0;
2164}
2165
2166STBTT_DEF int stbtt_GetGlyphShape(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **pvertices)
2167{
2168 if (!info->cff.size)
2169 return stbtt__GetGlyphShapeTT(info, glyph_index, pvertices);
2170 else
2171 return stbtt__GetGlyphShapeT2(info, glyph_index, pvertices);
2172}
2173
2174STBTT_DEF void stbtt_GetGlyphHMetrics(const stbtt_fontinfo *info, int glyph_index, int *advanceWidth, int *leftSideBearing)
2175{
2176 stbtt_uint16 numOfLongHorMetrics = ttUSHORT(info->data+info->hhea + 34);
2177 if (glyph_index < numOfLongHorMetrics) {
2178 if (advanceWidth) *advanceWidth = ttSHORT(info->data + info->hmtx + 4*glyph_index);
2179 if (leftSideBearing) *leftSideBearing = ttSHORT(info->data + info->hmtx + 4*glyph_index + 2);
2180 } else {
2181 if (advanceWidth) *advanceWidth = ttSHORT(info->data + info->hmtx + 4*(numOfLongHorMetrics-1));
2182 if (leftSideBearing) *leftSideBearing = ttSHORT(info->data + info->hmtx + 4*numOfLongHorMetrics + 2*(glyph_index - numOfLongHorMetrics));
2183 }
2184}
2185
2186STBTT_DEF int stbtt_GetKerningTableLength(const stbtt_fontinfo *info)
2187{
2188 stbtt_uint8 *data = info->data + info->kern;
2189
2190 // we only look at the first table. it must be 'horizontal' and format 0.
2191 if (!info->kern)
2192 return 0;
2193 if (ttUSHORT(data+2) < 1) // number of tables, need at least 1
2194 return 0;
2195 if (ttUSHORT(data+8) != 1) // horizontal flag must be set in format
2196 return 0;
2197
2198 return ttUSHORT(data+10);
2199}
2200
2201STBTT_DEF int stbtt_GetKerningTable(const stbtt_fontinfo *info, stbtt_kerningentry* table, int table_length)
2202{
2203 stbtt_uint8 *data = info->data + info->kern;
2204 int k, length;
2205
2206 // we only look at the first table. it must be 'horizontal' and format 0.
2207 if (!info->kern)
2208 return 0;
2209 if (ttUSHORT(data+2) < 1) // number of tables, need at least 1
2210 return 0;
2211 if (ttUSHORT(data+8) != 1) // horizontal flag must be set in format
2212 return 0;
2213
2214 length = ttUSHORT(data+10);
2215 if (table_length < length)
2216 length = table_length;
2217
2218 for (k = 0; k < length; k++)
2219 {
2220 table[k].glyph1 = ttUSHORT(data+18+(k*6));
2221 table[k].glyph2 = ttUSHORT(data+20+(k*6));
2222 table[k].advance = ttSHORT(data+22+(k*6));
2223 }
2224
2225 return length;
2226}
2227
2228static int stbtt__GetGlyphKernInfoAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2)
2229{
2230 stbtt_uint8 *data = info->data + info->kern;
2231 stbtt_uint32 needle, straw;
2232 int l, r, m;
2233
2234 // we only look at the first table. it must be 'horizontal' and format 0.
2235 if (!info->kern)
2236 return 0;
2237 if (ttUSHORT(data+2) < 1) // number of tables, need at least 1
2238 return 0;
2239 if (ttUSHORT(data+8) != 1) // horizontal flag must be set in format
2240 return 0;
2241
2242 l = 0;
2243 r = ttUSHORT(data+10) - 1;
2244 needle = glyph1 << 16 | glyph2;
2245 while (l <= r) {
2246 m = (l + r) >> 1;
2247 straw = ttULONG(data+18+(m*6)); // note: unaligned read
2248 if (needle < straw)
2249 r = m - 1;
2250 else if (needle > straw)
2251 l = m + 1;
2252 else
2253 return ttSHORT(data+22+(m*6));
2254 }
2255 return 0;
2256}
2257
2258static stbtt_int32 stbtt__GetCoverageIndex(stbtt_uint8 *coverageTable, int glyph)
2259{
2260 stbtt_uint16 coverageFormat = ttUSHORT(coverageTable);
2261 switch (coverageFormat) {
2262 case 1: {
2263 stbtt_uint16 glyphCount = ttUSHORT(coverageTable + 2);
2264
2265 // Binary search.
2266 stbtt_int32 l=0, r=glyphCount-1, m;
2267 int straw, needle=glyph;
2268 while (l <= r) {
2269 stbtt_uint8 *glyphArray = coverageTable + 4;
2270 stbtt_uint16 glyphID;
2271 m = (l + r) >> 1;
2272 glyphID = ttUSHORT(glyphArray + 2 * m);
2273 straw = glyphID;
2274 if (needle < straw)
2275 r = m - 1;
2276 else if (needle > straw)
2277 l = m + 1;
2278 else {
2279 return m;
2280 }
2281 }
2282 break;
2283 }
2284
2285 case 2: {
2286 stbtt_uint16 rangeCount = ttUSHORT(coverageTable + 2);
2287 stbtt_uint8 *rangeArray = coverageTable + 4;
2288
2289 // Binary search.
2290 stbtt_int32 l=0, r=rangeCount-1, m;
2291 int strawStart, strawEnd, needle=glyph;
2292 while (l <= r) {
2293 stbtt_uint8 *rangeRecord;
2294 m = (l + r) >> 1;
2295 rangeRecord = rangeArray + 6 * m;
2296 strawStart = ttUSHORT(rangeRecord);
2297 strawEnd = ttUSHORT(rangeRecord + 2);
2298 if (needle < strawStart)
2299 r = m - 1;
2300 else if (needle > strawEnd)
2301 l = m + 1;
2302 else {
2303 stbtt_uint16 startCoverageIndex = ttUSHORT(rangeRecord + 4);
2304 return startCoverageIndex + glyph - strawStart;
2305 }
2306 }
2307 break;
2308 }
2309
2310 default: return -1; // unsupported
2311 }
2312
2313 return -1;
2314}
2315
2316// Ligature glyph the font's own GSUB `liga`/`clig` lookups (type 4, directly or via
2317// type 7 extension) substitute for the glyph sequence first + rest[0..nrest), or 0.
2318static int stbtt__GetGsubLigature(const stbtt_fontinfo *info, int first, const int *rest, int nrest)
2319{
2320 if (!info->gsub) return 0;
2321 stbtt_uint8 *gsub = info->data + info->gsub;
2322 stbtt_uint8 *featureList = gsub + ttUSHORT(gsub + 6);
2323 stbtt_uint8 *lookupList = gsub + ttUSHORT(gsub + 8);
2324 int featureCount = ttUSHORT(featureList);
2325 int lookupCount = ttUSHORT(lookupList);
2326 int f, l, s, k, i;
2327 for (f = 0; f < featureCount; ++f) {
2328 stbtt_uint8 *rec = featureList + 2 + 6 * f;
2329 int isLiga = (rec[0]=='l' && rec[1]=='i' && rec[2]=='g' && rec[3]=='a');
2330 int isClig = (rec[0]=='c' && rec[1]=='l' && rec[2]=='i' && rec[3]=='g');
2331 if (!isLiga && !isClig) continue;
2332 stbtt_uint8 *feature = featureList + ttUSHORT(rec + 4);
2333 int nLookups = ttUSHORT(feature + 2);
2334 for (l = 0; l < nLookups; ++l) {
2335 int li = ttUSHORT(feature + 4 + 2 * l);
2336 if (li >= lookupCount) continue;
2337 stbtt_uint8 *lookup = lookupList + ttUSHORT(lookupList + 2 + 2 * li);
2338 int type = ttUSHORT(lookup);
2339 int nsub = ttUSHORT(lookup + 4);
2340 for (s = 0; s < nsub; ++s) {
2341 stbtt_uint8 *sub = lookup + ttUSHORT(lookup + 6 + 2 * s);
2342 int st = type;
2343 if (type == 7) {
2344 if (ttUSHORT(sub) != 1) continue;
2345 st = ttUSHORT(sub + 2);
2346 sub = sub + ttULONG(sub + 4);
2347 }
2348 if (st != 4 || ttUSHORT(sub) != 1) continue;
2349 int cov = stbtt__GetCoverageIndex(sub + ttUSHORT(sub + 2), first);
2350 if (cov < 0 || cov >= ttUSHORT(sub + 4)) continue;
2351 stbtt_uint8 *ligSet = sub + ttUSHORT(sub + 6 + 2 * cov);
2352 int ligCount = ttUSHORT(ligSet);
2353 for (k = 0; k < ligCount; ++k) {
2354 stbtt_uint8 *lig = ligSet + ttUSHORT(ligSet + 2 + 2 * k);
2355 int ligGlyph = ttUSHORT(lig);
2356 int compCount = ttUSHORT(lig + 2);
2357 if (compCount - 1 != nrest) continue;
2358 for (i = 0; i < nrest; ++i)
2359 if (ttUSHORT(lig + 4 + 2 * i) != rest[i]) break;
2360 if (i == nrest) return ligGlyph;
2361 }
2362 }
2363 }
2364 }
2365 return 0;
2366}
2367
2368static stbtt_int32 stbtt__GetGlyphClass(stbtt_uint8 *classDefTable, int glyph)
2369{
2370 stbtt_uint16 classDefFormat = ttUSHORT(classDefTable);
2371 switch (classDefFormat)
2372 {
2373 case 1: {
2374 stbtt_uint16 startGlyphID = ttUSHORT(classDefTable + 2);
2375 stbtt_uint16 glyphCount = ttUSHORT(classDefTable + 4);
2376 stbtt_uint8 *classDef1ValueArray = classDefTable + 6;
2377
2378 if (glyph >= startGlyphID && glyph < startGlyphID + glyphCount)
2379 return (stbtt_int32)ttUSHORT(classDef1ValueArray + 2 * (glyph - startGlyphID));
2380 break;
2381 }
2382
2383 case 2: {
2384 stbtt_uint16 classRangeCount = ttUSHORT(classDefTable + 2);
2385 stbtt_uint8 *classRangeRecords = classDefTable + 4;
2386
2387 // Binary search.
2388 stbtt_int32 l=0, r=classRangeCount-1, m;
2389 int strawStart, strawEnd, needle=glyph;
2390 while (l <= r) {
2391 stbtt_uint8 *classRangeRecord;
2392 m = (l + r) >> 1;
2393 classRangeRecord = classRangeRecords + 6 * m;
2394 strawStart = ttUSHORT(classRangeRecord);
2395 strawEnd = ttUSHORT(classRangeRecord + 2);
2396 if (needle < strawStart)
2397 r = m - 1;
2398 else if (needle > strawEnd)
2399 l = m + 1;
2400 else
2401 return (stbtt_int32)ttUSHORT(classRangeRecord + 4);
2402 }
2403 break;
2404 }
2405
2406 default:
2407 return -1; // Unsupported definition type, return an error.
2408 }
2409
2410 // "All glyphs not assigned to a class fall into class 0". (OpenType spec)
2411 return 0;
2412}
2413
2414// Define to STBTT_assert(x) if you want to break on unimplemented formats.
2415#define STBTT_GPOS_TODO_assert(x)
2416
2417static stbtt_int32 stbtt__GetGlyphGPOSInfoAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2)
2418{
2419 stbtt_uint16 lookupListOffset;
2420 stbtt_uint8 *lookupList;
2421 stbtt_uint16 lookupCount;
2422 stbtt_uint8 *data;
2423 stbtt_int32 i, sti;
2424
2425 if (!info->gpos) return 0;
2426
2427 data = info->data + info->gpos;
2428
2429 if (ttUSHORT(data+0) != 1) return 0; // Major version 1
2430 if (ttUSHORT(data+2) != 0) return 0; // Minor version 0
2431
2432 lookupListOffset = ttUSHORT(data+8);
2433 lookupList = data + lookupListOffset;
2434 lookupCount = ttUSHORT(lookupList);
2435
2436 for (i=0; i<lookupCount; ++i) {
2437 stbtt_uint16 lookupOffset = ttUSHORT(lookupList + 2 + 2 * i);
2438 stbtt_uint8 *lookupTable = lookupList + lookupOffset;
2439
2440 stbtt_uint16 lookupType = ttUSHORT(lookupTable);
2441 stbtt_uint16 subTableCount = ttUSHORT(lookupTable + 4);
2442 stbtt_uint8 *subTableOffsets = lookupTable + 6;
2443 if (lookupType != 2) // Pair Adjustment Positioning Subtable
2444 continue;
2445
2446 for (sti=0; sti<subTableCount; sti++) {
2447 stbtt_uint16 subtableOffset = ttUSHORT(subTableOffsets + 2 * sti);
2448 stbtt_uint8 *table = lookupTable + subtableOffset;
2449 stbtt_uint16 posFormat = ttUSHORT(table);
2450 stbtt_uint16 coverageOffset = ttUSHORT(table + 2);
2451 stbtt_int32 coverageIndex = stbtt__GetCoverageIndex(table + coverageOffset, glyph1);
2452 if (coverageIndex == -1) continue;
2453
2454 switch (posFormat) {
2455 case 1: {
2456 stbtt_int32 l, r, m;
2457 int straw, needle;
2458 stbtt_uint16 valueFormat1 = ttUSHORT(table + 4);
2459 stbtt_uint16 valueFormat2 = ttUSHORT(table + 6);
2460 if (valueFormat1 == 4 && valueFormat2 == 0) { // Support more formats?
2461 stbtt_int32 valueRecordPairSizeInBytes = 2;
2462 stbtt_uint16 pairSetCount = ttUSHORT(table + 8);
2463 stbtt_uint16 pairPosOffset = ttUSHORT(table + 10 + 2 * coverageIndex);
2464 stbtt_uint8 *pairValueTable = table + pairPosOffset;
2465 stbtt_uint16 pairValueCount = ttUSHORT(pairValueTable);
2466 stbtt_uint8 *pairValueArray = pairValueTable + 2;
2467
2468 if (coverageIndex >= pairSetCount) return 0;
2469
2470 needle=glyph2;
2471 r=pairValueCount-1;
2472 l=0;
2473
2474 // Binary search.
2475 while (l <= r) {
2476 stbtt_uint16 secondGlyph;
2477 stbtt_uint8 *pairValue;
2478 m = (l + r) >> 1;
2479 pairValue = pairValueArray + (2 + valueRecordPairSizeInBytes) * m;
2480 secondGlyph = ttUSHORT(pairValue);
2481 straw = secondGlyph;
2482 if (needle < straw)
2483 r = m - 1;
2484 else if (needle > straw)
2485 l = m + 1;
2486 else {
2487 stbtt_int16 xAdvance = ttSHORT(pairValue + 2);
2488 return xAdvance;
2489 }
2490 }
2491 } else
2492 return 0;
2493 break;
2494 }
2495
2496 case 2: {
2497 stbtt_uint16 valueFormat1 = ttUSHORT(table + 4);
2498 stbtt_uint16 valueFormat2 = ttUSHORT(table + 6);
2499 if (valueFormat1 == 4 && valueFormat2 == 0) { // Support more formats?
2500 stbtt_uint16 classDef1Offset = ttUSHORT(table + 8);
2501 stbtt_uint16 classDef2Offset = ttUSHORT(table + 10);
2502 int glyph1class = stbtt__GetGlyphClass(table + classDef1Offset, glyph1);
2503 int glyph2class = stbtt__GetGlyphClass(table + classDef2Offset, glyph2);
2504
2505 stbtt_uint16 class1Count = ttUSHORT(table + 12);
2506 stbtt_uint16 class2Count = ttUSHORT(table + 14);
2507 stbtt_uint8 *class1Records, *class2Records;
2508 stbtt_int16 xAdvance;
2509
2510 if (glyph1class < 0 || glyph1class >= class1Count) return 0; // malformed
2511 if (glyph2class < 0 || glyph2class >= class2Count) return 0; // malformed
2512
2513 class1Records = table + 16;
2514 class2Records = class1Records + 2 * (glyph1class * class2Count);
2515 xAdvance = ttSHORT(class2Records + 2 * glyph2class);
2516 return xAdvance;
2517 } else
2518 return 0;
2519 break;
2520 }
2521
2522 default:
2523 return 0; // Unsupported position format
2524 }
2525 }
2526 }
2527
2528 return 0;
2529}
2530
2531STBTT_DEF int stbtt_GetGlyphKernAdvance(const stbtt_fontinfo *info, int g1, int g2)
2532{
2533 int xAdvance = 0;
2534
2535 if (info->gpos)
2536 xAdvance += stbtt__GetGlyphGPOSInfoAdvance(info, g1, g2);
2537 else if (info->kern)
2538 xAdvance += stbtt__GetGlyphKernInfoAdvance(info, g1, g2);
2539
2540 return xAdvance;
2541}
2542
2543STBTT_DEF int stbtt_GetCodepointKernAdvance(const stbtt_fontinfo *info, int ch1, int ch2)
2544{
2545 if (!info->kern && !info->gpos) // if no kerning table, don't waste time looking up both codepoint->glyphs
2546 return 0;
2547 return stbtt_GetGlyphKernAdvance(info, stbtt_FindGlyphIndex(info,ch1), stbtt_FindGlyphIndex(info,ch2));
2548}
2549
2550STBTT_DEF void stbtt_GetCodepointHMetrics(const stbtt_fontinfo *info, int codepoint, int *advanceWidth, int *leftSideBearing)
2551{
2552 stbtt_GetGlyphHMetrics(info, stbtt_FindGlyphIndex(info,codepoint), advanceWidth, leftSideBearing);
2553}
2554
2555STBTT_DEF void stbtt_GetFontVMetrics(const stbtt_fontinfo *info, int *ascent, int *descent, int *lineGap)
2556{
2557 if (ascent ) *ascent = ttSHORT(info->data+info->hhea + 4);
2558 if (descent) *descent = ttSHORT(info->data+info->hhea + 6);
2559 if (lineGap) *lineGap = ttSHORT(info->data+info->hhea + 8);
2560}
2561
2562STBTT_DEF int stbtt_GetFontVMetricsOS2(const stbtt_fontinfo *info, int *typoAscent, int *typoDescent, int *typoLineGap)
2563{
2564 int tab = stbtt__find_table(info->data, info->fontstart, "OS/2");
2565 if (!tab)
2566 return 0;
2567 if (typoAscent ) *typoAscent = ttSHORT(info->data+tab + 68);
2568 if (typoDescent) *typoDescent = ttSHORT(info->data+tab + 70);
2569 if (typoLineGap) *typoLineGap = ttSHORT(info->data+tab + 72);
2570 return 1;
2571}
2572
2573STBTT_DEF void stbtt_GetFontBoundingBox(const stbtt_fontinfo *info, int *x0, int *y0, int *x1, int *y1)
2574{
2575 *x0 = ttSHORT(info->data + info->head + 36);
2576 *y0 = ttSHORT(info->data + info->head + 38);
2577 *x1 = ttSHORT(info->data + info->head + 40);
2578 *y1 = ttSHORT(info->data + info->head + 42);
2579}
2580
2581STBTT_DEF float stbtt_ScaleForPixelHeight(const stbtt_fontinfo *info, float height)
2582{
2583 int fheight = ttSHORT(info->data + info->hhea + 4) - ttSHORT(info->data + info->hhea + 6);
2584 return (float) height / fheight;
2585}
2586
2587STBTT_DEF float stbtt_ScaleForMappingEmToPixels(const stbtt_fontinfo *info, float pixels)
2588{
2589 int unitsPerEm = ttUSHORT(info->data + info->head + 18);
2590 return pixels / unitsPerEm;
2591}
2592
2593STBTT_DEF void stbtt_FreeShape(const stbtt_fontinfo *info, stbtt_vertex *v)
2594{
2595 STBTT_free(v, info->userdata);
2596}
2597
2598STBTT_DEF stbtt_uint8 *stbtt_FindSVGDoc(const stbtt_fontinfo *info, int gl)
2599{
2600 int i;
2601 stbtt_uint8 *data = info->data;
2602 stbtt_uint8 *svg_doc_list = data + stbtt__get_svg((stbtt_fontinfo *) info);
2603
2604 int numEntries = ttUSHORT(svg_doc_list);
2605 stbtt_uint8 *svg_docs = svg_doc_list + 2;
2606
2607 for(i=0; i<numEntries; i++) {
2608 stbtt_uint8 *svg_doc = svg_docs + (12 * i);
2609 if ((gl >= ttUSHORT(svg_doc)) && (gl <= ttUSHORT(svg_doc + 2)))
2610 return svg_doc;
2611 }
2612 return 0;
2613}
2614
2615STBTT_DEF int stbtt_GetGlyphSVG(const stbtt_fontinfo *info, int gl, const char **svg)
2616{
2617 stbtt_uint8 *data = info->data;
2618 stbtt_uint8 *svg_doc;
2619
2620 if (info->svg == 0)
2621 return 0;
2622
2623 svg_doc = stbtt_FindSVGDoc(info, gl);
2624 if (svg_doc != NULL) {
2625 *svg = (char *) data + info->svg + ttULONG(svg_doc + 4);
2626 return ttULONG(svg_doc + 8);
2627 } else {
2628 return 0;
2629 }
2630}
2631
2632STBTT_DEF int stbtt_GetCodepointSVG(const stbtt_fontinfo *info, int unicode_codepoint, const char **svg)
2633{
2634 return stbtt_GetGlyphSVG(info, stbtt_FindGlyphIndex(info, unicode_codepoint), svg);
2635}
2636
2638//
2639// antialiasing software rasterizer
2640//
2641
2642STBTT_DEF void stbtt_GetGlyphBitmapBoxSubpixel(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y,float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1)
2643{
2644 int x0=0,y0=0,x1,y1; // =0 suppresses compiler warning
2645 if (!stbtt_GetGlyphBox(font, glyph, &x0,&y0,&x1,&y1)) {
2646 // e.g. space character
2647 if (ix0) *ix0 = 0;
2648 if (iy0) *iy0 = 0;
2649 if (ix1) *ix1 = 0;
2650 if (iy1) *iy1 = 0;
2651 } else {
2652 // move to integral bboxes (treating pixels as little squares, what pixels get touched)?
2653 if (ix0) *ix0 = STBTT_ifloor( x0 * scale_x + shift_x);
2654 if (iy0) *iy0 = STBTT_ifloor(-y1 * scale_y + shift_y);
2655 if (ix1) *ix1 = STBTT_iceil ( x1 * scale_x + shift_x);
2656 if (iy1) *iy1 = STBTT_iceil (-y0 * scale_y + shift_y);
2657 }
2658}
2659
2660STBTT_DEF void stbtt_GetGlyphBitmapBox(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1)
2661{
2662 stbtt_GetGlyphBitmapBoxSubpixel(font, glyph, scale_x, scale_y,0.0f,0.0f, ix0, iy0, ix1, iy1);
2663}
2664
2665STBTT_DEF void stbtt_GetCodepointBitmapBoxSubpixel(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1)
2666{
2667 stbtt_GetGlyphBitmapBoxSubpixel(font, stbtt_FindGlyphIndex(font,codepoint), scale_x, scale_y,shift_x,shift_y, ix0,iy0,ix1,iy1);
2668}
2669
2670STBTT_DEF void stbtt_GetCodepointBitmapBox(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1)
2671{
2672 stbtt_GetCodepointBitmapBoxSubpixel(font, codepoint, scale_x, scale_y,0.0f,0.0f, ix0,iy0,ix1,iy1);
2673}
2674
2676//
2677// Rasterizer
2678
2683
2690
2691static void *stbtt__hheap_alloc(stbtt__hheap *hh, size_t size, void *userdata)
2692{
2693 if (hh->first_free) {
2694 void *p = hh->first_free;
2695 hh->first_free = * (void **) p;
2696 return p;
2697 } else {
2698 if (hh->num_remaining_in_head_chunk == 0) {
2699 int count = (size < 32 ? 2000 : size < 128 ? 800 : 100);
2700 stbtt__hheap_chunk *c = (stbtt__hheap_chunk *) STBTT_malloc(sizeof(stbtt__hheap_chunk) + size * count, userdata);
2701 if (c == NULL)
2702 return NULL;
2703 c->next = hh->head;
2704 hh->head = c;
2705 hh->num_remaining_in_head_chunk = count;
2706 }
2708 return (char *) (hh->head) + sizeof(stbtt__hheap_chunk) + size * hh->num_remaining_in_head_chunk;
2709 }
2710}
2711
2712static void stbtt__hheap_free(stbtt__hheap *hh, void *p)
2713{
2714 *(void **) p = hh->first_free;
2715 hh->first_free = p;
2716}
2717
2718static void stbtt__hheap_cleanup(stbtt__hheap *hh, void *userdata)
2719{
2720 stbtt__hheap_chunk *c = hh->head;
2721 while (c) {
2722 stbtt__hheap_chunk *n = c->next;
2723 STBTT_free(c, userdata);
2724 c = n;
2725 }
2726}
2727
2728typedef struct stbtt__edge {
2729 float x0,y0, x1,y1;
2732
2733
2735{
2737 #if STBTT_RASTERIZER_VERSION==1
2738 int x,dx;
2739 float ey;
2740 int direction;
2741 #elif STBTT_RASTERIZER_VERSION==2
2742 float fx,fdx,fdy;
2744 float sy;
2745 float ey;
2746 #else
2747 #error "Unrecognized value of STBTT_RASTERIZER_VERSION"
2748 #endif
2750
2751#if STBTT_RASTERIZER_VERSION == 1
2752#define STBTT_FIXSHIFT 10
2753#define STBTT_FIX (1 << STBTT_FIXSHIFT)
2754#define STBTT_FIXMASK (STBTT_FIX-1)
2755
2756static stbtt__active_edge *stbtt__new_active(stbtt__hheap *hh, stbtt__edge *e, int off_x, float start_point, void *userdata)
2757{
2758 stbtt__active_edge *z = (stbtt__active_edge *) stbtt__hheap_alloc(hh, sizeof(*z), userdata);
2759 float dxdy = (e->x1 - e->x0) / (e->y1 - e->y0);
2760 STBTT_assert(z != NULL);
2761 if (!z) return z;
2762
2763 // round dx down to avoid overshooting
2764 if (dxdy < 0)
2765 z->dx = -STBTT_ifloor(STBTT_FIX * -dxdy);
2766 else
2767 z->dx = STBTT_ifloor(STBTT_FIX * dxdy);
2768
2769 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
2770 z->x -= off_x * STBTT_FIX;
2771
2772 z->ey = e->y1;
2773 z->next = 0;
2774 z->direction = e->invert ? 1 : -1;
2775 return z;
2776}
2777#elif STBTT_RASTERIZER_VERSION == 2
2778static stbtt__active_edge *stbtt__new_active(stbtt__hheap *hh, stbtt__edge *e, int off_x, float start_point, void *userdata)
2779{
2780 stbtt__active_edge *z = (stbtt__active_edge *) stbtt__hheap_alloc(hh, sizeof(*z), userdata);
2781 float dxdy = (e->x1 - e->x0) / (e->y1 - e->y0);
2782 STBTT_assert(z != NULL);
2783 //STBTT_assert(e->y0 <= start_point);
2784 if (!z) return z;
2785 z->fdx = dxdy;
2786 z->fdy = dxdy != 0.0f ? (1.0f/dxdy) : 0.0f;
2787 z->fx = e->x0 + dxdy * (start_point - e->y0);
2788 z->fx -= off_x;
2789 z->direction = e->invert ? 1.0f : -1.0f;
2790 z->sy = e->y0;
2791 z->ey = e->y1;
2792 z->next = 0;
2793 return z;
2794}
2795#else
2796#error "Unrecognized value of STBTT_RASTERIZER_VERSION"
2797#endif
2798
2799#if STBTT_RASTERIZER_VERSION == 1
2800// note: this routine clips fills that extend off the edges... ideally this
2801// wouldn't happen, but it could happen if the truetype glyph bounding boxes
2802// are wrong, or if the user supplies a too-small bitmap
2803static void stbtt__fill_active_edges(unsigned char *scanline, int len, stbtt__active_edge *e, int max_weight)
2804{
2805 // non-zero winding fill
2806 int x0=0, w=0;
2807
2808 while (e) {
2809 if (w == 0) {
2810 // if we're currently at zero, we need to record the edge start point
2811 x0 = e->x; w += e->direction;
2812 } else {
2813 int x1 = e->x; w += e->direction;
2814 // if we went to zero, we need to draw
2815 if (w == 0) {
2816 int i = x0 >> STBTT_FIXSHIFT;
2817 int j = x1 >> STBTT_FIXSHIFT;
2818
2819 if (i < len && j >= 0) {
2820 if (i == j) {
2821 // x0,x1 are the same pixel, so compute combined coverage
2822 scanline[i] = scanline[i] + (stbtt_uint8) ((x1 - x0) * max_weight >> STBTT_FIXSHIFT);
2823 } else {
2824 if (i >= 0) // add antialiasing for x0
2825 scanline[i] = scanline[i] + (stbtt_uint8) (((STBTT_FIX - (x0 & STBTT_FIXMASK)) * max_weight) >> STBTT_FIXSHIFT);
2826 else
2827 i = -1; // clip
2828
2829 if (j < len) // add antialiasing for x1
2830 scanline[j] = scanline[j] + (stbtt_uint8) (((x1 & STBTT_FIXMASK) * max_weight) >> STBTT_FIXSHIFT);
2831 else
2832 j = len; // clip
2833
2834 for (++i; i < j; ++i) // fill pixels between x0 and x1
2835 scanline[i] = scanline[i] + (stbtt_uint8) max_weight;
2836 }
2837 }
2838 }
2839 }
2840
2841 e = e->next;
2842 }
2843}
2844
2845static void stbtt__rasterize_sorted_edges(stbtt__bitmap *result, stbtt__edge *e, int n, int vsubsample, int off_x, int off_y, void *userdata)
2846{
2847 stbtt__hheap hh = { 0, 0, 0 };
2848 stbtt__active_edge *active = NULL;
2849 int y,j=0;
2850 int max_weight = (255 / vsubsample); // weight per vertical scanline
2851 int s; // vertical subsample index
2852 unsigned char scanline_data[512], *scanline;
2853
2854 if (result->w > 512)
2855 scanline = (unsigned char *) STBTT_malloc(result->w, userdata);
2856 else
2857 scanline = scanline_data;
2858
2859 y = off_y * vsubsample;
2860 e[n].y0 = (off_y + result->h) * (float) vsubsample + 1;
2861
2862 while (j < result->h) {
2863 STBTT_memset(scanline, 0, result->w);
2864 for (s=0; s < vsubsample; ++s) {
2865 // find center of pixel for this scanline
2866 float scan_y = y + 0.5f;
2867 stbtt__active_edge **step = &active;
2868
2869 // update all active edges;
2870 // remove all active edges that terminate before the center of this scanline
2871 while (*step) {
2872 stbtt__active_edge * z = *step;
2873 if (z->ey <= scan_y) {
2874 *step = z->next; // delete from list
2876 z->direction = 0;
2877 stbtt__hheap_free(&hh, z);
2878 } else {
2879 z->x += z->dx; // advance to position for current scanline
2880 step = &((*step)->next); // advance through list
2881 }
2882 }
2883
2884 // resort the list if needed
2885 for(;;) {
2886 int changed=0;
2887 step = &active;
2888 while (*step && (*step)->next) {
2889 if ((*step)->x > (*step)->next->x) {
2890 stbtt__active_edge *t = *step;
2891 stbtt__active_edge *q = t->next;
2892
2893 t->next = q->next;
2894 q->next = t;
2895 *step = q;
2896 changed = 1;
2897 }
2898 step = &(*step)->next;
2899 }
2900 if (!changed) break;
2901 }
2902
2903 // insert all edges that start before the center of this scanline -- omit ones that also end on this scanline
2904 while (e->y0 <= scan_y) {
2905 if (e->y1 > scan_y) {
2906 stbtt__active_edge *z = stbtt__new_active(&hh, e, off_x, scan_y, userdata);
2907 if (z != NULL) {
2908 // find insertion point
2909 if (active == NULL)
2910 active = z;
2911 else if (z->x < active->x) {
2912 // insert at front
2913 z->next = active;
2914 active = z;
2915 } else {
2916 // find thing to insert AFTER
2917 stbtt__active_edge *p = active;
2918 while (p->next && p->next->x < z->x)
2919 p = p->next;
2920 // at this point, p->next->x is NOT < z->x
2921 z->next = p->next;
2922 p->next = z;
2923 }
2924 }
2925 }
2926 ++e;
2927 }
2928
2929 // now process all active edges in XOR fashion
2930 if (active)
2931 stbtt__fill_active_edges(scanline, result->w, active, max_weight);
2932
2933 ++y;
2934 }
2935 STBTT_memcpy(result->pixels + j * result->stride, scanline, result->w);
2936 ++j;
2937 }
2938
2939 stbtt__hheap_cleanup(&hh, userdata);
2940
2941 if (scanline != scanline_data)
2942 STBTT_free(scanline, userdata);
2943}
2944
2945#elif STBTT_RASTERIZER_VERSION == 2
2946
2947// the edge passed in here does not cross the vertical line at x or the vertical line at x+1
2948// (i.e. it has already been clipped to those)
2949static void stbtt__handle_clipped_edge(float *scanline, int x, stbtt__active_edge *e, float x0, float y0, float x1, float y1)
2950{
2951 if (y0 == y1) return;
2952 STBTT_assert(y0 < y1);
2953 STBTT_assert(e->sy <= e->ey);
2954 if (y0 > e->ey) return;
2955 if (y1 < e->sy) return;
2956 if (y0 < e->sy) {
2957 x0 += (x1-x0) * (e->sy - y0) / (y1-y0);
2958 y0 = e->sy;
2959 }
2960 if (y1 > e->ey) {
2961 x1 += (x1-x0) * (e->ey - y1) / (y1-y0);
2962 y1 = e->ey;
2963 }
2964
2965 if (x0 == x)
2966 STBTT_assert(x1 <= x+1);
2967 else if (x0 == x+1)
2968 STBTT_assert(x1 >= x);
2969 else if (x0 <= x)
2970 STBTT_assert(x1 <= x);
2971 else if (x0 >= x+1)
2972 STBTT_assert(x1 >= x+1);
2973 else
2974 STBTT_assert(x1 >= x && x1 <= x+1);
2975
2976 if (x0 <= x && x1 <= x)
2977 scanline[x] += e->direction * (y1-y0);
2978 else if (x0 >= x+1 && x1 >= x+1)
2979 ;
2980 else {
2981 STBTT_assert(x0 >= x && x0 <= x+1 && x1 >= x && x1 <= x+1);
2982 scanline[x] += e->direction * (y1-y0) * (1-((x0-x)+(x1-x))/2); // coverage = 1 - average x position
2983 }
2984}
2985
2986static float stbtt__sized_trapezoid_area(float height, float top_width, float bottom_width)
2987{
2988 STBTT_assert(top_width >= 0);
2989 STBTT_assert(bottom_width >= 0);
2990 return (top_width + bottom_width) / 2.0f * height;
2991}
2992
2993static float stbtt__position_trapezoid_area(float height, float tx0, float tx1, float bx0, float bx1)
2994{
2995 return stbtt__sized_trapezoid_area(height, tx1 - tx0, bx1 - bx0);
2996}
2997
2998static float stbtt__sized_triangle_area(float height, float width)
2999{
3000 return height * width / 2;
3001}
3002
3003static void stbtt__fill_active_edges_new(float *scanline, float *scanline_fill, int len, stbtt__active_edge *e, float y_top)
3004{
3005 float y_bottom = y_top+1;
3006
3007 while (e) {
3008 // brute force every pixel
3009
3010 // compute intersection points with top & bottom
3011 STBTT_assert(e->ey >= y_top);
3012
3013 if (e->fdx == 0) {
3014 float x0 = e->fx;
3015 if (x0 < len) {
3016 if (x0 >= 0) {
3017 stbtt__handle_clipped_edge(scanline,(int) x0,e, x0,y_top, x0,y_bottom);
3018 stbtt__handle_clipped_edge(scanline_fill-1,(int) x0+1,e, x0,y_top, x0,y_bottom);
3019 } else {
3020 stbtt__handle_clipped_edge(scanline_fill-1,0,e, x0,y_top, x0,y_bottom);
3021 }
3022 }
3023 } else {
3024 float x0 = e->fx;
3025 float dx = e->fdx;
3026 float xb = x0 + dx;
3027 float x_top, x_bottom;
3028 float sy0,sy1;
3029 float dy = e->fdy;
3030 STBTT_assert(e->sy <= y_bottom && e->ey >= y_top);
3031
3032 // compute endpoints of line segment clipped to this scanline (if the
3033 // line segment starts on this scanline. x0 is the intersection of the
3034 // line with y_top, but that may be off the line segment.
3035 if (e->sy > y_top) {
3036 x_top = x0 + dx * (e->sy - y_top);
3037 sy0 = e->sy;
3038 } else {
3039 x_top = x0;
3040 sy0 = y_top;
3041 }
3042 if (e->ey < y_bottom) {
3043 x_bottom = x0 + dx * (e->ey - y_top);
3044 sy1 = e->ey;
3045 } else {
3046 x_bottom = xb;
3047 sy1 = y_bottom;
3048 }
3049
3050 if (x_top >= 0 && x_bottom >= 0 && x_top < len && x_bottom < len) {
3051 // from here on, we don't have to range check x values
3052
3053 if ((int) x_top == (int) x_bottom) {
3054 float height;
3055 // simple case, only spans one pixel
3056 int x = (int) x_top;
3057 height = (sy1 - sy0) * e->direction;
3058 STBTT_assert(x >= 0 && x < len);
3059 scanline[x] += stbtt__position_trapezoid_area(height, x_top, x+1.0f, x_bottom, x+1.0f);
3060 scanline_fill[x] += height; // everything right of this pixel is filled
3061 } else {
3062 int x,x1,x2;
3063 float y_crossing, y_final, step, sign, area;
3064 // covers 2+ pixels
3065 if (x_top > x_bottom) {
3066 // flip scanline vertically; signed area is the same
3067 float t;
3068 sy0 = y_bottom - (sy0 - y_top);
3069 sy1 = y_bottom - (sy1 - y_top);
3070 t = sy0, sy0 = sy1, sy1 = t;
3071 t = x_bottom, x_bottom = x_top, x_top = t;
3072 dx = -dx;
3073 dy = -dy;
3074 t = x0, x0 = xb, xb = t;
3075 }
3076 STBTT_assert(dy >= 0);
3077 STBTT_assert(dx >= 0);
3078
3079 x1 = (int) x_top;
3080 x2 = (int) x_bottom;
3081 // compute intersection with y axis at x1+1
3082 y_crossing = y_top + dy * (x1+1 - x0);
3083
3084 // compute intersection with y axis at x2
3085 y_final = y_top + dy * (x2 - x0);
3086
3087 // x1 x_top x2 x_bottom
3088 // y_top +------|-----+------------+------------+--------|---+------------+
3089 // | | | | | |
3090 // | | | | | |
3091 // sy0 | Txxxxx|............|............|............|............|
3092 // y_crossing | *xxxxx.......|............|............|............|
3093 // | | xxxxx..|............|............|............|
3094 // | | /- xx*xxxx........|............|............|
3095 // | | dy < | xxxxxx..|............|............|
3096 // y_final | | \- | xx*xxx.........|............|
3097 // sy1 | | | | xxxxxB...|............|
3098 // | | | | | |
3099 // | | | | | |
3100 // y_bottom +------------+------------+------------+------------+------------+
3101 //
3102 // goal is to measure the area covered by '.' in each pixel
3103
3104 // if x2 is right at the right edge of x1, y_crossing can blow up, github #1057
3105 // @TODO: maybe test against sy1 rather than y_bottom?
3106 if (y_crossing > y_bottom)
3107 y_crossing = y_bottom;
3108
3109 sign = e->direction;
3110
3111 // area of the rectangle covered from sy0..y_crossing
3112 area = sign * (y_crossing-sy0);
3113
3114 // area of the triangle (x_top,sy0), (x1+1,sy0), (x1+1,y_crossing)
3115 scanline[x1] += stbtt__sized_triangle_area(area, x1+1 - x_top);
3116
3117 // check if final y_crossing is blown up; no test case for this
3118 if (y_final > y_bottom) {
3119 y_final = y_bottom;
3120 dy = (y_final - y_crossing ) / (x2 - (x1+1)); // if denom=0, y_final = y_crossing, so y_final <= y_bottom
3121 }
3122
3123 // in second pixel, area covered by line segment found in first pixel
3124 // is always a rectangle 1 wide * the height of that line segment; this
3125 // is exactly what the variable 'area' stores. it also gets a contribution
3126 // from the line segment within it. the THIRD pixel will get the first
3127 // pixel's rectangle contribution, the second pixel's rectangle contribution,
3128 // and its own contribution. the 'own contribution' is the same in every pixel except
3129 // the leftmost and rightmost, a trapezoid that slides down in each pixel.
3130 // the second pixel's contribution to the third pixel will be the
3131 // rectangle 1 wide times the height change in the second pixel, which is dy.
3132
3133 step = sign * dy * 1; // dy is dy/dx, change in y for every 1 change in x,
3134 // which multiplied by 1-pixel-width is how much pixel area changes for each step in x
3135 // so the area advances by 'step' every time
3136
3137 for (x = x1+1; x < x2; ++x) {
3138 scanline[x] += area + step/2; // area of trapezoid is 1*step/2
3139 area += step;
3140 }
3141 STBTT_assert(STBTT_fabs(area) <= 1.01f); // accumulated error from area += step unless we round step down
3142 STBTT_assert(sy1 > y_final-0.01f);
3143
3144 // area covered in the last pixel is the rectangle from all the pixels to the left,
3145 // plus the trapezoid filled by the line segment in this pixel all the way to the right edge
3146 scanline[x2] += area + sign * stbtt__position_trapezoid_area(sy1-y_final, (float) x2, x2+1.0f, x_bottom, x2+1.0f);
3147
3148 // the rest of the line is filled based on the total height of the line segment in this pixel
3149 scanline_fill[x2] += sign * (sy1-sy0);
3150 }
3151 } else {
3152 // if edge goes outside of box we're drawing, we require
3153 // clipping logic. since this does not match the intended use
3154 // of this library, we use a different, very slow brute
3155 // force implementation
3156 // note though that this does happen some of the time because
3157 // x_top and x_bottom can be extrapolated at the top & bottom of
3158 // the shape and actually lie outside the bounding box
3159 int x;
3160 for (x=0; x < len; ++x) {
3161 // cases:
3162 //
3163 // there can be up to two intersections with the pixel. any intersection
3164 // with left or right edges can be handled by splitting into two (or three)
3165 // regions. intersections with top & bottom do not necessitate case-wise logic.
3166 //
3167 // the old way of doing this found the intersections with the left & right edges,
3168 // then used some simple logic to produce up to three segments in sorted order
3169 // from top-to-bottom. however, this had a problem: if an x edge was epsilon
3170 // across the x border, then the corresponding y position might not be distinct
3171 // from the other y segment, and it might ignored as an empty segment. to avoid
3172 // that, we need to explicitly produce segments based on x positions.
3173
3174 // rename variables to clearly-defined pairs
3175 float y0 = y_top;
3176 float x1 = (float) (x);
3177 float x2 = (float) (x+1);
3178 float x3 = xb;
3179 float y3 = y_bottom;
3180
3181 // x = e->x + e->dx * (y-y_top)
3182 // (y-y_top) = (x - e->x) / e->dx
3183 // y = (x - e->x) / e->dx + y_top
3184 float y1 = (x - x0) / dx + y_top;
3185 float y2 = (x+1 - x0) / dx + y_top;
3186
3187 if (x0 < x1 && x3 > x2) { // three segments descending down-right
3188 stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x1,y1);
3189 stbtt__handle_clipped_edge(scanline,x,e, x1,y1, x2,y2);
3190 stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x3,y3);
3191 } else if (x3 < x1 && x0 > x2) { // three segments descending down-left
3192 stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x2,y2);
3193 stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x1,y1);
3194 stbtt__handle_clipped_edge(scanline,x,e, x1,y1, x3,y3);
3195 } else if (x0 < x1 && x3 > x1) { // two segments across x, down-right
3196 stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x1,y1);
3197 stbtt__handle_clipped_edge(scanline,x,e, x1,y1, x3,y3);
3198 } else if (x3 < x1 && x0 > x1) { // two segments across x, down-left
3199 stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x1,y1);
3200 stbtt__handle_clipped_edge(scanline,x,e, x1,y1, x3,y3);
3201 } else if (x0 < x2 && x3 > x2) { // two segments across x+1, down-right
3202 stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x2,y2);
3203 stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x3,y3);
3204 } else if (x3 < x2 && x0 > x2) { // two segments across x+1, down-left
3205 stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x2,y2);
3206 stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x3,y3);
3207 } else { // one segment
3208 stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x3,y3);
3209 }
3210 }
3211 }
3212 }
3213 e = e->next;
3214 }
3215}
3216
3217// directly AA rasterize edges w/o supersampling
3218static void stbtt__rasterize_sorted_edges(stbtt__bitmap *result, stbtt__edge *e, int n, int vsubsample, int off_x, int off_y, void *userdata)
3219{
3220 stbtt__hheap hh = { 0, 0, 0 };
3221 stbtt__active_edge *active = NULL;
3222 int y,j=0, i;
3223 float scanline_data[129], *scanline, *scanline2;
3224
3225 STBTT__NOTUSED(vsubsample);
3226
3227 if (result->w > 64)
3228 scanline = (float *) STBTT_malloc((result->w*2+1) * sizeof(float), userdata);
3229 else
3230 scanline = scanline_data;
3231
3232 scanline2 = scanline + result->w;
3233
3234 y = off_y;
3235 e[n].y0 = (float) (off_y + result->h) + 1;
3236
3237 while (j < result->h) {
3238 // find center of pixel for this scanline
3239 float scan_y_top = y + 0.0f;
3240 float scan_y_bottom = y + 1.0f;
3241 stbtt__active_edge **step = &active;
3242
3243 STBTT_memset(scanline , 0, result->w*sizeof(scanline[0]));
3244 STBTT_memset(scanline2, 0, (result->w+1)*sizeof(scanline[0]));
3245
3246 // update all active edges;
3247 // remove all active edges that terminate before the top of this scanline
3248 while (*step) {
3249 stbtt__active_edge * z = *step;
3250 if (z->ey <= scan_y_top) {
3251 *step = z->next; // delete from list
3253 z->direction = 0;
3254 stbtt__hheap_free(&hh, z);
3255 } else {
3256 step = &((*step)->next); // advance through list
3257 }
3258 }
3259
3260 // insert all edges that start before the bottom of this scanline
3261 while (e->y0 <= scan_y_bottom) {
3262 if (e->y0 != e->y1) {
3263 stbtt__active_edge *z = stbtt__new_active(&hh, e, off_x, scan_y_top, userdata);
3264 if (z != NULL) {
3265 if (j == 0 && off_y != 0) {
3266 if (z->ey < scan_y_top) {
3267 // this can happen due to subpixel positioning and some kind of fp rounding error i think
3268 z->ey = scan_y_top;
3269 }
3270 }
3271 STBTT_assert(z->ey >= scan_y_top); // if we get really unlucky a tiny bit of an edge can be out of bounds
3272 // insert at front
3273 z->next = active;
3274 active = z;
3275 }
3276 }
3277 ++e;
3278 }
3279
3280 // now process all active edges
3281 if (active)
3282 stbtt__fill_active_edges_new(scanline, scanline2+1, result->w, active, scan_y_top);
3283
3284 {
3285 float sum = 0;
3286 for (i=0; i < result->w; ++i) {
3287 float k;
3288 int m;
3289 sum += scanline2[i];
3290 k = scanline[i] + sum;
3291 k = (float) STBTT_fabs(k)*255 + 0.5f;
3292 m = (int) k;
3293 if (m > 255) m = 255;
3294 result->pixels[j*result->stride + i] = (unsigned char) m;
3295 }
3296 }
3297 // advance all the edges
3298 step = &active;
3299 while (*step) {
3300 stbtt__active_edge *z = *step;
3301 z->fx += z->fdx; // advance to position for current scanline
3302 step = &((*step)->next); // advance through list
3303 }
3304
3305 ++y;
3306 ++j;
3307 }
3308
3309 stbtt__hheap_cleanup(&hh, userdata);
3310
3311 if (scanline != scanline_data)
3312 STBTT_free(scanline, userdata);
3313}
3314#else
3315#error "Unrecognized value of STBTT_RASTERIZER_VERSION"
3316#endif
3317
3318#define STBTT__COMPARE(a,b) ((a)->y0 < (b)->y0)
3319
3320static void stbtt__sort_edges_ins_sort(stbtt__edge *p, int n)
3321{
3322 int i,j;
3323 for (i=1; i < n; ++i) {
3324 stbtt__edge t = p[i], *a = &t;
3325 j = i;
3326 while (j > 0) {
3327 stbtt__edge *b = &p[j-1];
3328 int c = STBTT__COMPARE(a,b);
3329 if (!c) break;
3330 p[j] = p[j-1];
3331 --j;
3332 }
3333 if (i != j)
3334 p[j] = t;
3335 }
3336}
3337
3338static void stbtt__sort_edges_quicksort(stbtt__edge *p, int n)
3339{
3340 /* threshold for transitioning to insertion sort */
3341 while (n > 12) {
3342 stbtt__edge t;
3343 int c01,c12,c,m,i,j;
3344
3345 /* compute median of three */
3346 m = n >> 1;
3347 c01 = STBTT__COMPARE(&p[0],&p[m]);
3348 c12 = STBTT__COMPARE(&p[m],&p[n-1]);
3349 /* if 0 >= mid >= end, or 0 < mid < end, then use mid */
3350 if (c01 != c12) {
3351 /* otherwise, we'll need to swap something else to middle */
3352 int z;
3353 c = STBTT__COMPARE(&p[0],&p[n-1]);
3354 /* 0>mid && mid<n: 0>n => n; 0<n => 0 */
3355 /* 0<mid && mid>n: 0>n => 0; 0<n => n */
3356 z = (c == c12) ? 0 : n-1;
3357 t = p[z];
3358 p[z] = p[m];
3359 p[m] = t;
3360 }
3361 /* now p[m] is the median-of-three */
3362 /* swap it to the beginning so it won't move around */
3363 t = p[0];
3364 p[0] = p[m];
3365 p[m] = t;
3366
3367 /* partition loop */
3368 i=1;
3369 j=n-1;
3370 for(;;) {
3371 /* handling of equality is crucial here */
3372 /* for sentinels & efficiency with duplicates */
3373 for (;;++i) {
3374 if (!STBTT__COMPARE(&p[i], &p[0])) break;
3375 }
3376 for (;;--j) {
3377 if (!STBTT__COMPARE(&p[0], &p[j])) break;
3378 }
3379 /* make sure we haven't crossed */
3380 if (i >= j) break;
3381 t = p[i];
3382 p[i] = p[j];
3383 p[j] = t;
3384
3385 ++i;
3386 --j;
3387 }
3388 /* recurse on smaller side, iterate on larger */
3389 if (j < (n-i)) {
3390 stbtt__sort_edges_quicksort(p,j);
3391 p = p+i;
3392 n = n-i;
3393 } else {
3394 stbtt__sort_edges_quicksort(p+i, n-i);
3395 n = j;
3396 }
3397 }
3398}
3399
3400static void stbtt__sort_edges(stbtt__edge *p, int n)
3401{
3402 stbtt__sort_edges_quicksort(p, n);
3403 stbtt__sort_edges_ins_sort(p, n);
3404}
3405
3406typedef struct
3407{
3408 float x,y;
3409} stbtt__point;
3410
3411static void stbtt__rasterize(stbtt__bitmap *result, stbtt__point *pts, int *wcount, int windings, float scale_x, float scale_y, float shift_x, float shift_y, int off_x, int off_y, int invert, void *userdata)
3412{
3413 float y_scale_inv = invert ? -scale_y : scale_y;
3414 stbtt__edge *e;
3415 int n,i,j,k,m;
3416#if STBTT_RASTERIZER_VERSION == 1
3417 int vsubsample = result->h < 8 ? 15 : 5;
3418#elif STBTT_RASTERIZER_VERSION == 2
3419 int vsubsample = 1;
3420#else
3421 #error "Unrecognized value of STBTT_RASTERIZER_VERSION"
3422#endif
3423 // vsubsample should divide 255 evenly; otherwise we won't reach full opacity
3424
3425 // now we have to blow out the windings into explicit edge lists
3426 n = 0;
3427 for (i=0; i < windings; ++i)
3428 n += wcount[i];
3429
3430 e = (stbtt__edge *) STBTT_malloc(sizeof(*e) * (n+1), userdata); // add an extra one as a sentinel
3431 if (e == 0) return;
3432 n = 0;
3433
3434 m=0;
3435 for (i=0; i < windings; ++i) {
3436 stbtt__point *p = pts + m;
3437 m += wcount[i];
3438 j = wcount[i]-1;
3439 for (k=0; k < wcount[i]; j=k++) {
3440 int a=k,b=j;
3441 // skip the edge if horizontal
3442 if (p[j].y == p[k].y)
3443 continue;
3444 // add edge from j to k to the list
3445 e[n].invert = 0;
3446 if (invert ? p[j].y > p[k].y : p[j].y < p[k].y) {
3447 e[n].invert = 1;
3448 a=j,b=k;
3449 }
3450 e[n].x0 = p[a].x * scale_x + shift_x;
3451 e[n].y0 = (p[a].y * y_scale_inv + shift_y) * vsubsample;
3452 e[n].x1 = p[b].x * scale_x + shift_x;
3453 e[n].y1 = (p[b].y * y_scale_inv + shift_y) * vsubsample;
3454 ++n;
3455 }
3456 }
3457
3458 // now sort the edges by their highest point (should snap to integer, and then by x)
3459 //STBTT_sort(e, n, sizeof(e[0]), stbtt__edge_compare);
3460 stbtt__sort_edges(e, n);
3461
3462 // now, traverse the scanlines and find the intersections on each scanline, use xor winding rule
3463 stbtt__rasterize_sorted_edges(result, e, n, vsubsample, off_x, off_y, userdata);
3464
3465 STBTT_free(e, userdata);
3466}
3467
3468static void stbtt__add_point(stbtt__point *points, int n, float x, float y)
3469{
3470 if (!points) return; // during first pass, it's unallocated
3471 points[n].x = x;
3472 points[n].y = y;
3473}
3474
3475// tessellate until threshold p is happy... @TODO warped to compensate for non-linear stretching
3476static int stbtt__tesselate_curve(stbtt__point *points, int *num_points, float x0, float y0, float x1, float y1, float x2, float y2, float objspace_flatness_squared, int n)
3477{
3478 // midpoint
3479 float mx = (x0 + 2*x1 + x2)/4;
3480 float my = (y0 + 2*y1 + y2)/4;
3481 // versus directly drawn line
3482 float dx = (x0+x2)/2 - mx;
3483 float dy = (y0+y2)/2 - my;
3484 if (n > 16) // 65536 segments on one curve better be enough!
3485 return 1;
3486 if (dx*dx+dy*dy > objspace_flatness_squared) { // half-pixel error allowed... need to be smaller if AA
3487 stbtt__tesselate_curve(points, num_points, x0,y0, (x0+x1)/2.0f,(y0+y1)/2.0f, mx,my, objspace_flatness_squared,n+1);
3488 stbtt__tesselate_curve(points, num_points, mx,my, (x1+x2)/2.0f,(y1+y2)/2.0f, x2,y2, objspace_flatness_squared,n+1);
3489 } else {
3490 stbtt__add_point(points, *num_points,x2,y2);
3491 *num_points = *num_points+1;
3492 }
3493 return 1;
3494}
3495
3496static void stbtt__tesselate_cubic(stbtt__point *points, int *num_points, float x0, float y0, float x1, float y1, float x2, float y2, float x3, float y3, float objspace_flatness_squared, int n)
3497{
3498 // @TODO this "flatness" calculation is just made-up nonsense that seems to work well enough
3499 float dx0 = x1-x0;
3500 float dy0 = y1-y0;
3501 float dx1 = x2-x1;
3502 float dy1 = y2-y1;
3503 float dx2 = x3-x2;
3504 float dy2 = y3-y2;
3505 float dx = x3-x0;
3506 float dy = y3-y0;
3507 float longlen = (float) (STBTT_sqrt(dx0*dx0+dy0*dy0)+STBTT_sqrt(dx1*dx1+dy1*dy1)+STBTT_sqrt(dx2*dx2+dy2*dy2));
3508 float shortlen = (float) STBTT_sqrt(dx*dx+dy*dy);
3509 float flatness_squared = longlen*longlen-shortlen*shortlen;
3510
3511 if (n > 16) // 65536 segments on one curve better be enough!
3512 return;
3513
3514 if (flatness_squared > objspace_flatness_squared) {
3515 float x01 = (x0+x1)/2;
3516 float y01 = (y0+y1)/2;
3517 float x12 = (x1+x2)/2;
3518 float y12 = (y1+y2)/2;
3519 float x23 = (x2+x3)/2;
3520 float y23 = (y2+y3)/2;
3521
3522 float xa = (x01+x12)/2;
3523 float ya = (y01+y12)/2;
3524 float xb = (x12+x23)/2;
3525 float yb = (y12+y23)/2;
3526
3527 float mx = (xa+xb)/2;
3528 float my = (ya+yb)/2;
3529
3530 stbtt__tesselate_cubic(points, num_points, x0,y0, x01,y01, xa,ya, mx,my, objspace_flatness_squared,n+1);
3531 stbtt__tesselate_cubic(points, num_points, mx,my, xb,yb, x23,y23, x3,y3, objspace_flatness_squared,n+1);
3532 } else {
3533 stbtt__add_point(points, *num_points,x3,y3);
3534 *num_points = *num_points+1;
3535 }
3536}
3537
3538// returns number of contours
3539static stbtt__point *stbtt_FlattenCurves(stbtt_vertex *vertices, int num_verts, float objspace_flatness, int **contour_lengths, int *num_contours, void *userdata)
3540{
3541 stbtt__point *points=0;
3542 int num_points=0;
3543
3544 float objspace_flatness_squared = objspace_flatness * objspace_flatness;
3545 int i,n=0,start=0, pass;
3546
3547 // count how many "moves" there are to get the contour count
3548 for (i=0; i < num_verts; ++i)
3549 if (vertices[i].type == STBTT_vmove)
3550 ++n;
3551
3552 *num_contours = n;
3553 if (n == 0) return 0;
3554
3555 *contour_lengths = (int *) STBTT_malloc(sizeof(**contour_lengths) * n, userdata);
3556
3557 if (*contour_lengths == 0) {
3558 *num_contours = 0;
3559 return 0;
3560 }
3561
3562 // make two passes through the points so we don't need to realloc
3563 for (pass=0; pass < 2; ++pass) {
3564 float x=0,y=0;
3565 if (pass == 1) {
3566 points = (stbtt__point *) STBTT_malloc(num_points * sizeof(points[0]), userdata);
3567 if (points == NULL) goto error;
3568 }
3569 num_points = 0;
3570 n= -1;
3571 for (i=0; i < num_verts; ++i) {
3572 switch (vertices[i].type) {
3573 case STBTT_vmove:
3574 // start the next contour
3575 if (n >= 0)
3576 (*contour_lengths)[n] = num_points - start;
3577 ++n;
3578 start = num_points;
3579
3580 x = vertices[i].x, y = vertices[i].y;
3581 stbtt__add_point(points, num_points++, x,y);
3582 break;
3583 case STBTT_vline:
3584 x = vertices[i].x, y = vertices[i].y;
3585 stbtt__add_point(points, num_points++, x, y);
3586 break;
3587 case STBTT_vcurve:
3588 stbtt__tesselate_curve(points, &num_points, x,y,
3589 vertices[i].cx, vertices[i].cy,
3590 vertices[i].x, vertices[i].y,
3591 objspace_flatness_squared, 0);
3592 x = vertices[i].x, y = vertices[i].y;
3593 break;
3594 case STBTT_vcubic:
3595 stbtt__tesselate_cubic(points, &num_points, x,y,
3596 vertices[i].cx, vertices[i].cy,
3597 vertices[i].cx1, vertices[i].cy1,
3598 vertices[i].x, vertices[i].y,
3599 objspace_flatness_squared, 0);
3600 x = vertices[i].x, y = vertices[i].y;
3601 break;
3602 }
3603 }
3604 (*contour_lengths)[n] = num_points - start;
3605 }
3606
3607 return points;
3608error:
3609 STBTT_free(points, userdata);
3610 STBTT_free(*contour_lengths, userdata);
3611 *contour_lengths = 0;
3612 *num_contours = 0;
3613 return NULL;
3614}
3615
3616STBTT_DEF void stbtt_Rasterize(stbtt__bitmap *result, float flatness_in_pixels, stbtt_vertex *vertices, int num_verts, float scale_x, float scale_y, float shift_x, float shift_y, int x_off, int y_off, int invert, void *userdata)
3617{
3618 float scale = scale_x > scale_y ? scale_y : scale_x;
3619 int winding_count = 0;
3620 int *winding_lengths = NULL;
3621 stbtt__point *windings = stbtt_FlattenCurves(vertices, num_verts, flatness_in_pixels / scale, &winding_lengths, &winding_count, userdata);
3622 if (windings) {
3623 stbtt__rasterize(result, windings, winding_lengths, winding_count, scale_x, scale_y, shift_x, shift_y, x_off, y_off, invert, userdata);
3624 STBTT_free(winding_lengths, userdata);
3625 STBTT_free(windings, userdata);
3626 }
3627}
3628
3629STBTT_DEF void stbtt_FreeBitmap(unsigned char *bitmap, void *userdata)
3630{
3631 STBTT_free(bitmap, userdata);
3632}
3633
3634STBTT_DEF unsigned char *stbtt_GetGlyphBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int glyph, int *width, int *height, int *xoff, int *yoff)
3635{
3636 int ix0,iy0,ix1,iy1;
3637 stbtt__bitmap gbm;
3638 stbtt_vertex *vertices;
3639 int num_verts = stbtt_GetGlyphShape(info, glyph, &vertices);
3640
3641 if (scale_x == 0) scale_x = scale_y;
3642 if (scale_y == 0) {
3643 if (scale_x == 0) {
3644 STBTT_free(vertices, info->userdata);
3645 return NULL;
3646 }
3647 scale_y = scale_x;
3648 }
3649
3650 stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale_x, scale_y, shift_x, shift_y, &ix0,&iy0,&ix1,&iy1);
3651
3652 // now we get the size
3653 gbm.w = (ix1 - ix0);
3654 gbm.h = (iy1 - iy0);
3655 gbm.pixels = NULL; // in case we error
3656
3657 if (width ) *width = gbm.w;
3658 if (height) *height = gbm.h;
3659 if (xoff ) *xoff = ix0;
3660 if (yoff ) *yoff = iy0;
3661
3662 if (gbm.w && gbm.h) {
3663 gbm.pixels = (unsigned char *) STBTT_malloc(gbm.w * gbm.h, info->userdata);
3664 if (gbm.pixels) {
3665 gbm.stride = gbm.w;
3666
3667 stbtt_Rasterize(&gbm, 0.35f, vertices, num_verts, scale_x, scale_y, shift_x, shift_y, ix0, iy0, 1, info->userdata);
3668 }
3669 }
3670 STBTT_free(vertices, info->userdata);
3671 return gbm.pixels;
3672}
3673
3674STBTT_DEF unsigned char *stbtt_GetGlyphBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int glyph, int *width, int *height, int *xoff, int *yoff)
3675{
3676 return stbtt_GetGlyphBitmapSubpixel(info, scale_x, scale_y, 0.0f, 0.0f, glyph, width, height, xoff, yoff);
3677}
3678
3679STBTT_DEF void stbtt_MakeGlyphBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int glyph)
3680{
3681 int ix0,iy0;
3682 stbtt_vertex *vertices;
3683 int num_verts = stbtt_GetGlyphShape(info, glyph, &vertices);
3684 stbtt__bitmap gbm;
3685
3686 stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale_x, scale_y, shift_x, shift_y, &ix0,&iy0,0,0);
3687 gbm.pixels = output;
3688 gbm.w = out_w;
3689 gbm.h = out_h;
3690 gbm.stride = out_stride;
3691
3692 if (gbm.w && gbm.h)
3693 stbtt_Rasterize(&gbm, 0.35f, vertices, num_verts, scale_x, scale_y, shift_x, shift_y, ix0,iy0, 1, info->userdata);
3694
3695 STBTT_free(vertices, info->userdata);
3696}
3697
3698STBTT_DEF void stbtt_MakeGlyphBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int glyph)
3699{
3700 stbtt_MakeGlyphBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, scale_y, 0.0f,0.0f, glyph);
3701}
3702
3703STBTT_DEF unsigned char *stbtt_GetCodepointBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint, int *width, int *height, int *xoff, int *yoff)
3704{
3705 return stbtt_GetGlyphBitmapSubpixel(info, scale_x, scale_y,shift_x,shift_y, stbtt_FindGlyphIndex(info,codepoint), width,height,xoff,yoff);
3706}
3707
3708STBTT_DEF void stbtt_MakeCodepointBitmapSubpixelPrefilter(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int oversample_x, int oversample_y, float *sub_x, float *sub_y, int codepoint)
3709{
3710 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));
3711}
3712
3713STBTT_DEF void stbtt_MakeCodepointBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint)
3714{
3715 stbtt_MakeGlyphBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, scale_y, shift_x, shift_y, stbtt_FindGlyphIndex(info,codepoint));
3716}
3717
3718STBTT_DEF unsigned char *stbtt_GetCodepointBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int codepoint, int *width, int *height, int *xoff, int *yoff)
3719{
3720 return stbtt_GetCodepointBitmapSubpixel(info, scale_x, scale_y, 0.0f,0.0f, codepoint, width,height,xoff,yoff);
3721}
3722
3723STBTT_DEF void stbtt_MakeCodepointBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int codepoint)
3724{
3725 stbtt_MakeCodepointBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, scale_y, 0.0f,0.0f, codepoint);
3726}
3727
3729//
3730// bitmap baking
3731//
3732// This is SUPER-CRAPPY packing to keep source code small
3733
3734static int stbtt_BakeFontBitmap_internal(unsigned char *data, int offset, // font location (use offset=0 for plain .ttf)
3735 float pixel_height, // height of font in pixels
3736 unsigned char *pixels, int pw, int ph, // bitmap to be filled in
3737 int first_char, int num_chars, // characters to bake
3738 stbtt_bakedchar *chardata)
3739{
3740 float scale;
3741 int x,y,bottom_y, i;
3743 f.userdata = NULL;
3744 if (!stbtt_InitFont(&f, data, offset))
3745 return -1;
3746 STBTT_memset(pixels, 0, pw*ph); // background of 0 around pixels
3747 x=y=1;
3748 bottom_y = 1;
3749
3750 scale = stbtt_ScaleForPixelHeight(&f, pixel_height);
3751
3752 for (i=0; i < num_chars; ++i) {
3753 int advance, lsb, x0,y0,x1,y1,gw,gh;
3754 int g = stbtt_FindGlyphIndex(&f, first_char + i);
3755 stbtt_GetGlyphHMetrics(&f, g, &advance, &lsb);
3756 stbtt_GetGlyphBitmapBox(&f, g, scale,scale, &x0,&y0,&x1,&y1);
3757 gw = x1-x0;
3758 gh = y1-y0;
3759 if (x + gw + 1 >= pw)
3760 y = bottom_y, x = 1; // advance to next row
3761 if (y + gh + 1 >= ph) // check if it fits vertically AFTER potentially moving to next row
3762 return -i;
3763 STBTT_assert(x+gw < pw);
3764 STBTT_assert(y+gh < ph);
3765 stbtt_MakeGlyphBitmap(&f, pixels+x+y*pw, gw,gh,pw, scale,scale, g);
3766 chardata[i].x0 = (stbtt_int16) x;
3767 chardata[i].y0 = (stbtt_int16) y;
3768 chardata[i].x1 = (stbtt_int16) (x + gw);
3769 chardata[i].y1 = (stbtt_int16) (y + gh);
3770 chardata[i].xadvance = scale * advance;
3771 chardata[i].xoff = (float) x0;
3772 chardata[i].yoff = (float) y0;
3773 x = x + gw + 1;
3774 if (y+gh+1 > bottom_y)
3775 bottom_y = y+gh+1;
3776 }
3777 return bottom_y;
3778}
3779
3780STBTT_DEF void stbtt_GetBakedQuad(const stbtt_bakedchar *chardata, int pw, int ph, int char_index, float *xpos, float *ypos, stbtt_aligned_quad *q, int opengl_fillrule)
3781{
3782 float d3d_bias = opengl_fillrule ? 0 : -0.5f;
3783 float ipw = 1.0f / pw, iph = 1.0f / ph;
3784 const stbtt_bakedchar *b = chardata + char_index;
3785 int round_x = STBTT_ifloor((*xpos + b->xoff) + 0.5f);
3786 int round_y = STBTT_ifloor((*ypos + b->yoff) + 0.5f);
3787
3788 q->x0 = round_x + d3d_bias;
3789 q->y0 = round_y + d3d_bias;
3790 q->x1 = round_x + b->x1 - b->x0 + d3d_bias;
3791 q->y1 = round_y + b->y1 - b->y0 + d3d_bias;
3792
3793 q->s0 = b->x0 * ipw;
3794 q->t0 = b->y0 * iph;
3795 q->s1 = b->x1 * ipw;
3796 q->t1 = b->y1 * iph;
3797
3798 *xpos += b->xadvance;
3799}
3800
3802//
3803// rectangle packing replacement routines if you don't have stb_rect_pack.h
3804//
3805
3806#ifndef STB_RECT_PACK_VERSION
3807
3808typedef int stbrp_coord;
3809
3811// //
3812// //
3813// COMPILER WARNING ?!?!? //
3814// //
3815// //
3816// if you get a compile warning due to these symbols being defined more than //
3817// once, move #include "stb_rect_pack.h" before #include "stb_truetype.h" //
3818// //
3820
3821typedef struct
3822{
3823 int width,height;
3824 int x,y,bottom_y;
3826
3827typedef struct
3828{
3829 unsigned char x;
3830} stbrp_node;
3831
3837
3838static void stbrp_init_target(stbrp_context *con, int pw, int ph, stbrp_node *nodes, int num_nodes)
3839{
3840 con->width = pw;
3841 con->height = ph;
3842 con->x = 0;
3843 con->y = 0;
3844 con->bottom_y = 0;
3845 STBTT__NOTUSED(nodes);
3846 STBTT__NOTUSED(num_nodes);
3847}
3848
3849static void stbrp_pack_rects(stbrp_context *con, stbrp_rect *rects, int num_rects)
3850{
3851 int i;
3852 for (i=0; i < num_rects; ++i) {
3853 if (con->x + rects[i].w > con->width) {
3854 con->x = 0;
3855 con->y = con->bottom_y;
3856 }
3857 if (con->y + rects[i].h > con->height)
3858 break;
3859 rects[i].x = con->x;
3860 rects[i].y = con->y;
3861 rects[i].was_packed = 1;
3862 con->x += rects[i].w;
3863 if (con->y + rects[i].h > con->bottom_y)
3864 con->bottom_y = con->y + rects[i].h;
3865 }
3866 for ( ; i < num_rects; ++i)
3867 rects[i].was_packed = 0;
3868}
3869#endif
3870
3872//
3873// bitmap baking
3874//
3875// This is SUPER-AWESOME (tm Ryan Gordon) packing using stb_rect_pack.h. If
3876// stb_rect_pack.h isn't available, it uses the BakeFontBitmap strategy.
3877
3878STBTT_DEF int stbtt_PackBegin(stbtt_pack_context *spc, unsigned char *pixels, int pw, int ph, int stride_in_bytes, int padding, void *alloc_context)
3879{
3880 stbrp_context *context = (stbrp_context *) STBTT_malloc(sizeof(*context) ,alloc_context);
3881 int num_nodes = pw - padding;
3882 stbrp_node *nodes = (stbrp_node *) STBTT_malloc(sizeof(*nodes ) * num_nodes,alloc_context);
3883
3884 if (context == NULL || nodes == NULL) {
3885 if (context != NULL) STBTT_free(context, alloc_context);
3886 if (nodes != NULL) STBTT_free(nodes , alloc_context);
3887 return 0;
3888 }
3889
3890 spc->user_allocator_context = alloc_context;
3891 spc->width = pw;
3892 spc->height = ph;
3893 spc->pixels = pixels;
3894 spc->pack_info = context;
3895 spc->nodes = nodes;
3896 spc->padding = padding;
3897 spc->stride_in_bytes = stride_in_bytes != 0 ? stride_in_bytes : pw;
3898 spc->h_oversample = 1;
3899 spc->v_oversample = 1;
3900 spc->skip_missing = 0;
3901
3902 stbrp_init_target(context, pw-padding, ph-padding, nodes, num_nodes);
3903
3904 if (pixels)
3905 STBTT_memset(pixels, 0, pw*ph); // background of 0 around pixels
3906
3907 return 1;
3908}
3909
3910STBTT_DEF void stbtt_PackEnd (stbtt_pack_context *spc)
3911{
3914}
3915
3916STBTT_DEF void stbtt_PackSetOversampling(stbtt_pack_context *spc, unsigned int h_oversample, unsigned int v_oversample)
3917{
3918 STBTT_assert(h_oversample <= STBTT_MAX_OVERSAMPLE);
3919 STBTT_assert(v_oversample <= STBTT_MAX_OVERSAMPLE);
3920 if (h_oversample <= STBTT_MAX_OVERSAMPLE)
3921 spc->h_oversample = h_oversample;
3922 if (v_oversample <= STBTT_MAX_OVERSAMPLE)
3923 spc->v_oversample = v_oversample;
3924}
3925
3926STBTT_DEF void stbtt_PackSetSkipMissingCodepoints(stbtt_pack_context *spc, int skip)
3927{
3928 spc->skip_missing = skip;
3929}
3930
3931#define STBTT__OVER_MASK (STBTT_MAX_OVERSAMPLE-1)
3932
3933static void stbtt__h_prefilter(unsigned char *pixels, int w, int h, int stride_in_bytes, unsigned int kernel_width)
3934{
3935 unsigned char buffer[STBTT_MAX_OVERSAMPLE];
3936 int safe_w = w - kernel_width;
3937 int j;
3938 STBTT_memset(buffer, 0, STBTT_MAX_OVERSAMPLE); // suppress bogus warning from VS2013 -analyze
3939 for (j=0; j < h; ++j) {
3940 int i;
3941 unsigned int total;
3942 STBTT_memset(buffer, 0, kernel_width);
3943
3944 total = 0;
3945
3946 // make kernel_width a constant in common cases so compiler can optimize out the divide
3947 switch (kernel_width) {
3948 case 2:
3949 for (i=0; i <= safe_w; ++i) {
3950 total += pixels[i] - buffer[i & STBTT__OVER_MASK];
3951 buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i];
3952 pixels[i] = (unsigned char) (total / 2);
3953 }
3954 break;
3955 case 3:
3956 for (i=0; i <= safe_w; ++i) {
3957 total += pixels[i] - buffer[i & STBTT__OVER_MASK];
3958 buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i];
3959 pixels[i] = (unsigned char) (total / 3);
3960 }
3961 break;
3962 case 4:
3963 for (i=0; i <= safe_w; ++i) {
3964 total += pixels[i] - buffer[i & STBTT__OVER_MASK];
3965 buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i];
3966 pixels[i] = (unsigned char) (total / 4);
3967 }
3968 break;
3969 case 5:
3970 for (i=0; i <= safe_w; ++i) {
3971 total += pixels[i] - buffer[i & STBTT__OVER_MASK];
3972 buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i];
3973 pixels[i] = (unsigned char) (total / 5);
3974 }
3975 break;
3976 default:
3977 for (i=0; i <= safe_w; ++i) {
3978 total += pixels[i] - buffer[i & STBTT__OVER_MASK];
3979 buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i];
3980 pixels[i] = (unsigned char) (total / kernel_width);
3981 }
3982 break;
3983 }
3984
3985 for (; i < w; ++i) {
3986 STBTT_assert(pixels[i] == 0);
3987 total -= buffer[i & STBTT__OVER_MASK];
3988 pixels[i] = (unsigned char) (total / kernel_width);
3989 }
3990
3991 pixels += stride_in_bytes;
3992 }
3993}
3994
3995static void stbtt__v_prefilter(unsigned char *pixels, int w, int h, int stride_in_bytes, unsigned int kernel_width)
3996{
3997 unsigned char buffer[STBTT_MAX_OVERSAMPLE];
3998 int safe_h = h - kernel_width;
3999 int j;
4000 STBTT_memset(buffer, 0, STBTT_MAX_OVERSAMPLE); // suppress bogus warning from VS2013 -analyze
4001 for (j=0; j < w; ++j) {
4002 int i;
4003 unsigned int total;
4004 STBTT_memset(buffer, 0, kernel_width);
4005
4006 total = 0;
4007
4008 // make kernel_width a constant in common cases so compiler can optimize out the divide
4009 switch (kernel_width) {
4010 case 2:
4011 for (i=0; i <= safe_h; ++i) {
4012 total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK];
4013 buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes];
4014 pixels[i*stride_in_bytes] = (unsigned char) (total / 2);
4015 }
4016 break;
4017 case 3:
4018 for (i=0; i <= safe_h; ++i) {
4019 total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK];
4020 buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes];
4021 pixels[i*stride_in_bytes] = (unsigned char) (total / 3);
4022 }
4023 break;
4024 case 4:
4025 for (i=0; i <= safe_h; ++i) {
4026 total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK];
4027 buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes];
4028 pixels[i*stride_in_bytes] = (unsigned char) (total / 4);
4029 }
4030 break;
4031 case 5:
4032 for (i=0; i <= safe_h; ++i) {
4033 total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK];
4034 buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes];
4035 pixels[i*stride_in_bytes] = (unsigned char) (total / 5);
4036 }
4037 break;
4038 default:
4039 for (i=0; i <= safe_h; ++i) {
4040 total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK];
4041 buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes];
4042 pixels[i*stride_in_bytes] = (unsigned char) (total / kernel_width);
4043 }
4044 break;
4045 }
4046
4047 for (; i < h; ++i) {
4048 STBTT_assert(pixels[i*stride_in_bytes] == 0);
4049 total -= buffer[i & STBTT__OVER_MASK];
4050 pixels[i*stride_in_bytes] = (unsigned char) (total / kernel_width);
4051 }
4052
4053 pixels += 1;
4054 }
4055}
4056
4057static float stbtt__oversample_shift(int oversample)
4058{
4059 if (!oversample)
4060 return 0.0f;
4061
4062 // The prefilter is a box filter of width "oversample",
4063 // which shifts phase by (oversample - 1)/2 pixels in
4064 // oversampled space. We want to shift in the opposite
4065 // direction to counter this.
4066 return (float)-(oversample - 1) / (2.0f * (float)oversample);
4067}
4068
4069// rects array must be big enough to accommodate all characters in the given ranges
4070STBTT_DEF int stbtt_PackFontRangesGatherRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects)
4071{
4072 int i,j,k;
4073 int missing_glyph_added = 0;
4074
4075 k=0;
4076 for (i=0; i < num_ranges; ++i) {
4077 float fh = ranges[i].font_size;
4078 float scale = fh > 0 ? stbtt_ScaleForPixelHeight(info, fh) : stbtt_ScaleForMappingEmToPixels(info, -fh);
4079 ranges[i].h_oversample = (unsigned char) spc->h_oversample;
4080 ranges[i].v_oversample = (unsigned char) spc->v_oversample;
4081 for (j=0; j < ranges[i].num_chars; ++j) {
4082 int x0,y0,x1,y1;
4083 int codepoint = ranges[i].array_of_unicode_codepoints == NULL ? ranges[i].first_unicode_codepoint_in_range + j : ranges[i].array_of_unicode_codepoints[j];
4084 int glyph = stbtt_FindGlyphIndex(info, codepoint);
4085 if (glyph == 0 && (spc->skip_missing || missing_glyph_added)) {
4086 rects[k].w = rects[k].h = 0;
4087 } else {
4088 stbtt_GetGlyphBitmapBoxSubpixel(info,glyph,
4089 scale * spc->h_oversample,
4090 scale * spc->v_oversample,
4091 0,0,
4092 &x0,&y0,&x1,&y1);
4093 rects[k].w = (stbrp_coord) (x1-x0 + spc->padding + spc->h_oversample-1);
4094 rects[k].h = (stbrp_coord) (y1-y0 + spc->padding + spc->v_oversample-1);
4095 if (glyph == 0)
4096 missing_glyph_added = 1;
4097 }
4098 ++k;
4099 }
4100 }
4101
4102 return k;
4103}
4104
4105STBTT_DEF void stbtt_MakeGlyphBitmapSubpixelPrefilter(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int prefilter_x, int prefilter_y, float *sub_x, float *sub_y, int glyph)
4106{
4107 stbtt_MakeGlyphBitmapSubpixel(info,
4108 output,
4109 out_w - (prefilter_x - 1),
4110 out_h - (prefilter_y - 1),
4111 out_stride,
4112 scale_x,
4113 scale_y,
4114 shift_x,
4115 shift_y,
4116 glyph);
4117
4118 if (prefilter_x > 1)
4119 stbtt__h_prefilter(output, out_w, out_h, out_stride, prefilter_x);
4120
4121 if (prefilter_y > 1)
4122 stbtt__v_prefilter(output, out_w, out_h, out_stride, prefilter_y);
4123
4124 *sub_x = stbtt__oversample_shift(prefilter_x);
4125 *sub_y = stbtt__oversample_shift(prefilter_y);
4126}
4127
4128// rects array must be big enough to accommodate all characters in the given ranges
4129STBTT_DEF int stbtt_PackFontRangesRenderIntoRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects)
4130{
4131 int i,j,k, missing_glyph = -1, return_value = 1;
4132
4133 // save current values
4134 int old_h_over = spc->h_oversample;
4135 int old_v_over = spc->v_oversample;
4136
4137 k = 0;
4138 for (i=0; i < num_ranges; ++i) {
4139 float fh = ranges[i].font_size;
4140 float scale = fh > 0 ? stbtt_ScaleForPixelHeight(info, fh) : stbtt_ScaleForMappingEmToPixels(info, -fh);
4141 float recip_h,recip_v,sub_x,sub_y;
4142 spc->h_oversample = ranges[i].h_oversample;
4143 spc->v_oversample = ranges[i].v_oversample;
4144 recip_h = 1.0f / spc->h_oversample;
4145 recip_v = 1.0f / spc->v_oversample;
4146 sub_x = stbtt__oversample_shift(spc->h_oversample);
4147 sub_y = stbtt__oversample_shift(spc->v_oversample);
4148 for (j=0; j < ranges[i].num_chars; ++j) {
4149 stbrp_rect *r = &rects[k];
4150 if (r->was_packed && r->w != 0 && r->h != 0) {
4151 stbtt_packedchar *bc = &ranges[i].chardata_for_range[j];
4152 int advance, lsb, x0,y0,x1,y1;
4153 int codepoint = ranges[i].array_of_unicode_codepoints == NULL ? ranges[i].first_unicode_codepoint_in_range + j : ranges[i].array_of_unicode_codepoints[j];
4154 int glyph = stbtt_FindGlyphIndex(info, codepoint);
4155 stbrp_coord pad = (stbrp_coord) spc->padding;
4156
4157 // pad on left and top
4158 r->x += pad;
4159 r->y += pad;
4160 r->w -= pad;
4161 r->h -= pad;
4162 stbtt_GetGlyphHMetrics(info, glyph, &advance, &lsb);
4163 stbtt_GetGlyphBitmapBox(info, glyph,
4164 scale * spc->h_oversample,
4165 scale * spc->v_oversample,
4166 &x0,&y0,&x1,&y1);
4167 stbtt_MakeGlyphBitmapSubpixel(info,
4168 spc->pixels + r->x + r->y*spc->stride_in_bytes,
4169 r->w - spc->h_oversample+1,
4170 r->h - spc->v_oversample+1,
4171 spc->stride_in_bytes,
4172 scale * spc->h_oversample,
4173 scale * spc->v_oversample,
4174 0,0,
4175 glyph);
4176
4177 if (spc->h_oversample > 1)
4178 stbtt__h_prefilter(spc->pixels + r->x + r->y*spc->stride_in_bytes,
4179 r->w, r->h, spc->stride_in_bytes,
4180 spc->h_oversample);
4181
4182 if (spc->v_oversample > 1)
4183 stbtt__v_prefilter(spc->pixels + r->x + r->y*spc->stride_in_bytes,
4184 r->w, r->h, spc->stride_in_bytes,
4185 spc->v_oversample);
4186
4187 bc->x0 = (stbtt_int16) r->x;
4188 bc->y0 = (stbtt_int16) r->y;
4189 bc->x1 = (stbtt_int16) (r->x + r->w);
4190 bc->y1 = (stbtt_int16) (r->y + r->h);
4191 bc->xadvance = scale * advance;
4192 bc->xoff = (float) x0 * recip_h + sub_x;
4193 bc->yoff = (float) y0 * recip_v + sub_y;
4194 bc->xoff2 = (x0 + r->w) * recip_h + sub_x;
4195 bc->yoff2 = (y0 + r->h) * recip_v + sub_y;
4196
4197 if (glyph == 0)
4198 missing_glyph = j;
4199 } else if (spc->skip_missing) {
4200 return_value = 0;
4201 } else if (r->was_packed && r->w == 0 && r->h == 0 && missing_glyph >= 0) {
4202 ranges[i].chardata_for_range[j] = ranges[i].chardata_for_range[missing_glyph];
4203 } else {
4204 return_value = 0; // if any fail, report failure
4205 }
4206
4207 ++k;
4208 }
4209 }
4210
4211 // restore original values
4212 spc->h_oversample = old_h_over;
4213 spc->v_oversample = old_v_over;
4214
4215 return return_value;
4216}
4217
4218STBTT_DEF void stbtt_PackFontRangesPackRects(stbtt_pack_context *spc, stbrp_rect *rects, int num_rects)
4219{
4220 stbrp_pack_rects((stbrp_context *) spc->pack_info, rects, num_rects);
4221}
4222
4223STBTT_DEF int stbtt_PackFontRanges(stbtt_pack_context *spc, const unsigned char *fontdata, int font_index, stbtt_pack_range *ranges, int num_ranges)
4224{
4225 stbtt_fontinfo info;
4226 int i,j,n, return_value = 1;
4227 //stbrp_context *context = (stbrp_context *) spc->pack_info;
4228 stbrp_rect *rects;
4229
4230 // flag all characters as NOT packed
4231 for (i=0; i < num_ranges; ++i)
4232 for (j=0; j < ranges[i].num_chars; ++j)
4233 ranges[i].chardata_for_range[j].x0 =
4234 ranges[i].chardata_for_range[j].y0 =
4235 ranges[i].chardata_for_range[j].x1 =
4236 ranges[i].chardata_for_range[j].y1 = 0;
4237
4238 n = 0;
4239 for (i=0; i < num_ranges; ++i)
4240 n += ranges[i].num_chars;
4241
4242 rects = (stbrp_rect *) STBTT_malloc(sizeof(*rects) * n, spc->user_allocator_context);
4243 if (rects == NULL)
4244 return 0;
4245
4246 info.userdata = spc->user_allocator_context;
4247 stbtt_InitFont(&info, fontdata, stbtt_GetFontOffsetForIndex(fontdata,font_index));
4248
4249 n = stbtt_PackFontRangesGatherRects(spc, &info, ranges, num_ranges, rects);
4250
4251 stbtt_PackFontRangesPackRects(spc, rects, n);
4252
4253 return_value = stbtt_PackFontRangesRenderIntoRects(spc, &info, ranges, num_ranges, rects);
4254
4256 return return_value;
4257}
4258
4259STBTT_DEF int stbtt_PackFontRange(stbtt_pack_context *spc, const unsigned char *fontdata, int font_index, float font_size,
4260 int first_unicode_codepoint_in_range, int num_chars_in_range, stbtt_packedchar *chardata_for_range)
4261{
4262 stbtt_pack_range range;
4263 range.first_unicode_codepoint_in_range = first_unicode_codepoint_in_range;
4264 range.array_of_unicode_codepoints = NULL;
4265 range.num_chars = num_chars_in_range;
4266 range.chardata_for_range = chardata_for_range;
4267 range.font_size = font_size;
4268 return stbtt_PackFontRanges(spc, fontdata, font_index, &range, 1);
4269}
4270
4271STBTT_DEF void stbtt_GetScaledFontVMetrics(const unsigned char *fontdata, int index, float size, float *ascent, float *descent, float *lineGap)
4272{
4273 int i_ascent, i_descent, i_lineGap;
4274 float scale;
4275 stbtt_fontinfo info;
4276 stbtt_InitFont(&info, fontdata, stbtt_GetFontOffsetForIndex(fontdata, index));
4277 scale = size > 0 ? stbtt_ScaleForPixelHeight(&info, size) : stbtt_ScaleForMappingEmToPixels(&info, -size);
4278 stbtt_GetFontVMetrics(&info, &i_ascent, &i_descent, &i_lineGap);
4279 *ascent = (float) i_ascent * scale;
4280 *descent = (float) i_descent * scale;
4281 *lineGap = (float) i_lineGap * scale;
4282}
4283
4284STBTT_DEF void stbtt_GetPackedQuad(const stbtt_packedchar *chardata, int pw, int ph, int char_index, float *xpos, float *ypos, stbtt_aligned_quad *q, int align_to_integer)
4285{
4286 float ipw = 1.0f / pw, iph = 1.0f / ph;
4287 const stbtt_packedchar *b = chardata + char_index;
4288
4289 if (align_to_integer) {
4290 float x = (float) STBTT_ifloor((*xpos + b->xoff) + 0.5f);
4291 float y = (float) STBTT_ifloor((*ypos + b->yoff) + 0.5f);
4292 q->x0 = x;
4293 q->y0 = y;
4294 q->x1 = x + b->xoff2 - b->xoff;
4295 q->y1 = y + b->yoff2 - b->yoff;
4296 } else {
4297 q->x0 = *xpos + b->xoff;
4298 q->y0 = *ypos + b->yoff;
4299 q->x1 = *xpos + b->xoff2;
4300 q->y1 = *ypos + b->yoff2;
4301 }
4302
4303 q->s0 = b->x0 * ipw;
4304 q->t0 = b->y0 * iph;
4305 q->s1 = b->x1 * ipw;
4306 q->t1 = b->y1 * iph;
4307
4308 *xpos += b->xadvance;
4309}
4310
4312//
4313// sdf computation
4314//
4315
4316#define STBTT_min(a,b) ((a) < (b) ? (a) : (b))
4317#define STBTT_max(a,b) ((a) < (b) ? (b) : (a))
4318
4319static int stbtt__ray_intersect_bezier(float orig[2], float ray[2], float q0[2], float q1[2], float q2[2], float hits[2][2])
4320{
4321 float q0perp = q0[1]*ray[0] - q0[0]*ray[1];
4322 float q1perp = q1[1]*ray[0] - q1[0]*ray[1];
4323 float q2perp = q2[1]*ray[0] - q2[0]*ray[1];
4324 float roperp = orig[1]*ray[0] - orig[0]*ray[1];
4325
4326 float a = q0perp - 2*q1perp + q2perp;
4327 float b = q1perp - q0perp;
4328 float c = q0perp - roperp;
4329
4330 float s0 = 0., s1 = 0.;
4331 int num_s = 0;
4332
4333 if (a != 0.0) {
4334 float discr = b*b - a*c;
4335 if (discr > 0.0) {
4336 float rcpna = -1 / a;
4337 float d = (float) STBTT_sqrt(discr);
4338 s0 = (b+d) * rcpna;
4339 s1 = (b-d) * rcpna;
4340 if (s0 >= 0.0 && s0 <= 1.0)
4341 num_s = 1;
4342 if (d > 0.0 && s1 >= 0.0 && s1 <= 1.0) {
4343 if (num_s == 0) s0 = s1;
4344 ++num_s;
4345 }
4346 }
4347 } else {
4348 // 2*b*s + c = 0
4349 // s = -c / (2*b)
4350 s0 = c / (-2 * b);
4351 if (s0 >= 0.0 && s0 <= 1.0)
4352 num_s = 1;
4353 }
4354
4355 if (num_s == 0)
4356 return 0;
4357 else {
4358 float rcp_len2 = 1 / (ray[0]*ray[0] + ray[1]*ray[1]);
4359 float rayn_x = ray[0] * rcp_len2, rayn_y = ray[1] * rcp_len2;
4360
4361 float q0d = q0[0]*rayn_x + q0[1]*rayn_y;
4362 float q1d = q1[0]*rayn_x + q1[1]*rayn_y;
4363 float q2d = q2[0]*rayn_x + q2[1]*rayn_y;
4364 float rod = orig[0]*rayn_x + orig[1]*rayn_y;
4365
4366 float q10d = q1d - q0d;
4367 float q20d = q2d - q0d;
4368 float q0rd = q0d - rod;
4369
4370 hits[0][0] = q0rd + s0*(2.0f - 2.0f*s0)*q10d + s0*s0*q20d;
4371 hits[0][1] = a*s0+b;
4372
4373 if (num_s > 1) {
4374 hits[1][0] = q0rd + s1*(2.0f - 2.0f*s1)*q10d + s1*s1*q20d;
4375 hits[1][1] = a*s1+b;
4376 return 2;
4377 } else {
4378 return 1;
4379 }
4380 }
4381}
4382
4383static int equal(float *a, float *b)
4384{
4385 return (a[0] == b[0] && a[1] == b[1]);
4386}
4387
4388static int stbtt__compute_crossings_x(float x, float y, int nverts, stbtt_vertex *verts)
4389{
4390 int i;
4391 float orig[2], ray[2] = { 1, 0 };
4392 float y_frac;
4393 int winding = 0;
4394
4395 // make sure y never passes through a vertex of the shape
4396 y_frac = (float) STBTT_fmod(y, 1.0f);
4397 if (y_frac < 0.01f)
4398 y += 0.01f;
4399 else if (y_frac > 0.99f)
4400 y -= 0.01f;
4401
4402 orig[0] = x;
4403 orig[1] = y;
4404
4405 // test a ray from (-infinity,y) to (x,y)
4406 for (i=0; i < nverts; ++i) {
4407 if (verts[i].type == STBTT_vline) {
4408 int x0 = (int) verts[i-1].x, y0 = (int) verts[i-1].y;
4409 int x1 = (int) verts[i ].x, y1 = (int) verts[i ].y;
4410 if (y > STBTT_min(y0,y1) && y < STBTT_max(y0,y1) && x > STBTT_min(x0,x1)) {
4411 float x_inter = (y - y0) / (y1 - y0) * (x1-x0) + x0;
4412 if (x_inter < x)
4413 winding += (y0 < y1) ? 1 : -1;
4414 }
4415 }
4416 if (verts[i].type == STBTT_vcurve) {
4417 int x0 = (int) verts[i-1].x , y0 = (int) verts[i-1].y ;
4418 int x1 = (int) verts[i ].cx, y1 = (int) verts[i ].cy;
4419 int x2 = (int) verts[i ].x , y2 = (int) verts[i ].y ;
4420 int ax = STBTT_min(x0,STBTT_min(x1,x2)), ay = STBTT_min(y0,STBTT_min(y1,y2));
4421 int by = STBTT_max(y0,STBTT_max(y1,y2));
4422 if (y > ay && y < by && x > ax) {
4423 float q0[2],q1[2],q2[2];
4424 float hits[2][2];
4425 q0[0] = (float)x0;
4426 q0[1] = (float)y0;
4427 q1[0] = (float)x1;
4428 q1[1] = (float)y1;
4429 q2[0] = (float)x2;
4430 q2[1] = (float)y2;
4431 if (equal(q0,q1) || equal(q1,q2)) {
4432 x0 = (int)verts[i-1].x;
4433 y0 = (int)verts[i-1].y;
4434 x1 = (int)verts[i ].x;
4435 y1 = (int)verts[i ].y;
4436 if (y > STBTT_min(y0,y1) && y < STBTT_max(y0,y1) && x > STBTT_min(x0,x1)) {
4437 float x_inter = (y - y0) / (y1 - y0) * (x1-x0) + x0;
4438 if (x_inter < x)
4439 winding += (y0 < y1) ? 1 : -1;
4440 }
4441 } else {
4442 int num_hits = stbtt__ray_intersect_bezier(orig, ray, q0, q1, q2, hits);
4443 if (num_hits >= 1)
4444 if (hits[0][0] < 0)
4445 winding += (hits[0][1] < 0 ? -1 : 1);
4446 if (num_hits >= 2)
4447 if (hits[1][0] < 0)
4448 winding += (hits[1][1] < 0 ? -1 : 1);
4449 }
4450 }
4451 }
4452 }
4453 return winding;
4454}
4455
4456static float stbtt__cuberoot( float x )
4457{
4458 if (x<0)
4459 return -(float) STBTT_pow(-x,1.0f/3.0f);
4460 else
4461 return (float) STBTT_pow( x,1.0f/3.0f);
4462}
4463
4464// x^3 + a*x^2 + b*x + c = 0
4465static int stbtt__solve_cubic(float a, float b, float c, float* r)
4466{
4467 float s = -a / 3;
4468 float p = b - a*a / 3;
4469 float q = a * (2*a*a - 9*b) / 27 + c;
4470 float p3 = p*p*p;
4471 float d = q*q + 4*p3 / 27;
4472 if (d >= 0) {
4473 float z = (float) STBTT_sqrt(d);
4474 float u = (-q + z) / 2;
4475 float v = (-q - z) / 2;
4476 u = stbtt__cuberoot(u);
4477 v = stbtt__cuberoot(v);
4478 r[0] = s + u + v;
4479 return 1;
4480 } else {
4481 float u = (float) STBTT_sqrt(-p/3);
4482 float v = (float) STBTT_acos(-STBTT_sqrt(-27/p3) * q / 2) / 3; // p3 must be negative, since d is negative
4483 float m = (float) STBTT_cos(v);
4484 float n = (float) STBTT_cos(v-3.141592/2)*1.732050808f;
4485 r[0] = s + u * 2 * m;
4486 r[1] = s - u * (m + n);
4487 r[2] = s - u * (m - n);
4488
4489 //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?
4490 //STBTT_assert( STBTT_fabs(((r[1]+a)*r[1]+b)*r[1]+c) < 0.05f);
4491 //STBTT_assert( STBTT_fabs(((r[2]+a)*r[2]+b)*r[2]+c) < 0.05f);
4492 return 3;
4493 }
4494}
4495
4496STBTT_DEF unsigned char * stbtt_GetGlyphSDF(const stbtt_fontinfo *info, float scale, int glyph, int padding, unsigned char onedge_value, float pixel_dist_scale, int *width, int *height, int *xoff, int *yoff)
4497{
4498 float scale_x = scale, scale_y = scale;
4499 int ix0,iy0,ix1,iy1;
4500 int w,h;
4501 unsigned char *data;
4502
4503 if (scale == 0) return NULL;
4504
4505 stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale, scale, 0.0f,0.0f, &ix0,&iy0,&ix1,&iy1);
4506
4507 // if empty, return NULL
4508 if (ix0 == ix1 || iy0 == iy1)
4509 return NULL;
4510
4511 ix0 -= padding;
4512 iy0 -= padding;
4513 ix1 += padding;
4514 iy1 += padding;
4515
4516 w = (ix1 - ix0);
4517 h = (iy1 - iy0);
4518
4519 if (width ) *width = w;
4520 if (height) *height = h;
4521 if (xoff ) *xoff = ix0;
4522 if (yoff ) *yoff = iy0;
4523
4524 // invert for y-downwards bitmaps
4525 scale_y = -scale_y;
4526
4527 {
4528 int x,y,i,j;
4529 float *precompute;
4530 stbtt_vertex *verts;
4531 int num_verts = stbtt_GetGlyphShape(info, glyph, &verts);
4532 data = (unsigned char *) STBTT_malloc(w * h, info->userdata);
4533 precompute = (float *) STBTT_malloc(num_verts * sizeof(float), info->userdata);
4534
4535 for (i=0,j=num_verts-1; i < num_verts; j=i++) {
4536 if (verts[i].type == STBTT_vline) {
4537 float x0 = verts[i].x*scale_x, y0 = verts[i].y*scale_y;
4538 float x1 = verts[j].x*scale_x, y1 = verts[j].y*scale_y;
4539 float dist = (float) STBTT_sqrt((x1-x0)*(x1-x0) + (y1-y0)*(y1-y0));
4540 precompute[i] = (dist == 0) ? 0.0f : 1.0f / dist;
4541 } else if (verts[i].type == STBTT_vcurve) {
4542 float x2 = verts[j].x *scale_x, y2 = verts[j].y *scale_y;
4543 float x1 = verts[i].cx*scale_x, y1 = verts[i].cy*scale_y;
4544 float x0 = verts[i].x *scale_x, y0 = verts[i].y *scale_y;
4545 float bx = x0 - 2*x1 + x2, by = y0 - 2*y1 + y2;
4546 float len2 = bx*bx + by*by;
4547 if (len2 != 0.0f)
4548 precompute[i] = 1.0f / (bx*bx + by*by);
4549 else
4550 precompute[i] = 0.0f;
4551 } else
4552 precompute[i] = 0.0f;
4553 }
4554
4555 for (y=iy0; y < iy1; ++y) {
4556 for (x=ix0; x < ix1; ++x) {
4557 float val;
4558 float min_dist = 999999.0f;
4559 float sx = (float) x + 0.5f;
4560 float sy = (float) y + 0.5f;
4561 float x_gspace = (sx / scale_x);
4562 float y_gspace = (sy / scale_y);
4563
4564 int winding = stbtt__compute_crossings_x(x_gspace, y_gspace, num_verts, verts); // @OPTIMIZE: this could just be a rasterization, but needs to be line vs. non-tesselated curves so a new path
4565
4566 for (i=0; i < num_verts; ++i) {
4567 float x0 = verts[i].x*scale_x, y0 = verts[i].y*scale_y;
4568
4569 if (verts[i].type == STBTT_vline && precompute[i] != 0.0f) {
4570 float x1 = verts[i-1].x*scale_x, y1 = verts[i-1].y*scale_y;
4571
4572 float dist,dist2 = (x0-sx)*(x0-sx) + (y0-sy)*(y0-sy);
4573 if (dist2 < min_dist*min_dist)
4574 min_dist = (float) STBTT_sqrt(dist2);
4575
4576 // coarse culling against bbox
4577 //if (sx > STBTT_min(x0,x1)-min_dist && sx < STBTT_max(x0,x1)+min_dist &&
4578 // sy > STBTT_min(y0,y1)-min_dist && sy < STBTT_max(y0,y1)+min_dist)
4579 dist = (float) STBTT_fabs((x1-x0)*(y0-sy) - (y1-y0)*(x0-sx)) * precompute[i];
4580 STBTT_assert(i != 0);
4581 if (dist < min_dist) {
4582 // check position along line
4583 // x' = x0 + t*(x1-x0), y' = y0 + t*(y1-y0)
4584 // minimize (x'-sx)*(x'-sx)+(y'-sy)*(y'-sy)
4585 float dx = x1-x0, dy = y1-y0;
4586 float px = x0-sx, py = y0-sy;
4587 // 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
4588 // derivative: 2*px*dx + 2*py*dy + (2*dx*dx+2*dy*dy)*t, set to 0 and solve
4589 float t = -(px*dx + py*dy) / (dx*dx + dy*dy);
4590 if (t >= 0.0f && t <= 1.0f)
4591 min_dist = dist;
4592 }
4593 } else if (verts[i].type == STBTT_vcurve) {
4594 float x2 = verts[i-1].x *scale_x, y2 = verts[i-1].y *scale_y;
4595 float x1 = verts[i ].cx*scale_x, y1 = verts[i ].cy*scale_y;
4596 float box_x0 = STBTT_min(STBTT_min(x0,x1),x2);
4597 float box_y0 = STBTT_min(STBTT_min(y0,y1),y2);
4598 float box_x1 = STBTT_max(STBTT_max(x0,x1),x2);
4599 float box_y1 = STBTT_max(STBTT_max(y0,y1),y2);
4600 // coarse culling against bbox to avoid computing cubic unnecessarily
4601 if (sx > box_x0-min_dist && sx < box_x1+min_dist && sy > box_y0-min_dist && sy < box_y1+min_dist) {
4602 int num=0;
4603 float ax = x1-x0, ay = y1-y0;
4604 float bx = x0 - 2*x1 + x2, by = y0 - 2*y1 + y2;
4605 float mx = x0 - sx, my = y0 - sy;
4606 float res[3] = {0.f,0.f,0.f};
4607 float px,py,t,it,dist2;
4608 float a_inv = precompute[i];
4609 if (a_inv == 0.0) { // if a_inv is 0, it's 2nd degree so use quadratic formula
4610 float a = 3*(ax*bx + ay*by);
4611 float b = 2*(ax*ax + ay*ay) + (mx*bx+my*by);
4612 float c = mx*ax+my*ay;
4613 if (a == 0.0) { // if a is 0, it's linear
4614 if (b != 0.0) {
4615 res[num++] = -c/b;
4616 }
4617 } else {
4618 float discriminant = b*b - 4*a*c;
4619 if (discriminant < 0)
4620 num = 0;
4621 else {
4622 float root = (float) STBTT_sqrt(discriminant);
4623 res[0] = (-b - root)/(2*a);
4624 res[1] = (-b + root)/(2*a);
4625 num = 2; // don't bother distinguishing 1-solution case, as code below will still work
4626 }
4627 }
4628 } else {
4629 float b = 3*(ax*bx + ay*by) * a_inv; // could precompute this as it doesn't depend on sample point
4630 float c = (2*(ax*ax + ay*ay) + (mx*bx+my*by)) * a_inv;
4631 float d = (mx*ax+my*ay) * a_inv;
4632 num = stbtt__solve_cubic(b, c, d, res);
4633 }
4634 dist2 = (x0-sx)*(x0-sx) + (y0-sy)*(y0-sy);
4635 if (dist2 < min_dist*min_dist)
4636 min_dist = (float) STBTT_sqrt(dist2);
4637
4638 if (num >= 1 && res[0] >= 0.0f && res[0] <= 1.0f) {
4639 t = res[0], it = 1.0f - t;
4640 px = it*it*x0 + 2*t*it*x1 + t*t*x2;
4641 py = it*it*y0 + 2*t*it*y1 + t*t*y2;
4642 dist2 = (px-sx)*(px-sx) + (py-sy)*(py-sy);
4643 if (dist2 < min_dist * min_dist)
4644 min_dist = (float) STBTT_sqrt(dist2);
4645 }
4646 if (num >= 2 && res[1] >= 0.0f && res[1] <= 1.0f) {
4647 t = res[1], it = 1.0f - t;
4648 px = it*it*x0 + 2*t*it*x1 + t*t*x2;
4649 py = it*it*y0 + 2*t*it*y1 + t*t*y2;
4650 dist2 = (px-sx)*(px-sx) + (py-sy)*(py-sy);
4651 if (dist2 < min_dist * min_dist)
4652 min_dist = (float) STBTT_sqrt(dist2);
4653 }
4654 if (num >= 3 && res[2] >= 0.0f && res[2] <= 1.0f) {
4655 t = res[2], it = 1.0f - t;
4656 px = it*it*x0 + 2*t*it*x1 + t*t*x2;
4657 py = it*it*y0 + 2*t*it*y1 + t*t*y2;
4658 dist2 = (px-sx)*(px-sx) + (py-sy)*(py-sy);
4659 if (dist2 < min_dist * min_dist)
4660 min_dist = (float) STBTT_sqrt(dist2);
4661 }
4662 }
4663 }
4664 }
4665 if (winding == 0)
4666 min_dist = -min_dist; // if outside the shape, value is negative
4667 val = onedge_value + pixel_dist_scale * min_dist;
4668 if (val < 0)
4669 val = 0;
4670 else if (val > 255)
4671 val = 255;
4672 data[(y-iy0)*w+(x-ix0)] = (unsigned char) val;
4673 }
4674 }
4675 STBTT_free(precompute, info->userdata);
4676 STBTT_free(verts, info->userdata);
4677 }
4678 return data;
4679}
4680
4681STBTT_DEF unsigned char * stbtt_GetCodepointSDF(const stbtt_fontinfo *info, float scale, int codepoint, int padding, unsigned char onedge_value, float pixel_dist_scale, int *width, int *height, int *xoff, int *yoff)
4682{
4683 return stbtt_GetGlyphSDF(info, scale, stbtt_FindGlyphIndex(info, codepoint), padding, onedge_value, pixel_dist_scale, width, height, xoff, yoff);
4684}
4685
4686STBTT_DEF void stbtt_FreeSDF(unsigned char *bitmap, void *userdata)
4687{
4688 STBTT_free(bitmap, userdata);
4689}
4690
4692//
4693// font name matching -- recommended not to use this
4694//
4695
4696// check if a utf8 string contains a prefix which is the utf16 string; if so return length of matching utf8 string
4697static stbtt_int32 stbtt__CompareUTF8toUTF16_bigendian_prefix(stbtt_uint8 *s1, stbtt_int32 len1, stbtt_uint8 *s2, stbtt_int32 len2)
4698{
4699 stbtt_int32 i=0;
4700
4701 // convert utf16 to utf8 and compare the results while converting
4702 while (len2) {
4703 stbtt_uint16 ch = s2[0]*256 + s2[1];
4704 if (ch < 0x80) {
4705 if (i >= len1) return -1;
4706 if (s1[i++] != ch) return -1;
4707 } else if (ch < 0x800) {
4708 if (i+1 >= len1) return -1;
4709 if (s1[i++] != 0xc0 + (ch >> 6)) return -1;
4710 if (s1[i++] != 0x80 + (ch & 0x3f)) return -1;
4711 } else if (ch >= 0xd800 && ch < 0xdc00) {
4712 stbtt_uint32 c;
4713 stbtt_uint16 ch2 = s2[2]*256 + s2[3];
4714 if (i+3 >= len1) return -1;
4715 c = ((ch - 0xd800) << 10) + (ch2 - 0xdc00) + 0x10000;
4716 if (s1[i++] != 0xf0 + (c >> 18)) return -1;
4717 if (s1[i++] != 0x80 + ((c >> 12) & 0x3f)) return -1;
4718 if (s1[i++] != 0x80 + ((c >> 6) & 0x3f)) return -1;
4719 if (s1[i++] != 0x80 + ((c ) & 0x3f)) return -1;
4720 s2 += 2; // plus another 2 below
4721 len2 -= 2;
4722 } else if (ch >= 0xdc00 && ch < 0xe000) {
4723 return -1;
4724 } else {
4725 if (i+2 >= len1) return -1;
4726 if (s1[i++] != 0xe0 + (ch >> 12)) return -1;
4727 if (s1[i++] != 0x80 + ((ch >> 6) & 0x3f)) return -1;
4728 if (s1[i++] != 0x80 + ((ch ) & 0x3f)) return -1;
4729 }
4730 s2 += 2;
4731 len2 -= 2;
4732 }
4733 return i;
4734}
4735
4736static int stbtt_CompareUTF8toUTF16_bigendian_internal(char *s1, int len1, char *s2, int len2)
4737{
4738 return len1 == stbtt__CompareUTF8toUTF16_bigendian_prefix((stbtt_uint8*) s1, len1, (stbtt_uint8*) s2, len2);
4739}
4740
4741// returns results in whatever encoding you request... but note that 2-byte encodings
4742// will be BIG-ENDIAN... use stbtt_CompareUTF8toUTF16_bigendian() to compare
4743STBTT_DEF const char *stbtt_GetFontNameString(const stbtt_fontinfo *font, int *length, int platformID, int encodingID, int languageID, int nameID)
4744{
4745 stbtt_int32 i,count,stringOffset;
4746 stbtt_uint8 *fc = font->data;
4747 stbtt_uint32 offset = font->fontstart;
4748 stbtt_uint32 nm = stbtt__find_table(fc, offset, "name");
4749 if (!nm) return NULL;
4750
4751 count = ttUSHORT(fc+nm+2);
4752 stringOffset = nm + ttUSHORT(fc+nm+4);
4753 for (i=0; i < count; ++i) {
4754 stbtt_uint32 loc = nm + 6 + 12 * i;
4755 if (platformID == ttUSHORT(fc+loc+0) && encodingID == ttUSHORT(fc+loc+2)
4756 && languageID == ttUSHORT(fc+loc+4) && nameID == ttUSHORT(fc+loc+6)) {
4757 *length = ttUSHORT(fc+loc+8);
4758 return (const char *) (fc+stringOffset+ttUSHORT(fc+loc+10));
4759 }
4760 }
4761 return NULL;
4762}
4763
4764static int stbtt__matchpair(stbtt_uint8 *fc, stbtt_uint32 nm, stbtt_uint8 *name, stbtt_int32 nlen, stbtt_int32 target_id, stbtt_int32 next_id)
4765{
4766 stbtt_int32 i;
4767 stbtt_int32 count = ttUSHORT(fc+nm+2);
4768 stbtt_int32 stringOffset = nm + ttUSHORT(fc+nm+4);
4769
4770 for (i=0; i < count; ++i) {
4771 stbtt_uint32 loc = nm + 6 + 12 * i;
4772 stbtt_int32 id = ttUSHORT(fc+loc+6);
4773 if (id == target_id) {
4774 // find the encoding
4775 stbtt_int32 platform = ttUSHORT(fc+loc+0), encoding = ttUSHORT(fc+loc+2), language = ttUSHORT(fc+loc+4);
4776
4777 // is this a Unicode encoding?
4778 if (platform == 0 || (platform == 3 && encoding == 1) || (platform == 3 && encoding == 10)) {
4779 stbtt_int32 slen = ttUSHORT(fc+loc+8);
4780 stbtt_int32 off = ttUSHORT(fc+loc+10);
4781
4782 // check if there's a prefix match
4783 stbtt_int32 matchlen = stbtt__CompareUTF8toUTF16_bigendian_prefix(name, nlen, fc+stringOffset+off,slen);
4784 if (matchlen >= 0) {
4785 // check for target_id+1 immediately following, with same encoding & language
4786 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) {
4787 slen = ttUSHORT(fc+loc+12+8);
4788 off = ttUSHORT(fc+loc+12+10);
4789 if (slen == 0) {
4790 if (matchlen == nlen)
4791 return 1;
4792 } else if (matchlen < nlen && name[matchlen] == ' ') {
4793 ++matchlen;
4794 if (stbtt_CompareUTF8toUTF16_bigendian_internal((char*) (name+matchlen), nlen-matchlen, (char*)(fc+stringOffset+off),slen))
4795 return 1;
4796 }
4797 } else {
4798 // if nothing immediately following
4799 if (matchlen == nlen)
4800 return 1;
4801 }
4802 }
4803 }
4804
4805 // @TODO handle other encodings
4806 }
4807 }
4808 return 0;
4809}
4810
4811static int stbtt__matches(stbtt_uint8 *fc, stbtt_uint32 offset, stbtt_uint8 *name, stbtt_int32 flags)
4812{
4813 stbtt_int32 nlen = (stbtt_int32) STBTT_strlen((char *) name);
4814 stbtt_uint32 nm,hd;
4815 if (!stbtt__isfont(fc+offset)) return 0;
4816
4817 // check italics/bold/underline flags in macStyle...
4818 if (flags) {
4819 hd = stbtt__find_table(fc, offset, "head");
4820 if ((ttUSHORT(fc+hd+44) & 7) != (flags & 7)) return 0;
4821 }
4822
4823 nm = stbtt__find_table(fc, offset, "name");
4824 if (!nm) return 0;
4825
4826 if (flags) {
4827 // if we checked the macStyle flags, then just check the family and ignore the subfamily
4828 if (stbtt__matchpair(fc, nm, name, nlen, 16, -1)) return 1;
4829 if (stbtt__matchpair(fc, nm, name, nlen, 1, -1)) return 1;
4830 if (stbtt__matchpair(fc, nm, name, nlen, 3, -1)) return 1;
4831 } else {
4832 if (stbtt__matchpair(fc, nm, name, nlen, 16, 17)) return 1;
4833 if (stbtt__matchpair(fc, nm, name, nlen, 1, 2)) return 1;
4834 if (stbtt__matchpair(fc, nm, name, nlen, 3, -1)) return 1;
4835 }
4836
4837 return 0;
4838}
4839
4840static int stbtt_FindMatchingFont_internal(unsigned char *font_collection, char *name_utf8, stbtt_int32 flags)
4841{
4842 stbtt_int32 i;
4843 for (i=0;;++i) {
4844 stbtt_int32 off = stbtt_GetFontOffsetForIndex(font_collection, i);
4845 if (off < 0) return off;
4846 if (stbtt__matches((stbtt_uint8 *) font_collection, off, (stbtt_uint8*) name_utf8, flags))
4847 return off;
4848 }
4849}
4850
4851#if defined(__GNUC__) || defined(__clang__)
4852#pragma GCC diagnostic push
4853#pragma GCC diagnostic ignored "-Wcast-qual"
4854#endif
4855
4856STBTT_DEF int stbtt_BakeFontBitmap(const unsigned char *data, int offset,
4857 float pixel_height, unsigned char *pixels, int pw, int ph,
4858 int first_char, int num_chars, stbtt_bakedchar *chardata)
4859{
4860 return stbtt_BakeFontBitmap_internal((unsigned char *) data, offset, pixel_height, pixels, pw, ph, first_char, num_chars, chardata);
4861}
4862
4863STBTT_DEF int stbtt_GetFontOffsetForIndex(const unsigned char *data, int index)
4864{
4865 return stbtt_GetFontOffsetForIndex_internal((unsigned char *) data, index);
4866}
4867
4868STBTT_DEF int stbtt_GetNumberOfFonts(const unsigned char *data)
4869{
4870 return stbtt_GetNumberOfFonts_internal((unsigned char *) data);
4871}
4872
4873STBTT_DEF int stbtt_InitFont(stbtt_fontinfo *info, const unsigned char *data, int offset)
4874{
4875 return stbtt_InitFont_internal(info, (unsigned char *) data, offset);
4876}
4877
4878STBTT_DEF int stbtt_FindMatchingFont(const unsigned char *fontdata, const char *name, int flags)
4879{
4880 return stbtt_FindMatchingFont_internal((unsigned char *) fontdata, (char *) name, flags);
4881}
4882
4883STBTT_DEF int stbtt_CompareUTF8toUTF16_bigendian(const char *s1, int len1, const char *s2, int len2)
4884{
4885 return stbtt_CompareUTF8toUTF16_bigendian_internal((char *) s1, len1, (char *) s2, len2);
4886}
4887
4888#if defined(__GNUC__) || defined(__clang__)
4889#pragma GCC diagnostic pop
4890#endif
4891
4892#endif // STB_TRUETYPE_IMPLEMENTATION
4893
4894
4895// FULL VERSION HISTORY
4896//
4897// 1.25 (2021-07-11) many fixes
4898// 1.24 (2020-02-05) fix warning
4899// 1.23 (2020-02-02) query SVG data for glyphs; query whole kerning table (but only kern not GPOS)
4900// 1.22 (2019-08-11) minimize missing-glyph duplication; fix kerning if both 'GPOS' and 'kern' are defined
4901// 1.21 (2019-02-25) fix warning
4902// 1.20 (2019-02-07) PackFontRange skips missing codepoints; GetScaleFontVMetrics()
4903// 1.19 (2018-02-11) OpenType GPOS kerning (horizontal only), STBTT_fmod
4904// 1.18 (2018-01-29) add missing function
4905// 1.17 (2017-07-23) make more arguments const; doc fix
4906// 1.16 (2017-07-12) SDF support
4907// 1.15 (2017-03-03) make more arguments const
4908// 1.14 (2017-01-16) num-fonts-in-TTC function
4909// 1.13 (2017-01-02) support OpenType fonts, certain Apple fonts
4910// 1.12 (2016-10-25) suppress warnings about casting away const with -Wcast-qual
4911// 1.11 (2016-04-02) fix unused-variable warning
4912// 1.10 (2016-04-02) allow user-defined fabs() replacement
4913// fix memory leak if fontsize=0.0
4914// fix warning from duplicate typedef
4915// 1.09 (2016-01-16) warning fix; avoid crash on outofmem; use alloc userdata for PackFontRanges
4916// 1.08 (2015-09-13) document stbtt_Rasterize(); fixes for vertical & horizontal edges
4917// 1.07 (2015-08-01) allow PackFontRanges to accept arrays of sparse codepoints;
4918// allow PackFontRanges to pack and render in separate phases;
4919// fix stbtt_GetFontOFfsetForIndex (never worked for non-0 input?);
4920// fixed an assert() bug in the new rasterizer
4921// replace assert() with STBTT_assert() in new rasterizer
4922// 1.06 (2015-07-14) performance improvements (~35% faster on x86 and x64 on test machine)
4923// also more precise AA rasterizer, except if shapes overlap
4924// remove need for STBTT_sort
4925// 1.05 (2015-04-15) fix misplaced definitions for STBTT_STATIC
4926// 1.04 (2015-04-15) typo in example
4927// 1.03 (2015-04-12) STBTT_STATIC, fix memory leak in new packing, various fixes
4928// 1.02 (2014-12-10) fix various warnings & compile issues w/ stb_rect_pack, C++
4929// 1.01 (2014-12-08) fix subpixel position when oversampling to exactly match
4930// non-oversampled; STBTT_POINT_SIZE for packed case only
4931// 1.00 (2014-12-06) add new PackBegin etc. API, w/ support for oversampling
4932// 0.99 (2014-09-18) fix multiple bugs with subpixel rendering (ryg)
4933// 0.9 (2014-08-07) support certain mac/iOS fonts without an MS platformID
4934// 0.8b (2014-07-07) fix a warning
4935// 0.8 (2014-05-25) fix a few more warnings
4936// 0.7 (2013-09-25) bugfix: subpixel glyph bug fixed in 0.5 had come back
4937// 0.6c (2012-07-24) improve documentation
4938// 0.6b (2012-07-20) fix a few more warnings
4939// 0.6 (2012-07-17) fix warnings; added stbtt_ScaleForMappingEmToPixels,
4940// stbtt_GetFontBoundingBox, stbtt_IsGlyphEmpty
4941// 0.5 (2011-12-09) bugfixes:
4942// subpixel glyph renderer computed wrong bounding box
4943// first vertex of shape can be off-curve (FreeSans)
4944// 0.4b (2011-12-03) fixed an error in the font baking example
4945// 0.4 (2011-12-01) kerning, subpixel rendering (tor)
4946// bugfixes for:
4947// codepoint-to-glyph conversion using table fmt=12
4948// codepoint-to-glyph conversion using table fmt=4
4949// stbtt_GetBakedQuad with non-square texture (Zer)
4950// updated Hello World! sample to use kerning and subpixel
4951// fixed some warnings
4952// 0.3 (2009-06-24) cmap fmt=12, compound shapes (MM)
4953// userdata, malloc-from-userdata, non-zero fill (stb)
4954// 0.2 (2009-03-11) Fix unsigned/signed char warnings
4955// 0.1 (2009-03-09) First public release
4956//
4957
4958/*
4959------------------------------------------------------------------------------
4960This software is available under 2 licenses -- choose whichever you prefer.
4961------------------------------------------------------------------------------
4962ALTERNATIVE A - MIT License
4963Copyright (c) 2017 Sean Barrett
4964Permission is hereby granted, free of charge, to any person obtaining a copy of
4965this software and associated documentation files (the "Software"), to deal in
4966the Software without restriction, including without limitation the rights to
4967use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
4968of the Software, and to permit persons to whom the Software is furnished to do
4969so, subject to the following conditions:
4970The above copyright notice and this permission notice shall be included in all
4971copies or substantial portions of the Software.
4972THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
4973IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
4974FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
4975AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
4976LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
4977OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
4978SOFTWARE.
4979------------------------------------------------------------------------------
4980ALTERNATIVE B - Public Domain (www.unlicense.org)
4981This is free and unencumbered software released into the public domain.
4982Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
4983software, either in source code form or as a compiled binary, for any purpose,
4984commercial or non-commercial, and by any means.
4985In jurisdictions that recognize copyright laws, the author or authors of this
4986software dedicate any and all copyright interest in the software to the public
4987domain. We make this dedication for the benefit of the public at large and to
4988the detriment of our heirs and successors. We intend this dedication to be an
4989overt act of relinquishment in perpetuity of all present and future rights to
4990this software under copyright law.
4991THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
4992IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
4993FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
4994AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
4995ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
4996WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
4997------------------------------------------------------------------------------
4998*/
4999// ---- end inlined stb_truetype ----
5000
5001namespace novasvg {
5002namespace render {
5003
5004static int text_iterator_length(const void* data, text_encoding_t encoding)
5005{
5006 int length = 0;
5007 switch(encoding) {
5010 const uint8_t* text = static_cast<const uint8_t*>(data);
5011 while(*text++)
5012 length++;
5013 break;
5015 const uint16_t* text = static_cast<const uint16_t*>(data);
5016 while(*text++)
5017 length++;
5018 break;
5020 const uint32_t* text = static_cast<const uint32_t*>(data);
5021 while(*text++)
5022 length++;
5023 break;
5024 } default:
5025 assert(false);
5026 }
5027
5028 return length;
5029}
5030
5031NOVASVG_INLINE void text_iterator_init(text_iterator_t* it, const void* text, int length, text_encoding_t encoding)
5032{
5033 if(length == -1)
5034 length = text_iterator_length(text, encoding);
5035 it->text = text;
5036 it->length = length;
5037 it->encoding = encoding;
5038 it->index = 0;
5039}
5040
5042{
5043 return it->index < it->length;
5044}
5045
5047{
5048 codepoint_t codepoint = 0;
5049 switch(it->encoding) {
5051 const uint8_t* text = static_cast<const uint8_t*>(it->text);
5052 codepoint = text[it->index++];
5053 break;
5055 static const uint8_t trailing[256] = {
5056 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5057 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5058 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5059 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5060 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5061 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5062 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5063 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5
5064 };
5065
5066 static const uint32_t offsets[6] = {
5067 0x00000000, 0x00003080, 0x000E2080, 0x03C82080, 0xFA082080, 0x82082080
5068 };
5069
5070 const uint8_t* text = static_cast<const uint8_t*>(it->text);
5071 uint8_t trailing_offset = trailing[text[it->index]];
5072 uint32_t offset_value = offsets[trailing_offset];
5073 while(trailing_offset > 0 && it->index < it->length - 1) {
5074 codepoint += text[it->index++];
5075 codepoint <<= 6;
5076 trailing_offset--;
5077 }
5078
5079 codepoint += text[it->index++];
5080 codepoint -= offset_value;
5081 break;
5083 const uint16_t* text = static_cast<const uint16_t*>(it->text);
5084 codepoint = text[it->index++];
5085 if(((codepoint) & 0xfffffc00) == 0xd800) {
5086 if(it->index < it->length && (((codepoint) & 0xfffffc00) == 0xdc00)) {
5087 uint16_t trail = text[it->index++];
5088 codepoint = (codepoint << 10) + trail - ((0xD800u << 10) - 0x10000u + 0xDC00u);
5089 }
5090 }
5091
5092 break;
5094 const uint32_t* text = static_cast<const uint32_t*>(it->text);
5095 codepoint = text[it->index++];
5096 break;
5097 } default:
5098 assert(false);
5099 }
5100
5101 return codepoint;
5102}
5103
5104#if defined(_WIN32)
5105
5106} // namespace render
5107} // namespace novasvg
5108#include <windows.h>
5109namespace novasvg {
5110namespace render {
5111
5112typedef CRITICAL_SECTION mutex_t;
5113
5114#define novasvg_mutex_init(mutex) InitializeCriticalSection(mutex)
5115#define novasvg_mutex_lock(mutex) EnterCriticalSection(mutex)
5116#define novasvg_mutex_unlock(mutex) LeaveCriticalSection(mutex)
5117#define novasvg_mutex_destroy(mutex) DeleteCriticalSection(mutex)
5118
5119#elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L && defined(HAVE_THREADS_H) && !defined(__STDC_NO_THREADS__)
5120
5121} // namespace render
5122} // namespace novasvg
5123#include <threads.h>
5124namespace novasvg {
5125namespace render {
5126
5127typedef mtx_t mutex_t;
5128
5129#define novasvg_mutex_init(mutex) mtx_init(mutex, mtx_plain | mtx_recursive)
5130#define novasvg_mutex_lock(mutex) mtx_lock(mutex)
5131#define novasvg_mutex_unlock(mutex) mtx_unlock(mutex)
5132#define novasvg_mutex_destroy(mutex) mtx_destroy(mutex)
5133
5134#else
5135
5136typedef int mutex_t;
5137
5138#define novasvg_mutex_init(mutex) ((void)(mutex))
5139#define novasvg_mutex_lock(mutex) ((void)(mutex))
5140#define novasvg_mutex_unlock(mutex) ((void)(mutex))
5141#define novasvg_mutex_destroy(mutex) ((void)(mutex))
5142
5143#endif
5144
5158
5159typedef struct {
5161 size_t size;
5162 size_t capacity;
5164
5170 int x1;
5171 int y1;
5172 int x2;
5173 int y2;
5178 void* closure;
5179 // Ligatures the font's GSUB `liga`/`clig` applies to f-sequences (see
5180 // font_face_apply_ligature()); built lazily, once, under `mutex`.
5183 struct {
5185 int len;
5188};
5189
5190static void glyph_cache_init(glyph_cache_t* cache)
5191{
5192 cache->glyphs = NULL;
5193 cache->size = 0;
5194 cache->capacity = 0;
5195}
5196
5197static void glyph_cache_finish(glyph_cache_t* cache, font_face_t* face)
5198{
5199 novasvg_mutex_lock(&face->mutex);
5200
5201 if(cache->glyphs) {
5202 for(size_t i = 0; i < cache->capacity; ++i) {
5203 glyph_t* glyph = cache->glyphs[i];
5204 while(glyph) {
5205 glyph_t* next = glyph->next;
5206 stbtt_FreeShape(&face->info, glyph->vertices);
5207 free(glyph);
5208 glyph = next;
5209 }
5210 }
5211
5212 free(cache->glyphs);
5213 cache->glyphs = NULL;
5214 cache->capacity = 0;
5215 cache->size = 0;
5216 }
5217
5218 novasvg_mutex_unlock(&face->mutex);
5219}
5220
5221#define GLYPH_CACHE_INIT_CAPACITY 128
5222
5223static glyph_t* glyph_cache_get(glyph_cache_t* cache, font_face_t* face, codepoint_t codepoint)
5224{
5225 novasvg_mutex_lock(&face->mutex);
5226
5227 if(cache->glyphs == NULL) {
5228 assert(cache->size == 0);
5229 cache->glyphs = static_cast<decltype(cache->glyphs)>(calloc(GLYPH_CACHE_INIT_CAPACITY, sizeof(glyph_t*)));
5230 cache->capacity = GLYPH_CACHE_INIT_CAPACITY;
5231 }
5232
5233 size_t index = codepoint & (cache->capacity - 1);
5234 glyph_t* glyph = cache->glyphs[index];
5235 while(glyph && glyph->codepoint != codepoint) {
5236 glyph = glyph->next;
5237 }
5238
5239 if(glyph == NULL) {
5240 glyph = static_cast<decltype(glyph)>(malloc(sizeof(glyph_t)));
5241 glyph->codepoint = codepoint;
5242 glyph->index = stbtt_FindGlyphIndex(&face->info, codepoint);
5243 glyph->nvertices = stbtt_GetGlyphShape(&face->info, glyph->index, &glyph->vertices);
5244 stbtt_GetGlyphHMetrics(&face->info, glyph->index, &glyph->advance_width, &glyph->left_side_bearing);
5245 if(!stbtt_GetGlyphBox(&face->info, glyph->index, &glyph->x1, &glyph->y1, &glyph->x2, &glyph->y2)) {
5246 glyph->x1 = glyph->y1 = glyph->x2 = glyph->y2 = 0;
5247 }
5248
5249 glyph->next = cache->glyphs[index];
5250 cache->glyphs[index] = glyph;
5251 cache->size += 1;
5252
5253 if(cache->size > (cache->capacity * 3 / 4)) {
5254 size_t newcapacity = cache->capacity << 1;
5255 glyph_t** newglyphs = static_cast<glyph_t**>(calloc(newcapacity, sizeof(glyph_t*)));
5256
5257 for(size_t i = 0; i < cache->capacity; ++i) {
5258 glyph_t* entry = cache->glyphs[i];
5259 while(entry) {
5260 glyph_t* next = entry->next;
5261 size_t newindex = entry->codepoint & (newcapacity - 1);
5262 entry->next = newglyphs[newindex];
5263 newglyphs[newindex] = entry;
5264 entry = next;
5265 }
5266 }
5267
5268 free(cache->glyphs);
5269 cache->glyphs = newglyphs;
5270 cache->capacity = newcapacity;
5271 }
5272 }
5273
5274 novasvg_mutex_unlock(&face->mutex);
5275 return glyph;
5276}
5277
5278NOVASVG_INLINE font_face_t* font_face_load_from_file(const char* filename, int ttcindex)
5279{
5280 FILE* fp = fopen(filename, "rb");
5281 if(fp == NULL) {
5282 return NULL;
5283 }
5284
5285 fseek(fp, 0, SEEK_END);
5286 long length = ftell(fp);
5287 if(length == -1L) {
5288 fclose(fp);
5289 return NULL;
5290 }
5291
5292 void* data = static_cast<void*>(malloc(length));
5293 if(data == NULL) {
5294 fclose(fp);
5295 return NULL;
5296 }
5297
5298 fseek(fp, 0, SEEK_SET);
5299 size_t nread = fread(data, 1, length, fp);
5300 fclose(fp);
5301
5302 if(nread != length) {
5303 free(data);
5304 return NULL;
5305 }
5306
5307 return font_face_load_from_data(data, length, ttcindex, free, data);
5308}
5309
5310NOVASVG_INLINE font_face_t* font_face_load_from_data(const void* data, unsigned int length, int ttcindex, destroy_func_t destroy_func, void* closure)
5311{
5312 stbtt_fontinfo info;
5313 int offset = stbtt_GetFontOffsetForIndex(static_cast<const unsigned char*>(data), ttcindex);
5314 if(offset == -1 || !stbtt_InitFont(&info, static_cast<const unsigned char*>(data), offset)) {
5315 if(destroy_func)
5316 destroy_func(closure);
5317 return NULL;
5318 }
5319
5320 font_face_t* face = static_cast<font_face_t*>(malloc(sizeof(font_face_t)));
5322 face->info = info;
5323 stbtt_GetFontVMetrics(&face->info, &face->ascent, &face->descent, &face->line_gap);
5324 stbtt_GetFontBoundingBox(&face->info, &face->x1, &face->y1, &face->x2, &face->y2);
5325 novasvg_mutex_init(&face->mutex);
5326 glyph_cache_init(&face->cache);
5327 face->destroy_func = destroy_func;
5328 face->closure = closure;
5329 face->ligatures_ready = 0;
5330 face->ligature_count = 0;
5331 return face;
5332}
5333
5339
5341{
5342 if(novasvg_destroy_reference(face)) {
5343 glyph_cache_finish(&face->cache, face);
5345 if(face->destroy_func)
5346 face->destroy_func(face->closure);
5347 free(face);
5348 }
5349}
5350
5355
5356static float font_face_get_scale(const font_face_t* face, float size)
5357{
5358 return stbtt_ScaleForMappingEmToPixels(&face->info, size);
5359}
5360
5361// unitsPerEm itself isn't exposed by stb_truetype as a direct getter (only
5362// buried in the private head-table offset math inside
5363// stbtt_ScaleForPixelHeight/stbtt_ScaleForMappingEmToPixels). Recovering it
5364// by evaluating the em-to-pixels scale at exactly 1 pixel --
5365// stbtt_ScaleForMappingEmToPixels(info, pixels) == pixels / unitsPerEm, so
5366// at pixels=1 that's 1/unitsPerEm -- avoids reaching into font_face's
5367// private stbtt_fontinfo/table-offset fields directly, and stays correct
5368// automatically if a future stb_truetype update changes how head.unitsPerEm
5369// is stored.
5371{
5372 return 1.0f / stbtt_ScaleForMappingEmToPixels(&face->info, 1.0f);
5373}
5374
5375// Enumerate every Unicode codepoint mapped by this font's cmap subtable --
5376// specifically the one subtable stb_truetype's own stbtt_InitFont already
5377// picked as authoritative (its platform/encoding priority scan runs once,
5378// far above, at font-load time), so this always agrees with whatever
5379// stbtt_FindGlyphIndex()/font_face_get_glyph_metrics() resolve for the same
5380// codepoint -- one selection, not two kept in sync by hand. Only formats 4
5381// (Windows BMP) and 12/13 (full-Unicode) are walked: the two formats
5382// virtually every modern TrueType/OpenType font uses, and the only ones
5383// stbtt_FindGlyphIndex() itself fully implements (see its format==2 branch
5384// above, which just asserts). Formats 0/2/6 are silently skipped --
5385// per-codepoint lookups (Font::measureText, FontFace::advanceWidthUnits)
5386// remain unaffected either way, only this *bulk* enumeration is narrower
5387// for those rarer subtable kinds.
5388NOVASVG_INLINE void font_face_enumerate_codepoints(const font_face_t* face, void (*callback)(uint32_t codepoint, void* closure), void* closure)
5389{
5390 const stbtt_fontinfo* info = &face->info;
5391 stbtt_uint8* data = info->data;
5392 stbtt_uint32 index_map = info->index_map;
5393 if(index_map == 0)
5394 return;
5395
5396 stbtt_uint16 format = ttUSHORT(data + index_map + 0);
5397 if(format == 4) {
5398 stbtt_uint16 segcount = ttUSHORT(data + index_map + 6) >> 1;
5399 stbtt_uint32 end_count_base = index_map + 14;
5400 stbtt_uint32 start_count_base = end_count_base + segcount * 2 + 2;
5401 for(stbtt_uint16 s = 0; s < segcount; ++s) {
5402 stbtt_uint16 end = ttUSHORT(data + end_count_base + s * 2);
5403 stbtt_uint16 start = ttUSHORT(data + start_count_base + s * 2);
5404 if(start == 0xFFFF && end == 0xFFFF)
5405 continue;
5406 for(uint32_t cp = start; cp <= end && cp != 0xFFFFu; ++cp) {
5407 if(stbtt_FindGlyphIndex(info, (int)cp) != 0)
5408 callback(cp, closure);
5409 }
5410 }
5411 } else if(format == 12 || format == 13) {
5412 stbtt_uint32 ngroups = ttULONG(data + index_map + 12);
5413 for(stbtt_uint32 g = 0; g < ngroups; ++g) {
5414 stbtt_uint32 start_char = ttULONG(data + index_map + 16 + g * 12);
5415 stbtt_uint32 end_char = ttULONG(data + index_map + 16 + g * 12 + 4);
5416 for(uint32_t cp = start_char; cp <= end_char; ++cp)
5417 callback(cp, closure);
5418 }
5419 }
5420}
5421
5422NOVASVG_INLINE void font_face_get_metrics(const font_face_t* face, float size, float* ascent, float* descent, float* line_gap, rect_t* extents)
5423{
5424 float scale = font_face_get_scale(face, size);
5425 if(ascent) *ascent = face->ascent * scale;
5426 if(descent) *descent = face->descent * scale;
5427 if(line_gap) *line_gap = face->line_gap * scale;
5428 if(extents) {
5429 extents->x = face->x1 * scale;
5430 extents->y = face->y2 * -scale;
5431 extents->w = (face->x2 - face->x1) * scale;
5432 extents->h = (face->y1 - face->y2) * -scale;
5433 }
5434}
5435
5436static glyph_t* font_face_get_glyph(font_face_t* face, codepoint_t codepoint)
5437{
5438 return glyph_cache_get(&face->cache, face, codepoint);
5439}
5440
5441NOVASVG_INLINE void font_face_get_glyph_metrics(font_face_t* face, float size, codepoint_t codepoint, float* advance_width, float* left_side_bearing, rect_t* extents)
5442{
5443 float scale = font_face_get_scale(face, size);
5444 glyph_t* glyph = font_face_get_glyph(face, codepoint);
5445 if(advance_width) *advance_width = glyph->advance_width * scale;
5446 if(left_side_bearing) *left_side_bearing = glyph->left_side_bearing * scale;
5447 if(extents) {
5448 extents->x = glyph->x1 * scale;
5449 extents->y = glyph->y2 * -scale;
5450 extents->w = (glyph->x2 - glyph->x1) * scale;
5451 extents->h = (glyph->y1 - glyph->y2) * -scale;
5452 }
5453}
5454
5455// Pairwise kerning adjustment between two consecutive codepoints, straight
5456// from the font's own `kern`/GPOS table via stb_truetype (present in the
5457// vendored copy, just never called from anywhere in novasvg's own code
5458// until now). Without this, both text measurement and actual glyph
5459// painting summed each glyph's bare advance_width only -- correct in
5460// total for fonts with no kerning pairs, but for ones that do (this
5461// benchmark's own feature-embedded-font*.svg test files, deliberately),
5462// the two loops previously advanced one codepoint at a time without ever
5463// asking the font "should these two sit closer/further apart", so a
5464// multi-character run's rendered position drifted further from every
5465// other engine's (all of which do apply it) the longer the string got.
5467{
5468 float scale = font_face_get_scale(face, size);
5469 return static_cast<float>(stbtt_GetCodepointKernAdvance(&face->info, static_cast<int>(ch1), static_cast<int>(ch2))) * scale;
5470}
5471
5472static void glyph_traverse_func(void* closure, path_command_t command, const point_t* points, int npoints)
5473{
5474 path_t* path = (path_t*)(closure);
5475 switch(command) {
5477 path_move_to(path, points[0].x, points[0].y);
5478 break;
5480 path_line_to(path, points[0].x, points[0].y);
5481 break;
5483 path_cubic_to(path, points[0].x, points[0].y, points[1].x, points[1].y, points[2].x, points[2].y);
5484 break;
5486 assert(false);
5487 }
5488}
5489
5490NOVASVG_INLINE float font_face_get_glyph_path(font_face_t* face, float size, float x, float y, codepoint_t codepoint, path_t* path)
5491{
5492 return font_face_traverse_glyph_path(face, size, x, y, codepoint, glyph_traverse_func, path);
5493}
5494
5495NOVASVG_INLINE float font_face_traverse_glyph_path(font_face_t* face, float size, float x, float y, codepoint_t codepoint, path_traverse_func_t traverse_func, void* closure)
5496{
5497 float scale = font_face_get_scale(face, size);
5500 matrix_scale(&matrix, scale, -scale);
5501
5502 point_t points[3];
5503 point_t current_point = {0, 0};
5504 glyph_t* glyph = font_face_get_glyph(face, codepoint);
5505 for(int i = 0; i < glyph->nvertices; i++) {
5506 switch(glyph->vertices[i].type) {
5507 case STBTT_vmove:
5508 points[0].x = glyph->vertices[i].x;
5509 points[0].y = glyph->vertices[i].y;
5510 current_point = points[0];
5511 matrix_map_points(&matrix, points, points, 1);
5512 traverse_func(closure, NOVASVG_PATH_COMMAND_MOVE_TO, points, 1);
5513 break;
5514 case STBTT_vline:
5515 points[0].x = glyph->vertices[i].x;
5516 points[0].y = glyph->vertices[i].y;
5517 current_point = points[0];
5518 matrix_map_points(&matrix, points, points, 1);
5519 traverse_func(closure, NOVASVG_PATH_COMMAND_LINE_TO, points, 1);
5520 break;
5521 case STBTT_vcurve:
5522 points[0].x = 2.f / 3.f * glyph->vertices[i].cx + 1.f / 3.f * current_point.x;
5523 points[0].y = 2.f / 3.f * glyph->vertices[i].cy + 1.f / 3.f * current_point.y;
5524 points[1].x = 2.f / 3.f * glyph->vertices[i].cx + 1.f / 3.f * glyph->vertices[i].x;
5525 points[1].y = 2.f / 3.f * glyph->vertices[i].cy + 1.f / 3.f * glyph->vertices[i].y;
5526 points[2].x = glyph->vertices[i].x;
5527 points[2].y = glyph->vertices[i].y;
5528 current_point = points[2];
5529 matrix_map_points(&matrix, points, points, 3);
5530 traverse_func(closure, NOVASVG_PATH_COMMAND_CUBIC_TO, points, 3);
5531 break;
5532 case STBTT_vcubic:
5533 points[0].x = glyph->vertices[i].cx;
5534 points[0].y = glyph->vertices[i].cy;
5535 points[1].x = glyph->vertices[i].cx1;
5536 points[1].y = glyph->vertices[i].cy1;
5537 points[2].x = glyph->vertices[i].x;
5538 points[2].y = glyph->vertices[i].y;
5539 current_point = points[2];
5540 matrix_map_points(&matrix, points, points, 3);
5541 traverse_func(closure, NOVASVG_PATH_COMMAND_CUBIC_TO, points, 3);
5542 break;
5543 default:
5544 assert(false);
5545 }
5546 }
5547
5548 return glyph->advance_width * scale;
5549}
5550
5551// Builds (once) the list of f-ligatures this font's own GSUB applies. A sequence is only
5552// taken when the glyph GSUB substitutes is the very glyph the Unicode presentation-form
5553// codepoint (U+FB00..FB04) maps to, so both measuring and painting can simply swap in that
5554// codepoint: a font without a `liga`/`clig` for the sequence (or whose ligature glyph has no
5555// such codepoint) is left exactly as it was.
5557{
5558 static const struct { codepoint_t seq[3]; int len; codepoint_t ligature; } candidates[5] = {
5559 {{'f', 'f', 'i'}, 3, 0xFB03}, {{'f', 'f', 'l'}, 3, 0xFB04}, {{'f', 'f', 0}, 2, 0xFB00},
5560 {{'f', 'i', 0}, 2, 0xFB01}, {{'f', 'l', 0}, 2, 0xFB02},
5561 };
5562 novasvg_mutex_lock(&face->mutex);
5563 if(!face->ligatures_ready) {
5564 face->ligature_count = 0;
5565 for(int c = 0; c < 5; ++c) {
5566 int glyphs[3] = {0, 0, 0};
5567 int ok = 1;
5568 for(int i = 0; i < candidates[c].len; ++i) {
5569 glyphs[i] = stbtt_FindGlyphIndex(&face->info, candidates[c].seq[i]);
5570 if(glyphs[i] == 0)
5571 ok = 0;
5572 }
5573 int presentation = stbtt_FindGlyphIndex(&face->info, candidates[c].ligature);
5574 if(!ok || presentation == 0)
5575 continue;
5576 if(stbtt__GetGsubLigature(&face->info, glyphs[0], glyphs + 1, candidates[c].len - 1) != presentation)
5577 continue;
5578 auto& e = face->ligatures[face->ligature_count++];
5579 for(int i = 0; i < 3; ++i)
5580 e.seq[i] = candidates[c].seq[i];
5581 e.len = candidates[c].len;
5582 e.ligature = candidates[c].ligature;
5583 }
5584 face->ligatures_ready = 1;
5585 }
5587}
5588
5589// `codepoint` was just read from `it`. If it starts an f-ligature the font applies (longest
5590// first: ffi, ffl, ff, fi, fl), consumes the rest of the sequence from `it` and returns the
5591// ligature's codepoint; otherwise returns `codepoint` unchanged.
5593{
5594 if(codepoint != 'f')
5595 return codepoint;
5596 if(!face->ligatures_ready)
5598 for(int k = 0; k < face->ligature_count; ++k) {
5599 const auto& e = face->ligatures[k];
5600 text_iterator_t peek = *it;
5601 int matched = 1;
5602 for(int i = 1; i < e.len; ++i) {
5603 if(!text_iterator_has_next(&peek) || text_iterator_next(&peek) != e.seq[i]) {
5604 matched = 0;
5605 break;
5606 }
5607 }
5608 if(matched) {
5609 *it = peek;
5610 return e.ligature;
5611 }
5612 }
5613 return codepoint;
5614}
5615
5616NOVASVG_INLINE float font_face_text_extents(font_face_t* face, float size, const void* text, int length, text_encoding_t encoding, rect_t* extents)
5617{
5618 text_iterator_t it;
5619 text_iterator_init(&it, text, length, encoding);
5620 rect_t* text_extents = NULL;
5621 float total_advance_width = 0.f;
5622 codepoint_t previous = 0;
5623 bool has_previous = false;
5624 while(text_iterator_has_next(&it)) {
5625 codepoint_t codepoint = text_iterator_next(&it);
5626 codepoint = font_face_apply_ligature(face, &it, codepoint);
5627 if(has_previous)
5628 total_advance_width += font_face_get_kern_advance(face, size, previous, codepoint);
5629 previous = codepoint;
5630 has_previous = true;
5631
5632 float advance_width;
5633 if(extents == NULL) {
5634 font_face_get_glyph_metrics(face, size, codepoint, &advance_width, NULL, NULL);
5635 total_advance_width += advance_width;
5636 continue;
5637 }
5638
5639 rect_t glyph_extents;
5640 font_face_get_glyph_metrics(face, size, codepoint, &advance_width, NULL, &glyph_extents);
5641
5642 glyph_extents.x += total_advance_width;
5643 total_advance_width += advance_width;
5644 if(text_extents == NULL) {
5645 text_extents = extents;
5646 *text_extents = glyph_extents;
5647 continue;
5648 }
5649
5650 float x1 = NOVASVG_MIN(text_extents->x, glyph_extents.x);
5651 float y1 = NOVASVG_MIN(text_extents->y, glyph_extents.y);
5652 float x2 = NOVASVG_MAX(text_extents->x + text_extents->w, glyph_extents.x + glyph_extents.w);
5653 float y2 = NOVASVG_MAX(text_extents->y + text_extents->h, glyph_extents.y + glyph_extents.h);
5654
5655 text_extents->x = x1;
5656 text_extents->y = y1;
5657 text_extents->w = x2 - x1;
5658 text_extents->h = y2 - y1;
5659 }
5660
5661 if(extents && !text_extents) {
5662 extents->x = 0;
5663 extents->y = 0;
5664 extents->w = 0;
5665 extents->h = 0;
5666 }
5667
5668 return total_advance_width;
5669}
5670
5680
5689
5691{
5692 font_face_cache_t* cache = static_cast<font_face_cache_t*>(malloc(sizeof(font_face_cache_t)));
5694 novasvg_mutex_init(&cache->mutex);
5695 cache->entries = NULL;
5696 cache->size = 0;
5697 cache->capacity = 0;
5698 cache->is_sorted = false;
5699 return cache;
5700}
5701
5707
5709{
5710 if(novasvg_destroy_reference(cache)) {
5711 font_face_cache_reset(cache);
5713 free(cache);
5714 }
5715}
5716
5721
5723{
5724 novasvg_mutex_lock(&cache->mutex);
5725
5726 for(int i = 0; i < cache->size; ++i) {
5727 font_face_entry_t* entry = cache->entries[i];
5728 do {
5729 font_face_entry_t* next = entry->next;
5730 font_face_destroy(entry->face);
5731 free(entry);
5732 entry = next;
5733 } while(entry);
5734 }
5735
5736 free(cache->entries);
5737 cache->entries = NULL;
5738 cache->size = 0;
5739 cache->capacity = 0;
5740 cache->is_sorted = false;
5741
5742 novasvg_mutex_unlock(&cache->mutex);
5743}
5744
5745static void font_face_cache_add_entry(font_face_cache_t* cache, font_face_entry_t* entry)
5746{
5747 novasvg_mutex_lock(&cache->mutex);
5748
5749 for(int i = 0; i < cache->size; ++i) {
5750 if(strcmp(entry->family, cache->entries[i]->family) == 0) {
5751 entry->next = cache->entries[i];
5752 cache->entries[i] = entry;
5753 goto unlock;
5754 }
5755 }
5756
5757 if(cache->size >= cache->capacity) {
5758 cache->capacity = cache->capacity == 0 ? 8 : cache->capacity << 2;
5759 cache->entries = static_cast<decltype(cache->entries)>(realloc(cache->entries, cache->capacity * sizeof(font_face_entry_t*)));
5760 }
5761
5762 entry->next = NULL;
5763 cache->entries[cache->size++] = entry;
5764 cache->is_sorted = false;
5765
5766unlock:
5767 novasvg_mutex_unlock(&cache->mutex);
5768}
5769
5770NOVASVG_INLINE void font_face_cache_add(font_face_cache_t* cache, const char* family, bool bold, bool italic, font_face_t* face)
5771{
5772 if(family == NULL) family = "";
5773 size_t family_length = strlen(family) + 1;
5774
5775 font_face_entry_t* entry = static_cast<font_face_entry_t*>(malloc(family_length + sizeof(font_face_entry_t)));
5776 entry->face = font_face_reference(face);
5777 entry->family = (char*)(entry + 1);
5778 memcpy(entry->family, family, family_length);
5779
5780 entry->filename = NULL;
5781 entry->ttcindex = 0;
5782 entry->bold = bold;
5783 entry->italic = italic;
5784
5785 font_face_cache_add_entry(cache, entry);
5786}
5787
5788NOVASVG_INLINE bool font_face_cache_add_file(font_face_cache_t* cache, const char* family, bool bold, bool italic, const char* filename, int ttcindex)
5789{
5790 font_face_t* face = font_face_load_from_file(filename, ttcindex);
5791 if(face == NULL)
5792 return false;
5793 font_face_cache_add(cache, family, bold, italic, face);
5794 font_face_destroy(face);
5795 return true;
5796}
5797
5798static font_face_entry_t* font_face_entry_select(font_face_entry_t* a, font_face_entry_t* b, bool bold, bool italic)
5799{
5800 int a_score = (bold == a->bold) + (italic == a->italic);
5801 int b_score = (bold == b->bold) + (italic == b->italic);
5802 return a_score > b_score ? a : b;
5803}
5804
5805static int font_face_entry_compare(const void* a, const void* b)
5806{
5807 const font_face_entry_t* a_entry = *(const font_face_entry_t**)a;
5808 const font_face_entry_t* b_entry = *(const font_face_entry_t**)b;
5809 return strcmp(a_entry->family, b_entry->family);
5810}
5811
5812NOVASVG_INLINE font_face_t* font_face_cache_get(font_face_cache_t* cache, const char* family, bool bold, bool italic)
5813{
5814 novasvg_mutex_lock(&cache->mutex);
5815
5816 if(!cache->is_sorted && cache->size > 0) {
5817 qsort(cache->entries, cache->size, sizeof(cache->entries[0]), font_face_entry_compare);
5818 cache->is_sorted = true;
5819 }
5820
5821 font_face_entry_t entry_key;
5822 entry_key.family = (char*)(family);
5823
5824 font_face_entry_t* entry_key_ptr = &entry_key;
5825 font_face_entry_t** entry_result = static_cast<font_face_entry_t**>(bsearch(
5826 &entry_key_ptr,
5827 cache->entries,
5828 cache->size,
5829 sizeof(cache->entries[0]),
5830 font_face_entry_compare
5831 ));
5832
5833 font_face_t* face = NULL;
5834 if(entry_result) {
5835 font_face_entry_t* selected = *entry_result;
5836 font_face_entry_t* entry = selected->next;
5837 while(entry) {
5838 selected = font_face_entry_select(entry, selected, bold, italic);
5839 entry = entry->next;
5840 }
5841
5842 if(selected->filename && selected->face == NULL)
5843 selected->face = font_face_load_from_file(selected->filename, selected->ttcindex);
5844 face = selected->face;
5845 }
5846
5847 novasvg_mutex_unlock(&cache->mutex);
5848 return face;
5849}
5850
5851#ifndef NOVASVG_DISABLE_FONT_FACE_CACHE_LOAD
5852
5853} // namespace render
5854} // namespace novasvg
5855#include <ctype.h>
5856namespace novasvg {
5857namespace render {
5858
5859#ifdef _WIN32
5860} // namespace render
5861} // namespace novasvg
5862#include <windows.h>
5863namespace novasvg {
5864namespace render {
5865#else
5866} // namespace render
5867} // namespace novasvg
5868#include <fcntl.h>
5869namespace novasvg {
5870namespace render {
5871} // namespace render
5872} // namespace novasvg
5873#include <unistd.h>
5874namespace novasvg {
5875namespace render {
5876} // namespace render
5877} // namespace novasvg
5878#include <dirent.h>
5879namespace novasvg {
5880namespace render {
5881
5882#ifdef __linux__
5883} // namespace render
5884} // namespace novasvg
5885#include <linux/limits.h>
5886namespace novasvg {
5887namespace render {
5888#else
5889} // namespace render
5890} // namespace novasvg
5891#include <limits.h>
5892namespace novasvg {
5893namespace render {
5894#endif
5895
5896} // namespace render
5897} // namespace novasvg
5898#include <sys/mman.h>
5899namespace novasvg {
5900namespace render {
5901} // namespace render
5902} // namespace novasvg
5903#include <sys/stat.h>
5904namespace novasvg {
5905namespace render {
5906#endif
5907
5908#ifdef _WIN32
5909
5910static void* mmap(const char* filename, long* length)
5911{
5912 HANDLE file = CreateFileA(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
5913 if(file == INVALID_HANDLE_VALUE)
5914 return NULL;
5915 DWORD size = GetFileSize(file, NULL);
5916 if(size == INVALID_FILE_SIZE) {
5917 CloseHandle(file);
5918 return NULL;
5919 }
5920
5921 HANDLE mapping = CreateFileMappingA(file, NULL, PAGE_READONLY, 0, 0, NULL);
5922 if(mapping == NULL) {
5923 CloseHandle(file);
5924 return NULL;
5925 }
5926
5927 void* data = MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0);
5928 CloseHandle(mapping);
5929 CloseHandle(file);
5930
5931 if(data == NULL)
5932 return NULL;
5933 *length = size;
5934 return data;
5935}
5936
5937static void unmap(void* data, long length)
5938{
5939 UnmapViewOfFile(data);
5940}
5941
5942#else
5943
5944static void* mmap(const char* filename, long* length)
5945{
5946 int fd = open(filename, O_RDONLY);
5947 if(fd < 0)
5948 return NULL;
5949 struct stat st;
5950 if(fstat(fd, &st) < 0) {
5951 close(fd);
5952 return NULL;
5953 }
5954
5955 if(st.st_size == 0) {
5956 close(fd);
5957 return NULL;
5958 }
5959
5960 void* data = ::mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
5961 close(fd);
5962
5963 if(data == MAP_FAILED)
5964 return NULL;
5965 *length = st.st_size;
5966 return data;
5967}
5968
5969static void unmap(void* data, long length)
5970{
5971 munmap(data, length);
5972}
5973
5974#endif // _WIN32
5975
5977{
5978 long length;
5979 stbtt_uint8* data = static_cast<stbtt_uint8*>(mmap(filename, &length));
5980 if(data == NULL) {
5981 return 0;
5982 }
5983
5984 int num_faces = 0;
5985
5986 int num_fonts = stbtt_GetNumberOfFonts(data);
5987 for(int index = 0; index < num_fonts; ++index) {
5988 int offset = stbtt_GetFontOffsetForIndex(data, index);
5989 if(offset == -1 || !stbtt__isfont(data + offset)) {
5990 continue;
5991 }
5992
5993 stbtt_uint32 nm = stbtt__find_table(data, offset, "name");
5994 stbtt_uint16 nm_count = ttUSHORT(data + nm + 2);
5995
5996 const stbtt_uint8* unicode_family_name = NULL;
5997 const stbtt_uint8* roman_family_name = NULL;
5998
5999 size_t family_length = 0;
6000 for(stbtt_int32 i = 0; i < nm_count; ++i) {
6001 stbtt_uint32 loc = nm + 6 + 12 * i;
6002 stbtt_uint16 nm_id = ttUSHORT(data + loc + 6);
6003 if(nm_id != 1) {
6004 continue;
6005 }
6006
6007 stbtt_uint16 platform = ttUSHORT(data + loc + 0);
6008 stbtt_uint16 encoding = ttUSHORT(data + loc + 2);
6009
6010 const stbtt_uint8* family_name = data + nm + ttUSHORT(data + nm + 4) + ttUSHORT(data + loc + 10);
6011 if(platform == 1 && encoding == 0) {
6012 family_length = ttUSHORT(data + loc + 8);
6013 roman_family_name = family_name;
6014 continue;
6015 }
6016
6017 if(platform == 0 || (platform == 3 && encoding == 1) || (platform == 3 && encoding == 10)) {
6018 family_length = ttUSHORT(data + loc + 8);
6019 unicode_family_name = family_name;
6020 break;
6021 }
6022 }
6023
6024 if(unicode_family_name == NULL && roman_family_name == NULL)
6025 continue;
6026 size_t filename_length = strlen(filename) + 1;
6027 size_t max_family_length = (unicode_family_name ? 3 * (family_length / 2) : family_length * 3) + 1;
6028
6029 font_face_entry_t* entry = static_cast<font_face_entry_t*>(malloc(max_family_length + filename_length + sizeof(font_face_entry_t)));
6030 entry->family = (char*)(entry + 1);
6031 entry->filename = entry->family + max_family_length;
6032 memcpy(entry->filename, filename, filename_length);
6033
6034 size_t family_index = 0;
6035 if(unicode_family_name) {
6036 const stbtt_uint8* family_name = unicode_family_name;
6037 while(family_length) {
6038 stbtt_uint16 ch = family_name[0] * 256 + family_name[1];
6039 if(ch < 0x80) {
6040 entry->family[family_index++] = ch;
6041 } else if(ch < 0x800) {
6042 entry->family[family_index++] = (0xc0 + (ch >> 6));
6043 entry->family[family_index++] = (0x80 + (ch & 0x3f));
6044 } else if(ch >= 0xd800 && ch < 0xdc00) {
6045 stbtt_uint16 ch2 = family_name[2] * 256 + family_name[3];
6046 stbtt_uint32 c = ((ch - 0xd800) << 10) + (ch2 - 0xdc00) + 0x10000;
6047
6048 entry->family[family_index++] = (0xf0 + (c >> 18));
6049 entry->family[family_index++] = (0x80 + ((c >> 12) & 0x3f));
6050 entry->family[family_index++] = (0x80 + ((c >> 6) & 0x3f));
6051 entry->family[family_index++] = (0x80 + ((c) & 0x3f));
6052
6053 family_name += 2;
6054 family_length -= 2;
6055 } else {
6056 entry->family[family_index++] = (0xe0 + (ch >> 12));
6057 entry->family[family_index++] = (0x80 + ((ch >> 6) & 0x3f));
6058 entry->family[family_index++] = (0x80 + ((ch) & 0x3f));
6059 }
6060
6061 family_name += 2;
6062 family_length -= 2;
6063 }
6064
6065 entry->family[family_index] = '\0';
6066 } else {
6067 static const stbtt_uint16 MAC_ROMAN_TABLE[256] = {
6068 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
6069 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
6070 0x0010, 0x2318, 0x21E7, 0x2325, 0x2303, 0x0015, 0x0016, 0x0017,
6071 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F,
6072 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
6073 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
6074 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
6075 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
6076 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
6077 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F,
6078 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
6079 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F,
6080 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
6081 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
6082 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
6083 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F,
6084 0x00C4, 0x00C5, 0x00C7, 0x00C9, 0x00D1, 0x00D6, 0x00DC, 0x00E1,
6085 0x00E0, 0x00E2, 0x00E4, 0x00E3, 0x00E5, 0x00E7, 0x00E9, 0x00E8,
6086 0x00EA, 0x00EB, 0x00ED, 0x00EC, 0x00EE, 0x00EF, 0x00F1, 0x00F3,
6087 0x00F2, 0x00F4, 0x00F6, 0x00F5, 0x00FA, 0x00F9, 0x00FB, 0x00FC,
6088 0x2020, 0x00B0, 0x00A2, 0x00A3, 0x00A7, 0x2022, 0x00B6, 0x00DF,
6089 0x00AE, 0x00A9, 0x2122, 0x00B4, 0x00A8, 0x2260, 0x00C6, 0x00D8,
6090 0x221E, 0x00B1, 0x2264, 0x2265, 0x00A5, 0x00B5, 0x2202, 0x2211,
6091 0x220F, 0x03C0, 0x222B, 0x00AA, 0x00BA, 0x03A9, 0x00E6, 0x00F8,
6092 0x00BF, 0x00A1, 0x00AC, 0x221A, 0x0192, 0x2248, 0x2206, 0x00AB,
6093 0x00BB, 0x2026, 0x00A0, 0x00C0, 0x00C3, 0x00D5, 0x0152, 0x0153,
6094 0x2013, 0x2014, 0x201C, 0x201D, 0x2018, 0x2019, 0x00F7, 0x25CA,
6095 0x00FF, 0x0178, 0x2044, 0x20AC, 0x2039, 0x203A, 0xFB01, 0xFB02,
6096 0x2021, 0x00B7, 0x201A, 0x201E, 0x2030, 0x00C2, 0x00CA, 0x00C1,
6097 0x00CB, 0x00C8, 0x00CD, 0x00CE, 0x00CF, 0x00CC, 0x00D3, 0x00D4,
6098 0xF8FF, 0x00D2, 0x00DA, 0x00DB, 0x00D9, 0x0131, 0x02C6, 0x02DC,
6099 0x00AF, 0x02D8, 0x02D9, 0x02DA, 0x00B8, 0x02DD, 0x02DB, 0x02C7,
6100 };
6101
6102 const stbtt_uint8* family_name = roman_family_name;
6103 while(family_length) {
6104 stbtt_uint16 ch = MAC_ROMAN_TABLE[family_name[0]];
6105 if(ch < 0x80) {
6106 entry->family[family_index++] = ch;
6107 } else if(ch < 0x800) {
6108 entry->family[family_index++] = (0xc0 + (ch >> 6));
6109 entry->family[family_index++] = (0x80 + (ch & 0x3f));
6110 } else {
6111 entry->family[family_index++] = (0xe0 + (ch >> 12));
6112 entry->family[family_index++] = (0x80 + ((ch >> 6) & 0x3f));
6113 entry->family[family_index++] = (0x80 + ((ch) & 0x3f));
6114 }
6115
6116 family_name += 1;
6117 family_length -= 1;
6118 }
6119
6120 entry->family[family_index] = '\0';
6121 }
6122
6123 entry->face = NULL;
6124 entry->bold = false;
6125 entry->italic = false;
6126 entry->ttcindex = index;
6127
6128 stbtt_uint32 hd = stbtt__find_table(data, offset, "head");
6129 stbtt_uint16 style = ttUSHORT(data + hd + 44);
6130 if(style & 0x1)
6131 entry->bold = true;
6132 if(style & 0x2) {
6133 entry->italic = true;
6134 }
6135
6136 font_face_cache_add_entry(cache, entry);
6137 num_faces++;
6138 }
6139
6140 unmap(data, length);
6141 return num_faces;
6142}
6143
6144static bool font_face_supports_file(const char* filename)
6145{
6146 const char* extension = strrchr(filename, '.');
6147 if(extension) {
6148 char ext[5];
6149 size_t length = strlen(extension);
6150 if(length == 4) {
6151 for(size_t i = 0; i < length; ++i)
6152 ext[i] = tolower(extension[i]);
6153 ext[length] = '\0';
6154 return strcmp(ext, ".ttf") == 0
6155 || strcmp(ext, ".otf") == 0
6156 || strcmp(ext, ".ttc") == 0
6157 || strcmp(ext, ".otc") == 0;
6158 }
6159 }
6160
6161 return false;
6162}
6163
6164#ifdef _WIN32
6165
6166NOVASVG_INLINE int font_face_cache_load_dir(font_face_cache_t* cache, const char* dirname)
6167{
6168 char search_path[MAX_PATH];
6169 snprintf(search_path, sizeof(search_path), "%s\\*", dirname);
6170
6171 WIN32_FIND_DATAA find_data;
6172 HANDLE handle = FindFirstFileA(search_path, &find_data);
6173 if(handle == INVALID_HANDLE_VALUE) {
6174 return 0;
6175 }
6176
6177 int num_faces = 0;
6178
6179 do {
6180 const char* name = find_data.cFileName;
6181 if(strcmp(name, ".") == 0 || strcmp(name, "..") == 0)
6182 continue;
6183 char path[MAX_PATH * 2];
6184 snprintf(path, sizeof(path), "%s\\%s", dirname, name);
6185
6186 if(find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
6187 num_faces += font_face_cache_load_dir(cache, path);
6188 } else if(font_face_supports_file(path)) {
6189 num_faces += font_face_cache_load_file(cache, path);
6190 }
6191 } while(FindNextFileA(handle, &find_data));
6192
6193 FindClose(handle);
6194 return num_faces;
6195}
6196
6197#else
6198
6200{
6201 DIR* dir = opendir(dirname);
6202 if(dir == NULL) {
6203 return 0;
6204 }
6205
6206 int num_faces = 0;
6207
6208 struct dirent* entry;
6209 while((entry = readdir(dir)) != NULL) {
6210 if(strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
6211 continue;
6212 char path[PATH_MAX];
6213 snprintf(path, sizeof(path), "%s/%s", dirname, entry->d_name);
6214
6215 struct stat st;
6216 if(stat(path, &st) == -1)
6217 continue;
6218 if(S_ISDIR(st.st_mode)) {
6219 num_faces += font_face_cache_load_dir(cache, path);
6220 } else if(S_ISREG(st.st_mode) && font_face_supports_file(path)) {
6221 num_faces += font_face_cache_load_file(cache, path);
6222 }
6223 }
6224
6225 closedir(dir);
6226 return num_faces;
6227}
6228
6229#endif // _WIN32
6230
6232{
6233 int num_faces = 0;
6234#if defined(_WIN32)
6235 num_faces += font_face_cache_load_dir(cache, "C:\\Windows\\Fonts");
6236#elif defined(__APPLE__)
6237 num_faces += font_face_cache_load_dir(cache, "/Library/Fonts");
6238 num_faces += font_face_cache_load_dir(cache, "/System/Library/Fonts");
6239#elif defined(__linux__)
6240 num_faces += font_face_cache_load_dir(cache, "/usr/share/fonts");
6241 num_faces += font_face_cache_load_dir(cache, "/usr/local/share/fonts");
6242#endif
6243 return num_faces;
6244}
6245
6246#else
6247
6248NOVASVG_INLINE int font_face_cache_load_file(font_face_cache_t* cache, const char* filename)
6249{
6250 return -1;
6251}
6252
6253NOVASVG_INLINE int font_face_cache_load_dir(font_face_cache_t* cache, const char* dirname)
6254{
6255 return -1;
6256}
6257
6259{
6260 return -1;
6261}
6262
6263#endif // NOVASVG_DISABLE_FONT_FACE_CACHE_LOAD
6264
6265
6266} // namespace render
6267} // namespace novasvg
#define NOVASVG_MAX(a, b)
Definition color.h:11
#define NOVASVG_MIN(a, b)
Definition color.h:14
NOVASVG_INLINE codepoint_t font_face_apply_ligature(font_face_t *face, text_iterator_t *it, codepoint_t codepoint)
Definition font.h:5592
NOVASVG_INLINE void font_face_cache_add(font_face_cache_t *cache, const char *family, bool bold, bool italic, font_face_t *face)
Add a font face to the cache with the specified family and style.
Definition font.h:5770
@ NOVASVG_PATH_COMMAND_CUBIC_TO
Draws a cubic Bézier curve to a new point.
Definition render.h:313
@ NOVASVG_PATH_COMMAND_CLOSE
Closes the current path by drawing a line to the starting point.
Definition render.h:314
@ NOVASVG_PATH_COMMAND_LINE_TO
Draws a straight line to a new point.
Definition render.h:312
@ NOVASVG_PATH_COMMAND_MOVE_TO
Moves the current point to a new position.
Definition render.h:311
NOVASVG_INLINE void font_face_cache_destroy(font_face_cache_t *cache)
Decrement the reference count of a font‐face cache and destroy it when it reaches zero.
Definition font.h:5708
NOVASVG_INLINE float font_face_text_extents(font_face_t *face, float size, const void *text, int length, text_encoding_t encoding, rect_t *extents)
Computes the bounding box of a text string and its advance width.
Definition font.h:5616
NOVASVG_INLINE float font_face_get_units_per_em(const font_face_t *face)
Definition font.h:5370
NOVASVG_INLINE int font_face_cache_load_dir(font_face_cache_t *cache, const char *dirname)
Load all font faces from files in a directory recursively and add them to the cache.
Definition font.h:6199
NOVASVG_INLINE void font_face_destroy(font_face_t *face)
Decrements the reference count and potentially destroys the font face.
Definition font.h:5340
NOVASVG_INLINE void path_move_to(path_t *path, float x, float y)
Moves the current point to a new position.
Definition path.h:93
enum novasvg::render::path_command path_command_t
Enumeration defining path commands.
NOVASVG_INLINE void matrix_map_points(const matrix_t *matrix, const point_t *src, point_t *dst, int count)
Transforms an array of src points using matrix and stores the results in dst.
Definition matrix.h:111
NOVASVG_INLINE float font_face_traverse_glyph_path(font_face_t *face, float size, float x, float y, codepoint_t codepoint, path_traverse_func_t traverse_func, void *closure)
Traverses the path of a glyph and calls a callback for each path element.
Definition font.h:5495
NOVASVG_INLINE void path_cubic_to(path_t *path, float x1, float y1, float x2, float y2, float x3, float y3)
Adds a cubic Bézier curve to the path.
Definition path.h:120
struct novasvg::render::glyph glyph_t
unsigned int codepoint_t
Represents a Unicode code point.
Definition render.h:768
NOVASVG_INLINE int font_face_cache_reference_count(const font_face_cache_t *cache)
Retrieve the current reference count of a font‐face cache.
Definition font.h:5717
NOVASVG_INLINE int font_face_get_reference_count(const font_face_t *face)
Retrieves the current reference count of a font face.
Definition font.h:5351
NOVASVG_INLINE font_face_cache_t * font_face_cache_reference(font_face_cache_t *cache)
Increments the reference count of a font‐face cache.
Definition font.h:5702
NOVASVG_INLINE font_face_t * font_face_load_from_data(const void *data, unsigned int length, int ttcindex, destroy_func_t destroy_func, void *closure)
Loads a font face from memory.
Definition font.h:5310
void(* path_traverse_func_t)(void *closure, path_command_t command, const point_t *points, int npoints)
Callback function type for traversing a path.
Definition render.h:658
NOVASVG_INLINE font_face_t * font_face_load_from_file(const char *filename, int ttcindex)
Loads a font face from a file.
Definition font.h:5278
NOVASVG_INLINE void font_face_get_glyph_metrics(font_face_t *face, float size, codepoint_t codepoint, float *advance_width, float *left_side_bearing, rect_t *extents)
Retrieves metrics for a specified glyph at a given size.
Definition font.h:5441
NOVASVG_INLINE font_face_t * font_face_cache_get(font_face_cache_t *cache, const char *family, bool bold, bool italic)
Retrieve a font face from the cache by family and style.
Definition font.h:5812
void(* destroy_func_t)(void *closure)
A function pointer type for a cleanup callback.
Definition render.h:92
NOVASVG_INLINE float font_face_get_kern_advance(font_face_t *face, float size, codepoint_t ch1, codepoint_t ch2)
Definition font.h:5466
NOVASVG_INLINE void font_face_enumerate_codepoints(const font_face_t *face, void(*callback)(uint32_t codepoint, void *closure), void *closure)
Definition font.h:5388
enum novasvg::render::text_encoding text_encoding_t
Text encodings used for converting text data to code points.
NOVASVG_INLINE void font_face_cache_reset(font_face_cache_t *cache)
Remove all entries from a font‐face cache.
Definition font.h:5722
NOVASVG_INLINE codepoint_t text_iterator_next(text_iterator_t *it)
Retrieves the next code point and advances the iterator.
Definition font.h:5046
@ NOVASVG_TEXT_ENCODING_UTF16
UTF-16 encoding.
Definition render.h:751
@ NOVASVG_TEXT_ENCODING_UTF32
UTF-32 encoding.
Definition render.h:752
@ NOVASVG_TEXT_ENCODING_UTF8
UTF-8 encoding.
Definition render.h:750
@ NOVASVG_TEXT_ENCODING_LATIN1
Latin-1 encoding.
Definition render.h:749
struct novasvg::render::font_face_entry font_face_entry_t
NOVASVG_INLINE void font_face_init_ligatures(font_face_t *face)
Definition font.h:5556
NOVASVG_INLINE void font_face_get_metrics(const font_face_t *face, float size, float *ascent, float *descent, float *line_gap, rect_t *extents)
Retrieves metrics for a font face at a specified size.
Definition font.h:5422
struct font_face_cache font_face_cache_t
Represents a cache of loaded font faces.
Definition render.h:912
NOVASVG_INLINE bool text_iterator_has_next(const text_iterator_t *it)
Checks if there are more code points to iterate.
Definition font.h:5041
NOVASVG_INLINE int font_face_cache_load_file(font_face_cache_t *cache, const char *filename)
Load all font faces from a file and add them to the cache.
Definition font.h:5976
NOVASVG_INLINE void matrix_scale(matrix_t *matrix, float sx, float sy)
Scales the matrix by factors sx and sy
Definition matrix.h:49
NOVASVG_INLINE bool font_face_cache_add_file(font_face_cache_t *cache, const char *family, bool bold, bool italic, const char *filename, int ttcindex)
Load a font face from a file and add it to the cache with the specified family and style.
Definition font.h:5788
NOVASVG_INLINE void path_line_to(path_t *path, float x, float y)
Adds a straight line segment to the path.
Definition path.h:101
struct font_face font_face_t
Represents a font face.
Definition render.h:799
NOVASVG_INLINE float font_face_get_glyph_path(font_face_t *face, float size, float x, float y, codepoint_t codepoint, path_t *path)
Retrieves the path of a glyph and its advance width.
Definition font.h:5490
NOVASVG_INLINE int font_face_cache_load_sys(font_face_cache_t *cache)
Load all available system font faces and add them to the cache.
Definition font.h:6231
NOVASVG_INLINE void text_iterator_init(text_iterator_t *it, const void *text, int length, text_encoding_t encoding)
Initializes a text iterator.
Definition font.h:5031
NOVASVG_INLINE void matrix_init_translate(matrix_t *matrix, float tx, float ty)
Initializes a 2D transformation matrix for translation.
Definition matrix.h:20
NOVASVG_INLINE font_face_t * font_face_reference(font_face_t *face)
Increments the reference count of a font face.
Definition font.h:5334
NOVASVG_INLINE font_face_cache_t * font_face_cache_create(void)
Create a new, empty font‐face cache.
Definition font.h:5690
Main namespace for the NovaSVG library.
Definition bitmap.h:23
#define NOVASVG_INLINE
Definition novasvg.h:42
#define novasvg_get_reference_count(ob)
Definition private.h:48
#define novasvg_destroy_reference(ob)
Definition private.h:47
#define novasvg_init_reference(ob)
Definition private.h:45
#define novasvg_increment_reference(ob)
Definition private.h:46
@ STBTT_MAC_EID_KOREAN
Definition font.h:938
@ STBTT_MAC_EID_ROMAN
Definition font.h:935
@ STBTT_MAC_EID_HEBREW
Definition font.h:936
@ STBTT_MAC_EID_CHINESE_TRAD
Definition font.h:937
@ STBTT_MAC_EID_JAPANESE
Definition font.h:936
@ STBTT_MAC_EID_RUSSIAN
Definition font.h:938
@ STBTT_MAC_EID_GREEK
Definition font.h:937
@ STBTT_MAC_EID_ARABIC
Definition font.h:935
#define stbtt__buf_get16(b)
Definition font.h:1046
signed short stbtt_int16
Definition font.h:299
#define STBTT_strlen(x)
Definition font.h:350
#define STBTT_assert(x)
Definition font.h:345
unsigned int stbtt_uint32
Definition font.h:300
#define ttCHAR(p)
Definition font.h:1151
#define STBTT_pow(x, y)
Definition font.h:317
#define STBTT_iceil(x)
Definition font.h:311
#define STBTT_fabs(x)
Definition font.h:333
#define novasvg_mutex_init(mutex)
Definition font.h:5138
#define STBTT__NOTUSED(v)
Definition font.h:993
#define STBTT_free(x, u)
Definition font.h:340
#define STBTT_ifloor(x)
Definition font.h:310
#define novasvg_mutex_lock(mutex)
Definition font.h:5139
#define STBTT_memset
Definition font.h:356
#define STBTT_memcpy
Definition font.h:355
int stbrp_coord
Definition font.h:3808
#define STBTT_MAX_OVERSAMPLE
Definition font.h:977
#define stbtt_tag4(p, c0, c1, c2, c3)
Definition font.h:1159
@ STBTT_UNICODE_EID_ISO_10646
Definition font.h:922
@ STBTT_UNICODE_EID_UNICODE_2_0_BMP
Definition font.h:923
@ STBTT_UNICODE_EID_UNICODE_2_0_FULL
Definition font.h:924
@ STBTT_UNICODE_EID_UNICODE_1_1
Definition font.h:921
@ STBTT_UNICODE_EID_UNICODE_1_0
Definition font.h:920
int stbtt__test_oversample_pow2[(8 &(8 -1))==0 ? 1 :-1]
Definition font.h:984
char stbtt__check_size16[sizeof(stbtt_int16)==2 ? 1 :-1]
Definition font.h:305
unsigned char stbtt_uint8
Definition font.h:296
#define STBTT__CSERR(s)
#define GLYPH_CACHE_INIT_CAPACITY
Definition font.h:5221
#define novasvg_mutex_destroy(mutex)
Definition font.h:5141
@ STBTT_MS_EID_UNICODE_FULL
Definition font.h:931
@ STBTT_MS_EID_SYMBOL
Definition font.h:928
@ STBTT_MS_EID_SHIFTJIS
Definition font.h:930
@ STBTT_MS_EID_UNICODE_BMP
Definition font.h:929
#define STBTT_acos(x)
Definition font.h:328
#define STBTT__COMPARE(a, b)
Definition font.h:3318
#define STBTT_max(a, b)
Definition font.h:4317
#define STBTT_malloc(x, u)
Definition font.h:339
#define stbtt_tag(p, str)
Definition font.h:1160
#define stbtt__buf_get32(b)
Definition font.h:1047
#define novasvg_mutex_unlock(mutex)
Definition font.h:5140
@ STBTT_MAC_LANG_SWEDISH
Definition font.h:956
@ STBTT_MAC_LANG_KOREAN
Definition font.h:953
@ STBTT_MAC_LANG_ITALIAN
Definition font.h:958
@ STBTT_MAC_LANG_SPANISH
Definition font.h:955
@ STBTT_MAC_LANG_CHINESE_SIMPLIFIED
Definition font.h:957
@ STBTT_MAC_LANG_ENGLISH
Definition font.h:952
@ STBTT_MAC_LANG_JAPANESE
Definition font.h:952
@ STBTT_MAC_LANG_FRENCH
Definition font.h:955
@ STBTT_MAC_LANG_HEBREW
Definition font.h:957
@ STBTT_MAC_LANG_GERMAN
Definition font.h:956
@ STBTT_MAC_LANG_ARABIC
Definition font.h:953
@ STBTT_MAC_LANG_DUTCH
Definition font.h:954
@ STBTT_MAC_LANG_CHINESE_TRAD
Definition font.h:958
@ STBTT_MAC_LANG_RUSSIAN
Definition font.h:954
#define STBTT_DEF
Definition font.h:371
#define stbtt_vertex_type
Definition font.h:702
#define STBTT_fmod(x, y)
Definition font.h:322
#define STBTT_cos(x)
Definition font.h:327
@ STBTT_vmove
Definition font.h:693
@ STBTT_vcubic
Definition font.h:696
@ STBTT_vcurve
Definition font.h:695
@ STBTT_vline
Definition font.h:694
@ STBTT_MS_LANG_DUTCH
Definition font.h:945
@ STBTT_MS_LANG_JAPANESE
Definition font.h:944
@ STBTT_MS_LANG_SWEDISH
Definition font.h:948
@ STBTT_MS_LANG_FRENCH
Definition font.h:946
@ STBTT_MS_LANG_SPANISH
Definition font.h:947
@ STBTT_MS_LANG_CHINESE
Definition font.h:944
@ STBTT_MS_LANG_ENGLISH
Definition font.h:943
@ STBTT_MS_LANG_RUSSIAN
Definition font.h:946
@ STBTT_MS_LANG_ITALIAN
Definition font.h:943
@ STBTT_MS_LANG_KOREAN
Definition font.h:945
@ STBTT_MS_LANG_GERMAN
Definition font.h:947
@ STBTT_MS_LANG_HEBREW
Definition font.h:948
unsigned short stbtt_uint16
Definition font.h:298
#define STBTT__CSCTX_INIT(bounds)
Definition font.h:1778
#define STBTT_sqrt(x)
Definition font.h:316
#define STBTT__OVER_MASK
Definition font.h:3931
#define STBTT_min(a, b)
Definition font.h:4316
signed char stbtt_int8
Definition font.h:297
@ STBTT_PLATFORM_ID_UNICODE
Definition font.h:913
@ STBTT_PLATFORM_ID_MICROSOFT
Definition font.h:916
@ STBTT_PLATFORM_ID_ISO
Definition font.h:915
@ STBTT_PLATFORM_ID_MAC
Definition font.h:914
#define ttBYTE(p)
Definition font.h:1150
signed int stbtt_int32
Definition font.h:301
char stbtt__check_size32[sizeof(stbtt_int32)==4 ? 1 :-1]
Definition font.h:304
font_face_entry_t ** entries
Definition font.h:5684
Definition font.h:5671
bool italic
Definition font.h:5677
struct font_face_entry * next
Definition font.h:5678
char * filename
Definition font.h:5674
char * family
Definition font.h:5673
int ttcindex
Definition font.h:5675
font_face_t * face
Definition font.h:5672
bool bold
Definition font.h:5676
glyph_cache_t cache
Definition font.h:5176
codepoint_t seq[3]
Definition font.h:5184
stbtt_fontinfo info
Definition font.h:5174
struct novasvg::render::font_face::@10 ligatures[5]
destroy_func_t destroy_func
Definition font.h:5177
ref_count_t ref_count
Definition font.h:5166
struct glyph * next
Definition font.h:5156
stbtt_vertex * vertices
Definition font.h:5147
codepoint_t codepoint
Definition font.h:5146
A structure representing a 2D transformation matrix.
Definition render.h:138
A structure representing a point in 2D space.
Definition render.h:114
float y
The y-coordinate of the point.
Definition render.h:116
float x
The x-coordinate of the point.
Definition render.h:115
A structure representing a rectangle in 2D space.
Definition render.h:125
float x
The x-coordinate of the top-left corner of the rectangle.
Definition render.h:126
float w
The width of the rectangle.
Definition render.h:128
float h
The height of the rectangle.
Definition render.h:129
float y
The y-coordinate of the top-left corner of the rectangle.
Definition render.h:127
Iterator for traversing code points in text data.
Definition render.h:758
text_encoding_t encoding
Encoding format of the text data.
Definition render.h:761
int length
Length of the text data.
Definition render.h:760
const void * text
Pointer to the text data.
Definition render.h:759
int index
Current position in the text data.
Definition render.h:762
int bottom_y
Definition font.h:3824
unsigned char x
Definition font.h:3829
stbrp_coord x
Definition font.h:3834
int h
Definition font.h:3835
int was_packed
Definition font.h:3835
int id
Definition font.h:3835
int w
Definition font.h:3835
stbrp_coord y
Definition font.h:3834
struct stbtt__active_edge * next
Definition font.h:2736
int stride
Definition font.h:794
unsigned char * pixels
Definition font.h:795
int size
Definition font.h:385
unsigned char * data
Definition font.h:383
int cursor
Definition font.h:384
int started
Definition font.h:1769
stbtt_int32 min_y
Definition font.h:1772
float first_x
Definition font.h:1770
stbtt_int32 min_x
Definition font.h:1772
int bounds
Definition font.h:1768
stbtt_int32 max_y
Definition font.h:1772
float x
Definition font.h:1771
float first_y
Definition font.h:1770
stbtt_vertex * pvertices
Definition font.h:1774
int num_vertices
Definition font.h:1775
stbtt_int32 max_x
Definition font.h:1772
float y
Definition font.h:1771
float y1
Definition font.h:2729
float x1
Definition font.h:2729
float y0
Definition font.h:2729
int invert
Definition font.h:2730
float x0
Definition font.h:2729
struct stbtt__hheap_chunk * next
Definition font.h:2681
struct stbtt__hheap_chunk * head
Definition font.h:2686
int num_remaining_in_head_chunk
Definition font.h:2688
void * first_free
Definition font.h:2687
float x
Definition font.h:3408
float y
Definition font.h:3408
float xoff
Definition font.h:398
unsigned short x1
Definition font.h:397
unsigned short x0
Definition font.h:397
float yoff
Definition font.h:398
unsigned short y1
Definition font.h:397
float xadvance
Definition font.h:398
unsigned short y0
Definition font.h:397
int index_map
Definition font.h:590
int fontstart
Definition font.h:585
stbtt__buf fdselect
Definition font.h:598
int indexToLocFormat
Definition font.h:591
stbtt__buf cff
Definition font.h:593
int numGlyphs
Definition font.h:587
stbtt__buf fontdicts
Definition font.h:597
void * userdata
Definition font.h:583
stbtt__buf charstrings
Definition font.h:594
stbtt__buf subrs
Definition font.h:596
unsigned char * data
Definition font.h:584
stbtt__buf gsubrs
Definition font.h:595
void * pack_info
Definition font.h:548
void * user_allocator_context
Definition font.h:547
unsigned int v_oversample
Definition font.h:554
unsigned char * pixels
Definition font.h:555
int stride_in_bytes
Definition font.h:551
unsigned int h_oversample
Definition font.h:554
int * array_of_unicode_codepoints
Definition font.h:491
float font_size
Definition font.h:489
int first_unicode_codepoint_in_range
Definition font.h:490
unsigned char v_oversample
Definition font.h:494
unsigned char h_oversample
Definition font.h:494
stbtt_packedchar * chardata_for_range
Definition font.h:493
unsigned short x0
Definition font.h:445
float xadvance
Definition font.h:446
float yoff2
Definition font.h:447
float xoff2
Definition font.h:447
unsigned short y0
Definition font.h:445
unsigned short y1
Definition font.h:445
unsigned short x1
Definition font.h:445
short cx
Definition font.h:705
short x
Definition font.h:705
short cy1
Definition font.h:705
short y
Definition font.h:705
unsigned char padding
Definition font.h:706
short cx1
Definition font.h:705
unsigned char type
Definition font.h:706
short cy
Definition font.h:705
unsigned char style
std::string text
UTF-8; ' ' marks a forced line break ( ,.