bwip-js
Version:
JavaScript barcode generator supporting over 100 types and standards.
1,467 lines (1,338 loc) • 64.8 kB
JavaScript
// bwip-js/stb_trutype.js
//
// JavaScript implementation of stb_truetype.h @ https://github.com/nothings/stb.
//
// This file is part of the bwip-js project available at:
//
// http://metafloor.github.io/bwip-js
//
// Copyright (c) 2019 Mark Warren : MIT LICENSE
// Copyright notice from stb_truetype.h:
//
// MIT License
//
// Copyright (c) 2017 Sean Barrett
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
// of the Software, and to permit persons to whom the Software is furnished to do
// so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
var STBTT = (function () {
var STBTT_vmove = 1,
STBTT_vline = 2,
STBTT_vcurve = 3,
STBTT_vcubic = 4,
STBTT_PLATFORM_ID_UNICODE = 0,
STBTT_PLATFORM_ID_MAC = 1,
STBTT_PLATFORM_ID_ISO = 2,
STBTT_PLATFORM_ID_MICROSOFT = 3,
STBTT_UNICODE_EID_UNICODE_1_0 = 0,
STBTT_UNICODE_EID_UNICODE_1_1 = 1,
STBTT_UNICODE_EID_ISO_10646 = 2,
STBTT_UNICODE_EID_UNICODE_2_0_BMP = 3,
STBTT_UNICODE_EID_UNICODE_2_0_FULL = 4,
STBTT_MS_EID_SYMBOL = 0,
STBTT_MS_EID_UNICODE_BMP = 1,
STBTT_MS_EID_SHIFTJIS = 2,
STBTT_MS_EID_UNICODE_FULL = 10;
var floor = Math.floor;
var ceil = Math.ceil;
var sqrt = Math.sqrt;
var abs = Math.abs;
// Allocate an array of objects - replaces malloc(sizeof struct * n)
function oalloc(n) {
var o = [];
for (var i = 0; i < n; i++) {
o.push({});
}
return o;
}
//static unsigned char stbtt__buf_get8(stbtt__buf * b)
function stbtt__buf_get8(b) {
return b[b.cursor++]||0;
}
//static unsigned char stbtt__buf_peek8(stbtt__buf * b)
function stbtt__buf_peek8(b) {
return b[b.cursor];
}
//static void stbtt__buf_seek(stbtt__buf * b, int o)
function stbtt__buf_seek(b, o) {
b.cursor = (o > b.length || o < 0) ? b.length : o;
}
//static void stbtt__buf_skip(stbtt__buf * b, int o)
function stbtt__buf_skip(b, o) {
stbtt__buf_seek(b, b.cursor + o);
}
//static unsigned int stbtt__buf_get(stbtt__buf * b, int n)
function stbtt__buf_get(b, n) {
var v = 0;
for (var i = 0; i < n; i++) {
v = (v << 8) | stbtt__buf_get8(b);
}
return v;
}
// This function is only called once with a real 'p', all other uses are
// for a NULL buffer. The for real usage, the code is inlined.
//static stbtt__buf stbtt__new_buf(const void *p, int size)
function stbtt__null_buf() {
return { length:0 };
}
//static stbtt__buf stbtt__buf_range(const stbtt__buf * b, int o, int s)
function stbtt__buf_range(b, o, s) {
if (o < 0 || s < 0 || o > b.length || s > b.length - o) {
return stbtt__null_buf();
}
var r = b.subarray(o, o + s);
r.cursor = 0;
return r;
}
//static stbtt__buf stbtt__cff_get_index(stbtt__buf * b)
function stbtt__cff_get_index(b) {
var start = b.cursor;
var count = stbtt__buf_get(b, 2);
if (count) {
var offsize = stbtt__buf_get8(b);
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 unsigned int stbtt__cff_int(stbtt__buf * b)
function stbtt__cff_int(b) {
var 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_get(b, 2);
} else if (b0 == 29) {
return stbtt__buf_get(b, 4);
}
return 0;
}
//static void stbtt__cff_skip_operand(stbtt__buf * b)
function stbtt__cff_skip_operand(b) {
var b0 = stbtt__buf_peek8(b);
if (b0 == 30) {
stbtt__buf_skip(b, 1);
while (b.cursor < b.length) {
var 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)
function stbtt__dict_get(b, key) {
stbtt__buf_seek(b, 0);
while (b.cursor < b.length) {
var 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, unsigned int *out)
function stbtt__dict_get_ints(b, key, outcount, out) {
var operands = stbtt__dict_get(b, key);
for (var i = 0; i < outcount && operands.cursor < operands.length; i++) {
out[i] = stbtt__cff_int(operands);
}
}
// single-integer format of above since javascript doesn't have address-of
function stbtt__dict_get_int(b, key, out) {
var operands = stbtt__dict_get(b, key);
if (operands.cursor < operands.length) {
out = stbtt__cff_int(operands);
}
return out;
}
//static int stbtt__cff_index_count(stbtt__buf * b)
function stbtt__cff_index_count(b) {
stbtt__buf_seek(b, 0);
return stbtt__buf_get(b, 2);
}
//static stbtt__buf stbtt__cff_index_get(stbtt__buf b, int i)
function stbtt__cff_index_get(b, i) {
var count, offsize, start, end;
stbtt__buf_seek(b, 0);
count = stbtt__buf_get(b, 2);
offsize = stbtt__buf_get8(b);
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);
}
// Convert sign-extend a 16-bit integer to JS number
function INT16(n) {
return n & 0x8000 ? (0xffff0000|n)>>0 : n;
}
//static unsigned short ttUSHORT(unsigned char *p)
function ttUSHORT(b, o) {
return b[o] * 256 + b[o+1];
}
//static short ttSHORT(unsigned char *p)
function ttSHORT(b, o) {
var n = b[o] * 256 + b[o+1];
return n & 0x8000 ? (0xffff0000|n)>>0 : n;
}
//static unsigned int ttULONG(unsigned char *p)
function ttULONG(b, o) {
return (b[o] << 24) + (b[o+1] << 16) + (b[o+2] << 8) + b[o+3];
}
//static unsigned int stbtt__find_table(unsigned char *data, unsigned int fontstart, const char *tag)
function stbtt__find_table(data, fontstart, tag) {
var num_tables = ttUSHORT(data, fontstart + 4);
var tabledir = fontstart + 12;
for (var i = 0; i < num_tables; ++i) {
var loc = tabledir + 16 * i;
if (data[loc] == tag[0] && data[loc+1] == tag[1] && data[loc+2] == tag[2] && data[loc+3] == tag[3]) {
return ttULONG(data, loc + 8);
}
}
return 0;
}
//static stbtt__buf stbtt__get_subrs(stbtt__buf cff, stbtt__buf fontdict)
function stbtt__get_subrs(cff, fontdict) {
var private_loc = [ 0, 0 ];
stbtt__dict_get_ints(fontdict, 18, 2, private_loc);
if (!private_loc[1] || !private_loc[0]) {
return stbtt__null_buf();
}
var pdict = stbtt__buf_range(cff, private_loc[1], private_loc[0]);
var subrsoff = stbtt__dict_get_int(pdict, 19, 0);
if (!subrsoff) {
return stbtt__null_buf();
}
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)
function stbtt_InitFont_internal(info, data, fontstart) {
var cmap, t, i, numTables;
info.data = data;
info.fontstart = fontstart;
info.cff = stbtt__null_buf();
cmap = stbtt__find_table(data, fontstart, [ 99, 109, 97, 112 ]); //"cmap"
info.loca = stbtt__find_table(data, fontstart, [ 108, 111, 99, 97 ]); //"loca"
info.head = stbtt__find_table(data, fontstart, [ 104, 101, 97, 100 ]); //"head"
info.glyf = stbtt__find_table(data, fontstart, [ 103, 108, 121, 102 ]); //"glyf"
info.hhea = stbtt__find_table(data, fontstart, [ 104, 104, 101, 97 ]); //"hhea"
info.hmtx = stbtt__find_table(data, fontstart, [ 104, 109, 116, 120 ]); //"hmtx"
info.kern = stbtt__find_table(data, fontstart, [ 107, 101, 114, 110 ]); //"kern"
if (!cmap || !info.head || !info.hhea || !info.hmtx) {
return 0;
}
if (info.glyf) {
if (!info.loca) {
return 0;
}
} else {
var b, topdict, topdictidx, cff,
cstype = 2, charstrings = 0, fdarrayoff = 0, fdselectoff = 0;
cff = stbtt__find_table(data, fontstart, [ 67, 70, 70, 32 ]); //"CFF "
if (!cff) {
return 0;
}
info.fontdicts = stbtt__null_buf();
info.fdselect = stbtt__null_buf();
info.cff = data.subarray(cff); //stbtt__new_buf(data + cff, 512 * 1024 * 1024);
info.cff.cursor = 0;
b = info.cff;
stbtt__buf_skip(b, 2);
stbtt__buf_seek(b, stbtt__buf_get8(b));
stbtt__cff_get_index(b);
topdictidx = stbtt__cff_get_index(b);
topdict = stbtt__cff_index_get(topdictidx, 0);
stbtt__cff_get_index(b);
info.gsubrs = stbtt__cff_get_index(b);
charstrings = stbtt__dict_get_int(topdict, 17, charstrings);
cstype = stbtt__dict_get_int(topdict, 0x100 | 6, cstype);
fdarrayoff = stbtt__dict_get_int(topdict, 0x100 | 36, fdarrayoff);
fdselectoff = stbtt__dict_get_int(topdict, 0x100 | 37, fdselectoff);
info.subrs = stbtt__get_subrs(b, topdict);
if (cstype != 2) {
return 0;
}
if (charstrings == 0) {
return 0;
}
if (fdarrayoff) {
if (!fdselectoff) {
return 0;
}
stbtt__buf_seek(b, fdarrayoff);
info.fontdicts = stbtt__cff_get_index(b);
info.fdselect = stbtt__buf_range(b, fdselectoff, b.length - fdselectoff);
}
stbtt__buf_seek(b, charstrings);
info.charstrings = stbtt__cff_get_index(b);
}
t = stbtt__find_table(data, fontstart, [ 109, 97, 120, 112 ]); //"maxp"
if (t) {
info.numGlyphs = ttUSHORT(data, t + 4);
}
else {
info.numGlyphs = 0xffff;
}
numTables = ttUSHORT(data, cmap + 2);
info.index_map = 0;
for (i = 0; i < numTables; ++i) {
var encoding_record = cmap + 4 + 8 * i;
switch (ttUSHORT(data, encoding_record)) {
case STBTT_PLATFORM_ID_MICROSOFT:
switch (ttUSHORT(data, encoding_record + 2)) {
case STBTT_MS_EID_UNICODE_BMP:
case STBTT_MS_EID_UNICODE_FULL:
info.index_map = cmap + ttULONG(data, encoding_record + 4);
break;
}
break;
case STBTT_PLATFORM_ID_UNICODE:
info.index_map = cmap + ttULONG(data, encoding_record + 4);
break;
}
}
if (info.index_map == 0) {
return 0;
}
info.indexToLocFormat = ttUSHORT(data, info.head + 50);
return 1;
}
//extern int stbtt_FindGlyphIndex(const stbtt_fontinfo * info, int unicode_codepoint)
function stbtt_FindGlyphIndex(info, unicode_codepoint) {
var data = info.data, index_map = info.index_map;
var format = ttUSHORT(data, index_map + 0);
if (format == 0) {
var bytes = ttUSHORT(data, index_map + 2);
if (unicode_codepoint < bytes - 6) {
return data[index_map + 6 + unicode_codepoint];
}
return 0;
} else if (format == 6) {
var first = ttUSHORT(data, index_map + 6),
count = ttUSHORT(data, index_map + 8);
if (unicode_codepoint >= first && unicode_codepoint < first + count) {
return ttUSHORT(data, index_map + 10 + (unicode_codepoint - first) * 2);
}
return 0;
} else if (format == 2) {
return 0;
} else if (format == 4) {
var segcount = ttUSHORT(data, index_map + 6) >> 1,
searchRange = ttUSHORT(data, index_map + 8) >> 1,
entrySelector = ttUSHORT(data, index_map + 10),
rangeShift = ttUSHORT(data, index_map + 12) >> 1,
endCount = index_map + 14,
search = endCount;
if (unicode_codepoint > 0xffff) {
return 0;
}
if (unicode_codepoint >= ttUSHORT(data, search + rangeShift * 2)) {
search += rangeShift * 2;
}
search -= 2;
while (entrySelector) {
searchRange >>= 1;
var end = ttUSHORT(data, search + searchRange * 2);
if (unicode_codepoint > end) {
search += searchRange * 2;
}
--entrySelector;
}
search += 2;
var offset, start, item = (search - endCount) >>> 1;
start = ttUSHORT(data, index_map + 14 + segcount * 2 + 2 + 2 * item);
if (unicode_codepoint < start) {
return 0;
}
offset = ttUSHORT(data, index_map + 14 + segcount * 6 + 2 + 2 * item);
if (offset == 0) {
return unicode_codepoint + ttSHORT(data, index_map + 14 + segcount * 4 + 2 + 2 * item);
}
return ttUSHORT(data, offset + (unicode_codepoint - start) * 2 +
index_map + 14 + segcount * 6 + 2 + 2 * item);
} else if (format == 12 || format == 13) {
var ngroups = ttULONG(data, index_map + 12),
low = 0, high = ngroups;
while (low < high) {
var mid = low + ((high - low) >> 1);
var start_char = ttULONG(data, index_map + 16 + mid * 12);
var end_char = ttULONG(data, index_map + 16 + mid * 12 + 4);
if (unicode_codepoint < start_char) {
high = mid;
} else if (unicode_codepoint > end_char) {
low = mid + 1;
} else {
var start_glyph = ttULONG(data, index_map + 16 + mid * 12 + 8);
if (format == 12) {
return start_glyph + unicode_codepoint - start_char;
} else {
return start_glyph;
}
}
}
return 0;
}
return 0;
}
//static void stbtt_setvertex(stbtt_vertex * v, unsigned char type, int x, int y, int cx, int cy)
function stbtt_setvertex(v, type, x, y, cx, cy) {
v.type = type;
v.x = x;
v.y = y;
v.cx = cx;
v.cy = cy;
}
//static int stbtt__GetGlyfOffset(const stbtt_fontinfo * info, int glyph_index)
function stbtt__GetGlyfOffset(info, glyph_index) {
var g1, g2;
if (glyph_index >= info.numGlyphs) {
return -1;
}
if (info.indexToLocFormat >= 2) {
return -1;
}
if (info.indexToLocFormat == 0) {
g1 = info.glyf + ttUSHORT(info.data, info.loca + glyph_index * 2) * 2;
g2 = info.glyf + ttUSHORT(info.data, info.loca + glyph_index * 2 + 2) * 2;
} else {
g1 = info.glyf + ttULONG(info.data, info.loca + glyph_index * 4);
g2 = info.glyf + ttULONG(info.data, info.loca + glyph_index * 4 + 4);
}
return g1 == g2 ? -1 : g1;
}
//extern int stbtt_GetGlyphBox(const stbtt_fontinfo * info, int glyph_index, int *x0, int *y0, int *x1, int *y1)
function stbtt_GetGlyphBox(info, glyph_index, out) {
if (info.cff.length) {
stbtt__GetGlyphInfoT2(info, glyph_index, out);
} else {
var g = stbtt__GetGlyfOffset(info, glyph_index);
if (g < 0) {
return 0;
}
out.x0 = ttSHORT(info.data, g + 2);
out.y0 = ttSHORT(info.data, g + 4);
out.x1 = ttSHORT(info.data, g + 6);
out.y1 = ttSHORT(info.data, g + 8);
}
return 1;
}
//static int stbtt__close_shape(stbtt_vertex * vertices, int num_vertices, int was_off,
// int start_off, int sx, int sy, int scx, int scy, int cx, int cy)
function stbtt__close_shape(vertices, num_vertices, was_off, start_off, sx, sy, scx, scy, cx, cy) {
if (start_off) {
if (was_off) {
stbtt_setvertex(vertices[num_vertices++], STBTT_vcurve,
(cx + scx) >> 1, (cy + scy) >> 1, cx, cy);
}
stbtt_setvertex(vertices[num_vertices++], STBTT_vcurve, sx, sy, scx, scy);
} else {
if (was_off) {
stbtt_setvertex(vertices[num_vertices++], STBTT_vcurve, sx, sy, cx, cy);
} else {
stbtt_setvertex(vertices[num_vertices++], STBTT_vline, sx, sy, 0, 0);
}
}
return num_vertices;
}
//static int stbtt__GetGlyphShapeTT(const stbtt_fontinfo * info, int glyph_index, stbtt_vertex ** pvertices)
function stbtt__GetGlyphShapeTT(info, glyph_index) {
var data = info.data,
g = stbtt__GetGlyfOffset(info, glyph_index);
if (g < 0) {
return null;
}
var vertices = [];
var numberOfContours = ttSHORT(data, g);
if (numberOfContours > 0) {
var flags = 0, flagcount,
i, j = 0, m, n, next_move, was_off = 0, off, start_off = 0,
x, y, cx, cy, sx, sy, scx, scy;
var endPtsOfContours = g + 10;
var ins = ttUSHORT(data, g + 10 + numberOfContours * 2);
var points = data.subarray(g + 10 + numberOfContours * 2 + 2 + ins);
var ptsoff = 0;
n = 1 + ttUSHORT(data, endPtsOfContours + numberOfContours * 2 - 2);
m = n + 2 * numberOfContours;
vertices = oalloc(m);
next_move = 0;
flagcount = 0;
off = m - n;
for (i = 0; i < n; ++i) {
if (flagcount == 0) {
flags = points[ptsoff++];
if (flags & 8) {
flagcount = points[ptsoff++];
}
} else {
--flagcount;
}
vertices[off + i].type = flags;
}
x = 0;
for (i = 0; i < n; ++i) {
flags = vertices[off + i].type;
if (flags & 2) {
var dx = points[ptsoff++];
x += (flags & 16) ? dx : -dx;
} else {
if (!(flags & 16)) {
x = x + INT16(points[ptsoff] * 256 + points[ptsoff+1]);
ptsoff += 2;
}
}
vertices[off + i].x = x;
}
y = 0;
for (i = 0; i < n; ++i) {
flags = vertices[off + i].type;
if (flags & 4) {
var dy = points[ptsoff++];
y += (flags & 32) ? dy : -dy;
} else {
if (!(flags & 32)) {
y = y + INT16(points[ptsoff] * 256 + points[ptsoff+1]);
ptsoff += 2;
}
}
vertices[off + i].y = y;
}
var num_vertices = 0;
sx = sy = cx = cy = scx = scy = 0;
for (i = 0; i < n; ++i) {
flags = vertices[off + i].type;
x = vertices[off + i].x;
y = vertices[off + i].y;
if (next_move == i) {
if (i != 0) {
num_vertices = stbtt__close_shape(vertices, num_vertices, was_off, start_off,
sx, sy, scx, scy, cx, cy);
}
start_off = !(flags & 1);
if (start_off) {
scx = x;
scy = y;
if (!(vertices[off + i + 1].type & 1)) {
sx = (x + vertices[off + i + 1].x) >> 1;
sy = (y + vertices[off + i + 1].y) >> 1;
} else {
sx = vertices[off + i + 1].x;
sy = vertices[off + i + 1].y;
++i;
}
} else {
sx = x;
sy = y;
}
stbtt_setvertex(vertices[num_vertices++], STBTT_vmove, sx, sy, 0, 0);
was_off = 0;
next_move = 1 + ttUSHORT(data, endPtsOfContours + j * 2);
++j;
} else {
if (!(flags & 1)) {
if (was_off) {
stbtt_setvertex(vertices[num_vertices++], STBTT_vcurve,
(cx + x) >> 1, (cy + y) >> 1, cx, cy);
}
cx = x;
cy = y;
was_off = 1;
} else {
if (was_off) {
stbtt_setvertex(vertices[num_vertices++], STBTT_vcurve, x, y, cx, cy);
} else {
stbtt_setvertex(vertices[num_vertices++], STBTT_vline, x, y, 0, 0);
}
was_off = 0;
}
}
}
vertices.length = stbtt__close_shape(vertices, num_vertices, was_off, start_off,
sx, sy, scx, scy, cx, cy);
} else if (numberOfContours == -1) {
var more = 1;
var comp = g + 10;
while (more) {
var flags, gidx, mtx = [ 1, 0, 0, 1, 0, 0 ];
flags = ttSHORT(data, comp);
comp += 2;
gidx = ttSHORT(data, comp);
comp += 2;
if (flags & 2) {
if (flags & 1) {
mtx[4] = ttSHORT(data, comp);
comp += 2;
mtx[5] = ttSHORT(data, comp);
comp += 2;
} else {
mtx[4] = stbtt__buf_get8(data, comp);
comp += 1;
mtx[5] = stbtt__buf_get8(data, comp);
comp += 1;
}
}
if (flags & (1 << 3)) {
mtx[0] = mtx[3] = ttSHORT(data, comp) / 16384.0;
comp += 2;
mtx[1] = mtx[2] = 0;
} else if (flags & (1 << 6)) {
mtx[0] = ttSHORT(data, comp) / 16384.0;
comp += 2;
mtx[1] = mtx[2] = 0;
mtx[3] = ttSHORT(data, comp) / 16384.0;
comp += 2;
} else if (flags & (1 << 7)) {
mtx[0] = ttSHORT(data, comp) / 16384.0;
comp += 2;
mtx[1] = ttSHORT(data, comp) / 16384.0;
comp += 2;
mtx[2] = ttSHORT(data, comp) / 16384.0;
comp += 2;
mtx[3] = ttSHORT(data, comp) / 16384.0;
comp += 2;
}
var m = sqrt(mtx[0] * mtx[0] + mtx[1] * mtx[1]);
var n = sqrt(mtx[2] * mtx[2] + mtx[3] * mtx[3]);
var comp_verts = stbtt_GetGlyphShape(info, gidx);
if (comp_verts.length > 0) {
for (var i = 0, l = comp_verts.length; i < l; ++i) {
var v = comp_verts[i], x, y;
x = v.x;
y = v.y;
v.x = floor(m * (mtx[0] * x + mtx[2] * y + mtx[4]));
v.y = floor(n * (mtx[1] * x + mtx[3] * y + mtx[5]));
x = v.cx;
y = v.cy;
v.cx = floor(m * (mtx[0] * x + mtx[2] * y + mtx[4]));
v.cy = floor(n * (mtx[1] * x + mtx[3] * y + mtx[5]));
}
vertices = vertices.concat(comp_verts);
}
more = flags & (1 << 5);
}
}
//console.log('vertices(' + vertices.length + ')');
//for (var i = 0; i < vertices.length; i++) {
// var pt = vertices[i];
// console.log(`${i}: ${pt.x},${pt.y} / ${pt.cx},${pt.cy} / ${pt.type}`);
//}
return vertices;
}
//static void stbtt__track_vertex(stbtt__csctx * c, int x, int y)
function stbtt__track_vertex(c, x, 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__csctx_v(stbtt__csctx * c, unsigned char type, int x, int y, int cx, int cy, int cx1, int cy1)
function stbtt__csctx_v(c, type, x, y, cx, cy, cx1, cy1) {
stbtt__track_vertex(c, x, y);
if (type == STBTT_vcubic) {
stbtt__track_vertex(c, cx, cy);
stbtt__track_vertex(c, cx1, cy1);
}
var v = {};
stbtt_setvertex(v, type, x, y, cx, cy);
v.cx1 = cx1;
v.cy1 = cy1;
c.vertices.push(v);
}
//static void stbtt__csctx_close_shape(stbtt__csctx * ctx)
function stbtt__csctx_close_shape(ctx) {
if (ctx.first_x != ctx.x || ctx.first_y != ctx.y) {
stbtt__csctx_v(ctx, STBTT_vline, ctx.first_x, ctx.first_y, 0, 0, 0, 0);
}
}
//static void stbtt__csctx_rmove_to(stbtt__csctx * ctx, float dx, float dy)
function stbtt__csctx_rmove_to(ctx, dx, dy) {
stbtt__csctx_close_shape(ctx);
ctx.first_x = ctx.x = ctx.x + dx;
ctx.first_y = ctx.y = ctx.y + dy;
stbtt__csctx_v(ctx, STBTT_vmove, ctx.x, ctx.y, 0, 0, 0, 0);
}
//static void stbtt__csctx_rline_to(stbtt__csctx * ctx, float dx, float dy)
function stbtt__csctx_rline_to(ctx, dx, dy) {
ctx.x += dx;
ctx.y += dy;
stbtt__csctx_v(ctx, STBTT_vline, ctx.x, 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)
function stbtt__csctx_rccurve_to(ctx, dx1, dy1, dx2, dy2, dx3, dy3) {
var cx1 = ctx.x + dx1,
cy1 = ctx.y + dy1,
cx2 = cx1 + dx2,
cy2 = cy1 + dy2;
ctx.x = cx2 + dx3;
ctx.y = cy2 + dy3;
stbtt__csctx_v(ctx, STBTT_vcubic, ctx.x, ctx.y, cx1, cy1, cx2, cy2);
}
//static stbtt__buf stbtt__get_subr(stbtt__buf idx, int n)
function stbtt__get_subr(b, n) {
var count = stbtt__cff_index_count(b);
var bias = 107;
if (count >= 33900) {
bias = 32768;
} else if (count >= 1240) {
bias = 1131;
}
n += bias;
if (n < 0 || n >= count) {
return stbtt__null_buf();
}
return stbtt__cff_index_get(b, n);
}
//static stbtt__buf stbtt__cid_get_glyph_subrs(const stbtt_fontinfo * info, int glyph_index)
function stbtt__cid_get_glyph_subrs(info, glyph_index) {
var fdselect = info.fdselect;
var nranges, start, end, v, fmt, fdselector = -1, i;
stbtt__buf_seek(fdselect, 0);
fmt = stbtt__buf_get8(fdselect);
if (fmt == 0) {
stbtt__buf_skip(fdselect, glyph_index);
fdselector = stbtt__buf_get8(fdselect);
} else if (fmt == 3) {
nranges = stbtt__buf_get(fdselect, 2);
start = stbtt__buf_get(fdselect, 2);
for (i = 0; i < nranges; i++) {
v = stbtt__buf_get8(fdselect);
end = stbtt__buf_get(fdselect, 2);
if (glyph_index >= start && glyph_index < end) {
fdselector = v;
break;
}
start = end;
}
}
if (fdselector == -1) {
stbtt__null_buf();
}
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)
function stbtt__run_charstring(info, glyph_index, c) {
var in_header = 1, maskbits = 0, subr_stack_height = 0, sp = 0, v, i, b0,
has_subrs = 0, clear_stack,
s = [], subr_stack = [], subrs = info.subrs, b, f;
b = stbtt__cff_index_get(info.charstrings, glyph_index);
while (b.cursor < b.length) {
i = 0;
clear_stack = 1;
b0 = stbtt__buf_get8(b);
switch (b0) {
case 0x13:
case 0x14:
if (in_header) {
maskbits += (sp / 2)|0;
}
in_header = 0;
stbtt__buf_skip(b, ((maskbits + 7) / 8)|0);
break;
case 0x01:
case 0x03:
case 0x12:
case 0x17:
maskbits += (sp / 2)|0;
break;
case 0x15:
in_header = 0;
if (sp < 2) {
return 0;
}
stbtt__csctx_rmove_to(c, s[sp - 2], s[sp - 1]);
break;
case 0x04:
in_header = 0;
if (sp < 1) {
return 0;
}
stbtt__csctx_rmove_to(c, 0, s[sp - 1]);
break;
case 0x16:
in_header = 0;
if (sp < 1) {
return 0;
}
stbtt__csctx_rmove_to(c, s[sp - 1], 0);
break;
case 0x05:
if (sp < 2) {
return 0;
}
for (; i + 1 < sp; i += 2) {
stbtt__csctx_rline_to(c, s[i], s[i + 1]);
}
break;
case 0x07:
if (sp < 1) {
return 0;
}
for (;;) {
if (i >= sp) {
break;
}
stbtt__csctx_rline_to(c, 0, s[i]);
i++;
if (i >= sp) {
break;
}
stbtt__csctx_rline_to(c, s[i], 0);
i++;
}
break;
case 0x06:
if (sp < 1) {
return 0;
}
for (;;) {
if (i >= sp) {
break;
}
stbtt__csctx_rline_to(c, s[i], 0);
i++;
if (i >= sp) {
break;
}
stbtt__csctx_rline_to(c, 0, s[i]);
i++;
}
break;
case 0x1F:
if (sp < 4) {
return 0;
}
for (;;) {
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.0,
s[i + 3]);
i += 4;
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.0);
i += 4;
}
break;
case 0x1E:
if (sp < 4) {
return 0;
}
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.0);
i += 4;
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.0,
s[i + 3]);
i += 4;
}
break;
case 0x08:
if (sp < 6) {
return 0;
}
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:
if (sp < 8) {
return 0;
}
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 0;
}
stbtt__csctx_rline_to(c, s[i], s[i + 1]);
break;
case 0x19:
if (sp < 8) {
return 0;
}
for (; i + 1 < sp - 6; i += 2) {
stbtt__csctx_rline_to(c, s[i], s[i + 1]);
}
if (i + 5 >= sp) {
return 0;
}
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:
case 0x1B:
if (sp < 4) {
return 0;
}
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:
if (!has_subrs) {
if (info.fdselect.length) {
subrs = stbtt__cid_get_glyph_subrs(info, glyph_index);
}
has_subrs = 1;
}
case 0x1D:
if (sp < 1) {
return 0;
}
v = s[--sp]|0;
if (subr_stack_height >= 10) {
return 0;
}
subr_stack[subr_stack_height++] = b;
b = stbtt__get_subr(b0 == 0x0A ? subrs : info.gsubrs, v);
if (b.length == 0) {
return 0;
}
b.cursor = 0;
clear_stack = 0;
break;
case 0x0B:
if (subr_stack_height <= 0) {
return 0;
}
b = subr_stack[--subr_stack_height];
clear_stack = 0;
break;
case 0x0E:
stbtt__csctx_close_shape(c);
return 1;
case 0x0C:
var dx1, dx2, dx3, dx4, dx5, dx6, dy1, dy2, dy3, dy4, dy5, dy6,
dx, dy, b1 = stbtt__buf_get8(b);
switch (b1) {
case 0x22:
if (sp < 7) {
return 0;
}
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:
if (sp < 13) {
return 0;
}
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];
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:
if (sp < 9) {
return 0;
}
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:
if (sp < 11) {
return 0;
}
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 (abs(dx) > abs(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 0;
}
break;
default:
if (b0 != 255 && b0 != 28 && (b0 < 32 || b0 > 254)) {
return 0;
}
if (b0 == 255) {
// f = (float)(stbtt_int32)stbtt__buf_get32(&b) / 0x10000;
f = (stbtt__buf_get(b, 4)|0) / 0x10000;
} else {
stbtt__buf_skip(b, -1);
// f = (float)(stbtt_int16)stbtt__cff_int(&b);
f = ((stbtt__cff_int(b)<<16)|0)>>16;
}
if (sp >= 48) {
return 0;
}
s[sp++] = f;
clear_stack = 0;
break;
}
if (clear_stack) {
sp = 0;
}
}
return 0;
}
function stbtt__csctx_init() {
return { started:0, first_x:0, first_y:0, x:0, y:0,
min_x:0, max_x:0, min_y:0, max_y:0,
vertices:[]
};
}
//static int stbtt__GetGlyphShapeT2(const stbtt_fontinfo * info, int glyph_index,
// stbtt_vertex ** pvertices)
function stbtt__GetGlyphShapeT2(info, glyph_index) {
var output_ctx = stbtt__csctx_init();
if (stbtt__run_charstring(info, glyph_index, output_ctx)) {
return output_ctx.vertices;
}
return null;
}
//static int stbtt__GetGlyphInfoT2(const stbtt_fontinfo * info, int glyph_index, int *x0,
// int *y0, int *x1, int *y1)
function stbtt__GetGlyphInfoT2(info, glyph_index, out) {
var c = stbtt__csctx_init();
var r = stbtt__run_charstring(info, glyph_index, c);
out.x0 = r ? c.min_x : 0;
out.y0 = r ? c.min_y : 0;
out.x1 = r ? c.max_x : 0;
out.y1 = r ? c.max_y : 0;
return r && c.vertices ? c.vertices.length : 0;
}
//extern int stbtt_GetGlyphShape(const stbtt_fontinfo * info, int glyph_index,
// stbtt_vertex ** pvertices)
function stbtt_GetGlyphShape(info, glyph_index) {
if (!info.cff.length) {
return stbtt__GetGlyphShapeTT(info, glyph_index);
} else {
return stbtt__GetGlyphShapeT2(info, glyph_index);
}
}
//extern void stbtt_GetGlyphHMetrics(const stbtt_fontinfo * info, int glyph_index,
// int *advanceWidth, int *leftSideBearing)
function stbtt_GetGlyphHMetrics(info, glyph_index) {
var numOfLongHorMetrics = ttUSHORT(info.data, info.hhea + 34);
if (glyph_index < numOfLongHorMetrics) {
return {
advanceWidth: ttSHORT(info.data, info.hmtx + 4 * glyph_index),
leftSideBearing:ttSHORT(info.data, info.hmtx + 4 * glyph_index + 2)
};
} else {
return {
advanceWidth: ttSHORT(info.data, info.hmtx + 4 * (numOfLongHorMetrics - 1)),
leftSideBearing:ttSHORT(info.data, info.hmtx + 4 * numOfLongHorMetrics +
2 * (glyph_index - numOfLongHorMetrics))
};
}
}
//extern void stbtt_GetCodepointHMetrics(const stbtt_fontinfo * info, int codepoint,
// int *advanceWidth, int *leftSideBearing)
function stbtt_GetCodepointHMetrics(info, codepoint) {
return stbtt_GetGlyphHMetrics(info, stbtt_FindGlyphIndex(info, codepoint));
}
//extern void stbtt_GetFontVMetrics(const stbtt_fontinfo * info, int *ascent, int *descent, int *lineGap)
function stbtt_GetFontVMetrics(info) {
return {
ascent: ttSHORT(info.data, info.hhea + 4),
descent:ttSHORT(info.data, info.hhea + 6),
linegap:ttSHORT(info.data, info.hhea + 8),
};
}
//extern 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)
function stbtt_GetGlyphBitmapBoxSubpixel(font, glyph, scale_x, scale_y, shift_x, shift_y) {
var tmp = {};
if (!stbtt_GetGlyphBox(font, glyph, tmp)) {
return { x0:0, y0:0, x1:0, y1:0 };
}
return {
x0:floor(tmp.x0 * scale_x + shift_x),
y0:floor(-tmp.y1 * scale_y + shift_y),
x1:ceil(tmp.x1 * scale_x + shift_x),
y1:ceil(-tmp.y0 * scale_y + shift_y),
};
}
//extern 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)
function stbtt_GetCodepointBitmapBoxSubpixel(font, codepoint, scale_x, scale_y, shift_x, shift_y) {
return stbtt_GetGlyphBitmapBoxSubpixel(font, stbtt_FindGlyphIndex(font, codepoint),
scale_x, scale_y, shift_x, shift_y);
}
//extern void stbtt_GetCodepointBitmapBox(const stbtt_fontinfo * font, int codepoint, float scale_x, float scale_y,
// int *ix0, int *iy0, int *ix1, int *iy1)
function stbtt_GetCodepointBitmapBox(font, codepoint, scale_x, scale_y) {
return stbtt_GetCodepointBitmapBoxSubpixel(font, codepoint, scale_x, scale_y, 0, 0);
}
//static stbtt__active_edge *stbtt__new_active(stbtt__hheap * hh, stbtt__edge * e, int off_x, float start_point, void *userdata)
function stbtt__new_active(e, off_x, start_point) {
var dxdy = (e.x1 - e.x0) / (e.y1 - e.y0);
return {
fdx:dxdy,
fdy:dxdy != 0.0 ? (1.0 / dxdy) : 0.0,
fx:(e.x0 + dxdy * (start_point - e.y0)) - (off_x|0),
direction:e.invert ? 1.0 : -1.0,
sy:e.y0,
ey:e.y1,
next:0,
};
}
//static void stbtt__handle_clipped_edge(float *scanline, int x, stbtt__active_edge * e,
// float x0, float y0, float x1, float y1)
function stbtt__handle_clipped_edge(scanline, x, e, x0, y0, x1, y1) {
x = x|0;
if (y0 == y1) {
return;
}
if (y0 > e.ey) {
return;
}
if (y1 < e.sy) {
return;
}
if (y0 < e.sy) {
x0 += (x1 - x0) * (e.sy - y0) / (y1 - y0);
y0 = e.sy;
}
if (y1 > e.ey) {
x1 += (x1 - x0) * (e.ey - y1) / (y1 - y0);
y1 = e.ey;
}
if (x0 <= x && x1 <= x) {
scanline[x] += e.direction * (y1 - y0);
} else if (x0 >= x + 1 && x1 >= x + 1) {
} else {
scanline[x] += e.direction * (y1 - y0) * (1 - ((x0 - x) + (x1 - x)) / 2);
}
}
//static void stbtt__fill_active_edges_new(float *scanline, float *scanline_fill, int len,
// stbtt__active_edge * e, float y_top)
// The C implementation passed scanline_fill as a +1 pointer on the call, and then -1 in
// places in this function. That doesn't work with array-views, so we reverse the handling.
function stbtt__fill_active_edges_new(scanline, scanline_fill, len, e, y_top) {
var y_bottom = y_top + 1;
while (e) {
if (e.fdx == 0) {
var x0 = e.fx;
if (x0 < len) {
if (x0 >= 0) {
stbtt__handle_clipped_edge(scanline, x0, e, x0, y_top, x0, y_bottom);
stbtt__handle_clipped_edge(scanline_fill, x0+1, e, x0, y_top, x0, y_bottom);
} else {
stbtt__handle_clipped_edge(scanline_fill, 0, e, x0, y_top, x0, y_bottom);
}
}
} else {
var x0 = e.fx,
dx = e.fdx,
xb = x0 + dx,
x_top, x_bottom,
sy0, sy1,
dy = e.fdy;
if (e.sy > y_top) {
x_top = x0 + dx * (e.sy - y_top);
sy0 = e.sy;
} else {
x_top = x0;
sy0 = y_top;
}
if (e.ey < y_bottom) {
x_bottom = x0 + dx * (e.ey - y_top);
sy1 = e.ey;
} else {
x_bottom = xb;
sy1 = y_bottom;
}
if (x_top >= 0 && x_bottom >= 0 && x_top < len && x_bottom < len) {
if ((x_top|0) == (x_bottom|0)) {
var height = sy1 - sy0,
x = x_top|0;
scanline[x] += e.direction * (1 - ((x_top - x) + (x_bottom - x)) / 2) * height;
scanline_fill[x+1] += e.direction * height;
} else {
var t, x, x1, x2, y_crossing, step, sign, area;
if (x_top > x_bottom) {
sy0 = y_bottom - (sy0 - y_top);
sy1 = y_bottom - (sy1 - y_top);
t = sy0, sy0 = sy1, sy1 = t;
t = x_bottom, x_bottom = x_top, x_top = t;
dx = -dx;
dy = -dy;
t = x0, x0 = xb, xb = t;
}
x1 = x_top|0;
x2 = x_bottom|0;
y_crossing = (x1 + 1 - x0) * dy + y_top;
sign = e.direction;
area = sign * (y_crossing - sy0);
scanline[x1] += area * (1 - ((x_top - x1) + (x1 + 1 - x1)) / 2);
step = sign * dy;
for (x = x1 + 1; x < x2; ++x) {
scanline[x] += area + step / 2;
area += step;
}
y_crossing += dy * (x2 - (x1 + 1));
scanline[x2] += area + sign * (1 - ((x2 - x2) + (x_bottom - x2)) / 2) *
(sy1 - y_crossing);
scanline_fill[x2+1] += sign * (sy1 - sy0);
}
} else {
for (var x = 0; x < len; ++x) {
var y0 = y_top,
x1 = x,
x2 = x + 1,
x3 = xb,
y3 = y_bottom,
y1 = (x - x0) / dx + y_top,
y2 = (x + 1 - x0) / dx + y_top;
if (x0 < x1 && x3 > x2) {
stbtt__handle_clipped_edge(scanline, x, e, x0, y0, x1, y1);
stbtt__handle_clipped_edge(scanline, x, e, x1, y1, x2, y2);
stbtt__handle_clipped_edge(scanline, x, e, x2, y2, x3, y3);
} else if (x3 < x1 && x0 > x2) {
stbtt__handle_clipped_edge(scanline, x, e, x0, y0, x2, y2);
stbtt__handle_clipped_edge(scanline, x, e, x2, y2, x1, y1);
stbtt__handle_clipped_edge(scanline, x, e, x1, y1, x3, y3);
} else if (x0 < x1 && x3 > x1) {
stbtt__handle_clipped_edge(scanline, x, e, x0, y0, x1, y1);
stbtt__handle_clipped_edge(scanline, x, e, x1, y1, x3, y3);
} else if (x3 < x1 && x0 > x1) {
stbtt__handle_clipped_edge(scanline, x, e, x0, y0, x1, y1);
stbtt__handle_clipped_edge(scanline, x, e, x1, y1, x3, y3);
} else if (x0 < x2 && x3 > x2) {
stbtt__handle_clipped_edge(scanline, x, e, x0, y0, x2, y2);
stbtt__handle_clipped_edge(scanline, x, e, x2, y2, x3, y3);
} else if (x3 < x2 && x0 > x2) {
stbtt__handle_clipped_edge(scanline, x, e, x0, y0, x2, y2);
stbtt__handle_clipped_edge(scanline, x, e, x2, y2, x3, y3);
} else {
stbtt__handle_clipped_edge(scanline, x, e, x0, y0, x3, y3);
}
}
}
}
e = e.next;
}
}
//static void stbtt__rasterize_sorted_edges(stbtt__bitmap * result, stbtt__edge * e, int n,
// int vsubsample, int off_x, int off_y, void *userdata)
function stbtt__rasterize_sorted_edges(result, edges, nedges, vsubsample, off_x, off_y) {
vsubsample |= 0, off_x |= 0, off_y |= 0;
var active = null, z;
var y = off_y, j = 0, i;
var scanline = new Float32Array(result.w * 2 + 1);
var scanline2 = scanline.subarray(result.w);
var eoff = 0;
edges[nedges].y0 = off_y + result.h + 1;
while (j < result.h) {
var scan_y_top = y + 0.0,
scan_y_bottom = y + 1.0,
step = a