mirror of https://github.com/nothings/stb.git
Merge branch 'cff-type2' of https://github.com/dougallj/stb into type2
Conflicts: stb_truetype.h
This commit is contained in:
commit
ad6614ad9f
710
stb_truetype.h
710
stb_truetype.h
|
@ -453,6 +453,14 @@ int main(int arg, char **argv)
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// private structure
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
stbtt_uint8 *data;
|
||||||
|
int cursor;
|
||||||
|
int size;
|
||||||
|
} stbtt__buf;
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
// TEXTURE BAKING API
|
// TEXTURE BAKING API
|
||||||
|
@ -643,6 +651,13 @@ struct stbtt_fontinfo
|
||||||
int loca,head,glyf,hhea,hmtx,kern; // table locations as offset from start of .ttf
|
int loca,head,glyf,hhea,hmtx,kern; // table locations as offset from start of .ttf
|
||||||
int index_map; // a cmap mapping for our chosen character encoding
|
int index_map; // a cmap mapping for our chosen character encoding
|
||||||
int indexToLocFormat; // format needed to map from glyph index to glyph
|
int indexToLocFormat; // format needed to map from glyph index to glyph
|
||||||
|
|
||||||
|
stbtt__buf cff; // cff font data
|
||||||
|
stbtt__buf charstrings; // the charstring index
|
||||||
|
stbtt__buf gsubrs; // global charstring subroutines index
|
||||||
|
stbtt__buf subrs; // private charstring subroutines index
|
||||||
|
stbtt__buf fontdicts; // array of font dicts
|
||||||
|
stbtt__buf fdselect; // map from glyph to fontdict
|
||||||
};
|
};
|
||||||
|
|
||||||
STBTT_DEF int stbtt_InitFont(stbtt_fontinfo *info, const unsigned char *data, int offset);
|
STBTT_DEF int stbtt_InitFont(stbtt_fontinfo *info, const unsigned char *data, int offset);
|
||||||
|
@ -720,7 +735,8 @@ STBTT_DEF int stbtt_GetGlyphBox(const stbtt_fontinfo *info, int glyph_index, in
|
||||||
enum {
|
enum {
|
||||||
STBTT_vmove=1,
|
STBTT_vmove=1,
|
||||||
STBTT_vline,
|
STBTT_vline,
|
||||||
STBTT_vcurve
|
STBTT_vcurve,
|
||||||
|
STBTT_vcubic
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -729,7 +745,7 @@ STBTT_DEF int stbtt_GetGlyphBox(const stbtt_fontinfo *info, int glyph_index, in
|
||||||
#define stbtt_vertex_type short // can't use stbtt_int16 because that's not visible in the header file
|
#define stbtt_vertex_type short // can't use stbtt_int16 because that's not visible in the header file
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
stbtt_vertex_type x,y,cx,cy;
|
stbtt_vertex_type x,y,cx,cy,cx1,cy1;
|
||||||
unsigned char type,padding;
|
unsigned char type,padding;
|
||||||
} stbtt_vertex;
|
} stbtt_vertex;
|
||||||
#endif
|
#endif
|
||||||
|
@ -951,6 +967,152 @@ typedef int stbtt__test_oversample_pow2[(STBTT_MAX_OVERSAMPLE & (STBTT_MAX_OVERS
|
||||||
#define STBTT__NOTUSED(v) (void)sizeof(v)
|
#define STBTT__NOTUSED(v) (void)sizeof(v)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// stbtt__buf helpers to parse data from file
|
||||||
|
//
|
||||||
|
|
||||||
|
static stbtt_uint8 stbtt__buf_get8(stbtt__buf *b)
|
||||||
|
{
|
||||||
|
if (b->cursor >= b->size)
|
||||||
|
return 0;
|
||||||
|
return b->data[b->cursor++];
|
||||||
|
}
|
||||||
|
|
||||||
|
static stbtt_uint8 stbtt__buf_peek8(stbtt__buf *b)
|
||||||
|
{
|
||||||
|
if (b->cursor >= b->size)
|
||||||
|
return 0;
|
||||||
|
return b->data[b->cursor];
|
||||||
|
}
|
||||||
|
|
||||||
|
static void stbtt__buf_seek(stbtt__buf *b, int o)
|
||||||
|
{
|
||||||
|
STBTT_assert(!(o > b->size || o < 0));
|
||||||
|
b->cursor = (o > b->size || o < 0) ? b->size : o;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void stbtt__buf_skip(stbtt__buf *b, int o)
|
||||||
|
{
|
||||||
|
stbtt__buf_seek(b, b->cursor + o);
|
||||||
|
}
|
||||||
|
|
||||||
|
static stbtt_uint32 stbtt__buf_get(stbtt__buf *b, int n)
|
||||||
|
{
|
||||||
|
stbtt_uint32 v = 0;
|
||||||
|
int i;
|
||||||
|
STBTT_assert(n >= 1 && n <= 4);
|
||||||
|
for (i = 0; i < n; i++)
|
||||||
|
v = (v << 8) | stbtt__buf_get8(b);
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
static stbtt__buf stbtt__new_buf(const void *p, size_t size)
|
||||||
|
{
|
||||||
|
stbtt__buf r;
|
||||||
|
STBTT_assert(size < 0x40000000);
|
||||||
|
r.data = (stbtt_uint8*) p;
|
||||||
|
r.size = (int) size;
|
||||||
|
r.cursor = 0;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define stbtt__buf_get16(b) stbtt__buf_get((b), 2)
|
||||||
|
#define stbtt__buf_get32(b) stbtt__buf_get((b), 4)
|
||||||
|
|
||||||
|
static stbtt__buf stbtt__buf_range(const stbtt__buf *b, int o, int s)
|
||||||
|
{
|
||||||
|
stbtt__buf r = stbtt__new_buf(NULL, 0);
|
||||||
|
if (o < 0 || s < 0 || o > b->size || s > b->size - o) return r;
|
||||||
|
r.data = b->data + o;
|
||||||
|
r.size = s;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
static stbtt__buf stbtt__cff_get_index(stbtt__buf *b)
|
||||||
|
{
|
||||||
|
int count, start, offsize;
|
||||||
|
start = b->cursor;
|
||||||
|
count = stbtt__buf_get16(b);
|
||||||
|
if (count) {
|
||||||
|
offsize = stbtt__buf_get8(b);
|
||||||
|
STBTT_assert(offsize >= 1 && offsize <= 4);
|
||||||
|
stbtt__buf_skip(b, offsize * count);
|
||||||
|
stbtt__buf_skip(b, stbtt__buf_get(b, offsize) - 1);
|
||||||
|
}
|
||||||
|
return stbtt__buf_range(b, start, b->cursor - start);
|
||||||
|
}
|
||||||
|
|
||||||
|
static stbtt_uint32 stbtt__cff_int(stbtt__buf *b)
|
||||||
|
{
|
||||||
|
int b0 = stbtt__buf_get8(b);
|
||||||
|
if (b0 >= 32 && b0 <= 246) return b0 - 139;
|
||||||
|
else if (b0 >= 247 && b0 <= 250) return (b0 - 247)*256 + stbtt__buf_get8(b) + 108;
|
||||||
|
else if (b0 >= 251 && b0 <= 254) return -(b0 - 251)*256 - stbtt__buf_get8(b) - 108;
|
||||||
|
else if (b0 == 28) return stbtt__buf_get16(b);
|
||||||
|
else if (b0 == 29) return stbtt__buf_get32(b);
|
||||||
|
STBTT_assert(0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void stbtt__cff_skip_operand(stbtt__buf *b) {
|
||||||
|
int v, b0 = stbtt__buf_peek8(b);
|
||||||
|
STBTT_assert(b0 >= 28);
|
||||||
|
if (b0 == 30) {
|
||||||
|
stbtt__buf_skip(b, 1);
|
||||||
|
while (b->cursor < b->size) {
|
||||||
|
v = stbtt__buf_get8(b);
|
||||||
|
if ((v & 0xF) == 0xF || (v >> 4) == 0xF)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
stbtt__cff_int(b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static stbtt__buf stbtt__dict_get(stbtt__buf *b, int key)
|
||||||
|
{
|
||||||
|
stbtt__buf_seek(b, 0);
|
||||||
|
while (b->cursor < b->size) {
|
||||||
|
int start = b->cursor, end, op;
|
||||||
|
while (stbtt__buf_peek8(b) >= 28)
|
||||||
|
stbtt__cff_skip_operand(b);
|
||||||
|
end = b->cursor;
|
||||||
|
op = stbtt__buf_get8(b);
|
||||||
|
if (op == 12) op = stbtt__buf_get8(b) | 0x100;
|
||||||
|
if (op == key) return stbtt__buf_range(b, start, end-start);
|
||||||
|
}
|
||||||
|
return stbtt__buf_range(b, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void stbtt__dict_get_ints(stbtt__buf *b, int key, int outcount, stbtt_uint32 *out)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
stbtt__buf operands = stbtt__dict_get(b, key);
|
||||||
|
for (i = 0; i < outcount && operands.cursor < operands.size; i++)
|
||||||
|
out[i] = stbtt__cff_int(&operands);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int stbtt__cff_index_count(stbtt__buf *b)
|
||||||
|
{
|
||||||
|
stbtt__buf_seek(b, 0);
|
||||||
|
return stbtt__buf_get16(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
static stbtt__buf stbtt__cff_index_get(stbtt__buf b, int i)
|
||||||
|
{
|
||||||
|
int count, offsize, start, end;
|
||||||
|
stbtt__buf_seek(&b, 0);
|
||||||
|
count = stbtt__buf_get16(&b);
|
||||||
|
offsize = stbtt__buf_get8(&b);
|
||||||
|
STBTT_assert(i >= 0 && i < count);
|
||||||
|
STBTT_assert(offsize >= 1 && offsize <= 4);
|
||||||
|
stbtt__buf_skip(&b, i*offsize);
|
||||||
|
start = stbtt__buf_get(&b, offsize);
|
||||||
|
end = stbtt__buf_get(&b, offsize);
|
||||||
|
return stbtt__buf_range(&b, 2+(count+1)*offsize+start, end - start);
|
||||||
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
// accessors to parse data from file
|
// accessors to parse data from file
|
||||||
|
@ -1014,6 +1176,19 @@ static int stbtt_GetFontOffsetForIndex_internal(unsigned char *font_collection,
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static stbtt__buf stbtt__get_subrs(stbtt__buf cff, stbtt__buf fontdict)
|
||||||
|
{
|
||||||
|
stbtt_uint32 subrsoff = 0, private_loc[2] = { 0, 0 };
|
||||||
|
stbtt__buf pdict;
|
||||||
|
stbtt__dict_get_ints(&fontdict, 18, 2, private_loc);
|
||||||
|
if (!private_loc[1] || !private_loc[0]) return stbtt__new_buf(NULL, 0);
|
||||||
|
pdict = stbtt__buf_range(&cff, private_loc[1], private_loc[0]);
|
||||||
|
stbtt__dict_get_ints(&pdict, 19, 1, &subrsoff);
|
||||||
|
if (!subrsoff) return stbtt__new_buf(NULL, 0);
|
||||||
|
stbtt__buf_seek(&cff, private_loc[1]+subrsoff);
|
||||||
|
return stbtt__cff_get_index(&cff);
|
||||||
|
}
|
||||||
|
|
||||||
static int stbtt_InitFont_internal(stbtt_fontinfo *info, unsigned char *data, int fontstart)
|
static int stbtt_InitFont_internal(stbtt_fontinfo *info, unsigned char *data, int fontstart)
|
||||||
{
|
{
|
||||||
stbtt_uint32 cmap, t;
|
stbtt_uint32 cmap, t;
|
||||||
|
@ -1021,6 +1196,7 @@ static int stbtt_InitFont_internal(stbtt_fontinfo *info, unsigned char *data, in
|
||||||
|
|
||||||
info->data = data;
|
info->data = data;
|
||||||
info->fontstart = fontstart;
|
info->fontstart = fontstart;
|
||||||
|
info->cff = stbtt__new_buf(NULL, 0);
|
||||||
|
|
||||||
cmap = stbtt__find_table(data, fontstart, "cmap"); // required
|
cmap = stbtt__find_table(data, fontstart, "cmap"); // required
|
||||||
info->loca = stbtt__find_table(data, fontstart, "loca"); // required
|
info->loca = stbtt__find_table(data, fontstart, "loca"); // required
|
||||||
|
@ -1029,8 +1205,61 @@ static int stbtt_InitFont_internal(stbtt_fontinfo *info, unsigned char *data, in
|
||||||
info->hhea = stbtt__find_table(data, fontstart, "hhea"); // required
|
info->hhea = stbtt__find_table(data, fontstart, "hhea"); // required
|
||||||
info->hmtx = stbtt__find_table(data, fontstart, "hmtx"); // required
|
info->hmtx = stbtt__find_table(data, fontstart, "hmtx"); // required
|
||||||
info->kern = stbtt__find_table(data, fontstart, "kern"); // not required
|
info->kern = stbtt__find_table(data, fontstart, "kern"); // not required
|
||||||
if (!cmap || !info->loca || !info->head || !info->glyf || !info->hhea || !info->hmtx)
|
|
||||||
|
if (!cmap || !info->head || !info->hhea || !info->hmtx)
|
||||||
return 0;
|
return 0;
|
||||||
|
if (info->glyf) {
|
||||||
|
// required for truetype
|
||||||
|
if (!info->loca) return 0;
|
||||||
|
} else {
|
||||||
|
// initialization for CFF / Type2 fonts (OTF)
|
||||||
|
stbtt__buf b, topdict, topdictidx;
|
||||||
|
stbtt_uint32 cstype = 2, charstrings = 0, fdarrayoff = 0, fdselectoff = 0;
|
||||||
|
stbtt_uint32 cff;
|
||||||
|
|
||||||
|
cff = stbtt__find_table(data, fontstart, "CFF ");
|
||||||
|
if (!cff) return 0;
|
||||||
|
|
||||||
|
info->fontdicts = stbtt__new_buf(NULL, 0);
|
||||||
|
info->fdselect = stbtt__new_buf(NULL, 0);
|
||||||
|
|
||||||
|
// @TODO this should use size from table (not 512MB)
|
||||||
|
info->cff = stbtt__new_buf(data+cff, 512*1024*1024);
|
||||||
|
b = info->cff;
|
||||||
|
|
||||||
|
// read the header
|
||||||
|
stbtt__buf_skip(&b, 2);
|
||||||
|
stbtt__buf_seek(&b, stbtt__buf_get8(&b)); // hdrsize
|
||||||
|
|
||||||
|
// @TODO the name INDEX could list multiple fonts,
|
||||||
|
// but we just use the first one.
|
||||||
|
stbtt__cff_get_index(&b); // name INDEX
|
||||||
|
topdictidx = stbtt__cff_get_index(&b);
|
||||||
|
topdict = stbtt__cff_index_get(topdictidx, 0);
|
||||||
|
stbtt__cff_get_index(&b); // string INDEX
|
||||||
|
info->gsubrs = stbtt__cff_get_index(&b);
|
||||||
|
|
||||||
|
stbtt__dict_get_ints(&topdict, 17, 1, &charstrings);
|
||||||
|
stbtt__dict_get_ints(&topdict, 0x100 | 6, 1, &cstype);
|
||||||
|
stbtt__dict_get_ints(&topdict, 0x100 | 36, 1, &fdarrayoff);
|
||||||
|
stbtt__dict_get_ints(&topdict, 0x100 | 37, 1, &fdselectoff);
|
||||||
|
info->subrs = stbtt__get_subrs(b, topdict);
|
||||||
|
|
||||||
|
// we only support Type 2 charstrings
|
||||||
|
if (cstype != 2) return 0;
|
||||||
|
if (charstrings == 0) return 0;
|
||||||
|
|
||||||
|
if (fdarrayoff) {
|
||||||
|
// looks like a CID font
|
||||||
|
if (!fdselectoff) return 0;
|
||||||
|
stbtt__buf_seek(&b, fdarrayoff);
|
||||||
|
info->fontdicts = stbtt__cff_get_index(&b);
|
||||||
|
info->fdselect = stbtt__buf_range(&b, fdselectoff, b.size-fdselectoff);
|
||||||
|
}
|
||||||
|
|
||||||
|
stbtt__buf_seek(&b, charstrings);
|
||||||
|
info->charstrings = stbtt__cff_get_index(&b);
|
||||||
|
}
|
||||||
|
|
||||||
t = stbtt__find_table(data, fontstart, "maxp");
|
t = stbtt__find_table(data, fontstart, "maxp");
|
||||||
if (t)
|
if (t)
|
||||||
|
@ -1181,6 +1410,8 @@ static int stbtt__GetGlyfOffset(const stbtt_fontinfo *info, int glyph_index)
|
||||||
{
|
{
|
||||||
int g1,g2;
|
int g1,g2;
|
||||||
|
|
||||||
|
STBTT_assert(!info->cff.size);
|
||||||
|
|
||||||
if (glyph_index >= info->numGlyphs) return -1; // glyph index out of range
|
if (glyph_index >= info->numGlyphs) return -1; // glyph index out of range
|
||||||
if (info->indexToLocFormat >= 2) return -1; // unknown index->glyph map format
|
if (info->indexToLocFormat >= 2) return -1; // unknown index->glyph map format
|
||||||
|
|
||||||
|
@ -1195,8 +1426,13 @@ static int stbtt__GetGlyfOffset(const stbtt_fontinfo *info, int glyph_index)
|
||||||
return g1==g2 ? -1 : g1; // if length is 0, return -1
|
return g1==g2 ? -1 : g1; // if length is 0, return -1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int stbtt__GetGlyphInfoT2(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1);
|
||||||
|
|
||||||
STBTT_DEF int stbtt_GetGlyphBox(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1)
|
STBTT_DEF int stbtt_GetGlyphBox(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1)
|
||||||
{
|
{
|
||||||
|
if (info->cff.size) {
|
||||||
|
stbtt__GetGlyphInfoT2(info, glyph_index, x0, y0, x1, y1);
|
||||||
|
} else {
|
||||||
int g = stbtt__GetGlyfOffset(info, glyph_index);
|
int g = stbtt__GetGlyfOffset(info, glyph_index);
|
||||||
if (g < 0) return 0;
|
if (g < 0) return 0;
|
||||||
|
|
||||||
|
@ -1204,6 +1440,7 @@ STBTT_DEF int stbtt_GetGlyphBox(const stbtt_fontinfo *info, int glyph_index, int
|
||||||
if (y0) *y0 = ttSHORT(info->data + g + 4);
|
if (y0) *y0 = ttSHORT(info->data + g + 4);
|
||||||
if (x1) *x1 = ttSHORT(info->data + g + 6);
|
if (x1) *x1 = ttSHORT(info->data + g + 6);
|
||||||
if (y1) *y1 = ttSHORT(info->data + g + 8);
|
if (y1) *y1 = ttSHORT(info->data + g + 8);
|
||||||
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1215,7 +1452,10 @@ STBTT_DEF int stbtt_GetCodepointBox(const stbtt_fontinfo *info, int codepoint, i
|
||||||
STBTT_DEF int stbtt_IsGlyphEmpty(const stbtt_fontinfo *info, int glyph_index)
|
STBTT_DEF int stbtt_IsGlyphEmpty(const stbtt_fontinfo *info, int glyph_index)
|
||||||
{
|
{
|
||||||
stbtt_int16 numberOfContours;
|
stbtt_int16 numberOfContours;
|
||||||
int g = stbtt__GetGlyfOffset(info, glyph_index);
|
int g;
|
||||||
|
if (info->cff.size)
|
||||||
|
return stbtt__GetGlyphInfoT2(info, glyph_index, NULL, NULL, NULL, NULL) == 0;
|
||||||
|
g = stbtt__GetGlyfOffset(info, glyph_index);
|
||||||
if (g < 0) return 1;
|
if (g < 0) return 1;
|
||||||
numberOfContours = ttSHORT(info->data + g);
|
numberOfContours = ttSHORT(info->data + g);
|
||||||
return numberOfContours == 0;
|
return numberOfContours == 0;
|
||||||
|
@ -1237,7 +1477,7 @@ static int stbtt__close_shape(stbtt_vertex *vertices, int num_vertices, int was_
|
||||||
return num_vertices;
|
return num_vertices;
|
||||||
}
|
}
|
||||||
|
|
||||||
STBTT_DEF int stbtt_GetGlyphShape(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **pvertices)
|
static int stbtt__GetGlyphShapeTT(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **pvertices)
|
||||||
{
|
{
|
||||||
stbtt_int16 numberOfContours;
|
stbtt_int16 numberOfContours;
|
||||||
stbtt_uint8 *endPtsOfContours;
|
stbtt_uint8 *endPtsOfContours;
|
||||||
|
@ -1463,6 +1703,416 @@ STBTT_DEF int stbtt_GetGlyphShape(const stbtt_fontinfo *info, int glyph_index, s
|
||||||
return num_vertices;
|
return num_vertices;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
int bounds;
|
||||||
|
int started;
|
||||||
|
float first_x, first_y;
|
||||||
|
float x, y;
|
||||||
|
stbtt_int32 min_x, max_x, min_y, max_y;
|
||||||
|
|
||||||
|
stbtt_vertex *pvertices;
|
||||||
|
int num_vertices;
|
||||||
|
} stbtt__csctx;
|
||||||
|
|
||||||
|
#define STBTT__CSCTX_INIT(bounds) {bounds,0, 0,0, 0,0, 0,0,0,0, NULL, 0}
|
||||||
|
|
||||||
|
static void stbtt__track_vertex(stbtt__csctx *c, stbtt_int32 x, stbtt_int32 y)
|
||||||
|
{
|
||||||
|
if (x > c->max_x || !c->started) c->max_x = x;
|
||||||
|
if (y > c->max_y || !c->started) c->max_y = y;
|
||||||
|
if (x < c->min_x || !c->started) c->min_x = x;
|
||||||
|
if (y < c->min_y || !c->started) c->min_y = y;
|
||||||
|
c->started = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void stbtt__cstx_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)
|
||||||
|
{
|
||||||
|
if (c->bounds) {
|
||||||
|
stbtt__track_vertex(c, x, y);
|
||||||
|
if (type == STBTT_vcubic) {
|
||||||
|
stbtt__track_vertex(c, cx, cy);
|
||||||
|
stbtt__track_vertex(c, cx1, cy1);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
stbtt_setvertex(&c->pvertices[c->num_vertices], type, x, y, cx, cy);
|
||||||
|
c->pvertices[c->num_vertices].cx1 = (stbtt_int16) cx1;
|
||||||
|
c->pvertices[c->num_vertices].cy1 = (stbtt_int16) cy1;
|
||||||
|
}
|
||||||
|
c->num_vertices++;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void stbtt__csctx_close_shape(stbtt__csctx *ctx)
|
||||||
|
{
|
||||||
|
if (ctx->first_x != ctx->x || ctx->first_y != ctx->y)
|
||||||
|
stbtt__cstx_v(ctx, STBTT_vline, (int)ctx->first_x, (int)ctx->first_y, 0, 0, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void stbtt__csctx_rmove_to(stbtt__csctx *ctx, float dx, float dy)
|
||||||
|
{
|
||||||
|
stbtt__csctx_close_shape(ctx);
|
||||||
|
ctx->first_x = ctx->x = ctx->x + dx;
|
||||||
|
ctx->first_y = ctx->y = ctx->y + dy;
|
||||||
|
stbtt__cstx_v(ctx, STBTT_vmove, (int)ctx->x, (int)ctx->y, 0, 0, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void stbtt__csctx_rline_to(stbtt__csctx *ctx, float dx, float dy)
|
||||||
|
{
|
||||||
|
ctx->x += dx;
|
||||||
|
ctx->y += dy;
|
||||||
|
stbtt__cstx_v(ctx, STBTT_vline, (int)ctx->x, (int)ctx->y, 0, 0, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void stbtt__csctx_rccurve_to(stbtt__csctx *ctx, float dx1, float dy1, float dx2, float dy2, float dx3, float dy3)
|
||||||
|
{
|
||||||
|
float cx1 = ctx->x + dx1;
|
||||||
|
float cy1 = ctx->y + dy1;
|
||||||
|
float cx2 = cx1 + dx2;
|
||||||
|
float cy2 = cy1 + dy2;
|
||||||
|
ctx->x = cx2 + dx3;
|
||||||
|
ctx->y = cy2 + dy3;
|
||||||
|
stbtt__cstx_v(ctx, STBTT_vcubic, (int)ctx->x, (int)ctx->y, (int)cx1, (int)cy1, (int)cx2, (int)cy2);
|
||||||
|
}
|
||||||
|
|
||||||
|
static stbtt__buf stbtt__get_subr(stbtt__buf idx, int n)
|
||||||
|
{
|
||||||
|
int count = stbtt__cff_index_count(&idx);
|
||||||
|
int bias = 107;
|
||||||
|
if (count >= 33900)
|
||||||
|
bias = 32768;
|
||||||
|
else if (count >= 1240)
|
||||||
|
bias = 1131;
|
||||||
|
n += bias;
|
||||||
|
if (n < 0 || n >= count)
|
||||||
|
return stbtt__new_buf(NULL, 0);
|
||||||
|
return stbtt__cff_index_get(idx, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
static stbtt__buf stbtt__cid_get_glyph_subrs(const stbtt_fontinfo *info, int glyph_index)
|
||||||
|
{
|
||||||
|
stbtt__buf fdselect = info->fdselect;
|
||||||
|
int nranges, start, end, v, fmt, fdselector = -1, i;
|
||||||
|
|
||||||
|
stbtt__buf_seek(&fdselect, 0);
|
||||||
|
fmt = stbtt__buf_get8(&fdselect);
|
||||||
|
if (fmt == 0) {
|
||||||
|
// untested
|
||||||
|
stbtt__buf_skip(&fdselect, glyph_index);
|
||||||
|
fdselector = stbtt__buf_get8(&fdselect);
|
||||||
|
} else if (fmt == 3) {
|
||||||
|
nranges = stbtt__buf_get16(&fdselect);
|
||||||
|
start = stbtt__buf_get16(&fdselect);
|
||||||
|
for (i = 0; i < nranges; i++) {
|
||||||
|
v = stbtt__buf_get8(&fdselect);
|
||||||
|
end = stbtt__buf_get16(&fdselect);
|
||||||
|
if (glyph_index >= start && glyph_index < end) {
|
||||||
|
fdselector = v;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
start = end;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (fdselector == -1) stbtt__new_buf(NULL, 0);
|
||||||
|
return stbtt__get_subrs(info->cff, stbtt__cff_index_get(info->fontdicts, fdselector));
|
||||||
|
}
|
||||||
|
|
||||||
|
static int stbtt__run_charstring(const stbtt_fontinfo *info, int glyph_index, stbtt__csctx *c)
|
||||||
|
{
|
||||||
|
int in_header = 1, maskbits = 0, subr_stack_height = 0, sp = 0, v, i, b0;
|
||||||
|
int has_subrs = 0, clear_stack;
|
||||||
|
float s[48];
|
||||||
|
stbtt__buf subr_stack[10], subrs = info->subrs, b;
|
||||||
|
float f;
|
||||||
|
|
||||||
|
#define STBTT__CSERR(s) (0)
|
||||||
|
|
||||||
|
// this currently ignores the initial width value, which isn't needed if we have hmtx
|
||||||
|
b = stbtt__cff_index_get(info->charstrings, glyph_index);
|
||||||
|
while (b.cursor < b.size) {
|
||||||
|
i = 0;
|
||||||
|
clear_stack = 1;
|
||||||
|
b0 = stbtt__buf_get8(&b);
|
||||||
|
switch (b0) {
|
||||||
|
// @TODO implement hinting
|
||||||
|
case 0x13: // hintmask
|
||||||
|
case 0x14: // cntrmask
|
||||||
|
if (in_header)
|
||||||
|
maskbits += (sp / 2); // implicit "vstem"
|
||||||
|
in_header = 0;
|
||||||
|
stbtt__buf_skip(&b, (maskbits + 7) / 8);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x01: // hstem
|
||||||
|
case 0x03: // vstem
|
||||||
|
case 0x12: // hstemhm
|
||||||
|
case 0x17: // vstemhm
|
||||||
|
maskbits += (sp / 2);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x15: // rmoveto
|
||||||
|
in_header = 0;
|
||||||
|
if (sp < 2) return STBTT__CSERR("rmoveto stack");
|
||||||
|
stbtt__csctx_rmove_to(c, s[sp-2], s[sp-1]);
|
||||||
|
break;
|
||||||
|
case 0x04: // vmoveto
|
||||||
|
in_header = 0;
|
||||||
|
if (sp < 1) return STBTT__CSERR("vmoveto stack");
|
||||||
|
stbtt__csctx_rmove_to(c, 0, s[sp-1]);
|
||||||
|
break;
|
||||||
|
case 0x16: // hmoveto
|
||||||
|
in_header = 0;
|
||||||
|
if (sp < 1) return STBTT__CSERR("hmoveto stack");
|
||||||
|
stbtt__csctx_rmove_to(c, s[sp-1], 0);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x05: // rlineto
|
||||||
|
if (sp < 2) return STBTT__CSERR("rlineto stack");
|
||||||
|
for (; i + 1 < sp; i += 2)
|
||||||
|
stbtt__csctx_rline_to(c, s[i], s[i+1]);
|
||||||
|
break;
|
||||||
|
|
||||||
|
// hlineto/vlineto and vhcurveto/hvcurveto alternate horizontal and vertical
|
||||||
|
// starting from a different place.
|
||||||
|
|
||||||
|
case 0x07: // vlineto
|
||||||
|
if (sp < 1) return STBTT__CSERR("vlineto stack");
|
||||||
|
goto vlineto;
|
||||||
|
case 0x06: // hlineto
|
||||||
|
if (sp < 1) return STBTT__CSERR("hlineto stack");
|
||||||
|
for (;;) {
|
||||||
|
if (i >= sp) break;
|
||||||
|
stbtt__csctx_rline_to(c, s[i], 0);
|
||||||
|
i++;
|
||||||
|
vlineto:
|
||||||
|
if (i >= sp) break;
|
||||||
|
stbtt__csctx_rline_to(c, 0, s[i]);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x1F: // hvcurveto
|
||||||
|
if (sp < 4) return STBTT__CSERR("hvcurveto stack");
|
||||||
|
goto hvcurveto;
|
||||||
|
case 0x1E: // vhcurveto
|
||||||
|
if (sp < 4) return STBTT__CSERR("vhcurveto stack");
|
||||||
|
for (;;) {
|
||||||
|
if (i + 3 >= sp) break;
|
||||||
|
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);
|
||||||
|
i += 4;
|
||||||
|
hvcurveto:
|
||||||
|
if (i + 3 >= sp) break;
|
||||||
|
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]);
|
||||||
|
i += 4;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x08: // rrcurveto
|
||||||
|
if (sp < 6) return STBTT__CSERR("rcurveline stack");
|
||||||
|
for (; i + 5 < sp; i += 6)
|
||||||
|
stbtt__csctx_rccurve_to(c, s[i], s[i+1], s[i+2], s[i+3], s[i+4], s[i+5]);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x18: // rcurveline
|
||||||
|
if (sp < 8) return STBTT__CSERR("rcurveline stack");
|
||||||
|
for (; i + 5 < sp - 2; i += 6)
|
||||||
|
stbtt__csctx_rccurve_to(c, s[i], s[i+1], s[i+2], s[i+3], s[i+4], s[i+5]);
|
||||||
|
if (i + 1 >= sp) return STBTT__CSERR("rcurveline stack");
|
||||||
|
stbtt__csctx_rline_to(c, s[i], s[i+1]);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x19: // rlinecurve
|
||||||
|
if (sp < 8) return STBTT__CSERR("rlinecurve stack");
|
||||||
|
for (; i + 1 < sp - 6; i += 2)
|
||||||
|
stbtt__csctx_rline_to(c, s[i], s[i+1]);
|
||||||
|
if (i + 5 >= sp) return STBTT__CSERR("rlinecurve stack");
|
||||||
|
stbtt__csctx_rccurve_to(c, s[i], s[i+1], s[i+2], s[i+3], s[i+4], s[i+5]);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x1A: // vvcurveto
|
||||||
|
case 0x1B: // hhcurveto
|
||||||
|
if (sp < 4) return STBTT__CSERR("(vv|hh)curveto stack");
|
||||||
|
f = 0.0;
|
||||||
|
if (sp & 1) { f = s[i]; i++; }
|
||||||
|
for (; i + 3 < sp; i += 4) {
|
||||||
|
if (b0 == 0x1B)
|
||||||
|
stbtt__csctx_rccurve_to(c, s[i], f, s[i+1], s[i+2], s[i+3], 0.0);
|
||||||
|
else
|
||||||
|
stbtt__csctx_rccurve_to(c, f, s[i], s[i+1], s[i+2], 0.0, s[i+3]);
|
||||||
|
f = 0.0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x0A: // callsubr
|
||||||
|
if (!has_subrs) {
|
||||||
|
if (info->fdselect.size)
|
||||||
|
subrs = stbtt__cid_get_glyph_subrs(info, glyph_index);
|
||||||
|
has_subrs = 1;
|
||||||
|
}
|
||||||
|
// fallthrough
|
||||||
|
case 0x1D: // callgsubr
|
||||||
|
if (sp < 1) return STBTT__CSERR("call(g|)subr stack");
|
||||||
|
v = (int) s[--sp];
|
||||||
|
if (subr_stack_height >= 10) return STBTT__CSERR("recursion limit");
|
||||||
|
subr_stack[subr_stack_height++] = b;
|
||||||
|
b = stbtt__get_subr(b0 == 0x0A ? subrs : info->gsubrs, v);
|
||||||
|
if (b.size == 0) return STBTT__CSERR("subr not found");
|
||||||
|
b.cursor = 0;
|
||||||
|
clear_stack = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x0B: // return
|
||||||
|
if (subr_stack_height <= 0) return STBTT__CSERR("return outside subr");
|
||||||
|
b = subr_stack[--subr_stack_height];
|
||||||
|
clear_stack = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x0E: // endchar
|
||||||
|
stbtt__csctx_close_shape(c);
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
case 0x0C: { // two-byte escape
|
||||||
|
float dx1, dx2, dx3, dx4, dx5, dx6, dy1, dy2, dy3, dy4, dy5, dy6;
|
||||||
|
float dx, dy;
|
||||||
|
int b1 = stbtt__buf_get8(&b);
|
||||||
|
switch (b1) {
|
||||||
|
// @TODO These "flex" implementations ignore the flex-depth and resolution,
|
||||||
|
// and always draw beziers.
|
||||||
|
case 0x22: // hflex
|
||||||
|
if (sp < 7) return STBTT__CSERR("hflex stack");
|
||||||
|
dx1 = s[0];
|
||||||
|
dx2 = s[1];
|
||||||
|
dy2 = s[2];
|
||||||
|
dx3 = s[3];
|
||||||
|
dx4 = s[4];
|
||||||
|
dx5 = s[5];
|
||||||
|
dx6 = s[6];
|
||||||
|
stbtt__csctx_rccurve_to(c, dx1, 0, dx2, dy2, dx3, 0);
|
||||||
|
stbtt__csctx_rccurve_to(c, dx4, 0, dx5, -dy2, dx6, 0);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x23: // flex
|
||||||
|
if (sp < 13) return STBTT__CSERR("flex stack");
|
||||||
|
dx1 = s[0];
|
||||||
|
dy1 = s[1];
|
||||||
|
dx2 = s[2];
|
||||||
|
dy2 = s[3];
|
||||||
|
dx3 = s[4];
|
||||||
|
dy3 = s[5];
|
||||||
|
dx4 = s[6];
|
||||||
|
dy4 = s[7];
|
||||||
|
dx5 = s[8];
|
||||||
|
dy5 = s[9];
|
||||||
|
dx6 = s[10];
|
||||||
|
dy6 = s[11];
|
||||||
|
//fd is s[12]
|
||||||
|
stbtt__csctx_rccurve_to(c, dx1, dy1, dx2, dy2, dx3, dy3);
|
||||||
|
stbtt__csctx_rccurve_to(c, dx4, dy4, dx5, dy5, dx6, dy6);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x24: // hflex1
|
||||||
|
if (sp < 9) return STBTT__CSERR("hflex1 stack");
|
||||||
|
dx1 = s[0];
|
||||||
|
dy1 = s[1];
|
||||||
|
dx2 = s[2];
|
||||||
|
dy2 = s[3];
|
||||||
|
dx3 = s[4];
|
||||||
|
dx4 = s[5];
|
||||||
|
dx5 = s[6];
|
||||||
|
dy5 = s[7];
|
||||||
|
dx6 = s[8];
|
||||||
|
stbtt__csctx_rccurve_to(c, dx1, dy1, dx2, dy2, dx3, 0);
|
||||||
|
stbtt__csctx_rccurve_to(c, dx4, 0, dx5, dy5, dx6, -(dy1+dy2+dy5));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x25: // flex1
|
||||||
|
if (sp < 11) return STBTT__CSERR("flex1 stack");
|
||||||
|
dx1 = s[0];
|
||||||
|
dy1 = s[1];
|
||||||
|
dx2 = s[2];
|
||||||
|
dy2 = s[3];
|
||||||
|
dx3 = s[4];
|
||||||
|
dy3 = s[5];
|
||||||
|
dx4 = s[6];
|
||||||
|
dy4 = s[7];
|
||||||
|
dx5 = s[8];
|
||||||
|
dy5 = s[9];
|
||||||
|
dx6 = dy6 = s[10];
|
||||||
|
dx = dx1+dx2+dx3+dx4+dx5;
|
||||||
|
dy = dy1+dy2+dy3+dy4+dy5;
|
||||||
|
if (STBTT_fabs(dx) > STBTT_fabs(dy))
|
||||||
|
dy6 = -dy;
|
||||||
|
else
|
||||||
|
dx6 = -dx;
|
||||||
|
stbtt__csctx_rccurve_to(c, dx1, dy1, dx2, dy2, dx3, dy3);
|
||||||
|
stbtt__csctx_rccurve_to(c, dx4, dy4, dx5, dy5, dx6, dy6);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return STBTT__CSERR("unimplemented");
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
if (b0 != 255 && b0 != 28 && (b0 < 32 || b0 > 254))
|
||||||
|
return STBTT__CSERR("reserved operator");
|
||||||
|
|
||||||
|
// push immediate
|
||||||
|
if (b0 == 255) {
|
||||||
|
f = (float)stbtt__buf_get32(&b) / 0x10000;
|
||||||
|
} else {
|
||||||
|
stbtt__buf_skip(&b, -1);
|
||||||
|
f = (float)(stbtt_int16)stbtt__cff_int(&b);
|
||||||
|
}
|
||||||
|
if (sp >= 48) return STBTT__CSERR("push stack overflow");
|
||||||
|
s[sp++] = f;
|
||||||
|
clear_stack = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (clear_stack) sp = 0;
|
||||||
|
}
|
||||||
|
return STBTT__CSERR("no endchar");
|
||||||
|
|
||||||
|
#undef STBTT__CSERR
|
||||||
|
}
|
||||||
|
|
||||||
|
static int stbtt__GetGlyphShapeT2(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **pvertices)
|
||||||
|
{
|
||||||
|
// runs the charstring twice, once to count and once to output (to avoid realloc)
|
||||||
|
stbtt__csctx count_ctx = STBTT__CSCTX_INIT(1);
|
||||||
|
stbtt__csctx output_ctx = STBTT__CSCTX_INIT(0);
|
||||||
|
if (stbtt__run_charstring(info, glyph_index, &count_ctx)) {
|
||||||
|
*pvertices = (stbtt_vertex*)STBTT_malloc(count_ctx.num_vertices*sizeof(stbtt_vertex), info->userdata);
|
||||||
|
output_ctx.pvertices = *pvertices;
|
||||||
|
if (stbtt__run_charstring(info, glyph_index, &output_ctx)) {
|
||||||
|
STBTT_assert(output_ctx.num_vertices == count_ctx.num_vertices);
|
||||||
|
return output_ctx.num_vertices;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*pvertices = NULL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int stbtt__GetGlyphInfoT2(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1)
|
||||||
|
{
|
||||||
|
stbtt__csctx c = STBTT__CSCTX_INIT(1);
|
||||||
|
int r = stbtt__run_charstring(info, glyph_index, &c);
|
||||||
|
if (x0) {
|
||||||
|
*x0 = r ? c.min_x : 0;
|
||||||
|
*y0 = r ? c.min_y : 0;
|
||||||
|
*x1 = r ? c.max_x : 0;
|
||||||
|
*y1 = r ? c.max_y : 0;
|
||||||
|
}
|
||||||
|
return r ? c.num_vertices : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
STBTT_DEF int stbtt_GetGlyphShape(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **pvertices)
|
||||||
|
{
|
||||||
|
if (!info->cff.size)
|
||||||
|
return stbtt__GetGlyphShapeTT(info, glyph_index, pvertices);
|
||||||
|
else
|
||||||
|
return stbtt__GetGlyphShapeT2(info, glyph_index, pvertices);
|
||||||
|
}
|
||||||
|
|
||||||
STBTT_DEF void stbtt_GetGlyphHMetrics(const stbtt_fontinfo *info, int glyph_index, int *advanceWidth, int *leftSideBearing)
|
STBTT_DEF void stbtt_GetGlyphHMetrics(const stbtt_fontinfo *info, int glyph_index, int *advanceWidth, int *leftSideBearing)
|
||||||
{
|
{
|
||||||
stbtt_uint16 numOfLongHorMetrics = ttUSHORT(info->data+info->hhea + 34);
|
stbtt_uint16 numOfLongHorMetrics = ttUSHORT(info->data+info->hhea + 34);
|
||||||
|
@ -2333,6 +2983,48 @@ static int stbtt__tesselate_curve(stbtt__point *points, int *num_points, float x
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
// @TODO this "flatness" calculation is just made-up nonsense that seems to work well enough
|
||||||
|
float dx0 = x1-x0;
|
||||||
|
float dy0 = y1-y0;
|
||||||
|
float dx1 = x2-x1;
|
||||||
|
float dy1 = y2-y1;
|
||||||
|
float dx2 = x3-x2;
|
||||||
|
float dy2 = y3-y2;
|
||||||
|
float dx = x3-x0;
|
||||||
|
float dy = y3-y0;
|
||||||
|
float longlen = (float) (STBTT_sqrt(dx0*dx0+dy0*dy0)+STBTT_sqrt(dx1*dx1+dy1*dy1)+STBTT_sqrt(dx2*dx2+dy2*dy2));
|
||||||
|
float shortlen = (float) STBTT_sqrt(dx*dx+dy*dy);
|
||||||
|
float flatness_squared = longlen*longlen-shortlen*shortlen;
|
||||||
|
|
||||||
|
if (n > 16) // 65536 segments on one curve better be enough!
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (flatness_squared > objspace_flatness_squared) {
|
||||||
|
float x01 = (x0+x1)/2;
|
||||||
|
float y01 = (y0+y1)/2;
|
||||||
|
float x12 = (x1+x2)/2;
|
||||||
|
float y12 = (y1+y2)/2;
|
||||||
|
float x23 = (x2+x3)/2;
|
||||||
|
float y23 = (y2+y3)/2;
|
||||||
|
|
||||||
|
float xa = (x01+x12)/2;
|
||||||
|
float ya = (y01+y12)/2;
|
||||||
|
float xb = (x12+x23)/2;
|
||||||
|
float yb = (y12+y23)/2;
|
||||||
|
|
||||||
|
float mx = (xa+xb)/2;
|
||||||
|
float my = (ya+yb)/2;
|
||||||
|
|
||||||
|
stbtt__tesselate_cubic(points, num_points, x0,y0, x01,y01, xa,ya, mx,my, objspace_flatness_squared,n+1);
|
||||||
|
stbtt__tesselate_cubic(points, num_points, mx,my, xb,yb, x23,y23, x3,y3, objspace_flatness_squared,n+1);
|
||||||
|
} else {
|
||||||
|
stbtt__add_point(points, *num_points,x3,y3);
|
||||||
|
*num_points = *num_points+1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// returns number of contours
|
// returns number of contours
|
||||||
static stbtt__point *stbtt_FlattenCurves(stbtt_vertex *vertices, int num_verts, float objspace_flatness, int **contour_lengths, int *num_contours, void *userdata)
|
static stbtt__point *stbtt_FlattenCurves(stbtt_vertex *vertices, int num_verts, float objspace_flatness, int **contour_lengths, int *num_contours, void *userdata)
|
||||||
{
|
{
|
||||||
|
@ -2389,6 +3081,14 @@ static stbtt__point *stbtt_FlattenCurves(stbtt_vertex *vertices, int num_verts,
|
||||||
objspace_flatness_squared, 0);
|
objspace_flatness_squared, 0);
|
||||||
x = vertices[i].x, y = vertices[i].y;
|
x = vertices[i].x, y = vertices[i].y;
|
||||||
break;
|
break;
|
||||||
|
case STBTT_vcubic:
|
||||||
|
stbtt__tesselate_cubic(points, &num_points, x,y,
|
||||||
|
vertices[i].cx, vertices[i].cy,
|
||||||
|
vertices[i].cx1, vertices[i].cy1,
|
||||||
|
vertices[i].x, vertices[i].y,
|
||||||
|
objspace_flatness_squared, 0);
|
||||||
|
x = vertices[i].x, y = vertices[i].y;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(*contour_lengths)[n] = num_points - start;
|
(*contour_lengths)[n] = num_points - start;
|
||||||
|
|
Loading…
Reference in New Issue