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