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

source code of imgui/imstb_truetype.h