Typr.U.js 39 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232
  1. Typr["U"] = {
  2. "shape" : function(font,str,ltr) {
  3. var getGlyphPosition = function(font, gls,i1,ltr)
  4. {
  5. var g1=gls[i1],g2=gls[i1+1], kern=font["kern"];
  6. if(kern) {
  7. var ind1 = kern.glyph1.indexOf(g1);
  8. if(ind1!=-1)
  9. {
  10. var ind2 = kern.rval[ind1].glyph2.indexOf(g2);
  11. if(ind2!=-1) return [0,0,kern.rval[ind1].vals[ind2],0];
  12. }
  13. }
  14. //console.log("no kern");
  15. return [0,0,0,0];
  16. }
  17. var gls = [];
  18. for(var i=0; i<str.length; i++) {
  19. var cc = str.codePointAt(i); if(cc>0xffff) i++;
  20. gls.push(Typr["U"]["codeToGlyph"](font, cc));
  21. }
  22. var shape = [];
  23. var x = 0, y = 0;
  24. for(var i=0; i<gls.length; i++) {
  25. var padj = getGlyphPosition(font, gls,i,ltr);
  26. var gid = gls[i];
  27. var ax=font["hmtx"].aWidth[gid]+padj[2];
  28. shape.push({"g":gid, "cl":i, "dx":0, "dy":0, "ax":ax, "ay":0});
  29. x+=ax;
  30. }
  31. return shape;
  32. },
  33. "shapeToPath" : function(font,shape,clr) {
  34. var tpath = {cmds:[], crds:[]};
  35. var x = 0, y = 0;
  36. for(var i=0; i<shape.length; i++) {
  37. var it = shape[i]
  38. var path = Typr["U"]["glyphToPath"](font, it["g"]), crds=path["crds"];
  39. for(var j=0; j<crds.length; j+=2) {
  40. tpath.crds.push(crds[j ] + x + it["dx"]);
  41. tpath.crds.push(crds[j+1] + y + it["dy"]);
  42. }
  43. if(clr) tpath.cmds.push(clr);
  44. for(var j=0; j<path["cmds"].length; j++) tpath.cmds.push(path["cmds"][j]);
  45. var clen = tpath.cmds.length;
  46. 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.
  47. x += it["ax"]; y+= it["ay"];
  48. }
  49. return {"cmds":tpath.cmds, "crds":tpath.crds};
  50. },
  51. "codeToGlyph" : function() {
  52. // find the greatest index with a value <=v
  53. function arrSearch(arr, k, v) {
  54. var l=0, r=~~(arr.length/k);
  55. while(l+1!=r) { var mid = l + ((r-l)>>>1); if(arr[mid*k]<=v) l=mid; else r=mid; }
  56. //var mi = 0; for(var i=0; i<arr.length; i+=k) if(arr[i]<=v) mi=i; if(mi!=l*k) throw "e";
  57. return l*k;
  58. }
  59. var wha = [0x9,0xa,0xb,0xc,0xd,0x20,0x85,0xa0,0x1680,0x180e,0x2028,0x2029,0x202f,0x2060,0x3000,0xfeff], whm={};
  60. for(var i=0; i<wha.length; i++) whm[wha[i]]=1;
  61. for(var i=0x2000; i<=0x200d; i++) whm[i]=1;
  62. function ctg(font, code)
  63. {
  64. //console.log(cmap);
  65. // "p3e10" for NotoEmoji-Regular.ttf
  66. //console.log(cmap);
  67. if(font["_ctab"]==null) {
  68. var cmap = font["cmap"];
  69. var tind = -1, pps=["p3e10","p0e4","p3e1","p1e0","p0e3","p0e1"/*,"p3e3"*/,"p3e0" /*Hebrew*/, "p3e5" /*Korean*/];
  70. for(var i=0; i<pps.length; i++) if(cmap.ids[pps[i]]!=null) { tind=cmap.ids[pps[i]]; break; }
  71. if(tind==-1) throw "no familiar platform and encoding!";
  72. font["_ctab"]=cmap.tables[tind];
  73. }
  74. var tab = font["_ctab"], fmt=tab.format, gid = -1; //console.log(fmt); throw "e";
  75. if(fmt==0) {
  76. if(code>=tab.map.length) gid = 0;
  77. else gid = tab.map[code];
  78. }
  79. /*else if(fmt==2) {
  80. var data=font["_data"], off = cmap.off+tab.off+6, bin=Typr["B"];
  81. var shKey = bin.readUshort(data,off + 2*(code>>>8));
  82. var shInd = off + 256*2 + shKey*8;
  83. var firstCode = bin.readUshort(data,shInd);
  84. var entryCount= bin.readUshort(data,shInd+2);
  85. var idDelta = bin.readShort (data,shInd+4);
  86. var idRangeOffset = bin.readUshort(data,shInd+6);
  87. if(firstCode<=code && code<=firstCode+entryCount) {
  88. // not completely correct
  89. gid = bin.readUshort(data, shInd+6+idRangeOffset + (code&255)*2);
  90. }
  91. else gid=0;
  92. //if(code>256) console.log(code,(code>>>8),shKey,firstCode,entryCount,idDelta,idRangeOffset);
  93. //throw "e";
  94. //console.log(tab, bin.readUshort(data,off));
  95. //throw "e";
  96. }*/
  97. else if(fmt==4) {
  98. var ec = tab.endCount; gid=0;
  99. if(code<=ec[ec.length-1]) {
  100. // smallest index with code <= value
  101. var sind = arrSearch(ec,1,code);
  102. if(ec[sind]<code) sind++;
  103. if(code>=tab.startCount[sind]) {
  104. var gli = 0;
  105. if(tab.idRangeOffset[sind]!=0) gli = tab.glyphIdArray[(code-tab.startCount[sind]) + (tab.idRangeOffset[sind]>>1) - (tab.idRangeOffset.length-sind)];
  106. else gli = code + tab.idDelta[sind];
  107. gid = (gli & 0xFFFF);
  108. }
  109. }
  110. }
  111. else if(fmt==6) {
  112. var off = code-tab.firstCode, arr=tab.glyphIdArray;
  113. if(off<0 || off>=arr.length) gid=0;
  114. else gid = arr[off];
  115. }
  116. else if(fmt==12) {
  117. var grp = tab.groups; gid=0; //console.log(grp); throw "e";
  118. if(code<=grp[grp.length-2]) {
  119. var i = arrSearch(grp,3,code);
  120. if(grp[i]<=code && code<=grp[i+1]) { gid = grp[i+2] + (code-grp[i]); }
  121. }
  122. }
  123. else throw "unknown cmap table format "+tab.format;
  124. //*
  125. var SVG = font["SVG "], loca = font["loca"];
  126. // 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!
  127. if(gid!=0 && font["CFF "]==null && (SVG==null || SVG.entries[gid]==null) && loca && loca[gid]==loca[gid+1] // loca not present in CFF or SVG fonts
  128. && whm[code]==null ) gid=0;
  129. //*/
  130. return gid;
  131. }
  132. return ctg;
  133. }(),
  134. "glyphToPath" : function(font, gid, noColor)
  135. {
  136. var path = { cmds:[], crds:[] };
  137. var SVG = font["SVG "], CFF = font["CFF "], COLR=font["COLR"], CBLC=font["CBLC"], CBDT=font["CBDT"], sbix=font["sbix"], upng=window["UPNG"];
  138. var U = Typr["U"];
  139. var strike = null;
  140. if(CBLC && upng) for(var i=0; i<CBLC.length; i++) if(CBLC[i][0]<=gid && gid<=CBLC[i][1]) strike=CBLC[i];
  141. if(strike || (sbix && sbix[gid])) {
  142. if(strike && strike[2]!=17) throw "not a PNG";
  143. if(font["__tmp"]==null) font["__tmp"]={};
  144. var cmd = font["__tmp"]["g"+gid];
  145. if(cmd==null) {
  146. var bmp, len;
  147. if(sbix) { bmp = sbix[gid]; len=bmp.length; }
  148. else {
  149. var boff = strike[3][gid-strike[0]]+5; // smallGlyphMetrics
  150. len = (CBDT[boff+1]<<16)|(CBDT[boff+2]<<8)|CBDT[boff+3]; boff+=4;
  151. bmp = new Uint8Array(CBDT.buffer, CBDT.byteOffset+boff,len);
  152. }
  153. var str = ""; for(var i=0; i<len; i++) str+=String.fromCharCode(bmp[i]);
  154. cmd = font["__tmp"]["g"+gid] = "data:image/png;base64,"+btoa(str);
  155. }
  156. path.cmds.push(cmd);
  157. var upe = font["head"]["unitsPerEm"]*1.15;
  158. var gw=Math.round(upe), gh=Math.round(upe), dy=Math.round(-gh*0.15);
  159. path.crds.push(0,gh+dy, gw,gh+dy, gw,dy, 0,dy); //*/
  160. }
  161. else if(SVG && SVG.entries[gid]) {
  162. var p = SVG.entries[gid];
  163. if(p!=null) {
  164. if(typeof p == "string") { p = U["SVG"].toPath(p); SVG.entries[gid]=p; }
  165. path=p;
  166. }
  167. }
  168. else if(noColor!=true && COLR && COLR[0]["g"+gid] && COLR[0]["g"+gid][1]>1) {
  169. function toHex(n){ var o=n.toString(16); return (o.length==1 ? "0":"")+o; }
  170. var CPAL = font["CPAL"], gl = COLR[0]["g"+gid];
  171. for(var i=0; i<gl[1]; i++) {
  172. var lid = gl[0]+i;
  173. var cgl = COLR[1][2*lid], pid=COLR[1][2*lid+1]*4;
  174. var pth = Typr["U"]["glyphToPath"](font,cgl, cgl==gid);
  175. var col = "#"+toHex(CPAL[pid+2])+toHex(CPAL[pid+1])+toHex(CPAL[pid+0]);
  176. path.cmds.push(col);
  177. path.cmds=path.cmds.concat(pth["cmds"]);
  178. path.crds=path.crds.concat(pth["crds"]);
  179. //console.log(gid, cgl,pid,col);
  180. path.cmds.push("X");
  181. }
  182. }
  183. else if(CFF) {
  184. var pdct = CFF["Private"];
  185. var state = {x:0,y:0,stack:[],nStems:0,haveWidth:false,width: pdct ? pdct["defaultWidthX"] : 0,open:false};
  186. if(CFF["ROS"]) {
  187. var gi = 0;
  188. while(CFF["FDSelect"][gi+2]<=gid) gi+=2;
  189. pdct = CFF["FDArray"][CFF["FDSelect"][gi+1]]["Private"];
  190. }
  191. U["_drawCFF"](CFF["CharStrings"][gid], state, CFF, pdct, path);
  192. }
  193. else if(font["glyf"]) { U["_drawGlyf"](gid, font, path); }
  194. return {"cmds":path.cmds, "crds":path.crds};
  195. },
  196. "_drawGlyf" : function(gid, font, path)
  197. {
  198. var gl = font["glyf"][gid];
  199. if(gl==null) gl = font["glyf"][gid] = Typr["T"].glyf._parseGlyf(font, gid);
  200. if(gl!=null){
  201. if(gl.noc>-1) Typr["U"]["_simpleGlyph"](gl, path);
  202. else Typr["U"]["_compoGlyph"] (gl, font, path);
  203. }
  204. },
  205. "_simpleGlyph" : function(gl, p)
  206. {
  207. var P = Typr["U"]["P"];
  208. for(var c=0; c<gl.noc; c++) {
  209. var i0 = (c==0) ? 0 : (gl.endPts[c-1] + 1);
  210. var il = gl.endPts[c];
  211. for(var i=i0; i<=il; i++) {
  212. var pr = (i==i0)?il:(i-1);
  213. var nx = (i==il)?i0:(i+1);
  214. var onCurve = gl.flags[i]&1;
  215. var prOnCurve = gl.flags[pr]&1;
  216. var nxOnCurve = gl.flags[nx]&1;
  217. var x = gl.xs[i], y = gl.ys[i];
  218. if(i==i0) {
  219. if(onCurve) {
  220. if(prOnCurve) P.MoveTo(p, gl.xs[pr], gl.ys[pr]);
  221. else { P.MoveTo(p,x,y); continue; /* will do CurveTo at il */ }
  222. }
  223. else {
  224. if(prOnCurve) P.MoveTo(p, gl.xs[pr], gl.ys[pr] );
  225. else P.MoveTo(p, Math.floor((gl.xs[pr]+x)*0.5), Math.floor((gl.ys[pr]+y)*0.5) );
  226. }
  227. }
  228. if(onCurve) {
  229. if(prOnCurve) P.LineTo(p,x,y);
  230. }
  231. else {
  232. if(nxOnCurve) P.qCurveTo(p, x, y, gl.xs[nx], gl.ys[nx]);
  233. else P.qCurveTo(p, x, y, Math.floor((x+gl.xs[nx])*0.5), Math.floor((y+gl.ys[nx])*0.5) );
  234. }
  235. }
  236. P.ClosePath(p);
  237. }
  238. },
  239. "_compoGlyph" : function(gl, font, p) {
  240. for(var j=0; j<gl.parts.length; j++) {
  241. var path = { cmds:[], crds:[] };
  242. var prt = gl.parts[j];
  243. Typr["U"]["_drawGlyf"](prt.glyphIndex, font, path);
  244. var m = prt.m;
  245. for(var i=0; i<path.crds.length; i+=2) {
  246. var x = path.crds[i ], y = path.crds[i+1];
  247. p.crds.push(x*m.a + y*m.c + m.tx); // not sure, probably right
  248. p.crds.push(x*m.b + y*m.d + m.ty);
  249. }
  250. for(var i=0; i<path.cmds.length; i++) p.cmds.push(path.cmds[i]);
  251. }
  252. },
  253. "pathToSVG" : function(path, prec)
  254. {
  255. var cmds = path["cmds"], crds = path["crds"];
  256. if(prec==null) prec = 5;
  257. function num(v) { return parseFloat(v.toFixed(prec)); }
  258. function merge(o) {
  259. var no = [], lstF=false, lstC="";
  260. for(var i=0; i<o.length; i++) {
  261. var it=o[i], isF=(typeof it)=="number";
  262. if(!isF) { if(it==lstC && it.length==1 && it!="m") continue; lstC=it; } // move should not be merged (it actually means lineTo)
  263. if(lstF && isF && it>=0) no.push(" ");
  264. no.push(it); lstF=isF;
  265. }
  266. return no.join("");
  267. }
  268. var out = [], co = 0, lmap = {"M":2,"L":2,"Q":4,"C":6};
  269. var x =0, y =0, // perfect coords
  270. //dx=0, dy=0, // relative perfect coords
  271. //rx=0, ry=0, // relative rounded coords
  272. ex=0, ey=0, // error between perfect and output coords
  273. mx=0, my=0; // perfect coords of the last "Move"
  274. for(var i=0; i<cmds.length; i++) {
  275. var cmd = cmds[i], cc=(lmap[cmd]?lmap[cmd]:0);
  276. var o0=[], dx, dy, rx, ry; // o1=[], cx, cy, ax,ay;
  277. if(cmd=="L") {
  278. dx=crds[co]-x; dy=crds[co+1]-y;
  279. rx = num(dx+ex); ry=num(dy+ey);
  280. // if this "lineTo" leads to the starting point, and "Z" follows, do not output anything.
  281. if(cmds[i+1]=="Z" && crds[co]==mx && crds[co+1]==my) { rx=dx; ry=dy; }
  282. else if(rx==0 && ry==0) {}
  283. else if(rx==0) o0.push("v",ry);
  284. else if(ry==0) o0.push("h",rx);
  285. else { o0.push("l",rx,ry); }
  286. }
  287. else {
  288. o0.push(cmd.toLowerCase());
  289. for(var j=0; j<cc; j+=2) {
  290. dx = crds[co+j]-x; dy=crds[co+j+1]-y;
  291. rx = num(dx+ex); ry=num(dy+ey);
  292. o0.push(rx,ry);
  293. }
  294. }
  295. if(cc!=0) { ex += dx-rx; ey += dy-ry; }
  296. /*
  297. if(cmd=="L") {
  298. cx=crds[co]; cy=crds[co+1];
  299. ax = num(cx); ay=num(cy);
  300. // if this "lineTo" leads to the starting point, and "Z" follows, do not output anything.
  301. if(cmds[i+1]=="Z" && crds[co]==mx && crds[co+1]==my) { ax=cx; ay=cy; }
  302. else if(ax==num(x) && ay==num(y)) {}
  303. else if(ax==num(x)) o1.push("V",ay);
  304. else if(ay==num(y)) o1.push("H",ax);
  305. else { o1.push("L",ax,ay); }
  306. }
  307. else {
  308. o1.push(cmd);
  309. for(var j=0; j<cc; j+=2) {
  310. cx = crds[co+j]; cy=crds[co+j+1];
  311. ax = num(cx); ay=num(cy);
  312. o1.push(ax,ay);
  313. }
  314. }
  315. var ou;
  316. if(merge(o0).length<merge(o1).length) {
  317. ou = o0;
  318. if(cc!=0) { ex += dx-rx; ey += dy-ry; }
  319. }
  320. else {
  321. ou = o1;
  322. if(cc!=0) { ex = cx-ax; ey = cy-ay; }
  323. }
  324. */
  325. var ou=o0;
  326. for(var j=0; j<ou.length; j++) out.push(ou[j]);
  327. if(cc !=0 ) { co+=cc; x=crds[co-2]; y=crds[co-1]; }
  328. if(cmd=="M") { mx=x; my=y; }
  329. if(cmd=="Z") { x=mx; y=my; }
  330. }
  331. return merge(out);
  332. },
  333. "SVGToPath" : function(d) {
  334. var pth = {cmds:[], crds:[]};
  335. Typr["U"]["SVG"].svgToPath(d, pth);
  336. return {"cmds":pth.cmds, "crds":pth.crds};
  337. },
  338. "pathToContext" : function() {
  339. var cnv, ct;
  340. function ptc(path, ctx) {
  341. var c = 0, cmds = path["cmds"], crds = path["crds"];
  342. //ctx.translate(3500,500); ctx.rotate(0.25); ctx.scale(1,-1);
  343. for(var j=0; j<cmds.length; j++) {
  344. var cmd = cmds[j];
  345. if (cmd=="M") {
  346. ctx.moveTo(crds[c], crds[c+1]);
  347. c+=2;
  348. }
  349. else if(cmd=="L") {
  350. ctx.lineTo(crds[c], crds[c+1]);
  351. c+=2;
  352. }
  353. else if(cmd=="C") {
  354. ctx.bezierCurveTo(crds[c], crds[c+1], crds[c+2], crds[c+3], crds[c+4], crds[c+5]);
  355. c+=6;
  356. }
  357. else if(cmd=="Q") {
  358. ctx.quadraticCurveTo(crds[c], crds[c+1], crds[c+2], crds[c+3]);
  359. c+=4;
  360. }
  361. else if(cmd[0]=="d") {
  362. var upng=window["UPNG"];
  363. var x0 = crds[c], y0=crds[c+1], x1=crds[c+2], y1=crds[c+3], x2=crds[c+4], y2=crds[c+5], x3=crds[c+6], y3=crds[c+7]; c+=8;
  364. //y0+=400; y1+=400; y1+=600;
  365. if(upng==null) {
  366. ctx.moveTo(x0,y0); ctx.lineTo(x1,y1); ctx.lineTo(x2,y2); ctx.lineTo(x3,y3); ctx.closePath();
  367. continue;
  368. }
  369. ctx.save();
  370. var dx0 = (x1-x0), dy0=(y1-y0), gw=Math.sqrt(dx0*dx0+dy0*dy0);
  371. var rot = Math.atan2(dy0,dx0);
  372. var dx1 = (x3-x0), dy1=(y3-y0), gh=Math.sqrt(dx1*dx1+dy1*dy1);
  373. var sgn = Math.sign(dx0*dy1 - dy0*dx1);
  374. var sbmp = atob(cmd.slice(22));
  375. var bmp = [];
  376. for(var i=0; i<sbmp.length; i++) bmp[i]=sbmp.charCodeAt(i);
  377. var img = upng["decode"](new Uint8Array(bmp)), w=img["width"], h=img["height"]; //console.log(img);
  378. var nbmp = new Uint8Array(upng["toRGBA8"](img)[0]);
  379. //*
  380. if(cnv==null) { cnv = document.createElement("canvas"); ct=cnv.getContext("2d"); }
  381. if(cnv.width!=w || cnv.height!=h) { cnv.width=w; cnv.height=h; }
  382. ct.putImageData(new ImageData(new Uint8ClampedArray(nbmp.buffer),w,h),0,0);
  383. ctx.translate(x0,y0);
  384. ctx.rotate(rot);
  385. ctx.scale(gw*(w/h)/w,sgn*gh/h);
  386. ctx.drawImage(cnv,0,0); //*/
  387. ctx.restore();
  388. }
  389. else if(cmd.charAt(0)=="#" || cmd.charAt(0)=="r") {
  390. ctx.beginPath();
  391. ctx.fillStyle = cmd;
  392. }
  393. else if(cmd.charAt(0)=="O" && cmd!="OX") {
  394. ctx.beginPath();
  395. var pts = cmd.split("-");
  396. ctx.lineWidth=parseFloat(pts[2]);
  397. ctx.strokeStyle = pts[1];
  398. }
  399. else if(cmd=="Z") {
  400. ctx.closePath();
  401. }
  402. else if(cmd=="X") {
  403. ctx.fill();
  404. }
  405. else if(cmd=="OX") {
  406. ctx.stroke();
  407. }
  408. }
  409. }
  410. return ptc;
  411. }(),
  412. "P" : {
  413. MoveTo : function(p, x, y) { p.cmds.push("M"); p.crds.push(x,y); },
  414. LineTo : function(p, x, y) { p.cmds.push("L"); p.crds.push(x,y); },
  415. CurveTo : function(p, a,b,c,d,e,f) { p.cmds.push("C"); p.crds.push(a,b,c,d,e,f); },
  416. qCurveTo : function(p, a,b,c,d) { p.cmds.push("Q"); p.crds.push(a,b,c,d); },
  417. ClosePath : function(p) { p.cmds.push("Z"); }
  418. },
  419. "_drawCFF" : function(cmds, state, font, pdct, p)
  420. {
  421. var stack = state.stack;
  422. var nStems = state.nStems, haveWidth=state.haveWidth, width=state.width, open=state.open;
  423. var i=0;
  424. 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;
  425. var CFF = Typr["T"].CFF, P = Typr["U"]["P"];
  426. var nominalWidthX = pdct["nominalWidthX"];
  427. var o = {val:0,size:0};
  428. //console.log(cmds);
  429. while(i<cmds.length)
  430. {
  431. CFF.getCharString(cmds, i, o);
  432. var v = o.val;
  433. i += o.size;
  434. if(false) {}
  435. else if(v=="o1" || v=="o18") // hstem || hstemhm
  436. {
  437. var hasWidthArg;
  438. // The number of stem operators on the stack is always even.
  439. // If the value is uneven, that means a width is specified.
  440. hasWidthArg = stack.length % 2 !== 0;
  441. if (hasWidthArg && !haveWidth) {
  442. width = stack.shift() + nominalWidthX;
  443. }
  444. nStems += stack.length >> 1;
  445. stack.length = 0;
  446. haveWidth = true;
  447. }
  448. else if(v=="o3" || v=="o23") // vstem || vstemhm
  449. {
  450. var hasWidthArg;
  451. // The number of stem operators on the stack is always even.
  452. // If the value is uneven, that means a width is specified.
  453. hasWidthArg = stack.length % 2 !== 0;
  454. if (hasWidthArg && !haveWidth) {
  455. width = stack.shift() + nominalWidthX;
  456. }
  457. nStems += stack.length >> 1;
  458. stack.length = 0;
  459. haveWidth = true;
  460. }
  461. else if(v=="o4")
  462. {
  463. if (stack.length > 1 && !haveWidth) {
  464. width = stack.shift() + nominalWidthX;
  465. haveWidth = true;
  466. }
  467. if(open) P.ClosePath(p);
  468. y += stack.pop();
  469. P.MoveTo(p,x,y); open=true;
  470. }
  471. else if(v=="o5")
  472. {
  473. while (stack.length > 0) {
  474. x += stack.shift();
  475. y += stack.shift();
  476. P.LineTo(p, x, y);
  477. }
  478. }
  479. else if(v=="o6" || v=="o7") // hlineto || vlineto
  480. {
  481. var count = stack.length;
  482. var isX = (v == "o6");
  483. for(var j=0; j<count; j++) {
  484. var sval = stack.shift();
  485. if(isX) x += sval; else y += sval;
  486. isX = !isX;
  487. P.LineTo(p, x, y);
  488. }
  489. }
  490. else if(v=="o8" || v=="o24") // rrcurveto || rcurveline
  491. {
  492. var count = stack.length;
  493. var index = 0;
  494. while(index+6 <= count) {
  495. c1x = x + stack.shift();
  496. c1y = y + stack.shift();
  497. c2x = c1x + stack.shift();
  498. c2y = c1y + stack.shift();
  499. x = c2x + stack.shift();
  500. y = c2y + stack.shift();
  501. P.CurveTo(p, c1x, c1y, c2x, c2y, x, y);
  502. index+=6;
  503. }
  504. if(v=="o24")
  505. {
  506. x += stack.shift();
  507. y += stack.shift();
  508. P.LineTo(p, x, y);
  509. }
  510. }
  511. else if(v=="o11") break;
  512. else if(v=="o1234" || v=="o1235" || v=="o1236" || v=="o1237")//if((v+"").slice(0,3)=="o12")
  513. {
  514. if(v=="o1234")
  515. {
  516. c1x = x + stack.shift(); // dx1
  517. c1y = y; // dy1
  518. c2x = c1x + stack.shift(); // dx2
  519. c2y = c1y + stack.shift(); // dy2
  520. jpx = c2x + stack.shift(); // dx3
  521. jpy = c2y; // dy3
  522. c3x = jpx + stack.shift(); // dx4
  523. c3y = c2y; // dy4
  524. c4x = c3x + stack.shift(); // dx5
  525. c4y = y; // dy5
  526. x = c4x + stack.shift(); // dx6
  527. P.CurveTo(p, c1x, c1y, c2x, c2y, jpx, jpy);
  528. P.CurveTo(p, c3x, c3y, c4x, c4y, x, y);
  529. }
  530. if(v=="o1235")
  531. {
  532. c1x = x + stack.shift(); // dx1
  533. c1y = y + stack.shift(); // dy1
  534. c2x = c1x + stack.shift(); // dx2
  535. c2y = c1y + stack.shift(); // dy2
  536. jpx = c2x + stack.shift(); // dx3
  537. jpy = c2y + stack.shift(); // dy3
  538. c3x = jpx + stack.shift(); // dx4
  539. c3y = jpy + stack.shift(); // dy4
  540. c4x = c3x + stack.shift(); // dx5
  541. c4y = c3y + stack.shift(); // dy5
  542. x = c4x + stack.shift(); // dx6
  543. y = c4y + stack.shift(); // dy6
  544. stack.shift(); // flex depth
  545. P.CurveTo(p, c1x, c1y, c2x, c2y, jpx, jpy);
  546. P.CurveTo(p, c3x, c3y, c4x, c4y, x, y);
  547. }
  548. if(v=="o1236")
  549. {
  550. c1x = x + stack.shift(); // dx1
  551. c1y = y + stack.shift(); // dy1
  552. c2x = c1x + stack.shift(); // dx2
  553. c2y = c1y + stack.shift(); // dy2
  554. jpx = c2x + stack.shift(); // dx3
  555. jpy = c2y; // dy3
  556. c3x = jpx + stack.shift(); // dx4
  557. c3y = c2y; // dy4
  558. c4x = c3x + stack.shift(); // dx5
  559. c4y = c3y + stack.shift(); // dy5
  560. x = c4x + stack.shift(); // dx6
  561. P.CurveTo(p, c1x, c1y, c2x, c2y, jpx, jpy);
  562. P.CurveTo(p, c3x, c3y, c4x, c4y, x, y);
  563. }
  564. if(v=="o1237")
  565. {
  566. c1x = x + stack.shift(); // dx1
  567. c1y = y + stack.shift(); // dy1
  568. c2x = c1x + stack.shift(); // dx2
  569. c2y = c1y + stack.shift(); // dy2
  570. jpx = c2x + stack.shift(); // dx3
  571. jpy = c2y + stack.shift(); // dy3
  572. c3x = jpx + stack.shift(); // dx4
  573. c3y = jpy + stack.shift(); // dy4
  574. c4x = c3x + stack.shift(); // dx5
  575. c4y = c3y + stack.shift(); // dy5
  576. if (Math.abs(c4x - x) > Math.abs(c4y - y)) {
  577. x = c4x + stack.shift();
  578. } else {
  579. y = c4y + stack.shift();
  580. }
  581. P.CurveTo(p, c1x, c1y, c2x, c2y, jpx, jpy);
  582. P.CurveTo(p, c3x, c3y, c4x, c4y, x, y);
  583. }
  584. }
  585. else if(v=="o14")
  586. {
  587. if (stack.length > 0 && stack.length!=4 && !haveWidth) {
  588. width = stack.shift() + font["nominalWidthX"];
  589. haveWidth = true;
  590. }
  591. if(stack.length==4) // seac = standard encoding accented character
  592. {
  593. var asb = 0;
  594. var adx = stack.shift();
  595. var ady = stack.shift();
  596. var bchar = stack.shift();
  597. var achar = stack.shift();
  598. var bind = CFF.glyphBySE(font, bchar);
  599. var aind = CFF.glyphBySE(font, achar);
  600. //console.log(bchar, bind);
  601. //console.log(achar, aind);
  602. //state.x=x; state.y=y; state.nStems=nStems; state.haveWidth=haveWidth; state.width=width; state.open=open;
  603. Typr["U"]["_drawCFF"](font["CharStrings"][bind], state,font,pdct,p);
  604. state.x = adx; state.y = ady;
  605. Typr["U"]["_drawCFF"](font["CharStrings"][aind], state,font,pdct,p);
  606. //x=state.x; y=state.y; nStems=state.nStems; haveWidth=state.haveWidth; width=state.width; open=state.open;
  607. }
  608. if(open) { P.ClosePath(p); open=false; }
  609. }
  610. else if(v=="o19" || v=="o20")
  611. {
  612. var hasWidthArg;
  613. // The number of stem operators on the stack is always even.
  614. // If the value is uneven, that means a width is specified.
  615. hasWidthArg = stack.length % 2 !== 0;
  616. if (hasWidthArg && !haveWidth) {
  617. width = stack.shift() + nominalWidthX;
  618. }
  619. nStems += stack.length >> 1;
  620. stack.length = 0;
  621. haveWidth = true;
  622. i += (nStems + 7) >> 3;
  623. }
  624. else if(v=="o21") {
  625. if (stack.length > 2 && !haveWidth) {
  626. width = stack.shift() + nominalWidthX;
  627. haveWidth = true;
  628. }
  629. y += stack.pop();
  630. x += stack.pop();
  631. if(open) P.ClosePath(p);
  632. P.MoveTo(p,x,y); open=true;
  633. }
  634. else if(v=="o22")
  635. {
  636. if (stack.length > 1 && !haveWidth) {
  637. width = stack.shift() + nominalWidthX;
  638. haveWidth = true;
  639. }
  640. x += stack.pop();
  641. if(open) P.ClosePath(p);
  642. P.MoveTo(p,x,y); open=true;
  643. }
  644. else if(v=="o25")
  645. {
  646. while (stack.length > 6) {
  647. x += stack.shift();
  648. y += stack.shift();
  649. P.LineTo(p, x, y);
  650. }
  651. c1x = x + stack.shift();
  652. c1y = y + stack.shift();
  653. c2x = c1x + stack.shift();
  654. c2y = c1y + stack.shift();
  655. x = c2x + stack.shift();
  656. y = c2y + stack.shift();
  657. P.CurveTo(p, c1x, c1y, c2x, c2y, x, y);
  658. }
  659. else if(v=="o26")
  660. {
  661. if (stack.length % 2) {
  662. x += stack.shift();
  663. }
  664. while (stack.length > 0) {
  665. c1x = x;
  666. c1y = y + stack.shift();
  667. c2x = c1x + stack.shift();
  668. c2y = c1y + stack.shift();
  669. x = c2x;
  670. y = c2y + stack.shift();
  671. P.CurveTo(p, c1x, c1y, c2x, c2y, x, y);
  672. }
  673. }
  674. else if(v=="o27")
  675. {
  676. if (stack.length % 2) {
  677. y += stack.shift();
  678. }
  679. while (stack.length > 0) {
  680. c1x = x + stack.shift();
  681. c1y = y;
  682. c2x = c1x + stack.shift();
  683. c2y = c1y + stack.shift();
  684. x = c2x + stack.shift();
  685. y = c2y;
  686. P.CurveTo(p, c1x, c1y, c2x, c2y, x, y);
  687. }
  688. }
  689. else if(v=="o10" || v=="o29") // callsubr || callgsubr
  690. {
  691. var obj = (v=="o10" ? pdct : font);
  692. if(stack.length==0) { console.log("error: empty stack"); }
  693. else {
  694. var ind = stack.pop();
  695. var subr = obj["Subrs"][ ind + obj["Bias"] ];
  696. state.x=x; state.y=y; state.nStems=nStems; state.haveWidth=haveWidth; state.width=width; state.open=open;
  697. Typr["U"]["_drawCFF"](subr, state,font,pdct,p);
  698. x=state.x; y=state.y; nStems=state.nStems; haveWidth=state.haveWidth; width=state.width; open=state.open;
  699. }
  700. }
  701. else if(v=="o30" || v=="o31") // vhcurveto || hvcurveto
  702. {
  703. var count, count1 = stack.length;
  704. var index = 0;
  705. var alternate = v == "o31";
  706. count = count1 & ~2;
  707. index += count1 - count;
  708. while ( index < count )
  709. {
  710. if(alternate)
  711. {
  712. c1x = x + stack.shift();
  713. c1y = y;
  714. c2x = c1x + stack.shift();
  715. c2y = c1y + stack.shift();
  716. y = c2y + stack.shift();
  717. if(count-index == 5) { x = c2x + stack.shift(); index++; }
  718. else x = c2x;
  719. alternate = false;
  720. }
  721. else
  722. {
  723. c1x = x;
  724. c1y = y + stack.shift();
  725. c2x = c1x + stack.shift();
  726. c2y = c1y + stack.shift();
  727. x = c2x + stack.shift();
  728. if(count-index == 5) { y = c2y + stack.shift(); index++; }
  729. else y = c2y;
  730. alternate = true;
  731. }
  732. P.CurveTo(p, c1x, c1y, c2x, c2y, x, y);
  733. index += 4;
  734. }
  735. }
  736. else if((v+"").charAt(0)=="o") { console.log("Unknown operation: "+v, cmds); throw v; }
  737. else stack.push(v);
  738. }
  739. //console.log(cmds);
  740. state.x=x; state.y=y; state.nStems=nStems; state.haveWidth=haveWidth; state.width=width; state.open=open;
  741. },
  742. "SVG" : function() {
  743. var M = {
  744. getScale : function(m) { return Math.sqrt(Math.abs(m[0]*m[3]-m[1]*m[2])); },
  745. translate: function(m,x,y) { M.concat(m, [1,0,0,1,x,y]); },
  746. rotate : function(m,a ) { M.concat(m, [Math.cos(a), -Math.sin(a), Math.sin(a), Math.cos(a),0,0]); },
  747. scale : function(m,x,y) { M.concat(m, [x,0,0,y,0,0]); },
  748. concat : function(m,w ) {
  749. var a=m[0],b=m[1],c=m[2],d=m[3],tx=m[4],ty=m[5];
  750. m[0] = (a *w[0])+(b *w[2]); m[1] = (a *w[1])+(b *w[3]);
  751. m[2] = (c *w[0])+(d *w[2]); m[3] = (c *w[1])+(d *w[3]);
  752. m[4] = (tx*w[0])+(ty*w[2])+w[4]; m[5] = (tx*w[1])+(ty*w[3])+w[5];
  753. },
  754. invert : function(m ) {
  755. var a=m[0],b=m[1],c=m[2],d=m[3],tx=m[4],ty=m[5], adbc=a*d-b*c;
  756. m[0] = d/adbc; m[1] = -b/adbc; m[2] =-c/adbc; m[3] = a/adbc;
  757. m[4] = (c*ty - d*tx)/adbc; m[5] = (b*tx - a*ty)/adbc;
  758. },
  759. 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]]; },
  760. 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]; } }
  761. }
  762. function _bracketSplit(str, lbr, rbr) {
  763. var out = [], pos=0, ci = 0, lvl = 0;
  764. while(true) { //throw "e";
  765. var li = str.indexOf(lbr, ci);
  766. var ri = str.indexOf(rbr, ci);
  767. if(li==-1 && ri==-1) break;
  768. if(ri==-1 || (li!=-1 && li<ri)) {
  769. if(lvl==0) { out.push(str.slice(pos,li).trim()); pos=li+1; }
  770. lvl++; ci=li+1;
  771. }
  772. else if(li==-1 || (ri!=-1 && ri<li)) {
  773. lvl--;
  774. if(lvl==0) { out.push(str.slice(pos,ri).trim()); pos=ri+1; }
  775. ci=ri+1;
  776. }
  777. }
  778. return out;
  779. }
  780. //"cssMap":
  781. function cssMap(str) {
  782. var pts = _bracketSplit(str, "{", "}");
  783. var css = {};
  784. for(var i=0; i<pts.length; i+=2) {
  785. var cn = pts[i].split(",");
  786. for(var j=0; j<cn.length; j++) {
  787. var cnj = cn[j].trim(); if(css[cnj]==null) css[cnj]="";
  788. css[cnj] += pts[i+1];
  789. }
  790. }
  791. return css;
  792. }
  793. //"readTrnf"
  794. function readTrnf(trna) {
  795. var pts = _bracketSplit(trna, "(",")");
  796. var m = [1,0,0,1,0,0];
  797. for(var i=0; i<pts.length; i+=2) { var om=m; m=_readTrnsAttr(pts[i], pts[i+1]); M.concat(m,om); }
  798. return m;
  799. }
  800. function _readTrnsAttr(fnc, vls) {
  801. //console.log(vls);
  802. //vls = vls.replace(/\-/g, " -").trim();
  803. var m = [1,0,0,1,0,0], gotSep = true;
  804. for(var i=0; i<vls.length; i++) { // matrix(.99915 0 0 .99915.418.552) matrix(1 0 0-.9474-22.535 271.03)
  805. var ch = vls.charAt(i);
  806. if(ch=="," || ch==" ") gotSep = true;
  807. else if(ch==".") {
  808. if(!gotSep) { vls = vls.slice(0,i) + ","+vls.slice(i); i++; } gotSep = false;
  809. }
  810. else if(ch=="-" && i>0 && vls[i-1]!="e") { vls = vls.slice(0,i) + " "+vls.slice(i); i++; gotSep=true; }
  811. }
  812. vls = vls.split(/\s*[\s,]\s*/).map(parseFloat);
  813. if(false) {}
  814. else if(fnc=="translate") { if(vls.length==1) M.translate(m,vls[0], 0); else M.translate(m,vls[0],vls[1]); }
  815. else if(fnc=="scale" ) { if(vls.length==1) M.scale (m,vls[0],vls[0]); else M.scale (m,vls[0],vls[1]); }
  816. 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); }
  817. else if(fnc=="matrix" ) m = vls;
  818. else console.log("unknown transform: ", fnc);
  819. return m;
  820. }
  821. function toPath(str)
  822. {
  823. var pth = {cmds:[], crds:[]};
  824. if(str==null) return pth;
  825. var prsr = new DOMParser();
  826. var doc = prsr["parseFromString"](str,"image/svg+xml");
  827. //var svg = doc.firstChild; while(svg.tagName!="svg") svg = svg.nextSibling;
  828. var svg = doc.getElementsByTagName("svg")[0];
  829. var vb = svg.getAttribute("viewBox");
  830. if(vb) vb = vb.trim().split(" ").map(parseFloat); else vb = [0,0,1000,1000];
  831. _toPath(svg.children, pth);
  832. for(var i=0; i<pth.crds.length; i+=2) {
  833. var x = pth.crds[i], y = pth.crds[i+1];
  834. x -= vb[0];
  835. y -= vb[1];
  836. y = -y;
  837. pth.crds[i] = x;
  838. pth.crds[i+1] = y;
  839. }
  840. return pth;
  841. }
  842. function _toPath(nds, pth, fill) {
  843. for(var ni=0; ni<nds.length; ni++) {
  844. var nd = nds[ni], tn = nd.tagName;
  845. var cfl = nd.getAttribute("fill"); if(cfl==null) cfl = fill;
  846. if(tn=="g") {
  847. var tp = {crds:[], cmds:[]};
  848. _toPath(nd.children, tp, cfl);
  849. var trf = nd.getAttribute("transform");
  850. if(trf) {
  851. var m = readTrnf(trf);
  852. M.multArray(m, tp.crds);
  853. }
  854. pth.crds=pth.crds.concat(tp.crds);
  855. pth.cmds=pth.cmds.concat(tp.cmds);
  856. }
  857. else if(tn=="path" || tn=="circle" || tn=="ellipse") {
  858. pth.cmds.push(cfl?cfl:"#000000");
  859. var d;
  860. if(tn=="path") d = nd.getAttribute("d"); //console.log(d);
  861. if(tn=="circle" || tn=="ellipse") {
  862. var vls=[0,0,0,0], nms=["cx","cy","rx","ry","r"];
  863. 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; } }
  864. var cx=vls[0],cy=vls[1],rx=vls[2],ry=vls[3];
  865. d = ["M",cx-rx,cy,"a",rx,ry,0,1,0,rx*2,0,"a",rx,ry,0,1,0,-rx*2,0].join(" ");
  866. }
  867. svgToPath(d, pth); pth.cmds.push("X");
  868. }
  869. else if(tn=="defs") {}
  870. else console.log(tn, nd);
  871. }
  872. }
  873. function _tokens(d) {
  874. var ts = [], off = 0, rn=false, cn="", pc="", lc="", nc=0; // reading number, current number, prev char, lastCommand, number count (after last command
  875. while(off<d.length){
  876. var cc=d.charCodeAt(off), ch = d.charAt(off); off++;
  877. var isNum = (48<=cc && cc<=57) || ch=="." || ch=="-" || ch=="+" || ch=="e" || ch=="E";
  878. if(rn) {
  879. if( ((ch=="+"||ch=="-") && pc!="e") || (ch=="." && cn.indexOf(".")!=-1) || (isNum && (lc=="a"||lc=="A") && ((nc%7)==3||(nc%7)==4))) { ts.push(parseFloat(cn)); nc++; cn=ch; }
  880. else if(isNum) cn+=ch;
  881. else { ts.push(parseFloat(cn)); nc++; if(ch!="," && ch!=" ") { ts.push(ch); lc=ch; nc=0; } rn=false; }
  882. }
  883. else {
  884. if(isNum) { cn=ch; rn=true; }
  885. else if(ch!="," && ch!=" ") { ts.push(ch); lc=ch; nc=0; }
  886. }
  887. pc = ch;
  888. }
  889. if(rn) ts.push(parseFloat(cn));
  890. return ts;
  891. }
  892. function _reps(ts, off, ps) {
  893. var i = off;
  894. while(i<ts.length) { if((typeof ts[i]) == "string") break; i+=ps; }
  895. return (i-off)/ps;
  896. }
  897. function svgToPath(d, pth) {
  898. var ts = _tokens(d);
  899. var i = 0, x = 0, y = 0, ox = 0, oy = 0, oldo=pth.crds.length;
  900. var pc = {"M":2,"L":2,"H":1,"V":1, "T":2,"S":4, "A":7, "Q":4, "C":6};
  901. var cmds = pth.cmds, crds = pth.crds;
  902. while(i<ts.length) {
  903. var cmd = ts[i]; i++;
  904. var cmu = cmd.toUpperCase();
  905. if(cmu=="Z") { cmds.push("Z"); x=ox; y=oy; }
  906. else {
  907. var ps = pc[cmu], reps = _reps(ts, i, ps);
  908. for(var j=0; j<reps; j++) {
  909. // If a moveto is followed by multiple pairs of coordinates, the subsequent pairs are treated as implicit lineto commands.
  910. if(j==1 && cmu=="M") { cmd=(cmd==cmu)?"L":"l"; cmu="L"; }
  911. var xi = 0, yi = 0; if(cmd!=cmu) { xi=x; yi=y; }
  912. if(false) {}
  913. else if(cmu=="M") { x = xi+ts[i++]; y = yi+ts[i++]; cmds.push("M"); crds.push(x,y); ox=x; oy=y; }
  914. else if(cmu=="L") { x = xi+ts[i++]; y = yi+ts[i++]; cmds.push("L"); crds.push(x,y); }
  915. else if(cmu=="H") { x = xi+ts[i++]; cmds.push("L"); crds.push(x,y); }
  916. else if(cmu=="V") { y = yi+ts[i++]; cmds.push("L"); crds.push(x,y); }
  917. else if(cmu=="Q") {
  918. var x1=xi+ts[i++], y1=yi+ts[i++], x2=xi+ts[i++], y2=yi+ts[i++];
  919. cmds.push("Q"); crds.push(x1,y1,x2,y2); x=x2; y=y2;
  920. }
  921. else if(cmu=="T") {
  922. var co = Math.max(crds.length-(cmds[cmds.length-1]=="Q"?4:2), oldo);
  923. var x1 = x+x-crds[co], y1 = y+y-crds[co+1];
  924. var x2=xi+ts[i++], y2=yi+ts[i++];
  925. cmds.push("Q"); crds.push(x1,y1,x2,y2); x=x2; y=y2;
  926. }
  927. else if(cmu=="C") {
  928. 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++];
  929. cmds.push("C"); crds.push(x1,y1,x2,y2,x3,y3); x=x3; y=y3;
  930. }
  931. else if(cmu=="S") {
  932. var co = Math.max(crds.length-(cmds[cmds.length-1]=="C"?4:2), oldo);
  933. var x1 = x+x-crds[co], y1 = y+y-crds[co+1];
  934. var x2=xi+ts[i++], y2=yi+ts[i++], x3=xi+ts[i++], y3=yi+ts[i++];
  935. cmds.push("C"); crds.push(x1,y1,x2,y2,x3,y3); x=x3; y=y3;
  936. }
  937. else if(cmu=="A") { // convert SVG Arc to four cubic bézier segments "C"
  938. var x1 = x, y1 = y;
  939. var rx = ts[i++], ry = ts[i++];
  940. var phi = ts[i++]*(Math.PI/180), fA = ts[i++], fS = ts[i++];
  941. var x2 = xi+ts[i++], y2 = yi+ts[i++];
  942. if(x2==x && y2==y && rx==0 && ry==0) continue;
  943. var hdx = (x1-x2)/2, hdy = (y1-y2)/2;
  944. var cosP = Math.cos(phi), sinP = Math.sin(phi);
  945. var x1A = cosP * hdx + sinP * hdy;
  946. var y1A = -sinP * hdx + cosP * hdy;
  947. var rxS = rx*rx, ryS = ry*ry;
  948. var x1AS = x1A*x1A, y1AS = y1A*y1A;
  949. var frc = (rxS*ryS - rxS*y1AS - ryS*x1AS) / (rxS*y1AS + ryS*x1AS);
  950. var coef = (fA!=fS ? 1 : -1) * Math.sqrt( Math.max(frc,0) );
  951. var cxA = coef * (rx * y1A) / ry;
  952. var cyA = -coef * (ry * x1A) / rx;
  953. var cx = cosP*cxA - sinP*cyA + (x1+x2)/2;
  954. var cy = sinP*cxA + cosP*cyA + (y1+y2)/2;
  955. var angl = function(ux,uy,vx,vy) { var lU = Math.sqrt(ux*ux+uy*uy), lV = Math.sqrt(vx*vx+vy*vy);
  956. var num = (ux*vx+uy*vy) / (lU*lV); //console.log(num, Math.acos(num));
  957. return (ux*vy-uy*vx>=0?1:-1) * Math.acos( Math.max(-1, Math.min(1, num)) ); }
  958. var vX = (x1A-cxA)/rx, vY = (y1A-cyA)/ry;
  959. var theta1 = angl( 1, 0, vX,vY);
  960. var dtheta = angl(vX,vY, (-x1A-cxA)/rx, (-y1A-cyA)/ry);
  961. dtheta = dtheta % (2*Math.PI);
  962. var arc = function(gst,x,y,r,a0,a1, neg) {
  963. var rotate = function(m, a) { var si=Math.sin(a), co=Math.cos(a);
  964. var a=m[0],b=m[1],c=m[2],d=m[3];
  965. m[0] = (a *co)+(b *si); m[1] = (-a *si)+(b *co);
  966. m[2] = (c *co)+(d *si); m[3] = (-c *si)+(d *co);
  967. }
  968. var multArr= function(m,a) {
  969. for(var j=0; j<a.length; j+=2) {
  970. var x=a[j], y=a[j+1];
  971. a[j ] = m[0]*x + m[2]*y + m[4];
  972. a[j+1] = m[1]*x + m[3]*y + m[5];
  973. }
  974. }
  975. var concatA= function(a,b) { for(var j=0; j<b.length; j++) a.push(b[j]); }
  976. var concatP= function(p,r) { concatA(p.cmds,r.cmds); concatA(p.crds,r.crds); }
  977. // circle from a0 counter-clock-wise to a1
  978. if(neg) while(a1>a0) a1-=2*Math.PI;
  979. else while(a1<a0) a1+=2*Math.PI;
  980. var th = (a1-a0)/4;
  981. var x0 = Math.cos(th/2), y0 = -Math.sin(th/2);
  982. var x1 = (4-x0)/3, y1 = y0==0 ? y0 : (1-x0)*(3-x0)/(3*y0);
  983. var x2 = x1, y2 = -y1;
  984. var x3 = x0, y3 = -y0;
  985. var ps = [x1,y1,x2,y2,x3,y3];
  986. var pth = {cmds:["C","C","C","C"], crds:ps.slice(0)};
  987. var rot = [1,0,0,1,0,0]; rotate(rot,-th);
  988. for(var j=0; j<3; j++) { multArr(rot,ps); concatA(pth.crds,ps); }
  989. rotate(rot, -a0+th/2); rot[0]*=r; rot[1]*=r; rot[2]*=r; rot[3]*=r; rot[4]=x; rot[5]=y;
  990. multArr(rot, pth.crds);
  991. multArr(gst.ctm, pth.crds);
  992. concatP(gst.pth, pth);
  993. }
  994. var gst = {pth:pth, ctm:[rx*cosP,rx*sinP,-ry*sinP,ry*cosP,cx,cy]};
  995. arc(gst, 0,0, 1, theta1, theta1+dtheta, fS==0);
  996. x=x2; y=y2;
  997. }
  998. else console.log("Unknown SVG command "+cmd);
  999. }
  1000. }
  1001. }
  1002. };
  1003. return { "cssMap":cssMap, "readTrnf":readTrnf, svgToPath:svgToPath, toPath:toPath };
  1004. }(),
  1005. "initHB": function(hurl,resp) {
  1006. var codeLength = function(code) {
  1007. var len=0;
  1008. if ((code&(0xffffffff-(1<< 7)+1))==0) { len=1; }
  1009. else if((code&(0xffffffff-(1<<11)+1))==0) { len=2; }
  1010. else if((code&(0xffffffff-(1<<16)+1))==0) { len=3; }
  1011. else if((code&(0xffffffff-(1<<21)+1))==0) { len=4; }
  1012. return len;
  1013. }
  1014. fetch(hurl)
  1015. .then(function (x ) { return x["arrayBuffer"](); })
  1016. .then(function (ab ) { return WebAssembly["instantiate"](ab); })
  1017. .then(function (res) {
  1018. console.log("HB ready");
  1019. var exp = res["instance"]["exports"], mem=exp["memory"];
  1020. //mem["grow"](30); // each page is 64kb in size
  1021. var heapu8, u32,i32;
  1022. var __lastFnt, blob,blobPtr,face,font;
  1023. Typr["U"]["shapeHB"] = (function () {
  1024. var toJson = function (ptr) {
  1025. var length = exp["hb_buffer_get_length"](ptr);
  1026. var result = [];
  1027. var iPtr32 = exp["hb_buffer_get_glyph_infos"](ptr, 0) >>>2;
  1028. var pPtr32 = exp["hb_buffer_get_glyph_positions"](ptr, 0) >>>2;
  1029. for(var i=0; i<length; ++i) {
  1030. var a=iPtr32+i*5, b=pPtr32+i*5;
  1031. result.push({
  1032. "g" : u32[a + 0],
  1033. "cl": u32[a + 2],
  1034. "ax": i32[b + 0],
  1035. "ay": i32[b + 1],
  1036. "dx": i32[b + 2],
  1037. "dy": i32[b + 3]
  1038. });
  1039. }
  1040. //console.log(result);
  1041. return result;
  1042. }
  1043. var te;
  1044. return function (fnt, str, ltr) {
  1045. var fdata = fnt["_data"], fn = fnt["name"]["postScriptName"];
  1046. var olen = mem.buffer.byteLength, nlen = 2*fdata.length+str.length*16 + 4e6;
  1047. if(olen<nlen) {
  1048. mem["grow"](((nlen-olen)>>>16)+4); //console.log("growing",nlen);
  1049. }
  1050. heapu8 = new Uint8Array (mem.buffer);
  1051. u32 = new Uint32Array(mem.buffer);
  1052. i32 = new Int32Array (mem.buffer);
  1053. if(__lastFnt!=fn) {
  1054. if(blob!=null) {
  1055. exp["hb_blob_destroy"](blob);
  1056. exp["free"](blobPtr);
  1057. exp["hb_face_destroy"](face);
  1058. exp["hb_font_destroy"](font);
  1059. }
  1060. blobPtr = exp["malloc"](fdata.byteLength); heapu8.set(fdata, blobPtr);
  1061. blob = exp["hb_blob_create"](blobPtr, fdata.byteLength, 2, 0, 0);
  1062. face = exp["hb_face_create"](blob, 0);
  1063. font = exp["hb_font_create"](face)
  1064. __lastFnt = fn;
  1065. }
  1066. if(window["TextEncoder"]==null) { alert("Your browser is too old. Please, update it."); return; }
  1067. if(te==null) te = new window["TextEncoder"]("utf8");
  1068. var buffer = exp["hb_buffer_create"]();
  1069. var bytes = te["encode"](str);
  1070. var len=bytes.length, strp = exp["malloc"](len); heapu8.set(bytes, strp);
  1071. exp["hb_buffer_add_utf8"](buffer, strp, len, 0, len);
  1072. exp["free"](strp);
  1073. exp["hb_buffer_set_direction"](buffer,ltr?4:5);
  1074. exp["hb_buffer_guess_segment_properties"](buffer);
  1075. exp["hb_shape"](font, buffer, 0, 0);
  1076. var json = toJson(buffer)//buffer["json"]();
  1077. exp["hb_buffer_destroy"](buffer);
  1078. var arr = json.slice(0); if(!ltr) arr.reverse();
  1079. var ci=0, bi=0; // character index, binary index
  1080. for(var i=1; i<arr.length; i++) {
  1081. var gl = arr[i], cl=gl["cl"];
  1082. while(true) {
  1083. var cpt = str.codePointAt(ci), cln = codeLength(cpt);
  1084. if(bi+cln <=cl) { bi+=cln; ci += cpt<=0xffff ? 1 : 2; }
  1085. else break;
  1086. }
  1087. //while(bi+codeLength(str.charCodeAt(ci)) <=cl) { bi+=codeLength(str.charCodeAt(ci)); ci++; }
  1088. gl["cl"]=ci;
  1089. }
  1090. return json;
  1091. }
  1092. }());
  1093. resp();
  1094. });
  1095. }
  1096. }