text: import { __awaiter, __generator } from "tslib";
  import { createCmap } from "./CMap";
  import { deriveFontFlags } from "./FontFlags";
  import PDFHexString from "../objects/PDFHexString";
  import PDFString from "../objects/PDFString";
  import { byAscendingId, Cache, sortedUniq, toHexStringOfMinLength, } from "../../utils";
  /**
   * A note of thanks to the developers of https://github.com/foliojs/pdfkit, as
   * this class borrows from:
   *   https://github.com/devongovett/pdfkit/blob/e71edab0dd4657b5a767804ba86c94c58d01fbca/lib/image/jpeg.coffee
   */
  var CustomFontEmbedder = /** @class */ (function () {
      function CustomFontEmbedder(font, fontData, customName, fontFeatures) {
          var _this = this;
          this.allGlyphsInFontSortedById = function () {
              var glyphs = new Array(_this.font.characterSet.length);
              for (var idx = 0, len = glyphs.length; idx < len; idx++) {
                  var codePoint = _this.font.characterSet[idx];
                  glyphs[idx] = _this.font.glyphForCodePoint(codePoint);
              }
              return sortedUniq(glyphs.sort(byAscendingId), function (g) { return g.id; });
          };
          this.font = font;
          this.scale = 1000 / this.font.unitsPerEm;
          this.fontData = fontData;
          this.fontName = this.font.postscriptName || 'Font';
          this.customName = customName;
          this.fontFeatures = fontFeatures;
          this.baseFontName = '';
          this.glyphCache = Cache.populatedBy(this.allGlyphsInFontSortedById);
      }
      CustomFontEmbedder.for = function (fontkit, fontData, customName, fontFeatures) {
          return __awaiter(this, void 0, void 0, function () {
              var font;
              return __generator(this, function (_a) {
                  switch (_a.label) {
                      case 0: return [4 /*yield*/, fontkit.create(fontData)];
                      case 1:
                          font = _a.sent();
                          return [2 /*return*/, new CustomFontEmbedder(font, fontData, customName, fontFeatures)];
                  }
              });
          });
      };
      /**
       * Encode the JavaScript string into this font. (JavaScript encodes strings in
       * Unicode, but embedded fonts use their own custom encodings)
       */
      CustomFontEmbedder.prototype.encodeText = function (text) {
          var glyphs = this.font.layout(text, this.fontFeatures).glyphs;
          var hexCodes = new Array(glyphs.length);
          for (var idx = 0, len = glyphs.length; idx < len; idx++) {
              hexCodes[idx] = toHexStringOfMinLength(glyphs[idx].id, 4);
          }
          return PDFHexString.of(hexCodes.join(''));
      };
      // The advanceWidth takes into account kerning automatically, so we don't
      // have to do that manually like we do for the standard fonts.
      CustomFontEmbedder.prototype.widthOfTextAtSize = function (text, size) {
          var glyphs = this.font.layout(text, this.fontFeatures).glyphs;
          var totalWidth = 0;
          for (var idx = 0, len = glyphs.length; idx < len; idx++) {
              totalWidth += glyphs[idx].advanceWidth * this.scale;
          }
          var scale = size / 1000;
          return totalWidth * scale;
      };
      CustomFontEmbedder.prototype.heightOfFontAtSize = function (size, options) {
          if (options === void 0) { options = {}; }
          var _a = options.descender, descender = _a === void 0 ? true : _a;
          var _b = this.font, ascent = _b.ascent, descent = _b.descent, bbox = _b.bbox;
          var yTop = (ascent || bbox.maxY) * this.scale;
          var yBottom = (descent || bbox.minY) * this.scale;
          var height = yTop - yBottom;
          if (!descender)
              height -= Math.abs(descent) || 0;
          return (height / 1000) * size;
      };
      CustomFontEmbedder.prototype.sizeOfFontAtHeight = function (height) {
          var _a = this.font, ascent = _a.ascent, descent = _a.descent, bbox = _a.bbox;
          var yTop = (ascent || bbox.maxY) * this.scale;
          var yBottom = (descent || bbox.minY) * this.scale;
          return (1000 * height) / (yTop - yBottom);
      };
      CustomFontEmbedder.prototype.embedIntoContext = function (context, ref) {
          this.baseFontName =
              this.customName || context.addRandomSuffix(this.fontName);
          return this.embedFontDict(context, ref);
      };
      CustomFontEmbedder.prototype.embedFontDict = function (context, ref) {
          return __awaiter(this, void 0, void 0, function () {
              var cidFontDictRef, unicodeCMapRef, fontDict;
              return __generator(this, function (_a) {
                  switch (_a.label) {
                      case 0: return [4 /*yield*/, this.embedCIDFontDict(context)];
                      case 1:
                          cidFontDictRef = _a.sent();
                          unicodeCMapRef = this.embedUnicodeCmap(context);
                          fontDict = context.obj({
                              Type: 'Font',
                              Subtype: 'Type0',
                              BaseFont: this.baseFontName,
                              Encoding: 'Identity-H',
                              DescendantFonts: [cidFontDictRef],
                              ToUnicode: unicodeCMapRef,
                          });
                          if (ref) {
                              context.assign(ref, fontDict);
                              return [2 /*return*/, ref];
                          }
                          else {
                              return [2 /*return*/, context.register(fontDict)];
                          }
                          return [2 /*return*/];
                  }
              });
          });
      };
      CustomFontEmbedder.prototype.isCFF = function () {
          return this.font.cff;
      };
      CustomFontEmbedder.prototype.embedCIDFontDict = function (context) {
          return __awaiter(this, void 0, void 0, function () {
              var fontDescriptorRef, cidFontDict;
              return __generator(this, function (_a) {
                  switch (_a.label) {
                      case 0: return [4 /*yield*/, this.embedFontDescriptor(context)];
                      case 1:
                          fontDescriptorRef = _a.sent();
                          cidFontDict = context.obj({
                              Type: 'Font',
                              Subtype: this.isCFF() ? 'CIDFontType0' : 'CIDFontType2',
                              CIDToGIDMap: 'Identity',
                              BaseFont: this.baseFontName,
                              CIDSystemInfo: {
                                  Registry: PDFString.of('Adobe'),
                                  Ordering: PDFString.of('Identity'),
                                  Supplement: 0,
                              },
                              FontDescriptor: fontDescriptorRef,
                              W: this.computeWidths(),
                          });
                          return [2 /*return*/, context.register(cidFontDict)];
                  }
              });
          });
      };
      CustomFontEmbedder.prototype.embedFontDescriptor = function (context) {
          return __awaiter(this, void 0, void 0, function () {
              var fontStreamRef, scale, _a, italicAngle, ascent, descent, capHeight, xHeight, _b, minX, minY, maxX, maxY, fontDescriptor;
              var _c;
              return __generator(this, function (_d) {
                  switch (_d.label) {
                      case 0: return [4 /*yield*/, this.embedFontStream(context)];
                      case 1:
                          fontStreamRef = _d.sent();
                          scale = this.scale;
                          _a = this.font, italicAngle = _a.italicAngle, ascent = _a.ascent, descent = _a.descent, capHeight = _a.capHeight, xHeight = _a.xHeight;
                          _b = this.font.bbox, minX = _b.minX, minY = _b.minY, maxX = _b.maxX, maxY = _b.maxY;
                          fontDescriptor = context.obj((_c = {
                                  Type: 'FontDescriptor',
                                  FontName: this.baseFontName,
                                  Flags: deriveFontFlags(this.font),
                                  FontBBox: [minX * scale, minY * scale, maxX * scale, maxY * scale],
                                  ItalicAngle: italicAngle,
                                  Ascent: ascent * scale,
                                  Descent: descent * scale,
                                  CapHeight: (capHeight || ascent) * scale,
                                  XHeight: (xHeight || 0) * scale,
                                  // Not sure how to compute/find this, nor is anybody else really:
                                  // https://stackoverflow.com/questions/35485179/stemv-value-of-the-truetype-font
                                  StemV: 0
                              },
                              _c[this.isCFF() ? 'FontFile3' : 'FontFile2'] = fontStreamRef,
                              _c));
                          return [2 /*return*/, context.register(fontDescriptor)];
                  }
              });
          });
      };
      CustomFontEmbedder.prototype.serializeFont = function () {
          return __awaiter(this, void 0, void 0, function () {
              return __generator(this, function (_a) {
                  return [2 /*return*/, this.fontData];
              });
          });
      };
      CustomFontEmbedder.prototype.embedFontStream = function (context) {
          return __awaiter(this, void 0, void 0, function () {
              var fontStream, _a, _b;
              return __generator(this, function (_c) {
                  switch (_c.label) {
                      case 0:
                          _b = (_a = context).flateStream;
                          return [4 /*yield*/, this.serializeFont()];
                      case 1:
                          fontStream = _b.apply(_a, [_c.sent(), {
                                  Subtype: this.isCFF() ? 'CIDFontType0C' : undefined,
                              }]);
                          return [2 /*return*/, context.register(fontStream)];
                  }
              });
          });
      };
      CustomFontEmbedder.prototype.embedUnicodeCmap = function (context) {
          var cmap = createCmap(this.glyphCache.access(), this.glyphId.bind(this));
          var cmapStream = context.flateStream(cmap);
          return context.register(cmapStream);
      };
      CustomFontEmbedder.prototype.glyphId = function (glyph) {
          return glyph ? glyph.id : -1;
      };
      CustomFontEmbedder.prototype.computeWidths = function () {
          var glyphs = this.glyphCache.access();
          var widths = [];
          var currSection = [];
          for (var idx = 0, len = glyphs.length; idx < len; idx++) {
              var currGlyph = glyphs[idx];
              var prevGlyph = glyphs[idx - 1];
              var currGlyphId = this.glyphId(currGlyph);
              var prevGlyphId = this.glyphId(prevGlyph);
              if (idx === 0) {
                  widths.push(currGlyphId);
              }
              else if (currGlyphId - prevGlyphId !== 1) {
                  widths.push(currSection);
                  widths.push(currGlyphId);
                  currSection = [];
              }
              currSection.push(currGlyph.advanceWidth * this.scale);
          }
          widths.push(currSection);
          return widths;
      };
      return CustomFontEmbedder;
  }());
  export default CustomFontEmbedder;
  //# sourceMappingURL=CustomFontEmbedder.js.map