(data, start, font)
| 3667 | |
| 3668 | // Parse the `CFF` table, which contains the glyph outlines in PostScript format. |
| 3669 | function parseCFFTable(data, start, font) { |
| 3670 | font.tables.cff = {}; |
| 3671 | var header = parseCFFHeader(data, start); |
| 3672 | var nameIndex = parseCFFIndex(data, header.endOffset, parse.bytesToString); |
| 3673 | var topDictIndex = parseCFFIndex(data, nameIndex.endOffset); |
| 3674 | var stringIndex = parseCFFIndex(data, topDictIndex.endOffset, parse.bytesToString); |
| 3675 | var globalSubrIndex = parseCFFIndex(data, stringIndex.endOffset); |
| 3676 | font.gsubrs = globalSubrIndex.objects; |
| 3677 | font.gsubrsBias = calcCFFSubroutineBias(font.gsubrs); |
| 3678 | |
| 3679 | var topDictData = new DataView(new Uint8Array(topDictIndex.objects[0]).buffer); |
| 3680 | var topDict = parseCFFTopDict(topDictData, stringIndex.objects); |
| 3681 | font.tables.cff.topDict = topDict; |
| 3682 | |
| 3683 | var privateDictOffset = start + topDict['private'][1]; |
| 3684 | var privateDict = parseCFFPrivateDict(data, privateDictOffset, topDict['private'][0], stringIndex.objects); |
| 3685 | font.defaultWidthX = privateDict.defaultWidthX; |
| 3686 | font.nominalWidthX = privateDict.nominalWidthX; |
| 3687 | |
| 3688 | if (privateDict.subrs !== 0) { |
| 3689 | var subrOffset = privateDictOffset + privateDict.subrs; |
| 3690 | var subrIndex = parseCFFIndex(data, subrOffset); |
| 3691 | font.subrs = subrIndex.objects; |
| 3692 | font.subrsBias = calcCFFSubroutineBias(font.subrs); |
| 3693 | } else { |
| 3694 | font.subrs = []; |
| 3695 | font.subrsBias = 0; |
| 3696 | } |
| 3697 | |
| 3698 | // Offsets in the top dict are relative to the beginning of the CFF data, so add the CFF start offset. |
| 3699 | var charStringsIndex = parseCFFIndex(data, start + topDict.charStrings); |
| 3700 | font.nGlyphs = charStringsIndex.objects.length; |
| 3701 | |
| 3702 | var charset = parseCFFCharset(data, start + topDict.charset, font.nGlyphs, stringIndex.objects); |
| 3703 | if (topDict.encoding === 0) { // Standard encoding |
| 3704 | font.cffEncoding = new encoding.CffEncoding(encoding.cffStandardEncoding, charset); |
| 3705 | } else if (topDict.encoding === 1) { // Expert encoding |
| 3706 | font.cffEncoding = new encoding.CffEncoding(encoding.cffExpertEncoding, charset); |
| 3707 | } else { |
| 3708 | font.cffEncoding = parseCFFEncoding(data, start + topDict.encoding, charset); |
| 3709 | } |
| 3710 | |
| 3711 | // Prefer the CMAP encoding to the CFF encoding. |
| 3712 | font.encoding = font.encoding || font.cffEncoding; |
| 3713 | |
| 3714 | font.glyphs = new glyphset.GlyphSet(font); |
| 3715 | for (var i = 0; i < font.nGlyphs; i += 1) { |
| 3716 | var charString = charStringsIndex.objects[i]; |
| 3717 | font.glyphs.push(i, glyphset.cffGlyphLoader(font, i, parseCFFCharstring, charString)); |
| 3718 | } |
| 3719 | } |
| 3720 | |
| 3721 | // Convert a string to a String ID (SID). |
| 3722 | // The list of strings is modified in place. |
nothing calls this directly
no test coverage detected