/**
 * @licstart The following is the entire license notice for the
 * Javascript code in this page
 *
 * Copyright 2019 Mozilla Foundation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * @licend The above is the entire license notice for the
 * Javascript code in this page
 */
"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.FontRendererFactory = void 0;

var _util = require("../shared/util");

var _cff_parser = require("./cff_parser");

var _glyphlist = require("./glyphlist");

var _encodings = require("./encodings");

var _stream = require("./stream");

function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }

function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); }

function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }

function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }

function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }

function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }

function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }

var FontRendererFactory = function FontRendererFactoryClosure() {
  function getLong(data, offset) {
    return data[offset] << 24 | data[offset + 1] << 16 | data[offset + 2] << 8 | data[offset + 3];
  }

  function getUshort(data, offset) {
    return data[offset] << 8 | data[offset + 1];
  }

  function parseCmap(data, start, end) {
    var offset = getUshort(data, start + 2) === 1 ? getLong(data, start + 8) : getLong(data, start + 16);
    var format = getUshort(data, start + offset);
    var ranges, p, i;

    if (format === 4) {
      getUshort(data, start + offset + 2);
      var segCount = getUshort(data, start + offset + 6) >> 1;
      p = start + offset + 14;
      ranges = [];

      for (i = 0; i < segCount; i++, p += 2) {
        ranges[i] = {
          end: getUshort(data, p)
        };
      }

      p += 2;

      for (i = 0; i < segCount; i++, p += 2) {
        ranges[i].start = getUshort(data, p);
      }

      for (i = 0; i < segCount; i++, p += 2) {
        ranges[i].idDelta = getUshort(data, p);
      }

      for (i = 0; i < segCount; i++, p += 2) {
        var idOffset = getUshort(data, p);

        if (idOffset === 0) {
          continue;
        }

        ranges[i].ids = [];

        for (var j = 0, jj = ranges[i].end - ranges[i].start + 1; j < jj; j++) {
          ranges[i].ids[j] = getUshort(data, p + idOffset);
          idOffset += 2;
        }
      }

      return ranges;
    } else if (format === 12) {
      getLong(data, start + offset + 4);
      var groups = getLong(data, start + offset + 12);
      p = start + offset + 16;
      ranges = [];

      for (i = 0; i < groups; i++) {
        ranges.push({
          start: getLong(data, p),
          end: getLong(data, p + 4),
          idDelta: getLong(data, p + 8) - getLong(data, p)
        });
        p += 12;
      }

      return ranges;
    }

    throw new _util.FormatError("unsupported cmap: ".concat(format));
  }

  function parseCff(data, start, end, seacAnalysisEnabled) {
    var properties = {};
    var parser = new _cff_parser.CFFParser(new _stream.Stream(data, start, end - start), properties, seacAnalysisEnabled);
    var cff = parser.parse();
    return {
      glyphs: cff.charStrings.objects,
      subrs: cff.topDict.privateDict && cff.topDict.privateDict.subrsIndex && cff.topDict.privateDict.subrsIndex.objects,
      gsubrs: cff.globalSubrIndex && cff.globalSubrIndex.objects,
      isCFFCIDFont: cff.isCIDFont,
      fdSelect: cff.fdSelect,
      fdArray: cff.fdArray
    };
  }

  function parseGlyfTable(glyf, loca, isGlyphLocationsLong) {
    var itemSize, itemDecode;

    if (isGlyphLocationsLong) {
      itemSize = 4;

      itemDecode = function fontItemDecodeLong(data, offset) {
        return data[offset] << 24 | data[offset + 1] << 16 | data[offset + 2] << 8 | data[offset + 3];
      };
    } else {
      itemSize = 2;

      itemDecode = function fontItemDecode(data, offset) {
        return data[offset] << 9 | data[offset + 1] << 1;
      };
    }

    var glyphs = [];
    var startOffset = itemDecode(loca, 0);

    for (var j = itemSize; j < loca.length; j += itemSize) {
      var endOffset = itemDecode(loca, j);
      glyphs.push(glyf.subarray(startOffset, endOffset));
      startOffset = endOffset;
    }

    return glyphs;
  }

  function lookupCmap(ranges, unicode) {
    var code = unicode.codePointAt(0),
        gid = 0;
    var l = 0,
        r = ranges.length - 1;

    while (l < r) {
      var c = l + r + 1 >> 1;

      if (code < ranges[c].start) {
        r = c - 1;
      } else {
        l = c;
      }
    }

    if (ranges[l].start <= code && code <= ranges[l].end) {
      gid = ranges[l].idDelta + (ranges[l].ids ? ranges[l].ids[code - ranges[l].start] : code) & 0xFFFF;
    }

    return {
      charCode: code,
      glyphId: gid
    };
  }

  function compileGlyf(code, cmds, font) {
    function moveTo(x, y) {
      cmds.push({
        cmd: 'moveTo',
        args: [x, y]
      });
    }

    function lineTo(x, y) {
      cmds.push({
        cmd: 'lineTo',
        args: [x, y]
      });
    }

    function quadraticCurveTo(xa, ya, x, y) {
      cmds.push({
        cmd: 'quadraticCurveTo',
        args: [xa, ya, x, y]
      });
    }

    var i = 0;
    var numberOfContours = (code[i] << 24 | code[i + 1] << 16) >> 16;
    var flags;
    var x = 0,
        y = 0;
    i += 10;

    if (numberOfContours < 0) {
      do {
        flags = code[i] << 8 | code[i + 1];
        var glyphIndex = code[i + 2] << 8 | code[i + 3];
        i += 4;
        var arg1, arg2;

        if (flags & 0x01) {
          arg1 = (code[i] << 24 | code[i + 1] << 16) >> 16;
          arg2 = (code[i + 2] << 24 | code[i + 3] << 16) >> 16;
          i += 4;
        } else {
          arg1 = code[i++];
          arg2 = code[i++];
        }

        if (flags & 0x02) {
          x = arg1;
          y = arg2;
        } else {
          x = 0;
          y = 0;
        }

        var scaleX = 1,
            scaleY = 1,
            scale01 = 0,
            scale10 = 0;

        if (flags & 0x08) {
          scaleX = scaleY = (code[i] << 24 | code[i + 1] << 16) / 1073741824;
          i += 2;
        } else if (flags & 0x40) {
          scaleX = (code[i] << 24 | code[i + 1] << 16) / 1073741824;
          scaleY = (code[i + 2] << 24 | code[i + 3] << 16) / 1073741824;
          i += 4;
        } else if (flags & 0x80) {
          scaleX = (code[i] << 24 | code[i + 1] << 16) / 1073741824;
          scale01 = (code[i + 2] << 24 | code[i + 3] << 16) / 1073741824;
          scale10 = (code[i + 4] << 24 | code[i + 5] << 16) / 1073741824;
          scaleY = (code[i + 6] << 24 | code[i + 7] << 16) / 1073741824;
          i += 8;
        }

        var subglyph = font.glyphs[glyphIndex];

        if (subglyph) {
          cmds.push({
            cmd: 'save'
          });
          cmds.push({
            cmd: 'transform',
            args: [scaleX, scale01, scale10, scaleY, x, y]
          });
          compileGlyf(subglyph, cmds, font);
          cmds.push({
            cmd: 'restore'
          });
        }
      } while (flags & 0x20);
    } else {
      var endPtsOfContours = [];
      var j, jj;

      for (j = 0; j < numberOfContours; j++) {
        endPtsOfContours.push(code[i] << 8 | code[i + 1]);
        i += 2;
      }

      var instructionLength = code[i] << 8 | code[i + 1];
      i += 2 + instructionLength;
      var numberOfPoints = endPtsOfContours[endPtsOfContours.length - 1] + 1;
      var points = [];

      while (points.length < numberOfPoints) {
        flags = code[i++];
        var repeat = 1;

        if (flags & 0x08) {
          repeat += code[i++];
        }

        while (repeat-- > 0) {
          points.push({
            flags: flags
          });
        }
      }

      for (j = 0; j < numberOfPoints; j++) {
        switch (points[j].flags & 0x12) {
          case 0x00:
            x += (code[i] << 24 | code[i + 1] << 16) >> 16;
            i += 2;
            break;

          case 0x02:
            x -= code[i++];
            break;

          case 0x12:
            x += code[i++];
            break;
        }

        points[j].x = x;
      }

      for (j = 0; j < numberOfPoints; j++) {
        switch (points[j].flags & 0x24) {
          case 0x00:
            y += (code[i] << 24 | code[i + 1] << 16) >> 16;
            i += 2;
            break;

          case 0x04:
            y -= code[i++];
            break;

          case 0x24:
            y += code[i++];
            break;
        }

        points[j].y = y;
      }

      var startPoint = 0;

      for (i = 0; i < numberOfContours; i++) {
        var endPoint = endPtsOfContours[i];
        var contour = points.slice(startPoint, endPoint + 1);

        if (contour[0].flags & 1) {
          contour.push(contour[0]);
        } else if (contour[contour.length - 1].flags & 1) {
          contour.unshift(contour[contour.length - 1]);
        } else {
          var p = {
            flags: 1,
            x: (contour[0].x + contour[contour.length - 1].x) / 2,
            y: (contour[0].y + contour[contour.length - 1].y) / 2
          };
          contour.unshift(p);
          contour.push(p);
        }

        moveTo(contour[0].x, contour[0].y);

        for (j = 1, jj = contour.length; j < jj; j++) {
          if (contour[j].flags & 1) {
            lineTo(contour[j].x, contour[j].y);
          } else if (contour[j + 1].flags & 1) {
            quadraticCurveTo(contour[j].x, contour[j].y, contour[j + 1].x, contour[j + 1].y);
            j++;
          } else {
            quadraticCurveTo(contour[j].x, contour[j].y, (contour[j].x + contour[j + 1].x) / 2, (contour[j].y + contour[j + 1].y) / 2);
          }
        }

        startPoint = endPoint + 1;
      }
    }
  }

  function compileCharString(code, cmds, font, glyphId) {
    var stack = [];
    var x = 0,
        y = 0;
    var stems = 0;

    function moveTo(x, y) {
      cmds.push({
        cmd: 'moveTo',
        args: [x, y]
      });
    }

    function lineTo(x, y) {
      cmds.push({
        cmd: 'lineTo',
        args: [x, y]
      });
    }

    function bezierCurveTo(x1, y1, x2, y2, x, y) {
      cmds.push({
        cmd: 'bezierCurveTo',
        args: [x1, y1, x2, y2, x, y]
      });
    }

    function parse(code) {
      var i = 0;

      while (i < code.length) {
        var stackClean = false;
        var v = code[i++];
        var xa, xb, ya, yb, y1, y2, y3, n, subrCode;

        switch (v) {
          case 1:
            stems += stack.length >> 1;
            stackClean = true;
            break;

          case 3:
            stems += stack.length >> 1;
            stackClean = true;
            break;

          case 4:
            y += stack.pop();
            moveTo(x, y);
            stackClean = true;
            break;

          case 5:
            while (stack.length > 0) {
              x += stack.shift();
              y += stack.shift();
              lineTo(x, y);
            }

            break;

          case 6:
            while (stack.length > 0) {
              x += stack.shift();
              lineTo(x, y);

              if (stack.length === 0) {
                break;
              }

              y += stack.shift();
              lineTo(x, y);
            }

            break;

          case 7:
            while (stack.length > 0) {
              y += stack.shift();
              lineTo(x, y);

              if (stack.length === 0) {
                break;
              }

              x += stack.shift();
              lineTo(x, y);
            }

            break;

          case 8:
            while (stack.length > 0) {
              xa = x + stack.shift();
              ya = y + stack.shift();
              xb = xa + stack.shift();
              yb = ya + stack.shift();
              x = xb + stack.shift();
              y = yb + stack.shift();
              bezierCurveTo(xa, ya, xb, yb, x, y);
            }

            break;

          case 10:
            n = stack.pop();
            subrCode = null;

            if (font.isCFFCIDFont) {
              var fdIndex = font.fdSelect.getFDIndex(glyphId);

              if (fdIndex >= 0 && fdIndex < font.fdArray.length) {
                var fontDict = font.fdArray[fdIndex],
                    subrs = void 0;

                if (fontDict.privateDict && fontDict.privateDict.subrsIndex) {
                  subrs = fontDict.privateDict.subrsIndex.objects;
                }

                if (subrs) {
                  var numSubrs = subrs.length;
                  n += numSubrs < 1240 ? 107 : numSubrs < 33900 ? 1131 : 32768;
                  subrCode = subrs[n];
                }
              } else {
                (0, _util.warn)('Invalid fd index for glyph index.');
              }
            } else {
              subrCode = font.subrs[n + font.subrsBias];
            }

            if (subrCode) {
              parse(subrCode);
            }

            break;

          case 11:
            return;

          case 12:
            v = code[i++];

            switch (v) {
              case 34:
                xa = x + stack.shift();
                xb = xa + stack.shift();
                y1 = y + stack.shift();
                x = xb + stack.shift();
                bezierCurveTo(xa, y, xb, y1, x, y1);
                xa = x + stack.shift();
                xb = xa + stack.shift();
                x = xb + stack.shift();
                bezierCurveTo(xa, y1, xb, y, x, y);
                break;

              case 35:
                xa = x + stack.shift();
                ya = y + stack.shift();
                xb = xa + stack.shift();
                yb = ya + stack.shift();
                x = xb + stack.shift();
                y = yb + stack.shift();
                bezierCurveTo(xa, ya, xb, yb, x, y);
                xa = x + stack.shift();
                ya = y + stack.shift();
                xb = xa + stack.shift();
                yb = ya + stack.shift();
                x = xb + stack.shift();
                y = yb + stack.shift();
                bezierCurveTo(xa, ya, xb, yb, x, y);
                stack.pop();
                break;

              case 36:
                xa = x + stack.shift();
                y1 = y + stack.shift();
                xb = xa + stack.shift();
                y2 = y1 + stack.shift();
                x = xb + stack.shift();
                bezierCurveTo(xa, y1, xb, y2, x, y2);
                xa = x + stack.shift();
                xb = xa + stack.shift();
                y3 = y2 + stack.shift();
                x = xb + stack.shift();
                bezierCurveTo(xa, y2, xb, y3, x, y);
                break;

              case 37:
                var x0 = x,
                    y0 = y;
                xa = x + stack.shift();
                ya = y + stack.shift();
                xb = xa + stack.shift();
                yb = ya + stack.shift();
                x = xb + stack.shift();
                y = yb + stack.shift();
                bezierCurveTo(xa, ya, xb, yb, x, y);
                xa = x + stack.shift();
                ya = y + stack.shift();
                xb = xa + stack.shift();
                yb = ya + stack.shift();
                x = xb;
                y = yb;

                if (Math.abs(x - x0) > Math.abs(y - y0)) {
                  x += stack.shift();
                } else {
                  y += stack.shift();
                }

                bezierCurveTo(xa, ya, xb, yb, x, y);
                break;

              default:
                throw new _util.FormatError("unknown operator: 12 ".concat(v));
            }

            break;

          case 14:
            if (stack.length >= 4) {
              var achar = stack.pop();
              var bchar = stack.pop();
              y = stack.pop();
              x = stack.pop();
              cmds.push({
                cmd: 'save'
              });
              cmds.push({
                cmd: 'translate',
                args: [x, y]
              });
              var cmap = lookupCmap(font.cmap, String.fromCharCode(font.glyphNameMap[_encodings.StandardEncoding[achar]]));
              compileCharString(font.glyphs[cmap.glyphId], cmds, font, cmap.glyphId);
              cmds.push({
                cmd: 'restore'
              });
              cmap = lookupCmap(font.cmap, String.fromCharCode(font.glyphNameMap[_encodings.StandardEncoding[bchar]]));
              compileCharString(font.glyphs[cmap.glyphId], cmds, font, cmap.glyphId);
            }

            return;

          case 18:
            stems += stack.length >> 1;
            stackClean = true;
            break;

          case 19:
            stems += stack.length >> 1;
            i += stems + 7 >> 3;
            stackClean = true;
            break;

          case 20:
            stems += stack.length >> 1;
            i += stems + 7 >> 3;
            stackClean = true;
            break;

          case 21:
            y += stack.pop();
            x += stack.pop();
            moveTo(x, y);
            stackClean = true;
            break;

          case 22:
            x += stack.pop();
            moveTo(x, y);
            stackClean = true;
            break;

          case 23:
            stems += stack.length >> 1;
            stackClean = true;
            break;

          case 24:
            while (stack.length > 2) {
              xa = x + stack.shift();
              ya = y + stack.shift();
              xb = xa + stack.shift();
              yb = ya + stack.shift();
              x = xb + stack.shift();
              y = yb + stack.shift();
              bezierCurveTo(xa, ya, xb, yb, x, y);
            }

            x += stack.shift();
            y += stack.shift();
            lineTo(x, y);
            break;

          case 25:
            while (stack.length > 6) {
              x += stack.shift();
              y += stack.shift();
              lineTo(x, y);
            }

            xa = x + stack.shift();
            ya = y + stack.shift();
            xb = xa + stack.shift();
            yb = ya + stack.shift();
            x = xb + stack.shift();
            y = yb + stack.shift();
            bezierCurveTo(xa, ya, xb, yb, x, y);
            break;

          case 26:
            if (stack.length % 2) {
              x += stack.shift();
            }

            while (stack.length > 0) {
              xa = x;
              ya = y + stack.shift();
              xb = xa + stack.shift();
              yb = ya + stack.shift();
              x = xb;
              y = yb + stack.shift();
              bezierCurveTo(xa, ya, xb, yb, x, y);
            }

            break;

          case 27:
            if (stack.length % 2) {
              y += stack.shift();
            }

            while (stack.length > 0) {
              xa = x + stack.shift();
              ya = y;
              xb = xa + stack.shift();
              yb = ya + stack.shift();
              x = xb + stack.shift();
              y = yb;
              bezierCurveTo(xa, ya, xb, yb, x, y);
            }

            break;

          case 28:
            stack.push((code[i] << 24 | code[i + 1] << 16) >> 16);
            i += 2;
            break;

          case 29:
            n = stack.pop() + font.gsubrsBias;
            subrCode = font.gsubrs[n];

            if (subrCode) {
              parse(subrCode);
            }

            break;

          case 30:
            while (stack.length > 0) {
              xa = x;
              ya = y + stack.shift();
              xb = xa + stack.shift();
              yb = ya + stack.shift();
              x = xb + stack.shift();
              y = yb + (stack.length === 1 ? stack.shift() : 0);
              bezierCurveTo(xa, ya, xb, yb, x, y);

              if (stack.length === 0) {
                break;
              }

              xa = x + stack.shift();
              ya = y;
              xb = xa + stack.shift();
              yb = ya + stack.shift();
              y = yb + stack.shift();
              x = xb + (stack.length === 1 ? stack.shift() : 0);
              bezierCurveTo(xa, ya, xb, yb, x, y);
            }

            break;

          case 31:
            while (stack.length > 0) {
              xa = x + stack.shift();
              ya = y;
              xb = xa + stack.shift();
              yb = ya + stack.shift();
              y = yb + stack.shift();
              x = xb + (stack.length === 1 ? stack.shift() : 0);
              bezierCurveTo(xa, ya, xb, yb, x, y);

              if (stack.length === 0) {
                break;
              }

              xa = x;
              ya = y + stack.shift();
              xb = xa + stack.shift();
              yb = ya + stack.shift();
              x = xb + stack.shift();
              y = yb + (stack.length === 1 ? stack.shift() : 0);
              bezierCurveTo(xa, ya, xb, yb, x, y);
            }

            break;

          default:
            if (v < 32) {
              throw new _util.FormatError("unknown operator: ".concat(v));
            }

            if (v < 247) {
              stack.push(v - 139);
            } else if (v < 251) {
              stack.push((v - 247) * 256 + code[i++] + 108);
            } else if (v < 255) {
              stack.push(-(v - 251) * 256 - code[i++] - 108);
            } else {
              stack.push((code[i] << 24 | code[i + 1] << 16 | code[i + 2] << 8 | code[i + 3]) / 65536);
              i += 4;
            }

            break;
        }

        if (stackClean) {
          stack.length = 0;
        }
      }
    }

    parse(code);
  }

  var NOOP = [];

  var CompiledFont =
  /*#__PURE__*/
  function () {
    function CompiledFont(fontMatrix) {
      _classCallCheck(this, CompiledFont);

      if (this.constructor === CompiledFont) {
        (0, _util.unreachable)('Cannot initialize CompiledFont.');
      }

      this.fontMatrix = fontMatrix;
      this.compiledGlyphs = Object.create(null);
      this.compiledCharCodeToGlyphId = Object.create(null);
    }

    _createClass(CompiledFont, [{
      key: "getPathJs",
      value: function getPathJs(unicode) {
        var cmap = lookupCmap(this.cmap, unicode);
        var fn = this.compiledGlyphs[cmap.glyphId];

        if (!fn) {
          fn = this.compileGlyph(this.glyphs[cmap.glyphId], cmap.glyphId);
          this.compiledGlyphs[cmap.glyphId] = fn;
        }

        if (this.compiledCharCodeToGlyphId[cmap.charCode] === undefined) {
          this.compiledCharCodeToGlyphId[cmap.charCode] = cmap.glyphId;
        }

        return fn;
      }
    }, {
      key: "compileGlyph",
      value: function compileGlyph(code, glyphId) {
        if (!code || code.length === 0 || code[0] === 14) {
          return NOOP;
        }

        var fontMatrix = this.fontMatrix;

        if (this.isCFFCIDFont) {
          var fdIndex = this.fdSelect.getFDIndex(glyphId);

          if (fdIndex >= 0 && fdIndex < this.fdArray.length) {
            var fontDict = this.fdArray[fdIndex];
            fontMatrix = fontDict.getByName('FontMatrix') || _util.FONT_IDENTITY_MATRIX;
          } else {
            (0, _util.warn)('Invalid fd index for glyph index.');
          }
        }

        var cmds = [];
        cmds.push({
          cmd: 'save'
        });
        cmds.push({
          cmd: 'transform',
          args: fontMatrix.slice()
        });
        cmds.push({
          cmd: 'scale',
          args: ['size', '-size']
        });
        this.compileGlyphImpl(code, cmds, glyphId);
        cmds.push({
          cmd: 'restore'
        });
        return cmds;
      }
    }, {
      key: "compileGlyphImpl",
      value: function compileGlyphImpl() {
        (0, _util.unreachable)('Children classes should implement this.');
      }
    }, {
      key: "hasBuiltPath",
      value: function hasBuiltPath(unicode) {
        var cmap = lookupCmap(this.cmap, unicode);
        return this.compiledGlyphs[cmap.glyphId] !== undefined && this.compiledCharCodeToGlyphId[cmap.charCode] !== undefined;
      }
    }]);

    return CompiledFont;
  }();

  var TrueTypeCompiled =
  /*#__PURE__*/
  function (_CompiledFont) {
    _inherits(TrueTypeCompiled, _CompiledFont);

    function TrueTypeCompiled(glyphs, cmap, fontMatrix) {
      var _this;

      _classCallCheck(this, TrueTypeCompiled);

      _this = _possibleConstructorReturn(this, _getPrototypeOf(TrueTypeCompiled).call(this, fontMatrix || [0.000488, 0, 0, 0.000488, 0, 0]));
      _this.glyphs = glyphs;
      _this.cmap = cmap;
      return _this;
    }

    _createClass(TrueTypeCompiled, [{
      key: "compileGlyphImpl",
      value: function compileGlyphImpl(code, cmds) {
        compileGlyf(code, cmds, this);
      }
    }]);

    return TrueTypeCompiled;
  }(CompiledFont);

  var Type2Compiled =
  /*#__PURE__*/
  function (_CompiledFont2) {
    _inherits(Type2Compiled, _CompiledFont2);

    function Type2Compiled(cffInfo, cmap, fontMatrix, glyphNameMap) {
      var _this2;

      _classCallCheck(this, Type2Compiled);

      _this2 = _possibleConstructorReturn(this, _getPrototypeOf(Type2Compiled).call(this, fontMatrix || [0.001, 0, 0, 0.001, 0, 0]));
      _this2.glyphs = cffInfo.glyphs;
      _this2.gsubrs = cffInfo.gsubrs || [];
      _this2.subrs = cffInfo.subrs || [];
      _this2.cmap = cmap;
      _this2.glyphNameMap = glyphNameMap || (0, _glyphlist.getGlyphsUnicode)();
      _this2.gsubrsBias = _this2.gsubrs.length < 1240 ? 107 : _this2.gsubrs.length < 33900 ? 1131 : 32768;
      _this2.subrsBias = _this2.subrs.length < 1240 ? 107 : _this2.subrs.length < 33900 ? 1131 : 32768;
      _this2.isCFFCIDFont = cffInfo.isCFFCIDFont;
      _this2.fdSelect = cffInfo.fdSelect;
      _this2.fdArray = cffInfo.fdArray;
      return _this2;
    }

    _createClass(Type2Compiled, [{
      key: "compileGlyphImpl",
      value: function compileGlyphImpl(code, cmds, glyphId) {
        compileCharString(code, cmds, this, glyphId);
      }
    }]);

    return Type2Compiled;
  }(CompiledFont);

  return {
    create: function FontRendererFactory_create(font, seacAnalysisEnabled) {
      var data = new Uint8Array(font.data);
      var cmap, glyf, loca, cff, indexToLocFormat, unitsPerEm;
      var numTables = getUshort(data, 4);

      for (var i = 0, p = 12; i < numTables; i++, p += 16) {
        var tag = (0, _util.bytesToString)(data.subarray(p, p + 4));
        var offset = getLong(data, p + 8);
        var length = getLong(data, p + 12);

        switch (tag) {
          case 'cmap':
            cmap = parseCmap(data, offset, offset + length);
            break;

          case 'glyf':
            glyf = data.subarray(offset, offset + length);
            break;

          case 'loca':
            loca = data.subarray(offset, offset + length);
            break;

          case 'head':
            unitsPerEm = getUshort(data, offset + 18);
            indexToLocFormat = getUshort(data, offset + 50);
            break;

          case 'CFF ':
            cff = parseCff(data, offset, offset + length, seacAnalysisEnabled);
            break;
        }
      }

      if (glyf) {
        var fontMatrix = !unitsPerEm ? font.fontMatrix : [1 / unitsPerEm, 0, 0, 1 / unitsPerEm, 0, 0];
        return new TrueTypeCompiled(parseGlyfTable(glyf, loca, indexToLocFormat), cmap, fontMatrix);
      }

      return new Type2Compiled(cff, cmap, font.fontMatrix, font.glyphNameMap);
    }
  };
}();

exports.FontRendererFactory = FontRendererFactory;