Typr["U"] = { "shape" : function(font,str,ltr) { var getGlyphPosition = function(font, gls,i1,ltr) { var g1=gls[i1],g2=gls[i1+1], kern=font["kern"]; if(kern) { var ind1 = kern.glyph1.indexOf(g1); if(ind1!=-1) { var ind2 = kern.rval[ind1].glyph2.indexOf(g2); if(ind2!=-1) return [0,0,kern.rval[ind1].vals[ind2],0]; } } //console.log("no kern"); return [0,0,0,0]; } var gls = []; for(var i=0; i0xffff) i++; gls.push(Typr["U"]["codeToGlyph"](font, cc)); } var shape = []; var x = 0, y = 0; for(var i=0; i>>1); if(arr[mid*k]<=v) l=mid; else r=mid; } //var mi = 0; for(var i=0; i=tab.map.length) gid = 0; else gid = tab.map[code]; } /*else if(fmt==2) { var data=font["_data"], off = cmap.off+tab.off+6, bin=Typr["B"]; var shKey = bin.readUshort(data,off + 2*(code>>>8)); var shInd = off + 256*2 + shKey*8; var firstCode = bin.readUshort(data,shInd); var entryCount= bin.readUshort(data,shInd+2); var idDelta = bin.readShort (data,shInd+4); var idRangeOffset = bin.readUshort(data,shInd+6); if(firstCode<=code && code<=firstCode+entryCount) { // not completely correct gid = bin.readUshort(data, shInd+6+idRangeOffset + (code&255)*2); } else gid=0; //if(code>256) console.log(code,(code>>>8),shKey,firstCode,entryCount,idDelta,idRangeOffset); //throw "e"; //console.log(tab, bin.readUshort(data,off)); //throw "e"; }*/ else if(fmt==4) { var ec = tab.endCount; gid=0; if(code<=ec[ec.length-1]) { // smallest index with code <= value var sind = arrSearch(ec,1,code); if(ec[sind]=tab.startCount[sind]) { var gli = 0; if(tab.idRangeOffset[sind]!=0) gli = tab.glyphIdArray[(code-tab.startCount[sind]) + (tab.idRangeOffset[sind]>>1) - (tab.idRangeOffset.length-sind)]; else gli = code + tab.idDelta[sind]; gid = (gli & 0xFFFF); } } } else if(fmt==6) { var off = code-tab.firstCode, arr=tab.glyphIdArray; if(off<0 || off>=arr.length) gid=0; else gid = arr[off]; } else if(fmt==12) { var grp = tab.groups; gid=0; //console.log(grp); throw "e"; if(code<=grp[grp.length-2]) { var i = arrSearch(grp,3,code); if(grp[i]<=code && code<=grp[i+1]) { gid = grp[i+2] + (code-grp[i]); } } } else throw "unknown cmap table format "+tab.format; //* var SVG = font["SVG "], loca = font["loca"]; // 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! 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 && whm[code]==null ) gid=0; //*/ return gid; } return ctg; }(), "glyphToPath" : function(font, gid, noColor) { var path = { cmds:[], crds:[] }; var SVG = font["SVG "], CFF = font["CFF "], COLR=font["COLR"], CBLC=font["CBLC"], CBDT=font["CBDT"], sbix=font["sbix"], upng=window["UPNG"]; var U = Typr["U"]; var strike = null; if(CBLC && upng) for(var i=0; i1) { function toHex(n){ var o=n.toString(16); return (o.length==1 ? "0":"")+o; } var CPAL = font["CPAL"], gl = COLR[0]["g"+gid]; for(var i=0; i-1) Typr["U"]["_simpleGlyph"](gl, path); else Typr["U"]["_compoGlyph"] (gl, font, path); } }, "_simpleGlyph" : function(gl, p) { var P = Typr["U"]["P"]; for(var c=0; c=0) no.push(" "); no.push(it); lstF=isF; } return no.join(""); } var out = [], co = 0, lmap = {"M":2,"L":2,"Q":4,"C":6}; var x =0, y =0, // perfect coords //dx=0, dy=0, // relative perfect coords //rx=0, ry=0, // relative rounded coords ex=0, ey=0, // error between perfect and output coords mx=0, my=0; // perfect coords of the last "Move" for(var i=0; i> 1; stack.length = 0; haveWidth = true; } else if(v=="o3" || v=="o23") // vstem || vstemhm { var hasWidthArg; // The number of stem operators on the stack is always even. // If the value is uneven, that means a width is specified. hasWidthArg = stack.length % 2 !== 0; if (hasWidthArg && !haveWidth) { width = stack.shift() + nominalWidthX; } nStems += stack.length >> 1; stack.length = 0; haveWidth = true; } else if(v=="o4") { if (stack.length > 1 && !haveWidth) { width = stack.shift() + nominalWidthX; haveWidth = true; } if(open) P.ClosePath(p); y += stack.pop(); P.MoveTo(p,x,y); open=true; } else if(v=="o5") { while (stack.length > 0) { x += stack.shift(); y += stack.shift(); P.LineTo(p, x, y); } } else if(v=="o6" || v=="o7") // hlineto || vlineto { var count = stack.length; var isX = (v == "o6"); for(var j=0; j Math.abs(c4y - y)) { x = c4x + stack.shift(); } else { y = c4y + stack.shift(); } P.CurveTo(p, c1x, c1y, c2x, c2y, jpx, jpy); P.CurveTo(p, c3x, c3y, c4x, c4y, x, y); } } else if(v=="o14") { if (stack.length > 0 && stack.length!=4 && !haveWidth) { width = stack.shift() + font["nominalWidthX"]; haveWidth = true; } if(stack.length==4) // seac = standard encoding accented character { var asb = 0; var adx = stack.shift(); var ady = stack.shift(); var bchar = stack.shift(); var achar = stack.shift(); var bind = CFF.glyphBySE(font, bchar); var aind = CFF.glyphBySE(font, achar); //console.log(bchar, bind); //console.log(achar, aind); //state.x=x; state.y=y; state.nStems=nStems; state.haveWidth=haveWidth; state.width=width; state.open=open; Typr["U"]["_drawCFF"](font["CharStrings"][bind], state,font,pdct,p); state.x = adx; state.y = ady; Typr["U"]["_drawCFF"](font["CharStrings"][aind], state,font,pdct,p); //x=state.x; y=state.y; nStems=state.nStems; haveWidth=state.haveWidth; width=state.width; open=state.open; } if(open) { P.ClosePath(p); open=false; } } else if(v=="o19" || v=="o20") { var hasWidthArg; // The number of stem operators on the stack is always even. // If the value is uneven, that means a width is specified. hasWidthArg = stack.length % 2 !== 0; if (hasWidthArg && !haveWidth) { width = stack.shift() + nominalWidthX; } nStems += stack.length >> 1; stack.length = 0; haveWidth = true; i += (nStems + 7) >> 3; } else if(v=="o21") { if (stack.length > 2 && !haveWidth) { width = stack.shift() + nominalWidthX; haveWidth = true; } y += stack.pop(); x += stack.pop(); if(open) P.ClosePath(p); P.MoveTo(p,x,y); open=true; } else if(v=="o22") { if (stack.length > 1 && !haveWidth) { width = stack.shift() + nominalWidthX; haveWidth = true; } x += stack.pop(); if(open) P.ClosePath(p); P.MoveTo(p,x,y); open=true; } else if(v=="o25") { while (stack.length > 6) { x += stack.shift(); y += stack.shift(); P.LineTo(p, x, y); } c1x = x + stack.shift(); c1y = y + stack.shift(); c2x = c1x + stack.shift(); c2y = c1y + stack.shift(); x = c2x + stack.shift(); y = c2y + stack.shift(); P.CurveTo(p, c1x, c1y, c2x, c2y, x, y); } else if(v=="o26") { if (stack.length % 2) { x += stack.shift(); } while (stack.length > 0) { c1x = x; c1y = y + stack.shift(); c2x = c1x + stack.shift(); c2y = c1y + stack.shift(); x = c2x; y = c2y + stack.shift(); P.CurveTo(p, c1x, c1y, c2x, c2y, x, y); } } else if(v=="o27") { if (stack.length % 2) { y += stack.shift(); } while (stack.length > 0) { c1x = x + stack.shift(); c1y = y; c2x = c1x + stack.shift(); c2y = c1y + stack.shift(); x = c2x + stack.shift(); y = c2y; P.CurveTo(p, c1x, c1y, c2x, c2y, x, y); } } else if(v=="o10" || v=="o29") // callsubr || callgsubr { var obj = (v=="o10" ? pdct : font); if(stack.length==0) { console.log("error: empty stack"); } else { var ind = stack.pop(); var subr = obj["Subrs"][ ind + obj["Bias"] ]; state.x=x; state.y=y; state.nStems=nStems; state.haveWidth=haveWidth; state.width=width; state.open=open; Typr["U"]["_drawCFF"](subr, state,font,pdct,p); x=state.x; y=state.y; nStems=state.nStems; haveWidth=state.haveWidth; width=state.width; open=state.open; } } else if(v=="o30" || v=="o31") // vhcurveto || hvcurveto { var count, count1 = stack.length; var index = 0; var alternate = v == "o31"; count = count1 & ~2; index += count1 - count; while ( index < count ) { if(alternate) { c1x = x + stack.shift(); c1y = y; c2x = c1x + stack.shift(); c2y = c1y + stack.shift(); y = c2y + stack.shift(); if(count-index == 5) { x = c2x + stack.shift(); index++; } else x = c2x; alternate = false; } else { c1x = x; c1y = y + stack.shift(); c2x = c1x + stack.shift(); c2y = c1y + stack.shift(); x = c2x + stack.shift(); if(count-index == 5) { y = c2y + stack.shift(); index++; } else y = c2y; alternate = true; } P.CurveTo(p, c1x, c1y, c2x, c2y, x, y); index += 4; } } else if((v+"").charAt(0)=="o") { console.log("Unknown operation: "+v, cmds); throw v; } else stack.push(v); } //console.log(cmds); state.x=x; state.y=y; state.nStems=nStems; state.haveWidth=haveWidth; state.width=width; state.open=open; }, "SVG" : function() { var M = { getScale : function(m) { return Math.sqrt(Math.abs(m[0]*m[3]-m[1]*m[2])); }, translate: function(m,x,y) { M.concat(m, [1,0,0,1,x,y]); }, rotate : function(m,a ) { M.concat(m, [Math.cos(a), -Math.sin(a), Math.sin(a), Math.cos(a),0,0]); }, scale : function(m,x,y) { M.concat(m, [x,0,0,y,0,0]); }, concat : function(m,w ) { var a=m[0],b=m[1],c=m[2],d=m[3],tx=m[4],ty=m[5]; m[0] = (a *w[0])+(b *w[2]); m[1] = (a *w[1])+(b *w[3]); m[2] = (c *w[0])+(d *w[2]); m[3] = (c *w[1])+(d *w[3]); m[4] = (tx*w[0])+(ty*w[2])+w[4]; m[5] = (tx*w[1])+(ty*w[3])+w[5]; }, invert : function(m ) { var a=m[0],b=m[1],c=m[2],d=m[3],tx=m[4],ty=m[5], adbc=a*d-b*c; m[0] = d/adbc; m[1] = -b/adbc; m[2] =-c/adbc; m[3] = a/adbc; m[4] = (c*ty - d*tx)/adbc; m[5] = (b*tx - a*ty)/adbc; }, 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]]; }, multArray: function(m, a ) { for(var i=0; i0 && vls[i-1]!="e") { vls = vls.slice(0,i) + " "+vls.slice(i); i++; gotSep=true; } } vls = vls.split(/\s*[\s,]\s*/).map(parseFloat); if(false) {} else if(fnc=="translate") { if(vls.length==1) M.translate(m,vls[0], 0); else M.translate(m,vls[0],vls[1]); } else if(fnc=="scale" ) { if(vls.length==1) M.scale (m,vls[0],vls[0]); else M.scale (m,vls[0],vls[1]); } 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); } else if(fnc=="matrix" ) m = vls; else console.log("unknown transform: ", fnc); return m; } function toPath(str) { var pth = {cmds:[], crds:[]}; if(str==null) return pth; var prsr = new DOMParser(); var doc = prsr["parseFromString"](str,"image/svg+xml"); //var svg = doc.firstChild; while(svg.tagName!="svg") svg = svg.nextSibling; var svg = doc.getElementsByTagName("svg")[0]; var vb = svg.getAttribute("viewBox"); if(vb) vb = vb.trim().split(" ").map(parseFloat); else vb = [0,0,1000,1000]; _toPath(svg.children, pth); for(var i=0; i=0?1:-1) * Math.acos( Math.max(-1, Math.min(1, num)) ); } var vX = (x1A-cxA)/rx, vY = (y1A-cyA)/ry; var theta1 = angl( 1, 0, vX,vY); var dtheta = angl(vX,vY, (-x1A-cxA)/rx, (-y1A-cyA)/ry); dtheta = dtheta % (2*Math.PI); var arc = function(gst,x,y,r,a0,a1, neg) { var rotate = function(m, a) { var si=Math.sin(a), co=Math.cos(a); var a=m[0],b=m[1],c=m[2],d=m[3]; m[0] = (a *co)+(b *si); m[1] = (-a *si)+(b *co); m[2] = (c *co)+(d *si); m[3] = (-c *si)+(d *co); } var multArr= function(m,a) { for(var j=0; ja0) a1-=2*Math.PI; else while(a1>>2; var pPtr32 = exp["hb_buffer_get_glyph_positions"](ptr, 0) >>>2; for(var i=0; i>>16)+4); //console.log("growing",nlen); } heapu8 = new Uint8Array (mem.buffer); u32 = new Uint32Array(mem.buffer); i32 = new Int32Array (mem.buffer); if(__lastFnt!=fn) { if(blob!=null) { exp["hb_blob_destroy"](blob); exp["free"](blobPtr); exp["hb_face_destroy"](face); exp["hb_font_destroy"](font); } blobPtr = exp["malloc"](fdata.byteLength); heapu8.set(fdata, blobPtr); blob = exp["hb_blob_create"](blobPtr, fdata.byteLength, 2, 0, 0); face = exp["hb_face_create"](blob, 0); font = exp["hb_font_create"](face) __lastFnt = fn; } if(window["TextEncoder"]==null) { alert("Your browser is too old. Please, update it."); return; } if(te==null) te = new window["TextEncoder"]("utf8"); var buffer = exp["hb_buffer_create"](); var bytes = te["encode"](str); var len=bytes.length, strp = exp["malloc"](len); heapu8.set(bytes, strp); exp["hb_buffer_add_utf8"](buffer, strp, len, 0, len); exp["free"](strp); exp["hb_buffer_set_direction"](buffer,ltr?4:5); exp["hb_buffer_guess_segment_properties"](buffer); exp["hb_shape"](font, buffer, 0, 0); var json = toJson(buffer)//buffer["json"](); exp["hb_buffer_destroy"](buffer); var arr = json.slice(0); if(!ltr) arr.reverse(); var ci=0, bi=0; // character index, binary index for(var i=1; i