three-stdlib
Version:
stand-alone library of threejs examples
1 lines • 727 kB
Source Map (JSON)
{"version":3,"file":"opentype.cjs","sources":["../../src/libs/opentype.js"],"sourcesContent":["const { parseBuffer } = /* @__PURE__ */ (() => {\n /**\n * https://opentype.js.org v1.3.4 | (c) Frederik De Bleser and other contributors | MIT License | Uses tiny-inflate by Devon Govett and string.prototype.codepointat polyfill by Mathias Bynens\n */\n\n var TINF_OK = 0\n var TINF_DATA_ERROR = -3\n\n function Tree() {\n this.table = new Uint16Array(16) /* table of code length counts */\n this.trans = new Uint16Array(288) /* code -> symbol translation table */\n }\n\n function Data(source, dest) {\n this.source = source\n this.sourceIndex = 0\n this.tag = 0\n this.bitcount = 0\n\n this.dest = dest\n this.destLen = 0\n\n this.ltree = new Tree() /* dynamic length/symbol tree */\n this.dtree = new Tree() /* dynamic distance tree */\n }\n\n /* --------------------------------------------------- *\n * -- uninitialized global data (static structures) -- *\n * --------------------------------------------------- */\n\n var sltree = new Tree()\n var sdtree = new Tree()\n\n /* extra bits and base tables for length codes */\n var length_bits = new Uint8Array(30)\n var length_base = new Uint16Array(30)\n\n /* extra bits and base tables for distance codes */\n var dist_bits = new Uint8Array(30)\n var dist_base = new Uint16Array(30)\n\n /* special ordering of code length codes */\n var clcidx = new Uint8Array([16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15])\n\n /* used by tinf_decode_trees, avoids allocations every call */\n var code_tree = new Tree()\n var lengths = new Uint8Array(288 + 32)\n\n /* ----------------------- *\n * -- utility functions -- *\n * ----------------------- */\n\n /* build extra bits and base tables */\n function tinf_build_bits_base(bits, base, delta, first) {\n var i, sum\n\n /* build bits table */\n for (i = 0; i < delta; ++i) {\n bits[i] = 0\n }\n for (i = 0; i < 30 - delta; ++i) {\n bits[i + delta] = (i / delta) | 0\n }\n\n /* build base table */\n for (sum = first, i = 0; i < 30; ++i) {\n base[i] = sum\n sum += 1 << bits[i]\n }\n }\n\n /* build the fixed huffman trees */\n function tinf_build_fixed_trees(lt, dt) {\n var i\n\n /* build fixed length tree */\n for (i = 0; i < 7; ++i) {\n lt.table[i] = 0\n }\n\n lt.table[7] = 24\n lt.table[8] = 152\n lt.table[9] = 112\n\n for (i = 0; i < 24; ++i) {\n lt.trans[i] = 256 + i\n }\n for (i = 0; i < 144; ++i) {\n lt.trans[24 + i] = i\n }\n for (i = 0; i < 8; ++i) {\n lt.trans[24 + 144 + i] = 280 + i\n }\n for (i = 0; i < 112; ++i) {\n lt.trans[24 + 144 + 8 + i] = 144 + i\n }\n\n /* build fixed distance tree */\n for (i = 0; i < 5; ++i) {\n dt.table[i] = 0\n }\n\n dt.table[5] = 32\n\n for (i = 0; i < 32; ++i) {\n dt.trans[i] = i\n }\n }\n\n /* given an array of code lengths, build a tree */\n var offs = new Uint16Array(16)\n\n function tinf_build_tree(t, lengths, off, num) {\n var i, sum\n\n /* clear code length count table */\n for (i = 0; i < 16; ++i) {\n t.table[i] = 0\n }\n\n /* scan symbol lengths, and sum code length counts */\n for (i = 0; i < num; ++i) {\n t.table[lengths[off + i]]++\n }\n\n t.table[0] = 0\n\n /* compute offset table for distribution sort */\n for (sum = 0, i = 0; i < 16; ++i) {\n offs[i] = sum\n sum += t.table[i]\n }\n\n /* create code->symbol translation table (symbols sorted by code) */\n for (i = 0; i < num; ++i) {\n if (lengths[off + i]) {\n t.trans[offs[lengths[off + i]]++] = i\n }\n }\n }\n\n /* ---------------------- *\n * -- decode functions -- *\n * ---------------------- */\n\n /* get one bit from source stream */\n function tinf_getbit(d) {\n /* check if tag is empty */\n if (!d.bitcount--) {\n /* load next tag */\n d.tag = d.source[d.sourceIndex++]\n d.bitcount = 7\n }\n\n /* shift bit out of tag */\n var bit = d.tag & 1\n d.tag >>>= 1\n\n return bit\n }\n\n /* read a num bit value from a stream and add base */\n function tinf_read_bits(d, num, base) {\n if (!num) {\n return base\n }\n\n while (d.bitcount < 24) {\n d.tag |= d.source[d.sourceIndex++] << d.bitcount\n d.bitcount += 8\n }\n\n var val = d.tag & (0xffff >>> (16 - num))\n d.tag >>>= num\n d.bitcount -= num\n return val + base\n }\n\n /* given a data stream and a tree, decode a symbol */\n function tinf_decode_symbol(d, t) {\n while (d.bitcount < 24) {\n d.tag |= d.source[d.sourceIndex++] << d.bitcount\n d.bitcount += 8\n }\n\n var sum = 0,\n cur = 0,\n len = 0\n var tag = d.tag\n\n /* get more bits while code value is above sum */\n do {\n cur = 2 * cur + (tag & 1)\n tag >>>= 1\n ++len\n\n sum += t.table[len]\n cur -= t.table[len]\n } while (cur >= 0)\n\n d.tag = tag\n d.bitcount -= len\n\n return t.trans[sum + cur]\n }\n\n /* given a data stream, decode dynamic trees from it */\n function tinf_decode_trees(d, lt, dt) {\n var hlit, hdist, hclen\n var i, num, length\n\n /* get 5 bits HLIT (257-286) */\n hlit = tinf_read_bits(d, 5, 257)\n\n /* get 5 bits HDIST (1-32) */\n hdist = tinf_read_bits(d, 5, 1)\n\n /* get 4 bits HCLEN (4-19) */\n hclen = tinf_read_bits(d, 4, 4)\n\n for (i = 0; i < 19; ++i) {\n lengths[i] = 0\n }\n\n /* read code lengths for code length alphabet */\n for (i = 0; i < hclen; ++i) {\n /* get 3 bits code length (0-7) */\n var clen = tinf_read_bits(d, 3, 0)\n lengths[clcidx[i]] = clen\n }\n\n /* build code length tree */\n tinf_build_tree(code_tree, lengths, 0, 19)\n\n /* decode code lengths for the dynamic trees */\n for (num = 0; num < hlit + hdist; ) {\n var sym = tinf_decode_symbol(d, code_tree)\n\n switch (sym) {\n case 16:\n /* copy previous code length 3-6 times (read 2 bits) */\n var prev = lengths[num - 1]\n for (length = tinf_read_bits(d, 2, 3); length; --length) {\n lengths[num++] = prev\n }\n break\n case 17:\n /* repeat code length 0 for 3-10 times (read 3 bits) */\n for (length = tinf_read_bits(d, 3, 3); length; --length) {\n lengths[num++] = 0\n }\n break\n case 18:\n /* repeat code length 0 for 11-138 times (read 7 bits) */\n for (length = tinf_read_bits(d, 7, 11); length; --length) {\n lengths[num++] = 0\n }\n break\n default:\n /* values 0-15 represent the actual code lengths */\n lengths[num++] = sym\n break\n }\n }\n\n /* build dynamic trees */\n tinf_build_tree(lt, lengths, 0, hlit)\n tinf_build_tree(dt, lengths, hlit, hdist)\n }\n\n /* ----------------------------- *\n * -- block inflate functions -- *\n * ----------------------------- */\n\n /* given a stream and two trees, inflate a block of data */\n function tinf_inflate_block_data(d, lt, dt) {\n while (1) {\n var sym = tinf_decode_symbol(d, lt)\n\n /* check for end of block */\n if (sym === 256) {\n return TINF_OK\n }\n\n if (sym < 256) {\n d.dest[d.destLen++] = sym\n } else {\n var length, dist, offs\n var i\n\n sym -= 257\n\n /* possibly get more bits from length code */\n length = tinf_read_bits(d, length_bits[sym], length_base[sym])\n\n dist = tinf_decode_symbol(d, dt)\n\n /* possibly get more bits from distance code */\n offs = d.destLen - tinf_read_bits(d, dist_bits[dist], dist_base[dist])\n\n /* copy match */\n for (i = offs; i < offs + length; ++i) {\n d.dest[d.destLen++] = d.dest[i]\n }\n }\n }\n }\n\n /* inflate an uncompressed block of data */\n function tinf_inflate_uncompressed_block(d) {\n var length, invlength\n var i\n\n /* unread from bitbuffer */\n while (d.bitcount > 8) {\n d.sourceIndex--\n d.bitcount -= 8\n }\n\n /* get length */\n length = d.source[d.sourceIndex + 1]\n length = 256 * length + d.source[d.sourceIndex]\n\n /* get one's complement of length */\n invlength = d.source[d.sourceIndex + 3]\n invlength = 256 * invlength + d.source[d.sourceIndex + 2]\n\n /* check length */\n if (length !== (~invlength & 0x0000ffff)) {\n return TINF_DATA_ERROR\n }\n\n d.sourceIndex += 4\n\n /* copy block */\n for (i = length; i; --i) {\n d.dest[d.destLen++] = d.source[d.sourceIndex++]\n }\n\n /* make sure we start next block on a byte boundary */\n d.bitcount = 0\n\n return TINF_OK\n }\n\n /* inflate stream from source to dest */\n function tinf_uncompress(source, dest) {\n var d = new Data(source, dest)\n var bfinal, btype, res\n\n do {\n /* read final block flag */\n bfinal = tinf_getbit(d)\n\n /* read block type (2 bits) */\n btype = tinf_read_bits(d, 2, 0)\n\n /* decompress block */\n switch (btype) {\n case 0:\n /* decompress uncompressed block */\n res = tinf_inflate_uncompressed_block(d)\n break\n case 1:\n /* decompress block with fixed huffman trees */\n res = tinf_inflate_block_data(d, sltree, sdtree)\n break\n case 2:\n /* decompress block with dynamic huffman trees */\n tinf_decode_trees(d, d.ltree, d.dtree)\n res = tinf_inflate_block_data(d, d.ltree, d.dtree)\n break\n default:\n res = TINF_DATA_ERROR\n }\n\n if (res !== TINF_OK) {\n throw new Error('Data error')\n }\n } while (!bfinal)\n\n if (d.destLen < d.dest.length) {\n if (typeof d.dest.slice === 'function') {\n return d.dest.slice(0, d.destLen)\n } else {\n return d.dest.subarray(0, d.destLen)\n }\n }\n\n return d.dest\n }\n\n /* -------------------- *\n * -- initialization -- *\n * -------------------- */\n\n /* build fixed huffman trees */\n tinf_build_fixed_trees(sltree, sdtree)\n\n /* build extra bits and base tables */\n tinf_build_bits_base(length_bits, length_base, 4, 3)\n tinf_build_bits_base(dist_bits, dist_base, 2, 1)\n\n /* fix a special case */\n length_bits[28] = 0\n length_base[28] = 258\n\n var tinyInflate = tinf_uncompress\n\n // The Bounding Box object\n\n function derive(v0, v1, v2, v3, t) {\n return (\n Math.pow(1 - t, 3) * v0 +\n 3 * Math.pow(1 - t, 2) * t * v1 +\n 3 * (1 - t) * Math.pow(t, 2) * v2 +\n Math.pow(t, 3) * v3\n )\n }\n /**\n * A bounding box is an enclosing box that describes the smallest measure within which all the points lie.\n * It is used to calculate the bounding box of a glyph or text path.\n *\n * On initialization, x1/y1/x2/y2 will be NaN. Check if the bounding box is empty using `isEmpty()`.\n *\n * @exports opentype.BoundingBox\n * @class\n * @constructor\n */\n function BoundingBox() {\n this.x1 = Number.NaN\n this.y1 = Number.NaN\n this.x2 = Number.NaN\n this.y2 = Number.NaN\n }\n\n /**\n * Returns true if the bounding box is empty, that is, no points have been added to the box yet.\n */\n BoundingBox.prototype.isEmpty = function () {\n return isNaN(this.x1) || isNaN(this.y1) || isNaN(this.x2) || isNaN(this.y2)\n }\n\n /**\n * Add the point to the bounding box.\n * The x1/y1/x2/y2 coordinates of the bounding box will now encompass the given point.\n * @param {number} x - The X coordinate of the point.\n * @param {number} y - The Y coordinate of the point.\n */\n BoundingBox.prototype.addPoint = function (x, y) {\n if (typeof x === 'number') {\n if (isNaN(this.x1) || isNaN(this.x2)) {\n this.x1 = x\n this.x2 = x\n }\n if (x < this.x1) {\n this.x1 = x\n }\n if (x > this.x2) {\n this.x2 = x\n }\n }\n if (typeof y === 'number') {\n if (isNaN(this.y1) || isNaN(this.y2)) {\n this.y1 = y\n this.y2 = y\n }\n if (y < this.y1) {\n this.y1 = y\n }\n if (y > this.y2) {\n this.y2 = y\n }\n }\n }\n\n /**\n * Add a X coordinate to the bounding box.\n * This extends the bounding box to include the X coordinate.\n * This function is used internally inside of addBezier.\n * @param {number} x - The X coordinate of the point.\n */\n BoundingBox.prototype.addX = function (x) {\n this.addPoint(x, null)\n }\n\n /**\n * Add a Y coordinate to the bounding box.\n * This extends the bounding box to include the Y coordinate.\n * This function is used internally inside of addBezier.\n * @param {number} y - The Y coordinate of the point.\n */\n BoundingBox.prototype.addY = function (y) {\n this.addPoint(null, y)\n }\n\n /**\n * Add a Bézier curve to the bounding box.\n * This extends the bounding box to include the entire Bézier.\n * @param {number} x0 - The starting X coordinate.\n * @param {number} y0 - The starting Y coordinate.\n * @param {number} x1 - The X coordinate of the first control point.\n * @param {number} y1 - The Y coordinate of the first control point.\n * @param {number} x2 - The X coordinate of the second control point.\n * @param {number} y2 - The Y coordinate of the second control point.\n * @param {number} x - The ending X coordinate.\n * @param {number} y - The ending Y coordinate.\n */\n BoundingBox.prototype.addBezier = function (x0, y0, x1, y1, x2, y2, x, y) {\n // This code is based on http://nishiohirokazu.blogspot.com/2009/06/how-to-calculate-bezier-curves-bounding.html\n // and https://github.com/icons8/svg-path-bounding-box\n\n var p0 = [x0, y0]\n var p1 = [x1, y1]\n var p2 = [x2, y2]\n var p3 = [x, y]\n\n this.addPoint(x0, y0)\n this.addPoint(x, y)\n\n for (var i = 0; i <= 1; i++) {\n var b = 6 * p0[i] - 12 * p1[i] + 6 * p2[i]\n var a = -3 * p0[i] + 9 * p1[i] - 9 * p2[i] + 3 * p3[i]\n var c = 3 * p1[i] - 3 * p0[i]\n\n if (a === 0) {\n if (b === 0) {\n continue\n }\n var t = -c / b\n if (0 < t && t < 1) {\n if (i === 0) {\n this.addX(derive(p0[i], p1[i], p2[i], p3[i], t))\n }\n if (i === 1) {\n this.addY(derive(p0[i], p1[i], p2[i], p3[i], t))\n }\n }\n continue\n }\n\n var b2ac = Math.pow(b, 2) - 4 * c * a\n if (b2ac < 0) {\n continue\n }\n var t1 = (-b + Math.sqrt(b2ac)) / (2 * a)\n if (0 < t1 && t1 < 1) {\n if (i === 0) {\n this.addX(derive(p0[i], p1[i], p2[i], p3[i], t1))\n }\n if (i === 1) {\n this.addY(derive(p0[i], p1[i], p2[i], p3[i], t1))\n }\n }\n var t2 = (-b - Math.sqrt(b2ac)) / (2 * a)\n if (0 < t2 && t2 < 1) {\n if (i === 0) {\n this.addX(derive(p0[i], p1[i], p2[i], p3[i], t2))\n }\n if (i === 1) {\n this.addY(derive(p0[i], p1[i], p2[i], p3[i], t2))\n }\n }\n }\n }\n\n /**\n * Add a quadratic curve to the bounding box.\n * This extends the bounding box to include the entire quadratic curve.\n * @param {number} x0 - The starting X coordinate.\n * @param {number} y0 - The starting Y coordinate.\n * @param {number} x1 - The X coordinate of the control point.\n * @param {number} y1 - The Y coordinate of the control point.\n * @param {number} x - The ending X coordinate.\n * @param {number} y - The ending Y coordinate.\n */\n BoundingBox.prototype.addQuad = function (x0, y0, x1, y1, x, y) {\n var cp1x = x0 + (2 / 3) * (x1 - x0)\n var cp1y = y0 + (2 / 3) * (y1 - y0)\n var cp2x = cp1x + (1 / 3) * (x - x0)\n var cp2y = cp1y + (1 / 3) * (y - y0)\n this.addBezier(x0, y0, cp1x, cp1y, cp2x, cp2y, x, y)\n }\n\n // Geometric objects\n\n /**\n * A bézier path containing a set of path commands similar to a SVG path.\n * Paths can be drawn on a context using `draw`.\n * @exports opentype.Path\n * @class\n * @constructor\n */\n function Path() {\n this.commands = []\n this.fill = 'black'\n this.stroke = null\n this.strokeWidth = 1\n }\n\n /**\n * @param {number} x\n * @param {number} y\n */\n Path.prototype.moveTo = function (x, y) {\n this.commands.push({\n type: 'M',\n x: x,\n y: y,\n })\n }\n\n /**\n * @param {number} x\n * @param {number} y\n */\n Path.prototype.lineTo = function (x, y) {\n this.commands.push({\n type: 'L',\n x: x,\n y: y,\n })\n }\n\n /**\n * Draws cubic curve\n * @function\n * curveTo\n * @memberof opentype.Path.prototype\n * @param {number} x1 - x of control 1\n * @param {number} y1 - y of control 1\n * @param {number} x2 - x of control 2\n * @param {number} y2 - y of control 2\n * @param {number} x - x of path point\n * @param {number} y - y of path point\n */\n\n /**\n * Draws cubic curve\n * @function\n * bezierCurveTo\n * @memberof opentype.Path.prototype\n * @param {number} x1 - x of control 1\n * @param {number} y1 - y of control 1\n * @param {number} x2 - x of control 2\n * @param {number} y2 - y of control 2\n * @param {number} x - x of path point\n * @param {number} y - y of path point\n * @see curveTo\n */\n Path.prototype.curveTo = Path.prototype.bezierCurveTo = function (x1, y1, x2, y2, x, y) {\n this.commands.push({\n type: 'C',\n x1: x1,\n y1: y1,\n x2: x2,\n y2: y2,\n x: x,\n y: y,\n })\n }\n\n /**\n * Draws quadratic curve\n * @function\n * quadraticCurveTo\n * @memberof opentype.Path.prototype\n * @param {number} x1 - x of control\n * @param {number} y1 - y of control\n * @param {number} x - x of path point\n * @param {number} y - y of path point\n */\n\n /**\n * Draws quadratic curve\n * @function\n * quadTo\n * @memberof opentype.Path.prototype\n * @param {number} x1 - x of control\n * @param {number} y1 - y of control\n * @param {number} x - x of path point\n * @param {number} y - y of path point\n */\n Path.prototype.quadTo = Path.prototype.quadraticCurveTo = function (x1, y1, x, y) {\n this.commands.push({\n type: 'Q',\n x1: x1,\n y1: y1,\n x: x,\n y: y,\n })\n }\n\n /**\n * Closes the path\n * @function closePath\n * @memberof opentype.Path.prototype\n */\n\n /**\n * Close the path\n * @function close\n * @memberof opentype.Path.prototype\n */\n Path.prototype.close = Path.prototype.closePath = function () {\n this.commands.push({\n type: 'Z',\n })\n }\n\n /**\n * Add the given path or list of commands to the commands of this path.\n * @param {Array} pathOrCommands - another opentype.Path, an opentype.BoundingBox, or an array of commands.\n */\n Path.prototype.extend = function (pathOrCommands) {\n if (pathOrCommands.commands) {\n pathOrCommands = pathOrCommands.commands\n } else if (pathOrCommands instanceof BoundingBox) {\n var box = pathOrCommands\n this.moveTo(box.x1, box.y1)\n this.lineTo(box.x2, box.y1)\n this.lineTo(box.x2, box.y2)\n this.lineTo(box.x1, box.y2)\n this.close()\n return\n }\n\n Array.prototype.push.apply(this.commands, pathOrCommands)\n }\n\n /**\n * Calculate the bounding box of the path.\n * @returns {opentype.BoundingBox}\n */\n Path.prototype.getBoundingBox = function () {\n var box = new BoundingBox()\n\n var startX = 0\n var startY = 0\n var prevX = 0\n var prevY = 0\n for (var i = 0; i < this.commands.length; i++) {\n var cmd = this.commands[i]\n switch (cmd.type) {\n case 'M':\n box.addPoint(cmd.x, cmd.y)\n startX = prevX = cmd.x\n startY = prevY = cmd.y\n break\n case 'L':\n box.addPoint(cmd.x, cmd.y)\n prevX = cmd.x\n prevY = cmd.y\n break\n case 'Q':\n box.addQuad(prevX, prevY, cmd.x1, cmd.y1, cmd.x, cmd.y)\n prevX = cmd.x\n prevY = cmd.y\n break\n case 'C':\n box.addBezier(prevX, prevY, cmd.x1, cmd.y1, cmd.x2, cmd.y2, cmd.x, cmd.y)\n prevX = cmd.x\n prevY = cmd.y\n break\n case 'Z':\n prevX = startX\n prevY = startY\n break\n default:\n throw new Error('Unexpected path command ' + cmd.type)\n }\n }\n if (box.isEmpty()) {\n box.addPoint(0, 0)\n }\n return box\n }\n\n /**\n * Draw the path to a 2D context.\n * @param {CanvasRenderingContext2D} ctx - A 2D drawing context.\n */\n Path.prototype.draw = function (ctx) {\n ctx.beginPath()\n for (var i = 0; i < this.commands.length; i += 1) {\n var cmd = this.commands[i]\n if (cmd.type === 'M') {\n ctx.moveTo(cmd.x, cmd.y)\n } else if (cmd.type === 'L') {\n ctx.lineTo(cmd.x, cmd.y)\n } else if (cmd.type === 'C') {\n ctx.bezierCurveTo(cmd.x1, cmd.y1, cmd.x2, cmd.y2, cmd.x, cmd.y)\n } else if (cmd.type === 'Q') {\n ctx.quadraticCurveTo(cmd.x1, cmd.y1, cmd.x, cmd.y)\n } else if (cmd.type === 'Z') {\n ctx.closePath()\n }\n }\n\n if (this.fill) {\n ctx.fillStyle = this.fill\n ctx.fill()\n }\n\n if (this.stroke) {\n ctx.strokeStyle = this.stroke\n ctx.lineWidth = this.strokeWidth\n ctx.stroke()\n }\n }\n\n /**\n * Convert the Path to a string of path data instructions\n * See http://www.w3.org/TR/SVG/paths.html#PathData\n * @param {number} [decimalPlaces=2] - The amount of decimal places for floating-point values\n * @return {string}\n */\n Path.prototype.toPathData = function (decimalPlaces) {\n decimalPlaces = decimalPlaces !== undefined ? decimalPlaces : 2\n\n function floatToString(v) {\n if (Math.round(v) === v) {\n return '' + Math.round(v)\n } else {\n return v.toFixed(decimalPlaces)\n }\n }\n\n function packValues() {\n var arguments$1 = arguments\n\n var s = ''\n for (var i = 0; i < arguments.length; i += 1) {\n var v = arguments$1[i]\n if (v >= 0 && i > 0) {\n s += ' '\n }\n\n s += floatToString(v)\n }\n\n return s\n }\n\n var d = ''\n for (var i = 0; i < this.commands.length; i += 1) {\n var cmd = this.commands[i]\n if (cmd.type === 'M') {\n d += 'M' + packValues(cmd.x, cmd.y)\n } else if (cmd.type === 'L') {\n d += 'L' + packValues(cmd.x, cmd.y)\n } else if (cmd.type === 'C') {\n d += 'C' + packValues(cmd.x1, cmd.y1, cmd.x2, cmd.y2, cmd.x, cmd.y)\n } else if (cmd.type === 'Q') {\n d += 'Q' + packValues(cmd.x1, cmd.y1, cmd.x, cmd.y)\n } else if (cmd.type === 'Z') {\n d += 'Z'\n }\n }\n\n return d\n }\n\n /**\n * Convert the path to an SVG <path> element, as a string.\n * @param {number} [decimalPlaces=2] - The amount of decimal places for floating-point values\n * @return {string}\n */\n Path.prototype.toSVG = function (decimalPlaces) {\n var svg = '<path d=\"'\n svg += this.toPathData(decimalPlaces)\n svg += '\"'\n if (this.fill && this.fill !== 'black') {\n if (this.fill === null) {\n svg += ' fill=\"none\"'\n } else {\n svg += ' fill=\"' + this.fill + '\"'\n }\n }\n\n if (this.stroke) {\n svg += ' stroke=\"' + this.stroke + '\" stroke-width=\"' + this.strokeWidth + '\"'\n }\n\n svg += '/>'\n return svg\n }\n\n /**\n * Convert the path to a DOM element.\n * @param {number} [decimalPlaces=2] - The amount of decimal places for floating-point values\n * @return {SVGPathElement}\n */\n Path.prototype.toDOMElement = function (decimalPlaces) {\n var temporaryPath = this.toPathData(decimalPlaces)\n var newPath = document.createElementNS('http://www.w3.org/2000/svg', 'path')\n\n newPath.setAttribute('d', temporaryPath)\n\n return newPath\n }\n\n // Run-time checking of preconditions.\n\n function fail(message) {\n throw new Error(message)\n }\n\n // Precondition function that checks if the given predicate is true.\n // If not, it will throw an error.\n function argument(predicate, message) {\n if (!predicate) {\n fail(message)\n }\n }\n var check = { fail: fail, argument: argument, assert: argument }\n\n // Data types used in the OpenType font file.\n\n var LIMIT16 = 32768 // The limit at which a 16-bit number switches signs == 2^15\n var LIMIT32 = 2147483648 // The limit at which a 32-bit number switches signs == 2 ^ 31\n\n /**\n * @exports opentype.decode\n * @class\n */\n var decode = {}\n /**\n * @exports opentype.encode\n * @class\n */\n var encode = {}\n /**\n * @exports opentype.sizeOf\n * @class\n */\n var sizeOf = {}\n\n // Return a function that always returns the same value.\n function constant(v) {\n return function () {\n return v\n }\n }\n\n // OpenType data types //////////////////////////////////////////////////////\n\n /**\n * Convert an 8-bit unsigned integer to a list of 1 byte.\n * @param {number}\n * @returns {Array}\n */\n encode.BYTE = function (v) {\n check.argument(v >= 0 && v <= 255, 'Byte value should be between 0 and 255.')\n return [v]\n }\n /**\n * @constant\n * @type {number}\n */\n sizeOf.BYTE = constant(1)\n\n /**\n * Convert a 8-bit signed integer to a list of 1 byte.\n * @param {string}\n * @returns {Array}\n */\n encode.CHAR = function (v) {\n return [v.charCodeAt(0)]\n }\n\n /**\n * @constant\n * @type {number}\n */\n sizeOf.CHAR = constant(1)\n\n /**\n * Convert an ASCII string to a list of bytes.\n * @param {string}\n * @returns {Array}\n */\n encode.CHARARRAY = function (v) {\n if (typeof v === 'undefined') {\n v = ''\n console.warn(\n 'Undefined CHARARRAY encountered and treated as an empty string. This is probably caused by a missing glyph name.',\n )\n }\n var b = []\n for (var i = 0; i < v.length; i += 1) {\n b[i] = v.charCodeAt(i)\n }\n\n return b\n }\n\n /**\n * @param {Array}\n * @returns {number}\n */\n sizeOf.CHARARRAY = function (v) {\n if (typeof v === 'undefined') {\n return 0\n }\n return v.length\n }\n\n /**\n * Convert a 16-bit unsigned integer to a list of 2 bytes.\n * @param {number}\n * @returns {Array}\n */\n encode.USHORT = function (v) {\n return [(v >> 8) & 0xff, v & 0xff]\n }\n\n /**\n * @constant\n * @type {number}\n */\n sizeOf.USHORT = constant(2)\n\n /**\n * Convert a 16-bit signed integer to a list of 2 bytes.\n * @param {number}\n * @returns {Array}\n */\n encode.SHORT = function (v) {\n // Two's complement\n if (v >= LIMIT16) {\n v = -(2 * LIMIT16 - v)\n }\n\n return [(v >> 8) & 0xff, v & 0xff]\n }\n\n /**\n * @constant\n * @type {number}\n */\n sizeOf.SHORT = constant(2)\n\n /**\n * Convert a 24-bit unsigned integer to a list of 3 bytes.\n * @param {number}\n * @returns {Array}\n */\n encode.UINT24 = function (v) {\n return [(v >> 16) & 0xff, (v >> 8) & 0xff, v & 0xff]\n }\n\n /**\n * @constant\n * @type {number}\n */\n sizeOf.UINT24 = constant(3)\n\n /**\n * Convert a 32-bit unsigned integer to a list of 4 bytes.\n * @param {number}\n * @returns {Array}\n */\n encode.ULONG = function (v) {\n return [(v >> 24) & 0xff, (v >> 16) & 0xff, (v >> 8) & 0xff, v & 0xff]\n }\n\n /**\n * @constant\n * @type {number}\n */\n sizeOf.ULONG = constant(4)\n\n /**\n * Convert a 32-bit unsigned integer to a list of 4 bytes.\n * @param {number}\n * @returns {Array}\n */\n encode.LONG = function (v) {\n // Two's complement\n if (v >= LIMIT32) {\n v = -(2 * LIMIT32 - v)\n }\n\n return [(v >> 24) & 0xff, (v >> 16) & 0xff, (v >> 8) & 0xff, v & 0xff]\n }\n\n /**\n * @constant\n * @type {number}\n */\n sizeOf.LONG = constant(4)\n\n encode.FIXED = encode.ULONG\n sizeOf.FIXED = sizeOf.ULONG\n\n encode.FWORD = encode.SHORT\n sizeOf.FWORD = sizeOf.SHORT\n\n encode.UFWORD = encode.USHORT\n sizeOf.UFWORD = sizeOf.USHORT\n\n /**\n * Convert a 32-bit Apple Mac timestamp integer to a list of 8 bytes, 64-bit timestamp.\n * @param {number}\n * @returns {Array}\n */\n encode.LONGDATETIME = function (v) {\n return [0, 0, 0, 0, (v >> 24) & 0xff, (v >> 16) & 0xff, (v >> 8) & 0xff, v & 0xff]\n }\n\n /**\n * @constant\n * @type {number}\n */\n sizeOf.LONGDATETIME = constant(8)\n\n /**\n * Convert a 4-char tag to a list of 4 bytes.\n * @param {string}\n * @returns {Array}\n */\n encode.TAG = function (v) {\n check.argument(v.length === 4, 'Tag should be exactly 4 ASCII characters.')\n return [v.charCodeAt(0), v.charCodeAt(1), v.charCodeAt(2), v.charCodeAt(3)]\n }\n\n /**\n * @constant\n * @type {number}\n */\n sizeOf.TAG = constant(4)\n\n // CFF data types ///////////////////////////////////////////////////////////\n\n encode.Card8 = encode.BYTE\n sizeOf.Card8 = sizeOf.BYTE\n\n encode.Card16 = encode.USHORT\n sizeOf.Card16 = sizeOf.USHORT\n\n encode.OffSize = encode.BYTE\n sizeOf.OffSize = sizeOf.BYTE\n\n encode.SID = encode.USHORT\n sizeOf.SID = sizeOf.USHORT\n\n // Convert a numeric operand or charstring number to a variable-size list of bytes.\n /**\n * Convert a numeric operand or charstring number to a variable-size list of bytes.\n * @param {number}\n * @returns {Array}\n */\n encode.NUMBER = function (v) {\n if (v >= -107 && v <= 107) {\n return [v + 139]\n } else if (v >= 108 && v <= 1131) {\n v = v - 108\n return [(v >> 8) + 247, v & 0xff]\n } else if (v >= -1131 && v <= -108) {\n v = -v - 108\n return [(v >> 8) + 251, v & 0xff]\n } else if (v >= -32768 && v <= 32767) {\n return encode.NUMBER16(v)\n } else {\n return encode.NUMBER32(v)\n }\n }\n\n /**\n * @param {number}\n * @returns {number}\n */\n sizeOf.NUMBER = function (v) {\n return encode.NUMBER(v).length\n }\n\n /**\n * Convert a signed number between -32768 and +32767 to a three-byte value.\n * This ensures we always use three bytes, but is not the most compact format.\n * @param {number}\n * @returns {Array}\n */\n encode.NUMBER16 = function (v) {\n return [28, (v >> 8) & 0xff, v & 0xff]\n }\n\n /**\n * @constant\n * @type {number}\n */\n sizeOf.NUMBER16 = constant(3)\n\n /**\n * Convert a signed number between -(2^31) and +(2^31-1) to a five-byte value.\n * This is useful if you want to be sure you always use four bytes,\n * at the expense of wasting a few bytes for smaller numbers.\n * @param {number}\n * @returns {Array}\n */\n encode.NUMBER32 = function (v) {\n return [29, (v >> 24) & 0xff, (v >> 16) & 0xff, (v >> 8) & 0xff, v & 0xff]\n }\n\n /**\n * @constant\n * @type {number}\n */\n sizeOf.NUMBER32 = constant(5)\n\n /**\n * @param {number}\n * @returns {Array}\n */\n encode.REAL = function (v) {\n var value = v.toString()\n\n // Some numbers use an epsilon to encode the value. (e.g. JavaScript will store 0.0000001 as 1e-7)\n // This code converts it back to a number without the epsilon.\n var m = /\\.(\\d*?)(?:9{5,20}|0{5,20})\\d{0,2}(?:e(.+)|$)/.exec(value)\n if (m) {\n var epsilon = parseFloat('1e' + ((m[2] ? +m[2] : 0) + m[1].length))\n value = (Math.round(v * epsilon) / epsilon).toString()\n }\n\n var nibbles = ''\n for (var i = 0, ii = value.length; i < ii; i += 1) {\n var c = value[i]\n if (c === 'e') {\n nibbles += value[++i] === '-' ? 'c' : 'b'\n } else if (c === '.') {\n nibbles += 'a'\n } else if (c === '-') {\n nibbles += 'e'\n } else {\n nibbles += c\n }\n }\n\n nibbles += nibbles.length & 1 ? 'f' : 'ff'\n var out = [30]\n for (var i$1 = 0, ii$1 = nibbles.length; i$1 < ii$1; i$1 += 2) {\n out.push(parseInt(nibbles.substr(i$1, 2), 16))\n }\n\n return out\n }\n\n /**\n * @param {number}\n * @returns {number}\n */\n sizeOf.REAL = function (v) {\n return encode.REAL(v).length\n }\n\n encode.NAME = encode.CHARARRAY\n sizeOf.NAME = sizeOf.CHARARRAY\n\n encode.STRING = encode.CHARARRAY\n sizeOf.STRING = sizeOf.CHARARRAY\n\n /**\n * @param {DataView} data\n * @param {number} offset\n * @param {number} numBytes\n * @returns {string}\n */\n decode.UTF8 = function (data, offset, numBytes) {\n var codePoints = []\n var numChars = numBytes\n for (var j = 0; j < numChars; j++, offset += 1) {\n codePoints[j] = data.getUint8(offset)\n }\n\n return String.fromCharCode.apply(null, codePoints)\n }\n\n /**\n * @param {DataView} data\n * @param {number} offset\n * @param {number} numBytes\n * @returns {string}\n */\n decode.UTF16 = function (data, offset, numBytes) {\n var codePoints = []\n var numChars = numBytes / 2\n for (var j = 0; j < numChars; j++, offset += 2) {\n codePoints[j] = data.getUint16(offset)\n }\n\n return String.fromCharCode.apply(null, codePoints)\n }\n\n /**\n * Convert a JavaScript string to UTF16-BE.\n * @param {string}\n * @returns {Array}\n */\n encode.UTF16 = function (v) {\n var b = []\n for (var i = 0; i < v.length; i += 1) {\n var codepoint = v.charCodeAt(i)\n b[b.length] = (codepoint >> 8) & 0xff\n b[b.length] = codepoint & 0xff\n }\n\n return b\n }\n\n /**\n * @param {string}\n * @returns {number}\n */\n sizeOf.UTF16 = function (v) {\n return v.length * 2\n }\n\n // Data for converting old eight-bit Macintosh encodings to Unicode.\n // This representation is optimized for decoding; encoding is slower\n // and needs more memory. The assumption is that all opentype.js users\n // want to open fonts, but saving a font will be comparatively rare\n // so it can be more expensive. Keyed by IANA character set name.\n //\n // Python script for generating these strings:\n //\n // s = u''.join([chr(c).decode('mac_greek') for c in range(128, 256)])\n // print(s.encode('utf-8'))\n /**\n * @private\n */\n var eightBitMacEncodings = {\n // Python: 'mac_croatian'\n 'x-mac-croatian':\n 'ÄÅÇÉÑÖÜáàâäãåçéèêëíìîïñóòôöõúùûü†°¢£§•¶ß®Š™´¨≠ŽØ∞±≤≥∆µ∂∑∏š∫ªºΩžø' +\n '¿¡¬√ƒ≈ƫȅ ÀÃÕŒœĐ—“”‘’÷◊©⁄€‹›Æ»–·‚„‰ÂćÁčÈÍÎÏÌÓÔđÒÚÛÙıˆ˜¯πË˚¸Êæˇ',\n // Python: 'mac_cyrillic'\n 'x-mac-cyrillic':\n 'АБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ†°Ґ£§•¶І®©™Ђђ≠Ѓѓ∞±≤≥іµґЈЄєЇїЉљЊњ' +\n 'јЅ¬√ƒ≈∆«»… ЋћЌќѕ–—“”‘’÷„ЎўЏџ№Ёёяабвгдежзийклмнопрстуфхцчшщъыьэю',\n // http://unicode.org/Public/MAPPINGS/VENDORS/APPLE/GAELIC.TXT\n 'x-mac-gaelic':\n 'ÄÅÇÉÑÖÜáàâäãåçéèêëíìîïñóòôöõúùûü†°¢£§•¶ß®©™´¨≠ÆØḂ±≤≥ḃĊċḊḋḞḟĠġṀæø' +\n 'ṁṖṗɼƒſṠ«»… ÀÃÕŒœ–—“”‘’ṡẛÿŸṪ€‹›Ŷŷṫ·Ỳỳ⁊ÂÊÁËÈÍÎÏÌÓÔ♣ÒÚÛÙıÝýŴŵẄẅẀẁẂẃ',\n // Python: 'mac_greek'\n 'x-mac-greek':\n 'Ĺ²É³ÖÜ΅àâä΄¨çéèê룙î‰ôö¦€ùûü†ΓΔΘΛΞΠß®©ΣΪ§≠°·Α±≤≥¥ΒΕΖΗΙΚΜΦΫΨΩ' +\n 'άΝ¬ΟΡ≈Τ«»… ΥΧΆΈœ–―“”‘’÷ΉΊΌΎέήίόΏύαβψδεφγηιξκλμνοπώρστθωςχυζϊϋΐΰ\\u00AD',\n // Python: 'mac_iceland'\n 'x-mac-icelandic':\n 'ÄÅÇÉÑÖÜáàâäãåçéèêëíìîïñóòôöõúùûüݰ¢£§•¶ß®©™´¨≠ÆØ∞±≤≥¥µ∂∑∏π∫ªºΩæø' +\n '¿¡¬√ƒ≈∆«»… ÀÃÕŒœ–—“”‘’÷◊ÿŸ⁄€ÐðÞþý·‚„‰ÂÊÁËÈÍÎÏÌÓÔÒÚÛÙıˆ˜¯˘˙˚¸˝˛ˇ',\n // http://unicode.org/Public/MAPPINGS/VENDORS/APPLE/INUIT.TXT\n 'x-mac-inuit':\n 'ᐃᐄᐅᐆᐊᐋᐱᐲᐳᐴᐸᐹᑉᑎᑏᑐᑑᑕᑖᑦᑭᑮᑯᑰᑲᑳᒃᒋᒌᒍᒎᒐᒑ°ᒡᒥᒦ•¶ᒧ®©™ᒨᒪᒫᒻᓂᓃᓄᓅᓇᓈᓐᓯᓰᓱᓲᓴᓵᔅᓕᓖᓗ' +\n 'ᓘᓚᓛᓪᔨᔩᔪᔫᔭ… ᔮᔾᕕᕖᕗ–—“”‘’ᕘᕙᕚᕝᕆᕇᕈᕉᕋᕌᕐᕿᖀᖁᖂᖃᖄᖅᖏᖐᖑᖒᖓᖔᖕᙱᙲᙳᙴᙵᙶᖖᖠᖡᖢᖣᖤᖥᖦᕼŁł',\n // Python: 'mac_latin2'\n 'x-mac-ce':\n 'ÄĀāÉĄÖÜáąČäčĆć鏟ĎíďĒēĖóėôöõúĚěü†°Ę£§•¶ß®©™ę¨≠ģĮįĪ≤≥īĶ∂∑łĻļĽľĹĺŅ' +\n 'ņѬ√ńŇ∆«»… ňŐÕőŌ–—“”‘’÷◊ōŔŕŘ‹›řŖŗŠ‚„šŚśÁŤťÍŽžŪÓÔūŮÚůŰűŲųÝýķŻŁżĢˇ',\n // Python: 'mac_roman'\n macintosh:\n 'ÄÅÇÉÑÖÜáàâäãåçéèêëíìîïñóòôöõúùûü†°¢£§•¶ß®©™´¨≠ÆØ∞±≤≥¥µ∂∑∏π∫ªºΩæø' +\n '¿¡¬√ƒ≈∆«»… ÀÃÕŒœ–—“”‘’÷◊ÿŸ⁄€‹›fifl‡·‚„‰ÂÊÁËÈÍÎÏÌÓÔÒÚÛÙıˆ˜¯˘˙˚¸˝˛ˇ',\n // Python: 'mac_romanian'\n 'x-mac-romanian':\n 'ÄÅÇÉÑÖÜáàâäãåçéèêëíìîïñóòôöõúùûü†°¢£§•¶ß®©™´¨≠ĂȘ∞±≤≥¥µ∂∑∏π∫ªºΩăș' +\n '¿¡¬√ƒ≈∆«»… ÀÃÕŒœ–—“”‘’÷◊ÿŸ⁄€‹›Țț‡·‚„‰ÂÊÁËÈÍÎÏÌÓÔÒÚÛÙıˆ˜¯˘˙˚¸˝˛ˇ',\n // Python: 'mac_turkish'\n 'x-mac-turkish':\n 'ÄÅÇÉÑÖÜáàâäãåçéèêëíìîïñóòôöõúùûü†°¢£§•¶ß®©™´¨≠ÆØ∞±≤≥¥µ∂∑∏π∫ªºΩæø' +\n '¿¡¬√ƒ≈∆«»… ÀÃÕŒœ–—“”‘’÷◊ÿŸĞğİıŞş‡·‚„‰ÂÊÁËÈÍÎÏÌÓÔÒÚÛÙˆ˜¯˘˙˚¸˝˛ˇ',\n }\n\n /**\n * Decodes an old-style Macintosh string. Returns either a Unicode JavaScript\n * string, or 'undefined' if the encoding is unsupported. For example, we do\n * not support Chinese, Japanese or Korean because these would need large\n * mapping tables.\n * @param {DataView} dataView\n * @param {number} offset\n * @param {number} dataLength\n * @param {string} encoding\n * @returns {string}\n */\n decode.MACSTRING = function (dataView, offset, dataLength, encoding) {\n var table = eightBitMacEncodings[encoding]\n if (table === undefined) {\n return undefined\n }\n\n var result = ''\n for (var i = 0; i < dataLength; i++) {\n var c = dataView.getUint8(offset + i)\n // In all eight-bit Mac encodings, the characters 0x00..0x7F are\n // mapped to U+0000..U+007F; we only need to look up the others.\n if (c <= 0x7f) {\n result += String.fromCharCode(c)\n } else {\n result += table[c & 0x7f]\n }\n }\n\n return result\n }\n\n // Helper function for encode.MACSTRING. Returns a dictionary for mapping\n // Unicode character codes to their 8-bit MacOS equivalent. This table\n // is not exactly a super cheap data structure, but we do not care because\n // encoding Macintosh strings is only rarely needed in typical applications.\n var macEncodingTableCache = typeof WeakMap === 'function' && new WeakMap()\n var macEncodingCacheKeys\n var getMacEncodingTable = function (encoding) {\n // Since we use encoding as a cache key for WeakMap, it has to be\n // a String object and not a literal. And at least on NodeJS 2.10.1,\n // WeakMap requires that the same String instance is passed for cache hits.\n if (!macEncodingCacheKeys) {\n macEncodingCacheKeys = {}\n for (var e in eightBitMacEncodings) {\n /*jshint -W053 */ // Suppress \"Do not use String as a constructor.\"\n macEncodingCacheKeys[e] = new String(e)\n }\n }\n\n var cacheKey = macEncodingCacheKeys[encoding]\n if (cacheKey === undefined) {\n return undefined\n }\n\n // We can't do \"if (cache.has(key)) {return cache.get(key)}\" here:\n // since garbage collection may run at any time, it could also kick in\n // between the calls to cache.has() and cache.get(). In that case,\n // we would return 'undefined' even though we do support the encoding.\n if (macEncodingTableCache) {\n var cachedTable = macEncodingTableCache.get(cacheKey)\n if (cachedTable !== undefined) {\n return cachedTable\n }\n }\n\n var decodingTable = eightBitMacEncodings[encoding]\n if (decodingTable === undefined) {\n return undefined\n }\n\n var encodingTable = {}\n for (var i = 0; i < decodingTable.length; i++) {\n encodingTable[decodingTable.charCodeAt(i)] = i + 0x80\n }\n\n if (macEncodingTableCache) {\n macEncodingTableCache.set(cacheKey, encodingTable)\n }\n\n return encodingTable\n }\n\n /**\n * Encodes an old-style Macintosh string. Returns a byte array upon success.\n * If the requested encoding is unsupported, or if the input string contains\n * a character that cannot be expressed in the encoding, the function returns\n * 'undefined'.\n * @param {string} str\n * @param {string} encoding\n * @returns {Array}\n */\n encode.MACSTRING = function (str, encoding) {\n var table = getMacEncodingTable(encoding)\n if (table === undefined) {\n return undefined\n }\n\n var result = []\n for (var i = 0; i < str.length; i++) {\n var c = str.charCodeAt(i)\n\n // In all eight-bit Mac encodings, the characters 0x00..0x7F are\n // mapped to U+0000..U+007F; we only need to look up the others.\n if (c >= 0x80) {\n c = table[c]\n if (c === undefined) {\n // str contains a Unicode character that cannot be encoded\n // in the requested encoding.\n return undefined\n }\n }\n result[i] = c\n // result.push(c);\n }\n\n return result\n }\n\n /**\n * @param {string} str\n * @param {string} encoding\n * @returns {number}\n */\n sizeOf.MACSTRING = function (str, encoding) {\n var b = encode.MACSTRING(str, encoding)\n if (b !== undefined) {\n return b.length\n } else {\n return 0\n }\n }\n\n // Helper for encode.VARDELTAS\n function isByteEncodable(value) {\n return value >= -128 && value <= 127\n }\n\n // Helper for encode.VARDELTAS\n function encodeVarDeltaRunAsZeroes(deltas, pos, result) {\n var runLength = 0\n var numDeltas = deltas.length\n while (pos < numDeltas && runLength < 64 && deltas[pos] === 0) {\n ++pos\n ++runLength\n }\n result.push(0x80 | (runLength - 1))\n return pos\n }\n\n // Helper for encode.VARDELTAS\n function encodeVarDeltaRunAsBytes(deltas, offset, result) {\n var runLength = 0\n var numDeltas = deltas.length\n var pos = offset\n while (pos < numDeltas && runLength < 64) {\n var value = deltas[pos]\n if (!isByteEncodable(value)) {\n break\n }\n\n // Within a byte-encoded run of deltas, a single zero is best\n // stored literally as 0x00 value. However, if we have two or\n // more zeroes in a sequence, it is better to start a new run.\n // Fore example, the sequence of deltas [15, 15, 0, 15, 15]\n // becomes 6 bytes (04 0F 0F 00 0F 0F) when storing the zero\n // within the current run, but 7 bytes (01 0F 0F 80 01 0F 0F)\n // when starting a new run.\n if (value === 0 && pos + 1 < numDeltas && deltas[pos + 1] === 0) {\n break\n }\n\n ++pos\n ++runLength\n }\n result.push(runLength - 1)\n for (var i = offset; i < pos; ++i) {\n result.push((deltas[i] + 256) & 0xff)\n }\n return pos\n }\n\n // Helper for encode.VARDELTAS\n function encodeVarDeltaRunAsWords(deltas, offset, result) {\n var runLength = 0\n var numDeltas = deltas.length\n var pos = offset\n while (pos < numDeltas && runLength < 64) {\n var value = deltas[pos]\n\n // Within a word-encoded run of deltas, it is easiest to start\n // a new run (with a different encoding) whenever we encounter\n // a zero value. For example, the sequence [0x6666, 0, 0x7777]\n // needs 7 bytes when storing the zero inside the current run\n // (42 66 66 00 00 77 77), and equally 7 bytes when starting a\n // new run (40 66 66 80 40 77 77).\n if (value === 0) {\n break\n }\n\n // Within a word-encoded run of deltas, a single value in the\n // range (-128..127) should be encoded within the current run\n // because it is more compact. For example, the sequence\n // [0x6666, 2, 0x7777] becomes 7 bytes when storing the value\n // literally (42 66 66 00 02 77 77), but 8 bytes when starting\n // a new run (40 66 66 00 02 40 77 77).\n if (isByteEncodable(value) && pos + 1 < numDeltas && isByteEncodable(deltas[pos + 1])) {\n break\n }\n\n ++pos\n ++runLength\n }\n result.push(0x40 | (runLength - 1))\n for (var i = offset; i < pos; ++i) {\n var val = deltas[i]\n result.push(((val + 0x10000) >> 8) & 0xff, (val + 0x100) & 0xff)\n }\n return pos\n }\n\n /**\n * Encode a list of variation adjustment deltas.\n *\n * Variation adjustment deltas are used in ‘gvar’ and ‘cvar’ tables.\n * They indicate how points (in ‘gvar’) or values (in ‘cvar’) get adjusted\n * when generating instances of variation fonts.\n *\n * @see https://www.microsoft.com/typography/otspec/gvar.htm\n * @see https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6gvar.html\n * @param {Array}\n * @return {Array}\n */\n encode.VARDELTAS = function (deltas) {\n var pos = 0\n var result = []\n while (pos < deltas.length) {\n var value = deltas[pos]\n if (value === 0) {\n pos = encodeVarDeltaRunAsZeroes(deltas, pos, result)\n } else if (value >= -128 && value <= 127) {\n pos = encodeVarDeltaRunAsBytes(deltas, pos, result)\n } else {\n pos = encodeVarDeltaRunAsWords(deltas, pos, result)\n }\n }\n return result\n }\n\n // Convert a list of values to a CFF INDEX structure.\n // The values should be objects containing name / type / value.\n /**\n * @param {Array} l\n * @returns {Array}\n */\n encode.INDEX = function (l) {\n //var offset, offsets, offsetEncoder, encodedOffsets, encodedOffset, data,\n // i, v;\n // Because we have to know which data type to use to encode the offsets,\n // we have to go through the values twice: once to encode the data and\n // calculate the offsets, then again to encode the offsets using the fitting data type.\n var offset = 1 // First offset is always 1.\n var offsets = [offset]\n var data = []\n for (var i = 0; i < l.length; i += 1) {\n var v = encode.OBJECT(l[i])\n Array.prototype.push.apply(data, v)\n offset += v.length\n offsets.push(offset)\n }\n\n if (data.length === 0) {\n return [0, 0]\n }\n\n var encodedOffsets = []\n var offSize = (1 + Math.floor(Math.log(offset) / Math.log(2)) / 8) | 0\n var offsetEncoder = [undefined, encode.BYTE, encode.USHORT, encode.UINT24, encode.ULONG][offSize]\n for (var i$1 = 0; i$1 < offsets.length; i$1 += 1) {\n var encodedOffset = offsetEncoder(offsets[i$1])\n Array.prototype.push.apply(encodedOffsets, encodedOffset)\n }\n\n return Array.prototype.concat(encode.Card16(l.length), encode.OffSize(offSize), encodedOffsets, data)\n }\n\n /**\n * @param {Array}\n * @returns {number}\n */\n sizeOf.INDEX = function (v) {\n return encode.INDEX(v).length\n }\n\n /**\n * Convert an object to a CFF DICT structure.\n * The keys should be numeric.\n * The values should be objects containing name / type / value.\n * @param {Object} m\n * @returns {Array}\n */\n encode.DICT = function (m) {\n var d = []\n var keys = Object.keys(m)\n var length = keys.length\n\n for (var i = 0; i < length; i += 1) {\n // Object.keys() return string keys, but our keys are always numeric.\n var k = parseInt(keys[i], 0)\n var v = m[k]\n // Value comes before the key.\n d = d.concat(encode.OPERAND(v.value, v.type))\n d = d.concat(encode.OPERATOR(k))\n }\n\n return d\n }\n\n /**\n * @param {Object}\n * @returns {number}\n */\n sizeOf.DICT = function (m) {\n return encode.DICT(m).length\n }\n\n /**\n * @param {number}\n * @returns {Array}\n */\n encode.OPERATOR = function (v) {\n if (v < 1200) {\n return [v]\n } else {\n return [12, v - 1200]\n }\n }\n\n /**\n * @param {Array} v\n * @param {string}\n * @returns {Array}\n */\n encode.OPERAND = function (v, type) {\n var d = []\n if (Array.isArray(type)) {\n for (var i = 0; i < type.length; i += 1) {\n check.argument(v.length === type.length, 'Not enough arguments given for type' + type)\n d = d.concat(encode.OPERAND(v[i], type[i]))\n }\n } else {\n if (type === 'SID') {\n d = d.concat(encode.NUMBER(v))\n } else if (type === 'offset') {\n // We make it easy for ourselves and always encode offsets as\n // 4 bytes. This makes offset calculation for the top dict easier.\n d = d.concat(encode.NUMBER32(v))\n } else if (type === 'number') {\n d = d.concat(encode.NUMBER(v))\n } else if (type === 'real') {\n d = d.concat(encode.REAL(v))\n } else {\n throw new Error('Unknown operand type ' + type)\n // FIXME Add support for booleans\n }\n }\n\n return d\n }\n\n encode.OP = encode.BYTE\n sizeOf.OP = sizeOf.BYTE\n\n // memoize charstring encoding using WeakMap if available\n var wmm = typeof WeakMap === 'function' && new WeakMap()\n\n /**\n * Convert a list of CharString operations to bytes.\n * @param {Array}\n * @returns {Array}\n */\n encode.CHARSTRING = function (ops) {\n // See encode.MACSTRING for why we don't do \"if (wmm && wmm.has(ops))\".\n if (wmm) {\n var cachedValue = wmm.get(ops)\n if (cachedValue !== undefined) {\n return cachedValue\n }\n }\n\n var d = []\n var length = ops.length\n\n for (var i = 0; i < length; i += 1) {\n var op = ops[i]\n d = d.concat(encode[op.type](op.value))\n }\n\n if (wmm) {\n wmm.set(ops, d)\n }\n\n return d\n }\n\n /**\n * @param {Array}\n * @returns {number}\n */\n sizeOf.CHARSTRING = function (ops) {\n return encode.CHARSTRING(ops).length\n }\n\n // Utility functions ////////////////////////////////////////////////////////\n\n /**\n * Convert an object containing name / type / value to bytes.\n * @param {Object}\n * @returns {Array}\n */\n encode.OBJECT = function (v) {\n var encodingFunction = encode[v.type]\n check.argument(encodingFunction !== undefined, 'No encoding function for type ' + v.type)\n return encodingFunction(v.value)\n }\n\n /**\n * @param {Object}\n * @returns {number}\n */\n sizeOf