UNPKG

p5

Version:

[![npm version](https://badge.fury.io/js/p5.svg)](https://www.npmjs.com/package/p5)

1,465 lines (1,250 loc) 102 kB
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)