p5
Version:
[](https://www.npmjs.com/package/p5)
1,465 lines (1,250 loc) • 102 kB
JavaScript
import { inflate } from 'pako';
// Mocking the pako module to just have inflate for a smaller package size
const pako = { inflate };
var Typr = {};
Typr["parse"] = function (buff) {
var bin = Typr["B"];
var readFont = function (data, idx, offset, tmap) {
var T = Typr["T"];
var prsr = {
"cmap": T.cmap,
"head": T.head,
"hhea": T.hhea,
"maxp": T.maxp,
"hmtx": T.hmtx,
"name": T.name,
"OS/2": T.OS2,
"post": T.post,
"loca": T.loca,
"kern": T.kern,
"glyf": T.glyf,
"CFF ": T.CFF,
/*
"GPOS",
"GSUB",
"GDEF",*/
"GSUB": T.GSUB,
"CBLC": T.CBLC,
"CBDT": T.CBDT,
"SVG ": T.SVG,
"COLR": T.colr,
"CPAL": T.cpal,
"sbix": T.sbix,
"fvar": T.fvar,
"gvar": T.gvar,
"avar": T.avar,
"HVAR": T.HVAR
//"VORG",
};
var obj = { "_data": data, "_index": idx, "_offset": offset };
for (var t in prsr) {
var tab = Typr["findTable"](data, t, offset);
if (tab) {
var off = tab[0], tobj = tmap[off];
if (tobj == null) tobj = prsr[t].parseTab(data, off, tab[1], obj);
obj[t] = tmap[off] = tobj;
}
}
return obj;
};
function woffToOtf(data) {
var numTables = bin.readUshort(data, 12);
var totalSize = bin.readUint(data, 16);
var otf = new Uint8Array(totalSize), toff = 12 + numTables * 16;
bin.writeASCII(otf, 0, "OTTO");
bin.writeUshort(otf, 4, numTables);
var off = 44;
for (var i = 0; i < numTables; i++) {
var tag = bin.readASCII(data, off, 4);
var tof = bin.readUint(data, off + 4);
var cLe = bin.readUint(data, off + 8);
var oLe = bin.readUint(data, off + 12);
off += 20;
//console.log(i, ":::", tag,tof,oLe);
var tab = data.slice(tof, tof + cLe);
if (cLe != oLe) tab = pako["inflate"](tab);
var to = 12 + i * 16;
bin.writeASCII(otf, to, tag);
bin.writeUint(otf, to + 8, toff);
bin.writeUint(otf, to + 12, oLe);
otf.set(tab, toff); toff += oLe;
}
//console.log(otf);
return otf;
}
var data = new Uint8Array(buff);
// PATCHED: keep around the compressed data if we inflate it
let compressedData;
if (data[0] == 0x77) {
compressedData = data;
data = woffToOtf(data);
}
var tmap = {};
var tag = bin.readASCII(data, 0, 4);
if (tag == "ttcf") {
var offset = 4;
bin.readUshort(data, offset); offset += 2;
bin.readUshort(data, offset); offset += 2;
var numF = bin.readUint(data, offset); offset += 4;
var fnts = [];
for (var i = 0; i < numF; i++) {
var foff = bin.readUint(data, offset); offset += 4;
fnts.push(readFont(data, i, foff, tmap));
}
return fnts;
}
var fnt = readFont(data, 0, 0, tmap); //console.log(fnt); throw "e";
fnt._compressedData = compressedData; // PATCH: make compressed data accessible
var fvar = fnt["fvar"];
if (fvar) {
var out = [fnt];
for (var i = 0; i < fvar[1].length; i++) {
var fv = fvar[1][i];
var obj = {}; out.push(obj); for (var p in fnt) obj[p] = fnt[p];
obj["_index"] = i;
var name = obj["name"] = JSON.parse(JSON.stringify(obj["name"]));
name["fontSubfamily"] = fv[0];
if (fv[3] == null) fv[3] = (name["fontFamily"] + "-" + name["fontSubfamily"])["replaceAll"](" ", "");
name["postScriptName"] = fv[3];
}
return out;
}
return [fnt];
};
Typr["findTable"] = function (data, tab, foff) {
var bin = Typr["B"];
var numTables = bin.readUshort(data, foff + 4);
var offset = foff + 12;
for (var i = 0; i < numTables; i++) {
var tag = bin.readASCII(data, offset, 4); //console.log(tag);
bin.readUint(data, offset + 4);
var toffset = bin.readUint(data, offset + 8);
var length = bin.readUint(data, offset + 12);
if (tag == tab) return [toffset, length];
offset += 16;
}
return null;
};
/*
Typr["splitBy"] = function(data,tag) {
data = new Uint8Array(data); console.log(data.slice(0,64));
var bin = Typr["B"];
var ttcf = bin.readASCII(data, 0, 4); if(ttcf!="ttcf") return {};
var offset = 8;
var numF = bin.readUint (data, offset); offset+=4;
var colls = [], used={};
for(var i=0; i<numF; i++) {
var foff = bin.readUint (data, offset); offset+=4;
var toff = Typr["findTable"](data,tag,foff)[0];
if(used[toff]==null) used[toff] = [];
used[toff].push([foff,bin.readUshort(data,foff+4)]); // font offset, numTables
}
for(var toff in used) {
var offs = used[toff];
var hlen = 12+4*offs.length;
var out = new Uint8Array(hlen);
for(var i=0; i<8; i++) out[i]=data[i];
bin.writeUint(out,8,offs.length);
for(var i=0; i<offs.length; i++) hlen += 12+offs[i][1]*16;
var hdrs = [out], tabs = [], hoff=out.length, toff=hlen, noffs={};
for(var i=0; i<offs.length; i++) {
bin.writeUint(out, 12+i*4, hoff); hoff+=12+offs[i][1]*16;
toff = Typr["_cutFont"](data, offs[i][0], hdrs, tabs, toff, noffs);
}
colls.push(Typr["_joinArrs"](hdrs.concat(tabs)));
}
return colls;
}
Typr["splitFonts"] = function(data) {
data = new Uint8Array(data);
var bin = Typr["B"];
var ttcf = bin.readASCII(data, 0, 4); if(ttcf!="ttcf") return {};
var offset = 8;
var numF = bin.readUint (data, offset); offset+=4;
var fnts = [];
for(var i=0; i<numF; i++) {
var foff = bin.readUint (data, offset); offset+=4;
fnts.push(Typr._cutFont(data, foff));
break;
}
return fnts;
}
Typr["_cutFont"] = function(data,foff,hdrs,tabs,toff, noffs) {
var bin = Typr["B"];
var numTables = bin.readUshort(data, foff+4);
var out = new Uint8Array(12+numTables*16); hdrs.push(out);
for(var i=0; i<12; i++) out[i]=data[foff+i]; //console.log(out);
var off = 12;
for(var i=0; i<numTables; i++)
{
var tag = bin.readASCII(data, foff+off, 4);
var checkSum = bin.readUint (data, foff+off+ 4);
var toffset = bin.readUint (data, foff+off+ 8);
var length = bin.readUint (data, foff+off+12);
while((length&3)!=0) length++;
for(var j=0; j<16; j++) out[off+j]=data[foff+off+j];
if(noffs[toffset]!=null) bin.writeUint(out,off+8,noffs[toffset]);
else {
noffs[toffset] = toff;
bin.writeUint(out, off+8, toff);
tabs.push(new Uint8Array(data.buffer, toffset, length)); toff+=length;
}
off+=16;
}
return toff;
}
Typr["_joinArrs"] = function(tabs) {
var len = 0;
for(var i=0; i<tabs.length; i++) len+=tabs[i].length;
var out = new Uint8Array(len), ooff=0;
for(var i=0; i<tabs.length; i++) {
var tab = tabs[i];
for(var j=0; j<tab.length; j++) out[ooff+j]=tab[j];
ooff+=tab.length;
}
return out;
}
*/
Typr["T"] = {};
Typr["B"] = {
readFixed: function (data, o) {
return ((data[o] << 8) | data[o + 1]) + (((data[o + 2] << 8) | data[o + 3]) / (256 * 256 + 4));
},
readF2dot14: function (data, o) {
var num = Typr["B"].readShort(data, o);
return num / 16384;
},
readInt: function (buff, p) {
//if(p>=buff.length) throw "error";
var a = Typr["B"].t.uint8;
a[0] = buff[p + 3];
a[1] = buff[p + 2];
a[2] = buff[p + 1];
a[3] = buff[p];
return Typr["B"].t.int32[0];
},
readInt8: function (buff, p) {
//if(p>=buff.length) throw "error";
var a = Typr["B"].t.uint8;
a[0] = buff[p];
return Typr["B"].t.int8[0];
},
readShort: function (buff, p) {
//if(p>=buff.length) throw "error";
var a = Typr["B"].t.uint16;
a[0] = (buff[p] << 8) | buff[p + 1];
return Typr["B"].t.int16[0];
},
readUshort: function (buff, p) {
//if(p>=buff.length) throw "error";
return (buff[p] << 8) | buff[p + 1];
},
writeUshort: function (buff, p, n) {
buff[p] = (n >> 8) & 255; buff[p + 1] = n & 255;
},
readUshorts: function (buff, p, len) {
var arr = [];
for (var i = 0; i < len; i++) {
var v = Typr["B"].readUshort(buff, p + i * 2); //if(v==932) console.log(p+i*2);
arr.push(v);
}
return arr;
},
readUint: function (buff, p) {
//if(p>=buff.length) throw "error";
var a = Typr["B"].t.uint8;
a[3] = buff[p]; a[2] = buff[p + 1]; a[1] = buff[p + 2]; a[0] = buff[p + 3];
return Typr["B"].t.uint32[0];
},
writeUint: function (buff, p, n) {
buff[p] = (n >> 24) & 255; buff[p + 1] = (n >> 16) & 255; buff[p + 2] = (n >> 8) & 255; buff[p + 3] = (n >> 0) & 255;
},
readUint64: function (buff, p) {
//if(p>=buff.length) throw "error";
return (Typr["B"].readUint(buff, p) * (0xffffffff + 1)) + Typr["B"].readUint(buff, p + 4);
},
readASCII: function (buff, p, l) // l : length in Characters (not Bytes)
{
//if(p>=buff.length) throw "error";
var s = "";
for (var i = 0; i < l; i++) s += String.fromCharCode(buff[p + i]);
return s;
},
writeASCII: function (buff, p, s) // l : length in Characters (not Bytes)
{
for (var i = 0; i < s.length; i++)
buff[p + i] = s.charCodeAt(i);
},
readUnicode: function (buff, p, l) {
//if(p>=buff.length) throw "error";
var s = "";
for (var i = 0; i < l; i++) {
var c = (buff[p++] << 8) | buff[p++];
s += String.fromCharCode(c);
}
return s;
},
_tdec: window["TextDecoder"] ? new window["TextDecoder"]() : null,
readUTF8: function (buff, p, l) {
var tdec = Typr["B"]._tdec;
if (tdec && p == 0 && l == buff.length) return tdec["decode"](buff);
return Typr["B"].readASCII(buff, p, l);
},
readBytes: function (buff, p, l) {
//if(p>=buff.length) throw "error";
var arr = [];
for (var i = 0; i < l; i++) arr.push(buff[p + i]);
return arr;
},
readASCIIArray: function (buff, p, l) // l : length in Characters (not Bytes)
{
//if(p>=buff.length) throw "error";
var s = [];
for (var i = 0; i < l; i++)
s.push(String.fromCharCode(buff[p + i]));
return s;
},
t: function () {
var ab = new ArrayBuffer(8);
return {
buff: ab,
int8: new Int8Array(ab),
uint8: new Uint8Array(ab),
int16: new Int16Array(ab),
uint16: new Uint16Array(ab),
int32: new Int32Array(ab),
uint32: new Uint32Array(ab)
}
}()
};
Typr["T"].CFF = {
parseTab: function (data, offset, length) {
var bin = Typr["B"];
var CFF = Typr["T"].CFF;
data = new Uint8Array(data.buffer, offset, length);
offset = 0;
// Header
data[offset]; offset++;
data[offset]; offset++;
data[offset]; offset++;
data[offset]; offset++;
//console.log(major, minor, hdrSize, offsize);
// Name INDEX
var ninds = [];
offset = CFF.readIndex(data, offset, ninds);
var names = [];
for (var i = 0; i < ninds.length - 1; i++) names.push(bin.readASCII(data, offset + ninds[i], ninds[i + 1] - ninds[i]));
offset += ninds[ninds.length - 1];
// Top DICT INDEX
var tdinds = [];
offset = CFF.readIndex(data, offset, tdinds); //console.log(tdinds);
// Top DICT Data
var topDicts = [];
for (var i = 0; i < tdinds.length - 1; i++) topDicts.push(CFF.readDict(data, offset + tdinds[i], offset + tdinds[i + 1]));
offset += tdinds[tdinds.length - 1];
var topdict = topDicts[0];
//console.log(topdict);
// String INDEX
var sinds = [];
offset = CFF.readIndex(data, offset, sinds);
// String Data
var strings = [];
for (var i = 0; i < sinds.length - 1; i++) strings.push(bin.readASCII(data, offset + sinds[i], sinds[i + 1] - sinds[i]));
offset += sinds[sinds.length - 1];
// Global Subr INDEX (subroutines)
CFF.readSubrs(data, offset, topdict);
// charstrings
if (topdict["CharStrings"]) topdict["CharStrings"] = CFF.readBytes(data, topdict["CharStrings"]);
// CID font
if (topdict["ROS"]) {
offset = topdict["FDArray"];
var fdind = [];
offset = CFF.readIndex(data, offset, fdind);
topdict["FDArray"] = [];
for (var i = 0; i < fdind.length - 1; i++) {
var dict = CFF.readDict(data, offset + fdind[i], offset + fdind[i + 1]);
CFF._readFDict(data, dict, strings);
topdict["FDArray"].push(dict);
}
offset += fdind[fdind.length - 1];
offset = topdict["FDSelect"];
topdict["FDSelect"] = [];
var fmt = data[offset]; offset++;
if (fmt == 3) {
var rns = bin.readUshort(data, offset); offset += 2;
for (var i = 0; i < rns + 1; i++) {
topdict["FDSelect"].push(bin.readUshort(data, offset), data[offset + 2]); offset += 3;
}
}
else throw fmt;
}
// Encoding
//if(topdict["Encoding"]) topdict["Encoding"] = CFF.readEncoding(data, topdict["Encoding"], topdict["CharStrings"].length);
// charset
if (topdict["charset"]) topdict["charset"] = CFF.readCharset(data, topdict["charset"], topdict["CharStrings"].length);
CFF._readFDict(data, topdict, strings);
return topdict;
},
_readFDict: function (data, dict, ss) {
var CFF = Typr["T"].CFF;
var offset;
if (dict["Private"]) {
offset = dict["Private"][1];
dict["Private"] = CFF.readDict(data, offset, offset + dict["Private"][0]);
if (dict["Private"]["Subrs"]) CFF.readSubrs(data, offset + dict["Private"]["Subrs"], dict["Private"]);
}
for (var p in dict) if (["FamilyName", "FontName", "FullName", "Notice", "version", "Copyright"].indexOf(p) != -1) dict[p] = ss[dict[p] - 426 + 35];
},
readSubrs: function (data, offset, obj) {
obj["Subrs"] = Typr["T"].CFF.readBytes(data, offset);
var bias, nSubrs = obj["Subrs"].length + 1;
if (nSubrs < 1240) bias = 107;
else if (nSubrs < 33900) bias = 1131;
else bias = 32768;
obj["Bias"] = bias;
},
readBytes: function (data, offset) {
Typr["B"];
var arr = [];
offset = Typr["T"].CFF.readIndex(data, offset, arr);
var subrs = [], arl = arr.length - 1, no = data.byteOffset + offset;
for (var i = 0; i < arl; i++) {
var ari = arr[i];
subrs.push(new Uint8Array(data.buffer, no + ari, arr[i + 1] - ari));
}
return subrs;
},
tableSE: [
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
1, 2, 3, 4, 5, 6, 7, 8,
9, 10, 11, 12, 13, 14, 15, 16,
17, 18, 19, 20, 21, 22, 23, 24,
25, 26, 27, 28, 29, 30, 31, 32,
33, 34, 35, 36, 37, 38, 39, 40,
41, 42, 43, 44, 45, 46, 47, 48,
49, 50, 51, 52, 53, 54, 55, 56,
57, 58, 59, 60, 61, 62, 63, 64,
65, 66, 67, 68, 69, 70, 71, 72,
73, 74, 75, 76, 77, 78, 79, 80,
81, 82, 83, 84, 85, 86, 87, 88,
89, 90, 91, 92, 93, 94, 95, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 96, 97, 98, 99, 100, 101, 102,
103, 104, 105, 106, 107, 108, 109, 110,
0, 111, 112, 113, 114, 0, 115, 116,
117, 118, 119, 120, 121, 122, 0, 123,
0, 124, 125, 126, 127, 128, 129, 130,
131, 0, 132, 133, 0, 134, 135, 136,
137, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 138, 0, 139, 0, 0, 0, 0,
140, 141, 142, 143, 0, 0, 0, 0,
0, 144, 0, 0, 0, 145, 0, 0,
146, 147, 148, 149, 0, 0, 0, 0
],
glyphByUnicode: function (cff, code) {
for (var i = 0; i < cff["charset"].length; i++) if (cff["charset"][i] == code) return i;
return -1;
},
glyphBySE: function (cff, charcode) // glyph by standard encoding
{
if (charcode < 0 || charcode > 255) return -1;
return Typr["T"].CFF.glyphByUnicode(cff, Typr["T"].CFF.tableSE[charcode]);
},
/*readEncoding : function(data, offset, num)
{
var bin = Typr["B"];
var array = ['.notdef'];
var format = data[offset]; offset++;
//console.log("Encoding");
//console.log(format);
if(format==0)
{
var nCodes = data[offset]; offset++;
for(var i=0; i<nCodes; i++) array.push(data[offset+i]);
}
/*
else if(format==1 || format==2)
{
while(charset.length<num)
{
var first = bin.readUshort(data, offset); offset+=2;
var nLeft=0;
if(format==1) { nLeft = data[offset]; offset++; }
else { nLeft = bin.readUshort(data, offset); offset+=2; }
for(var i=0; i<=nLeft; i++) { charset.push(first); first++; }
}
}
else throw "error: unknown encoding format: " + format;
return array;
},*/
readCharset: function (data, offset, num) {
var bin = Typr["B"];
var charset = ['.notdef'];
var format = data[offset]; offset++;
if (format == 0) {
for (var i = 0; i < num; i++) {
var first = bin.readUshort(data, offset); offset += 2;
charset.push(first);
}
}
else if (format == 1 || format == 2) {
while (charset.length < num) {
var first = bin.readUshort(data, offset); offset += 2;
var nLeft = 0;
if (format == 1) { nLeft = data[offset]; offset++; }
else { nLeft = bin.readUshort(data, offset); offset += 2; }
for (var i = 0; i <= nLeft; i++) { charset.push(first); first++; }
}
}
else throw "error: format: " + format;
return charset;
},
readIndex: function (data, offset, inds) {
var bin = Typr["B"];
var count = bin.readUshort(data, offset) + 1; offset += 2;
var offsize = data[offset]; offset++;
if (offsize == 1) for (var i = 0; i < count; i++) inds.push(data[offset + i]);
else if (offsize == 2) for (var i = 0; i < count; i++) inds.push(bin.readUshort(data, offset + i * 2));
else if (offsize == 3) for (var i = 0; i < count; i++) inds.push(bin.readUint(data, offset + i * 3 - 1) & 0x00ffffff);
else if (offsize == 4) for (var i = 0; i < count; i++) inds.push(bin.readUint(data, offset + i * 4));
else if (count != 1) throw "unsupported offset size: " + offsize + ", count: " + count;
offset += count * offsize;
return offset - 1;
},
getCharString: function (data, offset, o) {
var bin = Typr["B"];
var b0 = data[offset], b1 = data[offset + 1]; data[offset + 2]; data[offset + 3]; data[offset + 4];
var vs = 1;
var op = null, val = null;
// operand
if (b0 <= 20) { op = b0; vs = 1; }
if (b0 == 12) { op = b0 * 100 + b1; vs = 2; }
//if(b0==19 || b0==20) { op = b0/*+" "+b1*/; vs=2; }
if (21 <= b0 && b0 <= 27) { op = b0; vs = 1; }
if (b0 == 28) { val = bin.readShort(data, offset + 1); vs = 3; }
if (29 <= b0 && b0 <= 31) { op = b0; vs = 1; }
if (32 <= b0 && b0 <= 246) { val = b0 - 139; vs = 1; }
if (247 <= b0 && b0 <= 250) { val = (b0 - 247) * 256 + b1 + 108; vs = 2; }
if (251 <= b0 && b0 <= 254) { val = -(b0 - 251) * 256 - b1 - 108; vs = 2; }
if (b0 == 255) { val = bin.readInt(data, offset + 1) / 0xffff; vs = 5; }
o.val = val != null ? val : "o" + op;
o.size = vs;
},
readCharString: function (data, offset, length) {
var end = offset + length;
var bin = Typr["B"];
var arr = [];
while (offset < end) {
var b0 = data[offset], b1 = data[offset + 1]; data[offset + 2]; data[offset + 3]; data[offset + 4];
var vs = 1;
var op = null, val = null;
// operand
if (b0 <= 20) { op = b0; vs = 1; }
if (b0 == 12) { op = b0 * 100 + b1; vs = 2; }
if (b0 == 19 || b0 == 20) { op = b0/*+" "+b1*/; vs = 2; }
if (21 <= b0 && b0 <= 27) { op = b0; vs = 1; }
if (b0 == 28) { val = bin.readShort(data, offset + 1); vs = 3; }
if (29 <= b0 && b0 <= 31) { op = b0; vs = 1; }
if (32 <= b0 && b0 <= 246) { val = b0 - 139; vs = 1; }
if (247 <= b0 && b0 <= 250) { val = (b0 - 247) * 256 + b1 + 108; vs = 2; }
if (251 <= b0 && b0 <= 254) { val = -(b0 - 251) * 256 - b1 - 108; vs = 2; }
if (b0 == 255) { val = bin.readInt(data, offset + 1) / 0xffff; vs = 5; }
arr.push(val != null ? val : "o" + op);
offset += vs;
//var cv = arr[arr.length-1];
//if(cv==undefined) throw "error";
//console.log()
}
return arr;
},
readDict: function (data, offset, end) {
var bin = Typr["B"];
//var dict = [];
var dict = {};
var carr = [];
while (offset < end) {
var b0 = data[offset], b1 = data[offset + 1]; data[offset + 2]; data[offset + 3]; data[offset + 4];
var vs = 1;
var key = null, val = null;
// operand
if (b0 == 28) { val = bin.readShort(data, offset + 1); vs = 3; }
if (b0 == 29) { val = bin.readInt(data, offset + 1); vs = 5; }
if (32 <= b0 && b0 <= 246) { val = b0 - 139; vs = 1; }
if (247 <= b0 && b0 <= 250) { val = (b0 - 247) * 256 + b1 + 108; vs = 2; }
if (251 <= b0 && b0 <= 254) { val = -(b0 - 251) * 256 - b1 - 108; vs = 2; }
if (b0 == 255) { val = bin.readInt(data, offset + 1) / 0xffff; vs = 5; throw "unknown number"; }
if (b0 == 30) {
var nibs = [];
vs = 1;
while (true) {
var b = data[offset + vs]; vs++;
var nib0 = b >> 4, nib1 = b & 0xf;
if (nib0 != 0xf) nibs.push(nib0); if (nib1 != 0xf) nibs.push(nib1);
if (nib1 == 0xf) break;
}
var s = "";
var chars = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, ".", "e", "e-", "reserved", "-", "endOfNumber"];
for (var i = 0; i < nibs.length; i++) s += chars[nibs[i]];
//console.log(nibs);
val = parseFloat(s);
}
if (b0 <= 21) // operator
{
var keys = ["version", "Notice", "FullName", "FamilyName", "Weight", "FontBBox", "BlueValues", "OtherBlues", "FamilyBlues", "FamilyOtherBlues",
"StdHW", "StdVW", "escape", "UniqueID", "XUID", "charset", "Encoding", "CharStrings", "Private", "Subrs",
"defaultWidthX", "nominalWidthX"];
key = keys[b0]; vs = 1;
if (b0 == 12) {
var keys = ["Copyright", "isFixedPitch", "ItalicAngle", "UnderlinePosition", "UnderlineThickness", "PaintType", "CharstringType", "FontMatrix", "StrokeWidth", "BlueScale",
"BlueShift", "BlueFuzz", "StemSnapH", "StemSnapV", "ForceBold", "", "", "LanguageGroup", "ExpansionFactor", "initialRandomSeed",
"SyntheticBase", "PostScript", "BaseFontName", "BaseFontBlend", "", "", "", "", "", "",
"ROS", "CIDFontVersion", "CIDFontRevision", "CIDFontType", "CIDCount", "UIDBase", "FDArray", "FDSelect", "FontName"];
key = keys[b1]; vs = 2;
}
}
if (key != null) { dict[key] = carr.length == 1 ? carr[0] : carr; carr = []; }
else carr.push(val);
offset += vs;
}
return dict;
}
};
Typr["T"].cmap = {
parseTab: function (data, offset, length) {
var obj = { tables: [], ids: {}, off: offset };
data = new Uint8Array(data.buffer, offset, length);
offset = 0;
var bin = Typr["B"], rU = bin.readUshort, cmap = Typr["T"].cmap;
rU(data, offset); offset += 2;
var numTables = rU(data, offset); offset += 2;
//console.log(version, numTables);
var offs = [];
for (var i = 0; i < numTables; i++) {
var platformID = rU(data, offset); offset += 2;
var encodingID = rU(data, offset); offset += 2;
var noffset = bin.readUint(data, offset); offset += 4;
var id = "p" + platformID + "e" + encodingID;
//console.log("cmap subtable", platformID, encodingID, noffset);
var tind = offs.indexOf(noffset);
if (tind == -1) {
tind = obj.tables.length;
var subt = {};
offs.push(noffset);
//var time = Date.now();
var format = subt.format = rU(data, noffset);
if (format == 0) subt = cmap.parse0(data, noffset, subt);
//else if(format== 2) subt.off = noffset;
else if (format == 4) subt = cmap.parse4(data, noffset, subt);
else if (format == 6) subt = cmap.parse6(data, noffset, subt);
else if (format == 12) subt = cmap.parse12(data, noffset, subt);
//console.log(format, Date.now()-time);
//else console.log("unknown format: "+format, platformID, encodingID, noffset);
obj.tables.push(subt);
}
if (obj.ids[id] != null) console.log("multiple tables for one platform+encoding: " + id);
obj.ids[id] = tind;
}
return obj;
},
parse0: function (data, offset, obj) {
var bin = Typr["B"];
offset += 2;
var len = bin.readUshort(data, offset); offset += 2;
bin.readUshort(data, offset); offset += 2;
obj.map = [];
for (var i = 0; i < len - 6; i++) obj.map.push(data[offset + i]);
return obj;
},
parse4: function (data, offset, obj) {
var bin = Typr["B"], rU = bin.readUshort, rUs = bin.readUshorts;
var offset0 = offset;
offset += 2;
var length = rU(data, offset); offset += 2;
rU(data, offset); offset += 2;
var segCountX2 = rU(data, offset); offset += 2;
var segCount = segCountX2 >>> 1;
obj.searchRange = rU(data, offset); offset += 2;
obj.entrySelector = rU(data, offset); offset += 2;
obj.rangeShift = rU(data, offset); offset += 2;
obj.endCount = rUs(data, offset, segCount); offset += segCount * 2;
offset += 2;
obj.startCount = rUs(data, offset, segCount); offset += segCount * 2;
obj.idDelta = [];
for (var i = 0; i < segCount; i++) { obj.idDelta.push(bin.readShort(data, offset)); offset += 2; }
obj.idRangeOffset = rUs(data, offset, segCount); offset += segCount * 2;
obj.glyphIdArray = rUs(data, offset, ((offset0 + length) - offset) >> 1); //offset += segCount*2;
return obj;
},
parse6: function (data, offset, obj) {
var bin = Typr["B"];
offset += 2;
bin.readUshort(data, offset); offset += 2;
bin.readUshort(data, offset); offset += 2;
obj.firstCode = bin.readUshort(data, offset); offset += 2;
var entryCount = bin.readUshort(data, offset); offset += 2;
obj.glyphIdArray = [];
for (var i = 0; i < entryCount; i++) { obj.glyphIdArray.push(bin.readUshort(data, offset)); offset += 2; }
return obj;
},
parse12: function (data, offset, obj) {
var bin = Typr["B"], rU = bin.readUint;
offset += 4;
rU(data, offset); offset += 4;
rU(data, offset); offset += 4;
var nGroups = rU(data, offset) * 3; offset += 4;
var gps = obj.groups = new Uint32Array(nGroups);//new Uint32Array(data.slice(offset, offset+nGroups*12).buffer);
for (var i = 0; i < nGroups; i += 3) {
gps[i] = rU(data, offset + (i << 2));
gps[i + 1] = rU(data, offset + (i << 2) + 4);
gps[i + 2] = rU(data, offset + (i << 2) + 8);
}
return obj;
}
};
Typr["T"].CBLC = {
parseTab: function (data, offset, length) {
var bin = Typr["B"], ooff = offset;
bin.readUshort(data, offset); offset += 2;
bin.readUshort(data, offset); offset += 2;
var numSizes = bin.readUint(data, offset); offset += 4;
var out = [];
for (var i = 0; i < numSizes; i++) {
var off = bin.readUint(data, offset); offset += 4; // indexSubTableArrayOffset
bin.readUint(data, offset); offset += 4; // indexTablesSize
bin.readUint(data, offset); offset += 4; // numberOfIndexSubTables
offset += 4;
offset += 2 * 12;
bin.readUshort(data, offset); offset += 2;
bin.readUshort(data, offset); offset += 2;
//console.log(off,siz,num, sGlyph, eGlyph);
offset += 4;
var coff = ooff + off;
for (var j = 0; j < 3; j++) {
var fgI = bin.readUshort(data, coff); coff += 2;
var lgI = bin.readUshort(data, coff); coff += 2;
var nxt = bin.readUint(data, coff); coff += 4;
var gcnt = lgI - fgI + 1;
//console.log(fgI, lgI, nxt); //if(nxt==0) break;
var ioff = ooff + off + nxt;
var inF = bin.readUshort(data, ioff); ioff += 2; if (inF != 1) throw inF;
var imF = bin.readUshort(data, ioff); ioff += 2;
var imgo = bin.readUint(data, ioff); ioff += 4;
var oarr = [];
for (var gi = 0; gi < gcnt; gi++) {
var sbitO = bin.readUint(data, ioff + gi * 4); oarr.push(imgo + sbitO);
//console.log("--",sbitO);
}
out.push([fgI, lgI, imF, oarr]);
}
}
return out;
}
};
Typr["T"].CBDT = {
parseTab: function (data, offset, length) {
Typr["B"];
//var maj = bin.readUshort(data,offset); offset+=2;
//var min = bin.readUshort(data,offset); offset+=2;
return new Uint8Array(data.buffer, data.byteOffset + offset, length);
}
};
Typr["T"].glyf = {
parseTab: function (data, offset, length, font) {
var obj = [], ng = font["maxp"]["numGlyphs"];
for (var g = 0; g < ng; g++) obj.push(null);
return obj;
},
_parseGlyf: function (font, g) {
var bin = Typr["B"];
var data = font["_data"], loca = font["loca"];
if (loca[g] == loca[g + 1]) return null;
var offset = Typr["findTable"](data, "glyf", font["_offset"])[0] + loca[g];
var gl = {};
gl.noc = bin.readShort(data, offset); offset += 2; // number of contours
gl.xMin = bin.readShort(data, offset); offset += 2;
gl.yMin = bin.readShort(data, offset); offset += 2;
gl.xMax = bin.readShort(data, offset); offset += 2;
gl.yMax = bin.readShort(data, offset); offset += 2;
if (gl.xMin >= gl.xMax || gl.yMin >= gl.yMax) return null;
if (gl.noc > 0) {
gl.endPts = [];
for (var i = 0; i < gl.noc; i++) { gl.endPts.push(bin.readUshort(data, offset)); offset += 2; }
var instructionLength = bin.readUshort(data, offset); offset += 2;
if ((data.length - offset) < instructionLength) return null;
gl.instructions = bin.readBytes(data, offset, instructionLength); offset += instructionLength;
var crdnum = gl.endPts[gl.noc - 1] + 1;
gl.flags = [];
for (var i = 0; i < crdnum; i++) {
var flag = data[offset]; offset++;
gl.flags.push(flag);
if ((flag & 8) != 0) {
var rep = data[offset]; offset++;
for (var j = 0; j < rep; j++) { gl.flags.push(flag); i++; }
}
}
gl.xs = [];
for (var i = 0; i < crdnum; i++) {
var i8 = ((gl.flags[i] & 2) != 0), same = ((gl.flags[i] & 16) != 0);
if (i8) { gl.xs.push(same ? data[offset] : -data[offset]); offset++; }
else {
if (same) gl.xs.push(0);
else { gl.xs.push(bin.readShort(data, offset)); offset += 2; }
}
}
gl.ys = [];
for (var i = 0; i < crdnum; i++) {
var i8 = ((gl.flags[i] & 4) != 0), same = ((gl.flags[i] & 32) != 0);
if (i8) { gl.ys.push(same ? data[offset] : -data[offset]); offset++; }
else {
if (same) gl.ys.push(0);
else { gl.ys.push(bin.readShort(data, offset)); offset += 2; }
}
}
var x = 0, y = 0;
for (var i = 0; i < crdnum; i++) { x += gl.xs[i]; y += gl.ys[i]; gl.xs[i] = x; gl.ys[i] = y; }
//console.log(endPtsOfContours, instructionLength, instructions, flags, xCoordinates, yCoordinates);
}
else {
var ARG_1_AND_2_ARE_WORDS = 1 << 0;
var ARGS_ARE_XY_VALUES = 1 << 1;
var WE_HAVE_A_SCALE = 1 << 3;
var MORE_COMPONENTS = 1 << 5;
var WE_HAVE_AN_X_AND_Y_SCALE = 1 << 6;
var WE_HAVE_A_TWO_BY_TWO = 1 << 7;
var WE_HAVE_INSTRUCTIONS = 1 << 8;
gl.parts = [];
var flags;
do {
flags = bin.readUshort(data, offset); offset += 2;
var part = { m: { a: 1, b: 0, c: 0, d: 1, tx: 0, ty: 0 }, p1: -1, p2: -1 }; gl.parts.push(part);
part.glyphIndex = bin.readUshort(data, offset); offset += 2;
if (flags & ARG_1_AND_2_ARE_WORDS) {
var arg1 = bin.readShort(data, offset); offset += 2;
var arg2 = bin.readShort(data, offset); offset += 2;
} else {
var arg1 = bin.readInt8(data, offset); offset++;
var arg2 = bin.readInt8(data, offset); offset++;
}
if (flags & ARGS_ARE_XY_VALUES) { part.m.tx = arg1; part.m.ty = arg2; }
else { part.p1 = arg1; part.p2 = arg2; }
//part.m.tx = arg1; part.m.ty = arg2;
//else { throw "params are not XY values"; }
if (flags & WE_HAVE_A_SCALE) {
part.m.a = part.m.d = bin.readF2dot14(data, offset); offset += 2;
} else if (flags & WE_HAVE_AN_X_AND_Y_SCALE) {
part.m.a = bin.readF2dot14(data, offset); offset += 2;
part.m.d = bin.readF2dot14(data, offset); offset += 2;
} else if (flags & WE_HAVE_A_TWO_BY_TWO) {
part.m.a = bin.readF2dot14(data, offset); offset += 2;
part.m.b = bin.readF2dot14(data, offset); offset += 2;
part.m.c = bin.readF2dot14(data, offset); offset += 2;
part.m.d = bin.readF2dot14(data, offset); offset += 2;
}
} while (flags & MORE_COMPONENTS)
if (flags & WE_HAVE_INSTRUCTIONS) {
var numInstr = bin.readUshort(data, offset); offset += 2;
gl.instr = [];
for (var i = 0; i < numInstr; i++) { gl.instr.push(data[offset]); offset++; }
}
}
return gl;
}
};
Typr["T"].head = {
parseTab: function (data, offset, length) {
var bin = Typr["B"];
var obj = {};
bin.readFixed(data, offset); offset += 4;
obj["fontRevision"] = bin.readFixed(data, offset); offset += 4;
bin.readUint(data, offset); offset += 4;
bin.readUint(data, offset); offset += 4;
obj["flags"] = bin.readUshort(data, offset); offset += 2;
obj["unitsPerEm"] = bin.readUshort(data, offset); offset += 2;
obj["created"] = bin.readUint64(data, offset); offset += 8;
obj["modified"] = bin.readUint64(data, offset); offset += 8;
obj["xMin"] = bin.readShort(data, offset); offset += 2;
obj["yMin"] = bin.readShort(data, offset); offset += 2;
obj["xMax"] = bin.readShort(data, offset); offset += 2;
obj["yMax"] = bin.readShort(data, offset); offset += 2;
obj["macStyle"] = bin.readUshort(data, offset); offset += 2;
obj["lowestRecPPEM"] = bin.readUshort(data, offset); offset += 2;
obj["fontDirectionHint"] = bin.readShort(data, offset); offset += 2;
obj["indexToLocFormat"] = bin.readShort(data, offset); offset += 2;
obj["glyphDataFormat"] = bin.readShort(data, offset); offset += 2;
return obj;
}
};
Typr["T"].hhea = {
parseTab: function (data, offset, length) {
var bin = Typr["B"];
var obj = {};
bin.readFixed(data, offset); offset += 4;
var keys = ["ascender", "descender", "lineGap",
"advanceWidthMax", "minLeftSideBearing", "minRightSideBearing", "xMaxExtent",
"caretSlopeRise", "caretSlopeRun", "caretOffset",
"res0", "res1", "res2", "res3",
"metricDataFormat", "numberOfHMetrics"];
for (var i = 0; i < keys.length; i++) {
var key = keys[i];
var func = (key == "advanceWidthMax" || key == "numberOfHMetrics") ? bin.readUshort : bin.readShort;
obj[key] = func(data, offset + i * 2);
}
return obj;
}
};
Typr["T"].hmtx = {
parseTab: function (data, offset, length, font) {
var bin = Typr["B"];
var aWidth = [];
var lsBearing = [];
var nG = font["maxp"]["numGlyphs"], nH = font["hhea"]["numberOfHMetrics"];
var aw = 0, lsb = 0, i = 0;
while (i < nH) { aw = bin.readUshort(data, offset + (i << 2)); lsb = bin.readShort(data, offset + (i << 2) + 2); aWidth.push(aw); lsBearing.push(lsb); i++; }
while (i < nG) { aWidth.push(aw); lsBearing.push(lsb); i++; }
return { aWidth: aWidth, lsBearing: lsBearing };
}
};
Typr["T"].kern = {
parseTab: function (data, offset, length, font) {
var bin = Typr["B"], kern = Typr["T"].kern;
var version = bin.readUshort(data, offset);
if (version == 1) return kern.parseV1(data, offset, length, font);
var nTables = bin.readUshort(data, offset + 2); offset += 4;
var map = { glyph1: [], rval: [] };
for (var i = 0; i < nTables; i++) {
offset += 2; // skip version
var length = bin.readUshort(data, offset); offset += 2;
var coverage = bin.readUshort(data, offset); offset += 2;
var format = coverage >>> 8;
/* I have seen format 128 once, that's why I do */ format &= 0xf;
if (format == 0) offset = kern.readFormat0(data, offset, map);
//else throw "unknown kern table format: "+format;
}
return map;
},
parseV1: function (data, offset, length, font) {
var bin = Typr["B"], kern = Typr["T"].kern;
bin.readFixed(data, offset); // 0x00010000
var nTables = bin.readUint(data, offset + 4); offset += 8;
var map = { glyph1: [], rval: [] };
for (var i = 0; i < nTables; i++) {
bin.readUint(data, offset); offset += 4;
var coverage = bin.readUshort(data, offset); offset += 2;
bin.readUshort(data, offset); offset += 2;
var format = coverage & 0xff;
if (format == 0) offset = kern.readFormat0(data, offset, map);
//else throw "unknown kern table format: "+format;
}
return map;
},
readFormat0: function (data, offset, map) {
var bin = Typr["B"], rUs = bin.readUshort;
var pleft = -1;
var nPairs = rUs(data, offset);
rUs(data, offset + 2);
rUs(data, offset + 4);
rUs(data, offset + 6); offset += 8;
for (var j = 0; j < nPairs; j++) {
var left = rUs(data, offset); offset += 2;
var right = rUs(data, offset); offset += 2;
var value = bin.readShort(data, offset); offset += 2;
if (left != pleft) { map.glyph1.push(left); map.rval.push({ glyph2: [], vals: [] }); }
var rval = map.rval[map.rval.length - 1];
rval.glyph2.push(right); rval.vals.push(value);
pleft = left;
}
return offset;
}
};
Typr["T"].loca = {
parseTab: function (data, offset, length, font) {
var bin = Typr["B"];
var obj = [];
var ver = font["head"]["indexToLocFormat"];
var len = font["maxp"]["numGlyphs"] + 1;
if (ver == 0) for (var i = 0; i < len; i++) obj.push(bin.readUshort(data, offset + (i << 1)) << 1);
if (ver == 1) for (var i = 0; i < len; i++) obj.push(bin.readUint(data, offset + (i << 2)));
return obj;
}
};
Typr["T"].maxp = {
parseTab: function (data, offset, length) {
//console.log(data.length, offset, length);
var bin = Typr["B"], rU = bin.readUshort;
var obj = {};
// both versions 0.5 and 1.0
bin.readUint(data, offset); offset += 4;
obj["numGlyphs"] = rU(data, offset); offset += 2;
// only 1.0
/*
if(ver == 0x00010000) {
obj.maxPoints = rU(data, offset); offset += 2;
obj.maxContours = rU(data, offset); offset += 2;
obj.maxCompositePoints = rU(data, offset); offset += 2;
obj.maxCompositeContours = rU(data, offset); offset += 2;
obj.maxZones = rU(data, offset); offset += 2;
obj.maxTwilightPoints = rU(data, offset); offset += 2;
obj.maxStorage = rU(data, offset); offset += 2;
obj.maxFunctionDefs = rU(data, offset); offset += 2;
obj.maxInstructionDefs = rU(data, offset); offset += 2;
obj.maxStackElements = rU(data, offset); offset += 2;
obj.maxSizeOfInstructions = rU(data, offset); offset += 2;
obj.maxComponentElements = rU(data, offset); offset += 2;
obj.maxComponentDepth = rU(data, offset); offset += 2;
}
*/
return obj;
}
};
Typr["T"].name = {
parseTab: function (data, offset, length) {
var bin = Typr["B"];
var obj = {};
bin.readUshort(data, offset); offset += 2;
var count = bin.readUshort(data, offset); offset += 2;
var stringOffset = bin.readUshort(data, offset); offset += 2;
var ooo = offset - 6 + stringOffset;
//console.log(format,count);
var names = [
"copyright",
"fontFamily",
"fontSubfamily",
"ID",
"fullName",
"version",
"postScriptName",
"trademark",
"manufacturer",
"designer",
"description",
"urlVendor",
"urlDesigner",
"licence",
"licenceURL",
"---",
"typoFamilyName",
"typoSubfamilyName",
"compatibleFull",
"sampleText",
"postScriptCID",
"wwsFamilyName",
"wwsSubfamilyName",
"lightPalette",
"darkPalette"
];
var rU = bin.readUshort;
for (var i = 0; i < count; i++) {
var platformID = rU(data, offset); offset += 2;
var encodingID = rU(data, offset); offset += 2;
var languageID = rU(data, offset); offset += 2;
var nameID = rU(data, offset); offset += 2;
var slen = rU(data, offset); offset += 2;
var noffset = rU(data, offset); offset += 2;
//console.log(platformID, encodingID, languageID.toString(16), nameID, length, noffset);
var soff = ooo + noffset;
var str;
if (platformID == 0) str = bin.readUnicode(data, soff, slen / 2);
else if (platformID == 3 && encodingID == 0) str = bin.readUnicode(data, soff, slen / 2);
else if (platformID == 1 && encodingID == 25) str = bin.readUnicode(data, soff, slen / 2);
else if (encodingID == 0) str = bin.readASCII(data, soff, slen);
else if (encodingID == 1) str = bin.readUnicode(data, soff, slen / 2);
else if (encodingID == 3) str = bin.readUnicode(data, soff, slen / 2);
else if (encodingID == 4) str = bin.readUnicode(data, soff, slen / 2);
else if (encodingID == 5) str = bin.readUnicode(data, soff, slen / 2);
else if (encodingID == 10) str = bin.readUnicode(data, soff, slen / 2);
else if (platformID == 1) { str = bin.readASCII(data, soff, slen); console.log("reading unknown MAC encoding " + encodingID + " as ASCII"); }
else {
console.log("unknown encoding " + encodingID + ", platformID: " + platformID);
str = bin.readASCII(data, soff, slen);
}
var tid = "p" + platformID + "," + (languageID).toString(16);//Typr._platforms[platformID];
if (obj[tid] == null) obj[tid] = {};
var name = names[nameID]; if (name == null) name = "_" + nameID;
obj[tid][name] = str;
obj[tid]["_lang"] = languageID;
//console.log(tid, obj[tid]);
}
/*
if(format == 1)
{
var langTagCount = bin.readUshort(data, offset); offset += 2;
for(var i=0; i<langTagCount; i++)
{
var length = bin.readUshort(data, offset); offset += 2;
var noffset = bin.readUshort(data, offset); offset += 2;
}
}
*/
var out = Typr["T"].name.selectOne(obj), ff = "fontFamily";
if (out[ff] == null) for (var p in obj) if (obj[p][ff] != null) out[ff] = obj[p][ff];
return out;
},
selectOne: function (obj) {
//console.log(obj);
var psn = "postScriptName";
for (var p in obj) if (obj[p][psn] != null && obj[p]["_lang"] == 0x0409) return obj[p]; // United States
for (var p in obj) if (obj[p][psn] != null && obj[p]["_lang"] == 0x0000) return obj[p]; // Universal
for (var p in obj) if (obj[p][psn] != null && obj[p]["_lang"] == 0x0c0c) return obj[p]; // Canada
for (var p in obj) if (obj[p][psn] != null) return obj[p];
var out;
for (var p in obj) { out = obj[p]; break; }
console.log("returning name table with languageID " + out._lang);
if (out[psn] == null && out["ID"] != null) out[psn] = out["ID"];
return out;
}
};
Typr["T"].OS2 = {
parseTab: function (data, offset, length) {
var bin = Typr["B"];
var ver = bin.readUshort(data, offset); offset += 2;
var OS2 = Typr["T"].OS2;
var obj = {};
if (ver == 0) OS2.version0(data, offset, obj);
else if (ver == 1) OS2.version1(data, offset, obj);
else if (ver == 2 || ver == 3 || ver == 4) OS2.version2(data, offset, obj);
else if (ver == 5) OS2.version5(data, offset, obj);
else throw "unknown OS/2 table version: " + ver;
return obj;
},
version0: function (data, offset, obj) {
var bin = Typr["B"];
obj["xAvgCharWidth"] = bin.readShort(data, offset); offset += 2;
obj["usWeightClass"] = bin.readUshort(data, offset); offset += 2;
obj["usWidthClass"] = bin.readUshort(data, offset); offset += 2;
obj["fsType"] = bin.readUshort(data, offset); offset += 2;
obj["ySubscriptXSize"] = bin.readShort(data, offset); offset += 2;
obj["ySubscriptYSize"] = bin.readShort(data, offset); offset += 2;
obj["ySubscriptXOffset"] = bin.readShort(data, offset); offset += 2;
obj["ySubscriptYOffset"] = bin.readShort(data, offset); offset += 2;
obj["ySuperscriptXSize"] = bin.readShort(data, offset); offset += 2;
obj["ySuperscriptYSize"] = bin.readShort(data, offset); offset += 2;
obj["ySuperscriptXOffset"] = bin.readShort(data, offset); offset += 2;
obj["ySuperscriptYOffset"] = bin.readShort(data, offset); offset += 2;
obj["yStrikeoutSize"] = bin.readShort(data, offset); offset += 2;
obj["yStrikeoutPosition"] = bin.readShort(data, offset); offset += 2;
obj["sFamilyClass"] = bin.readShort(data, offset); offset += 2;
obj["panose"] = bin.readBytes(data, offset, 10); offset += 10;
obj["ulUnicodeRange1"] = bin.readUint(data, offset); offset += 4;
obj["ulUnicodeRange2"] = bin.readUint(data, offset); offset += 4;
obj["ulUnicodeRange3"] = bin.readUint(data, offset); offset += 4;
obj["ulUnicodeRange4"] = bin.readUint(data, offset); offset += 4;
obj["achVendID"] = bin.readASCII(data, offset, 4); offset += 4;
obj["fsSelection"] = bin.readUshort(data, offset); offset += 2;
obj["usFirstCharIndex"] = bin.readUshort(data, offset); offset += 2;
obj["usLastCharIndex"] = bin.readUshort(data, offset); offset += 2;
obj["sTypoAscender"] = bin.readShort(data, offset); offset += 2;
obj["sTypoDescender"] = bin.readShort(data, offset); offset += 2;
obj["sTypoLineGap"] = bin.readShort(data, offset); offset += 2;
obj["usWinAscent"] = bin.readUshort(data, offset); offset += 2;
obj["usWinDescent"] = bin.readUshort(data, offset); offset += 2;
return offset;
},
version1: function (data, offset, obj) {
var bin = Typr["B"];
offset = Typr["T"].OS2.version0(data, offset, obj);
obj["ulCodePageRange1"] = bin.readUint(data, offset); offset += 4;
obj["ulCodePageRange2"] = bin.readUint(data, offset); offset += 4;
return offset;
},
version2: function (data, offset, obj) {
var bin = Typr["B"], rU = bin.readUshort;
offset = Typr["T"].OS2.version1(data, offset, obj);
obj["sxHeight"] = bin.readShort(data, offset); offset += 2;
obj["sCapHeight"] = bin.readShort(data, offset); offset += 2;
obj["usDefault"] = rU(data, offset); offset += 2;
obj["usBreak"] = rU(data, offset); offset += 2;
obj["usMaxContext"] = rU(data, offset); offset += 2;
return offset;
},
version5: function (data, offset, obj) {
var rU = Typr["B"].readUshort;
offset = Typr["T"].OS2.version2(data, offset, obj);
obj["usLowerOpticalPointSize"] = rU(data, offset); offset += 2;
obj["usUpperOpticalPointSize"] = rU(data, offset); offset += 2;
return offset;
}
};
Typr["T"].post = {
parseTab: function (data, offset, length) {
var bin = Typr["B"];
var obj = {};
obj["version"] = bin.readFixed(data, offset); offset += 4;
obj["italicAngle"] = bin.readFixed(data, offset); offset += 4;
obj["underlinePosition"] = bin.readShort(data, offset); offset += 2;
obj["underlineThickness"] = bin.readShort(data, offset); offset += 2;
return obj;
}
};
Typr["T"].SVG = {
parseTab: function (data, offset, length) {
var bin = Typr["B"];
var obj = { entries: [], svgs: [] };
var offset0 = offset;
bin.readUshort(data, offset); offset += 2;
var svgDocIndexOffset = bin.readUint(data, offset); offset += 4;
bin.readUint(data, offset); offset += 4;
offset = svgDocIndexOffset + offset0;
var numEntries = bin.readUshort(data, offset); offset += 2;
for (var i = 0; i < numEntries; i++) {
var startGlyphID = bin.readUshort(data, offset); offset += 2;
var endGlyphID = bin.readUshort(data, offset); offset += 2;
var svgDocOffset = bin.readUint(data, offset); offset += 4;
var svgDocLength = bin.readUint(data, offset); offset += 4;
var sbuf = new Uint8Array(data.buffer, offset0 + svgDocOffset + svgDocIndexOffset, svgDocLength);
if (sbuf[0] == 0x1f && sbuf[1] == 0x8b && sbuf[2] == 0x08) sbuf = pako["inflate"](sbuf);
var svg = bin.readUTF8(sbuf, 0, sbuf.length);
for (var f = startGlyphID; f <= endGlyphID; f++) {
obj.entries[f] = obj.svgs.length;
}
obj.svgs.push(svg);
}
return obj;
}
};
Typr["T"].sbix = {
parseTab: function (data, offset, length, obj) {
var numGlyphs = obj["maxp"]["numGlyphs"];
var ooff = offset;
var bin = Typr["B"];
//var ver = bin.readUshort(data,offset); offset+=2;
//var flg = bin.readUshort(data,offset); offset+=2;
var numStrikes = bin.readUint(data, offset + 4);
var out = [];
for (var si = numStrikes - 1; si < numStrikes; si++) {
var off = ooff + bin.readUint(data, offset + 8 + si * 4);
//var ppem = bin.readUshort(data,off); off+=2;
//var ppi = bin.readUshort(data,off); off+=2;
for (var gi = 0; gi < numGlyphs; gi++) {
var aoff = bin.readUint(data, off + 4 + gi * 4);
var noff = bin.readUint(data, off + 4 + gi * 4 + 4); if (aoff == noff) { out[gi] = null; continue; }
var go = off + aoff;
//var ooX = bin.readUshort(data,go);
//var ooY = bin.readUshort(data,go+2);
var tag = bin.readASCII(data, go + 4, 4); if (tag != "png ") throw tag;
out[gi] = new Uint8Array(data.buffer, data.byteOffset + go + 8, noff - aoff - 8);
}
}
return out;
}
};
Typr["T"].colr = {
parseTab: function (data, offset, length) {
var bin = Typr["B"];
var ooff = offset;
offset += 2;
var num = bin.readUshort(data, offset); offset += 2;
var boff = bin.readUint(data, offset); offset += 4;
var loff = bin.readUint(data, offset); offset += 4;
var lnum = bin.readUshort(data, offset); offset += 2;
//console.log(num,boff,loff,lnum);
var base = {};
var coff = ooff + boff;
for (var i = 0; i < num; i++) {
base["g" + bin.readUshort(data, coff)] = [bin.readUshort(data, coff + 2), bin.readUshort(data, coff + 4)