function createOS2Table()

in src/core/fonts.js [763:881]


function createOS2Table(properties, charstrings, override) {
  override ||= {
    unitsPerEm: 0,
    yMax: 0,
    yMin: 0,
    ascent: 0,
    descent: 0,
  };

  let ulUnicodeRange1 = 0;
  let ulUnicodeRange2 = 0;
  let ulUnicodeRange3 = 0;
  let ulUnicodeRange4 = 0;

  let firstCharIndex = null;
  let lastCharIndex = 0;
  let position = -1;

  if (charstrings) {
    for (let code in charstrings) {
      code |= 0;
      if (firstCharIndex > code || !firstCharIndex) {
        firstCharIndex = code;
      }
      if (lastCharIndex < code) {
        lastCharIndex = code;
      }

      position = getUnicodeRangeFor(code, position);
      if (position < 32) {
        ulUnicodeRange1 |= 1 << position;
      } else if (position < 64) {
        ulUnicodeRange2 |= 1 << (position - 32);
      } else if (position < 96) {
        ulUnicodeRange3 |= 1 << (position - 64);
      } else if (position < 123) {
        ulUnicodeRange4 |= 1 << (position - 96);
      } else {
        throw new FormatError(
          "Unicode ranges Bits > 123 are reserved for internal usage"
        );
      }
    }
    if (lastCharIndex > 0xffff) {
      // OS2 only supports a 16 bit int. The spec says if supplementary
      // characters are used the field should just be set to 0xFFFF.
      lastCharIndex = 0xffff;
    }
  } else {
    // TODO
    firstCharIndex = 0;
    lastCharIndex = 255;
  }

  const bbox = properties.bbox || [0, 0, 0, 0];
  const unitsPerEm =
    override.unitsPerEm ||
    (properties.fontMatrix
      ? 1 / Math.max(...properties.fontMatrix.slice(0, 4).map(Math.abs))
      : 1000);

  // if the font units differ to the PDF glyph space units
  // then scale up the values
  const scale = properties.ascentScaled
    ? 1.0
    : unitsPerEm / PDF_GLYPH_SPACE_UNITS;

  const typoAscent =
    override.ascent || Math.round(scale * (properties.ascent || bbox[3]));
  let typoDescent =
    override.descent || Math.round(scale * (properties.descent || bbox[1]));
  if (typoDescent > 0 && properties.descent > 0 && bbox[1] < 0) {
    typoDescent = -typoDescent; // fixing incorrect descent
  }
  const winAscent = override.yMax || typoAscent;
  const winDescent = -override.yMin || -typoDescent;

  return (
    "\x00\x03" + // version
    "\x02\x24" + // xAvgCharWidth
    "\x01\xF4" + // usWeightClass
    "\x00\x05" + // usWidthClass
    "\x00\x00" + // fstype (0 to let the font loads via font-face on IE)
    "\x02\x8A" + // ySubscriptXSize
    "\x02\xBB" + // ySubscriptYSize
    "\x00\x00" + // ySubscriptXOffset
    "\x00\x8C" + // ySubscriptYOffset
    "\x02\x8A" + // ySuperScriptXSize
    "\x02\xBB" + // ySuperScriptYSize
    "\x00\x00" + // ySuperScriptXOffset
    "\x01\xDF" + // ySuperScriptYOffset
    "\x00\x31" + // yStrikeOutSize
    "\x01\x02" + // yStrikeOutPosition
    "\x00\x00" + // sFamilyClass
    "\x00\x00\x06" +
    String.fromCharCode(properties.fixedPitch ? 0x09 : 0x00) +
    "\x00\x00\x00\x00\x00\x00" + // Panose
    string32(ulUnicodeRange1) + // ulUnicodeRange1 (Bits 0-31)
    string32(ulUnicodeRange2) + // ulUnicodeRange2 (Bits 32-63)
    string32(ulUnicodeRange3) + // ulUnicodeRange3 (Bits 64-95)
    string32(ulUnicodeRange4) + // ulUnicodeRange4 (Bits 96-127)
    "\x2A\x32\x31\x2A" + // achVendID
    string16(properties.italicAngle ? 1 : 0) + // fsSelection
    string16(firstCharIndex || properties.firstChar) + // usFirstCharIndex
    string16(lastCharIndex || properties.lastChar) + // usLastCharIndex
    string16(typoAscent) + // sTypoAscender
    string16(typoDescent) + // sTypoDescender
    "\x00\x64" + // sTypoLineGap (7%-10% of the unitsPerEM value)
    string16(winAscent) + // usWinAscent
    string16(winDescent) + // usWinDescent
    "\x00\x00\x00\x00" + // ulCodePageRange1 (Bits 0-31)
    "\x00\x00\x00\x00" + // ulCodePageRange2 (Bits 32-63)
    string16(properties.xHeight) + // sxHeight
    string16(properties.capHeight) + // sCapHeight
    string16(0) + // usDefaultChar
    string16(firstCharIndex || properties.firstChar) + // usBreakChar
    "\x00\x03"
  ); // usMaxContext
}