Typr库

Typr 库 Greasy Fork镜像 镜像

此腳本不應該直接安裝,它是一個供其他腳本使用的函式庫。欲使用本函式庫,請在腳本 metadata 寫上: // @require https://update.gf.qytechs.cn/scripts/466179/1189955/Typr%E5%BA%93.js

  1.  
  2. var Typr = {};
  3.  
  4. Typr["parse"] = function(buff)
  5. {
  6. var readFont = function(data, idx, offset,tmap) {
  7. var bin = Typr["B"];
  8. var T = Typr["T"];
  9. var prsr = {
  10. "cmap":T.cmap,
  11. "head":T.head,
  12. "hhea":T.hhea,
  13. "maxp":T.maxp,
  14. "hmtx":T.hmtx,
  15. "name":T.name,
  16. "OS/2":T.OS2,
  17. "post":T.post,
  18. "loca":T.loca,
  19. "kern":T.kern,
  20. "glyf":T.glyf,
  21. "CFF ":T.CFF,
  22. /*
  23. "GPOS",
  24. "GSUB",
  25. "GDEF",*/
  26. "SVG ":T.SVG
  27. //"VORG",
  28. };
  29. var obj = {"_data":data, "_index":idx, "_offset":offset};
  30. for(var t in prsr) {
  31. var tab = Typr["findTable"](data, t, offset);
  32. if(tab) {
  33. var off=tab[0], tobj = tmap[off];
  34. if(tobj==null) tobj = prsr[t].parseTab(data, off, tab[1], obj);
  35. obj[t] = tmap[off] = tobj;
  36. }
  37. }
  38. return obj;
  39. }
  40. var bin = Typr["B"];
  41. var data = new Uint8Array(buff);
  42. var tmap = {};
  43. var tag = bin.readASCII(data, 0, 4);
  44. if(tag=="ttcf") {
  45. var offset = 4;
  46. var majV = bin.readUshort(data, offset); offset+=2;
  47. var minV = bin.readUshort(data, offset); offset+=2;
  48. var numF = bin.readUint (data, offset); offset+=4;
  49. var fnts = [];
  50. for(var i=0; i<numF; i++) {
  51. var foff = bin.readUint (data, offset); offset+=4;
  52. fnts.push(readFont(data, i, foff,tmap));
  53. }
  54. return fnts;
  55. }
  56. else return [readFont(data, 0, 0,tmap)];
  57. }
  58.  
  59.  
  60. Typr["findTable"] = function(data, tab, foff)
  61. {
  62. var bin = Typr["B"];
  63. var numTables = bin.readUshort(data, foff+4);
  64. var offset = foff+12;
  65. for(var i=0; i<numTables; i++)
  66. {
  67. var tag = bin.readASCII(data, offset, 4);
  68. var checkSum = bin.readUint (data, offset+ 4);
  69. var toffset = bin.readUint (data, offset+ 8);
  70. var length = bin.readUint (data, offset+12);
  71. if(tag==tab) return [toffset,length];
  72. offset+=16;
  73. }
  74. return null;
  75. }
  76. /*
  77. Typr["splitBy"] = function(data,tag) {
  78. data = new Uint8Array(data); console.log(data.slice(0,64));
  79. var bin = Typr["B"];
  80. var ttcf = bin.readASCII(data, 0, 4); if(ttcf!="ttcf") return {};
  81. var offset = 8;
  82. var numF = bin.readUint (data, offset); offset+=4;
  83. var colls = [], used={};
  84. for(var i=0; i<numF; i++) {
  85. var foff = bin.readUint (data, offset); offset+=4;
  86. var toff = Typr["findTable"](data,tag,foff)[0];
  87. if(used[toff]==null) used[toff] = [];
  88. used[toff].push([foff,bin.readUshort(data,foff+4)]); // font offset, numTables
  89. }
  90. for(var toff in used) {
  91. var offs = used[toff];
  92. var hlen = 12+4*offs.length;
  93. var out = new Uint8Array(hlen);
  94. for(var i=0; i<8; i++) out[i]=data[i];
  95. bin.writeUint(out,8,offs.length);
  96. for(var i=0; i<offs.length; i++) hlen += 12+offs[i][1]*16;
  97. var hdrs = [out], tabs = [], hoff=out.length, toff=hlen, noffs={};
  98. for(var i=0; i<offs.length; i++) {
  99. bin.writeUint(out, 12+i*4, hoff); hoff+=12+offs[i][1]*16;
  100. toff = Typr["_cutFont"](data, offs[i][0], hdrs, tabs, toff, noffs);
  101. }
  102. colls.push(Typr["_joinArrs"](hdrs.concat(tabs)));
  103. }
  104. return colls;
  105. }
  106.  
  107. Typr["splitFonts"] = function(data) {
  108. data = new Uint8Array(data);
  109. var bin = Typr["B"];
  110. var ttcf = bin.readASCII(data, 0, 4); if(ttcf!="ttcf") return {};
  111. var offset = 8;
  112. var numF = bin.readUint (data, offset); offset+=4;
  113. var fnts = [];
  114. for(var i=0; i<numF; i++) {
  115. var foff = bin.readUint (data, offset); offset+=4;
  116. fnts.push(Typr._cutFont(data, foff));
  117. break;
  118. }
  119. return fnts;
  120. }
  121.  
  122. Typr["_cutFont"] = function(data,foff,hdrs,tabs,toff, noffs) {
  123. var bin = Typr["B"];
  124. var numTables = bin.readUshort(data, foff+4);
  125. var out = new Uint8Array(12+numTables*16); hdrs.push(out);
  126. for(var i=0; i<12; i++) out[i]=data[foff+i]; //console.log(out);
  127. var off = 12;
  128. for(var i=0; i<numTables; i++)
  129. {
  130. var tag = bin.readASCII(data, foff+off, 4);
  131. var checkSum = bin.readUint (data, foff+off+ 4);
  132. var toffset = bin.readUint (data, foff+off+ 8);
  133. var length = bin.readUint (data, foff+off+12);
  134. while((length&3)!=0) length++;
  135. for(var j=0; j<16; j++) out[off+j]=data[foff+off+j];
  136. if(noffs[toffset]!=null) bin.writeUint(out,off+8,noffs[toffset]);
  137. else {
  138. noffs[toffset] = toff;
  139. bin.writeUint(out, off+8, toff);
  140. tabs.push(new Uint8Array(data.buffer, toffset, length)); toff+=length;
  141. }
  142. off+=16;
  143. }
  144. return toff;
  145. }
  146. Typr["_joinArrs"] = function(tabs) {
  147. var len = 0;
  148. for(var i=0; i<tabs.length; i++) len+=tabs[i].length;
  149. var out = new Uint8Array(len), ooff=0;
  150. for(var i=0; i<tabs.length; i++) {
  151. var tab = tabs[i];
  152. for(var j=0; j<tab.length; j++) out[ooff+j]=tab[j];
  153. ooff+=tab.length;
  154. }
  155. return out;
  156. }
  157. */
  158.  
  159. Typr["T"]={};
  160.  
  161.  
  162.  
  163.  
  164.  
  165. Typr["B"] = {
  166. readFixed : function(data, o)
  167. {
  168. return ((data[o]<<8) | data[o+1]) + (((data[o+2]<<8)|data[o+3])/(256*256+4));
  169. },
  170. readF2dot14 : function(data, o)
  171. {
  172. var num = Typr["B"].readShort(data, o);
  173. return num / 16384;
  174. },
  175. readInt : function(buff, p)
  176. {
  177. //if(p>=buff.length) throw "error";
  178. var a = Typr["B"].t.uint8;
  179. a[0] = buff[p+3];
  180. a[1] = buff[p+2];
  181. a[2] = buff[p+1];
  182. a[3] = buff[p];
  183. return Typr["B"].t.int32[0];
  184. },
  185. readInt8 : function(buff, p)
  186. {
  187. //if(p>=buff.length) throw "error";
  188. var a = Typr["B"].t.uint8;
  189. a[0] = buff[p];
  190. return Typr["B"].t.int8[0];
  191. },
  192. readShort : function(buff, p)
  193. {
  194. //if(p>=buff.length) throw "error";
  195. var a = Typr["B"].t.uint8;
  196. a[1] = buff[p]; a[0] = buff[p+1];
  197. return Typr["B"].t.int16[0];
  198. },
  199. readUshort : function(buff, p)
  200. {
  201. //if(p>=buff.length) throw "error";
  202. return (buff[p]<<8) | buff[p+1];
  203. },
  204. writeUshort : function(buff, p, n)
  205. {
  206. buff[p] = (n>>8)&255; buff[p+1] = n&255;
  207. },
  208. readUshorts : function(buff, p, len)
  209. {
  210. var arr = [];
  211. for(var i=0; i<len; i++) {
  212. var v = Typr["B"].readUshort(buff, p+i*2); //if(v==932) console.log(p+i*2);
  213. arr.push(v);
  214. }
  215. return arr;
  216. },
  217. readUint : function(buff, p)
  218. {
  219. //if(p>=buff.length) throw "error";
  220. var a = Typr["B"].t.uint8;
  221. a[3] = buff[p]; a[2] = buff[p+1]; a[1] = buff[p+2]; a[0] = buff[p+3];
  222. return Typr["B"].t.uint32[0];
  223. },
  224. writeUint: function(buff, p, n)
  225. {
  226. buff[p] = (n>>24)&255; buff[p+1] = (n>>16)&255; buff[p+2] = (n>>8)&255; buff[p+3] = (n>>0)&255;
  227. },
  228. readUint64 : function(buff, p)
  229. {
  230. //if(p>=buff.length) throw "error";
  231. return (Typr["B"].readUint(buff, p)*(0xffffffff+1)) + Typr["B"].readUint(buff, p+4);
  232. },
  233. readASCII : function(buff, p, l) // l : length in Characters (not Bytes)
  234. {
  235. //if(p>=buff.length) throw "error";
  236. var s = "";
  237. for(var i = 0; i < l; i++) s += String.fromCharCode(buff[p+i]);
  238. return s;
  239. },
  240. writeASCII : function(buff, p, s) // l : length in Characters (not Bytes)
  241. {
  242. for(var i = 0; i < s.length; i++)
  243. buff[p+i] = s.charCodeAt(i);
  244. },
  245. readUnicode : function(buff, p, l)
  246. {
  247. //if(p>=buff.length) throw "error";
  248. var s = "";
  249. for(var i = 0; i < l; i++)
  250. {
  251. var c = (buff[p++]<<8) | buff[p++];
  252. s += String.fromCharCode(c);
  253. }
  254. return s;
  255. },
  256. _tdec : window["TextDecoder"] ? new window["TextDecoder"]() : null,
  257. readUTF8 : function(buff, p, l) {
  258. var tdec = Typr["B"]._tdec;
  259. if(tdec && p==0 && l==buff.length) return tdec["decode"](buff);
  260. return Typr["B"].readASCII(buff,p,l);
  261. },
  262. readBytes : function(buff, p, l)
  263. {
  264. //if(p>=buff.length) throw "error";
  265. var arr = [];
  266. for(var i=0; i<l; i++) arr.push(buff[p+i]);
  267. return arr;
  268. },
  269. readASCIIArray : function(buff, p, l) // l : length in Characters (not Bytes)
  270. {
  271. //if(p>=buff.length) throw "error";
  272. var s = [];
  273. for(var i = 0; i < l; i++)
  274. s.push(String.fromCharCode(buff[p+i]));
  275. return s;
  276. },
  277. t : function() {
  278. var ab = new ArrayBuffer(8);
  279. return {
  280. buff : ab,
  281. int8 : new Int8Array (ab),
  282. uint8 : new Uint8Array (ab),
  283. int16 : new Int16Array (ab),
  284. uint16 : new Uint16Array(ab),
  285. int32 : new Int32Array (ab),
  286. uint32 : new Uint32Array(ab)
  287. }
  288. }()
  289. };
  290.  
  291.  
  292.  
  293.  
  294.  
  295.  
  296. Typr["T"].CFF = {
  297. parseTab : function(data, offset, length)
  298. {
  299. var bin = Typr["B"];
  300. var CFF = Typr["T"].CFF;
  301. data = new Uint8Array(data.buffer, offset, length);
  302. offset = 0;
  303. // Header
  304. var major = data[offset]; offset++;
  305. var minor = data[offset]; offset++;
  306. var hdrSize = data[offset]; offset++;
  307. var offsize = data[offset]; offset++;
  308. //console.log(major, minor, hdrSize, offsize);
  309. // Name INDEX
  310. var ninds = [];
  311. offset = CFF.readIndex(data, offset, ninds);
  312. var names = [];
  313. for(var i=0; i<ninds.length-1; i++) names.push(bin.readASCII(data, offset+ninds[i], ninds[i+1]-ninds[i]));
  314. offset += ninds[ninds.length-1];
  315. // Top DICT INDEX
  316. var tdinds = [];
  317. offset = CFF.readIndex(data, offset, tdinds); //console.log(tdinds);
  318. // Top DICT Data
  319. var topDicts = [];
  320. for(var i=0; i<tdinds.length-1; i++) topDicts.push( CFF.readDict(data, offset+tdinds[i], offset+tdinds[i+1]) );
  321. offset += tdinds[tdinds.length-1];
  322. var topdict = topDicts[0];
  323. //console.log(topdict);
  324. // String INDEX
  325. var sinds = [];
  326. offset = CFF.readIndex(data, offset, sinds);
  327. // String Data
  328. var strings = [];
  329. for(var i=0; i<sinds.length-1; i++) strings.push(bin.readASCII(data, offset+sinds[i], sinds[i+1]-sinds[i]));
  330. offset += sinds[sinds.length-1];
  331. // Global Subr INDEX (subroutines)
  332. CFF.readSubrs(data, offset, topdict);
  333. // charstrings
  334. if(topdict["CharStrings"]) topdict["CharStrings"] = CFF.readBytes(data, topdict["CharStrings"]);
  335. // CID font
  336. if(topdict["ROS"]) {
  337. offset = topdict["FDArray"];
  338. var fdind = [];
  339. offset = CFF.readIndex(data, offset, fdind);
  340. topdict["FDArray"] = [];
  341. for(var i=0; i<fdind.length-1; i++) {
  342. var dict = CFF.readDict(data, offset+fdind[i], offset+fdind[i+1]);
  343. CFF._readFDict(data, dict, strings);
  344. topdict["FDArray"].push( dict );
  345. }
  346. offset += fdind[fdind.length-1];
  347. offset = topdict["FDSelect"];
  348. topdict["FDSelect"] = [];
  349. var fmt = data[offset]; offset++;
  350. if(fmt==3) {
  351. var rns = bin.readUshort(data, offset); offset+=2;
  352. for(var i=0; i<rns+1; i++) {
  353. topdict["FDSelect"].push(bin.readUshort(data, offset), data[offset+2]); offset+=3;
  354. }
  355. }
  356. else throw fmt;
  357. }
  358. // Encoding
  359. //if(topdict["Encoding"]) topdict["Encoding"] = CFF.readEncoding(data, topdict["Encoding"], topdict["CharStrings"].length);
  360. // charset
  361. if(topdict["charset"] ) topdict["charset"] = CFF.readCharset (data, topdict["charset"] , topdict["CharStrings"].length);
  362. CFF._readFDict(data, topdict, strings);
  363. return topdict;
  364. },
  365. _readFDict : function(data, dict, ss) {
  366. var CFF = Typr["T"].CFF;
  367. var offset;
  368. if(dict["Private"]) {
  369. offset = dict["Private"][1];
  370. dict["Private"] = CFF.readDict(data, offset, offset+dict["Private"][0]);
  371. if(dict["Private"]["Subrs"]) CFF.readSubrs(data, offset+dict["Private"]["Subrs"], dict["Private"]);
  372. }
  373. for(var p in dict) if(["FamilyName","FontName","FullName","Notice","version","Copyright"].indexOf(p)!=-1) dict[p]=ss[dict[p] -426 + 35];
  374. },
  375. readSubrs : function(data, offset, obj)
  376. {
  377. obj["Subrs"] = Typr["T"].CFF.readBytes(data, offset);
  378. var bias, nSubrs = obj["Subrs"].length+1;
  379. if (false) bias = 0;
  380. else if (nSubrs < 1240) bias = 107;
  381. else if (nSubrs < 33900) bias = 1131;
  382. else bias = 32768;
  383. obj["Bias"] = bias;
  384. },
  385. readBytes : function(data, offset) {
  386. var bin = Typr["B"];
  387. var arr = [];
  388. offset = Typr["T"].CFF.readIndex(data, offset, arr);
  389. var subrs = [], arl = arr.length-1, no = data.byteOffset+offset;
  390. for(var i=0; i<arl; i++) {
  391. var ari = arr[i];
  392. subrs.push(new Uint8Array(data.buffer, no+ari, arr[i+1]-ari));
  393. }
  394. return subrs;
  395. },
  396. tableSE : [
  397. 0, 0, 0, 0, 0, 0, 0, 0,
  398. 0, 0, 0, 0, 0, 0, 0, 0,
  399. 0, 0, 0, 0, 0, 0, 0, 0,
  400. 0, 0, 0, 0, 0, 0, 0, 0,
  401. 1, 2, 3, 4, 5, 6, 7, 8,
  402. 9, 10, 11, 12, 13, 14, 15, 16,
  403. 17, 18, 19, 20, 21, 22, 23, 24,
  404. 25, 26, 27, 28, 29, 30, 31, 32,
  405. 33, 34, 35, 36, 37, 38, 39, 40,
  406. 41, 42, 43, 44, 45, 46, 47, 48,
  407. 49, 50, 51, 52, 53, 54, 55, 56,
  408. 57, 58, 59, 60, 61, 62, 63, 64,
  409. 65, 66, 67, 68, 69, 70, 71, 72,
  410. 73, 74, 75, 76, 77, 78, 79, 80,
  411. 81, 82, 83, 84, 85, 86, 87, 88,
  412. 89, 90, 91, 92, 93, 94, 95, 0,
  413. 0, 0, 0, 0, 0, 0, 0, 0,
  414. 0, 0, 0, 0, 0, 0, 0, 0,
  415. 0, 0, 0, 0, 0, 0, 0, 0,
  416. 0, 0, 0, 0, 0, 0, 0, 0,
  417. 0, 96, 97, 98, 99, 100, 101, 102,
  418. 103, 104, 105, 106, 107, 108, 109, 110,
  419. 0, 111, 112, 113, 114, 0, 115, 116,
  420. 117, 118, 119, 120, 121, 122, 0, 123,
  421. 0, 124, 125, 126, 127, 128, 129, 130,
  422. 131, 0, 132, 133, 0, 134, 135, 136,
  423. 137, 0, 0, 0, 0, 0, 0, 0,
  424. 0, 0, 0, 0, 0, 0, 0, 0,
  425. 0, 138, 0, 139, 0, 0, 0, 0,
  426. 140, 141, 142, 143, 0, 0, 0, 0,
  427. 0, 144, 0, 0, 0, 145, 0, 0,
  428. 146, 147, 148, 149, 0, 0, 0, 0
  429. ],
  430. glyphByUnicode : function(cff, code)
  431. {
  432. for(var i=0; i<cff["charset"].length; i++) if(cff["charset"][i]==code) return i;
  433. return -1;
  434. },
  435. glyphBySE : function(cff, charcode) // glyph by standard encoding
  436. {
  437. if ( charcode < 0 || charcode > 255 ) return -1;
  438. return Typr["T"].CFF.glyphByUnicode(cff, Typr["T"].CFF.tableSE[charcode]);
  439. },
  440. /*readEncoding : function(data, offset, num)
  441. {
  442. var bin = Typr["B"];
  443. var array = ['.notdef'];
  444. var format = data[offset]; offset++;
  445. //console.log("Encoding");
  446. //console.log(format);
  447. if(format==0)
  448. {
  449. var nCodes = data[offset]; offset++;
  450. for(var i=0; i<nCodes; i++) array.push(data[offset+i]);
  451. }
  452. /*
  453. else if(format==1 || format==2)
  454. {
  455. while(charset.length<num)
  456. {
  457. var first = bin.readUshort(data, offset); offset+=2;
  458. var nLeft=0;
  459. if(format==1) { nLeft = data[offset]; offset++; }
  460. else { nLeft = bin.readUshort(data, offset); offset+=2; }
  461. for(var i=0; i<=nLeft; i++) { charset.push(first); first++; }
  462. }
  463. }
  464. else throw "error: unknown encoding format: " + format;
  465. return array;
  466. },*/
  467.  
  468. readCharset : function(data, offset, num)
  469. {
  470. var bin = Typr["B"];
  471. var charset = ['.notdef'];
  472. var format = data[offset]; offset++;
  473. if(format==0)
  474. {
  475. for(var i=0; i<num; i++)
  476. {
  477. var first = bin.readUshort(data, offset); offset+=2;
  478. charset.push(first);
  479. }
  480. }
  481. else if(format==1 || format==2)
  482. {
  483. while(charset.length<num)
  484. {
  485. var first = bin.readUshort(data, offset); offset+=2;
  486. var nLeft=0;
  487. if(format==1) { nLeft = data[offset]; offset++; }
  488. else { nLeft = bin.readUshort(data, offset); offset+=2; }
  489. for(var i=0; i<=nLeft; i++) { charset.push(first); first++; }
  490. }
  491. }
  492. else throw "error: format: " + format;
  493. return charset;
  494. },
  495.  
  496. readIndex : function(data, offset, inds)
  497. {
  498. var bin = Typr["B"];
  499. var count = bin.readUshort(data, offset)+1; offset+=2;
  500. var offsize = data[offset]; offset++;
  501. if (offsize==1) for(var i=0; i<count; i++) inds.push( data[offset+i] );
  502. else if(offsize==2) for(var i=0; i<count; i++) inds.push( bin.readUshort(data, offset+i*2) );
  503. else if(offsize==3) for(var i=0; i<count; i++) inds.push( bin.readUint (data, offset+i*3 - 1) & 0x00ffffff );
  504. else if(offsize==4) for(var i=0; i<count; i++) inds.push( bin.readUint (data, offset+i*4) );
  505. else if(count!=1) throw "unsupported offset size: " + offsize + ", count: " + count;
  506. offset += count*offsize;
  507. return offset-1;
  508. },
  509. getCharString : function(data, offset, o)
  510. {
  511. var bin = Typr["B"];
  512. var b0 = data[offset], b1 = data[offset+1], b2 = data[offset+2], b3 = data[offset+3], b4=data[offset+4];
  513. var vs = 1;
  514. var op=null, val=null;
  515. // operand
  516. if(b0<=20) { op = b0; vs=1; }
  517. if(b0==12) { op = b0*100+b1; vs=2; }
  518. //if(b0==19 || b0==20) { op = b0/*+" "+b1*/; vs=2; }
  519. if(21 <=b0 && b0<= 27) { op = b0; vs=1; }
  520. if(b0==28) { val = bin.readShort(data,offset+1); vs=3; }
  521. if(29 <=b0 && b0<= 31) { op = b0; vs=1; }
  522. if(32 <=b0 && b0<=246) { val = b0-139; vs=1; }
  523. if(247<=b0 && b0<=250) { val = (b0-247)*256+b1+108; vs=2; }
  524. if(251<=b0 && b0<=254) { val =-(b0-251)*256-b1-108; vs=2; }
  525. if(b0==255) { val = bin.readInt(data, offset+1)/0xffff; vs=5; }
  526. o.val = val!=null ? val : "o"+op;
  527. o.size = vs;
  528. },
  529. readCharString : function(data, offset, length)
  530. {
  531. var end = offset + length;
  532. var bin = Typr["B"];
  533. var arr = [];
  534. while(offset<end)
  535. {
  536. var b0 = data[offset], b1 = data[offset+1], b2 = data[offset+2], b3 = data[offset+3], b4=data[offset+4];
  537. var vs = 1;
  538. var op=null, val=null;
  539. // operand
  540. if(b0<=20) { op = b0; vs=1; }
  541. if(b0==12) { op = b0*100+b1; vs=2; }
  542. if(b0==19 || b0==20) { op = b0/*+" "+b1*/; vs=2; }
  543. if(21 <=b0 && b0<= 27) { op = b0; vs=1; }
  544. if(b0==28) { val = bin.readShort(data,offset+1); vs=3; }
  545. if(29 <=b0 && b0<= 31) { op = b0; vs=1; }
  546. if(32 <=b0 && b0<=246) { val = b0-139; vs=1; }
  547. if(247<=b0 && b0<=250) { val = (b0-247)*256+b1+108; vs=2; }
  548. if(251<=b0 && b0<=254) { val =-(b0-251)*256-b1-108; vs=2; }
  549. if(b0==255) { val = bin.readInt(data, offset+1)/0xffff; vs=5; }
  550. arr.push(val!=null ? val : "o"+op);
  551. offset += vs;
  552.  
  553. //var cv = arr[arr.length-1];
  554. //if(cv==undefined) throw "error";
  555. //console.log()
  556. }
  557. return arr;
  558. },
  559.  
  560. readDict : function(data, offset, end)
  561. {
  562. var bin = Typr["B"];
  563. //var dict = [];
  564. var dict = {};
  565. var carr = [];
  566. while(offset<end)
  567. {
  568. var b0 = data[offset], b1 = data[offset+1], b2 = data[offset+2], b3 = data[offset+3], b4=data[offset+4];
  569. var vs = 1;
  570. var key=null, val=null;
  571. // operand
  572. if(b0==28) { val = bin.readShort(data,offset+1); vs=3; }
  573. if(b0==29) { val = bin.readInt (data,offset+1); vs=5; }
  574. if(32 <=b0 && b0<=246) { val = b0-139; vs=1; }
  575. if(247<=b0 && b0<=250) { val = (b0-247)*256+b1+108; vs=2; }
  576. if(251<=b0 && b0<=254) { val =-(b0-251)*256-b1-108; vs=2; }
  577. if(b0==255) { val = bin.readInt(data, offset+1)/0xffff; vs=5; throw "unknown number"; }
  578. if(b0==30)
  579. {
  580. var nibs = [];
  581. vs = 1;
  582. while(true)
  583. {
  584. var b = data[offset+vs]; vs++;
  585. var nib0 = b>>4, nib1 = b&0xf;
  586. if(nib0 != 0xf) nibs.push(nib0); if(nib1!=0xf) nibs.push(nib1);
  587. if(nib1==0xf) break;
  588. }
  589. var s = "";
  590. var chars = [0,1,2,3,4,5,6,7,8,9,".","e","e-","reserved","-","endOfNumber"];
  591. for(var i=0; i<nibs.length; i++) s += chars[nibs[i]];
  592. //console.log(nibs);
  593. val = parseFloat(s);
  594. }
  595. if(b0<=21) // operator
  596. {
  597. var keys = ["version", "Notice", "FullName", "FamilyName", "Weight", "FontBBox", "BlueValues", "OtherBlues", "FamilyBlues","FamilyOtherBlues",
  598. "StdHW", "StdVW", "escape", "UniqueID", "XUID", "charset", "Encoding", "CharStrings", "Private", "Subrs",
  599. "defaultWidthX", "nominalWidthX"];
  600. key = keys[b0]; vs=1;
  601. if(b0==12) {
  602. var keys = [ "Copyright", "isFixedPitch", "ItalicAngle", "UnderlinePosition", "UnderlineThickness", "PaintType", "CharstringType", "FontMatrix", "StrokeWidth", "BlueScale",
  603. "BlueShift", "BlueFuzz", "StemSnapH", "StemSnapV", "ForceBold", "","", "LanguageGroup", "ExpansionFactor", "initialRandomSeed",
  604. "SyntheticBase", "PostScript", "BaseFontName", "BaseFontBlend", "","","", "","","",
  605. "ROS", "CIDFontVersion", "CIDFontRevision", "CIDFontType", "CIDCount", "UIDBase", "FDArray", "FDSelect", "FontName"];
  606. key = keys[b1]; vs=2;
  607. }
  608. }
  609. if(key!=null) { dict[key] = carr.length==1 ? carr[0] : carr; carr=[]; }
  610. else carr.push(val);
  611. offset += vs;
  612. }
  613. return dict;
  614. }
  615. };
  616.  
  617.  
  618. Typr["T"].cmap = {
  619. parseTab : function(data, offset, length)
  620. {
  621. var obj = {tables:[],ids:{},off:offset};
  622. data = new Uint8Array(data.buffer, offset, length);
  623. offset = 0;
  624.  
  625. var offset0 = offset;
  626. var bin = Typr["B"], rU = bin.readUshort, cmap = Typr["T"].cmap;
  627. var version = rU(data, offset); offset += 2;
  628. var numTables = rU(data, offset); offset += 2;
  629. //console.log(version, numTables);
  630. var offs = [];
  631. for(var i=0; i<numTables; i++)
  632. {
  633. var platformID = rU(data, offset); offset += 2;
  634. var encodingID = rU(data, offset); offset += 2;
  635. var noffset = bin.readUint(data, offset); offset += 4;
  636. var id = "p"+platformID+"e"+encodingID;
  637. //console.log("cmap subtable", platformID, encodingID, noffset);
  638. var tind = offs.indexOf(noffset);
  639. if(tind==-1)
  640. {
  641. tind = obj.tables.length;
  642. var subt = {};
  643. offs.push(noffset);
  644. //var time = Date.now();
  645. var format = subt.format = rU(data, noffset);
  646. if (format== 0) subt = cmap.parse0(data, noffset, subt);
  647. //else if(format== 2) subt.off = noffset;
  648. else if(format== 4) subt = cmap.parse4(data, noffset, subt);
  649. else if(format== 6) subt = cmap.parse6(data, noffset, subt);
  650. else if(format==12) subt = cmap.parse12(data,noffset, subt);
  651. //console.log(format, Date.now()-time);
  652. //else console.log("unknown format: "+format, platformID, encodingID, noffset);
  653. obj.tables.push(subt);
  654. }
  655. if(obj.ids[id]!=null) throw "multiple tables for one platform+encoding";
  656. obj.ids[id] = tind;
  657. }
  658. return obj;
  659. },
  660.  
  661. parse0 : function(data, offset, obj)
  662. {
  663. var bin = Typr["B"];
  664. offset += 2;
  665. var len = bin.readUshort(data, offset); offset += 2;
  666. var lang = bin.readUshort(data, offset); offset += 2;
  667. obj.map = [];
  668. for(var i=0; i<len-6; i++) obj.map.push(data[offset+i]);
  669. return obj;
  670. },
  671.  
  672. parse4 : function(data, offset, obj)
  673. {
  674. var bin = Typr["B"], rU = bin.readUshort, rUs = bin.readUshorts;
  675. var offset0 = offset;
  676. offset+=2;
  677. var length = rU(data, offset); offset+=2;
  678. var language = rU(data, offset); offset+=2;
  679. var segCountX2 = rU(data, offset); offset+=2;
  680. var segCount = segCountX2>>>1;
  681. obj.searchRange = rU(data, offset); offset+=2;
  682. obj.entrySelector = rU(data, offset); offset+=2;
  683. obj.rangeShift = rU(data, offset); offset+=2;
  684. obj.endCount = rUs(data, offset, segCount); offset += segCount*2;
  685. offset+=2;
  686. obj.startCount = rUs(data, offset, segCount); offset += segCount*2;
  687. obj.idDelta = [];
  688. for(var i=0; i<segCount; i++) {obj.idDelta.push(bin.readShort(data, offset)); offset+=2;}
  689. obj.idRangeOffset = rUs(data, offset, segCount); offset += segCount*2;
  690. obj.glyphIdArray = rUs(data, offset, ((offset0+length)-offset)>>>1); //offset += segCount*2;
  691. return obj;
  692. },
  693.  
  694. parse6 : function(data, offset, obj)
  695. {
  696. var bin = Typr["B"];
  697. var offset0 = offset;
  698. offset+=2;
  699. var length = bin.readUshort(data, offset); offset+=2;
  700. var language = bin.readUshort(data, offset); offset+=2;
  701. obj.firstCode = bin.readUshort(data, offset); offset+=2;
  702. var entryCount = bin.readUshort(data, offset); offset+=2;
  703. obj.glyphIdArray = [];
  704. for(var i=0; i<entryCount; i++) {obj.glyphIdArray.push(bin.readUshort(data, offset)); offset+=2;}
  705. return obj;
  706. },
  707.  
  708. parse12 : function(data, offset, obj)
  709. {
  710. var bin = Typr["B"], rU = bin.readUint;
  711. var offset0 = offset;
  712. offset+=4;
  713. var length = rU(data, offset); offset+=4;
  714. var lang = rU(data, offset); offset+=4;
  715. var nGroups= rU(data, offset)*3; offset+=4;
  716. var gps = obj.groups = new Uint32Array(nGroups);//new Uint32Array(data.slice(offset, offset+nGroups*12).buffer);
  717. for(var i=0; i<nGroups; i+=3) {
  718. gps[i ] = rU(data, offset+(i<<2) );
  719. gps[i+1] = rU(data, offset+(i<<2)+4);
  720. gps[i+2] = rU(data, offset+(i<<2)+8);
  721. }
  722. return obj;
  723. }
  724. };
  725.  
  726. Typr["T"].glyf = {
  727. parseTab : function(data, offset, length, font)
  728. {
  729. var obj = [], ng=font["maxp"]["numGlyphs"];
  730. for(var g=0; g<ng; g++) obj.push(null);
  731. return obj;
  732. },
  733.  
  734. _parseGlyf : function(font, g)
  735. {
  736. var bin = Typr["B"];
  737. var data = font["_data"], loca=font["loca"];
  738. if(loca[g]==loca[g+1]) return null;
  739. var offset = Typr["findTable"](data, "glyf", font["_offset"])[0] + loca[g];
  740. var gl = {};
  741. gl.noc = bin.readShort(data, offset); offset+=2; // number of contours
  742. gl.xMin = bin.readShort(data, offset); offset+=2;
  743. gl.yMin = bin.readShort(data, offset); offset+=2;
  744. gl.xMax = bin.readShort(data, offset); offset+=2;
  745. gl.yMax = bin.readShort(data, offset); offset+=2;
  746. if(gl.xMin>=gl.xMax || gl.yMin>=gl.yMax) return null;
  747. if(gl.noc>0)
  748. {
  749. gl.endPts = [];
  750. for(var i=0; i<gl.noc; i++) { gl.endPts.push(bin.readUshort(data,offset)); offset+=2; }
  751. var instructionLength = bin.readUshort(data,offset); offset+=2;
  752. if((data.length-offset)<instructionLength) return null;
  753. gl.instructions = bin.readBytes(data, offset, instructionLength); offset+=instructionLength;
  754. var crdnum = gl.endPts[gl.noc-1]+1;
  755. gl.flags = [];
  756. for(var i=0; i<crdnum; i++ )
  757. {
  758. var flag = data[offset]; offset++;
  759. gl.flags.push(flag);
  760. if((flag&8)!=0)
  761. {
  762. var rep = data[offset]; offset++;
  763. for(var j=0; j<rep; j++) { gl.flags.push(flag); i++; }
  764. }
  765. }
  766. gl.xs = [];
  767. for(var i=0; i<crdnum; i++) {
  768. var i8=((gl.flags[i]&2)!=0), same=((gl.flags[i]&16)!=0);
  769. if(i8) { gl.xs.push(same ? data[offset] : -data[offset]); offset++; }
  770. else
  771. {
  772. if(same) gl.xs.push(0);
  773. else { gl.xs.push(bin.readShort(data, offset)); offset+=2; }
  774. }
  775. }
  776. gl.ys = [];
  777. for(var i=0; i<crdnum; i++) {
  778. var i8=((gl.flags[i]&4)!=0), same=((gl.flags[i]&32)!=0);
  779. if(i8) { gl.ys.push(same ? data[offset] : -data[offset]); offset++; }
  780. else
  781. {
  782. if(same) gl.ys.push(0);
  783. else { gl.ys.push(bin.readShort(data, offset)); offset+=2; }
  784. }
  785. }
  786. var x = 0, y = 0;
  787. for(var i=0; i<crdnum; i++) { x += gl.xs[i]; y += gl.ys[i]; gl.xs[i]=x; gl.ys[i]=y; }
  788. //console.log(endPtsOfContours, instructionLength, instructions, flags, xCoordinates, yCoordinates);
  789. }
  790. else
  791. {
  792. var ARG_1_AND_2_ARE_WORDS = 1<<0;
  793. var ARGS_ARE_XY_VALUES = 1<<1;
  794. var ROUND_XY_TO_GRID = 1<<2;
  795. var WE_HAVE_A_SCALE = 1<<3;
  796. var RESERVED = 1<<4;
  797. var MORE_COMPONENTS = 1<<5;
  798. var WE_HAVE_AN_X_AND_Y_SCALE= 1<<6;
  799. var WE_HAVE_A_TWO_BY_TWO = 1<<7;
  800. var WE_HAVE_INSTRUCTIONS = 1<<8;
  801. var USE_MY_METRICS = 1<<9;
  802. var OVERLAP_COMPOUND = 1<<10;
  803. var SCALED_COMPONENT_OFFSET = 1<<11;
  804. var UNSCALED_COMPONENT_OFFSET = 1<<12;
  805. gl.parts = [];
  806. var flags;
  807. do {
  808. flags = bin.readUshort(data, offset); offset += 2;
  809. var part = { m:{a:1,b:0,c:0,d:1,tx:0,ty:0}, p1:-1, p2:-1 }; gl.parts.push(part);
  810. part.glyphIndex = bin.readUshort(data, offset); offset += 2;
  811. if ( flags & ARG_1_AND_2_ARE_WORDS) {
  812. var arg1 = bin.readShort(data, offset); offset += 2;
  813. var arg2 = bin.readShort(data, offset); offset += 2;
  814. } else {
  815. var arg1 = bin.readInt8(data, offset); offset ++;
  816. var arg2 = bin.readInt8(data, offset); offset ++;
  817. }
  818. if(flags & ARGS_ARE_XY_VALUES) { part.m.tx = arg1; part.m.ty = arg2; }
  819. else { part.p1=arg1; part.p2=arg2; }
  820. //part.m.tx = arg1; part.m.ty = arg2;
  821. //else { throw "params are not XY values"; }
  822. if ( flags & WE_HAVE_A_SCALE ) {
  823. part.m.a = part.m.d = bin.readF2dot14(data, offset); offset += 2;
  824. } else if ( flags & WE_HAVE_AN_X_AND_Y_SCALE ) {
  825. part.m.a = bin.readF2dot14(data, offset); offset += 2;
  826. part.m.d = bin.readF2dot14(data, offset); offset += 2;
  827. } else if ( flags & WE_HAVE_A_TWO_BY_TWO ) {
  828. part.m.a = bin.readF2dot14(data, offset); offset += 2;
  829. part.m.b = bin.readF2dot14(data, offset); offset += 2;
  830. part.m.c = bin.readF2dot14(data, offset); offset += 2;
  831. part.m.d = bin.readF2dot14(data, offset); offset += 2;
  832. }
  833. } while ( flags & MORE_COMPONENTS )
  834. if (flags & WE_HAVE_INSTRUCTIONS){
  835. var numInstr = bin.readUshort(data, offset); offset += 2;
  836. gl.instr = [];
  837. for(var i=0; i<numInstr; i++) { gl.instr.push(data[offset]); offset++; }
  838. }
  839. }
  840. return gl;
  841. }
  842. };
  843.  
  844. Typr["T"].head = {
  845. parseTab : function(data, offset, length)
  846. {
  847. var bin = Typr["B"];
  848. var obj = {};
  849. var tableVersion = bin.readFixed(data, offset); offset += 4;
  850. obj["fontRevision"] = bin.readFixed(data, offset); offset += 4;
  851. var checkSumAdjustment = bin.readUint(data, offset); offset += 4;
  852. var magicNumber = bin.readUint(data, offset); offset += 4;
  853. obj["flags"] = bin.readUshort(data, offset); offset += 2;
  854. obj["unitsPerEm"] = bin.readUshort(data, offset); offset += 2;
  855. obj["created"] = bin.readUint64(data, offset); offset += 8;
  856. obj["modified"] = bin.readUint64(data, offset); offset += 8;
  857. obj["xMin"] = bin.readShort(data, offset); offset += 2;
  858. obj["yMin"] = bin.readShort(data, offset); offset += 2;
  859. obj["xMax"] = bin.readShort(data, offset); offset += 2;
  860. obj["yMax"] = bin.readShort(data, offset); offset += 2;
  861. obj["macStyle"] = bin.readUshort(data, offset); offset += 2;
  862. obj["lowestRecPPEM"] = bin.readUshort(data, offset); offset += 2;
  863. obj["fontDirectionHint"] = bin.readShort(data, offset); offset += 2;
  864. obj["indexToLocFormat"] = bin.readShort(data, offset); offset += 2;
  865. obj["glyphDataFormat"] = bin.readShort(data, offset); offset += 2;
  866. return obj;
  867. }
  868. };
  869.  
  870. Typr["T"].hhea = {
  871. parseTab : function(data, offset, length)
  872. {
  873. var bin = Typr["B"];
  874. var obj = {};
  875. var tableVersion = bin.readFixed(data, offset); offset += 4;
  876. var keys = ["ascender","descender","lineGap",
  877. "advanceWidthMax","minLeftSideBearing","minRightSideBearing","xMaxExtent",
  878. "caretSlopeRise","caretSlopeRun","caretOffset",
  879. "res0","res1","res2","res3",
  880. "metricDataFormat","numberOfHMetrics" ];
  881. for(var i=0; i< keys.length; i++) {
  882. var key = keys[i];
  883. var func = (key=="advanceWidthMax" || key=="numberOfHMetrics")?bin.readUshort:bin.readShort;
  884. obj[key]=func(data,offset+i*2);
  885. }
  886. return obj;
  887. }
  888. };
  889.  
  890.  
  891. Typr["T"].hmtx = {
  892. parseTab : function(data, offset, length, font)
  893. {
  894. var bin = Typr["B"];
  895. var aWidth = [];
  896. var lsBearing = [];
  897. var nG = font["maxp"]["numGlyphs"], nH = font["hhea"]["numberOfHMetrics"];
  898. var aw = 0, lsb = 0, i=0;
  899. 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++; }
  900. while(i<nG) { aWidth.push(aw); lsBearing.push(lsb); i++; }
  901. return {aWidth:aWidth, lsBearing:lsBearing};
  902. }
  903. };
  904.  
  905.  
  906. Typr["T"].kern = {
  907. parseTab : function(data, offset, length, font)
  908. {
  909. var bin = Typr["B"], kern=Typr["T"].kern;
  910. var version = bin.readUshort(data, offset);
  911. if(version==1) return kern.parseV1(data, offset, length, font);
  912. var nTables = bin.readUshort(data, offset+2); offset+=4;
  913. var map = {glyph1: [], rval:[]};
  914. for(var i=0; i<nTables; i++)
  915. {
  916. offset+=2; // skip version
  917. var length = bin.readUshort(data, offset); offset+=2;
  918. var coverage = bin.readUshort(data, offset); offset+=2;
  919. var format = coverage>>>8;
  920. /* I have seen format 128 once, that's why I do */ format &= 0xf;
  921. if(format==0) offset = kern.readFormat0(data, offset, map);
  922. //else throw "unknown kern table format: "+format;
  923. }
  924. return map;
  925. },
  926.  
  927. parseV1 : function(data, offset, length, font)
  928. {
  929. var bin = Typr["B"], kern=Typr["T"].kern;
  930. var version = bin.readFixed(data, offset); // 0x00010000
  931. var nTables = bin.readUint (data, offset+4); offset+=8;
  932. var map = {glyph1: [], rval:[]};
  933. for(var i=0; i<nTables; i++)
  934. {
  935. var length = bin.readUint(data, offset); offset+=4;
  936. var coverage = bin.readUshort(data, offset); offset+=2;
  937. var tupleIndex = bin.readUshort(data, offset); offset+=2;
  938. var format = coverage&0xff;
  939. if(format==0) offset = kern.readFormat0(data, offset, map);
  940. //else throw "unknown kern table format: "+format;
  941. }
  942. return map;
  943. },
  944.  
  945. readFormat0 : function(data, offset, map)
  946. {
  947. var bin = Typr["B"], rUs = bin.readUshort;
  948. var pleft = -1;
  949. var nPairs = rUs(data, offset);
  950. var searchRange = rUs(data, offset+2);
  951. var entrySelector = rUs(data, offset+4);
  952. var rangeShift = rUs(data, offset+6); offset+=8;
  953. for(var j=0; j<nPairs; j++)
  954. {
  955. var left = rUs(data, offset); offset+=2;
  956. var right = rUs(data, offset); offset+=2;
  957. var value = bin.readShort (data, offset); offset+=2;
  958. if(left!=pleft) { map.glyph1.push(left); map.rval.push({ glyph2:[], vals:[] }) }
  959. var rval = map.rval[map.rval.length-1];
  960. rval.glyph2.push(right); rval.vals.push(value);
  961. pleft = left;
  962. }
  963. return offset;
  964. }
  965. };
  966.  
  967.  
  968. Typr["T"].loca = {
  969. parseTab : function(data, offset, length, font)
  970. {
  971. var bin = Typr["B"];
  972. var obj = [];
  973. var ver = font["head"]["indexToLocFormat"];
  974. var len = font["maxp"]["numGlyphs"]+1;
  975. if(ver==0) for(var i=0; i<len; i++) obj.push(bin.readUshort(data, offset+(i<<1))<<1);
  976. if(ver==1) for(var i=0; i<len; i++) obj.push(bin.readUint (data, offset+(i<<2)) );
  977. return obj;
  978. }
  979. };
  980.  
  981.  
  982. Typr["T"].maxp = {
  983. parseTab : function(data, offset, length)
  984. {
  985. //console.log(data.length, offset, length);
  986. var bin = Typr["B"], rU=bin.readUshort;
  987. var obj = {};
  988. // both versions 0.5 and 1.0
  989. var ver = bin.readUint(data, offset); offset += 4;
  990. obj["numGlyphs"] = rU(data, offset); offset += 2;
  991. // only 1.0
  992. /*
  993. if(ver == 0x00010000) {
  994. obj.maxPoints = rU(data, offset); offset += 2;
  995. obj.maxContours = rU(data, offset); offset += 2;
  996. obj.maxCompositePoints = rU(data, offset); offset += 2;
  997. obj.maxCompositeContours = rU(data, offset); offset += 2;
  998. obj.maxZones = rU(data, offset); offset += 2;
  999. obj.maxTwilightPoints = rU(data, offset); offset += 2;
  1000. obj.maxStorage = rU(data, offset); offset += 2;
  1001. obj.maxFunctionDefs = rU(data, offset); offset += 2;
  1002. obj.maxInstructionDefs = rU(data, offset); offset += 2;
  1003. obj.maxStackElements = rU(data, offset); offset += 2;
  1004. obj.maxSizeOfInstructions = rU(data, offset); offset += 2;
  1005. obj.maxComponentElements = rU(data, offset); offset += 2;
  1006. obj.maxComponentDepth = rU(data, offset); offset += 2;
  1007. }
  1008. */
  1009. return obj;
  1010. }
  1011. };
  1012.  
  1013.  
  1014. Typr["T"].name = {
  1015. parseTab : function(data, offset, length)
  1016. {
  1017. var bin = Typr["B"];
  1018. var obj = {};
  1019. var format = bin.readUshort(data, offset); offset += 2;
  1020. var count = bin.readUshort(data, offset); offset += 2;
  1021. var stringOffset = bin.readUshort(data, offset); offset += 2;
  1022. //console.log(format,count);
  1023. var names = [
  1024. "copyright",
  1025. "fontFamily",
  1026. "fontSubfamily",
  1027. "ID",
  1028. "fullName",
  1029. "version",
  1030. "postScriptName",
  1031. "trademark",
  1032. "manufacturer",
  1033. "designer",
  1034. "description",
  1035. "urlVendor",
  1036. "urlDesigner",
  1037. "licence",
  1038. "licenceURL",
  1039. "---",
  1040. "typoFamilyName",
  1041. "typoSubfamilyName",
  1042. "compatibleFull",
  1043. "sampleText",
  1044. "postScriptCID",
  1045. "wwsFamilyName",
  1046. "wwsSubfamilyName",
  1047. "lightPalette",
  1048. "darkPalette"
  1049. ];
  1050. var offset0 = offset;
  1051. var rU = bin.readUshort;
  1052. for(var i=0; i<count; i++)
  1053. {
  1054. var platformID = rU(data, offset); offset += 2;
  1055. var encodingID = rU(data, offset); offset += 2;
  1056. var languageID = rU(data, offset); offset += 2;
  1057. var nameID = rU(data, offset); offset += 2;
  1058. var slen = rU(data, offset); offset += 2;
  1059. var noffset = rU(data, offset); offset += 2;
  1060. //console.log(platformID, encodingID, languageID.toString(16), nameID, length, noffset);
  1061. var soff = offset0 + count*12 + noffset;
  1062. var str;
  1063. if(false){}
  1064. else if(platformID == 0) str = bin.readUnicode(data, soff, slen/2);
  1065. else if(platformID == 3 && encodingID == 0) str = bin.readUnicode(data, soff, slen/2);
  1066. else if(encodingID == 0) str = bin.readASCII (data, soff, slen);
  1067. else if(encodingID == 1) str = bin.readUnicode(data, soff, slen/2);
  1068. else if(encodingID == 3) str = bin.readUnicode(data, soff, slen/2);
  1069. else if(encodingID == 4) str = bin.readUnicode(data, soff, slen/2);
  1070. else if(encodingID ==10) str = bin.readUnicode(data, soff, slen/2);
  1071. else if(platformID == 1) { str = bin.readASCII(data, soff, slen); console.log("reading unknown MAC encoding "+encodingID+" as ASCII") }
  1072. else {
  1073. console.log("unknown encoding "+encodingID + ", platformID: "+platformID);
  1074. str = bin.readASCII(data, soff, slen);
  1075. }
  1076. var tid = "p"+platformID+","+(languageID).toString(16);//Typr._platforms[platformID];
  1077. if(obj[tid]==null) obj[tid] = {};
  1078. obj[tid][names[nameID]] = str;
  1079. obj[tid]["_lang"] = languageID;
  1080. //console.log(tid, obj[tid]);
  1081. }
  1082. /*
  1083. if(format == 1)
  1084. {
  1085. var langTagCount = bin.readUshort(data, offset); offset += 2;
  1086. for(var i=0; i<langTagCount; i++)
  1087. {
  1088. var length = bin.readUshort(data, offset); offset += 2;
  1089. var noffset = bin.readUshort(data, offset); offset += 2;
  1090. }
  1091. }
  1092. */
  1093. //console.log(obj);
  1094. var psn = "postScriptName";
  1095. for(var p in obj) if(obj[p][psn]!=null && obj[p]["_lang"]==0x0409) return obj[p]; // United States
  1096. for(var p in obj) if(obj[p][psn]!=null && obj[p]["_lang"]==0x0000) return obj[p]; // Universal
  1097. for(var p in obj) if(obj[p][psn]!=null && obj[p]["_lang"]==0x0c0c) return obj[p]; // Canada
  1098. for(var p in obj) if(obj[p][psn]!=null) return obj[p];
  1099. var out;
  1100. for(var p in obj) { out=obj[p]; break; }
  1101. console.log("returning name table with languageID "+ out._lang);
  1102. if(out[psn]==null && out["ID"]!=null) out[psn]=out["ID"];
  1103. return out;
  1104. }
  1105. }
  1106.  
  1107. Typr["T"].OS2 = {
  1108. parseTab : function(data, offset, length)
  1109. {
  1110. var bin = Typr["B"];
  1111. var ver = bin.readUshort(data, offset); offset += 2;
  1112. var OS2 = Typr["T"].OS2;
  1113. var obj = {};
  1114. if (ver==0) OS2.version0(data, offset, obj);
  1115. else if(ver==1) OS2.version1(data, offset, obj);
  1116. else if(ver==2 || ver==3 || ver==4) OS2.version2(data, offset, obj);
  1117. else if(ver==5) OS2.version5(data, offset, obj);
  1118. else throw "unknown OS/2 table version: "+ver;
  1119. return obj;
  1120. },
  1121.  
  1122. version0 : function(data, offset, obj)
  1123. {
  1124. var bin = Typr["B"];
  1125. obj["xAvgCharWidth"] = bin.readShort(data, offset); offset += 2;
  1126. obj["usWeightClass"] = bin.readUshort(data, offset); offset += 2;
  1127. obj["usWidthClass"] = bin.readUshort(data, offset); offset += 2;
  1128. obj["fsType"] = bin.readUshort(data, offset); offset += 2;
  1129. obj["ySubscriptXSize"] = bin.readShort(data, offset); offset += 2;
  1130. obj["ySubscriptYSize"] = bin.readShort(data, offset); offset += 2;
  1131. obj["ySubscriptXOffset"] = bin.readShort(data, offset); offset += 2;
  1132. obj["ySubscriptYOffset"] = bin.readShort(data, offset); offset += 2;
  1133. obj["ySuperscriptXSize"] = bin.readShort(data, offset); offset += 2;
  1134. obj["ySuperscriptYSize"] = bin.readShort(data, offset); offset += 2;
  1135. obj["ySuperscriptXOffset"] = bin.readShort(data, offset); offset += 2;
  1136. obj["ySuperscriptYOffset"] = bin.readShort(data, offset); offset += 2;
  1137. obj["yStrikeoutSize"] = bin.readShort(data, offset); offset += 2;
  1138. obj["yStrikeoutPosition"] = bin.readShort(data, offset); offset += 2;
  1139. obj["sFamilyClass"] = bin.readShort(data, offset); offset += 2;
  1140. obj["panose"] = bin.readBytes(data, offset, 10); offset += 10;
  1141. obj["ulUnicodeRange1"] = bin.readUint(data, offset); offset += 4;
  1142. obj["ulUnicodeRange2"] = bin.readUint(data, offset); offset += 4;
  1143. obj["ulUnicodeRange3"] = bin.readUint(data, offset); offset += 4;
  1144. obj["ulUnicodeRange4"] = bin.readUint(data, offset); offset += 4;
  1145. obj["achVendID"] = bin.readASCII(data, offset, 4); offset += 4;
  1146. obj["fsSelection"] = bin.readUshort(data, offset); offset += 2;
  1147. obj["usFirstCharIndex"] = bin.readUshort(data, offset); offset += 2;
  1148. obj["usLastCharIndex"] = bin.readUshort(data, offset); offset += 2;
  1149. obj["sTypoAscender"] = bin.readShort(data, offset); offset += 2;
  1150. obj["sTypoDescender"] = bin.readShort(data, offset); offset += 2;
  1151. obj["sTypoLineGap"] = bin.readShort(data, offset); offset += 2;
  1152. obj["usWinAscent"] = bin.readUshort(data, offset); offset += 2;
  1153. obj["usWinDescent"] = bin.readUshort(data, offset); offset += 2;
  1154. return offset;
  1155. },
  1156.  
  1157. version1 : function(data, offset, obj)
  1158. {
  1159. var bin = Typr["B"];
  1160. offset = Typr["T"].OS2.version0(data, offset, obj);
  1161. obj["ulCodePageRange1"] = bin.readUint(data, offset); offset += 4;
  1162. obj["ulCodePageRange2"] = bin.readUint(data, offset); offset += 4;
  1163. return offset;
  1164. },
  1165.  
  1166. version2 : function(data, offset, obj)
  1167. {
  1168. var bin = Typr["B"], rU=bin.readUshort;
  1169. offset = Typr["T"].OS2.version1(data, offset, obj);
  1170. obj["sxHeight"] = bin.readShort(data, offset); offset += 2;
  1171. obj["sCapHeight"] = bin.readShort(data, offset); offset += 2;
  1172. obj["usDefault"] = rU(data, offset); offset += 2;
  1173. obj["usBreak"] = rU(data, offset); offset += 2;
  1174. obj["usMaxContext"] = rU(data, offset); offset += 2;
  1175. return offset;
  1176. },
  1177.  
  1178. version5 : function(data, offset, obj)
  1179. {
  1180. var rU = Typr["B"].readUshort;
  1181. offset = Typr["T"].OS2.version2(data, offset, obj);
  1182.  
  1183. obj["usLowerOpticalPointSize"] = rU(data, offset); offset += 2;
  1184. obj["usUpperOpticalPointSize"] = rU(data, offset); offset += 2;
  1185. return offset;
  1186. }
  1187. }
  1188.  
  1189. Typr["T"].post = {
  1190. parseTab : function(data, offset, length)
  1191. {
  1192. var bin = Typr["B"];
  1193. var obj = {};
  1194. obj["version"] = bin.readFixed(data, offset); offset+=4;
  1195. obj["italicAngle"] = bin.readFixed(data, offset); offset+=4;
  1196. obj["underlinePosition"] = bin.readShort(data, offset); offset+=2;
  1197. obj["underlineThickness"] = bin.readShort(data, offset); offset+=2;
  1198.  
  1199. return obj;
  1200. }
  1201. };
  1202. Typr["T"].SVG = {
  1203. parseTab : function(data, offset, length)
  1204. {
  1205. var bin = Typr["B"];
  1206. var obj = { entries: []};
  1207.  
  1208. var offset0 = offset;
  1209.  
  1210. var tableVersion = bin.readUshort(data, offset); offset += 2;
  1211. var svgDocIndexOffset = bin.readUint(data, offset); offset += 4;
  1212. var reserved = bin.readUint(data, offset); offset += 4;
  1213.  
  1214. offset = svgDocIndexOffset + offset0;
  1215.  
  1216. var numEntries = bin.readUshort(data, offset); offset += 2;
  1217.  
  1218. for(var i=0; i<numEntries; i++)
  1219. {
  1220. var startGlyphID = bin.readUshort(data, offset); offset += 2;
  1221. var endGlyphID = bin.readUshort(data, offset); offset += 2;
  1222. var svgDocOffset = bin.readUint (data, offset); offset += 4;
  1223. var svgDocLength = bin.readUint (data, offset); offset += 4;
  1224.  
  1225. var sbuf = new Uint8Array(data.buffer, offset0 + svgDocOffset + svgDocIndexOffset, svgDocLength);
  1226. var svg = bin.readUTF8(sbuf, 0, sbuf.length);
  1227. for(var f=startGlyphID; f<=endGlyphID; f++) {
  1228. obj.entries[f] = svg;
  1229. }
  1230. }
  1231. return obj;
  1232. }
  1233. };
  1234.  
  1235.  
  1236.  
  1237.  
  1238.  
  1239.  
  1240. Typr["U"] = {
  1241. "shape" : function(font,str,ltr) {
  1242. var getGlyphPosition = function(font, gls,i1,ltr)
  1243. {
  1244. var g1=gls[i1],g2=gls[i1+1], kern=font["kern"];
  1245. if(kern) {
  1246. var ind1 = kern.glyph1.indexOf(g1);
  1247. if(ind1!=-1)
  1248. {
  1249. var ind2 = kern.rval[ind1].glyph2.indexOf(g2);
  1250. if(ind2!=-1) return [0,0,kern.rval[ind1].vals[ind2],0];
  1251. }
  1252. }
  1253. //console.log("no kern");
  1254. return [0,0,0,0];
  1255. }
  1256. var gls = [];
  1257. for(var i=0; i<str.length; i++) {
  1258. var cc = str.codePointAt(i); if(cc>0xffff) i++;
  1259. gls.push(Typr["U"]["codeToGlyph"](font, cc));
  1260. }
  1261. var shape = [];
  1262. var x = 0, y = 0;
  1263. for(var i=0; i<gls.length; i++) {
  1264. var padj = getGlyphPosition(font, gls,i,ltr);
  1265. var gid = gls[i];
  1266. var ax=font["hmtx"].aWidth[gid]+padj[2];
  1267. shape.push({"g":gid, "cl":i, "dx":0, "dy":0, "ax":ax, "ay":0});
  1268. x+=ax;
  1269. }
  1270. return shape;
  1271. },
  1272. "shapeToPath" : function(font,shape,clr) {
  1273. var tpath = {cmds:[], crds:[]};
  1274. var x = 0, y = 0;
  1275. for(var i=0; i<shape.length; i++) {
  1276. var it = shape[i]
  1277. var path = Typr["U"]["glyphToPath"](font, it["g"]), crds=path["crds"];
  1278. for(var j=0; j<crds.length; j+=2) {
  1279. tpath.crds.push(crds[j ] + x + it["dx"]);
  1280. tpath.crds.push(crds[j+1] + y + it["dy"]);
  1281. }
  1282. if(clr) tpath.cmds.push(clr);
  1283. for(var j=0; j<path["cmds"].length; j++) tpath.cmds.push(path["cmds"][j]);
  1284. var clen = tpath.cmds.length;
  1285. if(clr) if(clen!=0 && tpath.cmds[clen-1]!="X") tpath.cmds.push("X"); // SVG fonts might contain "X". Then, nothing would stroke non-SVG glyphs.
  1286. x += it["ax"]; y+= it["ay"];
  1287. }
  1288. return {"cmds":tpath.cmds, "crds":tpath.crds};
  1289. },
  1290.  
  1291. "codeToGlyph" : function(font, code)
  1292. {
  1293. var cmap = font["cmap"];
  1294. //console.log(cmap);
  1295. // "p3e10" for NotoEmoji-Regular.ttf
  1296. var tind = -1, pps=["p3e10","p0e4","p3e1","p1e0","p0e3","p0e1"/*,"p3e3"*/];
  1297. for(var i=0; i<pps.length; i++) if(cmap.ids[pps[i]]!=null) { tind=cmap.ids[pps[i]]; break; }
  1298. if(tind==-1) throw "no familiar platform and encoding!";
  1299. // find the greatest index with a value <=v
  1300. var arrSearch = function(arr, k, v) {
  1301. var l=0, r=Math.floor(arr.length/k);
  1302. while(l+1!=r) { var mid = l + ((r-l)>>>1); if(arr[mid*k]<=v) l=mid; else r=mid; }
  1303. return l*k;
  1304. }
  1305. var tab = cmap.tables[tind], fmt=tab.format, gid = -1; //console.log(fmt); throw "e";
  1306. if(fmt==0) {
  1307. if(code>=tab.map.length) gid = 0;
  1308. else gid = tab.map[code];
  1309. }
  1310. /*else if(fmt==2) {
  1311. var data=font["_data"], off = cmap.off+tab.off+6, bin=Typr["B"];
  1312. var shKey = bin.readUshort(data,off + 2*(code>>>8));
  1313. var shInd = off + 256*2 + shKey*8;
  1314. var firstCode = bin.readUshort(data,shInd);
  1315. var entryCount= bin.readUshort(data,shInd+2);
  1316. var idDelta = bin.readShort (data,shInd+4);
  1317. var idRangeOffset = bin.readUshort(data,shInd+6);
  1318. if(firstCode<=code && code<=firstCode+entryCount) {
  1319. // not completely correct
  1320. gid = bin.readUshort(data, shInd+6+idRangeOffset + (code&255)*2);
  1321. }
  1322. else gid=0;
  1323. //if(code>256) console.log(code,(code>>>8),shKey,firstCode,entryCount,idDelta,idRangeOffset);
  1324. //throw "e";
  1325. //console.log(tab, bin.readUshort(data,off));
  1326. //throw "e";
  1327. }*/
  1328. else if(fmt==4) {
  1329. var sind = -1, ec = tab.endCount;
  1330. if(code>ec[ec.length-1]) sind=-1;
  1331. else {
  1332. // smallest index with code <= value
  1333. sind = arrSearch(ec,1,code);
  1334. if(ec[sind]<code) sind++;
  1335. }
  1336. if(sind==-1) gid = 0;
  1337. else if(code<tab.startCount[sind]) gid = 0;
  1338. else {
  1339. var gli = 0;
  1340. if(tab.idRangeOffset[sind]!=0) gli = tab.glyphIdArray[(code-tab.startCount[sind]) + (tab.idRangeOffset[sind]>>1) - (tab.idRangeOffset.length-sind)];
  1341. else gli = code + tab.idDelta[sind];
  1342. gid = (gli & 0xFFFF);
  1343. }
  1344. }
  1345. else if(fmt==6) {
  1346. var off = code-tab.firstCode, arr=tab.glyphIdArray;
  1347. if(off<0 || off>=arr.length) gid=0;
  1348. else gid = arr[off];
  1349. }
  1350. else if(fmt==12) {
  1351. var grp = tab.groups; //console.log(grp); throw "e";
  1352. if(code>grp[grp.length-2]) gid = 0;
  1353. else {
  1354. var i = arrSearch(grp,3,code);
  1355. if(grp[i]<=code && code<=grp[i+1]) { gid = grp[i+2] + (code-grp[i]); }
  1356. if(gid==-1) gid=0;
  1357. }
  1358. }
  1359. else throw "unknown cmap table format "+tab.format;
  1360. //*
  1361. var SVG = font["SVG "], loca = font["loca"];
  1362. // if the font claims to have a Glyph for a character, but the glyph is empty, and the character is not "white", it is a lie!
  1363. if(gid!=0 && font["CFF "]==null && (SVG==null || SVG.entries[gid]==null) && loca[gid]==loca[gid+1] // loca not present in CFF or SVG fonts
  1364. && [0x9,0xa,0xb,0xc,0xd,0x20,0x85,0xa0,0x1680,0x2028,0x2029,0x202f,0x3000,
  1365. 0x180e,0x200b,0x200c,0x200d,0x2060,0xfeff].indexOf(code)==-1 && !(0x2000<=code && code<=0x200a)) gid=0;
  1366. //*/
  1367. return gid;
  1368. },
  1369.  
  1370. "glyphToPath" : function(font, gid)
  1371. {
  1372. var path = { cmds:[], crds:[] };
  1373. var SVG = font["SVG "], CFF = font["CFF "];
  1374. var U = Typr["U"];
  1375. if(SVG && SVG.entries[gid]) {
  1376. var p = SVG.entries[gid];
  1377. if(p!=null) {
  1378. if(typeof p == "string") { p = U["SVG"].toPath(p); SVG.entries[gid]=p; }
  1379. path=p;
  1380. }
  1381. }
  1382. else if(CFF) {
  1383. var pdct = CFF["Private"];
  1384. var state = {x:0,y:0,stack:[],nStems:0,haveWidth:false,width: pdct ? pdct["defaultWidthX"] : 0,open:false};
  1385. if(CFF["ROS"]) {
  1386. var gi = 0;
  1387. while(CFF["FDSelect"][gi+2]<=gid) gi+=2;
  1388. pdct = CFF["FDArray"][CFF["FDSelect"][gi+1]]["Private"];
  1389. }
  1390. U["_drawCFF"](CFF["CharStrings"][gid], state, CFF, pdct, path);
  1391. }
  1392. else if(font["glyf"]) { U["_drawGlyf"](gid, font, path); }
  1393. return {"cmds":path.cmds, "crds":path.crds};
  1394. },
  1395.  
  1396. "_drawGlyf" : function(gid, font, path)
  1397. {
  1398. var gl = font["glyf"][gid];
  1399. if(gl==null) gl = font["glyf"][gid] = Typr["T"].glyf._parseGlyf(font, gid);
  1400. if(gl!=null){
  1401. if(gl.noc>-1) Typr["U"]["_simpleGlyph"](gl, path);
  1402. else Typr["U"]["_compoGlyph"] (gl, font, path);
  1403. }
  1404. },
  1405. "_simpleGlyph" : function(gl, p)
  1406. {
  1407. var P = Typr["U"]["P"];
  1408. for(var c=0; c<gl.noc; c++) {
  1409. var i0 = (c==0) ? 0 : (gl.endPts[c-1] + 1);
  1410. var il = gl.endPts[c];
  1411. for(var i=i0; i<=il; i++) {
  1412. var pr = (i==i0)?il:(i-1);
  1413. var nx = (i==il)?i0:(i+1);
  1414. var onCurve = gl.flags[i]&1;
  1415. var prOnCurve = gl.flags[pr]&1;
  1416. var nxOnCurve = gl.flags[nx]&1;
  1417. var x = gl.xs[i], y = gl.ys[i];
  1418. if(i==i0) {
  1419. if(onCurve) {
  1420. if(prOnCurve) P.MoveTo(p, gl.xs[pr], gl.ys[pr]);
  1421. else { P.MoveTo(p,x,y); continue; /* will do CurveTo at il */ }
  1422. }
  1423. else {
  1424. if(prOnCurve) P.MoveTo(p, gl.xs[pr], gl.ys[pr] );
  1425. else P.MoveTo(p, Math.floor((gl.xs[pr]+x)*0.5), Math.floor((gl.ys[pr]+y)*0.5) );
  1426. }
  1427. }
  1428. if(onCurve) {
  1429. if(prOnCurve) P.LineTo(p,x,y);
  1430. }
  1431. else {
  1432. if(nxOnCurve) P.qCurveTo(p, x, y, gl.xs[nx], gl.ys[nx]);
  1433. else P.qCurveTo(p, x, y, Math.floor((x+gl.xs[nx])*0.5), Math.floor((y+gl.ys[nx])*0.5) );
  1434. }
  1435. }
  1436. P.ClosePath(p);
  1437. }
  1438. },
  1439. "_compoGlyph" : function(gl, font, p) {
  1440. for(var j=0; j<gl.parts.length; j++) {
  1441. var path = { cmds:[], crds:[] };
  1442. var prt = gl.parts[j];
  1443. Typr["U"]["_drawGlyf"](prt.glyphIndex, font, path);
  1444. var m = prt.m;
  1445. for(var i=0; i<path.crds.length; i+=2) {
  1446. var x = path.crds[i ], y = path.crds[i+1];
  1447. p.crds.push(x*m.a + y*m.b + m.tx);
  1448. p.crds.push(x*m.c + y*m.d + m.ty);
  1449. }
  1450. for(var i=0; i<path.cmds.length; i++) p.cmds.push(path.cmds[i]);
  1451. }
  1452. },
  1453.  
  1454. "pathToSVG" : function(path, prec)
  1455. {
  1456. var cmds = path["cmds"], crds = path["crds"];
  1457. if(prec==null) prec = 5;
  1458. var out = [], co = 0, lmap = {"M":2,"L":2,"Q":4,"C":6};
  1459. for(var i=0; i<cmds.length; i++)
  1460. {
  1461. var cmd = cmds[i], cn = co+(lmap[cmd]?lmap[cmd]:0);
  1462. out.push(cmd);
  1463. while(co<cn) { var c = crds[co++]; out.push(parseFloat(c.toFixed(prec))+(co==cn?"":" ")); }
  1464. }
  1465. return out.join("");
  1466. },
  1467. "SVGToPath" : function(d) {
  1468. var pth = {cmds:[], crds:[]};
  1469. Typr["U"]["SVG"].svgToPath(d, pth);
  1470. return {"cmds":pth.cmds, "crds":pth.crds};
  1471. },
  1472.  
  1473. "pathToContext" : function(path, ctx) {
  1474. var c = 0, cmds = path["cmds"], crds = path["crds"];
  1475. for(var j=0; j<cmds.length; j++) {
  1476. var cmd = cmds[j];
  1477. if (cmd=="M") {
  1478. ctx.moveTo(crds[c], crds[c+1]);
  1479. c+=2;
  1480. }
  1481. else if(cmd=="L") {
  1482. ctx.lineTo(crds[c], crds[c+1]);
  1483. c+=2;
  1484. }
  1485. else if(cmd=="C") {
  1486. ctx.bezierCurveTo(crds[c], crds[c+1], crds[c+2], crds[c+3], crds[c+4], crds[c+5]);
  1487. c+=6;
  1488. }
  1489. else if(cmd=="Q") {
  1490. ctx.quadraticCurveTo(crds[c], crds[c+1], crds[c+2], crds[c+3]);
  1491. c+=4;
  1492. }
  1493. else if(cmd.charAt(0)=="#") {
  1494. ctx.beginPath();
  1495. ctx.fillStyle = cmd;
  1496. }
  1497. else if(cmd=="Z") {
  1498. ctx.closePath();
  1499. }
  1500. else if(cmd=="X") {
  1501. ctx.fill();
  1502. }
  1503. }
  1504. },
  1505.  
  1506. "P" : {
  1507. MoveTo : function(p, x, y) { p.cmds.push("M"); p.crds.push(x,y); },
  1508. LineTo : function(p, x, y) { p.cmds.push("L"); p.crds.push(x,y); },
  1509. CurveTo : function(p, a,b,c,d,e,f) { p.cmds.push("C"); p.crds.push(a,b,c,d,e,f); },
  1510. qCurveTo : function(p, a,b,c,d) { p.cmds.push("Q"); p.crds.push(a,b,c,d); },
  1511. ClosePath : function(p) { p.cmds.push("Z"); }
  1512. },
  1513.  
  1514. "_drawCFF" : function(cmds, state, font, pdct, p)
  1515. {
  1516. var stack = state.stack;
  1517. var nStems = state.nStems, haveWidth=state.haveWidth, width=state.width, open=state.open;
  1518. var i=0;
  1519. var x=state.x, y=state.y, c1x=0, c1y=0, c2x=0, c2y=0, c3x=0, c3y=0, c4x=0, c4y=0, jpx=0, jpy=0;
  1520. var CFF = Typr["T"].CFF, P = Typr["U"]["P"];
  1521. var nominalWidthX = pdct["nominalWidthX"];
  1522. var o = {val:0,size:0};
  1523. //console.log(cmds);
  1524. while(i<cmds.length)
  1525. {
  1526. CFF.getCharString(cmds, i, o);
  1527. var v = o.val;
  1528. i += o.size;
  1529. if(false) {}
  1530. else if(v=="o1" || v=="o18") // hstem || hstemhm
  1531. {
  1532. var hasWidthArg;
  1533.  
  1534. // The number of stem operators on the stack is always even.
  1535. // If the value is uneven, that means a width is specified.
  1536. hasWidthArg = stack.length % 2 !== 0;
  1537. if (hasWidthArg && !haveWidth) {
  1538. width = stack.shift() + nominalWidthX;
  1539. }
  1540.  
  1541. nStems += stack.length >> 1;
  1542. stack.length = 0;
  1543. haveWidth = true;
  1544. }
  1545. else if(v=="o3" || v=="o23") // vstem || vstemhm
  1546. {
  1547. var hasWidthArg;
  1548.  
  1549. // The number of stem operators on the stack is always even.
  1550. // If the value is uneven, that means a width is specified.
  1551. hasWidthArg = stack.length % 2 !== 0;
  1552. if (hasWidthArg && !haveWidth) {
  1553. width = stack.shift() + nominalWidthX;
  1554. }
  1555.  
  1556. nStems += stack.length >> 1;
  1557. stack.length = 0;
  1558. haveWidth = true;
  1559. }
  1560. else if(v=="o4")
  1561. {
  1562. if (stack.length > 1 && !haveWidth) {
  1563. width = stack.shift() + nominalWidthX;
  1564. haveWidth = true;
  1565. }
  1566. if(open) P.ClosePath(p);
  1567.  
  1568. y += stack.pop();
  1569. P.MoveTo(p,x,y); open=true;
  1570. }
  1571. else if(v=="o5")
  1572. {
  1573. while (stack.length > 0) {
  1574. x += stack.shift();
  1575. y += stack.shift();
  1576. P.LineTo(p, x, y);
  1577. }
  1578. }
  1579. else if(v=="o6" || v=="o7") // hlineto || vlineto
  1580. {
  1581. var count = stack.length;
  1582. var isX = (v == "o6");
  1583. for(var j=0; j<count; j++) {
  1584. var sval = stack.shift();
  1585. if(isX) x += sval; else y += sval;
  1586. isX = !isX;
  1587. P.LineTo(p, x, y);
  1588. }
  1589. }
  1590. else if(v=="o8" || v=="o24") // rrcurveto || rcurveline
  1591. {
  1592. var count = stack.length;
  1593. var index = 0;
  1594. while(index+6 <= count) {
  1595. c1x = x + stack.shift();
  1596. c1y = y + stack.shift();
  1597. c2x = c1x + stack.shift();
  1598. c2y = c1y + stack.shift();
  1599. x = c2x + stack.shift();
  1600. y = c2y + stack.shift();
  1601. P.CurveTo(p, c1x, c1y, c2x, c2y, x, y);
  1602. index+=6;
  1603. }
  1604. if(v=="o24")
  1605. {
  1606. x += stack.shift();
  1607. y += stack.shift();
  1608. P.LineTo(p, x, y);
  1609. }
  1610. }
  1611. else if(v=="o11") break;
  1612. else if(v=="o1234" || v=="o1235" || v=="o1236" || v=="o1237")//if((v+"").slice(0,3)=="o12")
  1613. {
  1614. if(v=="o1234")
  1615. {
  1616. c1x = x + stack.shift(); // dx1
  1617. c1y = y; // dy1
  1618. c2x = c1x + stack.shift(); // dx2
  1619. c2y = c1y + stack.shift(); // dy2
  1620. jpx = c2x + stack.shift(); // dx3
  1621. jpy = c2y; // dy3
  1622. c3x = jpx + stack.shift(); // dx4
  1623. c3y = c2y; // dy4
  1624. c4x = c3x + stack.shift(); // dx5
  1625. c4y = y; // dy5
  1626. x = c4x + stack.shift(); // dx6
  1627. P.CurveTo(p, c1x, c1y, c2x, c2y, jpx, jpy);
  1628. P.CurveTo(p, c3x, c3y, c4x, c4y, x, y);
  1629. }
  1630. if(v=="o1235")
  1631. {
  1632. c1x = x + stack.shift(); // dx1
  1633. c1y = y + stack.shift(); // dy1
  1634. c2x = c1x + stack.shift(); // dx2
  1635. c2y = c1y + stack.shift(); // dy2
  1636. jpx = c2x + stack.shift(); // dx3
  1637. jpy = c2y + stack.shift(); // dy3
  1638. c3x = jpx + stack.shift(); // dx4
  1639. c3y = jpy + stack.shift(); // dy4
  1640. c4x = c3x + stack.shift(); // dx5
  1641. c4y = c3y + stack.shift(); // dy5
  1642. x = c4x + stack.shift(); // dx6
  1643. y = c4y + stack.shift(); // dy6
  1644. stack.shift(); // flex depth
  1645. P.CurveTo(p, c1x, c1y, c2x, c2y, jpx, jpy);
  1646. P.CurveTo(p, c3x, c3y, c4x, c4y, x, y);
  1647. }
  1648. if(v=="o1236")
  1649. {
  1650. c1x = x + stack.shift(); // dx1
  1651. c1y = y + stack.shift(); // dy1
  1652. c2x = c1x + stack.shift(); // dx2
  1653. c2y = c1y + stack.shift(); // dy2
  1654. jpx = c2x + stack.shift(); // dx3
  1655. jpy = c2y; // dy3
  1656. c3x = jpx + stack.shift(); // dx4
  1657. c3y = c2y; // dy4
  1658. c4x = c3x + stack.shift(); // dx5
  1659. c4y = c3y + stack.shift(); // dy5
  1660. x = c4x + stack.shift(); // dx6
  1661. P.CurveTo(p, c1x, c1y, c2x, c2y, jpx, jpy);
  1662. P.CurveTo(p, c3x, c3y, c4x, c4y, x, y);
  1663. }
  1664. if(v=="o1237")
  1665. {
  1666. c1x = x + stack.shift(); // dx1
  1667. c1y = y + stack.shift(); // dy1
  1668. c2x = c1x + stack.shift(); // dx2
  1669. c2y = c1y + stack.shift(); // dy2
  1670. jpx = c2x + stack.shift(); // dx3
  1671. jpy = c2y + stack.shift(); // dy3
  1672. c3x = jpx + stack.shift(); // dx4
  1673. c3y = jpy + stack.shift(); // dy4
  1674. c4x = c3x + stack.shift(); // dx5
  1675. c4y = c3y + stack.shift(); // dy5
  1676. if (Math.abs(c4x - x) > Math.abs(c4y - y)) {
  1677. x = c4x + stack.shift();
  1678. } else {
  1679. y = c4y + stack.shift();
  1680. }
  1681. P.CurveTo(p, c1x, c1y, c2x, c2y, jpx, jpy);
  1682. P.CurveTo(p, c3x, c3y, c4x, c4y, x, y);
  1683. }
  1684. }
  1685. else if(v=="o14")
  1686. {
  1687. if (stack.length > 0 && !haveWidth) {
  1688. width = stack.shift() + font["nominalWidthX"];
  1689. haveWidth = true;
  1690. }
  1691. if(stack.length==4) // seac = standard encoding accented character
  1692. {
  1693. var asb = 0;
  1694. var adx = stack.shift();
  1695. var ady = stack.shift();
  1696. var bchar = stack.shift();
  1697. var achar = stack.shift();
  1698. var bind = CFF.glyphBySE(font, bchar);
  1699. var aind = CFF.glyphBySE(font, achar);
  1700. //console.log(bchar, bind);
  1701. //console.log(achar, aind);
  1702. //state.x=x; state.y=y; state.nStems=nStems; state.haveWidth=haveWidth; state.width=width; state.open=open;
  1703. Typr["U"]["_drawCFF"](font["CharStrings"][bind], state,font,pdct,p);
  1704. state.x = adx; state.y = ady;
  1705. Typr["U"]["_drawCFF"](font["CharStrings"][aind], state,font,pdct,p);
  1706. //x=state.x; y=state.y; nStems=state.nStems; haveWidth=state.haveWidth; width=state.width; open=state.open;
  1707. }
  1708. if(open) { P.ClosePath(p); open=false; }
  1709. }
  1710. else if(v=="o19" || v=="o20")
  1711. {
  1712. var hasWidthArg;
  1713.  
  1714. // The number of stem operators on the stack is always even.
  1715. // If the value is uneven, that means a width is specified.
  1716. hasWidthArg = stack.length % 2 !== 0;
  1717. if (hasWidthArg && !haveWidth) {
  1718. width = stack.shift() + nominalWidthX;
  1719. }
  1720.  
  1721. nStems += stack.length >> 1;
  1722. stack.length = 0;
  1723. haveWidth = true;
  1724. i += (nStems + 7) >> 3;
  1725. }
  1726. else if(v=="o21") {
  1727. if (stack.length > 2 && !haveWidth) {
  1728. width = stack.shift() + nominalWidthX;
  1729. haveWidth = true;
  1730. }
  1731.  
  1732. y += stack.pop();
  1733. x += stack.pop();
  1734. if(open) P.ClosePath(p);
  1735. P.MoveTo(p,x,y); open=true;
  1736. }
  1737. else if(v=="o22")
  1738. {
  1739. if (stack.length > 1 && !haveWidth) {
  1740. width = stack.shift() + nominalWidthX;
  1741. haveWidth = true;
  1742. }
  1743. x += stack.pop();
  1744. if(open) P.ClosePath(p);
  1745. P.MoveTo(p,x,y); open=true;
  1746. }
  1747. else if(v=="o25")
  1748. {
  1749. while (stack.length > 6) {
  1750. x += stack.shift();
  1751. y += stack.shift();
  1752. P.LineTo(p, x, y);
  1753. }
  1754.  
  1755. c1x = x + stack.shift();
  1756. c1y = y + stack.shift();
  1757. c2x = c1x + stack.shift();
  1758. c2y = c1y + stack.shift();
  1759. x = c2x + stack.shift();
  1760. y = c2y + stack.shift();
  1761. P.CurveTo(p, c1x, c1y, c2x, c2y, x, y);
  1762. }
  1763. else if(v=="o26")
  1764. {
  1765. if (stack.length % 2) {
  1766. x += stack.shift();
  1767. }
  1768.  
  1769. while (stack.length > 0) {
  1770. c1x = x;
  1771. c1y = y + stack.shift();
  1772. c2x = c1x + stack.shift();
  1773. c2y = c1y + stack.shift();
  1774. x = c2x;
  1775. y = c2y + stack.shift();
  1776. P.CurveTo(p, c1x, c1y, c2x, c2y, x, y);
  1777. }
  1778.  
  1779. }
  1780. else if(v=="o27")
  1781. {
  1782. if (stack.length % 2) {
  1783. y += stack.shift();
  1784. }
  1785.  
  1786. while (stack.length > 0) {
  1787. c1x = x + stack.shift();
  1788. c1y = y;
  1789. c2x = c1x + stack.shift();
  1790. c2y = c1y + stack.shift();
  1791. x = c2x + stack.shift();
  1792. y = c2y;
  1793. P.CurveTo(p, c1x, c1y, c2x, c2y, x, y);
  1794. }
  1795. }
  1796. else if(v=="o10" || v=="o29") // callsubr || callgsubr
  1797. {
  1798. var obj = (v=="o10" ? pdct : font);
  1799. if(stack.length==0) { console.log("error: empty stack"); }
  1800. else {
  1801. var ind = stack.pop();
  1802. var subr = obj["Subrs"][ ind + obj["Bias"] ];
  1803. state.x=x; state.y=y; state.nStems=nStems; state.haveWidth=haveWidth; state.width=width; state.open=open;
  1804. Typr["U"]["_drawCFF"](subr, state,font,pdct,p);
  1805. x=state.x; y=state.y; nStems=state.nStems; haveWidth=state.haveWidth; width=state.width; open=state.open;
  1806. }
  1807. }
  1808. else if(v=="o30" || v=="o31") // vhcurveto || hvcurveto
  1809. {
  1810. var count, count1 = stack.length;
  1811. var index = 0;
  1812. var alternate = v == "o31";
  1813. count = count1 & ~2;
  1814. index += count1 - count;
  1815. while ( index < count )
  1816. {
  1817. if(alternate)
  1818. {
  1819. c1x = x + stack.shift();
  1820. c1y = y;
  1821. c2x = c1x + stack.shift();
  1822. c2y = c1y + stack.shift();
  1823. y = c2y + stack.shift();
  1824. if(count-index == 5) { x = c2x + stack.shift(); index++; }
  1825. else x = c2x;
  1826. alternate = false;
  1827. }
  1828. else
  1829. {
  1830. c1x = x;
  1831. c1y = y + stack.shift();
  1832. c2x = c1x + stack.shift();
  1833. c2y = c1y + stack.shift();
  1834. x = c2x + stack.shift();
  1835. if(count-index == 5) { y = c2y + stack.shift(); index++; }
  1836. else y = c2y;
  1837. alternate = true;
  1838. }
  1839. P.CurveTo(p, c1x, c1y, c2x, c2y, x, y);
  1840. index += 4;
  1841. }
  1842. }
  1843. else if((v+"").charAt(0)=="o") { console.log("Unknown operation: "+v, cmds); throw v; }
  1844. else stack.push(v);
  1845. }
  1846. //console.log(cmds);
  1847. state.x=x; state.y=y; state.nStems=nStems; state.haveWidth=haveWidth; state.width=width; state.open=open;
  1848. },
  1849.  
  1850.  
  1851. "SVG" : function() {
  1852. var M = {
  1853. getScale : function(m) { return Math.sqrt(Math.abs(m[0]*m[3]-m[1]*m[2])); },
  1854. translate: function(m,x,y) { M.concat(m, [1,0,0,1,x,y]); },
  1855. rotate : function(m,a ) { M.concat(m, [Math.cos(a), -Math.sin(a), Math.sin(a), Math.cos(a),0,0]); },
  1856. scale : function(m,x,y) { M.concat(m, [x,0,0,y,0,0]); },
  1857. concat : function(m,w ) {
  1858. var a=m[0],b=m[1],c=m[2],d=m[3],tx=m[4],ty=m[5];
  1859. m[0] = (a *w[0])+(b *w[2]); m[1] = (a *w[1])+(b *w[3]);
  1860. m[2] = (c *w[0])+(d *w[2]); m[3] = (c *w[1])+(d *w[3]);
  1861. m[4] = (tx*w[0])+(ty*w[2])+w[4]; m[5] = (tx*w[1])+(ty*w[3])+w[5];
  1862. },
  1863. invert : function(m ) {
  1864. var a=m[0],b=m[1],c=m[2],d=m[3],tx=m[4],ty=m[5], adbc=a*d-b*c;
  1865. m[0] = d/adbc; m[1] = -b/adbc; m[2] =-c/adbc; m[3] = a/adbc;
  1866. m[4] = (c*ty - d*tx)/adbc; m[5] = (b*tx - a*ty)/adbc;
  1867. },
  1868. multPoint: function(m, p ) { var x=p[0],y=p[1]; return [x*m[0]+y*m[2]+m[4], x*m[1]+y*m[3]+m[5]]; },
  1869. multArray: function(m, a ) { for(var i=0; i<a.length; i+=2) { var x=a[i],y=a[i+1]; a[i]=x*m[0]+y*m[2]+m[4]; a[i+1]=x*m[1]+y*m[3]+m[5]; } }
  1870. }
  1871. function _bracketSplit(str, lbr, rbr) {
  1872. var out = [], pos=0, ci = 0, lvl = 0;
  1873. while(true) { //throw "e";
  1874. var li = str.indexOf(lbr, ci);
  1875. var ri = str.indexOf(rbr, ci);
  1876. if(li==-1 && ri==-1) break;
  1877. if(ri==-1 || (li!=-1 && li<ri)) {
  1878. if(lvl==0) { out.push(str.slice(pos,li).trim()); pos=li+1; }
  1879. lvl++; ci=li+1;
  1880. }
  1881. else if(li==-1 || (ri!=-1 && ri<li)) {
  1882. lvl--;
  1883. if(lvl==0) { out.push(str.slice(pos,ri).trim()); pos=ri+1; }
  1884. ci=ri+1;
  1885. }
  1886. }
  1887. return out;
  1888. }
  1889. //"cssMap":
  1890. function cssMap(str) {
  1891. var pts = _bracketSplit(str, "{", "}");
  1892. var css = {};
  1893. for(var i=0; i<pts.length; i+=2) {
  1894. var cn = pts[i].split(",");
  1895. for(var j=0; j<cn.length; j++) {
  1896. var cnj = cn[j].trim(); if(css[cnj]==null) css[cnj]="";
  1897. css[cnj] += pts[i+1];
  1898. }
  1899. }
  1900. return css;
  1901. }
  1902. //"readTrnf"
  1903. function readTrnf(trna) {
  1904. var pts = _bracketSplit(trna, "(",")");
  1905. var m = [1,0,0,1,0,0];
  1906. for(var i=0; i<pts.length; i+=2) { var om=m; m=_readTrnsAttr(pts[i], pts[i+1]); M.concat(m,om); }
  1907. return m;
  1908. }
  1909. function _readTrnsAttr(fnc, vls) {
  1910. //console.log(vls);
  1911. //vls = vls.replace(/\-/g, " -").trim();
  1912. var m = [1,0,0,1,0,0], gotSep = true;
  1913. for(var i=0; i<vls.length; i++) { // matrix(.99915 0 0 .99915.418.552) matrix(1 0 0-.9474-22.535 271.03)
  1914. var ch = vls.charAt(i);
  1915. if(ch=="," || ch==" ") gotSep = true;
  1916. else if(ch==".") {
  1917. if(!gotSep) { vls = vls.slice(0,i) + ","+vls.slice(i); i++; } gotSep = false;
  1918. }
  1919. else if(ch=="-" && i>0 && vls[i-1]!="e") { vls = vls.slice(0,i) + " "+vls.slice(i); i++; gotSep=true; }
  1920. }
  1921. vls = vls.split(/\s*[\s,]\s*/).map(parseFloat);
  1922. if(false) {}
  1923. else if(fnc=="translate") { if(vls.length==1) M.translate(m,vls[0], 0); else M.translate(m,vls[0],vls[1]); }
  1924. else if(fnc=="scale" ) { if(vls.length==1) M.scale (m,vls[0],vls[0]); else M.scale (m,vls[0],vls[1]); }
  1925. else if(fnc=="rotate" ) { var tx=0,ty=0; if(vls.length!=1) { tx=vls[1]; ty=vls[2]; } M.translate(m,-tx,-ty); M.rotate(m,-Math.PI*vls[0]/180); M.translate(m,tx,ty); }
  1926. else if(fnc=="matrix" ) m = vls;
  1927. else console.log("unknown transform: ", fnc);
  1928. return m;
  1929. }
  1930. function toPath(str)
  1931. {
  1932. var pth = {cmds:[], crds:[]};
  1933. if(str==null) return pth;
  1934. var prsr = new DOMParser();
  1935. var doc = prsr["parseFromString"](str,"image/svg+xml");
  1936. //var svg = doc.firstChild; while(svg.tagName!="svg") svg = svg.nextSibling;
  1937. var svg = doc.getElementsByTagName("svg")[0];
  1938. var vb = svg.getAttribute("viewBox");
  1939. if(vb) vb = vb.trim().split(" ").map(parseFloat); else vb = [0,0,1000,1000];
  1940. _toPath(svg.children, pth);
  1941. for(var i=0; i<pth.crds.length; i+=2) {
  1942. var x = pth.crds[i], y = pth.crds[i+1];
  1943. x -= vb[0];
  1944. y -= vb[1];
  1945. y = -y;
  1946. pth.crds[i] = x;
  1947. pth.crds[i+1] = y;
  1948. }
  1949. return pth;
  1950. }
  1951.  
  1952. function _toPath(nds, pth, fill) {
  1953. for(var ni=0; ni<nds.length; ni++) {
  1954. var nd = nds[ni], tn = nd.tagName;
  1955. var cfl = nd.getAttribute("fill"); if(cfl==null) cfl = fill;
  1956. if(tn=="g") {
  1957. var tp = {crds:[], cmds:[]};
  1958. _toPath(nd.children, tp, cfl);
  1959. var trf = nd.getAttribute("transform");
  1960. if(trf) {
  1961. var m = readTrnf(trf);
  1962. M.multArray(m, tp.crds);
  1963. }
  1964. pth.crds=pth.crds.concat(tp.crds);
  1965. pth.cmds=pth.cmds.concat(tp.cmds);
  1966. }
  1967. else if(tn=="path" || tn=="circle" || tn=="ellipse") {
  1968. pth.cmds.push(cfl?cfl:"#000000");
  1969. var d;
  1970. if(tn=="path") d = nd.getAttribute("d"); //console.log(d);
  1971. if(tn=="circle" || tn=="ellipse") {
  1972. var vls=[0,0,0,0], nms=["cx","cy","rx","ry","r"];
  1973. for(var i=0; i<5; i++) { var V=nd.getAttribute(nms[i]); if(V) { V=parseFloat(V); if(i<4) vls[i]=V; else vls[2]=vls[3]=V; } }
  1974. var cx=vls[0],cy=vls[1],rx=vls[2],ry=vls[3];
  1975. d = ["M",cx-rx,cy,"a",rx,ry,0,1,0,rx*2,0,"a",rx,ry,0,1,0,-rx*2,0].join(" ");
  1976. }
  1977. svgToPath(d, pth); pth.cmds.push("X");
  1978. }
  1979. else if(tn=="defs") {}
  1980. else console.log(tn, nd);
  1981. }
  1982. }
  1983.  
  1984. function _tokens(d) {
  1985. var ts = [], off = 0, rn=false, cn="", pc=""; // reading number, current number, prev char
  1986. while(off<d.length){
  1987. var cc=d.charCodeAt(off), ch = d.charAt(off); off++;
  1988. var isNum = (48<=cc && cc<=57) || ch=="." || ch=="-" || ch=="e" || ch=="E";
  1989. if(rn) {
  1990. if( (ch=="-" && pc!="e") || (ch=="." && cn.indexOf(".")!=-1)) { ts.push(parseFloat(cn)); cn=ch; }
  1991. else if(isNum) cn+=ch;
  1992. else { ts.push(parseFloat(cn)); if(ch!="," && ch!=" ") ts.push(ch); rn=false; }
  1993. }
  1994. else {
  1995. if(isNum) { cn=ch; rn=true; }
  1996. else if(ch!="," && ch!=" ") ts.push(ch);
  1997. }
  1998. pc = ch;
  1999. }
  2000. if(rn) ts.push(parseFloat(cn));
  2001. return ts;
  2002. }
  2003. function _reps(ts, off, ps) {
  2004. var i = off;
  2005. while(i<ts.length) { if((typeof ts[i]) == "string") break; i+=ps; }
  2006. return (i-off)/ps;
  2007. }
  2008.  
  2009. function svgToPath(d, pth) {
  2010. var ts = _tokens(d);
  2011. var i = 0, x = 0, y = 0, ox = 0, oy = 0, oldo=pth.crds.length;
  2012. var pc = {"M":2,"L":2,"H":1,"V":1, "T":2,"S":4, "A":7, "Q":4, "C":6};
  2013. var cmds = pth.cmds, crds = pth.crds;
  2014. while(i<ts.length) {
  2015. var cmd = ts[i]; i++;
  2016. var cmu = cmd.toUpperCase();
  2017. if(cmu=="Z") { cmds.push("Z"); x=ox; y=oy; }
  2018. else {
  2019. var ps = pc[cmu], reps = _reps(ts, i, ps);
  2020. for(var j=0; j<reps; j++) {
  2021. // If a moveto is followed by multiple pairs of coordinates, the subsequent pairs are treated as implicit lineto commands.
  2022. if(j==1 && cmu=="M") { cmd=(cmd==cmu)?"L":"l"; cmu="L"; }
  2023. var xi = 0, yi = 0; if(cmd!=cmu) { xi=x; yi=y; }
  2024. if(false) {}
  2025. else if(cmu=="M") { x = xi+ts[i++]; y = yi+ts[i++]; cmds.push("M"); crds.push(x,y); ox=x; oy=y; }
  2026. else if(cmu=="L") { x = xi+ts[i++]; y = yi+ts[i++]; cmds.push("L"); crds.push(x,y); }
  2027. else if(cmu=="H") { x = xi+ts[i++]; cmds.push("L"); crds.push(x,y); }
  2028. else if(cmu=="V") { y = yi+ts[i++]; cmds.push("L"); crds.push(x,y); }
  2029. else if(cmu=="Q") {
  2030. var x1=xi+ts[i++], y1=yi+ts[i++], x2=xi+ts[i++], y2=yi+ts[i++];
  2031. cmds.push("Q"); crds.push(x1,y1,x2,y2); x=x2; y=y2;
  2032. }
  2033. else if(cmu=="T") {
  2034. var co = Math.max(crds.length-2, oldo);
  2035. var x1 = x+x-crds[co], y1 = y+y-crds[co+1];
  2036. var x2=xi+ts[i++], y2=yi+ts[i++];
  2037. cmds.push("Q"); crds.push(x1,y1,x2,y2); x=x2; y=y2;
  2038. }
  2039. else if(cmu=="C") {
  2040. var x1=xi+ts[i++], y1=yi+ts[i++], x2=xi+ts[i++], y2=yi+ts[i++], x3=xi+ts[i++], y3=yi+ts[i++];
  2041. cmds.push("C"); crds.push(x1,y1,x2,y2,x3,y3); x=x3; y=y3;
  2042. }
  2043. else if(cmu=="S") {
  2044. var co = Math.max(crds.length-(cmds[cmds.length-1]=="C"?4:2), oldo);
  2045. var x1 = x+x-crds[co], y1 = y+y-crds[co+1];
  2046. var x2=xi+ts[i++], y2=yi+ts[i++], x3=xi+ts[i++], y3=yi+ts[i++];
  2047. cmds.push("C"); crds.push(x1,y1,x2,y2,x3,y3); x=x3; y=y3;
  2048. }
  2049. else if(cmu=="A") { // convert SVG Arc to four cubic bézier segments "C"
  2050. var x1 = x, y1 = y;
  2051. var rx = ts[i++], ry = ts[i++];
  2052. var phi = ts[i++]*(Math.PI/180), fA = ts[i++], fS = ts[i++];
  2053. var x2 = xi+ts[i++], y2 = yi+ts[i++];
  2054. if(x2==x && y2==y && rx==0 && ry==0) continue;
  2055. var hdx = (x1-x2)/2, hdy = (y1-y2)/2;
  2056. var cosP = Math.cos(phi), sinP = Math.sin(phi);
  2057. var x1A = cosP * hdx + sinP * hdy;
  2058. var y1A = -sinP * hdx + cosP * hdy;
  2059. var rxS = rx*rx, ryS = ry*ry;
  2060. var x1AS = x1A*x1A, y1AS = y1A*y1A;
  2061. var frc = (rxS*ryS - rxS*y1AS - ryS*x1AS) / (rxS*y1AS + ryS*x1AS);
  2062. var coef = (fA!=fS ? 1 : -1) * Math.sqrt( Math.max(frc,0) );
  2063. var cxA = coef * (rx * y1A) / ry;
  2064. var cyA = -coef * (ry * x1A) / rx;
  2065. var cx = cosP*cxA - sinP*cyA + (x1+x2)/2;
  2066. var cy = sinP*cxA + cosP*cyA + (y1+y2)/2;
  2067. var angl = function(ux,uy,vx,vy) { var lU = Math.sqrt(ux*ux+uy*uy), lV = Math.sqrt(vx*vx+vy*vy);
  2068. var num = (ux*vx+uy*vy) / (lU*lV); //console.log(num, Math.acos(num));
  2069. return (ux*vy-uy*vx>=0?1:-1) * Math.acos( Math.max(-1, Math.min(1, num)) ); }
  2070. var vX = (x1A-cxA)/rx, vY = (y1A-cyA)/ry;
  2071. var theta1 = angl( 1, 0, vX,vY);
  2072. var dtheta = angl(vX,vY, (-x1A-cxA)/rx, (-y1A-cyA)/ry);
  2073. dtheta = dtheta % (2*Math.PI);
  2074. var arc = function(gst,x,y,r,a0,a1, neg) {
  2075. var rotate = function(m, a) { var si=Math.sin(a), co=Math.cos(a);
  2076. var a=m[0],b=m[1],c=m[2],d=m[3];
  2077. m[0] = (a *co)+(b *si); m[1] = (-a *si)+(b *co);
  2078. m[2] = (c *co)+(d *si); m[3] = (-c *si)+(d *co);
  2079. }
  2080. var multArr= function(m,a) {
  2081. for(var j=0; j<a.length; j+=2) {
  2082. var x=a[j], y=a[j+1];
  2083. a[j ] = m[0]*x + m[2]*y + m[4];
  2084. a[j+1] = m[1]*x + m[3]*y + m[5];
  2085. }
  2086. }
  2087. var concatA= function(a,b) { for(var j=0; j<b.length; j++) a.push(b[j]); }
  2088. var concatP= function(p,r) { concatA(p.cmds,r.cmds); concatA(p.crds,r.crds); }
  2089. // circle from a0 counter-clock-wise to a1
  2090. if(neg) while(a1>a0) a1-=2*Math.PI;
  2091. else while(a1<a0) a1+=2*Math.PI;
  2092. var th = (a1-a0)/4;
  2093. var x0 = Math.cos(th/2), y0 = -Math.sin(th/2);
  2094. var x1 = (4-x0)/3, y1 = y0==0 ? y0 : (1-x0)*(3-x0)/(3*y0);
  2095. var x2 = x1, y2 = -y1;
  2096. var x3 = x0, y3 = -y0;
  2097. var ps = [x1,y1,x2,y2,x3,y3];
  2098. var pth = {cmds:["C","C","C","C"], crds:ps.slice(0)};
  2099. var rot = [1,0,0,1,0,0]; rotate(rot,-th);
  2100. for(var j=0; j<3; j++) { multArr(rot,ps); concatA(pth.crds,ps); }
  2101. rotate(rot, -a0+th/2); rot[0]*=r; rot[1]*=r; rot[2]*=r; rot[3]*=r; rot[4]=x; rot[5]=y;
  2102. multArr(rot, pth.crds);
  2103. multArr(gst.ctm, pth.crds);
  2104. concatP(gst.pth, pth);
  2105. }
  2106. var gst = {pth:pth, ctm:[rx*cosP,rx*sinP,-ry*sinP,ry*cosP,cx,cy]};
  2107. arc(gst, 0,0, 1, theta1, theta1+dtheta, fS==0);
  2108. x=x2; y=y2;
  2109. }
  2110. else console.log("Unknown SVG command "+cmd);
  2111. }
  2112. }
  2113. }
  2114. };
  2115. return { "cssMap":cssMap, "readTrnf":readTrnf, svgToPath:svgToPath, toPath:toPath };
  2116. }(),
  2117.  
  2118.  
  2119. "initHB": function(hurl,resp) {
  2120. var codeLength = function(code) {
  2121. var len=0;
  2122. if ((code&(0xffffffff-(1<< 7)+1))==0) { len=1; }
  2123. else if((code&(0xffffffff-(1<<11)+1))==0) { len=2; }
  2124. else if((code&(0xffffffff-(1<<16)+1))==0) { len=3; }
  2125. else if((code&(0xffffffff-(1<<21)+1))==0) { len=4; }
  2126. return len;
  2127. }
  2128. var te = new window["TextEncoder"]("utf8");
  2129. fetch(hurl)
  2130. .then(function (x ) { return x["arrayBuffer"](); })
  2131. .then(function (ab ) { return WebAssembly["instantiate"](ab); })
  2132. .then(function (res) {
  2133. console.log("HB ready");
  2134. var exp = res["instance"]["exports"], mem=exp["memory"];
  2135. mem["grow"](700); // each page is 64kb in size
  2136. var heapu8 = new Uint8Array (mem.buffer);
  2137. var u32 = new Uint32Array(mem.buffer);
  2138. var i32 = new Int32Array (mem.buffer);
  2139. var __lastFnt, blob,blobPtr,face,font;
  2140. Typr["U"]["shapeHB"] = (function () {
  2141. var toJson = function (ptr) {
  2142. var length = exp["hb_buffer_get_length"](ptr);
  2143. var result = [];
  2144. var iPtr32 = exp["hb_buffer_get_glyph_infos"](ptr, 0) >>>2;
  2145. var pPtr32 = exp["hb_buffer_get_glyph_positions"](ptr, 0) >>>2;
  2146. for(var i=0; i<length; ++i) {
  2147. var a=iPtr32+i*5, b=pPtr32+i*5;
  2148. result.push({
  2149. "g" : u32[a + 0],
  2150. "cl": u32[a + 2],
  2151. "ax": i32[b + 0],
  2152. "ay": i32[b + 1],
  2153. "dx": i32[b + 2],
  2154. "dy": i32[b + 3]
  2155. });
  2156. }
  2157. return result;
  2158. }
  2159. return function (fnt, str, ltr) {
  2160. var fdata = fnt["_data"], fn = fnt["name"]["postScriptName"];
  2161. if(__lastFnt!=fn) {
  2162. if(blob!=null) {
  2163. exp["hb_blob_destroy"](blob);
  2164. exp["free"](blobPtr);
  2165. exp["hb_face_destroy"](face);
  2166. exp["hb_font_destroy"](font);
  2167. }
  2168. blobPtr = exp["malloc"](fdata.byteLength); heapu8.set(fdata, blobPtr);
  2169. blob = exp["hb_blob_create"](blobPtr, fdata.byteLength, 2, 0, 0);
  2170. face = exp["hb_face_create"](blob, 0);
  2171. font = exp["hb_font_create"](face)
  2172. __lastFnt = fn;
  2173. }
  2174. var buffer = exp["hb_buffer_create"]();
  2175. var bytes = te["encode"](str);
  2176. var len=bytes.length, strp = exp["malloc"](len); heapu8.set(bytes, strp);
  2177. exp["hb_buffer_add_utf8"](buffer, strp, len, 0, len);
  2178. exp["free"](strp);
  2179. exp["hb_buffer_set_direction"](buffer,ltr?4:5);
  2180. exp["hb_buffer_guess_segment_properties"](buffer);
  2181. exp["hb_shape"](font, buffer, 0, 0);
  2182. var json = toJson(buffer)//buffer["json"]();
  2183. exp["hb_buffer_destroy"](buffer);
  2184. var arr = json.slice(0); if(!ltr) arr.reverse();
  2185. var ci=0, bi=0; // character index, binary index
  2186. for(var i=1; i<arr.length; i++) {
  2187. var gl = arr[i], cl=gl["cl"];
  2188. while(true) {
  2189. var cpt = str.codePointAt(ci), cln = codeLength(cpt);
  2190. if(bi+cln <=cl) { bi+=cln; ci += cpt<=0xffff ? 1 : 2; }
  2191. else break;
  2192. }
  2193. //while(bi+codeLength(str.charCodeAt(ci)) <=cl) { bi+=codeLength(str.charCodeAt(ci)); ci++; }
  2194. gl["cl"]=ci;
  2195. }
  2196. return json;
  2197. }
  2198. }());
  2199. resp();
  2200. });
  2201. }
  2202. }
  2203.  
  2204.  

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址