Blame src-nuklear/stb_truetype.h

Ivan Mahonin b53a5c
// stb_truetype.h - v1.26 - public domain
Ivan Mahonin b53a5c
// authored from 2009-2021 by Sean Barrett / RAD Game Tools
Ivan Mahonin b53a5c
//
Ivan Mahonin b53a5c
// =======================================================================
Ivan Mahonin b53a5c
//
Ivan Mahonin b53a5c
//    NO SECURITY GUARANTEE -- DO NOT USE THIS ON UNTRUSTED FONT FILES
Ivan Mahonin b53a5c
//
Ivan Mahonin b53a5c
// This library does no range checking of the offsets found in the file,
Ivan Mahonin b53a5c
// meaning an attacker can use it to read arbitrary memory.
Ivan Mahonin b53a5c
//
Ivan Mahonin b53a5c
// =======================================================================
Ivan Mahonin b53a5c
//
Ivan Mahonin b53a5c
//   This library processes TrueType files:
Ivan Mahonin b53a5c
//        parse files
Ivan Mahonin b53a5c
//        extract glyph metrics
Ivan Mahonin b53a5c
//        extract glyph shapes
Ivan Mahonin b53a5c
//        render glyphs to one-channel bitmaps with antialiasing (box filter)
Ivan Mahonin b53a5c
//        render glyphs to one-channel SDF bitmaps (signed-distance field/function)
Ivan Mahonin b53a5c
//
Ivan Mahonin b53a5c
//   Todo:
Ivan Mahonin b53a5c
//        non-MS cmaps
Ivan Mahonin b53a5c
//        crashproof on bad data
Ivan Mahonin b53a5c
//        hinting? (no longer patented)
Ivan Mahonin b53a5c
//        cleartype-style AA?
Ivan Mahonin b53a5c
//        optimize: use simple memory allocator for intermediates
Ivan Mahonin b53a5c
//        optimize: build edge-list directly from curves
Ivan Mahonin b53a5c
//        optimize: rasterize directly from curves?
Ivan Mahonin b53a5c
//
Ivan Mahonin b53a5c
// ADDITIONAL CONTRIBUTORS
Ivan Mahonin b53a5c
//
Ivan Mahonin b53a5c
//   Mikko Mononen: compound shape support, more cmap formats
Ivan Mahonin b53a5c
//   Tor Andersson: kerning, subpixel rendering
Ivan Mahonin b53a5c
//   Dougall Johnson: OpenType / Type 2 font handling
Ivan Mahonin b53a5c
//   Daniel Ribeiro Maciel: basic GPOS-based kerning
Ivan Mahonin b53a5c
//
Ivan Mahonin b53a5c
//   Misc other:
Ivan Mahonin b53a5c
//       Ryan Gordon
Ivan Mahonin b53a5c
//       Simon Glass
Ivan Mahonin b53a5c
//       github:IntellectualKitty
Ivan Mahonin b53a5c
//       Imanol Celaya
Ivan Mahonin b53a5c
//       Daniel Ribeiro Maciel
Ivan Mahonin b53a5c
//
Ivan Mahonin b53a5c
//   Bug/warning reports/fixes:
Ivan Mahonin b53a5c
//       "Zer" on mollyrocket       Fabian "ryg" Giesen   github:NiLuJe
Ivan Mahonin b53a5c
//       Cass Everitt               Martins Mozeiko       github:aloucks
Ivan Mahonin b53a5c
//       stoiko (Haemimont Games)   Cap Petschulat        github:oyvindjam
Ivan Mahonin b53a5c
//       Brian Hook                 Omar Cornut           github:vassvik
Ivan Mahonin b53a5c
//       Walter van Niftrik         Ryan Griege
Ivan Mahonin b53a5c
//       David Gow                  Peter LaValle
Ivan Mahonin b53a5c
//       David Given                Sergey Popov
Ivan Mahonin b53a5c
//       Ivan-Assen Ivanov          Giumo X. Clanjor
Ivan Mahonin b53a5c
//       Anthony Pesch              Higor Euripedes
Ivan Mahonin b53a5c
//       Johan Duparc               Thomas Fields
Ivan Mahonin b53a5c
//       Hou Qiming                 Derek Vinyard
Ivan Mahonin b53a5c
//       Rob Loach                  Cort Stratton
Ivan Mahonin b53a5c
//       Kenney Phillis Jr.         Brian Costabile
Ivan Mahonin b53a5c
//       Ken Voskuil (kaesve)
Ivan Mahonin b53a5c
//
Ivan Mahonin b53a5c
// VERSION HISTORY
Ivan Mahonin b53a5c
//
Ivan Mahonin b53a5c
//   1.26 (2021-08-28) fix broken rasterizer
Ivan Mahonin b53a5c
//   1.25 (2021-07-11) many fixes
Ivan Mahonin b53a5c
//   1.24 (2020-02-05) fix warning
Ivan Mahonin b53a5c
//   1.23 (2020-02-02) query SVG data for glyphs; query whole kerning table (but only kern not GPOS)
Ivan Mahonin b53a5c
//   1.22 (2019-08-11) minimize missing-glyph duplication; fix kerning if both 'GPOS' and 'kern' are defined
Ivan Mahonin b53a5c
//   1.21 (2019-02-25) fix warning
Ivan Mahonin b53a5c
//   1.20 (2019-02-07) PackFontRange skips missing codepoints; GetScaleFontVMetrics()
Ivan Mahonin b53a5c
//   1.19 (2018-02-11) GPOS kerning, STBTT_fmod
Ivan Mahonin b53a5c
//   1.18 (2018-01-29) add missing function
Ivan Mahonin b53a5c
//   1.17 (2017-07-23) make more arguments const; doc fix
Ivan Mahonin b53a5c
//   1.16 (2017-07-12) SDF support
Ivan Mahonin b53a5c
//   1.15 (2017-03-03) make more arguments const
Ivan Mahonin b53a5c
//   1.14 (2017-01-16) num-fonts-in-TTC function
Ivan Mahonin b53a5c
//   1.13 (2017-01-02) support OpenType fonts, certain Apple fonts
Ivan Mahonin b53a5c
//   1.12 (2016-10-25) suppress warnings about casting away const with -Wcast-qual
Ivan Mahonin b53a5c
//   1.11 (2016-04-02) fix unused-variable warning
Ivan Mahonin b53a5c
//   1.10 (2016-04-02) user-defined fabs(); rare memory leak; remove duplicate typedef
Ivan Mahonin b53a5c
//   1.09 (2016-01-16) warning fix; avoid crash on outofmem; use allocation userdata properly
Ivan Mahonin b53a5c
//   1.08 (2015-09-13) document stbtt_Rasterize(); fixes for vertical & horizontal edges
Ivan Mahonin b53a5c
//   1.07 (2015-08-01) allow PackFontRanges to accept arrays of sparse codepoints;
Ivan Mahonin b53a5c
//                     variant PackFontRanges to pack and render in separate phases;
Ivan Mahonin b53a5c
//                     fix stbtt_GetFontOFfsetForIndex (never worked for non-0 input?);
Ivan Mahonin b53a5c
//                     fixed an assert() bug in the new rasterizer
Ivan Mahonin b53a5c
//                     replace assert() with STBTT_assert() in new rasterizer
Ivan Mahonin b53a5c
//
Ivan Mahonin b53a5c
//   Full history can be found at the end of this file.
Ivan Mahonin b53a5c
//
Ivan Mahonin b53a5c
// LICENSE
Ivan Mahonin b53a5c
//
Ivan Mahonin b53a5c
//   See end of file for license information.
Ivan Mahonin b53a5c
//
Ivan Mahonin b53a5c
// USAGE
Ivan Mahonin b53a5c
//
Ivan Mahonin b53a5c
//   Include this file in whatever places need to refer to it. In ONE C/C++
Ivan Mahonin b53a5c
//   file, write:
Ivan Mahonin b53a5c
//      #define STB_TRUETYPE_IMPLEMENTATION
Ivan Mahonin b53a5c
//   before the #include of this file. This expands out the actual
Ivan Mahonin b53a5c
//   implementation into that C/C++ file.
Ivan Mahonin b53a5c
//
Ivan Mahonin b53a5c
//   To make the implementation private to the file that generates the implementation,
Ivan Mahonin b53a5c
//      #define STBTT_STATIC
Ivan Mahonin b53a5c
//
Ivan Mahonin b53a5c
//   Simple 3D API (don't ship this, but it's fine for tools and quick start)
Ivan Mahonin b53a5c
//           stbtt_BakeFontBitmap()               -- bake a font to a bitmap for use as texture
Ivan Mahonin b53a5c
//           stbtt_GetBakedQuad()                 -- compute quad to draw for a given char
Ivan Mahonin b53a5c
//
Ivan Mahonin b53a5c
//   Improved 3D API (more shippable):
Ivan Mahonin b53a5c
//           #include "stb_rect_pack.h"           -- optional, but you really want it
Ivan Mahonin b53a5c
//           stbtt_PackBegin()
Ivan Mahonin b53a5c
//           stbtt_PackSetOversampling()          -- for improved quality on small fonts
Ivan Mahonin b53a5c
//           stbtt_PackFontRanges()               -- pack and renders
Ivan Mahonin b53a5c
//           stbtt_PackEnd()
Ivan Mahonin b53a5c
//           stbtt_GetPackedQuad()
Ivan Mahonin b53a5c
//
Ivan Mahonin b53a5c
//   "Load" a font file from a memory buffer (you have to keep the buffer loaded)
Ivan Mahonin b53a5c
//           stbtt_InitFont()
Ivan Mahonin b53a5c
//           stbtt_GetFontOffsetForIndex()        -- indexing for TTC font collections
Ivan Mahonin b53a5c
//           stbtt_GetNumberOfFonts()             -- number of fonts for TTC font collections
Ivan Mahonin b53a5c
//
Ivan Mahonin b53a5c
//   Render a unicode codepoint to a bitmap
Ivan Mahonin b53a5c
//           stbtt_GetCodepointBitmap()           -- allocates and returns a bitmap
Ivan Mahonin b53a5c
//           stbtt_MakeCodepointBitmap()          -- renders into bitmap you provide
Ivan Mahonin b53a5c
//           stbtt_GetCodepointBitmapBox()        -- how big the bitmap must be
Ivan Mahonin b53a5c
//
Ivan Mahonin b53a5c
//   Character advance/positioning
Ivan Mahonin b53a5c
//           stbtt_GetCodepointHMetrics()
Ivan Mahonin b53a5c
//           stbtt_GetFontVMetrics()
Ivan Mahonin b53a5c
//           stbtt_GetFontVMetricsOS2()
Ivan Mahonin b53a5c
//           stbtt_GetCodepointKernAdvance()
Ivan Mahonin b53a5c
//
Ivan Mahonin b53a5c
//   Starting with version 1.06, the rasterizer was replaced with a new,
Ivan Mahonin b53a5c
//   faster and generally-more-precise rasterizer. The new rasterizer more
Ivan Mahonin b53a5c
//   accurately measures pixel coverage for anti-aliasing, except in the case
Ivan Mahonin b53a5c
//   where multiple shapes overlap, in which case it overestimates the AA pixel
Ivan Mahonin b53a5c
//   coverage. Thus, anti-aliasing of intersecting shapes may look wrong. If
Ivan Mahonin b53a5c
//   this turns out to be a problem, you can re-enable the old rasterizer with
Ivan Mahonin b53a5c
//        #define STBTT_RASTERIZER_VERSION 1
Ivan Mahonin b53a5c
//   which will incur about a 15% speed hit.
Ivan Mahonin b53a5c
//
Ivan Mahonin b53a5c
// ADDITIONAL DOCUMENTATION
Ivan Mahonin b53a5c
//
Ivan Mahonin b53a5c
//   Immediately after this block comment are a series of sample programs.
Ivan Mahonin b53a5c
//
Ivan Mahonin b53a5c
//   After the sample programs is the "header file" section. This section
Ivan Mahonin b53a5c
//   includes documentation for each API function.
Ivan Mahonin b53a5c
//
Ivan Mahonin b53a5c
//   Some important concepts to understand to use this library:
Ivan Mahonin b53a5c
//
Ivan Mahonin b53a5c
//      Codepoint
Ivan Mahonin b53a5c
//         Characters are defined by unicode codepoints, e.g. 65 is
Ivan Mahonin b53a5c
//         uppercase A, 231 is lowercase c with a cedilla, 0x7e30 is
Ivan Mahonin b53a5c
//         the hiragana for "ma".
Ivan Mahonin b53a5c
//
Ivan Mahonin b53a5c
//      Glyph
Ivan Mahonin b53a5c
//         A visual character shape (every codepoint is rendered as
Ivan Mahonin b53a5c
//         some glyph)
Ivan Mahonin b53a5c
//
Ivan Mahonin b53a5c
//      Glyph index
Ivan Mahonin b53a5c
//         A font-specific integer ID representing a glyph
Ivan Mahonin b53a5c
//
Ivan Mahonin b53a5c
//      Baseline
Ivan Mahonin b53a5c
//         Glyph shapes are defined relative to a baseline, which is the
Ivan Mahonin b53a5c
//         bottom of uppercase characters. Characters extend both above
Ivan Mahonin b53a5c
//         and below the baseline.
Ivan Mahonin b53a5c
//
Ivan Mahonin b53a5c
//      Current Point
Ivan Mahonin b53a5c
//         As you draw text to the screen, you keep track of a "current point"
Ivan Mahonin b53a5c
//         which is the origin of each character. The current point's vertical
Ivan Mahonin b53a5c
//         position is the baseline. Even "baked fonts" use this model.
Ivan Mahonin b53a5c
//
Ivan Mahonin b53a5c
//      Vertical Font Metrics
Ivan Mahonin b53a5c
//         The vertical qualities of the font, used to vertically position
Ivan Mahonin b53a5c
//         and space the characters. See docs for stbtt_GetFontVMetrics.
Ivan Mahonin b53a5c
//
Ivan Mahonin b53a5c
//      Font Size in Pixels or Points
Ivan Mahonin b53a5c
//         The preferred interface for specifying font sizes in stb_truetype
Ivan Mahonin b53a5c
//         is to specify how tall the font's vertical extent should be in pixels.
Ivan Mahonin b53a5c
//         If that sounds good enough, skip the next paragraph.
Ivan Mahonin b53a5c
//
Ivan Mahonin b53a5c
//         Most font APIs instead use "points", which are a common typographic
Ivan Mahonin b53a5c
//         measurement for describing font size, defined as 72 points per inch.
Ivan Mahonin b53a5c
//         stb_truetype provides a point API for compatibility. However, true
Ivan Mahonin b53a5c
//         "per inch" conventions don't make much sense on computer displays
Ivan Mahonin b53a5c
//         since different monitors have different number of pixels per
Ivan Mahonin b53a5c
//         inch. For example, Windows traditionally uses a convention that
Ivan Mahonin b53a5c
//         there are 96 pixels per inch, thus making 'inch' measurements have
Ivan Mahonin b53a5c
//         nothing to do with inches, and thus effectively defining a point to
Ivan Mahonin b53a5c
//         be 1.333 pixels. Additionally, the TrueType font data provides
Ivan Mahonin b53a5c
//         an explicit scale factor to scale a given font's glyphs to points,
Ivan Mahonin b53a5c
//         but the author has observed that this scale factor is often wrong
Ivan Mahonin b53a5c
//         for non-commercial fonts, thus making fonts scaled in points
Ivan Mahonin b53a5c
//         according to the TrueType spec incoherently sized in practice.
Ivan Mahonin b53a5c
//
Ivan Mahonin b53a5c
// DETAILED USAGE:
Ivan Mahonin b53a5c
//
Ivan Mahonin b53a5c
//  Scale:
Ivan Mahonin b53a5c
//    Select how high you want the font to be, in points or pixels.
Ivan Mahonin b53a5c
//    Call ScaleForPixelHeight or ScaleForMappingEmToPixels to compute
Ivan Mahonin b53a5c
//    a scale factor SF that will be used by all other functions.
Ivan Mahonin b53a5c
//
Ivan Mahonin b53a5c
//  Baseline:
Ivan Mahonin b53a5c
//    You need to select a y-coordinate that is the baseline of where
Ivan Mahonin b53a5c
//    your text will appear. Call GetFontBoundingBox to get the baseline-relative
Ivan Mahonin b53a5c
//    bounding box for all characters. SF*-y0 will be the distance in pixels
Ivan Mahonin b53a5c
//    that the worst-case character could extend above the baseline, so if
Ivan Mahonin b53a5c
//    you want the top edge of characters to appear at the top of the
Ivan Mahonin b53a5c
//    screen where y=0, then you would set the baseline to SF*-y0.
Ivan Mahonin b53a5c
//
Ivan Mahonin b53a5c
//  Current point:
Ivan Mahonin b53a5c
//    Set the current point where the first character will appear. The
Ivan Mahonin b53a5c
//    first character could extend left of the current point; this is font
Ivan Mahonin b53a5c
//    dependent. You can either choose a current point that is the leftmost
Ivan Mahonin b53a5c
//    point and hope, or add some padding, or check the bounding box or
Ivan Mahonin b53a5c
//    left-side-bearing of the first character to be displayed and set
Ivan Mahonin b53a5c
//    the current point based on that.
Ivan Mahonin b53a5c
//
Ivan Mahonin b53a5c
//  Displaying a character:
Ivan Mahonin b53a5c
//    Compute the bounding box of the character. It will contain signed values
Ivan Mahonin b53a5c
//    relative to <current_point, baseline>. I.e. if it returns x0,y0,x1,y1,
Ivan Mahonin b53a5c
//    then the character should be displayed in the rectangle from
Ivan Mahonin b53a5c
//    <current_point+SF*x0, baseline+SF*y0> to <current_point+SF*x1,baseline+SF*y1).
Ivan Mahonin b53a5c
//
Ivan Mahonin b53a5c
//  Advancing for the next character:
Ivan Mahonin b53a5c
//    Call GlyphHMetrics, and compute 'current_point += SF * advance'.
Ivan Mahonin b53a5c
//
Ivan Mahonin b53a5c
//
Ivan Mahonin b53a5c
// ADVANCED USAGE
Ivan Mahonin b53a5c
//
Ivan Mahonin b53a5c
//   Quality:
Ivan Mahonin b53a5c
//
Ivan Mahonin b53a5c
//    - Use the functions with Subpixel at the end to allow your characters
Ivan Mahonin b53a5c
//      to have subpixel positioning. Since the font is anti-aliased, not
Ivan Mahonin b53a5c
//      hinted, this is very import for quality. (This is not possible with
Ivan Mahonin b53a5c
//      baked fonts.)
Ivan Mahonin b53a5c
//
Ivan Mahonin b53a5c
//    - Kerning is now supported, and if you're supporting subpixel rendering
Ivan Mahonin b53a5c
//      then kerning is worth using to give your text a polished look.
Ivan Mahonin b53a5c
//
Ivan Mahonin b53a5c
//   Performance:
Ivan Mahonin b53a5c
//
Ivan Mahonin b53a5c
//    - Convert Unicode codepoints to glyph indexes and operate on the glyphs;
Ivan Mahonin b53a5c
//      if you don't do this, stb_truetype is forced to do the conversion on
Ivan Mahonin b53a5c
//      every call.
Ivan Mahonin b53a5c
//
Ivan Mahonin b53a5c
//    - There are a lot of memory allocations. We should modify it to take
Ivan Mahonin b53a5c
//      a temp buffer and allocate from the temp buffer (without freeing),
Ivan Mahonin b53a5c
//      should help performance a lot.
Ivan Mahonin b53a5c
//
Ivan Mahonin b53a5c
// NOTES
Ivan Mahonin b53a5c
//
Ivan Mahonin b53a5c
//   The system uses the raw data found in the .ttf file without changing it
Ivan Mahonin b53a5c
//   and without building auxiliary data structures. This is a bit inefficient
Ivan Mahonin b53a5c
//   on little-endian systems (the data is big-endian), but assuming you're
Ivan Mahonin b53a5c
//   caching the bitmaps or glyph shapes this shouldn't be a big deal.
Ivan Mahonin b53a5c
//
Ivan Mahonin b53a5c
//   It appears to be very hard to programmatically determine what font a
Ivan Mahonin b53a5c
//   given file is in a general way. I provide an API for this, but I don't
Ivan Mahonin b53a5c
//   recommend it.
Ivan Mahonin b53a5c
//
Ivan Mahonin b53a5c
//
Ivan Mahonin b53a5c
// PERFORMANCE MEASUREMENTS FOR 1.06:
Ivan Mahonin b53a5c
//
Ivan Mahonin b53a5c
//                      32-bit     64-bit
Ivan Mahonin b53a5c
//   Previous release:  8.83 s     7.68 s
Ivan Mahonin b53a5c
//   Pool allocations:  7.72 s     6.34 s
Ivan Mahonin b53a5c
//   Inline sort     :  6.54 s     5.65 s
Ivan Mahonin b53a5c
//   New rasterizer  :  5.63 s     5.00 s
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
//////////////////////////////////////////////////////////////////////////////
Ivan Mahonin b53a5c
//////////////////////////////////////////////////////////////////////////////
Ivan Mahonin b53a5c
////
Ivan Mahonin b53a5c
////  SAMPLE PROGRAMS
Ivan Mahonin b53a5c
////
Ivan Mahonin b53a5c
//
Ivan Mahonin b53a5c
//  Incomplete text-in-3d-api example, which draws quads properly aligned to be lossless.
Ivan Mahonin b53a5c
//  See "tests/truetype_demo_win32.c" for a complete version.
Ivan Mahonin b53a5c
#if 0
Ivan Mahonin b53a5c
#define STB_TRUETYPE_IMPLEMENTATION  // force following include to generate implementation
Ivan Mahonin b53a5c
#include "stb_truetype.h"
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
unsigned char ttf_buffer[1<<20];
Ivan Mahonin b53a5c
unsigned char temp_bitmap[512*512];
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
stbtt_bakedchar cdata[96]; // ASCII 32..126 is 95 glyphs
Ivan Mahonin b53a5c
GLuint ftex;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
void my_stbtt_initfont(void)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   fread(ttf_buffer, 1, 1<<20, fopen("c:/windows/fonts/times.ttf", "rb"));
Ivan Mahonin b53a5c
   stbtt_BakeFontBitmap(ttf_buffer,0, 32.0, temp_bitmap,512,512, 32,96, cdata); // no guarantee this fits!
Ivan Mahonin b53a5c
   // can free ttf_buffer at this point
Ivan Mahonin b53a5c
   glGenTextures(1, &ftex);
Ivan Mahonin b53a5c
   glBindTexture(GL_TEXTURE_2D, ftex);
Ivan Mahonin b53a5c
   glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, 512,512, 0, GL_ALPHA, GL_UNSIGNED_BYTE, temp_bitmap);
Ivan Mahonin b53a5c
   // can free temp_bitmap at this point
Ivan Mahonin b53a5c
   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
void my_stbtt_print(float x, float y, char *text)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   // assume orthographic projection with units = screen pixels, origin at top left
Ivan Mahonin b53a5c
   glEnable(GL_BLEND);
Ivan Mahonin b53a5c
   glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
Ivan Mahonin b53a5c
   glEnable(GL_TEXTURE_2D);
Ivan Mahonin b53a5c
   glBindTexture(GL_TEXTURE_2D, ftex);
Ivan Mahonin b53a5c
   glBegin(GL_QUADS);
Ivan Mahonin b53a5c
   while (*text) {
Ivan Mahonin b53a5c
      if (*text >= 32 && *text < 128) {
Ivan Mahonin b53a5c
         stbtt_aligned_quad q;
Ivan Mahonin b53a5c
         stbtt_GetBakedQuad(cdata, 512,512, *text-32, &x,&y,&q,1);//1=opengl & d3d10+,0=d3d9
Ivan Mahonin b53a5c
         glTexCoord2f(q.s0,q.t0); glVertex2f(q.x0,q.y0);
Ivan Mahonin b53a5c
         glTexCoord2f(q.s1,q.t0); glVertex2f(q.x1,q.y0);
Ivan Mahonin b53a5c
         glTexCoord2f(q.s1,q.t1); glVertex2f(q.x1,q.y1);
Ivan Mahonin b53a5c
         glTexCoord2f(q.s0,q.t1); glVertex2f(q.x0,q.y1);
Ivan Mahonin b53a5c
      }
Ivan Mahonin b53a5c
      ++text;
Ivan Mahonin b53a5c
   }
Ivan Mahonin b53a5c
   glEnd();
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
#endif
Ivan Mahonin b53a5c
//
Ivan Mahonin b53a5c
//
Ivan Mahonin b53a5c
//////////////////////////////////////////////////////////////////////////////
Ivan Mahonin b53a5c
//
Ivan Mahonin b53a5c
// Complete program (this compiles): get a single bitmap, print as ASCII art
Ivan Mahonin b53a5c
//
Ivan Mahonin b53a5c
#if 0
Ivan Mahonin b53a5c
#include <stdio.h>
Ivan Mahonin b53a5c
#define STB_TRUETYPE_IMPLEMENTATION  // force following include to generate implementation
Ivan Mahonin b53a5c
#include "stb_truetype.h"
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
char ttf_buffer[1<<25];
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
int main(int argc, char **argv)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   stbtt_fontinfo font;
Ivan Mahonin b53a5c
   unsigned char *bitmap;
Ivan Mahonin b53a5c
   int w,h,i,j,c = (argc > 1 ? atoi(argv[1]) : 'a'), s = (argc > 2 ? atoi(argv[2]) : 20);
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   fread(ttf_buffer, 1, 1<<25, fopen(argc > 3 ? argv[3] : "c:/windows/fonts/arialbd.ttf", "rb"));
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   stbtt_InitFont(&font, ttf_buffer, stbtt_GetFontOffsetForIndex(ttf_buffer,0));
Ivan Mahonin b53a5c
   bitmap = stbtt_GetCodepointBitmap(&font, 0,stbtt_ScaleForPixelHeight(&font, s), c, &w, &h, 0,0);
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   for (j=0; j < h; ++j) {
Ivan Mahonin b53a5c
      for (i=0; i < w; ++i)
Ivan Mahonin b53a5c
         putchar(" .:ioVM@"[bitmap[j*w+i]>>5]);
Ivan Mahonin b53a5c
      putchar('\n');
Ivan Mahonin b53a5c
   }
Ivan Mahonin b53a5c
   return 0;
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
#endif
Ivan Mahonin b53a5c
//
Ivan Mahonin b53a5c
// Output:
Ivan Mahonin b53a5c
//
Ivan Mahonin b53a5c
//     .ii.
Ivan Mahonin b53a5c
//    @@@@@@.
Ivan Mahonin b53a5c
//   V@Mio@@o
Ivan Mahonin b53a5c
//   :i.  V@V
Ivan Mahonin b53a5c
//     :oM@@M
Ivan Mahonin b53a5c
//   :@@@MM@M
Ivan Mahonin b53a5c
//   @@o  o@M
Ivan Mahonin b53a5c
//  :@@.  M@M
Ivan Mahonin b53a5c
//   @@@o@@@@
Ivan Mahonin b53a5c
//   :M@@V:@@.
Ivan Mahonin b53a5c
//
Ivan Mahonin b53a5c
//////////////////////////////////////////////////////////////////////////////
Ivan Mahonin b53a5c
//
Ivan Mahonin b53a5c
// Complete program: print "Hello World!" banner, with bugs
Ivan Mahonin b53a5c
//
Ivan Mahonin b53a5c
#if 0
Ivan Mahonin b53a5c
char buffer[24<<20];
Ivan Mahonin b53a5c
unsigned char screen[20][79];
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
int main(int arg, char **argv)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   stbtt_fontinfo font;
Ivan Mahonin b53a5c
   int i,j,ascent,baseline,ch=0;
Ivan Mahonin b53a5c
   float scale, xpos=2; // leave a little padding in case the character extends left
Ivan Mahonin b53a5c
   char *text = "Heljo World!"; // intentionally misspelled to show 'lj' brokenness
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   fread(buffer, 1, 1000000, fopen("c:/windows/fonts/arialbd.ttf", "rb"));
Ivan Mahonin b53a5c
   stbtt_InitFont(&font, buffer, 0);
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   scale = stbtt_ScaleForPixelHeight(&font, 15);
Ivan Mahonin b53a5c
   stbtt_GetFontVMetrics(&font, &ascent,0,0);
Ivan Mahonin b53a5c
   baseline = (int) (ascent*scale);
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   while (text[ch]) {
Ivan Mahonin b53a5c
      int advance,lsb,x0,y0,x1,y1;
Ivan Mahonin b53a5c
      float x_shift = xpos - (float) floor(xpos);
Ivan Mahonin b53a5c
      stbtt_GetCodepointHMetrics(&font, text[ch], &advance, &lsb);
Ivan Mahonin b53a5c
      stbtt_GetCodepointBitmapBoxSubpixel(&font, text[ch], scale,scale,x_shift,0, &x0,&y0,&x1,&y1);
Ivan Mahonin b53a5c
      stbtt_MakeCodepointBitmapSubpixel(&font, &screen[baseline + y0][(int) xpos + x0], x1-x0,y1-y0, 79, scale,scale,x_shift,0, text[ch]);
Ivan Mahonin b53a5c
      // note that this stomps the old data, so where character boxes overlap (e.g. 'lj') it's wrong
Ivan Mahonin b53a5c
      // because this API is really for baking character bitmaps into textures. if you want to render
Ivan Mahonin b53a5c
      // a sequence of characters, you really need to render each bitmap to a temp buffer, then
Ivan Mahonin b53a5c
      // "alpha blend" that into the working buffer
Ivan Mahonin b53a5c
      xpos += (advance * scale);
Ivan Mahonin b53a5c
      if (text[ch+1])
Ivan Mahonin b53a5c
         xpos += scale*stbtt_GetCodepointKernAdvance(&font, text[ch],text[ch+1]);
Ivan Mahonin b53a5c
      ++ch;
Ivan Mahonin b53a5c
   }
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   for (j=0; j < 20; ++j) {
Ivan Mahonin b53a5c
      for (i=0; i < 78; ++i)
Ivan Mahonin b53a5c
         putchar(" .:ioVM@"[screen[j][i]>>5]);
Ivan Mahonin b53a5c
      putchar('\n');
Ivan Mahonin b53a5c
   }
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   return 0;
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
#endif
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
//////////////////////////////////////////////////////////////////////////////
Ivan Mahonin b53a5c
//////////////////////////////////////////////////////////////////////////////
Ivan Mahonin b53a5c
////
Ivan Mahonin b53a5c
////   INTEGRATION WITH YOUR CODEBASE
Ivan Mahonin b53a5c
////
Ivan Mahonin b53a5c
////   The following sections allow you to supply alternate definitions
Ivan Mahonin b53a5c
////   of C library functions used by stb_truetype, e.g. if you don't
Ivan Mahonin b53a5c
////   link with the C runtime library.
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
#ifdef STB_TRUETYPE_IMPLEMENTATION
Ivan Mahonin b53a5c
   // #define your own (u)stbtt_int8/16/32 before including to override this
Ivan Mahonin b53a5c
   #ifndef stbtt_uint8
Ivan Mahonin b53a5c
   typedef unsigned char   stbtt_uint8;
Ivan Mahonin b53a5c
   typedef signed   char   stbtt_int8;
Ivan Mahonin b53a5c
   typedef unsigned short  stbtt_uint16;
Ivan Mahonin b53a5c
   typedef signed   short  stbtt_int16;
Ivan Mahonin b53a5c
   typedef unsigned int    stbtt_uint32;
Ivan Mahonin b53a5c
   typedef signed   int    stbtt_int32;
Ivan Mahonin b53a5c
   #endif
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   typedef char stbtt__check_size32[sizeof(stbtt_int32)==4 ? 1 : -1];
Ivan Mahonin b53a5c
   typedef char stbtt__check_size16[sizeof(stbtt_int16)==2 ? 1 : -1];
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   // e.g. #define your own STBTT_ifloor/STBTT_iceil() to avoid math.h
Ivan Mahonin b53a5c
   #ifndef STBTT_ifloor
Ivan Mahonin b53a5c
   #include <math.h>
Ivan Mahonin b53a5c
   #define STBTT_ifloor(x)   ((int) floor(x))
Ivan Mahonin b53a5c
   #define STBTT_iceil(x)    ((int) ceil(x))
Ivan Mahonin b53a5c
   #endif
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   #ifndef STBTT_sqrt
Ivan Mahonin b53a5c
   #include <math.h>
Ivan Mahonin b53a5c
   #define STBTT_sqrt(x)      sqrt(x)
Ivan Mahonin b53a5c
   #define STBTT_pow(x,y)     pow(x,y)
Ivan Mahonin b53a5c
   #endif
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   #ifndef STBTT_fmod
Ivan Mahonin b53a5c
   #include <math.h>
Ivan Mahonin b53a5c
   #define STBTT_fmod(x,y)    fmod(x,y)
Ivan Mahonin b53a5c
   #endif
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   #ifndef STBTT_cos
Ivan Mahonin b53a5c
   #include <math.h>
Ivan Mahonin b53a5c
   #define STBTT_cos(x)       cos(x)
Ivan Mahonin b53a5c
   #define STBTT_acos(x)      acos(x)
Ivan Mahonin b53a5c
   #endif
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   #ifndef STBTT_fabs
Ivan Mahonin b53a5c
   #include <math.h>
Ivan Mahonin b53a5c
   #define STBTT_fabs(x)      fabs(x)
Ivan Mahonin b53a5c
   #endif
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   // #define your own functions "STBTT_malloc" / "STBTT_free" to avoid malloc.h
Ivan Mahonin b53a5c
   #ifndef STBTT_malloc
Ivan Mahonin b53a5c
   #include <stdlib.h>
Ivan Mahonin b53a5c
   #define STBTT_malloc(x,u)  ((void)(u),malloc(x))
Ivan Mahonin b53a5c
   #define STBTT_free(x,u)    ((void)(u),free(x))
Ivan Mahonin b53a5c
   #endif
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   #ifndef STBTT_assert
Ivan Mahonin b53a5c
   #include <assert.h>
Ivan Mahonin b53a5c
   #define STBTT_assert(x)    assert(x)
Ivan Mahonin b53a5c
   #endif
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   #ifndef STBTT_strlen
Ivan Mahonin b53a5c
   #include <string.h>
Ivan Mahonin b53a5c
   #define STBTT_strlen(x)    strlen(x)
Ivan Mahonin b53a5c
   #endif
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   #ifndef STBTT_memcpy
Ivan Mahonin b53a5c
   #include <string.h>
Ivan Mahonin b53a5c
   #define STBTT_memcpy       memcpy
Ivan Mahonin b53a5c
   #define STBTT_memset       memset
Ivan Mahonin b53a5c
   #endif
Ivan Mahonin b53a5c
#endif
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
///////////////////////////////////////////////////////////////////////////////
Ivan Mahonin b53a5c
///////////////////////////////////////////////////////////////////////////////
Ivan Mahonin b53a5c
////
Ivan Mahonin b53a5c
////   INTERFACE
Ivan Mahonin b53a5c
////
Ivan Mahonin b53a5c
////
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
#ifndef __STB_INCLUDE_STB_TRUETYPE_H__
Ivan Mahonin b53a5c
#define __STB_INCLUDE_STB_TRUETYPE_H__
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
#ifdef STBTT_STATIC
Ivan Mahonin b53a5c
#define STBTT_DEF static
Ivan Mahonin b53a5c
#else
Ivan Mahonin b53a5c
#define STBTT_DEF extern
Ivan Mahonin b53a5c
#endif
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
#ifdef __cplusplus
Ivan Mahonin b53a5c
extern "C" {
Ivan Mahonin b53a5c
#endif
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
// private structure
Ivan Mahonin b53a5c
typedef struct
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   unsigned char *data;
Ivan Mahonin b53a5c
   int cursor;
Ivan Mahonin b53a5c
   int size;
Ivan Mahonin b53a5c
} stbtt__buf;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
//////////////////////////////////////////////////////////////////////////////
Ivan Mahonin b53a5c
//
Ivan Mahonin b53a5c
// TEXTURE BAKING API
Ivan Mahonin b53a5c
//
Ivan Mahonin b53a5c
// If you use this API, you only have to call two functions ever.
Ivan Mahonin b53a5c
//
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
typedef struct
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   unsigned short x0,y0,x1,y1; // coordinates of bbox in bitmap
Ivan Mahonin b53a5c
   float xoff,yoff,xadvance;
Ivan Mahonin b53a5c
} stbtt_bakedchar;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
STBTT_DEF int stbtt_BakeFontBitmap(const unsigned char *data, int offset,  // font location (use offset=0 for plain .ttf)
Ivan Mahonin b53a5c
                                float pixel_height,                     // height of font in pixels
Ivan Mahonin b53a5c
                                unsigned char *pixels, int pw, int ph,  // bitmap to be filled in
Ivan Mahonin b53a5c
                                int first_char, int num_chars,          // characters to bake
Ivan Mahonin b53a5c
                                stbtt_bakedchar *chardata);             // you allocate this, it's num_chars long
Ivan Mahonin b53a5c
// if return is positive, the first unused row of the bitmap
Ivan Mahonin b53a5c
// if return is negative, returns the negative of the number of characters that fit
Ivan Mahonin b53a5c
// if return is 0, no characters fit and no rows were used
Ivan Mahonin b53a5c
// This uses a very crappy packing.
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
typedef struct
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   float x0,y0,s0,t0; // top-left
Ivan Mahonin b53a5c
   float x1,y1,s1,t1; // bottom-right
Ivan Mahonin b53a5c
} stbtt_aligned_quad;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
STBTT_DEF void stbtt_GetBakedQuad(const stbtt_bakedchar *chardata, int pw, int ph,  // same data as above
Ivan Mahonin b53a5c
                               int char_index,             // character to display
Ivan Mahonin b53a5c
                               float *xpos, float *ypos,   // pointers to current position in screen pixel space
Ivan Mahonin b53a5c
                               stbtt_aligned_quad *q,      // output: quad to draw
Ivan Mahonin b53a5c
                               int opengl_fillrule);       // true if opengl fill rule; false if DX9 or earlier
Ivan Mahonin b53a5c
// Call GetBakedQuad with char_index = 'character - first_char', and it
Ivan Mahonin b53a5c
// creates the quad you need to draw and advances the current position.
Ivan Mahonin b53a5c
//
Ivan Mahonin b53a5c
// The coordinate system used assumes y increases downwards.
Ivan Mahonin b53a5c
//
Ivan Mahonin b53a5c
// Characters will extend both above and below the current position;
Ivan Mahonin b53a5c
// see discussion of "BASELINE" above.
Ivan Mahonin b53a5c
//
Ivan Mahonin b53a5c
// It's inefficient; you might want to c&p it and optimize it.
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
STBTT_DEF void stbtt_GetScaledFontVMetrics(const unsigned char *fontdata, int index, float size, float *ascent, float *descent, float *lineGap);
Ivan Mahonin b53a5c
// Query the font vertical metrics without having to create a font first.
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
//////////////////////////////////////////////////////////////////////////////
Ivan Mahonin b53a5c
//
Ivan Mahonin b53a5c
// NEW TEXTURE BAKING API
Ivan Mahonin b53a5c
//
Ivan Mahonin b53a5c
// This provides options for packing multiple fonts into one atlas, not
Ivan Mahonin b53a5c
// perfectly but better than nothing.
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
typedef struct
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   unsigned short x0,y0,x1,y1; // coordinates of bbox in bitmap
Ivan Mahonin b53a5c
   float xoff,yoff,xadvance;
Ivan Mahonin b53a5c
   float xoff2,yoff2;
Ivan Mahonin b53a5c
} stbtt_packedchar;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
typedef struct stbtt_pack_context stbtt_pack_context;
Ivan Mahonin b53a5c
typedef struct stbtt_fontinfo stbtt_fontinfo;
Ivan Mahonin b53a5c
#ifndef STB_RECT_PACK_VERSION
Ivan Mahonin b53a5c
typedef struct stbrp_rect stbrp_rect;
Ivan Mahonin b53a5c
#endif
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
STBTT_DEF int  stbtt_PackBegin(stbtt_pack_context *spc, unsigned char *pixels, int width, int height, int stride_in_bytes, int padding, void *alloc_context);
Ivan Mahonin b53a5c
// Initializes a packing context stored in the passed-in stbtt_pack_context.
Ivan Mahonin b53a5c
// Future calls using this context will pack characters into the bitmap passed
Ivan Mahonin b53a5c
// in here: a 1-channel bitmap that is width * height. stride_in_bytes is
Ivan Mahonin b53a5c
// the distance from one row to the next (or 0 to mean they are packed tightly
Ivan Mahonin b53a5c
// together). "padding" is the amount of padding to leave between each
Ivan Mahonin b53a5c
// character (normally you want '1' for bitmaps you'll use as textures with
Ivan Mahonin b53a5c
// bilinear filtering).
Ivan Mahonin b53a5c
//
Ivan Mahonin b53a5c
// Returns 0 on failure, 1 on success.
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
STBTT_DEF void stbtt_PackEnd  (stbtt_pack_context *spc);
Ivan Mahonin b53a5c
// Cleans up the packing context and frees all memory.
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
#define STBTT_POINT_SIZE(x)   (-(x))
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
STBTT_DEF int  stbtt_PackFontRange(stbtt_pack_context *spc, const unsigned char *fontdata, int font_index, float font_size,
Ivan Mahonin b53a5c
                                int first_unicode_char_in_range, int num_chars_in_range, stbtt_packedchar *chardata_for_range);
Ivan Mahonin b53a5c
// Creates character bitmaps from the font_index'th font found in fontdata (use
Ivan Mahonin b53a5c
// font_index=0 if you don't know what that is). It creates num_chars_in_range
Ivan Mahonin b53a5c
// bitmaps for characters with unicode values starting at first_unicode_char_in_range
Ivan Mahonin b53a5c
// and increasing. Data for how to render them is stored in chardata_for_range;
Ivan Mahonin b53a5c
// pass these to stbtt_GetPackedQuad to get back renderable quads.
Ivan Mahonin b53a5c
//
Ivan Mahonin b53a5c
// font_size is the full height of the character from ascender to descender,
Ivan Mahonin b53a5c
// as computed by stbtt_ScaleForPixelHeight. To use a point size as computed
Ivan Mahonin b53a5c
// by stbtt_ScaleForMappingEmToPixels, wrap the point size in STBTT_POINT_SIZE()
Ivan Mahonin b53a5c
// and pass that result as 'font_size':
Ivan Mahonin b53a5c
//       ...,                  20 , ... // font max minus min y is 20 pixels tall
Ivan Mahonin b53a5c
//       ..., STBTT_POINT_SIZE(20), ... // 'M' is 20 pixels tall
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
typedef struct
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   float font_size;
Ivan Mahonin b53a5c
   int first_unicode_codepoint_in_range;  // if non-zero, then the chars are continuous, and this is the first codepoint
Ivan Mahonin b53a5c
   int *array_of_unicode_codepoints;       // if non-zero, then this is an array of unicode codepoints
Ivan Mahonin b53a5c
   int num_chars;
Ivan Mahonin b53a5c
   stbtt_packedchar *chardata_for_range; // output
Ivan Mahonin b53a5c
   unsigned char h_oversample, v_oversample; // don't set these, they're used internally
Ivan Mahonin b53a5c
} stbtt_pack_range;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
STBTT_DEF int  stbtt_PackFontRanges(stbtt_pack_context *spc, const unsigned char *fontdata, int font_index, stbtt_pack_range *ranges, int num_ranges);
Ivan Mahonin b53a5c
// Creates character bitmaps from multiple ranges of characters stored in
Ivan Mahonin b53a5c
// ranges. This will usually create a better-packed bitmap than multiple
Ivan Mahonin b53a5c
// calls to stbtt_PackFontRange. Note that you can call this multiple
Ivan Mahonin b53a5c
// times within a single PackBegin/PackEnd.
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
STBTT_DEF void stbtt_PackSetOversampling(stbtt_pack_context *spc, unsigned int h_oversample, unsigned int v_oversample);
Ivan Mahonin b53a5c
// Oversampling a font increases the quality by allowing higher-quality subpixel
Ivan Mahonin b53a5c
// positioning, and is especially valuable at smaller text sizes.
Ivan Mahonin b53a5c
//
Ivan Mahonin b53a5c
// This function sets the amount of oversampling for all following calls to
Ivan Mahonin b53a5c
// stbtt_PackFontRange(s) or stbtt_PackFontRangesGatherRects for a given
Ivan Mahonin b53a5c
// pack context. The default (no oversampling) is achieved by h_oversample=1
Ivan Mahonin b53a5c
// and v_oversample=1. The total number of pixels required is
Ivan Mahonin b53a5c
// h_oversample*v_oversample larger than the default; for example, 2x2
Ivan Mahonin b53a5c
// oversampling requires 4x the storage of 1x1. For best results, render
Ivan Mahonin b53a5c
// oversampled textures with bilinear filtering. Look at the readme in
Ivan Mahonin b53a5c
// stb/tests/oversample for information about oversampled fonts
Ivan Mahonin b53a5c
//
Ivan Mahonin b53a5c
// To use with PackFontRangesGather etc., you must set it before calls
Ivan Mahonin b53a5c
// call to PackFontRangesGatherRects.
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
STBTT_DEF void stbtt_PackSetSkipMissingCodepoints(stbtt_pack_context *spc, int skip);
Ivan Mahonin b53a5c
// If skip != 0, this tells stb_truetype to skip any codepoints for which
Ivan Mahonin b53a5c
// there is no corresponding glyph. If skip=0, which is the default, then
Ivan Mahonin b53a5c
// codepoints without a glyph recived the font's "missing character" glyph,
Ivan Mahonin b53a5c
// typically an empty box by convention.
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
STBTT_DEF void stbtt_GetPackedQuad(const stbtt_packedchar *chardata, int pw, int ph,  // same data as above
Ivan Mahonin b53a5c
                               int char_index,             // character to display
Ivan Mahonin b53a5c
                               float *xpos, float *ypos,   // pointers to current position in screen pixel space
Ivan Mahonin b53a5c
                               stbtt_aligned_quad *q,      // output: quad to draw
Ivan Mahonin b53a5c
                               int align_to_integer);
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
STBTT_DEF int  stbtt_PackFontRangesGatherRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects);
Ivan Mahonin b53a5c
STBTT_DEF void stbtt_PackFontRangesPackRects(stbtt_pack_context *spc, stbrp_rect *rects, int num_rects);
Ivan Mahonin b53a5c
STBTT_DEF int  stbtt_PackFontRangesRenderIntoRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects);
Ivan Mahonin b53a5c
// Calling these functions in sequence is roughly equivalent to calling
Ivan Mahonin b53a5c
// stbtt_PackFontRanges(). If you more control over the packing of multiple
Ivan Mahonin b53a5c
// fonts, or if you want to pack custom data into a font texture, take a look
Ivan Mahonin b53a5c
// at the source to of stbtt_PackFontRanges() and create a custom version
Ivan Mahonin b53a5c
// using these functions, e.g. call GatherRects multiple times,
Ivan Mahonin b53a5c
// building up a single array of rects, then call PackRects once,
Ivan Mahonin b53a5c
// then call RenderIntoRects repeatedly. This may result in a
Ivan Mahonin b53a5c
// better packing than calling PackFontRanges multiple times
Ivan Mahonin b53a5c
// (or it may not).
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
// this is an opaque structure that you shouldn't mess with which holds
Ivan Mahonin b53a5c
// all the context needed from PackBegin to PackEnd.
Ivan Mahonin b53a5c
struct stbtt_pack_context {
Ivan Mahonin b53a5c
   void *user_allocator_context;
Ivan Mahonin b53a5c
   void *pack_info;
Ivan Mahonin b53a5c
   int   width;
Ivan Mahonin b53a5c
   int   height;
Ivan Mahonin b53a5c
   int   stride_in_bytes;
Ivan Mahonin b53a5c
   int   padding;
Ivan Mahonin b53a5c
   int   skip_missing;
Ivan Mahonin b53a5c
   unsigned int   h_oversample, v_oversample;
Ivan Mahonin b53a5c
   unsigned char *pixels;
Ivan Mahonin b53a5c
   void  *nodes;
Ivan Mahonin b53a5c
};
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
//////////////////////////////////////////////////////////////////////////////
Ivan Mahonin b53a5c
//
Ivan Mahonin b53a5c
// FONT LOADING
Ivan Mahonin b53a5c
//
Ivan Mahonin b53a5c
//
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
STBTT_DEF int stbtt_GetNumberOfFonts(const unsigned char *data);
Ivan Mahonin b53a5c
// This function will determine the number of fonts in a font file.  TrueType
Ivan Mahonin b53a5c
// collection (.ttc) files may contain multiple fonts, while TrueType font
Ivan Mahonin b53a5c
// (.ttf) files only contain one font. The number of fonts can be used for
Ivan Mahonin b53a5c
// indexing with the previous function where the index is between zero and one
Ivan Mahonin b53a5c
// less than the total fonts. If an error occurs, -1 is returned.
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
STBTT_DEF int stbtt_GetFontOffsetForIndex(const unsigned char *data, int index);
Ivan Mahonin b53a5c
// Each .ttf/.ttc file may have more than one font. Each font has a sequential
Ivan Mahonin b53a5c
// index number starting from 0. Call this function to get the font offset for
Ivan Mahonin b53a5c
// a given index; it returns -1 if the index is out of range. A regular .ttf
Ivan Mahonin b53a5c
// file will only define one font and it always be at offset 0, so it will
Ivan Mahonin b53a5c
// return '0' for index 0, and -1 for all other indices.
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
// The following structure is defined publicly so you can declare one on
Ivan Mahonin b53a5c
// the stack or as a global or etc, but you should treat it as opaque.
Ivan Mahonin b53a5c
struct stbtt_fontinfo
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   void           * userdata;
Ivan Mahonin b53a5c
   unsigned char  * data;              // pointer to .ttf file
Ivan Mahonin b53a5c
   int              fontstart;         // offset of start of font
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   int numGlyphs;                     // number of glyphs, needed for range checking
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   int loca,head,glyf,hhea,hmtx,kern,gpos,svg; // table locations as offset from start of .ttf
Ivan Mahonin b53a5c
   int index_map;                     // a cmap mapping for our chosen character encoding
Ivan Mahonin b53a5c
   int indexToLocFormat;              // format needed to map from glyph index to glyph
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   stbtt__buf cff;                    // cff font data
Ivan Mahonin b53a5c
   stbtt__buf charstrings;            // the charstring index
Ivan Mahonin b53a5c
   stbtt__buf gsubrs;                 // global charstring subroutines index
Ivan Mahonin b53a5c
   stbtt__buf subrs;                  // private charstring subroutines index
Ivan Mahonin b53a5c
   stbtt__buf fontdicts;              // array of font dicts
Ivan Mahonin b53a5c
   stbtt__buf fdselect;               // map from glyph to fontdict
Ivan Mahonin b53a5c
};
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
STBTT_DEF int stbtt_InitFont(stbtt_fontinfo *info, const unsigned char *data, int offset);
Ivan Mahonin b53a5c
// Given an offset into the file that defines a font, this function builds
Ivan Mahonin b53a5c
// the necessary cached info for the rest of the system. You must allocate
Ivan Mahonin b53a5c
// the stbtt_fontinfo yourself, and stbtt_InitFont will fill it out. You don't
Ivan Mahonin b53a5c
// need to do anything special to free it, because the contents are pure
Ivan Mahonin b53a5c
// value data with no additional data structures. Returns 0 on failure.
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
//////////////////////////////////////////////////////////////////////////////
Ivan Mahonin b53a5c
//
Ivan Mahonin b53a5c
// CHARACTER TO GLYPH-INDEX CONVERSIOn
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
STBTT_DEF int stbtt_FindGlyphIndex(const stbtt_fontinfo *info, int unicode_codepoint);
Ivan Mahonin b53a5c
// If you're going to perform multiple operations on the same character
Ivan Mahonin b53a5c
// and you want a speed-up, call this function with the character you're
Ivan Mahonin b53a5c
// going to process, then use glyph-based functions instead of the
Ivan Mahonin b53a5c
// codepoint-based functions.
Ivan Mahonin b53a5c
// Returns 0 if the character codepoint is not defined in the font.
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
//////////////////////////////////////////////////////////////////////////////
Ivan Mahonin b53a5c
//
Ivan Mahonin b53a5c
// CHARACTER PROPERTIES
Ivan Mahonin b53a5c
//
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
STBTT_DEF float stbtt_ScaleForPixelHeight(const stbtt_fontinfo *info, float pixels);
Ivan Mahonin b53a5c
// computes a scale factor to produce a font whose "height" is 'pixels' tall.
Ivan Mahonin b53a5c
// Height is measured as the distance from the highest ascender to the lowest
Ivan Mahonin b53a5c
// descender; in other words, it's equivalent to calling stbtt_GetFontVMetrics
Ivan Mahonin b53a5c
// and computing:
Ivan Mahonin b53a5c
//       scale = pixels / (ascent - descent)
Ivan Mahonin b53a5c
// so if you prefer to measure height by the ascent only, use a similar calculation.
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
STBTT_DEF float stbtt_ScaleForMappingEmToPixels(const stbtt_fontinfo *info, float pixels);
Ivan Mahonin b53a5c
// computes a scale factor to produce a font whose EM size is mapped to
Ivan Mahonin b53a5c
// 'pixels' tall. This is probably what traditional APIs compute, but
Ivan Mahonin b53a5c
// I'm not positive.
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
STBTT_DEF void stbtt_GetFontVMetrics(const stbtt_fontinfo *info, int *ascent, int *descent, int *lineGap);
Ivan Mahonin b53a5c
// ascent is the coordinate above the baseline the font extends; descent
Ivan Mahonin b53a5c
// is the coordinate below the baseline the font extends (i.e. it is typically negative)
Ivan Mahonin b53a5c
// lineGap is the spacing between one row's descent and the next row's ascent...
Ivan Mahonin b53a5c
// so you should advance the vertical position by "*ascent - *descent + *lineGap"
Ivan Mahonin b53a5c
//   these are expressed in unscaled coordinates, so you must multiply by
Ivan Mahonin b53a5c
//   the scale factor for a given size
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
STBTT_DEF int  stbtt_GetFontVMetricsOS2(const stbtt_fontinfo *info, int *typoAscent, int *typoDescent, int *typoLineGap);
Ivan Mahonin b53a5c
// analogous to GetFontVMetrics, but returns the "typographic" values from the OS/2
Ivan Mahonin b53a5c
// table (specific to MS/Windows TTF files).
Ivan Mahonin b53a5c
//
Ivan Mahonin b53a5c
// Returns 1 on success (table present), 0 on failure.
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
STBTT_DEF void stbtt_GetFontBoundingBox(const stbtt_fontinfo *info, int *x0, int *y0, int *x1, int *y1);
Ivan Mahonin b53a5c
// the bounding box around all possible characters
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
STBTT_DEF void stbtt_GetCodepointHMetrics(const stbtt_fontinfo *info, int codepoint, int *advanceWidth, int *leftSideBearing);
Ivan Mahonin b53a5c
// leftSideBearing is the offset from the current horizontal position to the left edge of the character
Ivan Mahonin b53a5c
// advanceWidth is the offset from the current horizontal position to the next horizontal position
Ivan Mahonin b53a5c
//   these are expressed in unscaled coordinates
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
STBTT_DEF int  stbtt_GetCodepointKernAdvance(const stbtt_fontinfo *info, int ch1, int ch2);
Ivan Mahonin b53a5c
// an additional amount to add to the 'advance' value between ch1 and ch2
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
STBTT_DEF int stbtt_GetCodepointBox(const stbtt_fontinfo *info, int codepoint, int *x0, int *y0, int *x1, int *y1);
Ivan Mahonin b53a5c
// Gets the bounding box of the visible part of the glyph, in unscaled coordinates
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
STBTT_DEF void stbtt_GetGlyphHMetrics(const stbtt_fontinfo *info, int glyph_index, int *advanceWidth, int *leftSideBearing);
Ivan Mahonin b53a5c
STBTT_DEF int  stbtt_GetGlyphKernAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2);
Ivan Mahonin b53a5c
STBTT_DEF int  stbtt_GetGlyphBox(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1);
Ivan Mahonin b53a5c
// as above, but takes one or more glyph indices for greater efficiency
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
typedef struct stbtt_kerningentry
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   int glyph1; // use stbtt_FindGlyphIndex
Ivan Mahonin b53a5c
   int glyph2;
Ivan Mahonin b53a5c
   int advance;
Ivan Mahonin b53a5c
} stbtt_kerningentry;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
STBTT_DEF int  stbtt_GetKerningTableLength(const stbtt_fontinfo *info);
Ivan Mahonin b53a5c
STBTT_DEF int  stbtt_GetKerningTable(const stbtt_fontinfo *info, stbtt_kerningentry* table, int table_length);
Ivan Mahonin b53a5c
// Retrieves a complete list of all of the kerning pairs provided by the font
Ivan Mahonin b53a5c
// stbtt_GetKerningTable never writes more than table_length entries and returns how many entries it did write.
Ivan Mahonin b53a5c
// The table will be sorted by (a.glyph1 == b.glyph1)?(a.glyph2 < b.glyph2):(a.glyph1 < b.glyph1)
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
//////////////////////////////////////////////////////////////////////////////
Ivan Mahonin b53a5c
//
Ivan Mahonin b53a5c
// GLYPH SHAPES (you probably don't need these, but they have to go before
Ivan Mahonin b53a5c
// the bitmaps for C declaration-order reasons)
Ivan Mahonin b53a5c
//
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
#ifndef STBTT_vmove // you can predefine these to use different values (but why?)
Ivan Mahonin b53a5c
   enum {
Ivan Mahonin b53a5c
      STBTT_vmove=1,
Ivan Mahonin b53a5c
      STBTT_vline,
Ivan Mahonin b53a5c
      STBTT_vcurve,
Ivan Mahonin b53a5c
      STBTT_vcubic
Ivan Mahonin b53a5c
   };
Ivan Mahonin b53a5c
#endif
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
#ifndef stbtt_vertex // you can predefine this to use different values
Ivan Mahonin b53a5c
                   // (we share this with other code at RAD)
Ivan Mahonin b53a5c
   #define stbtt_vertex_type short // can't use stbtt_int16 because that's not visible in the header file
Ivan Mahonin b53a5c
   typedef struct
Ivan Mahonin b53a5c
   {
Ivan Mahonin b53a5c
      stbtt_vertex_type x,y,cx,cy,cx1,cy1;
Ivan Mahonin b53a5c
      unsigned char type,padding;
Ivan Mahonin b53a5c
   } stbtt_vertex;
Ivan Mahonin b53a5c
#endif
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
STBTT_DEF int stbtt_IsGlyphEmpty(const stbtt_fontinfo *info, int glyph_index);
Ivan Mahonin b53a5c
// returns non-zero if nothing is drawn for this glyph
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
STBTT_DEF int stbtt_GetCodepointShape(const stbtt_fontinfo *info, int unicode_codepoint, stbtt_vertex **vertices);
Ivan Mahonin b53a5c
STBTT_DEF int stbtt_GetGlyphShape(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **vertices);
Ivan Mahonin b53a5c
// returns # of vertices and fills *vertices with the pointer to them
Ivan Mahonin b53a5c
//   these are expressed in "unscaled" coordinates
Ivan Mahonin b53a5c
//
Ivan Mahonin b53a5c
// The shape is a series of contours. Each one starts with
Ivan Mahonin b53a5c
// a STBTT_moveto, then consists of a series of mixed
Ivan Mahonin b53a5c
// STBTT_lineto and STBTT_curveto segments. A lineto
Ivan Mahonin b53a5c
// draws a line from previous endpoint to its x,y; a curveto
Ivan Mahonin b53a5c
// draws a quadratic bezier from previous endpoint to
Ivan Mahonin b53a5c
// its x,y, using cx,cy as the bezier control point.
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
STBTT_DEF void stbtt_FreeShape(const stbtt_fontinfo *info, stbtt_vertex *vertices);
Ivan Mahonin b53a5c
// frees the data allocated above
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
STBTT_DEF unsigned char *stbtt_FindSVGDoc(const stbtt_fontinfo *info, int gl);
Ivan Mahonin b53a5c
STBTT_DEF int stbtt_GetCodepointSVG(const stbtt_fontinfo *info, int unicode_codepoint, const char **svg);
Ivan Mahonin b53a5c
STBTT_DEF int stbtt_GetGlyphSVG(const stbtt_fontinfo *info, int gl, const char **svg);
Ivan Mahonin b53a5c
// fills svg with the character's SVG data.
Ivan Mahonin b53a5c
// returns data size or 0 if SVG not found.
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
//////////////////////////////////////////////////////////////////////////////
Ivan Mahonin b53a5c
//
Ivan Mahonin b53a5c
// BITMAP RENDERING
Ivan Mahonin b53a5c
//
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
STBTT_DEF void stbtt_FreeBitmap(unsigned char *bitmap, void *userdata);
Ivan Mahonin b53a5c
// frees the bitmap allocated below
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
STBTT_DEF unsigned char *stbtt_GetCodepointBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int codepoint, int *width, int *height, int *xoff, int *yoff);
Ivan Mahonin b53a5c
// allocates a large-enough single-channel 8bpp bitmap and renders the
Ivan Mahonin b53a5c
// specified character/glyph at the specified scale into it, with
Ivan Mahonin b53a5c
// antialiasing. 0 is no coverage (transparent), 255 is fully covered (opaque).
Ivan Mahonin b53a5c
// *width & *height are filled out with the width & height of the bitmap,
Ivan Mahonin b53a5c
// which is stored left-to-right, top-to-bottom.
Ivan Mahonin b53a5c
//
Ivan Mahonin b53a5c
// xoff/yoff are the offset it pixel space from the glyph origin to the top-left of the bitmap
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
STBTT_DEF unsigned char *stbtt_GetCodepointBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint, int *width, int *height, int *xoff, int *yoff);
Ivan Mahonin b53a5c
// the same as stbtt_GetCodepoitnBitmap, but you can specify a subpixel
Ivan Mahonin b53a5c
// shift for the character
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
STBTT_DEF void stbtt_MakeCodepointBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int codepoint);
Ivan Mahonin b53a5c
// the same as stbtt_GetCodepointBitmap, but you pass in storage for the bitmap
Ivan Mahonin b53a5c
// in the form of 'output', with row spacing of 'out_stride' bytes. the bitmap
Ivan Mahonin b53a5c
// is clipped to out_w/out_h bytes. Call stbtt_GetCodepointBitmapBox to get the
Ivan Mahonin b53a5c
// width and height and positioning info for it first.
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
STBTT_DEF void stbtt_MakeCodepointBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint);
Ivan Mahonin b53a5c
// same as stbtt_MakeCodepointBitmap, but you can specify a subpixel
Ivan Mahonin b53a5c
// shift for the character
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
STBTT_DEF void stbtt_MakeCodepointBitmapSubpixelPrefilter(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int oversample_x, int oversample_y, float *sub_x, float *sub_y, int codepoint);
Ivan Mahonin b53a5c
// same as stbtt_MakeCodepointBitmapSubpixel, but prefiltering
Ivan Mahonin b53a5c
// is performed (see stbtt_PackSetOversampling)
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
STBTT_DEF void stbtt_GetCodepointBitmapBox(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1);
Ivan Mahonin b53a5c
// get the bbox of the bitmap centered around the glyph origin; so the
Ivan Mahonin b53a5c
// bitmap width is ix1-ix0, height is iy1-iy0, and location to place
Ivan Mahonin b53a5c
// the bitmap top left is (leftSideBearing*scale,iy0).
Ivan Mahonin b53a5c
// (Note that the bitmap uses y-increases-down, but the shape uses
Ivan Mahonin b53a5c
// y-increases-up, so CodepointBitmapBox and CodepointBox are inverted.)
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
STBTT_DEF void stbtt_GetCodepointBitmapBoxSubpixel(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1);
Ivan Mahonin b53a5c
// same as stbtt_GetCodepointBitmapBox, but you can specify a subpixel
Ivan Mahonin b53a5c
// shift for the character
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
// the following functions are equivalent to the above functions, but operate
Ivan Mahonin b53a5c
// on glyph indices instead of Unicode codepoints (for efficiency)
Ivan Mahonin b53a5c
STBTT_DEF unsigned char *stbtt_GetGlyphBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int glyph, int *width, int *height, int *xoff, int *yoff);
Ivan Mahonin b53a5c
STBTT_DEF unsigned char *stbtt_GetGlyphBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int glyph, int *width, int *height, int *xoff, int *yoff);
Ivan Mahonin b53a5c
STBTT_DEF void stbtt_MakeGlyphBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int glyph);
Ivan Mahonin b53a5c
STBTT_DEF void stbtt_MakeGlyphBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int glyph);
Ivan Mahonin b53a5c
STBTT_DEF void stbtt_MakeGlyphBitmapSubpixelPrefilter(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int oversample_x, int oversample_y, float *sub_x, float *sub_y, int glyph);
Ivan Mahonin b53a5c
STBTT_DEF void stbtt_GetGlyphBitmapBox(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1);
Ivan Mahonin b53a5c
STBTT_DEF void stbtt_GetGlyphBitmapBoxSubpixel(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y,float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1);
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
// @TODO: don't expose this structure
Ivan Mahonin b53a5c
typedef struct
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   int w,h,stride;
Ivan Mahonin b53a5c
   unsigned char *pixels;
Ivan Mahonin b53a5c
} stbtt__bitmap;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
// rasterize a shape with quadratic beziers into a bitmap
Ivan Mahonin b53a5c
STBTT_DEF void stbtt_Rasterize(stbtt__bitmap *result,        // 1-channel bitmap to draw into
Ivan Mahonin b53a5c
                               float flatness_in_pixels,     // allowable error of curve in pixels
Ivan Mahonin b53a5c
                               stbtt_vertex *vertices,       // array of vertices defining shape
Ivan Mahonin b53a5c
                               int num_verts,                // number of vertices in above array
Ivan Mahonin b53a5c
                               float scale_x, float scale_y, // scale applied to input vertices
Ivan Mahonin b53a5c
                               float shift_x, float shift_y, // translation applied to input vertices
Ivan Mahonin b53a5c
                               int x_off, int y_off,         // another translation applied to input
Ivan Mahonin b53a5c
                               int invert,                   // if non-zero, vertically flip shape
Ivan Mahonin b53a5c
                               void *userdata);              // context for to STBTT_MALLOC
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
//////////////////////////////////////////////////////////////////////////////
Ivan Mahonin b53a5c
//
Ivan Mahonin b53a5c
// Signed Distance Function (or Field) rendering
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
STBTT_DEF void stbtt_FreeSDF(unsigned char *bitmap, void *userdata);
Ivan Mahonin b53a5c
// frees the SDF bitmap allocated below
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
STBTT_DEF unsigned char * stbtt_GetGlyphSDF(const stbtt_fontinfo *info, float scale, int glyph, int padding, unsigned char onedge_value, float pixel_dist_scale, int *width, int *height, int *xoff, int *yoff);
Ivan Mahonin b53a5c
STBTT_DEF unsigned char * stbtt_GetCodepointSDF(const stbtt_fontinfo *info, float scale, int codepoint, int padding, unsigned char onedge_value, float pixel_dist_scale, int *width, int *height, int *xoff, int *yoff);
Ivan Mahonin b53a5c
// These functions compute a discretized SDF field for a single character, suitable for storing
Ivan Mahonin b53a5c
// in a single-channel texture, sampling with bilinear filtering, and testing against
Ivan Mahonin b53a5c
// larger than some threshold to produce scalable fonts.
Ivan Mahonin b53a5c
//        info              --  the font
Ivan Mahonin b53a5c
//        scale             --  controls the size of the resulting SDF bitmap, same as it would be creating a regular bitmap
Ivan Mahonin b53a5c
//        glyph/codepoint   --  the character to generate the SDF for
Ivan Mahonin b53a5c
//        padding           --  extra "pixels" around the character which are filled with the distance to the character (not 0),
Ivan Mahonin b53a5c
//                                 which allows effects like bit outlines
Ivan Mahonin b53a5c
//        onedge_value      --  value 0-255 to test the SDF against to reconstruct the character (i.e. the isocontour of the character)
Ivan Mahonin b53a5c
//        pixel_dist_scale  --  what value the SDF should increase by when moving one SDF "pixel" away from the edge (on the 0..255 scale)
Ivan Mahonin b53a5c
//                                 if positive, > onedge_value is inside; if negative, < onedge_value is inside
Ivan Mahonin b53a5c
//        width,height      --  output height & width of the SDF bitmap (including padding)
Ivan Mahonin b53a5c
//        xoff,yoff         --  output origin of the character
Ivan Mahonin b53a5c
//        return value      --  a 2D array of bytes 0..255, width*height in size
Ivan Mahonin b53a5c
//
Ivan Mahonin b53a5c
// pixel_dist_scale & onedge_value are a scale & bias that allows you to make
Ivan Mahonin b53a5c
// optimal use of the limited 0..255 for your application, trading off precision
Ivan Mahonin b53a5c
// and special effects. SDF values outside the range 0..255 are clamped to 0..255.
Ivan Mahonin b53a5c
//
Ivan Mahonin b53a5c
// Example:
Ivan Mahonin b53a5c
//      scale = stbtt_ScaleForPixelHeight(22)
Ivan Mahonin b53a5c
//      padding = 5
Ivan Mahonin b53a5c
//      onedge_value = 180
Ivan Mahonin b53a5c
//      pixel_dist_scale = 180/5.0 = 36.0
Ivan Mahonin b53a5c
//
Ivan Mahonin b53a5c
//      This will create an SDF bitmap in which the character is about 22 pixels
Ivan Mahonin b53a5c
//      high but the whole bitmap is about 22+5+5=32 pixels high. To produce a filled
Ivan Mahonin b53a5c
//      shape, sample the SDF at each pixel and fill the pixel if the SDF value
Ivan Mahonin b53a5c
//      is greater than or equal to 180/255. (You'll actually want to antialias,
Ivan Mahonin b53a5c
//      which is beyond the scope of this example.) Additionally, you can compute
Ivan Mahonin b53a5c
//      offset outlines (e.g. to stroke the character border inside & outside,
Ivan Mahonin b53a5c
//      or only outside). For example, to fill outside the character up to 3 SDF
Ivan Mahonin b53a5c
//      pixels, you would compare against (180-36.0*3)/255 = 72/255. The above
Ivan Mahonin b53a5c
//      choice of variables maps a range from 5 pixels outside the shape to
Ivan Mahonin b53a5c
//      2 pixels inside the shape to 0..255; this is intended primarily for apply
Ivan Mahonin b53a5c
//      outside effects only (the interior range is needed to allow proper
Ivan Mahonin b53a5c
//      antialiasing of the font at *smaller* sizes)
Ivan Mahonin b53a5c
//
Ivan Mahonin b53a5c
// The function computes the SDF analytically at each SDF pixel, not by e.g.
Ivan Mahonin b53a5c
// building a higher-res bitmap and approximating it. In theory the quality
Ivan Mahonin b53a5c
// should be as high as possible for an SDF of this size & representation, but
Ivan Mahonin b53a5c
// unclear if this is true in practice (perhaps building a higher-res bitmap
Ivan Mahonin b53a5c
// and computing from that can allow drop-out prevention).
Ivan Mahonin b53a5c
//
Ivan Mahonin b53a5c
// The algorithm has not been optimized at all, so expect it to be slow
Ivan Mahonin b53a5c
// if computing lots of characters or very large sizes.
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
//////////////////////////////////////////////////////////////////////////////
Ivan Mahonin b53a5c
//
Ivan Mahonin b53a5c
// Finding the right font...
Ivan Mahonin b53a5c
//
Ivan Mahonin b53a5c
// You should really just solve this offline, keep your own tables
Ivan Mahonin b53a5c
// of what font is what, and don't try to get it out of the .ttf file.
Ivan Mahonin b53a5c
// That's because getting it out of the .ttf file is really hard, because
Ivan Mahonin b53a5c
// the names in the file can appear in many possible encodings, in many
Ivan Mahonin b53a5c
// possible languages, and e.g. if you need a case-insensitive comparison,
Ivan Mahonin b53a5c
// the details of that depend on the encoding & language in a complex way
Ivan Mahonin b53a5c
// (actually underspecified in truetype, but also gigantic).
Ivan Mahonin b53a5c
//
Ivan Mahonin b53a5c
// But you can use the provided functions in two possible ways:
Ivan Mahonin b53a5c
//     stbtt_FindMatchingFont() will use *case-sensitive* comparisons on
Ivan Mahonin b53a5c
//             unicode-encoded names to try to find the font you want;
Ivan Mahonin b53a5c
//             you can run this before calling stbtt_InitFont()
Ivan Mahonin b53a5c
//
Ivan Mahonin b53a5c
//     stbtt_GetFontNameString() lets you get any of the various strings
Ivan Mahonin b53a5c
//             from the file yourself and do your own comparisons on them.
Ivan Mahonin b53a5c
//             You have to have called stbtt_InitFont() first.
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
STBTT_DEF int stbtt_FindMatchingFont(const unsigned char *fontdata, const char *name, int flags);
Ivan Mahonin b53a5c
// returns the offset (not index) of the font that matches, or -1 if none
Ivan Mahonin b53a5c
//   if you use STBTT_MACSTYLE_DONTCARE, use a font name like "Arial Bold".
Ivan Mahonin b53a5c
//   if you use any other flag, use a font name like "Arial"; this checks
Ivan Mahonin b53a5c
//     the 'macStyle' header field; i don't know if fonts set this consistently
Ivan Mahonin b53a5c
#define STBTT_MACSTYLE_DONTCARE     0
Ivan Mahonin b53a5c
#define STBTT_MACSTYLE_BOLD         1
Ivan Mahonin b53a5c
#define STBTT_MACSTYLE_ITALIC       2
Ivan Mahonin b53a5c
#define STBTT_MACSTYLE_UNDERSCORE   4
Ivan Mahonin b53a5c
#define STBTT_MACSTYLE_NONE         8   // <= not same as 0, this makes us check the bitfield is 0
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
STBTT_DEF int stbtt_CompareUTF8toUTF16_bigendian(const char *s1, int len1, const char *s2, int len2);
Ivan Mahonin b53a5c
// returns 1/0 whether the first string interpreted as utf8 is identical to
Ivan Mahonin b53a5c
// the second string interpreted as big-endian utf16... useful for strings from next func
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
STBTT_DEF const char *stbtt_GetFontNameString(const stbtt_fontinfo *font, int *length, int platformID, int encodingID, int languageID, int nameID);
Ivan Mahonin b53a5c
// returns the string (which may be big-endian double byte, e.g. for unicode)
Ivan Mahonin b53a5c
// and puts the length in bytes in *length.
Ivan Mahonin b53a5c
//
Ivan Mahonin b53a5c
// some of the values for the IDs are below; for more see the truetype spec:
Ivan Mahonin b53a5c
//     http://developer.apple.com/textfonts/TTRefMan/RM06/Chap6name.html
Ivan Mahonin b53a5c
//     http://www.microsoft.com/typography/otspec/name.htm
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
enum { // platformID
Ivan Mahonin b53a5c
   STBTT_PLATFORM_ID_UNICODE   =0,
Ivan Mahonin b53a5c
   STBTT_PLATFORM_ID_MAC       =1,
Ivan Mahonin b53a5c
   STBTT_PLATFORM_ID_ISO       =2,
Ivan Mahonin b53a5c
   STBTT_PLATFORM_ID_MICROSOFT =3
Ivan Mahonin b53a5c
};
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
enum { // encodingID for STBTT_PLATFORM_ID_UNICODE
Ivan Mahonin b53a5c
   STBTT_UNICODE_EID_UNICODE_1_0    =0,
Ivan Mahonin b53a5c
   STBTT_UNICODE_EID_UNICODE_1_1    =1,
Ivan Mahonin b53a5c
   STBTT_UNICODE_EID_ISO_10646      =2,
Ivan Mahonin b53a5c
   STBTT_UNICODE_EID_UNICODE_2_0_BMP=3,
Ivan Mahonin b53a5c
   STBTT_UNICODE_EID_UNICODE_2_0_FULL=4
Ivan Mahonin b53a5c
};
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
enum { // encodingID for STBTT_PLATFORM_ID_MICROSOFT
Ivan Mahonin b53a5c
   STBTT_MS_EID_SYMBOL        =0,
Ivan Mahonin b53a5c
   STBTT_MS_EID_UNICODE_BMP   =1,
Ivan Mahonin b53a5c
   STBTT_MS_EID_SHIFTJIS      =2,
Ivan Mahonin b53a5c
   STBTT_MS_EID_UNICODE_FULL  =10
Ivan Mahonin b53a5c
};
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
enum { // encodingID for STBTT_PLATFORM_ID_MAC; same as Script Manager codes
Ivan Mahonin b53a5c
   STBTT_MAC_EID_ROMAN        =0,   STBTT_MAC_EID_ARABIC       =4,
Ivan Mahonin b53a5c
   STBTT_MAC_EID_JAPANESE     =1,   STBTT_MAC_EID_HEBREW       =5,
Ivan Mahonin b53a5c
   STBTT_MAC_EID_CHINESE_TRAD =2,   STBTT_MAC_EID_GREEK        =6,
Ivan Mahonin b53a5c
   STBTT_MAC_EID_KOREAN       =3,   STBTT_MAC_EID_RUSSIAN      =7
Ivan Mahonin b53a5c
};
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
enum { // languageID for STBTT_PLATFORM_ID_MICROSOFT; same as LCID...
Ivan Mahonin b53a5c
       // problematic because there are e.g. 16 english LCIDs and 16 arabic LCIDs
Ivan Mahonin b53a5c
   STBTT_MS_LANG_ENGLISH     =0x0409,   STBTT_MS_LANG_ITALIAN     =0x0410,
Ivan Mahonin b53a5c
   STBTT_MS_LANG_CHINESE     =0x0804,   STBTT_MS_LANG_JAPANESE    =0x0411,
Ivan Mahonin b53a5c
   STBTT_MS_LANG_DUTCH       =0x0413,   STBTT_MS_LANG_KOREAN      =0x0412,
Ivan Mahonin b53a5c
   STBTT_MS_LANG_FRENCH      =0x040c,   STBTT_MS_LANG_RUSSIAN     =0x0419,
Ivan Mahonin b53a5c
   STBTT_MS_LANG_GERMAN      =0x0407,   STBTT_MS_LANG_SPANISH     =0x0409,
Ivan Mahonin b53a5c
   STBTT_MS_LANG_HEBREW      =0x040d,   STBTT_MS_LANG_SWEDISH     =0x041D
Ivan Mahonin b53a5c
};
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
enum { // languageID for STBTT_PLATFORM_ID_MAC
Ivan Mahonin b53a5c
   STBTT_MAC_LANG_ENGLISH      =0 ,   STBTT_MAC_LANG_JAPANESE     =11,
Ivan Mahonin b53a5c
   STBTT_MAC_LANG_ARABIC       =12,   STBTT_MAC_LANG_KOREAN       =23,
Ivan Mahonin b53a5c
   STBTT_MAC_LANG_DUTCH        =4 ,   STBTT_MAC_LANG_RUSSIAN      =32,
Ivan Mahonin b53a5c
   STBTT_MAC_LANG_FRENCH       =1 ,   STBTT_MAC_LANG_SPANISH      =6 ,
Ivan Mahonin b53a5c
   STBTT_MAC_LANG_GERMAN       =2 ,   STBTT_MAC_LANG_SWEDISH      =5 ,
Ivan Mahonin b53a5c
   STBTT_MAC_LANG_HEBREW       =10,   STBTT_MAC_LANG_CHINESE_SIMPLIFIED =33,
Ivan Mahonin b53a5c
   STBTT_MAC_LANG_ITALIAN      =3 ,   STBTT_MAC_LANG_CHINESE_TRAD =19
Ivan Mahonin b53a5c
};
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
#ifdef __cplusplus
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
#endif
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
#endif // __STB_INCLUDE_STB_TRUETYPE_H__
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
///////////////////////////////////////////////////////////////////////////////
Ivan Mahonin b53a5c
///////////////////////////////////////////////////////////////////////////////
Ivan Mahonin b53a5c
////
Ivan Mahonin b53a5c
////   IMPLEMENTATION
Ivan Mahonin b53a5c
////
Ivan Mahonin b53a5c
////
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
#ifdef STB_TRUETYPE_IMPLEMENTATION
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
#ifndef STBTT_MAX_OVERSAMPLE
Ivan Mahonin b53a5c
#define STBTT_MAX_OVERSAMPLE   8
Ivan Mahonin b53a5c
#endif
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
#if STBTT_MAX_OVERSAMPLE > 255
Ivan Mahonin b53a5c
#error "STBTT_MAX_OVERSAMPLE cannot be > 255"
Ivan Mahonin b53a5c
#endif
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
typedef int stbtt__test_oversample_pow2[(STBTT_MAX_OVERSAMPLE & (STBTT_MAX_OVERSAMPLE-1)) == 0 ? 1 : -1];
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
#ifndef STBTT_RASTERIZER_VERSION
Ivan Mahonin b53a5c
#define STBTT_RASTERIZER_VERSION 2
Ivan Mahonin b53a5c
#endif
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
#ifdef _MSC_VER
Ivan Mahonin b53a5c
#define STBTT__NOTUSED(v)  (void)(v)
Ivan Mahonin b53a5c
#else
Ivan Mahonin b53a5c
#define STBTT__NOTUSED(v)  (void)sizeof(v)
Ivan Mahonin b53a5c
#endif
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
//////////////////////////////////////////////////////////////////////////
Ivan Mahonin b53a5c
//
Ivan Mahonin b53a5c
// stbtt__buf helpers to parse data from file
Ivan Mahonin b53a5c
//
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
static stbtt_uint8 stbtt__buf_get8(stbtt__buf *b)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   if (b->cursor >= b->size)
Ivan Mahonin b53a5c
      return 0;
Ivan Mahonin b53a5c
   return b->data[b->cursor++];
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
static stbtt_uint8 stbtt__buf_peek8(stbtt__buf *b)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   if (b->cursor >= b->size)
Ivan Mahonin b53a5c
      return 0;
Ivan Mahonin b53a5c
   return b->data[b->cursor];
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
static void stbtt__buf_seek(stbtt__buf *b, int o)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   STBTT_assert(!(o > b->size || o < 0));
Ivan Mahonin b53a5c
   b->cursor = (o > b->size || o < 0) ? b->size : o;
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
static void stbtt__buf_skip(stbtt__buf *b, int o)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   stbtt__buf_seek(b, b->cursor + o);
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
static stbtt_uint32 stbtt__buf_get(stbtt__buf *b, int n)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   stbtt_uint32 v = 0;
Ivan Mahonin b53a5c
   int i;
Ivan Mahonin b53a5c
   STBTT_assert(n >= 1 && n <= 4);
Ivan Mahonin b53a5c
   for (i = 0; i < n; i++)
Ivan Mahonin b53a5c
      v = (v << 8) | stbtt__buf_get8(b);
Ivan Mahonin b53a5c
   return v;
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
static stbtt__buf stbtt__new_buf(const void *p, size_t size)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   stbtt__buf r;
Ivan Mahonin b53a5c
   STBTT_assert(size < 0x40000000);
Ivan Mahonin b53a5c
   r.data = (stbtt_uint8*) p;
Ivan Mahonin b53a5c
   r.size = (int) size;
Ivan Mahonin b53a5c
   r.cursor = 0;
Ivan Mahonin b53a5c
   return r;
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
#define stbtt__buf_get16(b)  stbtt__buf_get((b), 2)
Ivan Mahonin b53a5c
#define stbtt__buf_get32(b)  stbtt__buf_get((b), 4)
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
static stbtt__buf stbtt__buf_range(const stbtt__buf *b, int o, int s)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   stbtt__buf r = stbtt__new_buf(NULL, 0);
Ivan Mahonin b53a5c
   if (o < 0 || s < 0 || o > b->size || s > b->size - o) return r;
Ivan Mahonin b53a5c
   r.data = b->data + o;
Ivan Mahonin b53a5c
   r.size = s;
Ivan Mahonin b53a5c
   return r;
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
static stbtt__buf stbtt__cff_get_index(stbtt__buf *b)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   int count, start, offsize;
Ivan Mahonin b53a5c
   start = b->cursor;
Ivan Mahonin b53a5c
   count = stbtt__buf_get16(b);
Ivan Mahonin b53a5c
   if (count) {
Ivan Mahonin b53a5c
      offsize = stbtt__buf_get8(b);
Ivan Mahonin b53a5c
      STBTT_assert(offsize >= 1 && offsize <= 4);
Ivan Mahonin b53a5c
      stbtt__buf_skip(b, offsize * count);
Ivan Mahonin b53a5c
      stbtt__buf_skip(b, stbtt__buf_get(b, offsize) - 1);
Ivan Mahonin b53a5c
   }
Ivan Mahonin b53a5c
   return stbtt__buf_range(b, start, b->cursor - start);
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
static stbtt_uint32 stbtt__cff_int(stbtt__buf *b)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   int b0 = stbtt__buf_get8(b);
Ivan Mahonin b53a5c
   if (b0 >= 32 && b0 <= 246)       return b0 - 139;
Ivan Mahonin b53a5c
   else if (b0 >= 247 && b0 <= 250) return (b0 - 247)*256 + stbtt__buf_get8(b) + 108;
Ivan Mahonin b53a5c
   else if (b0 >= 251 && b0 <= 254) return -(b0 - 251)*256 - stbtt__buf_get8(b) - 108;
Ivan Mahonin b53a5c
   else if (b0 == 28)               return stbtt__buf_get16(b);
Ivan Mahonin b53a5c
   else if (b0 == 29)               return stbtt__buf_get32(b);
Ivan Mahonin b53a5c
   STBTT_assert(0);
Ivan Mahonin b53a5c
   return 0;
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
static void stbtt__cff_skip_operand(stbtt__buf *b) {
Ivan Mahonin b53a5c
   int v, b0 = stbtt__buf_peek8(b);
Ivan Mahonin b53a5c
   STBTT_assert(b0 >= 28);
Ivan Mahonin b53a5c
   if (b0 == 30) {
Ivan Mahonin b53a5c
      stbtt__buf_skip(b, 1);
Ivan Mahonin b53a5c
      while (b->cursor < b->size) {
Ivan Mahonin b53a5c
         v = stbtt__buf_get8(b);
Ivan Mahonin b53a5c
         if ((v & 0xF) == 0xF || (v >> 4) == 0xF)
Ivan Mahonin b53a5c
            break;
Ivan Mahonin b53a5c
      }
Ivan Mahonin b53a5c
   } else {
Ivan Mahonin b53a5c
      stbtt__cff_int(b);
Ivan Mahonin b53a5c
   }
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
static stbtt__buf stbtt__dict_get(stbtt__buf *b, int key)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   stbtt__buf_seek(b, 0);
Ivan Mahonin b53a5c
   while (b->cursor < b->size) {
Ivan Mahonin b53a5c
      int start = b->cursor, end, op;
Ivan Mahonin b53a5c
      while (stbtt__buf_peek8(b) >= 28)
Ivan Mahonin b53a5c
         stbtt__cff_skip_operand(b);
Ivan Mahonin b53a5c
      end = b->cursor;
Ivan Mahonin b53a5c
      op = stbtt__buf_get8(b);
Ivan Mahonin b53a5c
      if (op == 12)  op = stbtt__buf_get8(b) | 0x100;
Ivan Mahonin b53a5c
      if (op == key) return stbtt__buf_range(b, start, end-start);
Ivan Mahonin b53a5c
   }
Ivan Mahonin b53a5c
   return stbtt__buf_range(b, 0, 0);
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
static void stbtt__dict_get_ints(stbtt__buf *b, int key, int outcount, stbtt_uint32 *out)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   int i;
Ivan Mahonin b53a5c
   stbtt__buf operands = stbtt__dict_get(b, key);
Ivan Mahonin b53a5c
   for (i = 0; i < outcount && operands.cursor < operands.size; i++)
Ivan Mahonin b53a5c
      out[i] = stbtt__cff_int(&operands);
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
static int stbtt__cff_index_count(stbtt__buf *b)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   stbtt__buf_seek(b, 0);
Ivan Mahonin b53a5c
   return stbtt__buf_get16(b);
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
static stbtt__buf stbtt__cff_index_get(stbtt__buf b, int i)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   int count, offsize, start, end;
Ivan Mahonin b53a5c
   stbtt__buf_seek(&b, 0);
Ivan Mahonin b53a5c
   count = stbtt__buf_get16(&b);
Ivan Mahonin b53a5c
   offsize = stbtt__buf_get8(&b);
Ivan Mahonin b53a5c
   STBTT_assert(i >= 0 && i < count);
Ivan Mahonin b53a5c
   STBTT_assert(offsize >= 1 && offsize <= 4);
Ivan Mahonin b53a5c
   stbtt__buf_skip(&b, i*offsize);
Ivan Mahonin b53a5c
   start = stbtt__buf_get(&b, offsize);
Ivan Mahonin b53a5c
   end = stbtt__buf_get(&b, offsize);
Ivan Mahonin b53a5c
   return stbtt__buf_range(&b, 2+(count+1)*offsize+start, end - start);
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
//////////////////////////////////////////////////////////////////////////
Ivan Mahonin b53a5c
//
Ivan Mahonin b53a5c
// accessors to parse data from file
Ivan Mahonin b53a5c
//
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
// on platforms that don't allow misaligned reads, if we want to allow
Ivan Mahonin b53a5c
// truetype fonts that aren't padded to alignment, define ALLOW_UNALIGNED_TRUETYPE
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
#define ttBYTE(p)     (* (stbtt_uint8 *) (p))
Ivan Mahonin b53a5c
#define ttCHAR(p)     (* (stbtt_int8 *) (p))
Ivan Mahonin b53a5c
#define ttFixed(p)    ttLONG(p)
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
static stbtt_uint16 ttUSHORT(stbtt_uint8 *p) { return p[0]*256 + p[1]; }
Ivan Mahonin b53a5c
static stbtt_int16 ttSHORT(stbtt_uint8 *p)   { return p[0]*256 + p[1]; }
Ivan Mahonin b53a5c
static stbtt_uint32 ttULONG(stbtt_uint8 *p)  { return (p[0]<<24) + (p[1]<<16) + (p[2]<<8) + p[3]; }
Ivan Mahonin b53a5c
static stbtt_int32 ttLONG(stbtt_uint8 *p)    { return (p[0]<<24) + (p[1]<<16) + (p[2]<<8) + p[3]; }
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
#define stbtt_tag4(p,c0,c1,c2,c3) ((p)[0] == (c0) && (p)[1] == (c1) && (p)[2] == (c2) && (p)[3] == (c3))
Ivan Mahonin b53a5c
#define stbtt_tag(p,str)           stbtt_tag4(p,str[0],str[1],str[2],str[3])
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
static int stbtt__isfont(stbtt_uint8 *font)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   // check the version number
Ivan Mahonin b53a5c
   if (stbtt_tag4(font, '1',0,0,0))  return 1; // TrueType 1
Ivan Mahonin b53a5c
   if (stbtt_tag(font, "typ1"))   return 1; // TrueType with type 1 font -- we don't support this!
Ivan Mahonin b53a5c
   if (stbtt_tag(font, "OTTO"))   return 1; // OpenType with CFF
Ivan Mahonin b53a5c
   if (stbtt_tag4(font, 0,1,0,0)) return 1; // OpenType 1.0
Ivan Mahonin b53a5c
   if (stbtt_tag(font, "true"))   return 1; // Apple specification for TrueType fonts
Ivan Mahonin b53a5c
   return 0;
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
// @OPTIMIZE: binary search
Ivan Mahonin b53a5c
static stbtt_uint32 stbtt__find_table(stbtt_uint8 *data, stbtt_uint32 fontstart, const char *tag)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   stbtt_int32 num_tables = ttUSHORT(data+fontstart+4);
Ivan Mahonin b53a5c
   stbtt_uint32 tabledir = fontstart + 12;
Ivan Mahonin b53a5c
   stbtt_int32 i;
Ivan Mahonin b53a5c
   for (i=0; i < num_tables; ++i) {
Ivan Mahonin b53a5c
      stbtt_uint32 loc = tabledir + 16*i;
Ivan Mahonin b53a5c
      if (stbtt_tag(data+loc+0, tag))
Ivan Mahonin b53a5c
         return ttULONG(data+loc+8);
Ivan Mahonin b53a5c
   }
Ivan Mahonin b53a5c
   return 0;
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
static int stbtt_GetFontOffsetForIndex_internal(unsigned char *font_collection, int index)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   // if it's just a font, there's only one valid index
Ivan Mahonin b53a5c
   if (stbtt__isfont(font_collection))
Ivan Mahonin b53a5c
      return index == 0 ? 0 : -1;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   // check if it's a TTC
Ivan Mahonin b53a5c
   if (stbtt_tag(font_collection, "ttcf")) {
Ivan Mahonin b53a5c
      // version 1?
Ivan Mahonin b53a5c
      if (ttULONG(font_collection+4) == 0x00010000 || ttULONG(font_collection+4) == 0x00020000) {
Ivan Mahonin b53a5c
         stbtt_int32 n = ttLONG(font_collection+8);
Ivan Mahonin b53a5c
         if (index >= n)
Ivan Mahonin b53a5c
            return -1;
Ivan Mahonin b53a5c
         return ttULONG(font_collection+12+index*4);
Ivan Mahonin b53a5c
      }
Ivan Mahonin b53a5c
   }
Ivan Mahonin b53a5c
   return -1;
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
static int stbtt_GetNumberOfFonts_internal(unsigned char *font_collection)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   // if it's just a font, there's only one valid font
Ivan Mahonin b53a5c
   if (stbtt__isfont(font_collection))
Ivan Mahonin b53a5c
      return 1;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   // check if it's a TTC
Ivan Mahonin b53a5c
   if (stbtt_tag(font_collection, "ttcf")) {
Ivan Mahonin b53a5c
      // version 1?
Ivan Mahonin b53a5c
      if (ttULONG(font_collection+4) == 0x00010000 || ttULONG(font_collection+4) == 0x00020000) {
Ivan Mahonin b53a5c
         return ttLONG(font_collection+8);
Ivan Mahonin b53a5c
      }
Ivan Mahonin b53a5c
   }
Ivan Mahonin b53a5c
   return 0;
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
static stbtt__buf stbtt__get_subrs(stbtt__buf cff, stbtt__buf fontdict)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   stbtt_uint32 subrsoff = 0, private_loc[2] = { 0, 0 };
Ivan Mahonin b53a5c
   stbtt__buf pdict;
Ivan Mahonin b53a5c
   stbtt__dict_get_ints(&fontdict, 18, 2, private_loc);
Ivan Mahonin b53a5c
   if (!private_loc[1] || !private_loc[0]) return stbtt__new_buf(NULL, 0);
Ivan Mahonin b53a5c
   pdict = stbtt__buf_range(&cff, private_loc[1], private_loc[0]);
Ivan Mahonin b53a5c
   stbtt__dict_get_ints(&pdict, 19, 1, &subrsoff);
Ivan Mahonin b53a5c
   if (!subrsoff) return stbtt__new_buf(NULL, 0);
Ivan Mahonin b53a5c
   stbtt__buf_seek(&cff, private_loc[1]+subrsoff);
Ivan Mahonin b53a5c
   return stbtt__cff_get_index(&cff);
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
// since most people won't use this, find this table the first time it's needed
Ivan Mahonin b53a5c
static int stbtt__get_svg(stbtt_fontinfo *info)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   stbtt_uint32 t;
Ivan Mahonin b53a5c
   if (info->svg < 0) {
Ivan Mahonin b53a5c
      t = stbtt__find_table(info->data, info->fontstart, "SVG ");
Ivan Mahonin b53a5c
      if (t) {
Ivan Mahonin b53a5c
         stbtt_uint32 offset = ttULONG(info->data + t + 2);
Ivan Mahonin b53a5c
         info->svg = t + offset;
Ivan Mahonin b53a5c
      } else {
Ivan Mahonin b53a5c
         info->svg = 0;
Ivan Mahonin b53a5c
      }
Ivan Mahonin b53a5c
   }
Ivan Mahonin b53a5c
   return info->svg;
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
static int stbtt_InitFont_internal(stbtt_fontinfo *info, unsigned char *data, int fontstart)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   stbtt_uint32 cmap, t;
Ivan Mahonin b53a5c
   stbtt_int32 i,numTables;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   info->data = data;
Ivan Mahonin b53a5c
   info->fontstart = fontstart;
Ivan Mahonin b53a5c
   info->cff = stbtt__new_buf(NULL, 0);
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   cmap = stbtt__find_table(data, fontstart, "cmap");       // required
Ivan Mahonin b53a5c
   info->loca = stbtt__find_table(data, fontstart, "loca"); // required
Ivan Mahonin b53a5c
   info->head = stbtt__find_table(data, fontstart, "head"); // required
Ivan Mahonin b53a5c
   info->glyf = stbtt__find_table(data, fontstart, "glyf"); // required
Ivan Mahonin b53a5c
   info->hhea = stbtt__find_table(data, fontstart, "hhea"); // required
Ivan Mahonin b53a5c
   info->hmtx = stbtt__find_table(data, fontstart, "hmtx"); // required
Ivan Mahonin b53a5c
   info->kern = stbtt__find_table(data, fontstart, "kern"); // not required
Ivan Mahonin b53a5c
   info->gpos = stbtt__find_table(data, fontstart, "GPOS"); // not required
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   if (!cmap || !info->head || !info->hhea || !info->hmtx)
Ivan Mahonin b53a5c
      return 0;
Ivan Mahonin b53a5c
   if (info->glyf) {
Ivan Mahonin b53a5c
      // required for truetype
Ivan Mahonin b53a5c
      if (!info->loca) return 0;
Ivan Mahonin b53a5c
   } else {
Ivan Mahonin b53a5c
      // initialization for CFF / Type2 fonts (OTF)
Ivan Mahonin b53a5c
      stbtt__buf b, topdict, topdictidx;
Ivan Mahonin b53a5c
      stbtt_uint32 cstype = 2, charstrings = 0, fdarrayoff = 0, fdselectoff = 0;
Ivan Mahonin b53a5c
      stbtt_uint32 cff;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
      cff = stbtt__find_table(data, fontstart, "CFF ");
Ivan Mahonin b53a5c
      if (!cff) return 0;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
      info->fontdicts = stbtt__new_buf(NULL, 0);
Ivan Mahonin b53a5c
      info->fdselect = stbtt__new_buf(NULL, 0);
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
      // @TODO this should use size from table (not 512MB)
Ivan Mahonin b53a5c
      info->cff = stbtt__new_buf(data+cff, 512*1024*1024);
Ivan Mahonin b53a5c
      b = info->cff;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
      // read the header
Ivan Mahonin b53a5c
      stbtt__buf_skip(&b, 2);
Ivan Mahonin b53a5c
      stbtt__buf_seek(&b, stbtt__buf_get8(&b)); // hdrsize
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
      // @TODO the name INDEX could list multiple fonts,
Ivan Mahonin b53a5c
      // but we just use the first one.
Ivan Mahonin b53a5c
      stbtt__cff_get_index(&b);  // name INDEX
Ivan Mahonin b53a5c
      topdictidx = stbtt__cff_get_index(&b);
Ivan Mahonin b53a5c
      topdict = stbtt__cff_index_get(topdictidx, 0);
Ivan Mahonin b53a5c
      stbtt__cff_get_index(&b);  // string INDEX
Ivan Mahonin b53a5c
      info->gsubrs = stbtt__cff_get_index(&b);
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
      stbtt__dict_get_ints(&topdict, 17, 1, &charstrings);
Ivan Mahonin b53a5c
      stbtt__dict_get_ints(&topdict, 0x100 | 6, 1, &cstype);
Ivan Mahonin b53a5c
      stbtt__dict_get_ints(&topdict, 0x100 | 36, 1, &fdarrayoff);
Ivan Mahonin b53a5c
      stbtt__dict_get_ints(&topdict, 0x100 | 37, 1, &fdselectoff);
Ivan Mahonin b53a5c
      info->subrs = stbtt__get_subrs(b, topdict);
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
      // we only support Type 2 charstrings
Ivan Mahonin b53a5c
      if (cstype != 2) return 0;
Ivan Mahonin b53a5c
      if (charstrings == 0) return 0;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
      if (fdarrayoff) {
Ivan Mahonin b53a5c
         // looks like a CID font
Ivan Mahonin b53a5c
         if (!fdselectoff) return 0;
Ivan Mahonin b53a5c
         stbtt__buf_seek(&b, fdarrayoff);
Ivan Mahonin b53a5c
         info->fontdicts = stbtt__cff_get_index(&b);
Ivan Mahonin b53a5c
         info->fdselect = stbtt__buf_range(&b, fdselectoff, b.size-fdselectoff);
Ivan Mahonin b53a5c
      }
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
      stbtt__buf_seek(&b, charstrings);
Ivan Mahonin b53a5c
      info->charstrings = stbtt__cff_get_index(&b);
Ivan Mahonin b53a5c
   }
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   t = stbtt__find_table(data, fontstart, "maxp");
Ivan Mahonin b53a5c
   if (t)
Ivan Mahonin b53a5c
      info->numGlyphs = ttUSHORT(data+t+4);
Ivan Mahonin b53a5c
   else
Ivan Mahonin b53a5c
      info->numGlyphs = 0xffff;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   info->svg = -1;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   // find a cmap encoding table we understand *now* to avoid searching
Ivan Mahonin b53a5c
   // later. (todo: could make this installable)
Ivan Mahonin b53a5c
   // the same regardless of glyph.
Ivan Mahonin b53a5c
   numTables = ttUSHORT(data + cmap + 2);
Ivan Mahonin b53a5c
   info->index_map = 0;
Ivan Mahonin b53a5c
   for (i=0; i < numTables; ++i) {
Ivan Mahonin b53a5c
      stbtt_uint32 encoding_record = cmap + 4 + 8 * i;
Ivan Mahonin b53a5c
      // find an encoding we understand:
Ivan Mahonin b53a5c
      switch(ttUSHORT(data+encoding_record)) {
Ivan Mahonin b53a5c
         case STBTT_PLATFORM_ID_MICROSOFT:
Ivan Mahonin b53a5c
            switch (ttUSHORT(data+encoding_record+2)) {
Ivan Mahonin b53a5c
               case STBTT_MS_EID_UNICODE_BMP:
Ivan Mahonin b53a5c
               case STBTT_MS_EID_UNICODE_FULL:
Ivan Mahonin b53a5c
                  // MS/Unicode
Ivan Mahonin b53a5c
                  info->index_map = cmap + ttULONG(data+encoding_record+4);
Ivan Mahonin b53a5c
                  break;
Ivan Mahonin b53a5c
            }
Ivan Mahonin b53a5c
            break;
Ivan Mahonin b53a5c
        case STBTT_PLATFORM_ID_UNICODE:
Ivan Mahonin b53a5c
            // Mac/iOS has these
Ivan Mahonin b53a5c
            // all the encodingIDs are unicode, so we don't bother to check it
Ivan Mahonin b53a5c
            info->index_map = cmap + ttULONG(data+encoding_record+4);
Ivan Mahonin b53a5c
            break;
Ivan Mahonin b53a5c
      }
Ivan Mahonin b53a5c
   }
Ivan Mahonin b53a5c
   if (info->index_map == 0)
Ivan Mahonin b53a5c
      return 0;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   info->indexToLocFormat = ttUSHORT(data+info->head + 50);
Ivan Mahonin b53a5c
   return 1;
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
STBTT_DEF int stbtt_FindGlyphIndex(const stbtt_fontinfo *info, int unicode_codepoint)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   stbtt_uint8 *data = info->data;
Ivan Mahonin b53a5c
   stbtt_uint32 index_map = info->index_map;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   stbtt_uint16 format = ttUSHORT(data + index_map + 0);
Ivan Mahonin b53a5c
   if (format == 0) { // apple byte encoding
Ivan Mahonin b53a5c
      stbtt_int32 bytes = ttUSHORT(data + index_map + 2);
Ivan Mahonin b53a5c
      if (unicode_codepoint < bytes-6)
Ivan Mahonin b53a5c
         return ttBYTE(data + index_map + 6 + unicode_codepoint);
Ivan Mahonin b53a5c
      return 0;
Ivan Mahonin b53a5c
   } else if (format == 6) {
Ivan Mahonin b53a5c
      stbtt_uint32 first = ttUSHORT(data + index_map + 6);
Ivan Mahonin b53a5c
      stbtt_uint32 count = ttUSHORT(data + index_map + 8);
Ivan Mahonin b53a5c
      if ((stbtt_uint32) unicode_codepoint >= first && (stbtt_uint32) unicode_codepoint < first+count)
Ivan Mahonin b53a5c
         return ttUSHORT(data + index_map + 10 + (unicode_codepoint - first)*2);
Ivan Mahonin b53a5c
      return 0;
Ivan Mahonin b53a5c
   } else if (format == 2) {
Ivan Mahonin b53a5c
      STBTT_assert(0); // @TODO: high-byte mapping for japanese/chinese/korean
Ivan Mahonin b53a5c
      return 0;
Ivan Mahonin b53a5c
   } else if (format == 4) { // standard mapping for windows fonts: binary search collection of ranges
Ivan Mahonin b53a5c
      stbtt_uint16 segcount = ttUSHORT(data+index_map+6) >> 1;
Ivan Mahonin b53a5c
      stbtt_uint16 searchRange = ttUSHORT(data+index_map+8) >> 1;
Ivan Mahonin b53a5c
      stbtt_uint16 entrySelector = ttUSHORT(data+index_map+10);
Ivan Mahonin b53a5c
      stbtt_uint16 rangeShift = ttUSHORT(data+index_map+12) >> 1;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
      // do a binary search of the segments
Ivan Mahonin b53a5c
      stbtt_uint32 endCount = index_map + 14;
Ivan Mahonin b53a5c
      stbtt_uint32 search = endCount;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
      if (unicode_codepoint > 0xffff)
Ivan Mahonin b53a5c
         return 0;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
      // they lie from endCount .. endCount + segCount
Ivan Mahonin b53a5c
      // but searchRange is the nearest power of two, so...
Ivan Mahonin b53a5c
      if (unicode_codepoint >= ttUSHORT(data + search + rangeShift*2))
Ivan Mahonin b53a5c
         search += rangeShift*2;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
      // now decrement to bias correctly to find smallest
Ivan Mahonin b53a5c
      search -= 2;
Ivan Mahonin b53a5c
      while (entrySelector) {
Ivan Mahonin b53a5c
         stbtt_uint16 end;
Ivan Mahonin b53a5c
         searchRange >>= 1;
Ivan Mahonin b53a5c
         end = ttUSHORT(data + search + searchRange*2);
Ivan Mahonin b53a5c
         if (unicode_codepoint > end)
Ivan Mahonin b53a5c
            search += searchRange*2;
Ivan Mahonin b53a5c
         --entrySelector;
Ivan Mahonin b53a5c
      }
Ivan Mahonin b53a5c
      search += 2;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
      {
Ivan Mahonin b53a5c
         stbtt_uint16 offset, start, last;
Ivan Mahonin b53a5c
         stbtt_uint16 item = (stbtt_uint16) ((search - endCount) >> 1);
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
         start = ttUSHORT(data + index_map + 14 + segcount*2 + 2 + 2*item);
Ivan Mahonin b53a5c
         last = ttUSHORT(data + endCount + 2*item);
Ivan Mahonin b53a5c
         if (unicode_codepoint < start || unicode_codepoint > last)
Ivan Mahonin b53a5c
            return 0;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
         offset = ttUSHORT(data + index_map + 14 + segcount*6 + 2 + 2*item);
Ivan Mahonin b53a5c
         if (offset == 0)
Ivan Mahonin b53a5c
            return (stbtt_uint16) (unicode_codepoint + ttSHORT(data + index_map + 14 + segcount*4 + 2 + 2*item));
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
         return ttUSHORT(data + offset + (unicode_codepoint-start)*2 + index_map + 14 + segcount*6 + 2 + 2*item);
Ivan Mahonin b53a5c
      }
Ivan Mahonin b53a5c
   } else if (format == 12 || format == 13) {
Ivan Mahonin b53a5c
      stbtt_uint32 ngroups = ttULONG(data+index_map+12);
Ivan Mahonin b53a5c
      stbtt_int32 low,high;
Ivan Mahonin b53a5c
      low = 0; high = (stbtt_int32)ngroups;
Ivan Mahonin b53a5c
      // Binary search the right group.
Ivan Mahonin b53a5c
      while (low < high) {
Ivan Mahonin b53a5c
         stbtt_int32 mid = low + ((high-low) >> 1); // rounds down, so low <= mid < high
Ivan Mahonin b53a5c
         stbtt_uint32 start_char = ttULONG(data+index_map+16+mid*12);
Ivan Mahonin b53a5c
         stbtt_uint32 end_char = ttULONG(data+index_map+16+mid*12+4);
Ivan Mahonin b53a5c
         if ((stbtt_uint32) unicode_codepoint < start_char)
Ivan Mahonin b53a5c
            high = mid;
Ivan Mahonin b53a5c
         else if ((stbtt_uint32) unicode_codepoint > end_char)
Ivan Mahonin b53a5c
            low = mid+1;
Ivan Mahonin b53a5c
         else {
Ivan Mahonin b53a5c
            stbtt_uint32 start_glyph = ttULONG(data+index_map+16+mid*12+8);
Ivan Mahonin b53a5c
            if (format == 12)
Ivan Mahonin b53a5c
               return start_glyph + unicode_codepoint-start_char;
Ivan Mahonin b53a5c
            else // format == 13
Ivan Mahonin b53a5c
               return start_glyph;
Ivan Mahonin b53a5c
         }
Ivan Mahonin b53a5c
      }
Ivan Mahonin b53a5c
      return 0; // not found
Ivan Mahonin b53a5c
   }
Ivan Mahonin b53a5c
   // @TODO
Ivan Mahonin b53a5c
   STBTT_assert(0);
Ivan Mahonin b53a5c
   return 0;
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
STBTT_DEF int stbtt_GetCodepointShape(const stbtt_fontinfo *info, int unicode_codepoint, stbtt_vertex **vertices)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   return stbtt_GetGlyphShape(info, stbtt_FindGlyphIndex(info, unicode_codepoint), vertices);
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
static void stbtt_setvertex(stbtt_vertex *v, stbtt_uint8 type, stbtt_int32 x, stbtt_int32 y, stbtt_int32 cx, stbtt_int32 cy)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   v->type = type;
Ivan Mahonin b53a5c
   v->x = (stbtt_int16) x;
Ivan Mahonin b53a5c
   v->y = (stbtt_int16) y;
Ivan Mahonin b53a5c
   v->cx = (stbtt_int16) cx;
Ivan Mahonin b53a5c
   v->cy = (stbtt_int16) cy;
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
static int stbtt__GetGlyfOffset(const stbtt_fontinfo *info, int glyph_index)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   int g1,g2;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   STBTT_assert(!info->cff.size);
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   if (glyph_index >= info->numGlyphs) return -1; // glyph index out of range
Ivan Mahonin b53a5c
   if (info->indexToLocFormat >= 2)    return -1; // unknown index->glyph map format
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   if (info->indexToLocFormat == 0) {
Ivan Mahonin b53a5c
      g1 = info->glyf + ttUSHORT(info->data + info->loca + glyph_index * 2) * 2;
Ivan Mahonin b53a5c
      g2 = info->glyf + ttUSHORT(info->data + info->loca + glyph_index * 2 + 2) * 2;
Ivan Mahonin b53a5c
   } else {
Ivan Mahonin b53a5c
      g1 = info->glyf + ttULONG (info->data + info->loca + glyph_index * 4);
Ivan Mahonin b53a5c
      g2 = info->glyf + ttULONG (info->data + info->loca + glyph_index * 4 + 4);
Ivan Mahonin b53a5c
   }
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   return g1==g2 ? -1 : g1; // if length is 0, return -1
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
static int stbtt__GetGlyphInfoT2(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1);
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
STBTT_DEF int stbtt_GetGlyphBox(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   if (info->cff.size) {
Ivan Mahonin b53a5c
      stbtt__GetGlyphInfoT2(info, glyph_index, x0, y0, x1, y1);
Ivan Mahonin b53a5c
   } else {
Ivan Mahonin b53a5c
      int g = stbtt__GetGlyfOffset(info, glyph_index);
Ivan Mahonin b53a5c
      if (g < 0) return 0;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
      if (x0) *x0 = ttSHORT(info->data + g + 2);
Ivan Mahonin b53a5c
      if (y0) *y0 = ttSHORT(info->data + g + 4);
Ivan Mahonin b53a5c
      if (x1) *x1 = ttSHORT(info->data + g + 6);
Ivan Mahonin b53a5c
      if (y1) *y1 = ttSHORT(info->data + g + 8);
Ivan Mahonin b53a5c
   }
Ivan Mahonin b53a5c
   return 1;
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
STBTT_DEF int stbtt_GetCodepointBox(const stbtt_fontinfo *info, int codepoint, int *x0, int *y0, int *x1, int *y1)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   return stbtt_GetGlyphBox(info, stbtt_FindGlyphIndex(info,codepoint), x0,y0,x1,y1);
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
STBTT_DEF int stbtt_IsGlyphEmpty(const stbtt_fontinfo *info, int glyph_index)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   stbtt_int16 numberOfContours;
Ivan Mahonin b53a5c
   int g;
Ivan Mahonin b53a5c
   if (info->cff.size)
Ivan Mahonin b53a5c
      return stbtt__GetGlyphInfoT2(info, glyph_index, NULL, NULL, NULL, NULL) == 0;
Ivan Mahonin b53a5c
   g = stbtt__GetGlyfOffset(info, glyph_index);
Ivan Mahonin b53a5c
   if (g < 0) return 1;
Ivan Mahonin b53a5c
   numberOfContours = ttSHORT(info->data + g);
Ivan Mahonin b53a5c
   return numberOfContours == 0;
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
static int stbtt__close_shape(stbtt_vertex *vertices, int num_vertices, int was_off, int start_off,
Ivan Mahonin b53a5c
    stbtt_int32 sx, stbtt_int32 sy, stbtt_int32 scx, stbtt_int32 scy, stbtt_int32 cx, stbtt_int32 cy)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   if (start_off) {
Ivan Mahonin b53a5c
      if (was_off)
Ivan Mahonin b53a5c
         stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, (cx+scx)>>1, (cy+scy)>>1, cx,cy);
Ivan Mahonin b53a5c
      stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, sx,sy,scx,scy);
Ivan Mahonin b53a5c
   } else {
Ivan Mahonin b53a5c
      if (was_off)
Ivan Mahonin b53a5c
         stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve,sx,sy,cx,cy);
Ivan Mahonin b53a5c
      else
Ivan Mahonin b53a5c
         stbtt_setvertex(&vertices[num_vertices++], STBTT_vline,sx,sy,0,0);
Ivan Mahonin b53a5c
   }
Ivan Mahonin b53a5c
   return num_vertices;
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
static int stbtt__GetGlyphShapeTT(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **pvertices)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   stbtt_int16 numberOfContours;
Ivan Mahonin b53a5c
   stbtt_uint8 *endPtsOfContours;
Ivan Mahonin b53a5c
   stbtt_uint8 *data = info->data;
Ivan Mahonin b53a5c
   stbtt_vertex *vertices=0;
Ivan Mahonin b53a5c
   int num_vertices=0;
Ivan Mahonin b53a5c
   int g = stbtt__GetGlyfOffset(info, glyph_index);
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   *pvertices = NULL;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   if (g < 0) return 0;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   numberOfContours = ttSHORT(data + g);
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   if (numberOfContours > 0) {
Ivan Mahonin b53a5c
      stbtt_uint8 flags=0,flagcount;
Ivan Mahonin b53a5c
      stbtt_int32 ins, i,j=0,m,n, next_move, was_off=0, off, start_off=0;
Ivan Mahonin b53a5c
      stbtt_int32 x,y,cx,cy,sx,sy, scx,scy;
Ivan Mahonin b53a5c
      stbtt_uint8 *points;
Ivan Mahonin b53a5c
      endPtsOfContours = (data + g + 10);
Ivan Mahonin b53a5c
      ins = ttUSHORT(data + g + 10 + numberOfContours * 2);
Ivan Mahonin b53a5c
      points = data + g + 10 + numberOfContours * 2 + 2 + ins;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
      n = 1+ttUSHORT(endPtsOfContours + numberOfContours*2-2);
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
      m = n + 2*numberOfContours;  // a loose bound on how many vertices we might need
Ivan Mahonin b53a5c
      vertices = (stbtt_vertex *) STBTT_malloc(m * sizeof(vertices[0]), info->userdata);
Ivan Mahonin b53a5c
      if (vertices == 0)
Ivan Mahonin b53a5c
         return 0;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
      next_move = 0;
Ivan Mahonin b53a5c
      flagcount=0;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
      // in first pass, we load uninterpreted data into the allocated array
Ivan Mahonin b53a5c
      // above, shifted to the end of the array so we won't overwrite it when
Ivan Mahonin b53a5c
      // we create our final data starting from the front
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
      off = m - n; // starting offset for uninterpreted data, regardless of how m ends up being calculated
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
      // first load flags
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
      for (i=0; i < n; ++i) {
Ivan Mahonin b53a5c
         if (flagcount == 0) {
Ivan Mahonin b53a5c
            flags = *points++;
Ivan Mahonin b53a5c
            if (flags & 8)
Ivan Mahonin b53a5c
               flagcount = *points++;
Ivan Mahonin b53a5c
         } else
Ivan Mahonin b53a5c
            --flagcount;
Ivan Mahonin b53a5c
         vertices[off+i].type = flags;
Ivan Mahonin b53a5c
      }
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
      // now load x coordinates
Ivan Mahonin b53a5c
      x=0;
Ivan Mahonin b53a5c
      for (i=0; i < n; ++i) {
Ivan Mahonin b53a5c
         flags = vertices[off+i].type;
Ivan Mahonin b53a5c
         if (flags & 2) {
Ivan Mahonin b53a5c
            stbtt_int16 dx = *points++;
Ivan Mahonin b53a5c
            x += (flags & 16) ? dx : -dx; // ???
Ivan Mahonin b53a5c
         } else {
Ivan Mahonin b53a5c
            if (!(flags & 16)) {
Ivan Mahonin b53a5c
               x = x + (stbtt_int16) (points[0]*256 + points[1]);
Ivan Mahonin b53a5c
               points += 2;
Ivan Mahonin b53a5c
            }
Ivan Mahonin b53a5c
         }
Ivan Mahonin b53a5c
         vertices[off+i].x = (stbtt_int16) x;
Ivan Mahonin b53a5c
      }
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
      // now load y coordinates
Ivan Mahonin b53a5c
      y=0;
Ivan Mahonin b53a5c
      for (i=0; i < n; ++i) {
Ivan Mahonin b53a5c
         flags = vertices[off+i].type;
Ivan Mahonin b53a5c
         if (flags & 4) {
Ivan Mahonin b53a5c
            stbtt_int16 dy = *points++;
Ivan Mahonin b53a5c
            y += (flags & 32) ? dy : -dy; // ???
Ivan Mahonin b53a5c
         } else {
Ivan Mahonin b53a5c
            if (!(flags & 32)) {
Ivan Mahonin b53a5c
               y = y + (stbtt_int16) (points[0]*256 + points[1]);
Ivan Mahonin b53a5c
               points += 2;
Ivan Mahonin b53a5c
            }
Ivan Mahonin b53a5c
         }
Ivan Mahonin b53a5c
         vertices[off+i].y = (stbtt_int16) y;
Ivan Mahonin b53a5c
      }
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
      // now convert them to our format
Ivan Mahonin b53a5c
      num_vertices=0;
Ivan Mahonin b53a5c
      sx = sy = cx = cy = scx = scy = 0;
Ivan Mahonin b53a5c
      for (i=0; i < n; ++i) {
Ivan Mahonin b53a5c
         flags = vertices[off+i].type;
Ivan Mahonin b53a5c
         x     = (stbtt_int16) vertices[off+i].x;
Ivan Mahonin b53a5c
         y     = (stbtt_int16) vertices[off+i].y;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
         if (next_move == i) {
Ivan Mahonin b53a5c
            if (i != 0)
Ivan Mahonin b53a5c
               num_vertices = stbtt__close_shape(vertices, num_vertices, was_off, start_off, sx,sy,scx,scy,cx,cy);
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
            // now start the new one
Ivan Mahonin b53a5c
            start_off = !(flags & 1);
Ivan Mahonin b53a5c
            if (start_off) {
Ivan Mahonin b53a5c
               // if we start off with an off-curve point, then when we need to find a point on the curve
Ivan Mahonin b53a5c
               // where we can start, and we need to save some state for when we wraparound.
Ivan Mahonin b53a5c
               scx = x;
Ivan Mahonin b53a5c
               scy = y;
Ivan Mahonin b53a5c
               if (!(vertices[off+i+1].type & 1)) {
Ivan Mahonin b53a5c
                  // next point is also a curve point, so interpolate an on-point curve
Ivan Mahonin b53a5c
                  sx = (x + (stbtt_int32) vertices[off+i+1].x) >> 1;
Ivan Mahonin b53a5c
                  sy = (y + (stbtt_int32) vertices[off+i+1].y) >> 1;
Ivan Mahonin b53a5c
               } else {
Ivan Mahonin b53a5c
                  // otherwise just use the next point as our start point
Ivan Mahonin b53a5c
                  sx = (stbtt_int32) vertices[off+i+1].x;
Ivan Mahonin b53a5c
                  sy = (stbtt_int32) vertices[off+i+1].y;
Ivan Mahonin b53a5c
                  ++i; // we're using point i+1 as the starting point, so skip it
Ivan Mahonin b53a5c
               }
Ivan Mahonin b53a5c
            } else {
Ivan Mahonin b53a5c
               sx = x;
Ivan Mahonin b53a5c
               sy = y;
Ivan Mahonin b53a5c
            }
Ivan Mahonin b53a5c
            stbtt_setvertex(&vertices[num_vertices++], STBTT_vmove,sx,sy,0,0);
Ivan Mahonin b53a5c
            was_off = 0;
Ivan Mahonin b53a5c
            next_move = 1 + ttUSHORT(endPtsOfContours+j*2);
Ivan Mahonin b53a5c
            ++j;
Ivan Mahonin b53a5c
         } else {
Ivan Mahonin b53a5c
            if (!(flags & 1)) { // if it's a curve
Ivan Mahonin b53a5c
               if (was_off) // two off-curve control points in a row means interpolate an on-curve midpoint
Ivan Mahonin b53a5c
                  stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, (cx+x)>>1, (cy+y)>>1, cx, cy);
Ivan Mahonin b53a5c
               cx = x;
Ivan Mahonin b53a5c
               cy = y;
Ivan Mahonin b53a5c
               was_off = 1;
Ivan Mahonin b53a5c
            } else {
Ivan Mahonin b53a5c
               if (was_off)
Ivan Mahonin b53a5c
                  stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, x,y, cx, cy);
Ivan Mahonin b53a5c
               else
Ivan Mahonin b53a5c
                  stbtt_setvertex(&vertices[num_vertices++], STBTT_vline, x,y,0,0);
Ivan Mahonin b53a5c
               was_off = 0;
Ivan Mahonin b53a5c
            }
Ivan Mahonin b53a5c
         }
Ivan Mahonin b53a5c
      }
Ivan Mahonin b53a5c
      num_vertices = stbtt__close_shape(vertices, num_vertices, was_off, start_off, sx,sy,scx,scy,cx,cy);
Ivan Mahonin b53a5c
   } else if (numberOfContours < 0) {
Ivan Mahonin b53a5c
      // Compound shapes.
Ivan Mahonin b53a5c
      int more = 1;
Ivan Mahonin b53a5c
      stbtt_uint8 *comp = data + g + 10;
Ivan Mahonin b53a5c
      num_vertices = 0;
Ivan Mahonin b53a5c
      vertices = 0;
Ivan Mahonin b53a5c
      while (more) {
Ivan Mahonin b53a5c
         stbtt_uint16 flags, gidx;
Ivan Mahonin b53a5c
         int comp_num_verts = 0, i;
Ivan Mahonin b53a5c
         stbtt_vertex *comp_verts = 0, *tmp = 0;
Ivan Mahonin b53a5c
         float mtx[6] = {1,0,0,1,0,0}, m, n;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
         flags = ttSHORT(comp); comp+=2;
Ivan Mahonin b53a5c
         gidx = ttSHORT(comp); comp+=2;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
         if (flags & 2) { // XY values
Ivan Mahonin b53a5c
            if (flags & 1) { // shorts
Ivan Mahonin b53a5c
               mtx[4] = ttSHORT(comp); comp+=2;
Ivan Mahonin b53a5c
               mtx[5] = ttSHORT(comp); comp+=2;
Ivan Mahonin b53a5c
            } else {
Ivan Mahonin b53a5c
               mtx[4] = ttCHAR(comp); comp+=1;
Ivan Mahonin b53a5c
               mtx[5] = ttCHAR(comp); comp+=1;
Ivan Mahonin b53a5c
            }
Ivan Mahonin b53a5c
         }
Ivan Mahonin b53a5c
         else {
Ivan Mahonin b53a5c
            // @TODO handle matching point
Ivan Mahonin b53a5c
            STBTT_assert(0);
Ivan Mahonin b53a5c
         }
Ivan Mahonin b53a5c
         if (flags & (1<<3)) { // WE_HAVE_A_SCALE
Ivan Mahonin b53a5c
            mtx[0] = mtx[3] = ttSHORT(comp)/16384.0f; comp+=2;
Ivan Mahonin b53a5c
            mtx[1] = mtx[2] = 0;
Ivan Mahonin b53a5c
         } else if (flags & (1<<6)) { // WE_HAVE_AN_X_AND_YSCALE
Ivan Mahonin b53a5c
            mtx[0] = ttSHORT(comp)/16384.0f; comp+=2;
Ivan Mahonin b53a5c
            mtx[1] = mtx[2] = 0;
Ivan Mahonin b53a5c
            mtx[3] = ttSHORT(comp)/16384.0f; comp+=2;
Ivan Mahonin b53a5c
         } else if (flags & (1<<7)) { // WE_HAVE_A_TWO_BY_TWO
Ivan Mahonin b53a5c
            mtx[0] = ttSHORT(comp)/16384.0f; comp+=2;
Ivan Mahonin b53a5c
            mtx[1] = ttSHORT(comp)/16384.0f; comp+=2;
Ivan Mahonin b53a5c
            mtx[2] = ttSHORT(comp)/16384.0f; comp+=2;
Ivan Mahonin b53a5c
            mtx[3] = ttSHORT(comp)/16384.0f; comp+=2;
Ivan Mahonin b53a5c
         }
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
         // Find transformation scales.
Ivan Mahonin b53a5c
         m = (float) STBTT_sqrt(mtx[0]*mtx[0] + mtx[1]*mtx[1]);
Ivan Mahonin b53a5c
         n = (float) STBTT_sqrt(mtx[2]*mtx[2] + mtx[3]*mtx[3]);
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
         // Get indexed glyph.
Ivan Mahonin b53a5c
         comp_num_verts = stbtt_GetGlyphShape(info, gidx, &comp_verts);
Ivan Mahonin b53a5c
         if (comp_num_verts > 0) {
Ivan Mahonin b53a5c
            // Transform vertices.
Ivan Mahonin b53a5c
            for (i = 0; i < comp_num_verts; ++i) {
Ivan Mahonin b53a5c
               stbtt_vertex* v = &comp_verts[i];
Ivan Mahonin b53a5c
               stbtt_vertex_type x,y;
Ivan Mahonin b53a5c
               x=v->x; y=v->y;
Ivan Mahonin b53a5c
               v->x = (stbtt_vertex_type)(m * (mtx[0]*x + mtx[2]*y + mtx[4]));
Ivan Mahonin b53a5c
               v->y = (stbtt_vertex_type)(n * (mtx[1]*x + mtx[3]*y + mtx[5]));
Ivan Mahonin b53a5c
               x=v->cx; y=v->cy;
Ivan Mahonin b53a5c
               v->cx = (stbtt_vertex_type)(m * (mtx[0]*x + mtx[2]*y + mtx[4]));
Ivan Mahonin b53a5c
               v->cy = (stbtt_vertex_type)(n * (mtx[1]*x + mtx[3]*y + mtx[5]));
Ivan Mahonin b53a5c
            }
Ivan Mahonin b53a5c
            // Append vertices.
Ivan Mahonin b53a5c
            tmp = (stbtt_vertex*)STBTT_malloc((num_vertices+comp_num_verts)*sizeof(stbtt_vertex), info->userdata);
Ivan Mahonin b53a5c
            if (!tmp) {
Ivan Mahonin b53a5c
               if (vertices) STBTT_free(vertices, info->userdata);
Ivan Mahonin b53a5c
               if (comp_verts) STBTT_free(comp_verts, info->userdata);
Ivan Mahonin b53a5c
               return 0;
Ivan Mahonin b53a5c
            }
Ivan Mahonin b53a5c
            if (num_vertices > 0 && vertices) STBTT_memcpy(tmp, vertices, num_vertices*sizeof(stbtt_vertex));
Ivan Mahonin b53a5c
            STBTT_memcpy(tmp+num_vertices, comp_verts, comp_num_verts*sizeof(stbtt_vertex));
Ivan Mahonin b53a5c
            if (vertices) STBTT_free(vertices, info->userdata);
Ivan Mahonin b53a5c
            vertices = tmp;
Ivan Mahonin b53a5c
            STBTT_free(comp_verts, info->userdata);
Ivan Mahonin b53a5c
            num_vertices += comp_num_verts;
Ivan Mahonin b53a5c
         }
Ivan Mahonin b53a5c
         // More components ?
Ivan Mahonin b53a5c
         more = flags & (1<<5);
Ivan Mahonin b53a5c
      }
Ivan Mahonin b53a5c
   } else {
Ivan Mahonin b53a5c
      // numberOfCounters == 0, do nothing
Ivan Mahonin b53a5c
   }
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   *pvertices = vertices;
Ivan Mahonin b53a5c
   return num_vertices;
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
typedef struct
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   int bounds;
Ivan Mahonin b53a5c
   int started;
Ivan Mahonin b53a5c
   float first_x, first_y;
Ivan Mahonin b53a5c
   float x, y;
Ivan Mahonin b53a5c
   stbtt_int32 min_x, max_x, min_y, max_y;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   stbtt_vertex *pvertices;
Ivan Mahonin b53a5c
   int num_vertices;
Ivan Mahonin b53a5c
} stbtt__csctx;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
#define STBTT__CSCTX_INIT(bounds) {bounds,0, 0,0, 0,0, 0,0,0,0, NULL, 0}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
static void stbtt__track_vertex(stbtt__csctx *c, stbtt_int32 x, stbtt_int32 y)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   if (x > c->max_x || !c->started) c->max_x = x;
Ivan Mahonin b53a5c
   if (y > c->max_y || !c->started) c->max_y = y;
Ivan Mahonin b53a5c
   if (x < c->min_x || !c->started) c->min_x = x;
Ivan Mahonin b53a5c
   if (y < c->min_y || !c->started) c->min_y = y;
Ivan Mahonin b53a5c
   c->started = 1;
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
static void stbtt__csctx_v(stbtt__csctx *c, stbtt_uint8 type, stbtt_int32 x, stbtt_int32 y, stbtt_int32 cx, stbtt_int32 cy, stbtt_int32 cx1, stbtt_int32 cy1)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   if (c->bounds) {
Ivan Mahonin b53a5c
      stbtt__track_vertex(c, x, y);
Ivan Mahonin b53a5c
      if (type == STBTT_vcubic) {
Ivan Mahonin b53a5c
         stbtt__track_vertex(c, cx, cy);
Ivan Mahonin b53a5c
         stbtt__track_vertex(c, cx1, cy1);
Ivan Mahonin b53a5c
      }
Ivan Mahonin b53a5c
   } else {
Ivan Mahonin b53a5c
      stbtt_setvertex(&c->pvertices[c->num_vertices], type, x, y, cx, cy);
Ivan Mahonin b53a5c
      c->pvertices[c->num_vertices].cx1 = (stbtt_int16) cx1;
Ivan Mahonin b53a5c
      c->pvertices[c->num_vertices].cy1 = (stbtt_int16) cy1;
Ivan Mahonin b53a5c
   }
Ivan Mahonin b53a5c
   c->num_vertices++;
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
static void stbtt__csctx_close_shape(stbtt__csctx *ctx)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   if (ctx->first_x != ctx->x || ctx->first_y != ctx->y)
Ivan Mahonin b53a5c
      stbtt__csctx_v(ctx, STBTT_vline, (int)ctx->first_x, (int)ctx->first_y, 0, 0, 0, 0);
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
static void stbtt__csctx_rmove_to(stbtt__csctx *ctx, float dx, float dy)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   stbtt__csctx_close_shape(ctx);
Ivan Mahonin b53a5c
   ctx->first_x = ctx->x = ctx->x + dx;
Ivan Mahonin b53a5c
   ctx->first_y = ctx->y = ctx->y + dy;
Ivan Mahonin b53a5c
   stbtt__csctx_v(ctx, STBTT_vmove, (int)ctx->x, (int)ctx->y, 0, 0, 0, 0);
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
static void stbtt__csctx_rline_to(stbtt__csctx *ctx, float dx, float dy)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   ctx->x += dx;
Ivan Mahonin b53a5c
   ctx->y += dy;
Ivan Mahonin b53a5c
   stbtt__csctx_v(ctx, STBTT_vline, (int)ctx->x, (int)ctx->y, 0, 0, 0, 0);
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
static void stbtt__csctx_rccurve_to(stbtt__csctx *ctx, float dx1, float dy1, float dx2, float dy2, float dx3, float dy3)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   float cx1 = ctx->x + dx1;
Ivan Mahonin b53a5c
   float cy1 = ctx->y + dy1;
Ivan Mahonin b53a5c
   float cx2 = cx1 + dx2;
Ivan Mahonin b53a5c
   float cy2 = cy1 + dy2;
Ivan Mahonin b53a5c
   ctx->x = cx2 + dx3;
Ivan Mahonin b53a5c
   ctx->y = cy2 + dy3;
Ivan Mahonin b53a5c
   stbtt__csctx_v(ctx, STBTT_vcubic, (int)ctx->x, (int)ctx->y, (int)cx1, (int)cy1, (int)cx2, (int)cy2);
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
static stbtt__buf stbtt__get_subr(stbtt__buf idx, int n)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   int count = stbtt__cff_index_count(&idx);
Ivan Mahonin b53a5c
   int bias = 107;
Ivan Mahonin b53a5c
   if (count >= 33900)
Ivan Mahonin b53a5c
      bias = 32768;
Ivan Mahonin b53a5c
   else if (count >= 1240)
Ivan Mahonin b53a5c
      bias = 1131;
Ivan Mahonin b53a5c
   n += bias;
Ivan Mahonin b53a5c
   if (n < 0 || n >= count)
Ivan Mahonin b53a5c
      return stbtt__new_buf(NULL, 0);
Ivan Mahonin b53a5c
   return stbtt__cff_index_get(idx, n);
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
static stbtt__buf stbtt__cid_get_glyph_subrs(const stbtt_fontinfo *info, int glyph_index)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   stbtt__buf fdselect = info->fdselect;
Ivan Mahonin b53a5c
   int nranges, start, end, v, fmt, fdselector = -1, i;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   stbtt__buf_seek(&fdselect, 0);
Ivan Mahonin b53a5c
   fmt = stbtt__buf_get8(&fdselect);
Ivan Mahonin b53a5c
   if (fmt == 0) {
Ivan Mahonin b53a5c
      // untested
Ivan Mahonin b53a5c
      stbtt__buf_skip(&fdselect, glyph_index);
Ivan Mahonin b53a5c
      fdselector = stbtt__buf_get8(&fdselect);
Ivan Mahonin b53a5c
   } else if (fmt == 3) {
Ivan Mahonin b53a5c
      nranges = stbtt__buf_get16(&fdselect);
Ivan Mahonin b53a5c
      start = stbtt__buf_get16(&fdselect);
Ivan Mahonin b53a5c
      for (i = 0; i < nranges; i++) {
Ivan Mahonin b53a5c
         v = stbtt__buf_get8(&fdselect);
Ivan Mahonin b53a5c
         end = stbtt__buf_get16(&fdselect);
Ivan Mahonin b53a5c
         if (glyph_index >= start && glyph_index < end) {
Ivan Mahonin b53a5c
            fdselector = v;
Ivan Mahonin b53a5c
            break;
Ivan Mahonin b53a5c
         }
Ivan Mahonin b53a5c
         start = end;
Ivan Mahonin b53a5c
      }
Ivan Mahonin b53a5c
   }
Ivan Mahonin b53a5c
   if (fdselector == -1) stbtt__new_buf(NULL, 0);
Ivan Mahonin b53a5c
   return stbtt__get_subrs(info->cff, stbtt__cff_index_get(info->fontdicts, fdselector));
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
static int stbtt__run_charstring(const stbtt_fontinfo *info, int glyph_index, stbtt__csctx *c)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   int in_header = 1, maskbits = 0, subr_stack_height = 0, sp = 0, v, i, b0;
Ivan Mahonin b53a5c
   int has_subrs = 0, clear_stack;
Ivan Mahonin b53a5c
   float s[48];
Ivan Mahonin b53a5c
   stbtt__buf subr_stack[10], subrs = info->subrs, b;
Ivan Mahonin b53a5c
   float f;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
#define STBTT__CSERR(s) (0)
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   // this currently ignores the initial width value, which isn't needed if we have hmtx
Ivan Mahonin b53a5c
   b = stbtt__cff_index_get(info->charstrings, glyph_index);
Ivan Mahonin b53a5c
   while (b.cursor < b.size) {
Ivan Mahonin b53a5c
      i = 0;
Ivan Mahonin b53a5c
      clear_stack = 1;
Ivan Mahonin b53a5c
      b0 = stbtt__buf_get8(&b);
Ivan Mahonin b53a5c
      switch (b0) {
Ivan Mahonin b53a5c
      // @TODO implement hinting
Ivan Mahonin b53a5c
      case 0x13: // hintmask
Ivan Mahonin b53a5c
      case 0x14: // cntrmask
Ivan Mahonin b53a5c
         if (in_header)
Ivan Mahonin b53a5c
            maskbits += (sp / 2); // implicit "vstem"
Ivan Mahonin b53a5c
         in_header = 0;
Ivan Mahonin b53a5c
         stbtt__buf_skip(&b, (maskbits + 7) / 8);
Ivan Mahonin b53a5c
         break;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
      case 0x01: // hstem
Ivan Mahonin b53a5c
      case 0x03: // vstem
Ivan Mahonin b53a5c
      case 0x12: // hstemhm
Ivan Mahonin b53a5c
      case 0x17: // vstemhm
Ivan Mahonin b53a5c
         maskbits += (sp / 2);
Ivan Mahonin b53a5c
         break;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
      case 0x15: // rmoveto
Ivan Mahonin b53a5c
         in_header = 0;
Ivan Mahonin b53a5c
         if (sp < 2) return STBTT__CSERR("rmoveto stack");
Ivan Mahonin b53a5c
         stbtt__csctx_rmove_to(c, s[sp-2], s[sp-1]);
Ivan Mahonin b53a5c
         break;
Ivan Mahonin b53a5c
      case 0x04: // vmoveto
Ivan Mahonin b53a5c
         in_header = 0;
Ivan Mahonin b53a5c
         if (sp < 1) return STBTT__CSERR("vmoveto stack");
Ivan Mahonin b53a5c
         stbtt__csctx_rmove_to(c, 0, s[sp-1]);
Ivan Mahonin b53a5c
         break;
Ivan Mahonin b53a5c
      case 0x16: // hmoveto
Ivan Mahonin b53a5c
         in_header = 0;
Ivan Mahonin b53a5c
         if (sp < 1) return STBTT__CSERR("hmoveto stack");
Ivan Mahonin b53a5c
         stbtt__csctx_rmove_to(c, s[sp-1], 0);
Ivan Mahonin b53a5c
         break;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
      case 0x05: // rlineto
Ivan Mahonin b53a5c
         if (sp < 2) return STBTT__CSERR("rlineto stack");
Ivan Mahonin b53a5c
         for (; i + 1 < sp; i += 2)
Ivan Mahonin b53a5c
            stbtt__csctx_rline_to(c, s[i], s[i+1]);
Ivan Mahonin b53a5c
         break;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
      // hlineto/vlineto and vhcurveto/hvcurveto alternate horizontal and vertical
Ivan Mahonin b53a5c
      // starting from a different place.
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
      case 0x07: // vlineto
Ivan Mahonin b53a5c
         if (sp < 1) return STBTT__CSERR("vlineto stack");
Ivan Mahonin b53a5c
         goto vlineto;
Ivan Mahonin b53a5c
      case 0x06: // hlineto
Ivan Mahonin b53a5c
         if (sp < 1) return STBTT__CSERR("hlineto stack");
Ivan Mahonin b53a5c
         for (;;) {
Ivan Mahonin b53a5c
            if (i >= sp) break;
Ivan Mahonin b53a5c
            stbtt__csctx_rline_to(c, s[i], 0);
Ivan Mahonin b53a5c
            i++;
Ivan Mahonin b53a5c
      vlineto:
Ivan Mahonin b53a5c
            if (i >= sp) break;
Ivan Mahonin b53a5c
            stbtt__csctx_rline_to(c, 0, s[i]);
Ivan Mahonin b53a5c
            i++;
Ivan Mahonin b53a5c
         }
Ivan Mahonin b53a5c
         break;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
      case 0x1F: // hvcurveto
Ivan Mahonin b53a5c
         if (sp < 4) return STBTT__CSERR("hvcurveto stack");
Ivan Mahonin b53a5c
         goto hvcurveto;
Ivan Mahonin b53a5c
      case 0x1E: // vhcurveto
Ivan Mahonin b53a5c
         if (sp < 4) return STBTT__CSERR("vhcurveto stack");
Ivan Mahonin b53a5c
         for (;;) {
Ivan Mahonin b53a5c
            if (i + 3 >= sp) break;
Ivan Mahonin b53a5c
            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);
Ivan Mahonin b53a5c
            i += 4;
Ivan Mahonin b53a5c
      hvcurveto:
Ivan Mahonin b53a5c
            if (i + 3 >= sp) break;
Ivan Mahonin b53a5c
            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]);
Ivan Mahonin b53a5c
            i += 4;
Ivan Mahonin b53a5c
         }
Ivan Mahonin b53a5c
         break;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
      case 0x08: // rrcurveto
Ivan Mahonin b53a5c
         if (sp < 6) return STBTT__CSERR("rcurveline stack");
Ivan Mahonin b53a5c
         for (; i + 5 < sp; i += 6)
Ivan Mahonin b53a5c
            stbtt__csctx_rccurve_to(c, s[i], s[i+1], s[i+2], s[i+3], s[i+4], s[i+5]);
Ivan Mahonin b53a5c
         break;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
      case 0x18: // rcurveline
Ivan Mahonin b53a5c
         if (sp < 8) return STBTT__CSERR("rcurveline stack");
Ivan Mahonin b53a5c
         for (; i + 5 < sp - 2; i += 6)
Ivan Mahonin b53a5c
            stbtt__csctx_rccurve_to(c, s[i], s[i+1], s[i+2], s[i+3], s[i+4], s[i+5]);
Ivan Mahonin b53a5c
         if (i + 1 >= sp) return STBTT__CSERR("rcurveline stack");
Ivan Mahonin b53a5c
         stbtt__csctx_rline_to(c, s[i], s[i+1]);
Ivan Mahonin b53a5c
         break;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
      case 0x19: // rlinecurve
Ivan Mahonin b53a5c
         if (sp < 8) return STBTT__CSERR("rlinecurve stack");
Ivan Mahonin b53a5c
         for (; i + 1 < sp - 6; i += 2)
Ivan Mahonin b53a5c
            stbtt__csctx_rline_to(c, s[i], s[i+1]);
Ivan Mahonin b53a5c
         if (i + 5 >= sp) return STBTT__CSERR("rlinecurve stack");
Ivan Mahonin b53a5c
         stbtt__csctx_rccurve_to(c, s[i], s[i+1], s[i+2], s[i+3], s[i+4], s[i+5]);
Ivan Mahonin b53a5c
         break;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
      case 0x1A: // vvcurveto
Ivan Mahonin b53a5c
      case 0x1B: // hhcurveto
Ivan Mahonin b53a5c
         if (sp < 4) return STBTT__CSERR("(vv|hh)curveto stack");
Ivan Mahonin b53a5c
         f = 0.0;
Ivan Mahonin b53a5c
         if (sp & 1) { f = s[i]; i++; }
Ivan Mahonin b53a5c
         for (; i + 3 < sp; i += 4) {
Ivan Mahonin b53a5c
            if (b0 == 0x1B)
Ivan Mahonin b53a5c
               stbtt__csctx_rccurve_to(c, s[i], f, s[i+1], s[i+2], s[i+3], 0.0);
Ivan Mahonin b53a5c
            else
Ivan Mahonin b53a5c
               stbtt__csctx_rccurve_to(c, f, s[i], s[i+1], s[i+2], 0.0, s[i+3]);
Ivan Mahonin b53a5c
            f = 0.0;
Ivan Mahonin b53a5c
         }
Ivan Mahonin b53a5c
         break;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
      case 0x0A: // callsubr
Ivan Mahonin b53a5c
         if (!has_subrs) {
Ivan Mahonin b53a5c
            if (info->fdselect.size)
Ivan Mahonin b53a5c
               subrs = stbtt__cid_get_glyph_subrs(info, glyph_index);
Ivan Mahonin b53a5c
            has_subrs = 1;
Ivan Mahonin b53a5c
         }
Ivan Mahonin b53a5c
         // FALLTHROUGH
Ivan Mahonin b53a5c
      case 0x1D: // callgsubr
Ivan Mahonin b53a5c
         if (sp < 1) return STBTT__CSERR("call(g|)subr stack");
Ivan Mahonin b53a5c
         v = (int) s[--sp];
Ivan Mahonin b53a5c
         if (subr_stack_height >= 10) return STBTT__CSERR("recursion limit");
Ivan Mahonin b53a5c
         subr_stack[subr_stack_height++] = b;
Ivan Mahonin b53a5c
         b = stbtt__get_subr(b0 == 0x0A ? subrs : info->gsubrs, v);
Ivan Mahonin b53a5c
         if (b.size == 0) return STBTT__CSERR("subr not found");
Ivan Mahonin b53a5c
         b.cursor = 0;
Ivan Mahonin b53a5c
         clear_stack = 0;
Ivan Mahonin b53a5c
         break;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
      case 0x0B: // return
Ivan Mahonin b53a5c
         if (subr_stack_height <= 0) return STBTT__CSERR("return outside subr");
Ivan Mahonin b53a5c
         b = subr_stack[--subr_stack_height];
Ivan Mahonin b53a5c
         clear_stack = 0;
Ivan Mahonin b53a5c
         break;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
      case 0x0E: // endchar
Ivan Mahonin b53a5c
         stbtt__csctx_close_shape(c);
Ivan Mahonin b53a5c
         return 1;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
      case 0x0C: { // two-byte escape
Ivan Mahonin b53a5c
         float dx1, dx2, dx3, dx4, dx5, dx6, dy1, dy2, dy3, dy4, dy5, dy6;
Ivan Mahonin b53a5c
         float dx, dy;
Ivan Mahonin b53a5c
         int b1 = stbtt__buf_get8(&b);
Ivan Mahonin b53a5c
         switch (b1) {
Ivan Mahonin b53a5c
         // @TODO These "flex" implementations ignore the flex-depth and resolution,
Ivan Mahonin b53a5c
         // and always draw beziers.
Ivan Mahonin b53a5c
         case 0x22: // hflex
Ivan Mahonin b53a5c
            if (sp < 7) return STBTT__CSERR("hflex stack");
Ivan Mahonin b53a5c
            dx1 = s[0];
Ivan Mahonin b53a5c
            dx2 = s[1];
Ivan Mahonin b53a5c
            dy2 = s[2];
Ivan Mahonin b53a5c
            dx3 = s[3];
Ivan Mahonin b53a5c
            dx4 = s[4];
Ivan Mahonin b53a5c
            dx5 = s[5];
Ivan Mahonin b53a5c
            dx6 = s[6];
Ivan Mahonin b53a5c
            stbtt__csctx_rccurve_to(c, dx1, 0, dx2, dy2, dx3, 0);
Ivan Mahonin b53a5c
            stbtt__csctx_rccurve_to(c, dx4, 0, dx5, -dy2, dx6, 0);
Ivan Mahonin b53a5c
            break;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
         case 0x23: // flex
Ivan Mahonin b53a5c
            if (sp < 13) return STBTT__CSERR("flex stack");
Ivan Mahonin b53a5c
            dx1 = s[0];
Ivan Mahonin b53a5c
            dy1 = s[1];
Ivan Mahonin b53a5c
            dx2 = s[2];
Ivan Mahonin b53a5c
            dy2 = s[3];
Ivan Mahonin b53a5c
            dx3 = s[4];
Ivan Mahonin b53a5c
            dy3 = s[5];
Ivan Mahonin b53a5c
            dx4 = s[6];
Ivan Mahonin b53a5c
            dy4 = s[7];
Ivan Mahonin b53a5c
            dx5 = s[8];
Ivan Mahonin b53a5c
            dy5 = s[9];
Ivan Mahonin b53a5c
            dx6 = s[10];
Ivan Mahonin b53a5c
            dy6 = s[11];
Ivan Mahonin b53a5c
            //fd is s[12]
Ivan Mahonin b53a5c
            stbtt__csctx_rccurve_to(c, dx1, dy1, dx2, dy2, dx3, dy3);
Ivan Mahonin b53a5c
            stbtt__csctx_rccurve_to(c, dx4, dy4, dx5, dy5, dx6, dy6);
Ivan Mahonin b53a5c
            break;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
         case 0x24: // hflex1
Ivan Mahonin b53a5c
            if (sp < 9) return STBTT__CSERR("hflex1 stack");
Ivan Mahonin b53a5c
            dx1 = s[0];
Ivan Mahonin b53a5c
            dy1 = s[1];
Ivan Mahonin b53a5c
            dx2 = s[2];
Ivan Mahonin b53a5c
            dy2 = s[3];
Ivan Mahonin b53a5c
            dx3 = s[4];
Ivan Mahonin b53a5c
            dx4 = s[5];
Ivan Mahonin b53a5c
            dx5 = s[6];
Ivan Mahonin b53a5c
            dy5 = s[7];
Ivan Mahonin b53a5c
            dx6 = s[8];
Ivan Mahonin b53a5c
            stbtt__csctx_rccurve_to(c, dx1, dy1, dx2, dy2, dx3, 0);
Ivan Mahonin b53a5c
            stbtt__csctx_rccurve_to(c, dx4, 0, dx5, dy5, dx6, -(dy1+dy2+dy5));
Ivan Mahonin b53a5c
            break;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
         case 0x25: // flex1
Ivan Mahonin b53a5c
            if (sp < 11) return STBTT__CSERR("flex1 stack");
Ivan Mahonin b53a5c
            dx1 = s[0];
Ivan Mahonin b53a5c
            dy1 = s[1];
Ivan Mahonin b53a5c
            dx2 = s[2];
Ivan Mahonin b53a5c
            dy2 = s[3];
Ivan Mahonin b53a5c
            dx3 = s[4];
Ivan Mahonin b53a5c
            dy3 = s[5];
Ivan Mahonin b53a5c
            dx4 = s[6];
Ivan Mahonin b53a5c
            dy4 = s[7];
Ivan Mahonin b53a5c
            dx5 = s[8];
Ivan Mahonin b53a5c
            dy5 = s[9];
Ivan Mahonin b53a5c
            dx6 = dy6 = s[10];
Ivan Mahonin b53a5c
            dx = dx1+dx2+dx3+dx4+dx5;
Ivan Mahonin b53a5c
            dy = dy1+dy2+dy3+dy4+dy5;
Ivan Mahonin b53a5c
            if (STBTT_fabs(dx) > STBTT_fabs(dy))
Ivan Mahonin b53a5c
               dy6 = -dy;
Ivan Mahonin b53a5c
            else
Ivan Mahonin b53a5c
               dx6 = -dx;
Ivan Mahonin b53a5c
            stbtt__csctx_rccurve_to(c, dx1, dy1, dx2, dy2, dx3, dy3);
Ivan Mahonin b53a5c
            stbtt__csctx_rccurve_to(c, dx4, dy4, dx5, dy5, dx6, dy6);
Ivan Mahonin b53a5c
            break;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
         default:
Ivan Mahonin b53a5c
            return STBTT__CSERR("unimplemented");
Ivan Mahonin b53a5c
         }
Ivan Mahonin b53a5c
      } break;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
      default:
Ivan Mahonin b53a5c
         if (b0 != 255 && b0 != 28 && b0 < 32)
Ivan Mahonin b53a5c
            return STBTT__CSERR("reserved operator");
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
         // push immediate
Ivan Mahonin b53a5c
         if (b0 == 255) {
Ivan Mahonin b53a5c
            f = (float)(stbtt_int32)stbtt__buf_get32(&b) / 0x10000;
Ivan Mahonin b53a5c
         } else {
Ivan Mahonin b53a5c
            stbtt__buf_skip(&b, -1);
Ivan Mahonin b53a5c
            f = (float)(stbtt_int16)stbtt__cff_int(&b);
Ivan Mahonin b53a5c
         }
Ivan Mahonin b53a5c
         if (sp >= 48) return STBTT__CSERR("push stack overflow");
Ivan Mahonin b53a5c
         s[sp++] = f;
Ivan Mahonin b53a5c
         clear_stack = 0;
Ivan Mahonin b53a5c
         break;
Ivan Mahonin b53a5c
      }
Ivan Mahonin b53a5c
      if (clear_stack) sp = 0;
Ivan Mahonin b53a5c
   }
Ivan Mahonin b53a5c
   return STBTT__CSERR("no endchar");
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
#undef STBTT__CSERR
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
static int stbtt__GetGlyphShapeT2(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **pvertices)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   // runs the charstring twice, once to count and once to output (to avoid realloc)
Ivan Mahonin b53a5c
   stbtt__csctx count_ctx = STBTT__CSCTX_INIT(1);
Ivan Mahonin b53a5c
   stbtt__csctx output_ctx = STBTT__CSCTX_INIT(0);
Ivan Mahonin b53a5c
   if (stbtt__run_charstring(info, glyph_index, &count_ctx)) {
Ivan Mahonin b53a5c
      *pvertices = (stbtt_vertex*)STBTT_malloc(count_ctx.num_vertices*sizeof(stbtt_vertex), info->userdata);
Ivan Mahonin b53a5c
      output_ctx.pvertices = *pvertices;
Ivan Mahonin b53a5c
      if (stbtt__run_charstring(info, glyph_index, &output_ctx)) {
Ivan Mahonin b53a5c
         STBTT_assert(output_ctx.num_vertices == count_ctx.num_vertices);
Ivan Mahonin b53a5c
         return output_ctx.num_vertices;
Ivan Mahonin b53a5c
      }
Ivan Mahonin b53a5c
   }
Ivan Mahonin b53a5c
   *pvertices = NULL;
Ivan Mahonin b53a5c
   return 0;
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
static int stbtt__GetGlyphInfoT2(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   stbtt__csctx c = STBTT__CSCTX_INIT(1);
Ivan Mahonin b53a5c
   int r = stbtt__run_charstring(info, glyph_index, &c);
Ivan Mahonin b53a5c
   if (x0)  *x0 = r ? c.min_x : 0;
Ivan Mahonin b53a5c
   if (y0)  *y0 = r ? c.min_y : 0;
Ivan Mahonin b53a5c
   if (x1)  *x1 = r ? c.max_x : 0;
Ivan Mahonin b53a5c
   if (y1)  *y1 = r ? c.max_y : 0;
Ivan Mahonin b53a5c
   return r ? c.num_vertices : 0;
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
STBTT_DEF int stbtt_GetGlyphShape(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **pvertices)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   if (!info->cff.size)
Ivan Mahonin b53a5c
      return stbtt__GetGlyphShapeTT(info, glyph_index, pvertices);
Ivan Mahonin b53a5c
   else
Ivan Mahonin b53a5c
      return stbtt__GetGlyphShapeT2(info, glyph_index, pvertices);
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
STBTT_DEF void stbtt_GetGlyphHMetrics(const stbtt_fontinfo *info, int glyph_index, int *advanceWidth, int *leftSideBearing)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   stbtt_uint16 numOfLongHorMetrics = ttUSHORT(info->data+info->hhea + 34);
Ivan Mahonin b53a5c
   if (glyph_index < numOfLongHorMetrics) {
Ivan Mahonin b53a5c
      if (advanceWidth)     *advanceWidth    = ttSHORT(info->data + info->hmtx + 4*glyph_index);
Ivan Mahonin b53a5c
      if (leftSideBearing)  *leftSideBearing = ttSHORT(info->data + info->hmtx + 4*glyph_index + 2);
Ivan Mahonin b53a5c
   } else {
Ivan Mahonin b53a5c
      if (advanceWidth)     *advanceWidth    = ttSHORT(info->data + info->hmtx + 4*(numOfLongHorMetrics-1));
Ivan Mahonin b53a5c
      if (leftSideBearing)  *leftSideBearing = ttSHORT(info->data + info->hmtx + 4*numOfLongHorMetrics + 2*(glyph_index - numOfLongHorMetrics));
Ivan Mahonin b53a5c
   }
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
STBTT_DEF int  stbtt_GetKerningTableLength(const stbtt_fontinfo *info)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   stbtt_uint8 *data = info->data + info->kern;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   // we only look at the first table. it must be 'horizontal' and format 0.
Ivan Mahonin b53a5c
   if (!info->kern)
Ivan Mahonin b53a5c
      return 0;
Ivan Mahonin b53a5c
   if (ttUSHORT(data+2) < 1) // number of tables, need at least 1
Ivan Mahonin b53a5c
      return 0;
Ivan Mahonin b53a5c
   if (ttUSHORT(data+8) != 1) // horizontal flag must be set in format
Ivan Mahonin b53a5c
      return 0;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   return ttUSHORT(data+10);
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
STBTT_DEF int stbtt_GetKerningTable(const stbtt_fontinfo *info, stbtt_kerningentry* table, int table_length)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   stbtt_uint8 *data = info->data + info->kern;
Ivan Mahonin b53a5c
   int k, length;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   // we only look at the first table. it must be 'horizontal' and format 0.
Ivan Mahonin b53a5c
   if (!info->kern)
Ivan Mahonin b53a5c
      return 0;
Ivan Mahonin b53a5c
   if (ttUSHORT(data+2) < 1) // number of tables, need at least 1
Ivan Mahonin b53a5c
      return 0;
Ivan Mahonin b53a5c
   if (ttUSHORT(data+8) != 1) // horizontal flag must be set in format
Ivan Mahonin b53a5c
      return 0;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   length = ttUSHORT(data+10);
Ivan Mahonin b53a5c
   if (table_length < length)
Ivan Mahonin b53a5c
      length = table_length;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   for (k = 0; k < length; k++)
Ivan Mahonin b53a5c
   {
Ivan Mahonin b53a5c
      table[k].glyph1 = ttUSHORT(data+18+(k*6));
Ivan Mahonin b53a5c
      table[k].glyph2 = ttUSHORT(data+20+(k*6));
Ivan Mahonin b53a5c
      table[k].advance = ttSHORT(data+22+(k*6));
Ivan Mahonin b53a5c
   }
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   return length;
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
static int stbtt__GetGlyphKernInfoAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   stbtt_uint8 *data = info->data + info->kern;
Ivan Mahonin b53a5c
   stbtt_uint32 needle, straw;
Ivan Mahonin b53a5c
   int l, r, m;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   // we only look at the first table. it must be 'horizontal' and format 0.
Ivan Mahonin b53a5c
   if (!info->kern)
Ivan Mahonin b53a5c
      return 0;
Ivan Mahonin b53a5c
   if (ttUSHORT(data+2) < 1) // number of tables, need at least 1
Ivan Mahonin b53a5c
      return 0;
Ivan Mahonin b53a5c
   if (ttUSHORT(data+8) != 1) // horizontal flag must be set in format
Ivan Mahonin b53a5c
      return 0;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   l = 0;
Ivan Mahonin b53a5c
   r = ttUSHORT(data+10) - 1;
Ivan Mahonin b53a5c
   needle = glyph1 << 16 | glyph2;
Ivan Mahonin b53a5c
   while (l <= r) {
Ivan Mahonin b53a5c
      m = (l + r) >> 1;
Ivan Mahonin b53a5c
      straw = ttULONG(data+18+(m*6)); // note: unaligned read
Ivan Mahonin b53a5c
      if (needle < straw)
Ivan Mahonin b53a5c
         r = m - 1;
Ivan Mahonin b53a5c
      else if (needle > straw)
Ivan Mahonin b53a5c
         l = m + 1;
Ivan Mahonin b53a5c
      else
Ivan Mahonin b53a5c
         return ttSHORT(data+22+(m*6));
Ivan Mahonin b53a5c
   }
Ivan Mahonin b53a5c
   return 0;
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
static stbtt_int32 stbtt__GetCoverageIndex(stbtt_uint8 *coverageTable, int glyph)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   stbtt_uint16 coverageFormat = ttUSHORT(coverageTable);
Ivan Mahonin b53a5c
   switch (coverageFormat) {
Ivan Mahonin b53a5c
      case 1: {
Ivan Mahonin b53a5c
         stbtt_uint16 glyphCount = ttUSHORT(coverageTable + 2);
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
         // Binary search.
Ivan Mahonin b53a5c
         stbtt_int32 l=0, r=glyphCount-1, m;
Ivan Mahonin b53a5c
         int straw, needle=glyph;
Ivan Mahonin b53a5c
         while (l <= r) {
Ivan Mahonin b53a5c
            stbtt_uint8 *glyphArray = coverageTable + 4;
Ivan Mahonin b53a5c
            stbtt_uint16 glyphID;
Ivan Mahonin b53a5c
            m = (l + r) >> 1;
Ivan Mahonin b53a5c
            glyphID = ttUSHORT(glyphArray + 2 * m);
Ivan Mahonin b53a5c
            straw = glyphID;
Ivan Mahonin b53a5c
            if (needle < straw)
Ivan Mahonin b53a5c
               r = m - 1;
Ivan Mahonin b53a5c
            else if (needle > straw)
Ivan Mahonin b53a5c
               l = m + 1;
Ivan Mahonin b53a5c
            else {
Ivan Mahonin b53a5c
               return m;
Ivan Mahonin b53a5c
            }
Ivan Mahonin b53a5c
         }
Ivan Mahonin b53a5c
         break;
Ivan Mahonin b53a5c
      }
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
      case 2: {
Ivan Mahonin b53a5c
         stbtt_uint16 rangeCount = ttUSHORT(coverageTable + 2);
Ivan Mahonin b53a5c
         stbtt_uint8 *rangeArray = coverageTable + 4;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
         // Binary search.
Ivan Mahonin b53a5c
         stbtt_int32 l=0, r=rangeCount-1, m;
Ivan Mahonin b53a5c
         int strawStart, strawEnd, needle=glyph;
Ivan Mahonin b53a5c
         while (l <= r) {
Ivan Mahonin b53a5c
            stbtt_uint8 *rangeRecord;
Ivan Mahonin b53a5c
            m = (l + r) >> 1;
Ivan Mahonin b53a5c
            rangeRecord = rangeArray + 6 * m;
Ivan Mahonin b53a5c
            strawStart = ttUSHORT(rangeRecord);
Ivan Mahonin b53a5c
            strawEnd = ttUSHORT(rangeRecord + 2);
Ivan Mahonin b53a5c
            if (needle < strawStart)
Ivan Mahonin b53a5c
               r = m - 1;
Ivan Mahonin b53a5c
            else if (needle > strawEnd)
Ivan Mahonin b53a5c
               l = m + 1;
Ivan Mahonin b53a5c
            else {
Ivan Mahonin b53a5c
               stbtt_uint16 startCoverageIndex = ttUSHORT(rangeRecord + 4);
Ivan Mahonin b53a5c
               return startCoverageIndex + glyph - strawStart;
Ivan Mahonin b53a5c
            }
Ivan Mahonin b53a5c
         }
Ivan Mahonin b53a5c
         break;
Ivan Mahonin b53a5c
      }
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
      default: return -1; // unsupported
Ivan Mahonin b53a5c
   }
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   return -1;
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
static stbtt_int32  stbtt__GetGlyphClass(stbtt_uint8 *classDefTable, int glyph)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   stbtt_uint16 classDefFormat = ttUSHORT(classDefTable);
Ivan Mahonin b53a5c
   switch (classDefFormat)
Ivan Mahonin b53a5c
   {
Ivan Mahonin b53a5c
      case 1: {
Ivan Mahonin b53a5c
         stbtt_uint16 startGlyphID = ttUSHORT(classDefTable + 2);
Ivan Mahonin b53a5c
         stbtt_uint16 glyphCount = ttUSHORT(classDefTable + 4);
Ivan Mahonin b53a5c
         stbtt_uint8 *classDef1ValueArray = classDefTable + 6;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
         if (glyph >= startGlyphID && glyph < startGlyphID + glyphCount)
Ivan Mahonin b53a5c
            return (stbtt_int32)ttUSHORT(classDef1ValueArray + 2 * (glyph - startGlyphID));
Ivan Mahonin b53a5c
         break;
Ivan Mahonin b53a5c
      }
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
      case 2: {
Ivan Mahonin b53a5c
         stbtt_uint16 classRangeCount = ttUSHORT(classDefTable + 2);
Ivan Mahonin b53a5c
         stbtt_uint8 *classRangeRecords = classDefTable + 4;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
         // Binary search.
Ivan Mahonin b53a5c
         stbtt_int32 l=0, r=classRangeCount-1, m;
Ivan Mahonin b53a5c
         int strawStart, strawEnd, needle=glyph;
Ivan Mahonin b53a5c
         while (l <= r) {
Ivan Mahonin b53a5c
            stbtt_uint8 *classRangeRecord;
Ivan Mahonin b53a5c
            m = (l + r) >> 1;
Ivan Mahonin b53a5c
            classRangeRecord = classRangeRecords + 6 * m;
Ivan Mahonin b53a5c
            strawStart = ttUSHORT(classRangeRecord);
Ivan Mahonin b53a5c
            strawEnd = ttUSHORT(classRangeRecord + 2);
Ivan Mahonin b53a5c
            if (needle < strawStart)
Ivan Mahonin b53a5c
               r = m - 1;
Ivan Mahonin b53a5c
            else if (needle > strawEnd)
Ivan Mahonin b53a5c
               l = m + 1;
Ivan Mahonin b53a5c
            else
Ivan Mahonin b53a5c
               return (stbtt_int32)ttUSHORT(classRangeRecord + 4);
Ivan Mahonin b53a5c
         }
Ivan Mahonin b53a5c
         break;
Ivan Mahonin b53a5c
      }
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
      default:
Ivan Mahonin b53a5c
         return -1; // Unsupported definition type, return an error.
Ivan Mahonin b53a5c
   }
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   // "All glyphs not assigned to a class fall into class 0". (OpenType spec)
Ivan Mahonin b53a5c
   return 0;
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
// Define to STBTT_assert(x) if you want to break on unimplemented formats.
Ivan Mahonin b53a5c
#define STBTT_GPOS_TODO_assert(x)
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
static stbtt_int32 stbtt__GetGlyphGPOSInfoAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   stbtt_uint16 lookupListOffset;
Ivan Mahonin b53a5c
   stbtt_uint8 *lookupList;
Ivan Mahonin b53a5c
   stbtt_uint16 lookupCount;
Ivan Mahonin b53a5c
   stbtt_uint8 *data;
Ivan Mahonin b53a5c
   stbtt_int32 i, sti;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   if (!info->gpos) return 0;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   data = info->data + info->gpos;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   if (ttUSHORT(data+0) != 1) return 0; // Major version 1
Ivan Mahonin b53a5c
   if (ttUSHORT(data+2) != 0) return 0; // Minor version 0
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   lookupListOffset = ttUSHORT(data+8);
Ivan Mahonin b53a5c
   lookupList = data + lookupListOffset;
Ivan Mahonin b53a5c
   lookupCount = ttUSHORT(lookupList);
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   for (i=0; i
Ivan Mahonin b53a5c
      stbtt_uint16 lookupOffset = ttUSHORT(lookupList + 2 + 2 * i);
Ivan Mahonin b53a5c
      stbtt_uint8 *lookupTable = lookupList + lookupOffset;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
      stbtt_uint16 lookupType = ttUSHORT(lookupTable);
Ivan Mahonin b53a5c
      stbtt_uint16 subTableCount = ttUSHORT(lookupTable + 4);
Ivan Mahonin b53a5c
      stbtt_uint8 *subTableOffsets = lookupTable + 6;
Ivan Mahonin b53a5c
      if (lookupType != 2) // Pair Adjustment Positioning Subtable
Ivan Mahonin b53a5c
         continue;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
      for (sti=0; sti
Ivan Mahonin b53a5c
         stbtt_uint16 subtableOffset = ttUSHORT(subTableOffsets + 2 * sti);
Ivan Mahonin b53a5c
         stbtt_uint8 *table = lookupTable + subtableOffset;
Ivan Mahonin b53a5c
         stbtt_uint16 posFormat = ttUSHORT(table);
Ivan Mahonin b53a5c
         stbtt_uint16 coverageOffset = ttUSHORT(table + 2);
Ivan Mahonin b53a5c
         stbtt_int32 coverageIndex = stbtt__GetCoverageIndex(table + coverageOffset, glyph1);
Ivan Mahonin b53a5c
         if (coverageIndex == -1) continue;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
         switch (posFormat) {
Ivan Mahonin b53a5c
            case 1: {
Ivan Mahonin b53a5c
               stbtt_int32 l, r, m;
Ivan Mahonin b53a5c
               int straw, needle;
Ivan Mahonin b53a5c
               stbtt_uint16 valueFormat1 = ttUSHORT(table + 4);
Ivan Mahonin b53a5c
               stbtt_uint16 valueFormat2 = ttUSHORT(table + 6);
Ivan Mahonin b53a5c
               if (valueFormat1 == 4 && valueFormat2 == 0) { // Support more formats?
Ivan Mahonin b53a5c
                  stbtt_int32 valueRecordPairSizeInBytes = 2;
Ivan Mahonin b53a5c
                  stbtt_uint16 pairSetCount = ttUSHORT(table + 8);
Ivan Mahonin b53a5c
                  stbtt_uint16 pairPosOffset = ttUSHORT(table + 10 + 2 * coverageIndex);
Ivan Mahonin b53a5c
                  stbtt_uint8 *pairValueTable = table + pairPosOffset;
Ivan Mahonin b53a5c
                  stbtt_uint16 pairValueCount = ttUSHORT(pairValueTable);
Ivan Mahonin b53a5c
                  stbtt_uint8 *pairValueArray = pairValueTable + 2;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
                  if (coverageIndex >= pairSetCount) return 0;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
                  needle=glyph2;
Ivan Mahonin b53a5c
                  r=pairValueCount-1;
Ivan Mahonin b53a5c
                  l=0;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
                  // Binary search.
Ivan Mahonin b53a5c
                  while (l <= r) {
Ivan Mahonin b53a5c
                     stbtt_uint16 secondGlyph;
Ivan Mahonin b53a5c
                     stbtt_uint8 *pairValue;
Ivan Mahonin b53a5c
                     m = (l + r) >> 1;
Ivan Mahonin b53a5c
                     pairValue = pairValueArray + (2 + valueRecordPairSizeInBytes) * m;
Ivan Mahonin b53a5c
                     secondGlyph = ttUSHORT(pairValue);
Ivan Mahonin b53a5c
                     straw = secondGlyph;
Ivan Mahonin b53a5c
                     if (needle < straw)
Ivan Mahonin b53a5c
                        r = m - 1;
Ivan Mahonin b53a5c
                     else if (needle > straw)
Ivan Mahonin b53a5c
                        l = m + 1;
Ivan Mahonin b53a5c
                     else {
Ivan Mahonin b53a5c
                        stbtt_int16 xAdvance = ttSHORT(pairValue + 2);
Ivan Mahonin b53a5c
                        return xAdvance;
Ivan Mahonin b53a5c
                     }
Ivan Mahonin b53a5c
                  }
Ivan Mahonin b53a5c
               } else
Ivan Mahonin b53a5c
                  return 0;
Ivan Mahonin b53a5c
               break;
Ivan Mahonin b53a5c
            }
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
            case 2: {
Ivan Mahonin b53a5c
               stbtt_uint16 valueFormat1 = ttUSHORT(table + 4);
Ivan Mahonin b53a5c
               stbtt_uint16 valueFormat2 = ttUSHORT(table + 6);
Ivan Mahonin b53a5c
               if (valueFormat1 == 4 && valueFormat2 == 0) { // Support more formats?
Ivan Mahonin b53a5c
                  stbtt_uint16 classDef1Offset = ttUSHORT(table + 8);
Ivan Mahonin b53a5c
                  stbtt_uint16 classDef2Offset = ttUSHORT(table + 10);
Ivan Mahonin b53a5c
                  int glyph1class = stbtt__GetGlyphClass(table + classDef1Offset, glyph1);
Ivan Mahonin b53a5c
                  int glyph2class = stbtt__GetGlyphClass(table + classDef2Offset, glyph2);
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
                  stbtt_uint16 class1Count = ttUSHORT(table + 12);
Ivan Mahonin b53a5c
                  stbtt_uint16 class2Count = ttUSHORT(table + 14);
Ivan Mahonin b53a5c
                  stbtt_uint8 *class1Records, *class2Records;
Ivan Mahonin b53a5c
                  stbtt_int16 xAdvance;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
                  if (glyph1class < 0 || glyph1class >= class1Count) return 0; // malformed
Ivan Mahonin b53a5c
                  if (glyph2class < 0 || glyph2class >= class2Count) return 0; // malformed
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
                  class1Records = table + 16;
Ivan Mahonin b53a5c
                  class2Records = class1Records + 2 * (glyph1class * class2Count);
Ivan Mahonin b53a5c
                  xAdvance = ttSHORT(class2Records + 2 * glyph2class);
Ivan Mahonin b53a5c
                  return xAdvance;
Ivan Mahonin b53a5c
               } else
Ivan Mahonin b53a5c
                  return 0;
Ivan Mahonin b53a5c
               break;
Ivan Mahonin b53a5c
            }
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
            default:
Ivan Mahonin b53a5c
               return 0; // Unsupported position format
Ivan Mahonin b53a5c
         }
Ivan Mahonin b53a5c
      }
Ivan Mahonin b53a5c
   }
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   return 0;
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
STBTT_DEF int  stbtt_GetGlyphKernAdvance(const stbtt_fontinfo *info, int g1, int g2)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   int xAdvance = 0;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   if (info->gpos)
Ivan Mahonin b53a5c
      xAdvance += stbtt__GetGlyphGPOSInfoAdvance(info, g1, g2);
Ivan Mahonin b53a5c
   else if (info->kern)
Ivan Mahonin b53a5c
      xAdvance += stbtt__GetGlyphKernInfoAdvance(info, g1, g2);
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   return xAdvance;
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
STBTT_DEF int  stbtt_GetCodepointKernAdvance(const stbtt_fontinfo *info, int ch1, int ch2)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   if (!info->kern && !info->gpos) // if no kerning table, don't waste time looking up both codepoint->glyphs
Ivan Mahonin b53a5c
      return 0;
Ivan Mahonin b53a5c
   return stbtt_GetGlyphKernAdvance(info, stbtt_FindGlyphIndex(info,ch1), stbtt_FindGlyphIndex(info,ch2));
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
STBTT_DEF void stbtt_GetCodepointHMetrics(const stbtt_fontinfo *info, int codepoint, int *advanceWidth, int *leftSideBearing)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   stbtt_GetGlyphHMetrics(info, stbtt_FindGlyphIndex(info,codepoint), advanceWidth, leftSideBearing);
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
STBTT_DEF void stbtt_GetFontVMetrics(const stbtt_fontinfo *info, int *ascent, int *descent, int *lineGap)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   if (ascent ) *ascent  = ttSHORT(info->data+info->hhea + 4);
Ivan Mahonin b53a5c
   if (descent) *descent = ttSHORT(info->data+info->hhea + 6);
Ivan Mahonin b53a5c
   if (lineGap) *lineGap = ttSHORT(info->data+info->hhea + 8);
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
STBTT_DEF int  stbtt_GetFontVMetricsOS2(const stbtt_fontinfo *info, int *typoAscent, int *typoDescent, int *typoLineGap)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   int tab = stbtt__find_table(info->data, info->fontstart, "OS/2");
Ivan Mahonin b53a5c
   if (!tab)
Ivan Mahonin b53a5c
      return 0;
Ivan Mahonin b53a5c
   if (typoAscent ) *typoAscent  = ttSHORT(info->data+tab + 68);
Ivan Mahonin b53a5c
   if (typoDescent) *typoDescent = ttSHORT(info->data+tab + 70);
Ivan Mahonin b53a5c
   if (typoLineGap) *typoLineGap = ttSHORT(info->data+tab + 72);
Ivan Mahonin b53a5c
   return 1;
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
STBTT_DEF void stbtt_GetFontBoundingBox(const stbtt_fontinfo *info, int *x0, int *y0, int *x1, int *y1)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   *x0 = ttSHORT(info->data + info->head + 36);
Ivan Mahonin b53a5c
   *y0 = ttSHORT(info->data + info->head + 38);
Ivan Mahonin b53a5c
   *x1 = ttSHORT(info->data + info->head + 40);
Ivan Mahonin b53a5c
   *y1 = ttSHORT(info->data + info->head + 42);
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
STBTT_DEF float stbtt_ScaleForPixelHeight(const stbtt_fontinfo *info, float height)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   int fheight = ttSHORT(info->data + info->hhea + 4) - ttSHORT(info->data + info->hhea + 6);
Ivan Mahonin b53a5c
   return (float) height / fheight;
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
STBTT_DEF float stbtt_ScaleForMappingEmToPixels(const stbtt_fontinfo *info, float pixels)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   int unitsPerEm = ttUSHORT(info->data + info->head + 18);
Ivan Mahonin b53a5c
   return pixels / unitsPerEm;
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
STBTT_DEF void stbtt_FreeShape(const stbtt_fontinfo *info, stbtt_vertex *v)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   STBTT_free(v, info->userdata);
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
STBTT_DEF stbtt_uint8 *stbtt_FindSVGDoc(const stbtt_fontinfo *info, int gl)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   int i;
Ivan Mahonin b53a5c
   stbtt_uint8 *data = info->data;
Ivan Mahonin b53a5c
   stbtt_uint8 *svg_doc_list = data + stbtt__get_svg((stbtt_fontinfo *) info);
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   int numEntries = ttUSHORT(svg_doc_list);
Ivan Mahonin b53a5c
   stbtt_uint8 *svg_docs = svg_doc_list + 2;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   for(i=0; i
Ivan Mahonin b53a5c
      stbtt_uint8 *svg_doc = svg_docs + (12 * i);
Ivan Mahonin b53a5c
      if ((gl >= ttUSHORT(svg_doc)) && (gl <= ttUSHORT(svg_doc + 2)))
Ivan Mahonin b53a5c
         return svg_doc;
Ivan Mahonin b53a5c
   }
Ivan Mahonin b53a5c
   return 0;
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
STBTT_DEF int stbtt_GetGlyphSVG(const stbtt_fontinfo *info, int gl, const char **svg)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   stbtt_uint8 *data = info->data;
Ivan Mahonin b53a5c
   stbtt_uint8 *svg_doc;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   if (info->svg == 0)
Ivan Mahonin b53a5c
      return 0;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   svg_doc = stbtt_FindSVGDoc(info, gl);
Ivan Mahonin b53a5c
   if (svg_doc != NULL) {
Ivan Mahonin b53a5c
      *svg = (char *) data + info->svg + ttULONG(svg_doc + 4);
Ivan Mahonin b53a5c
      return ttULONG(svg_doc + 8);
Ivan Mahonin b53a5c
   } else {
Ivan Mahonin b53a5c
      return 0;
Ivan Mahonin b53a5c
   }
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
STBTT_DEF int stbtt_GetCodepointSVG(const stbtt_fontinfo *info, int unicode_codepoint, const char **svg)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   return stbtt_GetGlyphSVG(info, stbtt_FindGlyphIndex(info, unicode_codepoint), svg);
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
//////////////////////////////////////////////////////////////////////////////
Ivan Mahonin b53a5c
//
Ivan Mahonin b53a5c
// antialiasing software rasterizer
Ivan Mahonin b53a5c
//
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
STBTT_DEF void stbtt_GetGlyphBitmapBoxSubpixel(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y,float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   int x0=0,y0=0,x1,y1; // =0 suppresses compiler warning
Ivan Mahonin b53a5c
   if (!stbtt_GetGlyphBox(font, glyph, &x0,&y0,&x1,&y1)) {
Ivan Mahonin b53a5c
      // e.g. space character
Ivan Mahonin b53a5c
      if (ix0) *ix0 = 0;
Ivan Mahonin b53a5c
      if (iy0) *iy0 = 0;
Ivan Mahonin b53a5c
      if (ix1) *ix1 = 0;
Ivan Mahonin b53a5c
      if (iy1) *iy1 = 0;
Ivan Mahonin b53a5c
   } else {
Ivan Mahonin b53a5c
      // move to integral bboxes (treating pixels as little squares, what pixels get touched)?
Ivan Mahonin b53a5c
      if (ix0) *ix0 = STBTT_ifloor( x0 * scale_x + shift_x);
Ivan Mahonin b53a5c
      if (iy0) *iy0 = STBTT_ifloor(-y1 * scale_y + shift_y);
Ivan Mahonin b53a5c
      if (ix1) *ix1 = STBTT_iceil ( x1 * scale_x + shift_x);
Ivan Mahonin b53a5c
      if (iy1) *iy1 = STBTT_iceil (-y0 * scale_y + shift_y);
Ivan Mahonin b53a5c
   }
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
STBTT_DEF void stbtt_GetGlyphBitmapBox(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   stbtt_GetGlyphBitmapBoxSubpixel(font, glyph, scale_x, scale_y,0.0f,0.0f, ix0, iy0, ix1, iy1);
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
STBTT_DEF void stbtt_GetCodepointBitmapBoxSubpixel(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   stbtt_GetGlyphBitmapBoxSubpixel(font, stbtt_FindGlyphIndex(font,codepoint), scale_x, scale_y,shift_x,shift_y, ix0,iy0,ix1,iy1);
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
STBTT_DEF void stbtt_GetCodepointBitmapBox(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   stbtt_GetCodepointBitmapBoxSubpixel(font, codepoint, scale_x, scale_y,0.0f,0.0f, ix0,iy0,ix1,iy1);
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
//////////////////////////////////////////////////////////////////////////////
Ivan Mahonin b53a5c
//
Ivan Mahonin b53a5c
//  Rasterizer
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
typedef struct stbtt__hheap_chunk
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   struct stbtt__hheap_chunk *next;
Ivan Mahonin b53a5c
} stbtt__hheap_chunk;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
typedef struct stbtt__hheap
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   struct stbtt__hheap_chunk *head;
Ivan Mahonin b53a5c
   void   *first_free;
Ivan Mahonin b53a5c
   int    num_remaining_in_head_chunk;
Ivan Mahonin b53a5c
} stbtt__hheap;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
static void *stbtt__hheap_alloc(stbtt__hheap *hh, size_t size, void *userdata)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   if (hh->first_free) {
Ivan Mahonin b53a5c
      void *p = hh->first_free;
Ivan Mahonin b53a5c
      hh->first_free = * (void **) p;
Ivan Mahonin b53a5c
      return p;
Ivan Mahonin b53a5c
   } else {
Ivan Mahonin b53a5c
      if (hh->num_remaining_in_head_chunk == 0) {
Ivan Mahonin b53a5c
         int count = (size < 32 ? 2000 : size < 128 ? 800 : 100);
Ivan Mahonin b53a5c
         stbtt__hheap_chunk *c = (stbtt__hheap_chunk *) STBTT_malloc(sizeof(stbtt__hheap_chunk) + size * count, userdata);
Ivan Mahonin b53a5c
         if (c == NULL)
Ivan Mahonin b53a5c
            return NULL;
Ivan Mahonin b53a5c
         c->next = hh->head;
Ivan Mahonin b53a5c
         hh->head = c;
Ivan Mahonin b53a5c
         hh->num_remaining_in_head_chunk = count;
Ivan Mahonin b53a5c
      }
Ivan Mahonin b53a5c
      --hh->num_remaining_in_head_chunk;
Ivan Mahonin b53a5c
      return (char *) (hh->head) + sizeof(stbtt__hheap_chunk) + size * hh->num_remaining_in_head_chunk;
Ivan Mahonin b53a5c
   }
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
static void stbtt__hheap_free(stbtt__hheap *hh, void *p)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   *(void **) p = hh->first_free;
Ivan Mahonin b53a5c
   hh->first_free = p;
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
static void stbtt__hheap_cleanup(stbtt__hheap *hh, void *userdata)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   stbtt__hheap_chunk *c = hh->head;
Ivan Mahonin b53a5c
   while (c) {
Ivan Mahonin b53a5c
      stbtt__hheap_chunk *n = c->next;
Ivan Mahonin b53a5c
      STBTT_free(c, userdata);
Ivan Mahonin b53a5c
      c = n;
Ivan Mahonin b53a5c
   }
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
typedef struct stbtt__edge {
Ivan Mahonin b53a5c
   float x0,y0, x1,y1;
Ivan Mahonin b53a5c
   int invert;
Ivan Mahonin b53a5c
} stbtt__edge;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
typedef struct stbtt__active_edge
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   struct stbtt__active_edge *next;
Ivan Mahonin b53a5c
   #if STBTT_RASTERIZER_VERSION==1
Ivan Mahonin b53a5c
   int x,dx;
Ivan Mahonin b53a5c
   float ey;
Ivan Mahonin b53a5c
   int direction;
Ivan Mahonin b53a5c
   #elif STBTT_RASTERIZER_VERSION==2
Ivan Mahonin b53a5c
   float fx,fdx,fdy;
Ivan Mahonin b53a5c
   float direction;
Ivan Mahonin b53a5c
   float sy;
Ivan Mahonin b53a5c
   float ey;
Ivan Mahonin b53a5c
   #else
Ivan Mahonin b53a5c
   #error "Unrecognized value of STBTT_RASTERIZER_VERSION"
Ivan Mahonin b53a5c
   #endif
Ivan Mahonin b53a5c
} stbtt__active_edge;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
#if STBTT_RASTERIZER_VERSION == 1
Ivan Mahonin b53a5c
#define STBTT_FIXSHIFT   10
Ivan Mahonin b53a5c
#define STBTT_FIX        (1 << STBTT_FIXSHIFT)
Ivan Mahonin b53a5c
#define STBTT_FIXMASK    (STBTT_FIX-1)
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
static stbtt__active_edge *stbtt__new_active(stbtt__hheap *hh, stbtt__edge *e, int off_x, float start_point, void *userdata)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   stbtt__active_edge *z = (stbtt__active_edge *) stbtt__hheap_alloc(hh, sizeof(*z), userdata);
Ivan Mahonin b53a5c
   float dxdy = (e->x1 - e->x0) / (e->y1 - e->y0);
Ivan Mahonin b53a5c
   STBTT_assert(z != NULL);
Ivan Mahonin b53a5c
   if (!z) return z;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   // round dx down to avoid overshooting
Ivan Mahonin b53a5c
   if (dxdy < 0)
Ivan Mahonin b53a5c
      z->dx = -STBTT_ifloor(STBTT_FIX * -dxdy);
Ivan Mahonin b53a5c
   else
Ivan Mahonin b53a5c
      z->dx = STBTT_ifloor(STBTT_FIX * dxdy);
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   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
Ivan Mahonin b53a5c
   z->x -= off_x * STBTT_FIX;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   z->ey = e->y1;
Ivan Mahonin b53a5c
   z->next = 0;
Ivan Mahonin b53a5c
   z->direction = e->invert ? 1 : -1;
Ivan Mahonin b53a5c
   return z;
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
#elif STBTT_RASTERIZER_VERSION == 2
Ivan Mahonin b53a5c
static stbtt__active_edge *stbtt__new_active(stbtt__hheap *hh, stbtt__edge *e, int off_x, float start_point, void *userdata)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   stbtt__active_edge *z = (stbtt__active_edge *) stbtt__hheap_alloc(hh, sizeof(*z), userdata);
Ivan Mahonin b53a5c
   float dxdy = (e->x1 - e->x0) / (e->y1 - e->y0);
Ivan Mahonin b53a5c
   STBTT_assert(z != NULL);
Ivan Mahonin b53a5c
   //STBTT_assert(e->y0 <= start_point);
Ivan Mahonin b53a5c
   if (!z) return z;
Ivan Mahonin b53a5c
   z->fdx = dxdy;
Ivan Mahonin b53a5c
   z->fdy = dxdy != 0.0f ? (1.0f/dxdy) : 0.0f;
Ivan Mahonin b53a5c
   z->fx = e->x0 + dxdy * (start_point - e->y0);
Ivan Mahonin b53a5c
   z->fx -= off_x;
Ivan Mahonin b53a5c
   z->direction = e->invert ? 1.0f : -1.0f;
Ivan Mahonin b53a5c
   z->sy = e->y0;
Ivan Mahonin b53a5c
   z->ey = e->y1;
Ivan Mahonin b53a5c
   z->next = 0;
Ivan Mahonin b53a5c
   return z;
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
#else
Ivan Mahonin b53a5c
#error "Unrecognized value of STBTT_RASTERIZER_VERSION"
Ivan Mahonin b53a5c
#endif
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
#if STBTT_RASTERIZER_VERSION == 1
Ivan Mahonin b53a5c
// note: this routine clips fills that extend off the edges... ideally this
Ivan Mahonin b53a5c
// wouldn't happen, but it could happen if the truetype glyph bounding boxes
Ivan Mahonin b53a5c
// are wrong, or if the user supplies a too-small bitmap
Ivan Mahonin b53a5c
static void stbtt__fill_active_edges(unsigned char *scanline, int len, stbtt__active_edge *e, int max_weight)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   // non-zero winding fill
Ivan Mahonin b53a5c
   int x0=0, w=0;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   while (e) {
Ivan Mahonin b53a5c
      if (w == 0) {
Ivan Mahonin b53a5c
         // if we're currently at zero, we need to record the edge start point
Ivan Mahonin b53a5c
         x0 = e->x; w += e->direction;
Ivan Mahonin b53a5c
      } else {
Ivan Mahonin b53a5c
         int x1 = e->x; w += e->direction;
Ivan Mahonin b53a5c
         // if we went to zero, we need to draw
Ivan Mahonin b53a5c
         if (w == 0) {
Ivan Mahonin b53a5c
            int i = x0 >> STBTT_FIXSHIFT;
Ivan Mahonin b53a5c
            int j = x1 >> STBTT_FIXSHIFT;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
            if (i < len && j >= 0) {
Ivan Mahonin b53a5c
               if (i == j) {
Ivan Mahonin b53a5c
                  // x0,x1 are the same pixel, so compute combined coverage
Ivan Mahonin b53a5c
                  scanline[i] = scanline[i] + (stbtt_uint8) ((x1 - x0) * max_weight >> STBTT_FIXSHIFT);
Ivan Mahonin b53a5c
               } else {
Ivan Mahonin b53a5c
                  if (i >= 0) // add antialiasing for x0
Ivan Mahonin b53a5c
                     scanline[i] = scanline[i] + (stbtt_uint8) (((STBTT_FIX - (x0 & STBTT_FIXMASK)) * max_weight) >> STBTT_FIXSHIFT);
Ivan Mahonin b53a5c
                  else
Ivan Mahonin b53a5c
                     i = -1; // clip
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
                  if (j < len) // add antialiasing for x1
Ivan Mahonin b53a5c
                     scanline[j] = scanline[j] + (stbtt_uint8) (((x1 & STBTT_FIXMASK) * max_weight) >> STBTT_FIXSHIFT);
Ivan Mahonin b53a5c
                  else
Ivan Mahonin b53a5c
                     j = len; // clip
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
                  for (++i; i < j; ++i) // fill pixels between x0 and x1
Ivan Mahonin b53a5c
                     scanline[i] = scanline[i] + (stbtt_uint8) max_weight;
Ivan Mahonin b53a5c
               }
Ivan Mahonin b53a5c
            }
Ivan Mahonin b53a5c
         }
Ivan Mahonin b53a5c
      }
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
      e = e->next;
Ivan Mahonin b53a5c
   }
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
static void stbtt__rasterize_sorted_edges(stbtt__bitmap *result, stbtt__edge *e, int n, int vsubsample, int off_x, int off_y, void *userdata)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   stbtt__hheap hh = { 0, 0, 0 };
Ivan Mahonin b53a5c
   stbtt__active_edge *active = NULL;
Ivan Mahonin b53a5c
   int y,j=0;
Ivan Mahonin b53a5c
   int max_weight = (255 / vsubsample);  // weight per vertical scanline
Ivan Mahonin b53a5c
   int s; // vertical subsample index
Ivan Mahonin b53a5c
   unsigned char scanline_data[512], *scanline;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   if (result->w > 512)
Ivan Mahonin b53a5c
      scanline = (unsigned char *) STBTT_malloc(result->w, userdata);
Ivan Mahonin b53a5c
   else
Ivan Mahonin b53a5c
      scanline = scanline_data;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   y = off_y * vsubsample;
Ivan Mahonin b53a5c
   e[n].y0 = (off_y + result->h) * (float) vsubsample + 1;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   while (j < result->h) {
Ivan Mahonin b53a5c
      STBTT_memset(scanline, 0, result->w);
Ivan Mahonin b53a5c
      for (s=0; s < vsubsample; ++s) {
Ivan Mahonin b53a5c
         // find center of pixel for this scanline
Ivan Mahonin b53a5c
         float scan_y = y + 0.5f;
Ivan Mahonin b53a5c
         stbtt__active_edge **step = &active;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
         // update all active edges;
Ivan Mahonin b53a5c
         // remove all active edges that terminate before the center of this scanline
Ivan Mahonin b53a5c
         while (*step) {
Ivan Mahonin b53a5c
            stbtt__active_edge * z = *step;
Ivan Mahonin b53a5c
            if (z->ey <= scan_y) {
Ivan Mahonin b53a5c
               *step = z->next; // delete from list
Ivan Mahonin b53a5c
               STBTT_assert(z->direction);
Ivan Mahonin b53a5c
               z->direction = 0;
Ivan Mahonin b53a5c
               stbtt__hheap_free(&hh, z);
Ivan Mahonin b53a5c
            } else {
Ivan Mahonin b53a5c
               z->x += z->dx; // advance to position for current scanline
Ivan Mahonin b53a5c
               step = &((*step)->next); // advance through list
Ivan Mahonin b53a5c
            }
Ivan Mahonin b53a5c
         }
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
         // resort the list if needed
Ivan Mahonin b53a5c
         for(;;) {
Ivan Mahonin b53a5c
            int changed=0;
Ivan Mahonin b53a5c
            step = &active;
Ivan Mahonin b53a5c
            while (*step && (*step)->next) {
Ivan Mahonin b53a5c
               if ((*step)->x > (*step)->next->x) {
Ivan Mahonin b53a5c
                  stbtt__active_edge *t = *step;
Ivan Mahonin b53a5c
                  stbtt__active_edge *q = t->next;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
                  t->next = q->next;
Ivan Mahonin b53a5c
                  q->next = t;
Ivan Mahonin b53a5c
                  *step = q;
Ivan Mahonin b53a5c
                  changed = 1;
Ivan Mahonin b53a5c
               }
Ivan Mahonin b53a5c
               step = &(*step)->next;
Ivan Mahonin b53a5c
            }
Ivan Mahonin b53a5c
            if (!changed) break;
Ivan Mahonin b53a5c
         }
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
         // insert all edges that start before the center of this scanline -- omit ones that also end on this scanline
Ivan Mahonin b53a5c
         while (e->y0 <= scan_y) {
Ivan Mahonin b53a5c
            if (e->y1 > scan_y) {
Ivan Mahonin b53a5c
               stbtt__active_edge *z = stbtt__new_active(&hh, e, off_x, scan_y, userdata);
Ivan Mahonin b53a5c
               if (z != NULL) {
Ivan Mahonin b53a5c
                  // find insertion point
Ivan Mahonin b53a5c
                  if (active == NULL)
Ivan Mahonin b53a5c
                     active = z;
Ivan Mahonin b53a5c
                  else if (z->x < active->x) {
Ivan Mahonin b53a5c
                     // insert at front
Ivan Mahonin b53a5c
                     z->next = active;
Ivan Mahonin b53a5c
                     active = z;
Ivan Mahonin b53a5c
                  } else {
Ivan Mahonin b53a5c
                     // find thing to insert AFTER
Ivan Mahonin b53a5c
                     stbtt__active_edge *p = active;
Ivan Mahonin b53a5c
                     while (p->next && p->next->x < z->x)
Ivan Mahonin b53a5c
                        p = p->next;
Ivan Mahonin b53a5c
                     // at this point, p->next->x is NOT < z->x
Ivan Mahonin b53a5c
                     z->next = p->next;
Ivan Mahonin b53a5c
                     p->next = z;
Ivan Mahonin b53a5c
                  }
Ivan Mahonin b53a5c
               }
Ivan Mahonin b53a5c
            }
Ivan Mahonin b53a5c
            ++e;
Ivan Mahonin b53a5c
         }
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
         // now process all active edges in XOR fashion
Ivan Mahonin b53a5c
         if (active)
Ivan Mahonin b53a5c
            stbtt__fill_active_edges(scanline, result->w, active, max_weight);
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
         ++y;
Ivan Mahonin b53a5c
      }
Ivan Mahonin b53a5c
      STBTT_memcpy(result->pixels + j * result->stride, scanline, result->w);
Ivan Mahonin b53a5c
      ++j;
Ivan Mahonin b53a5c
   }
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   stbtt__hheap_cleanup(&hh, userdata);
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   if (scanline != scanline_data)
Ivan Mahonin b53a5c
      STBTT_free(scanline, userdata);
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
#elif STBTT_RASTERIZER_VERSION == 2
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
// the edge passed in here does not cross the vertical line at x or the vertical line at x+1
Ivan Mahonin b53a5c
// (i.e. it has already been clipped to those)
Ivan Mahonin b53a5c
static void stbtt__handle_clipped_edge(float *scanline, int x, stbtt__active_edge *e, float x0, float y0, float x1, float y1)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   if (y0 == y1) return;
Ivan Mahonin b53a5c
   STBTT_assert(y0 < y1);
Ivan Mahonin b53a5c
   STBTT_assert(e->sy <= e->ey);
Ivan Mahonin b53a5c
   if (y0 > e->ey) return;
Ivan Mahonin b53a5c
   if (y1 < e->sy) return;
Ivan Mahonin b53a5c
   if (y0 < e->sy) {
Ivan Mahonin b53a5c
      x0 += (x1-x0) * (e->sy - y0) / (y1-y0);
Ivan Mahonin b53a5c
      y0 = e->sy;
Ivan Mahonin b53a5c
   }
Ivan Mahonin b53a5c
   if (y1 > e->ey) {
Ivan Mahonin b53a5c
      x1 += (x1-x0) * (e->ey - y1) / (y1-y0);
Ivan Mahonin b53a5c
      y1 = e->ey;
Ivan Mahonin b53a5c
   }
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   if (x0 == x)
Ivan Mahonin b53a5c
      STBTT_assert(x1 <= x+1);
Ivan Mahonin b53a5c
   else if (x0 == x+1)
Ivan Mahonin b53a5c
      STBTT_assert(x1 >= x);
Ivan Mahonin b53a5c
   else if (x0 <= x)
Ivan Mahonin b53a5c
      STBTT_assert(x1 <= x);
Ivan Mahonin b53a5c
   else if (x0 >= x+1)
Ivan Mahonin b53a5c
      STBTT_assert(x1 >= x+1);
Ivan Mahonin b53a5c
   else
Ivan Mahonin b53a5c
      STBTT_assert(x1 >= x && x1 <= x+1);
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   if (x0 <= x && x1 <= x)
Ivan Mahonin b53a5c
      scanline[x] += e->direction * (y1-y0);
Ivan Mahonin b53a5c
   else if (x0 >= x+1 && x1 >= x+1)
Ivan Mahonin b53a5c
      ;
Ivan Mahonin b53a5c
   else {
Ivan Mahonin b53a5c
      STBTT_assert(x0 >= x && x0 <= x+1 && x1 >= x && x1 <= x+1);
Ivan Mahonin b53a5c
      scanline[x] += e->direction * (y1-y0) * (1-((x0-x)+(x1-x))/2); // coverage = 1 - average x position
Ivan Mahonin b53a5c
   }
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
static float stbtt__sized_trapezoid_area(float height, float top_width, float bottom_width)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   STBTT_assert(top_width >= 0);
Ivan Mahonin b53a5c
   STBTT_assert(bottom_width >= 0);
Ivan Mahonin b53a5c
   return (top_width + bottom_width) / 2.0f * height;
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
static float stbtt__position_trapezoid_area(float height, float tx0, float tx1, float bx0, float bx1)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   return stbtt__sized_trapezoid_area(height, tx1 - tx0, bx1 - bx0);
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
static float stbtt__sized_triangle_area(float height, float width)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   return height * width / 2;
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
static void stbtt__fill_active_edges_new(float *scanline, float *scanline_fill, int len, stbtt__active_edge *e, float y_top)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   float y_bottom = y_top+1;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   while (e) {
Ivan Mahonin b53a5c
      // brute force every pixel
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
      // compute intersection points with top & bottom
Ivan Mahonin b53a5c
      STBTT_assert(e->ey >= y_top);
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
      if (e->fdx == 0) {
Ivan Mahonin b53a5c
         float x0 = e->fx;
Ivan Mahonin b53a5c
         if (x0 < len) {
Ivan Mahonin b53a5c
            if (x0 >= 0) {
Ivan Mahonin b53a5c
               stbtt__handle_clipped_edge(scanline,(int) x0,e, x0,y_top, x0,y_bottom);
Ivan Mahonin b53a5c
               stbtt__handle_clipped_edge(scanline_fill-1,(int) x0+1,e, x0,y_top, x0,y_bottom);
Ivan Mahonin b53a5c
            } else {
Ivan Mahonin b53a5c
               stbtt__handle_clipped_edge(scanline_fill-1,0,e, x0,y_top, x0,y_bottom);
Ivan Mahonin b53a5c
            }
Ivan Mahonin b53a5c
         }
Ivan Mahonin b53a5c
      } else {
Ivan Mahonin b53a5c
         float x0 = e->fx;
Ivan Mahonin b53a5c
         float dx = e->fdx;
Ivan Mahonin b53a5c
         float xb = x0 + dx;
Ivan Mahonin b53a5c
         float x_top, x_bottom;
Ivan Mahonin b53a5c
         float sy0,sy1;
Ivan Mahonin b53a5c
         float dy = e->fdy;
Ivan Mahonin b53a5c
         STBTT_assert(e->sy <= y_bottom && e->ey >= y_top);
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
         // compute endpoints of line segment clipped to this scanline (if the
Ivan Mahonin b53a5c
         // line segment starts on this scanline. x0 is the intersection of the
Ivan Mahonin b53a5c
         // line with y_top, but that may be off the line segment.
Ivan Mahonin b53a5c
         if (e->sy > y_top) {
Ivan Mahonin b53a5c
            x_top = x0 + dx * (e->sy - y_top);
Ivan Mahonin b53a5c
            sy0 = e->sy;
Ivan Mahonin b53a5c
         } else {
Ivan Mahonin b53a5c
            x_top = x0;
Ivan Mahonin b53a5c
            sy0 = y_top;
Ivan Mahonin b53a5c
         }
Ivan Mahonin b53a5c
         if (e->ey < y_bottom) {
Ivan Mahonin b53a5c
            x_bottom = x0 + dx * (e->ey - y_top);
Ivan Mahonin b53a5c
            sy1 = e->ey;
Ivan Mahonin b53a5c
         } else {
Ivan Mahonin b53a5c
            x_bottom = xb;
Ivan Mahonin b53a5c
            sy1 = y_bottom;
Ivan Mahonin b53a5c
         }
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
         if (x_top >= 0 && x_bottom >= 0 && x_top < len && x_bottom < len) {
Ivan Mahonin b53a5c
            // from here on, we don't have to range check x values
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
            if ((int) x_top == (int) x_bottom) {
Ivan Mahonin b53a5c
               float height;
Ivan Mahonin b53a5c
               // simple case, only spans one pixel
Ivan Mahonin b53a5c
               int x = (int) x_top;
Ivan Mahonin b53a5c
               height = (sy1 - sy0) * e->direction;
Ivan Mahonin b53a5c
               STBTT_assert(x >= 0 && x < len);
Ivan Mahonin b53a5c
               scanline[x]      += stbtt__position_trapezoid_area(height, x_top, x+1.0f, x_bottom, x+1.0f);
Ivan Mahonin b53a5c
               scanline_fill[x] += height; // everything right of this pixel is filled
Ivan Mahonin b53a5c
            } else {
Ivan Mahonin b53a5c
               int x,x1,x2;
Ivan Mahonin b53a5c
               float y_crossing, y_final, step, sign, area;
Ivan Mahonin b53a5c
               // covers 2+ pixels
Ivan Mahonin b53a5c
               if (x_top > x_bottom) {
Ivan Mahonin b53a5c
                  // flip scanline vertically; signed area is the same
Ivan Mahonin b53a5c
                  float t;
Ivan Mahonin b53a5c
                  sy0 = y_bottom - (sy0 - y_top);
Ivan Mahonin b53a5c
                  sy1 = y_bottom - (sy1 - y_top);
Ivan Mahonin b53a5c
                  t = sy0, sy0 = sy1, sy1 = t;
Ivan Mahonin b53a5c
                  t = x_bottom, x_bottom = x_top, x_top = t;
Ivan Mahonin b53a5c
                  dx = -dx;
Ivan Mahonin b53a5c
                  dy = -dy;
Ivan Mahonin b53a5c
                  t = x0, x0 = xb, xb = t;
Ivan Mahonin b53a5c
               }
Ivan Mahonin b53a5c
               STBTT_assert(dy >= 0);
Ivan Mahonin b53a5c
               STBTT_assert(dx >= 0);
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
               x1 = (int) x_top;
Ivan Mahonin b53a5c
               x2 = (int) x_bottom;
Ivan Mahonin b53a5c
               // compute intersection with y axis at x1+1
Ivan Mahonin b53a5c
               y_crossing = y_top + dy * (x1+1 - x0);
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
               // compute intersection with y axis at x2
Ivan Mahonin b53a5c
               y_final = y_top + dy * (x2 - x0);
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
               //           x1    x_top                            x2    x_bottom
Ivan Mahonin b53a5c
               //     y_top  +------|-----+------------+------------+--------|---+------------+
Ivan Mahonin b53a5c
               //            |            |            |            |            |            |
Ivan Mahonin b53a5c
               //            |            |            |            |            |            |
Ivan Mahonin b53a5c
               //       sy0  |      Txxxxx|............|............|............|............|
Ivan Mahonin b53a5c
               // y_crossing |            *xxxxx.......|............|............|............|
Ivan Mahonin b53a5c
               //            |            |     xxxxx..|............|............|............|
Ivan Mahonin b53a5c
               //            |            |     /-   xx*xxxx........|............|............|
Ivan Mahonin b53a5c
               //            |            | dy <       |    xxxxxx..|............|............|
Ivan Mahonin b53a5c
               //   y_final  |            |     \-     |          xx*xxx.........|............|
Ivan Mahonin b53a5c
               //       sy1  |            |            |            |   xxxxxB...|............|
Ivan Mahonin b53a5c
               //            |            |            |            |            |            |
Ivan Mahonin b53a5c
               //            |            |            |            |            |            |
Ivan Mahonin b53a5c
               //  y_bottom  +------------+------------+------------+------------+------------+
Ivan Mahonin b53a5c
               //
Ivan Mahonin b53a5c
               // goal is to measure the area covered by '.' in each pixel
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
               // if x2 is right at the right edge of x1, y_crossing can blow up, github #1057
Ivan Mahonin b53a5c
               // @TODO: maybe test against sy1 rather than y_bottom?
Ivan Mahonin b53a5c
               if (y_crossing > y_bottom)
Ivan Mahonin b53a5c
                  y_crossing = y_bottom;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
               sign = e->direction;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
               // area of the rectangle covered from sy0..y_crossing
Ivan Mahonin b53a5c
               area = sign * (y_crossing-sy0);
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
               // area of the triangle (x_top,sy0), (x1+1,sy0), (x1+1,y_crossing)
Ivan Mahonin b53a5c
               scanline[x1] += stbtt__sized_triangle_area(area, x1+1 - x_top);
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
               // check if final y_crossing is blown up; no test case for this
Ivan Mahonin b53a5c
               if (y_final > y_bottom) {
Ivan Mahonin b53a5c
                  y_final = y_bottom;
Ivan Mahonin b53a5c
                  dy = (y_final - y_crossing ) / (x2 - (x1+1)); // if denom=0, y_final = y_crossing, so y_final <= y_bottom
Ivan Mahonin b53a5c
               }
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
               // in second pixel, area covered by line segment found in first pixel
Ivan Mahonin b53a5c
               // is always a rectangle 1 wide * the height of that line segment; this
Ivan Mahonin b53a5c
               // is exactly what the variable 'area' stores. it also gets a contribution
Ivan Mahonin b53a5c
               // from the line segment within it. the THIRD pixel will get the first
Ivan Mahonin b53a5c
               // pixel's rectangle contribution, the second pixel's rectangle contribution,
Ivan Mahonin b53a5c
               // and its own contribution. the 'own contribution' is the same in every pixel except
Ivan Mahonin b53a5c
               // the leftmost and rightmost, a trapezoid that slides down in each pixel.
Ivan Mahonin b53a5c
               // the second pixel's contribution to the third pixel will be the
Ivan Mahonin b53a5c
               // rectangle 1 wide times the height change in the second pixel, which is dy.
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
               step = sign * dy * 1; // dy is dy/dx, change in y for every 1 change in x,
Ivan Mahonin b53a5c
               // which multiplied by 1-pixel-width is how much pixel area changes for each step in x
Ivan Mahonin b53a5c
               // so the area advances by 'step' every time
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
               for (x = x1+1; x < x2; ++x) {
Ivan Mahonin b53a5c
                  scanline[x] += area + step/2; // area of trapezoid is 1*step/2
Ivan Mahonin b53a5c
                  area += step;
Ivan Mahonin b53a5c
               }
Ivan Mahonin b53a5c
               STBTT_assert(STBTT_fabs(area) <= 1.01f); // accumulated error from area += step unless we round step down
Ivan Mahonin b53a5c
               STBTT_assert(sy1 > y_final-0.01f);
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
               // area covered in the last pixel is the rectangle from all the pixels to the left,
Ivan Mahonin b53a5c
               // plus the trapezoid filled by the line segment in this pixel all the way to the right edge
Ivan Mahonin b53a5c
               scanline[x2] += area + sign * stbtt__position_trapezoid_area(sy1-y_final, (float) x2, x2+1.0f, x_bottom, x2+1.0f);
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
               // the rest of the line is filled based on the total height of the line segment in this pixel
Ivan Mahonin b53a5c
               scanline_fill[x2] += sign * (sy1-sy0);
Ivan Mahonin b53a5c
            }
Ivan Mahonin b53a5c
         } else {
Ivan Mahonin b53a5c
            // if edge goes outside of box we're drawing, we require
Ivan Mahonin b53a5c
            // clipping logic. since this does not match the intended use
Ivan Mahonin b53a5c
            // of this library, we use a different, very slow brute
Ivan Mahonin b53a5c
            // force implementation
Ivan Mahonin b53a5c
            // note though that this does happen some of the time because
Ivan Mahonin b53a5c
            // x_top and x_bottom can be extrapolated at the top & bottom of
Ivan Mahonin b53a5c
            // the shape and actually lie outside the bounding box
Ivan Mahonin b53a5c
            int x;
Ivan Mahonin b53a5c
            for (x=0; x < len; ++x) {
Ivan Mahonin b53a5c
               // cases:
Ivan Mahonin b53a5c
               //
Ivan Mahonin b53a5c
               // there can be up to two intersections with the pixel. any intersection
Ivan Mahonin b53a5c
               // with left or right edges can be handled by splitting into two (or three)
Ivan Mahonin b53a5c
               // regions. intersections with top & bottom do not necessitate case-wise logic.
Ivan Mahonin b53a5c
               //
Ivan Mahonin b53a5c
               // the old way of doing this found the intersections with the left & right edges,
Ivan Mahonin b53a5c
               // then used some simple logic to produce up to three segments in sorted order
Ivan Mahonin b53a5c
               // from top-to-bottom. however, this had a problem: if an x edge was epsilon
Ivan Mahonin b53a5c
               // across the x border, then the corresponding y position might not be distinct
Ivan Mahonin b53a5c
               // from the other y segment, and it might ignored as an empty segment. to avoid
Ivan Mahonin b53a5c
               // that, we need to explicitly produce segments based on x positions.
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
               // rename variables to clearly-defined pairs
Ivan Mahonin b53a5c
               float y0 = y_top;
Ivan Mahonin b53a5c
               float x1 = (float) (x);
Ivan Mahonin b53a5c
               float x2 = (float) (x+1);
Ivan Mahonin b53a5c
               float x3 = xb;
Ivan Mahonin b53a5c
               float y3 = y_bottom;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
               // x = e->x + e->dx * (y-y_top)
Ivan Mahonin b53a5c
               // (y-y_top) = (x - e->x) / e->dx
Ivan Mahonin b53a5c
               // y = (x - e->x) / e->dx + y_top
Ivan Mahonin b53a5c
               float y1 = (x - x0) / dx + y_top;
Ivan Mahonin b53a5c
               float y2 = (x+1 - x0) / dx + y_top;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
               if (x0 < x1 && x3 > x2) {         // three segments descending down-right
Ivan Mahonin b53a5c
                  stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x1,y1);
Ivan Mahonin b53a5c
                  stbtt__handle_clipped_edge(scanline,x,e, x1,y1, x2,y2);
Ivan Mahonin b53a5c
                  stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x3,y3);
Ivan Mahonin b53a5c
               } else if (x3 < x1 && x0 > x2) {  // three segments descending down-left
Ivan Mahonin b53a5c
                  stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x2,y2);
Ivan Mahonin b53a5c
                  stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x1,y1);
Ivan Mahonin b53a5c
                  stbtt__handle_clipped_edge(scanline,x,e, x1,y1, x3,y3);
Ivan Mahonin b53a5c
               } else if (x0 < x1 && x3 > x1) {  // two segments across x, down-right
Ivan Mahonin b53a5c
                  stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x1,y1);
Ivan Mahonin b53a5c
                  stbtt__handle_clipped_edge(scanline,x,e, x1,y1, x3,y3);
Ivan Mahonin b53a5c
               } else if (x3 < x1 && x0 > x1) {  // two segments across x, down-left
Ivan Mahonin b53a5c
                  stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x1,y1);
Ivan Mahonin b53a5c
                  stbtt__handle_clipped_edge(scanline,x,e, x1,y1, x3,y3);
Ivan Mahonin b53a5c
               } else if (x0 < x2 && x3 > x2) {  // two segments across x+1, down-right
Ivan Mahonin b53a5c
                  stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x2,y2);
Ivan Mahonin b53a5c
                  stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x3,y3);
Ivan Mahonin b53a5c
               } else if (x3 < x2 && x0 > x2) {  // two segments across x+1, down-left
Ivan Mahonin b53a5c
                  stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x2,y2);
Ivan Mahonin b53a5c
                  stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x3,y3);
Ivan Mahonin b53a5c
               } else {  // one segment
Ivan Mahonin b53a5c
                  stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x3,y3);
Ivan Mahonin b53a5c
               }
Ivan Mahonin b53a5c
            }
Ivan Mahonin b53a5c
         }
Ivan Mahonin b53a5c
      }
Ivan Mahonin b53a5c
      e = e->next;
Ivan Mahonin b53a5c
   }
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
// directly AA rasterize edges w/o supersampling
Ivan Mahonin b53a5c
static void stbtt__rasterize_sorted_edges(stbtt__bitmap *result, stbtt__edge *e, int n, int vsubsample, int off_x, int off_y, void *userdata)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   stbtt__hheap hh = { 0, 0, 0 };
Ivan Mahonin b53a5c
   stbtt__active_edge *active = NULL;
Ivan Mahonin b53a5c
   int y,j=0, i;
Ivan Mahonin b53a5c
   float scanline_data[129], *scanline, *scanline2;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   STBTT__NOTUSED(vsubsample);
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   if (result->w > 64)
Ivan Mahonin b53a5c
      scanline = (float *) STBTT_malloc((result->w*2+1) * sizeof(float), userdata);
Ivan Mahonin b53a5c
   else
Ivan Mahonin b53a5c
      scanline = scanline_data;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   scanline2 = scanline + result->w;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   y = off_y;
Ivan Mahonin b53a5c
   e[n].y0 = (float) (off_y + result->h) + 1;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   while (j < result->h) {
Ivan Mahonin b53a5c
      // find center of pixel for this scanline
Ivan Mahonin b53a5c
      float scan_y_top    = y + 0.0f;
Ivan Mahonin b53a5c
      float scan_y_bottom = y + 1.0f;
Ivan Mahonin b53a5c
      stbtt__active_edge **step = &active;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
      STBTT_memset(scanline , 0, result->w*sizeof(scanline[0]));
Ivan Mahonin b53a5c
      STBTT_memset(scanline2, 0, (result->w+1)*sizeof(scanline[0]));
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
      // update all active edges;
Ivan Mahonin b53a5c
      // remove all active edges that terminate before the top of this scanline
Ivan Mahonin b53a5c
      while (*step) {
Ivan Mahonin b53a5c
         stbtt__active_edge * z = *step;
Ivan Mahonin b53a5c
         if (z->ey <= scan_y_top) {
Ivan Mahonin b53a5c
            *step = z->next; // delete from list
Ivan Mahonin b53a5c
            STBTT_assert(z->direction);
Ivan Mahonin b53a5c
            z->direction = 0;
Ivan Mahonin b53a5c
            stbtt__hheap_free(&hh, z);
Ivan Mahonin b53a5c
         } else {
Ivan Mahonin b53a5c
            step = &((*step)->next); // advance through list
Ivan Mahonin b53a5c
         }
Ivan Mahonin b53a5c
      }
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
      // insert all edges that start before the bottom of this scanline
Ivan Mahonin b53a5c
      while (e->y0 <= scan_y_bottom) {
Ivan Mahonin b53a5c
         if (e->y0 != e->y1) {
Ivan Mahonin b53a5c
            stbtt__active_edge *z = stbtt__new_active(&hh, e, off_x, scan_y_top, userdata);
Ivan Mahonin b53a5c
            if (z != NULL) {
Ivan Mahonin b53a5c
               if (j == 0 && off_y != 0) {
Ivan Mahonin b53a5c
                  if (z->ey < scan_y_top) {
Ivan Mahonin b53a5c
                     // this can happen due to subpixel positioning and some kind of fp rounding error i think
Ivan Mahonin b53a5c
                     z->ey = scan_y_top;
Ivan Mahonin b53a5c
                  }
Ivan Mahonin b53a5c
               }
Ivan Mahonin b53a5c
               STBTT_assert(z->ey >= scan_y_top); // if we get really unlucky a tiny bit of an edge can be out of bounds
Ivan Mahonin b53a5c
               // insert at front
Ivan Mahonin b53a5c
               z->next = active;
Ivan Mahonin b53a5c
               active = z;
Ivan Mahonin b53a5c
            }
Ivan Mahonin b53a5c
         }
Ivan Mahonin b53a5c
         ++e;
Ivan Mahonin b53a5c
      }
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
      // now process all active edges
Ivan Mahonin b53a5c
      if (active)
Ivan Mahonin b53a5c
         stbtt__fill_active_edges_new(scanline, scanline2+1, result->w, active, scan_y_top);
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
      {
Ivan Mahonin b53a5c
         float sum = 0;
Ivan Mahonin b53a5c
         for (i=0; i < result->w; ++i) {
Ivan Mahonin b53a5c
            float k;
Ivan Mahonin b53a5c
            int m;
Ivan Mahonin b53a5c
            sum += scanline2[i];
Ivan Mahonin b53a5c
            k = scanline[i] + sum;
Ivan Mahonin b53a5c
            k = (float) STBTT_fabs(k)*255 + 0.5f;
Ivan Mahonin b53a5c
            m = (int) k;
Ivan Mahonin b53a5c
            if (m > 255) m = 255;
Ivan Mahonin b53a5c
            result->pixels[j*result->stride + i] = (unsigned char) m;
Ivan Mahonin b53a5c
         }
Ivan Mahonin b53a5c
      }
Ivan Mahonin b53a5c
      // advance all the edges
Ivan Mahonin b53a5c
      step = &active;
Ivan Mahonin b53a5c
      while (*step) {
Ivan Mahonin b53a5c
         stbtt__active_edge *z = *step;
Ivan Mahonin b53a5c
         z->fx += z->fdx; // advance to position for current scanline
Ivan Mahonin b53a5c
         step = &((*step)->next); // advance through list
Ivan Mahonin b53a5c
      }
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
      ++y;
Ivan Mahonin b53a5c
      ++j;
Ivan Mahonin b53a5c
   }
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   stbtt__hheap_cleanup(&hh, userdata);
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   if (scanline != scanline_data)
Ivan Mahonin b53a5c
      STBTT_free(scanline, userdata);
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
#else
Ivan Mahonin b53a5c
#error "Unrecognized value of STBTT_RASTERIZER_VERSION"
Ivan Mahonin b53a5c
#endif
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
#define STBTT__COMPARE(a,b)  ((a)->y0 < (b)->y0)
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
static void stbtt__sort_edges_ins_sort(stbtt__edge *p, int n)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   int i,j;
Ivan Mahonin b53a5c
   for (i=1; i < n; ++i) {
Ivan Mahonin b53a5c
      stbtt__edge t = p[i], *a = &t;
Ivan Mahonin b53a5c
      j = i;
Ivan Mahonin b53a5c
      while (j > 0) {
Ivan Mahonin b53a5c
         stbtt__edge *b = &p[j-1];
Ivan Mahonin b53a5c
         int c = STBTT__COMPARE(a,b);
Ivan Mahonin b53a5c
         if (!c) break;
Ivan Mahonin b53a5c
         p[j] = p[j-1];
Ivan Mahonin b53a5c
         --j;
Ivan Mahonin b53a5c
      }
Ivan Mahonin b53a5c
      if (i != j)
Ivan Mahonin b53a5c
         p[j] = t;
Ivan Mahonin b53a5c
   }
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
static void stbtt__sort_edges_quicksort(stbtt__edge *p, int n)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   /* threshold for transitioning to insertion sort */
Ivan Mahonin b53a5c
   while (n > 12) {
Ivan Mahonin b53a5c
      stbtt__edge t;
Ivan Mahonin b53a5c
      int c01,c12,c,m,i,j;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
      /* compute median of three */
Ivan Mahonin b53a5c
      m = n >> 1;
Ivan Mahonin b53a5c
      c01 = STBTT__COMPARE(&p[0],&p[m]);
Ivan Mahonin b53a5c
      c12 = STBTT__COMPARE(&p[m],&p[n-1]);
Ivan Mahonin b53a5c
      /* if 0 >= mid >= end, or 0 < mid < end, then use mid */
Ivan Mahonin b53a5c
      if (c01 != c12) {
Ivan Mahonin b53a5c
         /* otherwise, we'll need to swap something else to middle */
Ivan Mahonin b53a5c
         int z;
Ivan Mahonin b53a5c
         c = STBTT__COMPARE(&p[0],&p[n-1]);
Ivan Mahonin b53a5c
         /* 0>mid && mid<n:  0>n => n; 0<n => 0 */
Ivan Mahonin b53a5c
         /* 0<mid && mid>n:  0>n => 0; 0<n => n */
Ivan Mahonin b53a5c
         z = (c == c12) ? 0 : n-1;
Ivan Mahonin b53a5c
         t = p[z];
Ivan Mahonin b53a5c
         p[z] = p[m];
Ivan Mahonin b53a5c
         p[m] = t;
Ivan Mahonin b53a5c
      }
Ivan Mahonin b53a5c
      /* now p[m] is the median-of-three */
Ivan Mahonin b53a5c
      /* swap it to the beginning so it won't move around */
Ivan Mahonin b53a5c
      t = p[0];
Ivan Mahonin b53a5c
      p[0] = p[m];
Ivan Mahonin b53a5c
      p[m] = t;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
      /* partition loop */
Ivan Mahonin b53a5c
      i=1;
Ivan Mahonin b53a5c
      j=n-1;
Ivan Mahonin b53a5c
      for(;;) {
Ivan Mahonin b53a5c
         /* handling of equality is crucial here */
Ivan Mahonin b53a5c
         /* for sentinels & efficiency with duplicates */
Ivan Mahonin b53a5c
         for (;;++i) {
Ivan Mahonin b53a5c
            if (!STBTT__COMPARE(&p[i], &p[0])) break;
Ivan Mahonin b53a5c
         }
Ivan Mahonin b53a5c
         for (;;--j) {
Ivan Mahonin b53a5c
            if (!STBTT__COMPARE(&p[0], &p[j])) break;
Ivan Mahonin b53a5c
         }
Ivan Mahonin b53a5c
         /* make sure we haven't crossed */
Ivan Mahonin b53a5c
         if (i >= j) break;
Ivan Mahonin b53a5c
         t = p[i];
Ivan Mahonin b53a5c
         p[i] = p[j];
Ivan Mahonin b53a5c
         p[j] = t;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
         ++i;
Ivan Mahonin b53a5c
         --j;
Ivan Mahonin b53a5c
      }
Ivan Mahonin b53a5c
      /* recurse on smaller side, iterate on larger */
Ivan Mahonin b53a5c
      if (j < (n-i)) {
Ivan Mahonin b53a5c
         stbtt__sort_edges_quicksort(p,j);
Ivan Mahonin b53a5c
         p = p+i;
Ivan Mahonin b53a5c
         n = n-i;
Ivan Mahonin b53a5c
      } else {
Ivan Mahonin b53a5c
         stbtt__sort_edges_quicksort(p+i, n-i);
Ivan Mahonin b53a5c
         n = j;
Ivan Mahonin b53a5c
      }
Ivan Mahonin b53a5c
   }
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
static void stbtt__sort_edges(stbtt__edge *p, int n)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   stbtt__sort_edges_quicksort(p, n);
Ivan Mahonin b53a5c
   stbtt__sort_edges_ins_sort(p, n);
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
typedef struct
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   float x,y;
Ivan Mahonin b53a5c
} stbtt__point;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
static 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)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   float y_scale_inv = invert ? -scale_y : scale_y;
Ivan Mahonin b53a5c
   stbtt__edge *e;
Ivan Mahonin b53a5c
   int n,i,j,k,m;
Ivan Mahonin b53a5c
#if STBTT_RASTERIZER_VERSION == 1
Ivan Mahonin b53a5c
   int vsubsample = result->h < 8 ? 15 : 5;
Ivan Mahonin b53a5c
#elif STBTT_RASTERIZER_VERSION == 2
Ivan Mahonin b53a5c
   int vsubsample = 1;
Ivan Mahonin b53a5c
#else
Ivan Mahonin b53a5c
   #error "Unrecognized value of STBTT_RASTERIZER_VERSION"
Ivan Mahonin b53a5c
#endif
Ivan Mahonin b53a5c
   // vsubsample should divide 255 evenly; otherwise we won't reach full opacity
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   // now we have to blow out the windings into explicit edge lists
Ivan Mahonin b53a5c
   n = 0;
Ivan Mahonin b53a5c
   for (i=0; i < windings; ++i)
Ivan Mahonin b53a5c
      n += wcount[i];
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   e = (stbtt__edge *) STBTT_malloc(sizeof(*e) * (n+1), userdata); // add an extra one as a sentinel
Ivan Mahonin b53a5c
   if (e == 0) return;
Ivan Mahonin b53a5c
   n = 0;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   m=0;
Ivan Mahonin b53a5c
   for (i=0; i < windings; ++i) {
Ivan Mahonin b53a5c
      stbtt__point *p = pts + m;
Ivan Mahonin b53a5c
      m += wcount[i];
Ivan Mahonin b53a5c
      j = wcount[i]-1;
Ivan Mahonin b53a5c
      for (k=0; k < wcount[i]; j=k++) {
Ivan Mahonin b53a5c
         int a=k,b=j;
Ivan Mahonin b53a5c
         // skip the edge if horizontal
Ivan Mahonin b53a5c
         if (p[j].y == p[k].y)
Ivan Mahonin b53a5c
            continue;
Ivan Mahonin b53a5c
         // add edge from j to k to the list
Ivan Mahonin b53a5c
         e[n].invert = 0;
Ivan Mahonin b53a5c
         if (invert ? p[j].y > p[k].y : p[j].y < p[k].y) {
Ivan Mahonin b53a5c
            e[n].invert = 1;
Ivan Mahonin b53a5c
            a=j,b=k;
Ivan Mahonin b53a5c
         }
Ivan Mahonin b53a5c
         e[n].x0 = p[a].x * scale_x + shift_x;
Ivan Mahonin b53a5c
         e[n].y0 = (p[a].y * y_scale_inv + shift_y) * vsubsample;
Ivan Mahonin b53a5c
         e[n].x1 = p[b].x * scale_x + shift_x;
Ivan Mahonin b53a5c
         e[n].y1 = (p[b].y * y_scale_inv + shift_y) * vsubsample;
Ivan Mahonin b53a5c
         ++n;
Ivan Mahonin b53a5c
      }
Ivan Mahonin b53a5c
   }
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   // now sort the edges by their highest point (should snap to integer, and then by x)
Ivan Mahonin b53a5c
   //STBTT_sort(e, n, sizeof(e[0]), stbtt__edge_compare);
Ivan Mahonin b53a5c
   stbtt__sort_edges(e, n);
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   // now, traverse the scanlines and find the intersections on each scanline, use xor winding rule
Ivan Mahonin b53a5c
   stbtt__rasterize_sorted_edges(result, e, n, vsubsample, off_x, off_y, userdata);
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   STBTT_free(e, userdata);
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
static void stbtt__add_point(stbtt__point *points, int n, float x, float y)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   if (!points) return; // during first pass, it's unallocated
Ivan Mahonin b53a5c
   points[n].x = x;
Ivan Mahonin b53a5c
   points[n].y = y;
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
// tessellate until threshold p is happy... @TODO warped to compensate for non-linear stretching
Ivan Mahonin b53a5c
static 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)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   // midpoint
Ivan Mahonin b53a5c
   float mx = (x0 + 2*x1 + x2)/4;
Ivan Mahonin b53a5c
   float my = (y0 + 2*y1 + y2)/4;
Ivan Mahonin b53a5c
   // versus directly drawn line
Ivan Mahonin b53a5c
   float dx = (x0+x2)/2 - mx;
Ivan Mahonin b53a5c
   float dy = (y0+y2)/2 - my;
Ivan Mahonin b53a5c
   if (n > 16) // 65536 segments on one curve better be enough!
Ivan Mahonin b53a5c
      return 1;
Ivan Mahonin b53a5c
   if (dx*dx+dy*dy > objspace_flatness_squared) { // half-pixel error allowed... need to be smaller if AA
Ivan Mahonin b53a5c
      stbtt__tesselate_curve(points, num_points, x0,y0, (x0+x1)/2.0f,(y0+y1)/2.0f, mx,my, objspace_flatness_squared,n+1);
Ivan Mahonin b53a5c
      stbtt__tesselate_curve(points, num_points, mx,my, (x1+x2)/2.0f,(y1+y2)/2.0f, x2,y2, objspace_flatness_squared,n+1);
Ivan Mahonin b53a5c
   } else {
Ivan Mahonin b53a5c
      stbtt__add_point(points, *num_points,x2,y2);
Ivan Mahonin b53a5c
      *num_points = *num_points+1;
Ivan Mahonin b53a5c
   }
Ivan Mahonin b53a5c
   return 1;
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
static 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)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   // @TODO this "flatness" calculation is just made-up nonsense that seems to work well enough
Ivan Mahonin b53a5c
   float dx0 = x1-x0;
Ivan Mahonin b53a5c
   float dy0 = y1-y0;
Ivan Mahonin b53a5c
   float dx1 = x2-x1;
Ivan Mahonin b53a5c
   float dy1 = y2-y1;
Ivan Mahonin b53a5c
   float dx2 = x3-x2;
Ivan Mahonin b53a5c
   float dy2 = y3-y2;
Ivan Mahonin b53a5c
   float dx = x3-x0;
Ivan Mahonin b53a5c
   float dy = y3-y0;
Ivan Mahonin b53a5c
   float longlen = (float) (STBTT_sqrt(dx0*dx0+dy0*dy0)+STBTT_sqrt(dx1*dx1+dy1*dy1)+STBTT_sqrt(dx2*dx2+dy2*dy2));
Ivan Mahonin b53a5c
   float shortlen = (float) STBTT_sqrt(dx*dx+dy*dy);
Ivan Mahonin b53a5c
   float flatness_squared = longlen*longlen-shortlen*shortlen;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   if (n > 16) // 65536 segments on one curve better be enough!
Ivan Mahonin b53a5c
      return;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   if (flatness_squared > objspace_flatness_squared) {
Ivan Mahonin b53a5c
      float x01 = (x0+x1)/2;
Ivan Mahonin b53a5c
      float y01 = (y0+y1)/2;
Ivan Mahonin b53a5c
      float x12 = (x1+x2)/2;
Ivan Mahonin b53a5c
      float y12 = (y1+y2)/2;
Ivan Mahonin b53a5c
      float x23 = (x2+x3)/2;
Ivan Mahonin b53a5c
      float y23 = (y2+y3)/2;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
      float xa = (x01+x12)/2;
Ivan Mahonin b53a5c
      float ya = (y01+y12)/2;
Ivan Mahonin b53a5c
      float xb = (x12+x23)/2;
Ivan Mahonin b53a5c
      float yb = (y12+y23)/2;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
      float mx = (xa+xb)/2;
Ivan Mahonin b53a5c
      float my = (ya+yb)/2;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
      stbtt__tesselate_cubic(points, num_points, x0,y0, x01,y01, xa,ya, mx,my, objspace_flatness_squared,n+1);
Ivan Mahonin b53a5c
      stbtt__tesselate_cubic(points, num_points, mx,my, xb,yb, x23,y23, x3,y3, objspace_flatness_squared,n+1);
Ivan Mahonin b53a5c
   } else {
Ivan Mahonin b53a5c
      stbtt__add_point(points, *num_points,x3,y3);
Ivan Mahonin b53a5c
      *num_points = *num_points+1;
Ivan Mahonin b53a5c
   }
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
// returns number of contours
Ivan Mahonin b53a5c
static stbtt__point *stbtt_FlattenCurves(stbtt_vertex *vertices, int num_verts, float objspace_flatness, int **contour_lengths, int *num_contours, void *userdata)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   stbtt__point *points=0;
Ivan Mahonin b53a5c
   int num_points=0;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   float objspace_flatness_squared = objspace_flatness * objspace_flatness;
Ivan Mahonin b53a5c
   int i,n=0,start=0, pass;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   // count how many "moves" there are to get the contour count
Ivan Mahonin b53a5c
   for (i=0; i < num_verts; ++i)
Ivan Mahonin b53a5c
      if (vertices[i].type == STBTT_vmove)
Ivan Mahonin b53a5c
         ++n;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   *num_contours = n;
Ivan Mahonin b53a5c
   if (n == 0) return 0;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   *contour_lengths = (int *) STBTT_malloc(sizeof(**contour_lengths) * n, userdata);
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   if (*contour_lengths == 0) {
Ivan Mahonin b53a5c
      *num_contours = 0;
Ivan Mahonin b53a5c
      return 0;
Ivan Mahonin b53a5c
   }
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   // make two passes through the points so we don't need to realloc
Ivan Mahonin b53a5c
   for (pass=0; pass < 2; ++pass) {
Ivan Mahonin b53a5c
      float x=0,y=0;
Ivan Mahonin b53a5c
      if (pass == 1) {
Ivan Mahonin b53a5c
         points = (stbtt__point *) STBTT_malloc(num_points * sizeof(points[0]), userdata);
Ivan Mahonin b53a5c
         if (points == NULL) goto error;
Ivan Mahonin b53a5c
      }
Ivan Mahonin b53a5c
      num_points = 0;
Ivan Mahonin b53a5c
      n= -1;
Ivan Mahonin b53a5c
      for (i=0; i < num_verts; ++i) {
Ivan Mahonin b53a5c
         switch (vertices[i].type) {
Ivan Mahonin b53a5c
            case STBTT_vmove:
Ivan Mahonin b53a5c
               // start the next contour
Ivan Mahonin b53a5c
               if (n >= 0)
Ivan Mahonin b53a5c
                  (*contour_lengths)[n] = num_points - start;
Ivan Mahonin b53a5c
               ++n;
Ivan Mahonin b53a5c
               start = num_points;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
               x = vertices[i].x, y = vertices[i].y;
Ivan Mahonin b53a5c
               stbtt__add_point(points, num_points++, x,y);
Ivan Mahonin b53a5c
               break;
Ivan Mahonin b53a5c
            case STBTT_vline:
Ivan Mahonin b53a5c
               x = vertices[i].x, y = vertices[i].y;
Ivan Mahonin b53a5c
               stbtt__add_point(points, num_points++, x, y);
Ivan Mahonin b53a5c
               break;
Ivan Mahonin b53a5c
            case STBTT_vcurve:
Ivan Mahonin b53a5c
               stbtt__tesselate_curve(points, &num_points, x,y,
Ivan Mahonin b53a5c
                                        vertices[i].cx, vertices[i].cy,
Ivan Mahonin b53a5c
                                        vertices[i].x,  vertices[i].y,
Ivan Mahonin b53a5c
                                        objspace_flatness_squared, 0);
Ivan Mahonin b53a5c
               x = vertices[i].x, y = vertices[i].y;
Ivan Mahonin b53a5c
               break;
Ivan Mahonin b53a5c
            case STBTT_vcubic:
Ivan Mahonin b53a5c
               stbtt__tesselate_cubic(points, &num_points, x,y,
Ivan Mahonin b53a5c
                                        vertices[i].cx, vertices[i].cy,
Ivan Mahonin b53a5c
                                        vertices[i].cx1, vertices[i].cy1,
Ivan Mahonin b53a5c
                                        vertices[i].x,  vertices[i].y,
Ivan Mahonin b53a5c
                                        objspace_flatness_squared, 0);
Ivan Mahonin b53a5c
               x = vertices[i].x, y = vertices[i].y;
Ivan Mahonin b53a5c
               break;
Ivan Mahonin b53a5c
         }
Ivan Mahonin b53a5c
      }
Ivan Mahonin b53a5c
      (*contour_lengths)[n] = num_points - start;
Ivan Mahonin b53a5c
   }
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   return points;
Ivan Mahonin b53a5c
error:
Ivan Mahonin b53a5c
   STBTT_free(points, userdata);
Ivan Mahonin b53a5c
   STBTT_free(*contour_lengths, userdata);
Ivan Mahonin b53a5c
   *contour_lengths = 0;
Ivan Mahonin b53a5c
   *num_contours = 0;
Ivan Mahonin b53a5c
   return NULL;
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
STBTT_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)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   float scale            = scale_x > scale_y ? scale_y : scale_x;
Ivan Mahonin b53a5c
   int winding_count      = 0;
Ivan Mahonin b53a5c
   int *winding_lengths   = NULL;
Ivan Mahonin b53a5c
   stbtt__point *windings = stbtt_FlattenCurves(vertices, num_verts, flatness_in_pixels / scale, &winding_lengths, &winding_count, userdata);
Ivan Mahonin b53a5c
   if (windings) {
Ivan Mahonin b53a5c
      stbtt__rasterize(result, windings, winding_lengths, winding_count, scale_x, scale_y, shift_x, shift_y, x_off, y_off, invert, userdata);
Ivan Mahonin b53a5c
      STBTT_free(winding_lengths, userdata);
Ivan Mahonin b53a5c
      STBTT_free(windings, userdata);
Ivan Mahonin b53a5c
   }
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
STBTT_DEF void stbtt_FreeBitmap(unsigned char *bitmap, void *userdata)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   STBTT_free(bitmap, userdata);
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
STBTT_DEF unsigned char *stbtt_GetGlyphBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int glyph, int *width, int *height, int *xoff, int *yoff)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   int ix0,iy0,ix1,iy1;
Ivan Mahonin b53a5c
   stbtt__bitmap gbm;
Ivan Mahonin b53a5c
   stbtt_vertex *vertices;
Ivan Mahonin b53a5c
   int num_verts = stbtt_GetGlyphShape(info, glyph, &vertices);
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   if (scale_x == 0) scale_x = scale_y;
Ivan Mahonin b53a5c
   if (scale_y == 0) {
Ivan Mahonin b53a5c
      if (scale_x == 0) {
Ivan Mahonin b53a5c
         STBTT_free(vertices, info->userdata);
Ivan Mahonin b53a5c
         return NULL;
Ivan Mahonin b53a5c
      }
Ivan Mahonin b53a5c
      scale_y = scale_x;
Ivan Mahonin b53a5c
   }
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale_x, scale_y, shift_x, shift_y, &ix0,&iy0,&ix1,&iy1);
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   // now we get the size
Ivan Mahonin b53a5c
   gbm.w = (ix1 - ix0);
Ivan Mahonin b53a5c
   gbm.h = (iy1 - iy0);
Ivan Mahonin b53a5c
   gbm.pixels = NULL; // in case we error
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   if (width ) *width  = gbm.w;
Ivan Mahonin b53a5c
   if (height) *height = gbm.h;
Ivan Mahonin b53a5c
   if (xoff  ) *xoff   = ix0;
Ivan Mahonin b53a5c
   if (yoff  ) *yoff   = iy0;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   if (gbm.w && gbm.h) {
Ivan Mahonin b53a5c
      gbm.pixels = (unsigned char *) STBTT_malloc(gbm.w * gbm.h, info->userdata);
Ivan Mahonin b53a5c
      if (gbm.pixels) {
Ivan Mahonin b53a5c
         gbm.stride = gbm.w;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
         stbtt_Rasterize(&gbm, 0.35f, vertices, num_verts, scale_x, scale_y, shift_x, shift_y, ix0, iy0, 1, info->userdata);
Ivan Mahonin b53a5c
      }
Ivan Mahonin b53a5c
   }
Ivan Mahonin b53a5c
   STBTT_free(vertices, info->userdata);
Ivan Mahonin b53a5c
   return gbm.pixels;
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
STBTT_DEF unsigned char *stbtt_GetGlyphBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int glyph, int *width, int *height, int *xoff, int *yoff)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   return stbtt_GetGlyphBitmapSubpixel(info, scale_x, scale_y, 0.0f, 0.0f, glyph, width, height, xoff, yoff);
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
STBTT_DEF void stbtt_MakeGlyphBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int glyph)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   int ix0,iy0;
Ivan Mahonin b53a5c
   stbtt_vertex *vertices;
Ivan Mahonin b53a5c
   int num_verts = stbtt_GetGlyphShape(info, glyph, &vertices);
Ivan Mahonin b53a5c
   stbtt__bitmap gbm;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale_x, scale_y, shift_x, shift_y, &ix0,&iy0,0,0);
Ivan Mahonin b53a5c
   gbm.pixels = output;
Ivan Mahonin b53a5c
   gbm.w = out_w;
Ivan Mahonin b53a5c
   gbm.h = out_h;
Ivan Mahonin b53a5c
   gbm.stride = out_stride;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   if (gbm.w && gbm.h)
Ivan Mahonin b53a5c
      stbtt_Rasterize(&gbm, 0.35f, vertices, num_verts, scale_x, scale_y, shift_x, shift_y, ix0,iy0, 1, info->userdata);
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   STBTT_free(vertices, info->userdata);
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
STBTT_DEF void stbtt_MakeGlyphBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int glyph)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   stbtt_MakeGlyphBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, scale_y, 0.0f,0.0f, glyph);
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
STBTT_DEF unsigned char *stbtt_GetCodepointBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint, int *width, int *height, int *xoff, int *yoff)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   return stbtt_GetGlyphBitmapSubpixel(info, scale_x, scale_y,shift_x,shift_y, stbtt_FindGlyphIndex(info,codepoint), width,height,xoff,yoff);
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
STBTT_DEF void stbtt_MakeCodepointBitmapSubpixelPrefilter(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int oversample_x, int oversample_y, float *sub_x, float *sub_y, int codepoint)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   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));
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
STBTT_DEF void stbtt_MakeCodepointBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   stbtt_MakeGlyphBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, scale_y, shift_x, shift_y, stbtt_FindGlyphIndex(info,codepoint));
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
STBTT_DEF unsigned char *stbtt_GetCodepointBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int codepoint, int *width, int *height, int *xoff, int *yoff)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   return stbtt_GetCodepointBitmapSubpixel(info, scale_x, scale_y, 0.0f,0.0f, codepoint, width,height,xoff,yoff);
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
STBTT_DEF void stbtt_MakeCodepointBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int codepoint)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   stbtt_MakeCodepointBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, scale_y, 0.0f,0.0f, codepoint);
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
//////////////////////////////////////////////////////////////////////////////
Ivan Mahonin b53a5c
//
Ivan Mahonin b53a5c
// bitmap baking
Ivan Mahonin b53a5c
//
Ivan Mahonin b53a5c
// This is SUPER-CRAPPY packing to keep source code small
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
static int stbtt_BakeFontBitmap_internal(unsigned char *data, int offset,  // font location (use offset=0 for plain .ttf)
Ivan Mahonin b53a5c
                                float pixel_height,                     // height of font in pixels
Ivan Mahonin b53a5c
                                unsigned char *pixels, int pw, int ph,  // bitmap to be filled in
Ivan Mahonin b53a5c
                                int first_char, int num_chars,          // characters to bake
Ivan Mahonin b53a5c
                                stbtt_bakedchar *chardata)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   float scale;
Ivan Mahonin b53a5c
   int x,y,bottom_y, i;
Ivan Mahonin b53a5c
   stbtt_fontinfo f;
Ivan Mahonin b53a5c
   f.userdata = NULL;
Ivan Mahonin b53a5c
   if (!stbtt_InitFont(&f, data, offset))
Ivan Mahonin b53a5c
      return -1;
Ivan Mahonin b53a5c
   STBTT_memset(pixels, 0, pw*ph); // background of 0 around pixels
Ivan Mahonin b53a5c
   x=y=1;
Ivan Mahonin b53a5c
   bottom_y = 1;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   scale = stbtt_ScaleForPixelHeight(&f, pixel_height);
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   for (i=0; i < num_chars; ++i) {
Ivan Mahonin b53a5c
      int advance, lsb, x0,y0,x1,y1,gw,gh;
Ivan Mahonin b53a5c
      int g = stbtt_FindGlyphIndex(&f, first_char + i);
Ivan Mahonin b53a5c
      stbtt_GetGlyphHMetrics(&f, g, &advance, &lsb);
Ivan Mahonin b53a5c
      stbtt_GetGlyphBitmapBox(&f, g, scale,scale, &x0,&y0,&x1,&y1);
Ivan Mahonin b53a5c
      gw = x1-x0;
Ivan Mahonin b53a5c
      gh = y1-y0;
Ivan Mahonin b53a5c
      if (x + gw + 1 >= pw)
Ivan Mahonin b53a5c
         y = bottom_y, x = 1; // advance to next row
Ivan Mahonin b53a5c
      if (y + gh + 1 >= ph) // check if it fits vertically AFTER potentially moving to next row
Ivan Mahonin b53a5c
         return -i;
Ivan Mahonin b53a5c
      STBTT_assert(x+gw < pw);
Ivan Mahonin b53a5c
      STBTT_assert(y+gh < ph);
Ivan Mahonin b53a5c
      stbtt_MakeGlyphBitmap(&f, pixels+x+y*pw, gw,gh,pw, scale,scale, g);
Ivan Mahonin b53a5c
      chardata[i].x0 = (stbtt_int16) x;
Ivan Mahonin b53a5c
      chardata[i].y0 = (stbtt_int16) y;
Ivan Mahonin b53a5c
      chardata[i].x1 = (stbtt_int16) (x + gw);
Ivan Mahonin b53a5c
      chardata[i].y1 = (stbtt_int16) (y + gh);
Ivan Mahonin b53a5c
      chardata[i].xadvance = scale * advance;
Ivan Mahonin b53a5c
      chardata[i].xoff     = (float) x0;
Ivan Mahonin b53a5c
      chardata[i].yoff     = (float) y0;
Ivan Mahonin b53a5c
      x = x + gw + 1;
Ivan Mahonin b53a5c
      if (y+gh+1 > bottom_y)
Ivan Mahonin b53a5c
         bottom_y = y+gh+1;
Ivan Mahonin b53a5c
   }
Ivan Mahonin b53a5c
   return bottom_y;
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
STBTT_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)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   float d3d_bias = opengl_fillrule ? 0 : -0.5f;
Ivan Mahonin b53a5c
   float ipw = 1.0f / pw, iph = 1.0f / ph;
Ivan Mahonin b53a5c
   const stbtt_bakedchar *b = chardata + char_index;
Ivan Mahonin b53a5c
   int round_x = STBTT_ifloor((*xpos + b->xoff) + 0.5f);
Ivan Mahonin b53a5c
   int round_y = STBTT_ifloor((*ypos + b->yoff) + 0.5f);
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   q->x0 = round_x + d3d_bias;
Ivan Mahonin b53a5c
   q->y0 = round_y + d3d_bias;
Ivan Mahonin b53a5c
   q->x1 = round_x + b->x1 - b->x0 + d3d_bias;
Ivan Mahonin b53a5c
   q->y1 = round_y + b->y1 - b->y0 + d3d_bias;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   q->s0 = b->x0 * ipw;
Ivan Mahonin b53a5c
   q->t0 = b->y0 * iph;
Ivan Mahonin b53a5c
   q->s1 = b->x1 * ipw;
Ivan Mahonin b53a5c
   q->t1 = b->y1 * iph;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   *xpos += b->xadvance;
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
//////////////////////////////////////////////////////////////////////////////
Ivan Mahonin b53a5c
//
Ivan Mahonin b53a5c
// rectangle packing replacement routines if you don't have stb_rect_pack.h
Ivan Mahonin b53a5c
//
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
#ifndef STB_RECT_PACK_VERSION
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
typedef int stbrp_coord;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
////////////////////////////////////////////////////////////////////////////////////
Ivan Mahonin b53a5c
//                                                                                //
Ivan Mahonin b53a5c
//                                                                                //
Ivan Mahonin b53a5c
// COMPILER WARNING ?!?!?                                                         //
Ivan Mahonin b53a5c
//                                                                                //
Ivan Mahonin b53a5c
//                                                                                //
Ivan Mahonin b53a5c
// if you get a compile warning due to these symbols being defined more than      //
Ivan Mahonin b53a5c
// once, move #include "stb_rect_pack.h" before #include "stb_truetype.h"         //
Ivan Mahonin b53a5c
//                                                                                //
Ivan Mahonin b53a5c
////////////////////////////////////////////////////////////////////////////////////
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
typedef struct
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   int width,height;
Ivan Mahonin b53a5c
   int x,y,bottom_y;
Ivan Mahonin b53a5c
} stbrp_context;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
typedef struct
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   unsigned char x;
Ivan Mahonin b53a5c
} stbrp_node;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
struct stbrp_rect
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   stbrp_coord x,y;
Ivan Mahonin b53a5c
   int id,w,h,was_packed;
Ivan Mahonin b53a5c
};
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
static void stbrp_init_target(stbrp_context *con, int pw, int ph, stbrp_node *nodes, int num_nodes)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   con->width  = pw;
Ivan Mahonin b53a5c
   con->height = ph;
Ivan Mahonin b53a5c
   con->x = 0;
Ivan Mahonin b53a5c
   con->y = 0;
Ivan Mahonin b53a5c
   con->bottom_y = 0;
Ivan Mahonin b53a5c
   STBTT__NOTUSED(nodes);
Ivan Mahonin b53a5c
   STBTT__NOTUSED(num_nodes);
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
static void stbrp_pack_rects(stbrp_context *con, stbrp_rect *rects, int num_rects)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   int i;
Ivan Mahonin b53a5c
   for (i=0; i < num_rects; ++i) {
Ivan Mahonin b53a5c
      if (con->x + rects[i].w > con->width) {
Ivan Mahonin b53a5c
         con->x = 0;
Ivan Mahonin b53a5c
         con->y = con->bottom_y;
Ivan Mahonin b53a5c
      }
Ivan Mahonin b53a5c
      if (con->y + rects[i].h > con->height)
Ivan Mahonin b53a5c
         break;
Ivan Mahonin b53a5c
      rects[i].x = con->x;
Ivan Mahonin b53a5c
      rects[i].y = con->y;
Ivan Mahonin b53a5c
      rects[i].was_packed = 1;
Ivan Mahonin b53a5c
      con->x += rects[i].w;
Ivan Mahonin b53a5c
      if (con->y + rects[i].h > con->bottom_y)
Ivan Mahonin b53a5c
         con->bottom_y = con->y + rects[i].h;
Ivan Mahonin b53a5c
   }
Ivan Mahonin b53a5c
   for (   ; i < num_rects; ++i)
Ivan Mahonin b53a5c
      rects[i].was_packed = 0;
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
#endif
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
//////////////////////////////////////////////////////////////////////////////
Ivan Mahonin b53a5c
//
Ivan Mahonin b53a5c
// bitmap baking
Ivan Mahonin b53a5c
//
Ivan Mahonin b53a5c
// This is SUPER-AWESOME (tm Ryan Gordon) packing using stb_rect_pack.h. If
Ivan Mahonin b53a5c
// stb_rect_pack.h isn't available, it uses the BakeFontBitmap strategy.
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
STBTT_DEF int stbtt_PackBegin(stbtt_pack_context *spc, unsigned char *pixels, int pw, int ph, int stride_in_bytes, int padding, void *alloc_context)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   stbrp_context *context = (stbrp_context *) STBTT_malloc(sizeof(*context)            ,alloc_context);
Ivan Mahonin b53a5c
   int            num_nodes = pw - padding;
Ivan Mahonin b53a5c
   stbrp_node    *nodes   = (stbrp_node    *) STBTT_malloc(sizeof(*nodes  ) * num_nodes,alloc_context);
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   if (context == NULL || nodes == NULL) {
Ivan Mahonin b53a5c
      if (context != NULL) STBTT_free(context, alloc_context);
Ivan Mahonin b53a5c
      if (nodes   != NULL) STBTT_free(nodes  , alloc_context);
Ivan Mahonin b53a5c
      return 0;
Ivan Mahonin b53a5c
   }
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   spc->user_allocator_context = alloc_context;
Ivan Mahonin b53a5c
   spc->width = pw;
Ivan Mahonin b53a5c
   spc->height = ph;
Ivan Mahonin b53a5c
   spc->pixels = pixels;
Ivan Mahonin b53a5c
   spc->pack_info = context;
Ivan Mahonin b53a5c
   spc->nodes = nodes;
Ivan Mahonin b53a5c
   spc->padding = padding;
Ivan Mahonin b53a5c
   spc->stride_in_bytes = stride_in_bytes != 0 ? stride_in_bytes : pw;
Ivan Mahonin b53a5c
   spc->h_oversample = 1;
Ivan Mahonin b53a5c
   spc->v_oversample = 1;
Ivan Mahonin b53a5c
   spc->skip_missing = 0;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   stbrp_init_target(context, pw-padding, ph-padding, nodes, num_nodes);
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   if (pixels)
Ivan Mahonin b53a5c
      STBTT_memset(pixels, 0, pw*ph); // background of 0 around pixels
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   return 1;
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
STBTT_DEF void stbtt_PackEnd  (stbtt_pack_context *spc)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   STBTT_free(spc->nodes    , spc->user_allocator_context);
Ivan Mahonin b53a5c
   STBTT_free(spc->pack_info, spc->user_allocator_context);
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
STBTT_DEF void stbtt_PackSetOversampling(stbtt_pack_context *spc, unsigned int h_oversample, unsigned int v_oversample)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   STBTT_assert(h_oversample <= STBTT_MAX_OVERSAMPLE);
Ivan Mahonin b53a5c
   STBTT_assert(v_oversample <= STBTT_MAX_OVERSAMPLE);
Ivan Mahonin b53a5c
   if (h_oversample <= STBTT_MAX_OVERSAMPLE)
Ivan Mahonin b53a5c
      spc->h_oversample = h_oversample;
Ivan Mahonin b53a5c
   if (v_oversample <= STBTT_MAX_OVERSAMPLE)
Ivan Mahonin b53a5c
      spc->v_oversample = v_oversample;
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
STBTT_DEF void stbtt_PackSetSkipMissingCodepoints(stbtt_pack_context *spc, int skip)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   spc->skip_missing = skip;
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
#define STBTT__OVER_MASK  (STBTT_MAX_OVERSAMPLE-1)
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
static void stbtt__h_prefilter(unsigned char *pixels, int w, int h, int stride_in_bytes, unsigned int kernel_width)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   unsigned char buffer[STBTT_MAX_OVERSAMPLE];
Ivan Mahonin b53a5c
   int safe_w = w - kernel_width;
Ivan Mahonin b53a5c
   int j;
Ivan Mahonin b53a5c
   STBTT_memset(buffer, 0, STBTT_MAX_OVERSAMPLE); // suppress bogus warning from VS2013 -analyze
Ivan Mahonin b53a5c
   for (j=0; j < h; ++j) {
Ivan Mahonin b53a5c
      int i;
Ivan Mahonin b53a5c
      unsigned int total;
Ivan Mahonin b53a5c
      STBTT_memset(buffer, 0, kernel_width);
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
      total = 0;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
      // make kernel_width a constant in common cases so compiler can optimize out the divide
Ivan Mahonin b53a5c
      switch (kernel_width) {
Ivan Mahonin b53a5c
         case 2:
Ivan Mahonin b53a5c
            for (i=0; i <= safe_w; ++i) {
Ivan Mahonin b53a5c
               total += pixels[i] - buffer[i & STBTT__OVER_MASK];
Ivan Mahonin b53a5c
               buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i];
Ivan Mahonin b53a5c
               pixels[i] = (unsigned char) (total / 2);
Ivan Mahonin b53a5c
            }
Ivan Mahonin b53a5c
            break;
Ivan Mahonin b53a5c
         case 3:
Ivan Mahonin b53a5c
            for (i=0; i <= safe_w; ++i) {
Ivan Mahonin b53a5c
               total += pixels[i] - buffer[i & STBTT__OVER_MASK];
Ivan Mahonin b53a5c
               buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i];
Ivan Mahonin b53a5c
               pixels[i] = (unsigned char) (total / 3);
Ivan Mahonin b53a5c
            }
Ivan Mahonin b53a5c
            break;
Ivan Mahonin b53a5c
         case 4:
Ivan Mahonin b53a5c
            for (i=0; i <= safe_w; ++i) {
Ivan Mahonin b53a5c
               total += pixels[i] - buffer[i & STBTT__OVER_MASK];
Ivan Mahonin b53a5c
               buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i];
Ivan Mahonin b53a5c
               pixels[i] = (unsigned char) (total / 4);
Ivan Mahonin b53a5c
            }
Ivan Mahonin b53a5c
            break;
Ivan Mahonin b53a5c
         case 5:
Ivan Mahonin b53a5c
            for (i=0; i <= safe_w; ++i) {
Ivan Mahonin b53a5c
               total += pixels[i] - buffer[i & STBTT__OVER_MASK];
Ivan Mahonin b53a5c
               buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i];
Ivan Mahonin b53a5c
               pixels[i] = (unsigned char) (total / 5);
Ivan Mahonin b53a5c
            }
Ivan Mahonin b53a5c
            break;
Ivan Mahonin b53a5c
         default:
Ivan Mahonin b53a5c
            for (i=0; i <= safe_w; ++i) {
Ivan Mahonin b53a5c
               total += pixels[i] - buffer[i & STBTT__OVER_MASK];
Ivan Mahonin b53a5c
               buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i];
Ivan Mahonin b53a5c
               pixels[i] = (unsigned char) (total / kernel_width);
Ivan Mahonin b53a5c
            }
Ivan Mahonin b53a5c
            break;
Ivan Mahonin b53a5c
      }
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
      for (; i < w; ++i) {
Ivan Mahonin b53a5c
         STBTT_assert(pixels[i] == 0);
Ivan Mahonin b53a5c
         total -= buffer[i & STBTT__OVER_MASK];
Ivan Mahonin b53a5c
         pixels[i] = (unsigned char) (total / kernel_width);
Ivan Mahonin b53a5c
      }
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
      pixels += stride_in_bytes;
Ivan Mahonin b53a5c
   }
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
static void stbtt__v_prefilter(unsigned char *pixels, int w, int h, int stride_in_bytes, unsigned int kernel_width)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   unsigned char buffer[STBTT_MAX_OVERSAMPLE];
Ivan Mahonin b53a5c
   int safe_h = h - kernel_width;
Ivan Mahonin b53a5c
   int j;
Ivan Mahonin b53a5c
   STBTT_memset(buffer, 0, STBTT_MAX_OVERSAMPLE); // suppress bogus warning from VS2013 -analyze
Ivan Mahonin b53a5c
   for (j=0; j < w; ++j) {
Ivan Mahonin b53a5c
      int i;
Ivan Mahonin b53a5c
      unsigned int total;
Ivan Mahonin b53a5c
      STBTT_memset(buffer, 0, kernel_width);
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
      total = 0;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
      // make kernel_width a constant in common cases so compiler can optimize out the divide
Ivan Mahonin b53a5c
      switch (kernel_width) {
Ivan Mahonin b53a5c
         case 2:
Ivan Mahonin b53a5c
            for (i=0; i <= safe_h; ++i) {
Ivan Mahonin b53a5c
               total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK];
Ivan Mahonin b53a5c
               buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes];
Ivan Mahonin b53a5c
               pixels[i*stride_in_bytes] = (unsigned char) (total / 2);
Ivan Mahonin b53a5c
            }
Ivan Mahonin b53a5c
            break;
Ivan Mahonin b53a5c
         case 3:
Ivan Mahonin b53a5c
            for (i=0; i <= safe_h; ++i) {
Ivan Mahonin b53a5c
               total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK];
Ivan Mahonin b53a5c
               buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes];
Ivan Mahonin b53a5c
               pixels[i*stride_in_bytes] = (unsigned char) (total / 3);
Ivan Mahonin b53a5c
            }
Ivan Mahonin b53a5c
            break;
Ivan Mahonin b53a5c
         case 4:
Ivan Mahonin b53a5c
            for (i=0; i <= safe_h; ++i) {
Ivan Mahonin b53a5c
               total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK];
Ivan Mahonin b53a5c
               buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes];
Ivan Mahonin b53a5c
               pixels[i*stride_in_bytes] = (unsigned char) (total / 4);
Ivan Mahonin b53a5c
            }
Ivan Mahonin b53a5c
            break;
Ivan Mahonin b53a5c
         case 5:
Ivan Mahonin b53a5c
            for (i=0; i <= safe_h; ++i) {
Ivan Mahonin b53a5c
               total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK];
Ivan Mahonin b53a5c
               buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes];
Ivan Mahonin b53a5c
               pixels[i*stride_in_bytes] = (unsigned char) (total / 5);
Ivan Mahonin b53a5c
            }
Ivan Mahonin b53a5c
            break;
Ivan Mahonin b53a5c
         default:
Ivan Mahonin b53a5c
            for (i=0; i <= safe_h; ++i) {
Ivan Mahonin b53a5c
               total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK];
Ivan Mahonin b53a5c
               buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes];
Ivan Mahonin b53a5c
               pixels[i*stride_in_bytes] = (unsigned char) (total / kernel_width);
Ivan Mahonin b53a5c
            }
Ivan Mahonin b53a5c
            break;
Ivan Mahonin b53a5c
      }
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
      for (; i < h; ++i) {
Ivan Mahonin b53a5c
         STBTT_assert(pixels[i*stride_in_bytes] == 0);
Ivan Mahonin b53a5c
         total -= buffer[i & STBTT__OVER_MASK];
Ivan Mahonin b53a5c
         pixels[i*stride_in_bytes] = (unsigned char) (total / kernel_width);
Ivan Mahonin b53a5c
      }
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
      pixels += 1;
Ivan Mahonin b53a5c
   }
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
static float stbtt__oversample_shift(int oversample)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   if (!oversample)
Ivan Mahonin b53a5c
      return 0.0f;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   // The prefilter is a box filter of width "oversample",
Ivan Mahonin b53a5c
   // which shifts phase by (oversample - 1)/2 pixels in
Ivan Mahonin b53a5c
   // oversampled space. We want to shift in the opposite
Ivan Mahonin b53a5c
   // direction to counter this.
Ivan Mahonin b53a5c
   return (float)-(oversample - 1) / (2.0f * (float)oversample);
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
// rects array must be big enough to accommodate all characters in the given ranges
Ivan Mahonin b53a5c
STBTT_DEF int stbtt_PackFontRangesGatherRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   int i,j,k;
Ivan Mahonin b53a5c
   int missing_glyph_added = 0;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   k=0;
Ivan Mahonin b53a5c
   for (i=0; i < num_ranges; ++i) {
Ivan Mahonin b53a5c
      float fh = ranges[i].font_size;
Ivan Mahonin b53a5c
      float scale = fh > 0 ? stbtt_ScaleForPixelHeight(info, fh) : stbtt_ScaleForMappingEmToPixels(info, -fh);
Ivan Mahonin b53a5c
      ranges[i].h_oversample = (unsigned char) spc->h_oversample;
Ivan Mahonin b53a5c
      ranges[i].v_oversample = (unsigned char) spc->v_oversample;
Ivan Mahonin b53a5c
      for (j=0; j < ranges[i].num_chars; ++j) {
Ivan Mahonin b53a5c
         int x0,y0,x1,y1;
Ivan Mahonin b53a5c
         int codepoint = ranges[i].array_of_unicode_codepoints == NULL ? ranges[i].first_unicode_codepoint_in_range + j : ranges[i].array_of_unicode_codepoints[j];
Ivan Mahonin b53a5c
         int glyph = stbtt_FindGlyphIndex(info, codepoint);
Ivan Mahonin b53a5c
         if (glyph == 0 && (spc->skip_missing || missing_glyph_added)) {
Ivan Mahonin b53a5c
            rects[k].w = rects[k].h = 0;
Ivan Mahonin b53a5c
         } else {
Ivan Mahonin b53a5c
            stbtt_GetGlyphBitmapBoxSubpixel(info,glyph,
Ivan Mahonin b53a5c
                                            scale * spc->h_oversample,
Ivan Mahonin b53a5c
                                            scale * spc->v_oversample,
Ivan Mahonin b53a5c
                                            0,0,
Ivan Mahonin b53a5c
                                            &x0,&y0,&x1,&y1);
Ivan Mahonin b53a5c
            rects[k].w = (stbrp_coord) (x1-x0 + spc->padding + spc->h_oversample-1);
Ivan Mahonin b53a5c
            rects[k].h = (stbrp_coord) (y1-y0 + spc->padding + spc->v_oversample-1);
Ivan Mahonin b53a5c
            if (glyph == 0)
Ivan Mahonin b53a5c
               missing_glyph_added = 1;
Ivan Mahonin b53a5c
         }
Ivan Mahonin b53a5c
         ++k;
Ivan Mahonin b53a5c
      }
Ivan Mahonin b53a5c
   }
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   return k;
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
STBTT_DEF void stbtt_MakeGlyphBitmapSubpixelPrefilter(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int prefilter_x, int prefilter_y, float *sub_x, float *sub_y, int glyph)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   stbtt_MakeGlyphBitmapSubpixel(info,
Ivan Mahonin b53a5c
                                 output,
Ivan Mahonin b53a5c
                                 out_w - (prefilter_x - 1),
Ivan Mahonin b53a5c
                                 out_h - (prefilter_y - 1),
Ivan Mahonin b53a5c
                                 out_stride,
Ivan Mahonin b53a5c
                                 scale_x,
Ivan Mahonin b53a5c
                                 scale_y,
Ivan Mahonin b53a5c
                                 shift_x,
Ivan Mahonin b53a5c
                                 shift_y,
Ivan Mahonin b53a5c
                                 glyph);
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   if (prefilter_x > 1)
Ivan Mahonin b53a5c
      stbtt__h_prefilter(output, out_w, out_h, out_stride, prefilter_x);
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   if (prefilter_y > 1)
Ivan Mahonin b53a5c
      stbtt__v_prefilter(output, out_w, out_h, out_stride, prefilter_y);
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   *sub_x = stbtt__oversample_shift(prefilter_x);
Ivan Mahonin b53a5c
   *sub_y = stbtt__oversample_shift(prefilter_y);
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
// rects array must be big enough to accommodate all characters in the given ranges
Ivan Mahonin b53a5c
STBTT_DEF int stbtt_PackFontRangesRenderIntoRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   int i,j,k, missing_glyph = -1, return_value = 1;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   // save current values
Ivan Mahonin b53a5c
   int old_h_over = spc->h_oversample;
Ivan Mahonin b53a5c
   int old_v_over = spc->v_oversample;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   k = 0;
Ivan Mahonin b53a5c
   for (i=0; i < num_ranges; ++i) {
Ivan Mahonin b53a5c
      float fh = ranges[i].font_size;
Ivan Mahonin b53a5c
      float scale = fh > 0 ? stbtt_ScaleForPixelHeight(info, fh) : stbtt_ScaleForMappingEmToPixels(info, -fh);
Ivan Mahonin b53a5c
      float recip_h,recip_v,sub_x,sub_y;
Ivan Mahonin b53a5c
      spc->h_oversample = ranges[i].h_oversample;
Ivan Mahonin b53a5c
      spc->v_oversample = ranges[i].v_oversample;
Ivan Mahonin b53a5c
      recip_h = 1.0f / spc->h_oversample;
Ivan Mahonin b53a5c
      recip_v = 1.0f / spc->v_oversample;
Ivan Mahonin b53a5c
      sub_x = stbtt__oversample_shift(spc->h_oversample);
Ivan Mahonin b53a5c
      sub_y = stbtt__oversample_shift(spc->v_oversample);
Ivan Mahonin b53a5c
      for (j=0; j < ranges[i].num_chars; ++j) {
Ivan Mahonin b53a5c
         stbrp_rect *r = &rects[k];
Ivan Mahonin b53a5c
         if (r->was_packed && r->w != 0 && r->h != 0) {
Ivan Mahonin b53a5c
            stbtt_packedchar *bc = &ranges[i].chardata_for_range[j];
Ivan Mahonin b53a5c
            int advance, lsb, x0,y0,x1,y1;
Ivan Mahonin b53a5c
            int codepoint = ranges[i].array_of_unicode_codepoints == NULL ? ranges[i].first_unicode_codepoint_in_range + j : ranges[i].array_of_unicode_codepoints[j];
Ivan Mahonin b53a5c
            int glyph = stbtt_FindGlyphIndex(info, codepoint);
Ivan Mahonin b53a5c
            stbrp_coord pad = (stbrp_coord) spc->padding;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
            // pad on left and top
Ivan Mahonin b53a5c
            r->x += pad;
Ivan Mahonin b53a5c
            r->y += pad;
Ivan Mahonin b53a5c
            r->w -= pad;
Ivan Mahonin b53a5c
            r->h -= pad;
Ivan Mahonin b53a5c
            stbtt_GetGlyphHMetrics(info, glyph, &advance, &lsb);
Ivan Mahonin b53a5c
            stbtt_GetGlyphBitmapBox(info, glyph,
Ivan Mahonin b53a5c
                                    scale * spc->h_oversample,
Ivan Mahonin b53a5c
                                    scale * spc->v_oversample,
Ivan Mahonin b53a5c
                                    &x0,&y0,&x1,&y1);
Ivan Mahonin b53a5c
            stbtt_MakeGlyphBitmapSubpixel(info,
Ivan Mahonin b53a5c
                                          spc->pixels + r->x + r->y*spc->stride_in_bytes,
Ivan Mahonin b53a5c
                                          r->w - spc->h_oversample+1,
Ivan Mahonin b53a5c
                                          r->h - spc->v_oversample+1,
Ivan Mahonin b53a5c
                                          spc->stride_in_bytes,
Ivan Mahonin b53a5c
                                          scale * spc->h_oversample,
Ivan Mahonin b53a5c
                                          scale * spc->v_oversample,
Ivan Mahonin b53a5c
                                          0,0,
Ivan Mahonin b53a5c
                                          glyph);
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
            if (spc->h_oversample > 1)
Ivan Mahonin b53a5c
               stbtt__h_prefilter(spc->pixels + r->x + r->y*spc->stride_in_bytes,
Ivan Mahonin b53a5c
                                  r->w, r->h, spc->stride_in_bytes,
Ivan Mahonin b53a5c
                                  spc->h_oversample);
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
            if (spc->v_oversample > 1)
Ivan Mahonin b53a5c
               stbtt__v_prefilter(spc->pixels + r->x + r->y*spc->stride_in_bytes,
Ivan Mahonin b53a5c
                                  r->w, r->h, spc->stride_in_bytes,
Ivan Mahonin b53a5c
                                  spc->v_oversample);
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
            bc->x0       = (stbtt_int16)  r->x;
Ivan Mahonin b53a5c
            bc->y0       = (stbtt_int16)  r->y;
Ivan Mahonin b53a5c
            bc->x1       = (stbtt_int16) (r->x + r->w);
Ivan Mahonin b53a5c
            bc->y1       = (stbtt_int16) (r->y + r->h);
Ivan Mahonin b53a5c
            bc->xadvance =                scale * advance;
Ivan Mahonin b53a5c
            bc->xoff     =       (float)  x0 * recip_h + sub_x;
Ivan Mahonin b53a5c
            bc->yoff     =       (float)  y0 * recip_v + sub_y;
Ivan Mahonin b53a5c
            bc->xoff2    =                (x0 + r->w) * recip_h + sub_x;
Ivan Mahonin b53a5c
            bc->yoff2    =                (y0 + r->h) * recip_v + sub_y;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
            if (glyph == 0)
Ivan Mahonin b53a5c
               missing_glyph = j;
Ivan Mahonin b53a5c
         } else if (spc->skip_missing) {
Ivan Mahonin b53a5c
            return_value = 0;
Ivan Mahonin b53a5c
         } else if (r->was_packed && r->w == 0 && r->h == 0 && missing_glyph >= 0) {
Ivan Mahonin b53a5c
            ranges[i].chardata_for_range[j] = ranges[i].chardata_for_range[missing_glyph];
Ivan Mahonin b53a5c
         } else {
Ivan Mahonin b53a5c
            return_value = 0; // if any fail, report failure
Ivan Mahonin b53a5c
         }
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
         ++k;
Ivan Mahonin b53a5c
      }
Ivan Mahonin b53a5c
   }
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   // restore original values
Ivan Mahonin b53a5c
   spc->h_oversample = old_h_over;
Ivan Mahonin b53a5c
   spc->v_oversample = old_v_over;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   return return_value;
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
STBTT_DEF void stbtt_PackFontRangesPackRects(stbtt_pack_context *spc, stbrp_rect *rects, int num_rects)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   stbrp_pack_rects((stbrp_context *) spc->pack_info, rects, num_rects);
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
STBTT_DEF int stbtt_PackFontRanges(stbtt_pack_context *spc, const unsigned char *fontdata, int font_index, stbtt_pack_range *ranges, int num_ranges)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   stbtt_fontinfo info;
Ivan Mahonin b53a5c
   int i,j,n, return_value = 1;
Ivan Mahonin b53a5c
   //stbrp_context *context = (stbrp_context *) spc->pack_info;
Ivan Mahonin b53a5c
   stbrp_rect    *rects;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   // flag all characters as NOT packed
Ivan Mahonin b53a5c
   for (i=0; i < num_ranges; ++i)
Ivan Mahonin b53a5c
      for (j=0; j < ranges[i].num_chars; ++j)
Ivan Mahonin b53a5c
         ranges[i].chardata_for_range[j].x0 =
Ivan Mahonin b53a5c
         ranges[i].chardata_for_range[j].y0 =
Ivan Mahonin b53a5c
         ranges[i].chardata_for_range[j].x1 =
Ivan Mahonin b53a5c
         ranges[i].chardata_for_range[j].y1 = 0;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   n = 0;
Ivan Mahonin b53a5c
   for (i=0; i < num_ranges; ++i)
Ivan Mahonin b53a5c
      n += ranges[i].num_chars;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   rects = (stbrp_rect *) STBTT_malloc(sizeof(*rects) * n, spc->user_allocator_context);
Ivan Mahonin b53a5c
   if (rects == NULL)
Ivan Mahonin b53a5c
      return 0;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   info.userdata = spc->user_allocator_context;
Ivan Mahonin b53a5c
   stbtt_InitFont(&info, fontdata, stbtt_GetFontOffsetForIndex(fontdata,font_index));
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   n = stbtt_PackFontRangesGatherRects(spc, &info, ranges, num_ranges, rects);
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   stbtt_PackFontRangesPackRects(spc, rects, n);
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   return_value = stbtt_PackFontRangesRenderIntoRects(spc, &info, ranges, num_ranges, rects);
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   STBTT_free(rects, spc->user_allocator_context);
Ivan Mahonin b53a5c
   return return_value;
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
STBTT_DEF int stbtt_PackFontRange(stbtt_pack_context *spc, const unsigned char *fontdata, int font_index, float font_size,
Ivan Mahonin b53a5c
            int first_unicode_codepoint_in_range, int num_chars_in_range, stbtt_packedchar *chardata_for_range)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   stbtt_pack_range range;
Ivan Mahonin b53a5c
   range.first_unicode_codepoint_in_range = first_unicode_codepoint_in_range;
Ivan Mahonin b53a5c
   range.array_of_unicode_codepoints = NULL;
Ivan Mahonin b53a5c
   range.num_chars                   = num_chars_in_range;
Ivan Mahonin b53a5c
   range.chardata_for_range          = chardata_for_range;
Ivan Mahonin b53a5c
   range.font_size                   = font_size;
Ivan Mahonin b53a5c
   return stbtt_PackFontRanges(spc, fontdata, font_index, &range, 1);
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
STBTT_DEF void stbtt_GetScaledFontVMetrics(const unsigned char *fontdata, int index, float size, float *ascent, float *descent, float *lineGap)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   int i_ascent, i_descent, i_lineGap;
Ivan Mahonin b53a5c
   float scale;
Ivan Mahonin b53a5c
   stbtt_fontinfo info;
Ivan Mahonin b53a5c
   stbtt_InitFont(&info, fontdata, stbtt_GetFontOffsetForIndex(fontdata, index));
Ivan Mahonin b53a5c
   scale = size > 0 ? stbtt_ScaleForPixelHeight(&info, size) : stbtt_ScaleForMappingEmToPixels(&info, -size);
Ivan Mahonin b53a5c
   stbtt_GetFontVMetrics(&info, &i_ascent, &i_descent, &i_lineGap);
Ivan Mahonin b53a5c
   *ascent  = (float) i_ascent  * scale;
Ivan Mahonin b53a5c
   *descent = (float) i_descent * scale;
Ivan Mahonin b53a5c
   *lineGap = (float) i_lineGap * scale;
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
STBTT_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)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   float ipw = 1.0f / pw, iph = 1.0f / ph;
Ivan Mahonin b53a5c
   const stbtt_packedchar *b = chardata + char_index;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   if (align_to_integer) {
Ivan Mahonin b53a5c
      float x = (float) STBTT_ifloor((*xpos + b->xoff) + 0.5f);
Ivan Mahonin b53a5c
      float y = (float) STBTT_ifloor((*ypos + b->yoff) + 0.5f);
Ivan Mahonin b53a5c
      q->x0 = x;
Ivan Mahonin b53a5c
      q->y0 = y;
Ivan Mahonin b53a5c
      q->x1 = x + b->xoff2 - b->xoff;
Ivan Mahonin b53a5c
      q->y1 = y + b->yoff2 - b->yoff;
Ivan Mahonin b53a5c
   } else {
Ivan Mahonin b53a5c
      q->x0 = *xpos + b->xoff;
Ivan Mahonin b53a5c
      q->y0 = *ypos + b->yoff;
Ivan Mahonin b53a5c
      q->x1 = *xpos + b->xoff2;
Ivan Mahonin b53a5c
      q->y1 = *ypos + b->yoff2;
Ivan Mahonin b53a5c
   }
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   q->s0 = b->x0 * ipw;
Ivan Mahonin b53a5c
   q->t0 = b->y0 * iph;
Ivan Mahonin b53a5c
   q->s1 = b->x1 * ipw;
Ivan Mahonin b53a5c
   q->t1 = b->y1 * iph;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   *xpos += b->xadvance;
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
//////////////////////////////////////////////////////////////////////////////
Ivan Mahonin b53a5c
//
Ivan Mahonin b53a5c
// sdf computation
Ivan Mahonin b53a5c
//
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
#define STBTT_min(a,b)  ((a) < (b) ? (a) : (b))
Ivan Mahonin b53a5c
#define STBTT_max(a,b)  ((a) < (b) ? (b) : (a))
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
static int stbtt__ray_intersect_bezier(float orig[2], float ray[2], float q0[2], float q1[2], float q2[2], float hits[2][2])
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   float q0perp = q0[1]*ray[0] - q0[0]*ray[1];
Ivan Mahonin b53a5c
   float q1perp = q1[1]*ray[0] - q1[0]*ray[1];
Ivan Mahonin b53a5c
   float q2perp = q2[1]*ray[0] - q2[0]*ray[1];
Ivan Mahonin b53a5c
   float roperp = orig[1]*ray[0] - orig[0]*ray[1];
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   float a = q0perp - 2*q1perp + q2perp;
Ivan Mahonin b53a5c
   float b = q1perp - q0perp;
Ivan Mahonin b53a5c
   float c = q0perp - roperp;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   float s0 = 0., s1 = 0.;
Ivan Mahonin b53a5c
   int num_s = 0;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   if (a != 0.0) {
Ivan Mahonin b53a5c
      float discr = b*b - a*c;
Ivan Mahonin b53a5c
      if (discr > 0.0) {
Ivan Mahonin b53a5c
         float rcpna = -1 / a;
Ivan Mahonin b53a5c
         float d = (float) STBTT_sqrt(discr);
Ivan Mahonin b53a5c
         s0 = (b+d) * rcpna;
Ivan Mahonin b53a5c
         s1 = (b-d) * rcpna;
Ivan Mahonin b53a5c
         if (s0 >= 0.0 && s0 <= 1.0)
Ivan Mahonin b53a5c
            num_s = 1;
Ivan Mahonin b53a5c
         if (d > 0.0 && s1 >= 0.0 && s1 <= 1.0) {
Ivan Mahonin b53a5c
            if (num_s == 0) s0 = s1;
Ivan Mahonin b53a5c
            ++num_s;
Ivan Mahonin b53a5c
         }
Ivan Mahonin b53a5c
      }
Ivan Mahonin b53a5c
   } else {
Ivan Mahonin b53a5c
      // 2*b*s + c = 0
Ivan Mahonin b53a5c
      // s = -c / (2*b)
Ivan Mahonin b53a5c
      s0 = c / (-2 * b);
Ivan Mahonin b53a5c
      if (s0 >= 0.0 && s0 <= 1.0)
Ivan Mahonin b53a5c
         num_s = 1;
Ivan Mahonin b53a5c
   }
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   if (num_s == 0)
Ivan Mahonin b53a5c
      return 0;
Ivan Mahonin b53a5c
   else {
Ivan Mahonin b53a5c
      float rcp_len2 = 1 / (ray[0]*ray[0] + ray[1]*ray[1]);
Ivan Mahonin b53a5c
      float rayn_x = ray[0] * rcp_len2, rayn_y = ray[1] * rcp_len2;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
      float q0d =   q0[0]*rayn_x +   q0[1]*rayn_y;
Ivan Mahonin b53a5c
      float q1d =   q1[0]*rayn_x +   q1[1]*rayn_y;
Ivan Mahonin b53a5c
      float q2d =   q2[0]*rayn_x +   q2[1]*rayn_y;
Ivan Mahonin b53a5c
      float rod = orig[0]*rayn_x + orig[1]*rayn_y;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
      float q10d = q1d - q0d;
Ivan Mahonin b53a5c
      float q20d = q2d - q0d;
Ivan Mahonin b53a5c
      float q0rd = q0d - rod;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
      hits[0][0] = q0rd + s0*(2.0f - 2.0f*s0)*q10d + s0*s0*q20d;
Ivan Mahonin b53a5c
      hits[0][1] = a*s0+b;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
      if (num_s > 1) {
Ivan Mahonin b53a5c
         hits[1][0] = q0rd + s1*(2.0f - 2.0f*s1)*q10d + s1*s1*q20d;
Ivan Mahonin b53a5c
         hits[1][1] = a*s1+b;
Ivan Mahonin b53a5c
         return 2;
Ivan Mahonin b53a5c
      } else {
Ivan Mahonin b53a5c
         return 1;
Ivan Mahonin b53a5c
      }
Ivan Mahonin b53a5c
   }
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
static int equal(float *a, float *b)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   return (a[0] == b[0] && a[1] == b[1]);
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
static int stbtt__compute_crossings_x(float x, float y, int nverts, stbtt_vertex *verts)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   int i;
Ivan Mahonin b53a5c
   float orig[2], ray[2] = { 1, 0 };
Ivan Mahonin b53a5c
   float y_frac;
Ivan Mahonin b53a5c
   int winding = 0;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   // make sure y never passes through a vertex of the shape
Ivan Mahonin b53a5c
   y_frac = (float) STBTT_fmod(y, 1.0f);
Ivan Mahonin b53a5c
   if (y_frac < 0.01f)
Ivan Mahonin b53a5c
      y += 0.01f;
Ivan Mahonin b53a5c
   else if (y_frac > 0.99f)
Ivan Mahonin b53a5c
      y -= 0.01f;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   orig[0] = x;
Ivan Mahonin b53a5c
   orig[1] = y;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   // test a ray from (-infinity,y) to (x,y)
Ivan Mahonin b53a5c
   for (i=0; i < nverts; ++i) {
Ivan Mahonin b53a5c
      if (verts[i].type == STBTT_vline) {
Ivan Mahonin b53a5c
         int x0 = (int) verts[i-1].x, y0 = (int) verts[i-1].y;
Ivan Mahonin b53a5c
         int x1 = (int) verts[i  ].x, y1 = (int) verts[i  ].y;
Ivan Mahonin b53a5c
         if (y > STBTT_min(y0,y1) && y < STBTT_max(y0,y1) && x > STBTT_min(x0,x1)) {
Ivan Mahonin b53a5c
            float x_inter = (y - y0) / (y1 - y0) * (x1-x0) + x0;
Ivan Mahonin b53a5c
            if (x_inter < x)
Ivan Mahonin b53a5c
               winding += (y0 < y1) ? 1 : -1;
Ivan Mahonin b53a5c
         }
Ivan Mahonin b53a5c
      }
Ivan Mahonin b53a5c
      if (verts[i].type == STBTT_vcurve) {
Ivan Mahonin b53a5c
         int x0 = (int) verts[i-1].x , y0 = (int) verts[i-1].y ;
Ivan Mahonin b53a5c
         int x1 = (int) verts[i  ].cx, y1 = (int) verts[i  ].cy;
Ivan Mahonin b53a5c
         int x2 = (int) verts[i  ].x , y2 = (int) verts[i  ].y ;
Ivan Mahonin b53a5c
         int ax = STBTT_min(x0,STBTT_min(x1,x2)), ay = STBTT_min(y0,STBTT_min(y1,y2));
Ivan Mahonin b53a5c
         int by = STBTT_max(y0,STBTT_max(y1,y2));
Ivan Mahonin b53a5c
         if (y > ay && y < by && x > ax) {
Ivan Mahonin b53a5c
            float q0[2],q1[2],q2[2];
Ivan Mahonin b53a5c
            float hits[2][2];
Ivan Mahonin b53a5c
            q0[0] = (float)x0;
Ivan Mahonin b53a5c
            q0[1] = (float)y0;
Ivan Mahonin b53a5c
            q1[0] = (float)x1;
Ivan Mahonin b53a5c
            q1[1] = (float)y1;
Ivan Mahonin b53a5c
            q2[0] = (float)x2;
Ivan Mahonin b53a5c
            q2[1] = (float)y2;
Ivan Mahonin b53a5c
            if (equal(q0,q1) || equal(q1,q2)) {
Ivan Mahonin b53a5c
               x0 = (int)verts[i-1].x;
Ivan Mahonin b53a5c
               y0 = (int)verts[i-1].y;
Ivan Mahonin b53a5c
               x1 = (int)verts[i  ].x;
Ivan Mahonin b53a5c
               y1 = (int)verts[i  ].y;
Ivan Mahonin b53a5c
               if (y > STBTT_min(y0,y1) && y < STBTT_max(y0,y1) && x > STBTT_min(x0,x1)) {
Ivan Mahonin b53a5c
                  float x_inter = (y - y0) / (y1 - y0) * (x1-x0) + x0;
Ivan Mahonin b53a5c
                  if (x_inter < x)
Ivan Mahonin b53a5c
                     winding += (y0 < y1) ? 1 : -1;
Ivan Mahonin b53a5c
               }
Ivan Mahonin b53a5c
            } else {
Ivan Mahonin b53a5c
               int num_hits = stbtt__ray_intersect_bezier(orig, ray, q0, q1, q2, hits);
Ivan Mahonin b53a5c
               if (num_hits >= 1)
Ivan Mahonin b53a5c
                  if (hits[0][0] < 0)
Ivan Mahonin b53a5c
                     winding += (hits[0][1] < 0 ? -1 : 1);
Ivan Mahonin b53a5c
               if (num_hits >= 2)
Ivan Mahonin b53a5c
                  if (hits[1][0] < 0)
Ivan Mahonin b53a5c
                     winding += (hits[1][1] < 0 ? -1 : 1);
Ivan Mahonin b53a5c
            }
Ivan Mahonin b53a5c
         }
Ivan Mahonin b53a5c
      }
Ivan Mahonin b53a5c
   }
Ivan Mahonin b53a5c
   return winding;
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
static float stbtt__cuberoot( float x )
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   if (x<0)
Ivan Mahonin b53a5c
      return -(float) STBTT_pow(-x,1.0f/3.0f);
Ivan Mahonin b53a5c
   else
Ivan Mahonin b53a5c
      return  (float) STBTT_pow( x,1.0f/3.0f);
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
// x^3 + a*x^2 + b*x + c = 0
Ivan Mahonin b53a5c
static int stbtt__solve_cubic(float a, float b, float c, float* r)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   float s = -a / 3;
Ivan Mahonin b53a5c
   float p = b - a*a / 3;
Ivan Mahonin b53a5c
   float q = a * (2*a*a - 9*b) / 27 + c;
Ivan Mahonin b53a5c
   float p3 = p*p*p;
Ivan Mahonin b53a5c
   float d = q*q + 4*p3 / 27;
Ivan Mahonin b53a5c
   if (d >= 0) {
Ivan Mahonin b53a5c
      float z = (float) STBTT_sqrt(d);
Ivan Mahonin b53a5c
      float u = (-q + z) / 2;
Ivan Mahonin b53a5c
      float v = (-q - z) / 2;
Ivan Mahonin b53a5c
      u = stbtt__cuberoot(u);
Ivan Mahonin b53a5c
      v = stbtt__cuberoot(v);
Ivan Mahonin b53a5c
      r[0] = s + u + v;
Ivan Mahonin b53a5c
      return 1;
Ivan Mahonin b53a5c
   } else {
Ivan Mahonin b53a5c
      float u = (float) STBTT_sqrt(-p/3);
Ivan Mahonin b53a5c
      float v = (float) STBTT_acos(-STBTT_sqrt(-27/p3) * q / 2) / 3; // p3 must be negative, since d is negative
Ivan Mahonin b53a5c
      float m = (float) STBTT_cos(v);
Ivan Mahonin b53a5c
      float n = (float) STBTT_cos(v-3.141592/2)*1.732050808f;
Ivan Mahonin b53a5c
      r[0] = s + u * 2 * m;
Ivan Mahonin b53a5c
      r[1] = s - u * (m + n);
Ivan Mahonin b53a5c
      r[2] = s - u * (m - n);
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
      //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?
Ivan Mahonin b53a5c
      //STBTT_assert( STBTT_fabs(((r[1]+a)*r[1]+b)*r[1]+c) < 0.05f);
Ivan Mahonin b53a5c
      //STBTT_assert( STBTT_fabs(((r[2]+a)*r[2]+b)*r[2]+c) < 0.05f);
Ivan Mahonin b53a5c
      return 3;
Ivan Mahonin b53a5c
   }
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
STBTT_DEF unsigned char * stbtt_GetGlyphSDF(const stbtt_fontinfo *info, float scale, int glyph, int padding, unsigned char onedge_value, float pixel_dist_scale, int *width, int *height, int *xoff, int *yoff)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   float scale_x = scale, scale_y = scale;
Ivan Mahonin b53a5c
   int ix0,iy0,ix1,iy1;
Ivan Mahonin b53a5c
   int w,h;
Ivan Mahonin b53a5c
   unsigned char *data;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   if (scale == 0) return NULL;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale, scale, 0.0f,0.0f, &ix0,&iy0,&ix1,&iy1);
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   // if empty, return NULL
Ivan Mahonin b53a5c
   if (ix0 == ix1 || iy0 == iy1)
Ivan Mahonin b53a5c
      return NULL;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   ix0 -= padding;
Ivan Mahonin b53a5c
   iy0 -= padding;
Ivan Mahonin b53a5c
   ix1 += padding;
Ivan Mahonin b53a5c
   iy1 += padding;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   w = (ix1 - ix0);
Ivan Mahonin b53a5c
   h = (iy1 - iy0);
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   if (width ) *width  = w;
Ivan Mahonin b53a5c
   if (height) *height = h;
Ivan Mahonin b53a5c
   if (xoff  ) *xoff   = ix0;
Ivan Mahonin b53a5c
   if (yoff  ) *yoff   = iy0;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   // invert for y-downwards bitmaps
Ivan Mahonin b53a5c
   scale_y = -scale_y;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   {
Ivan Mahonin b53a5c
      int x,y,i,j;
Ivan Mahonin b53a5c
      float *precompute;
Ivan Mahonin b53a5c
      stbtt_vertex *verts;
Ivan Mahonin b53a5c
      int num_verts = stbtt_GetGlyphShape(info, glyph, &verts);
Ivan Mahonin b53a5c
      data = (unsigned char *) STBTT_malloc(w * h, info->userdata);
Ivan Mahonin b53a5c
      precompute = (float *) STBTT_malloc(num_verts * sizeof(float), info->userdata);
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
      for (i=0,j=num_verts-1; i < num_verts; j=i++) {
Ivan Mahonin b53a5c
         if (verts[i].type == STBTT_vline) {
Ivan Mahonin b53a5c
            float x0 = verts[i].x*scale_x, y0 = verts[i].y*scale_y;
Ivan Mahonin b53a5c
            float x1 = verts[j].x*scale_x, y1 = verts[j].y*scale_y;
Ivan Mahonin b53a5c
            float dist = (float) STBTT_sqrt((x1-x0)*(x1-x0) + (y1-y0)*(y1-y0));
Ivan Mahonin b53a5c
            precompute[i] = (dist == 0) ? 0.0f : 1.0f / dist;
Ivan Mahonin b53a5c
         } else if (verts[i].type == STBTT_vcurve) {
Ivan Mahonin b53a5c
            float x2 = verts[j].x *scale_x, y2 = verts[j].y *scale_y;
Ivan Mahonin b53a5c
            float x1 = verts[i].cx*scale_x, y1 = verts[i].cy*scale_y;
Ivan Mahonin b53a5c
            float x0 = verts[i].x *scale_x, y0 = verts[i].y *scale_y;
Ivan Mahonin b53a5c
            float bx = x0 - 2*x1 + x2, by = y0 - 2*y1 + y2;
Ivan Mahonin b53a5c
            float len2 = bx*bx + by*by;
Ivan Mahonin b53a5c
            if (len2 != 0.0f)
Ivan Mahonin b53a5c
               precompute[i] = 1.0f / (bx*bx + by*by);
Ivan Mahonin b53a5c
            else
Ivan Mahonin b53a5c
               precompute[i] = 0.0f;
Ivan Mahonin b53a5c
         } else
Ivan Mahonin b53a5c
            precompute[i] = 0.0f;
Ivan Mahonin b53a5c
      }
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
      for (y=iy0; y < iy1; ++y) {
Ivan Mahonin b53a5c
         for (x=ix0; x < ix1; ++x) {
Ivan Mahonin b53a5c
            float val;
Ivan Mahonin b53a5c
            float min_dist = 999999.0f;
Ivan Mahonin b53a5c
            float sx = (float) x + 0.5f;
Ivan Mahonin b53a5c
            float sy = (float) y + 0.5f;
Ivan Mahonin b53a5c
            float x_gspace = (sx / scale_x);
Ivan Mahonin b53a5c
            float y_gspace = (sy / scale_y);
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
            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
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
            for (i=0; i < num_verts; ++i) {
Ivan Mahonin b53a5c
               float x0 = verts[i].x*scale_x, y0 = verts[i].y*scale_y;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
               if (verts[i].type == STBTT_vline && precompute[i] != 0.0f) {
Ivan Mahonin b53a5c
                  float x1 = verts[i-1].x*scale_x, y1 = verts[i-1].y*scale_y;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
                  float dist,dist2 = (x0-sx)*(x0-sx) + (y0-sy)*(y0-sy);
Ivan Mahonin b53a5c
                  if (dist2 < min_dist*min_dist)
Ivan Mahonin b53a5c
                     min_dist = (float) STBTT_sqrt(dist2);
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
                  // coarse culling against bbox
Ivan Mahonin b53a5c
                  //if (sx > STBTT_min(x0,x1)-min_dist && sx < STBTT_max(x0,x1)+min_dist &&
Ivan Mahonin b53a5c
                  //    sy > STBTT_min(y0,y1)-min_dist && sy < STBTT_max(y0,y1)+min_dist)
Ivan Mahonin b53a5c
                  dist = (float) STBTT_fabs((x1-x0)*(y0-sy) - (y1-y0)*(x0-sx)) * precompute[i];
Ivan Mahonin b53a5c
                  STBTT_assert(i != 0);
Ivan Mahonin b53a5c
                  if (dist < min_dist) {
Ivan Mahonin b53a5c
                     // check position along line
Ivan Mahonin b53a5c
                     // x' = x0 + t*(x1-x0), y' = y0 + t*(y1-y0)
Ivan Mahonin b53a5c
                     // minimize (x'-sx)*(x'-sx)+(y'-sy)*(y'-sy)
Ivan Mahonin b53a5c
                     float dx = x1-x0, dy = y1-y0;
Ivan Mahonin b53a5c
                     float px = x0-sx, py = y0-sy;
Ivan Mahonin b53a5c
                     // 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
Ivan Mahonin b53a5c
                     // derivative: 2*px*dx + 2*py*dy + (2*dx*dx+2*dy*dy)*t, set to 0 and solve
Ivan Mahonin b53a5c
                     float t = -(px*dx + py*dy) / (dx*dx + dy*dy);
Ivan Mahonin b53a5c
                     if (t >= 0.0f && t <= 1.0f)
Ivan Mahonin b53a5c
                        min_dist = dist;
Ivan Mahonin b53a5c
                  }
Ivan Mahonin b53a5c
               } else if (verts[i].type == STBTT_vcurve) {
Ivan Mahonin b53a5c
                  float x2 = verts[i-1].x *scale_x, y2 = verts[i-1].y *scale_y;
Ivan Mahonin b53a5c
                  float x1 = verts[i  ].cx*scale_x, y1 = verts[i  ].cy*scale_y;
Ivan Mahonin b53a5c
                  float box_x0 = STBTT_min(STBTT_min(x0,x1),x2);
Ivan Mahonin b53a5c
                  float box_y0 = STBTT_min(STBTT_min(y0,y1),y2);
Ivan Mahonin b53a5c
                  float box_x1 = STBTT_max(STBTT_max(x0,x1),x2);
Ivan Mahonin b53a5c
                  float box_y1 = STBTT_max(STBTT_max(y0,y1),y2);
Ivan Mahonin b53a5c
                  // coarse culling against bbox to avoid computing cubic unnecessarily
Ivan Mahonin b53a5c
                  if (sx > box_x0-min_dist && sx < box_x1+min_dist && sy > box_y0-min_dist && sy < box_y1+min_dist) {
Ivan Mahonin b53a5c
                     int num=0;
Ivan Mahonin b53a5c
                     float ax = x1-x0, ay = y1-y0;
Ivan Mahonin b53a5c
                     float bx = x0 - 2*x1 + x2, by = y0 - 2*y1 + y2;
Ivan Mahonin b53a5c
                     float mx = x0 - sx, my = y0 - sy;
Ivan Mahonin b53a5c
                     float res[3] = {0.f,0.f,0.f};
Ivan Mahonin b53a5c
                     float px,py,t,it,dist2;
Ivan Mahonin b53a5c
                     float a_inv = precompute[i];
Ivan Mahonin b53a5c
                     if (a_inv == 0.0) { // if a_inv is 0, it's 2nd degree so use quadratic formula
Ivan Mahonin b53a5c
                        float a = 3*(ax*bx + ay*by);
Ivan Mahonin b53a5c
                        float b = 2*(ax*ax + ay*ay) + (mx*bx+my*by);
Ivan Mahonin b53a5c
                        float c = mx*ax+my*ay;
Ivan Mahonin b53a5c
                        if (a == 0.0) { // if a is 0, it's linear
Ivan Mahonin b53a5c
                           if (b != 0.0) {
Ivan Mahonin b53a5c
                              res[num++] = -c/b;
Ivan Mahonin b53a5c
                           }
Ivan Mahonin b53a5c
                        } else {
Ivan Mahonin b53a5c
                           float discriminant = b*b - 4*a*c;
Ivan Mahonin b53a5c
                           if (discriminant < 0)
Ivan Mahonin b53a5c
                              num = 0;
Ivan Mahonin b53a5c
                           else {
Ivan Mahonin b53a5c
                              float root = (float) STBTT_sqrt(discriminant);
Ivan Mahonin b53a5c
                              res[0] = (-b - root)/(2*a);
Ivan Mahonin b53a5c
                              res[1] = (-b + root)/(2*a);
Ivan Mahonin b53a5c
                              num = 2; // don't bother distinguishing 1-solution case, as code below will still work
Ivan Mahonin b53a5c
                           }
Ivan Mahonin b53a5c
                        }
Ivan Mahonin b53a5c
                     } else {
Ivan Mahonin b53a5c
                        float b = 3*(ax*bx + ay*by) * a_inv; // could precompute this as it doesn't depend on sample point
Ivan Mahonin b53a5c
                        float c = (2*(ax*ax + ay*ay) + (mx*bx+my*by)) * a_inv;
Ivan Mahonin b53a5c
                        float d = (mx*ax+my*ay) * a_inv;
Ivan Mahonin b53a5c
                        num = stbtt__solve_cubic(b, c, d, res);
Ivan Mahonin b53a5c
                     }
Ivan Mahonin b53a5c
                     dist2 = (x0-sx)*(x0-sx) + (y0-sy)*(y0-sy);
Ivan Mahonin b53a5c
                     if (dist2 < min_dist*min_dist)
Ivan Mahonin b53a5c
                        min_dist = (float) STBTT_sqrt(dist2);
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
                     if (num >= 1 && res[0] >= 0.0f && res[0] <= 1.0f) {
Ivan Mahonin b53a5c
                        t = res[0], it = 1.0f - t;
Ivan Mahonin b53a5c
                        px = it*it*x0 + 2*t*it*x1 + t*t*x2;
Ivan Mahonin b53a5c
                        py = it*it*y0 + 2*t*it*y1 + t*t*y2;
Ivan Mahonin b53a5c
                        dist2 = (px-sx)*(px-sx) + (py-sy)*(py-sy);
Ivan Mahonin b53a5c
                        if (dist2 < min_dist * min_dist)
Ivan Mahonin b53a5c
                           min_dist = (float) STBTT_sqrt(dist2);
Ivan Mahonin b53a5c
                     }
Ivan Mahonin b53a5c
                     if (num >= 2 && res[1] >= 0.0f && res[1] <= 1.0f) {
Ivan Mahonin b53a5c
                        t = res[1], it = 1.0f - t;
Ivan Mahonin b53a5c
                        px = it*it*x0 + 2*t*it*x1 + t*t*x2;
Ivan Mahonin b53a5c
                        py = it*it*y0 + 2*t*it*y1 + t*t*y2;
Ivan Mahonin b53a5c
                        dist2 = (px-sx)*(px-sx) + (py-sy)*(py-sy);
Ivan Mahonin b53a5c
                        if (dist2 < min_dist * min_dist)
Ivan Mahonin b53a5c
                           min_dist = (float) STBTT_sqrt(dist2);
Ivan Mahonin b53a5c
                     }
Ivan Mahonin b53a5c
                     if (num >= 3 && res[2] >= 0.0f && res[2] <= 1.0f) {
Ivan Mahonin b53a5c
                        t = res[2], it = 1.0f - t;
Ivan Mahonin b53a5c
                        px = it*it*x0 + 2*t*it*x1 + t*t*x2;
Ivan Mahonin b53a5c
                        py = it*it*y0 + 2*t*it*y1 + t*t*y2;
Ivan Mahonin b53a5c
                        dist2 = (px-sx)*(px-sx) + (py-sy)*(py-sy);
Ivan Mahonin b53a5c
                        if (dist2 < min_dist * min_dist)
Ivan Mahonin b53a5c
                           min_dist = (float) STBTT_sqrt(dist2);
Ivan Mahonin b53a5c
                     }
Ivan Mahonin b53a5c
                  }
Ivan Mahonin b53a5c
               }
Ivan Mahonin b53a5c
            }
Ivan Mahonin b53a5c
            if (winding == 0)
Ivan Mahonin b53a5c
               min_dist = -min_dist;  // if outside the shape, value is negative
Ivan Mahonin b53a5c
            val = onedge_value + pixel_dist_scale * min_dist;
Ivan Mahonin b53a5c
            if (val < 0)
Ivan Mahonin b53a5c
               val = 0;
Ivan Mahonin b53a5c
            else if (val > 255)
Ivan Mahonin b53a5c
               val = 255;
Ivan Mahonin b53a5c
            data[(y-iy0)*w+(x-ix0)] = (unsigned char) val;
Ivan Mahonin b53a5c
         }
Ivan Mahonin b53a5c
      }
Ivan Mahonin b53a5c
      STBTT_free(precompute, info->userdata);
Ivan Mahonin b53a5c
      STBTT_free(verts, info->userdata);
Ivan Mahonin b53a5c
   }
Ivan Mahonin b53a5c
   return data;
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
STBTT_DEF unsigned char * stbtt_GetCodepointSDF(const stbtt_fontinfo *info, float scale, int codepoint, int padding, unsigned char onedge_value, float pixel_dist_scale, int *width, int *height, int *xoff, int *yoff)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   return stbtt_GetGlyphSDF(info, scale, stbtt_FindGlyphIndex(info, codepoint), padding, onedge_value, pixel_dist_scale, width, height, xoff, yoff);
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
STBTT_DEF void stbtt_FreeSDF(unsigned char *bitmap, void *userdata)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   STBTT_free(bitmap, userdata);
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
//////////////////////////////////////////////////////////////////////////////
Ivan Mahonin b53a5c
//
Ivan Mahonin b53a5c
// font name matching -- recommended not to use this
Ivan Mahonin b53a5c
//
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
// check if a utf8 string contains a prefix which is the utf16 string; if so return length of matching utf8 string
Ivan Mahonin b53a5c
static stbtt_int32 stbtt__CompareUTF8toUTF16_bigendian_prefix(stbtt_uint8 *s1, stbtt_int32 len1, stbtt_uint8 *s2, stbtt_int32 len2)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   stbtt_int32 i=0;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   // convert utf16 to utf8 and compare the results while converting
Ivan Mahonin b53a5c
   while (len2) {
Ivan Mahonin b53a5c
      stbtt_uint16 ch = s2[0]*256 + s2[1];
Ivan Mahonin b53a5c
      if (ch < 0x80) {
Ivan Mahonin b53a5c
         if (i >= len1) return -1;
Ivan Mahonin b53a5c
         if (s1[i++] != ch) return -1;
Ivan Mahonin b53a5c
      } else if (ch < 0x800) {
Ivan Mahonin b53a5c
         if (i+1 >= len1) return -1;
Ivan Mahonin b53a5c
         if (s1[i++] != 0xc0 + (ch >> 6)) return -1;
Ivan Mahonin b53a5c
         if (s1[i++] != 0x80 + (ch & 0x3f)) return -1;
Ivan Mahonin b53a5c
      } else if (ch >= 0xd800 && ch < 0xdc00) {
Ivan Mahonin b53a5c
         stbtt_uint32 c;
Ivan Mahonin b53a5c
         stbtt_uint16 ch2 = s2[2]*256 + s2[3];
Ivan Mahonin b53a5c
         if (i+3 >= len1) return -1;
Ivan Mahonin b53a5c
         c = ((ch - 0xd800) << 10) + (ch2 - 0xdc00) + 0x10000;
Ivan Mahonin b53a5c
         if (s1[i++] != 0xf0 + (c >> 18)) return -1;
Ivan Mahonin b53a5c
         if (s1[i++] != 0x80 + ((c >> 12) & 0x3f)) return -1;
Ivan Mahonin b53a5c
         if (s1[i++] != 0x80 + ((c >>  6) & 0x3f)) return -1;
Ivan Mahonin b53a5c
         if (s1[i++] != 0x80 + ((c      ) & 0x3f)) return -1;
Ivan Mahonin b53a5c
         s2 += 2; // plus another 2 below
Ivan Mahonin b53a5c
         len2 -= 2;
Ivan Mahonin b53a5c
      } else if (ch >= 0xdc00 && ch < 0xe000) {
Ivan Mahonin b53a5c
         return -1;
Ivan Mahonin b53a5c
      } else {
Ivan Mahonin b53a5c
         if (i+2 >= len1) return -1;
Ivan Mahonin b53a5c
         if (s1[i++] != 0xe0 + (ch >> 12)) return -1;
Ivan Mahonin b53a5c
         if (s1[i++] != 0x80 + ((ch >> 6) & 0x3f)) return -1;
Ivan Mahonin b53a5c
         if (s1[i++] != 0x80 + ((ch     ) & 0x3f)) return -1;
Ivan Mahonin b53a5c
      }
Ivan Mahonin b53a5c
      s2 += 2;
Ivan Mahonin b53a5c
      len2 -= 2;
Ivan Mahonin b53a5c
   }
Ivan Mahonin b53a5c
   return i;
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
static int stbtt_CompareUTF8toUTF16_bigendian_internal(char *s1, int len1, char *s2, int len2)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   return len1 == stbtt__CompareUTF8toUTF16_bigendian_prefix((stbtt_uint8*) s1, len1, (stbtt_uint8*) s2, len2);
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
// returns results in whatever encoding you request... but note that 2-byte encodings
Ivan Mahonin b53a5c
// will be BIG-ENDIAN... use stbtt_CompareUTF8toUTF16_bigendian() to compare
Ivan Mahonin b53a5c
STBTT_DEF const char *stbtt_GetFontNameString(const stbtt_fontinfo *font, int *length, int platformID, int encodingID, int languageID, int nameID)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   stbtt_int32 i,count,stringOffset;
Ivan Mahonin b53a5c
   stbtt_uint8 *fc = font->data;
Ivan Mahonin b53a5c
   stbtt_uint32 offset = font->fontstart;
Ivan Mahonin b53a5c
   stbtt_uint32 nm = stbtt__find_table(fc, offset, "name");
Ivan Mahonin b53a5c
   if (!nm) return NULL;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   count = ttUSHORT(fc+nm+2);
Ivan Mahonin b53a5c
   stringOffset = nm + ttUSHORT(fc+nm+4);
Ivan Mahonin b53a5c
   for (i=0; i < count; ++i) {
Ivan Mahonin b53a5c
      stbtt_uint32 loc = nm + 6 + 12 * i;
Ivan Mahonin b53a5c
      if (platformID == ttUSHORT(fc+loc+0) && encodingID == ttUSHORT(fc+loc+2)
Ivan Mahonin b53a5c
          && languageID == ttUSHORT(fc+loc+4) && nameID == ttUSHORT(fc+loc+6)) {
Ivan Mahonin b53a5c
         *length = ttUSHORT(fc+loc+8);
Ivan Mahonin b53a5c
         return (const char *) (fc+stringOffset+ttUSHORT(fc+loc+10));
Ivan Mahonin b53a5c
      }
Ivan Mahonin b53a5c
   }
Ivan Mahonin b53a5c
   return NULL;
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
static int stbtt__matchpair(stbtt_uint8 *fc, stbtt_uint32 nm, stbtt_uint8 *name, stbtt_int32 nlen, stbtt_int32 target_id, stbtt_int32 next_id)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   stbtt_int32 i;
Ivan Mahonin b53a5c
   stbtt_int32 count = ttUSHORT(fc+nm+2);
Ivan Mahonin b53a5c
   stbtt_int32 stringOffset = nm + ttUSHORT(fc+nm+4);
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   for (i=0; i < count; ++i) {
Ivan Mahonin b53a5c
      stbtt_uint32 loc = nm + 6 + 12 * i;
Ivan Mahonin b53a5c
      stbtt_int32 id = ttUSHORT(fc+loc+6);
Ivan Mahonin b53a5c
      if (id == target_id) {
Ivan Mahonin b53a5c
         // find the encoding
Ivan Mahonin b53a5c
         stbtt_int32 platform = ttUSHORT(fc+loc+0), encoding = ttUSHORT(fc+loc+2), language = ttUSHORT(fc+loc+4);
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
         // is this a Unicode encoding?
Ivan Mahonin b53a5c
         if (platform == 0 || (platform == 3 && encoding == 1) || (platform == 3 && encoding == 10)) {
Ivan Mahonin b53a5c
            stbtt_int32 slen = ttUSHORT(fc+loc+8);
Ivan Mahonin b53a5c
            stbtt_int32 off = ttUSHORT(fc+loc+10);
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
            // check if there's a prefix match
Ivan Mahonin b53a5c
            stbtt_int32 matchlen = stbtt__CompareUTF8toUTF16_bigendian_prefix(name, nlen, fc+stringOffset+off,slen);
Ivan Mahonin b53a5c
            if (matchlen >= 0) {
Ivan Mahonin b53a5c
               // check for target_id+1 immediately following, with same encoding & language
Ivan Mahonin b53a5c
               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) {
Ivan Mahonin b53a5c
                  slen = ttUSHORT(fc+loc+12+8);
Ivan Mahonin b53a5c
                  off = ttUSHORT(fc+loc+12+10);
Ivan Mahonin b53a5c
                  if (slen == 0) {
Ivan Mahonin b53a5c
                     if (matchlen == nlen)
Ivan Mahonin b53a5c
                        return 1;
Ivan Mahonin b53a5c
                  } else if (matchlen < nlen && name[matchlen] == ' ') {
Ivan Mahonin b53a5c
                     ++matchlen;
Ivan Mahonin b53a5c
                     if (stbtt_CompareUTF8toUTF16_bigendian_internal((char*) (name+matchlen), nlen-matchlen, (char*)(fc+stringOffset+off),slen))
Ivan Mahonin b53a5c
                        return 1;
Ivan Mahonin b53a5c
                  }
Ivan Mahonin b53a5c
               } else {
Ivan Mahonin b53a5c
                  // if nothing immediately following
Ivan Mahonin b53a5c
                  if (matchlen == nlen)
Ivan Mahonin b53a5c
                     return 1;
Ivan Mahonin b53a5c
               }
Ivan Mahonin b53a5c
            }
Ivan Mahonin b53a5c
         }
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
         // @TODO handle other encodings
Ivan Mahonin b53a5c
      }
Ivan Mahonin b53a5c
   }
Ivan Mahonin b53a5c
   return 0;
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
static int stbtt__matches(stbtt_uint8 *fc, stbtt_uint32 offset, stbtt_uint8 *name, stbtt_int32 flags)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   stbtt_int32 nlen = (stbtt_int32) STBTT_strlen((char *) name);
Ivan Mahonin b53a5c
   stbtt_uint32 nm,hd;
Ivan Mahonin b53a5c
   if (!stbtt__isfont(fc+offset)) return 0;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   // check italics/bold/underline flags in macStyle...
Ivan Mahonin b53a5c
   if (flags) {
Ivan Mahonin b53a5c
      hd = stbtt__find_table(fc, offset, "head");
Ivan Mahonin b53a5c
      if ((ttUSHORT(fc+hd+44) & 7) != (flags & 7)) return 0;
Ivan Mahonin b53a5c
   }
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   nm = stbtt__find_table(fc, offset, "name");
Ivan Mahonin b53a5c
   if (!nm) return 0;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   if (flags) {
Ivan Mahonin b53a5c
      // if we checked the macStyle flags, then just check the family and ignore the subfamily
Ivan Mahonin b53a5c
      if (stbtt__matchpair(fc, nm, name, nlen, 16, -1))  return 1;
Ivan Mahonin b53a5c
      if (stbtt__matchpair(fc, nm, name, nlen,  1, -1))  return 1;
Ivan Mahonin b53a5c
      if (stbtt__matchpair(fc, nm, name, nlen,  3, -1))  return 1;
Ivan Mahonin b53a5c
   } else {
Ivan Mahonin b53a5c
      if (stbtt__matchpair(fc, nm, name, nlen, 16, 17))  return 1;
Ivan Mahonin b53a5c
      if (stbtt__matchpair(fc, nm, name, nlen,  1,  2))  return 1;
Ivan Mahonin b53a5c
      if (stbtt__matchpair(fc, nm, name, nlen,  3, -1))  return 1;
Ivan Mahonin b53a5c
   }
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
   return 0;
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
static int stbtt_FindMatchingFont_internal(unsigned char *font_collection, char *name_utf8, stbtt_int32 flags)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   stbtt_int32 i;
Ivan Mahonin b53a5c
   for (i=0;;++i) {
Ivan Mahonin b53a5c
      stbtt_int32 off = stbtt_GetFontOffsetForIndex(font_collection, i);
Ivan Mahonin b53a5c
      if (off < 0) return off;
Ivan Mahonin b53a5c
      if (stbtt__matches((stbtt_uint8 *) font_collection, off, (stbtt_uint8*) name_utf8, flags))
Ivan Mahonin b53a5c
         return off;
Ivan Mahonin b53a5c
   }
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
#if defined(__GNUC__) || defined(__clang__)
Ivan Mahonin b53a5c
#pragma GCC diagnostic push
Ivan Mahonin b53a5c
#pragma GCC diagnostic ignored "-Wcast-qual"
Ivan Mahonin b53a5c
#endif
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
STBTT_DEF int stbtt_BakeFontBitmap(const unsigned char *data, int offset,
Ivan Mahonin b53a5c
                                float pixel_height, unsigned char *pixels, int pw, int ph,
Ivan Mahonin b53a5c
                                int first_char, int num_chars, stbtt_bakedchar *chardata)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   return stbtt_BakeFontBitmap_internal((unsigned char *) data, offset, pixel_height, pixels, pw, ph, first_char, num_chars, chardata);
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
STBTT_DEF int stbtt_GetFontOffsetForIndex(const unsigned char *data, int index)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   return stbtt_GetFontOffsetForIndex_internal((unsigned char *) data, index);
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
STBTT_DEF int stbtt_GetNumberOfFonts(const unsigned char *data)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   return stbtt_GetNumberOfFonts_internal((unsigned char *) data);
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
STBTT_DEF int stbtt_InitFont(stbtt_fontinfo *info, const unsigned char *data, int offset)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   return stbtt_InitFont_internal(info, (unsigned char *) data, offset);
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
STBTT_DEF int stbtt_FindMatchingFont(const unsigned char *fontdata, const char *name, int flags)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   return stbtt_FindMatchingFont_internal((unsigned char *) fontdata, (char *) name, flags);
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
STBTT_DEF int stbtt_CompareUTF8toUTF16_bigendian(const char *s1, int len1, const char *s2, int len2)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
   return stbtt_CompareUTF8toUTF16_bigendian_internal((char *) s1, len1, (char *) s2, len2);
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
#if defined(__GNUC__) || defined(__clang__)
Ivan Mahonin b53a5c
#pragma GCC diagnostic pop
Ivan Mahonin b53a5c
#endif
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
#endif // STB_TRUETYPE_IMPLEMENTATION
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
// FULL VERSION HISTORY
Ivan Mahonin b53a5c
//
Ivan Mahonin b53a5c
//   1.25 (2021-07-11) many fixes
Ivan Mahonin b53a5c
//   1.24 (2020-02-05) fix warning
Ivan Mahonin b53a5c
//   1.23 (2020-02-02) query SVG data for glyphs; query whole kerning table (but only kern not GPOS)
Ivan Mahonin b53a5c
//   1.22 (2019-08-11) minimize missing-glyph duplication; fix kerning if both 'GPOS' and 'kern' are defined
Ivan Mahonin b53a5c
//   1.21 (2019-02-25) fix warning
Ivan Mahonin b53a5c
//   1.20 (2019-02-07) PackFontRange skips missing codepoints; GetScaleFontVMetrics()
Ivan Mahonin b53a5c
//   1.19 (2018-02-11) OpenType GPOS kerning (horizontal only), STBTT_fmod
Ivan Mahonin b53a5c
//   1.18 (2018-01-29) add missing function
Ivan Mahonin b53a5c
//   1.17 (2017-07-23) make more arguments const; doc fix
Ivan Mahonin b53a5c
//   1.16 (2017-07-12) SDF support
Ivan Mahonin b53a5c
//   1.15 (2017-03-03) make more arguments const
Ivan Mahonin b53a5c
//   1.14 (2017-01-16) num-fonts-in-TTC function
Ivan Mahonin b53a5c
//   1.13 (2017-01-02) support OpenType fonts, certain Apple fonts
Ivan Mahonin b53a5c
//   1.12 (2016-10-25) suppress warnings about casting away const with -Wcast-qual
Ivan Mahonin b53a5c
//   1.11 (2016-04-02) fix unused-variable warning
Ivan Mahonin b53a5c
//   1.10 (2016-04-02) allow user-defined fabs() replacement
Ivan Mahonin b53a5c
//                     fix memory leak if fontsize=0.0
Ivan Mahonin b53a5c
//                     fix warning from duplicate typedef
Ivan Mahonin b53a5c
//   1.09 (2016-01-16) warning fix; avoid crash on outofmem; use alloc userdata for PackFontRanges
Ivan Mahonin b53a5c
//   1.08 (2015-09-13) document stbtt_Rasterize(); fixes for vertical & horizontal edges
Ivan Mahonin b53a5c
//   1.07 (2015-08-01) allow PackFontRanges to accept arrays of sparse codepoints;
Ivan Mahonin b53a5c
//                     allow PackFontRanges to pack and render in separate phases;
Ivan Mahonin b53a5c
//                     fix stbtt_GetFontOFfsetForIndex (never worked for non-0 input?);
Ivan Mahonin b53a5c
//                     fixed an assert() bug in the new rasterizer
Ivan Mahonin b53a5c
//                     replace assert() with STBTT_assert() in new rasterizer
Ivan Mahonin b53a5c
//   1.06 (2015-07-14) performance improvements (~35% faster on x86 and x64 on test machine)
Ivan Mahonin b53a5c
//                     also more precise AA rasterizer, except if shapes overlap
Ivan Mahonin b53a5c
//                     remove need for STBTT_sort
Ivan Mahonin b53a5c
//   1.05 (2015-04-15) fix misplaced definitions for STBTT_STATIC
Ivan Mahonin b53a5c
//   1.04 (2015-04-15) typo in example
Ivan Mahonin b53a5c
//   1.03 (2015-04-12) STBTT_STATIC, fix memory leak in new packing, various fixes
Ivan Mahonin b53a5c
//   1.02 (2014-12-10) fix various warnings & compile issues w/ stb_rect_pack, C++
Ivan Mahonin b53a5c
//   1.01 (2014-12-08) fix subpixel position when oversampling to exactly match
Ivan Mahonin b53a5c
//                        non-oversampled; STBTT_POINT_SIZE for packed case only
Ivan Mahonin b53a5c
//   1.00 (2014-12-06) add new PackBegin etc. API, w/ support for oversampling
Ivan Mahonin b53a5c
//   0.99 (2014-09-18) fix multiple bugs with subpixel rendering (ryg)
Ivan Mahonin b53a5c
//   0.9  (2014-08-07) support certain mac/iOS fonts without an MS platformID
Ivan Mahonin b53a5c
//   0.8b (2014-07-07) fix a warning
Ivan Mahonin b53a5c
//   0.8  (2014-05-25) fix a few more warnings
Ivan Mahonin b53a5c
//   0.7  (2013-09-25) bugfix: subpixel glyph bug fixed in 0.5 had come back
Ivan Mahonin b53a5c
//   0.6c (2012-07-24) improve documentation
Ivan Mahonin b53a5c
//   0.6b (2012-07-20) fix a few more warnings
Ivan Mahonin b53a5c
//   0.6  (2012-07-17) fix warnings; added stbtt_ScaleForMappingEmToPixels,
Ivan Mahonin b53a5c
//                        stbtt_GetFontBoundingBox, stbtt_IsGlyphEmpty
Ivan Mahonin b53a5c
//   0.5  (2011-12-09) bugfixes:
Ivan Mahonin b53a5c
//                        subpixel glyph renderer computed wrong bounding box
Ivan Mahonin b53a5c
//                        first vertex of shape can be off-curve (FreeSans)
Ivan Mahonin b53a5c
//   0.4b (2011-12-03) fixed an error in the font baking example
Ivan Mahonin b53a5c
//   0.4  (2011-12-01) kerning, subpixel rendering (tor)
Ivan Mahonin b53a5c
//                    bugfixes for:
Ivan Mahonin b53a5c
//                        codepoint-to-glyph conversion using table fmt=12
Ivan Mahonin b53a5c
//                        codepoint-to-glyph conversion using table fmt=4
Ivan Mahonin b53a5c
//                        stbtt_GetBakedQuad with non-square texture (Zer)
Ivan Mahonin b53a5c
//                    updated Hello World! sample to use kerning and subpixel
Ivan Mahonin b53a5c
//                    fixed some warnings
Ivan Mahonin b53a5c
//   0.3  (2009-06-24) cmap fmt=12, compound shapes (MM)
Ivan Mahonin b53a5c
//                    userdata, malloc-from-userdata, non-zero fill (stb)
Ivan Mahonin b53a5c
//   0.2  (2009-03-11) Fix unsigned/signed char warnings
Ivan Mahonin b53a5c
//   0.1  (2009-03-09) First public release
Ivan Mahonin b53a5c
//
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
/*
Ivan Mahonin b53a5c
------------------------------------------------------------------------------
Ivan Mahonin b53a5c
This software is available under 2 licenses -- choose whichever you prefer.
Ivan Mahonin b53a5c
------------------------------------------------------------------------------
Ivan Mahonin b53a5c
ALTERNATIVE A - MIT License
Ivan Mahonin b53a5c
Copyright (c) 2017 Sean Barrett
Ivan Mahonin b53a5c
Permission is hereby granted, free of charge, to any person obtaining a copy of
Ivan Mahonin b53a5c
this software and associated documentation files (the "Software"), to deal in
Ivan Mahonin b53a5c
the Software without restriction, including without limitation the rights to
Ivan Mahonin b53a5c
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
Ivan Mahonin b53a5c
of the Software, and to permit persons to whom the Software is furnished to do
Ivan Mahonin b53a5c
so, subject to the following conditions:
Ivan Mahonin b53a5c
The above copyright notice and this permission notice shall be included in all
Ivan Mahonin b53a5c
copies or substantial portions of the Software.
Ivan Mahonin b53a5c
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
Ivan Mahonin b53a5c
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
Ivan Mahonin b53a5c
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
Ivan Mahonin b53a5c
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
Ivan Mahonin b53a5c
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
Ivan Mahonin b53a5c
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
Ivan Mahonin b53a5c
SOFTWARE.
Ivan Mahonin b53a5c
------------------------------------------------------------------------------
Ivan Mahonin b53a5c
ALTERNATIVE B - Public Domain (www.unlicense.org)
Ivan Mahonin b53a5c
This is free and unencumbered software released into the public domain.
Ivan Mahonin b53a5c
Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
Ivan Mahonin b53a5c
software, either in source code form or as a compiled binary, for any purpose,
Ivan Mahonin b53a5c
commercial or non-commercial, and by any means.
Ivan Mahonin b53a5c
In jurisdictions that recognize copyright laws, the author or authors of this
Ivan Mahonin b53a5c
software dedicate any and all copyright interest in the software to the public
Ivan Mahonin b53a5c
domain. We make this dedication for the benefit of the public at large and to
Ivan Mahonin b53a5c
the detriment of our heirs and successors. We intend this dedication to be an
Ivan Mahonin b53a5c
overt act of relinquishment in perpetuity of all present and future rights to
Ivan Mahonin b53a5c
this software under copyright law.
Ivan Mahonin b53a5c
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
Ivan Mahonin b53a5c
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
Ivan Mahonin b53a5c
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
Ivan Mahonin b53a5c
AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
Ivan Mahonin b53a5c
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
Ivan Mahonin b53a5c
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Ivan Mahonin b53a5c
------------------------------------------------------------------------------
Ivan Mahonin b53a5c
*/