Merge pull request #3525 from fonttools/cff-converters-fixes

CFF converters fixes
This commit is contained in:
خالد حسني (Khaled Hosny) 2024-05-27 22:19:16 +03:00 committed by GitHub
commit ed7701a0a2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 65 additions and 13 deletions

View File

@ -2,7 +2,13 @@
from fontTools.ttLib import TTFont, newTable
from fontTools.misc.cliTools import makeOutputFileName
from fontTools.cffLib import TopDictIndex, buildOrder, topDictOperators
from fontTools.cffLib import (
TopDictIndex,
buildOrder,
buildDefaults,
topDictOperators,
privateDictOperators,
)
from .width import optimizeWidths
from collections import defaultdict
import logging
@ -36,16 +42,32 @@ def _convertCFF2ToCFF(cff, otFont):
if hasattr(topDict, "VarStore"):
raise ValueError("Variable CFF2 font cannot be converted to CFF format.")
if hasattr(topDict, "Private"):
privateDict = topDict.Private
else:
privateDict = None
opOrder = buildOrder(topDictOperators)
topDict.order = opOrder
for key in topDict.rawDict.keys():
if key not in opOrder:
del topDict.rawDict[key]
if hasattr(topDict, key):
delattr(topDict, key)
fdArray = topDict.FDArray
charStrings = topDict.CharStrings
defaults = buildDefaults(privateDictOperators)
order = buildOrder(privateDictOperators)
for fd in fdArray:
fd.setCFF2(False)
privateDict = fd.Private
privateDict.order = order
for key in order:
if key not in privateDict.rawDict and key in defaults:
privateDict.rawDict[key] = defaults[key]
for key in privateDict.rawDict.keys():
if key not in order:
del privateDict.rawDict[key]
if hasattr(privateDict, key):
delattr(privateDict, key)
for cs in charStrings.values():
cs.decompile()
cs.program.append("endchar")

View File

@ -43,7 +43,15 @@ def _convertCFFToCFF2(cff, otFont):
fdArray = topDict.FDArray if hasattr(topDict, "FDArray") else None
charStrings = topDict.CharStrings
globalSubrs = cff.GlobalSubrs
localSubrs = [getattr(fd.Private, "Subrs", []) for fd in fdArray] if fdArray else []
localSubrs = (
[getattr(fd.Private, "Subrs", []) for fd in fdArray]
if fdArray
else (
[topDict.Private.Subrs]
if hasattr(topDict, "Private") and hasattr(topDict.Private, "Subrs")
else []
)
)
for glyphName in charStrings.keys():
cs, fdIndex = charStrings.getItemAndSelector(glyphName)
@ -70,13 +78,21 @@ def _convertCFFToCFF2(cff, otFont):
for glyphName in charStrings.keys():
cs, fdIndex = charStrings.getItemAndSelector(glyphName)
program = cs.program
if fdIndex == None:
fdIndex = 0
thisLocalSubrs = (
localSubrs[fdIndex]
if fdIndex
else (
getattr(topDict.Private, "Subrs", [])
if hasattr(topDict, "Private")
else []
)
)
# Intentionally use custom type for nominalWidthX, such that any
# CharString that has an explicit width encoded will throw back to us.
extractor = T2WidthExtractor(
localSubrs[fdIndex] if localSubrs else [],
thisLocalSubrs,
globalSubrs,
nominalWidthXError,
0,
@ -94,7 +110,7 @@ def _convertCFFToCFF2(cff, otFont):
op = program.pop(0)
bias = extractor.localBias if op == "callsubr" else extractor.globalBias
subrNumber += bias
subrSet = localSubrs[fdIndex] if op == "callsubr" else globalSubrs
subrSet = thisLocalSubrs if op == "callsubr" else globalSubrs
subrProgram = subrSet[subrNumber].program
program[:0] = subrProgram
# Now pop the actual width

View File

@ -1470,7 +1470,7 @@ class CharsetConverter(SimpleConverter):
else: # offset == 0 -> no charset data.
if isCID or "CharStrings" not in parent.rawDict:
# We get here only when processing fontDicts from the FDArray of
# CFF-CID fonts. Only the real topDict references the chrset.
# CFF-CID fonts. Only the real topDict references the charset.
assert value == 0
charset = None
elif value == 0:

View File

@ -342,7 +342,7 @@ def _cs_drop_hints(charstring):
del charstring._hints
def remove_hints(cff):
def remove_hints(cff, *, removeUnusedSubrs: bool = True):
for fontname in cff.keys():
font = cff[fontname]
cs = font.CharStrings
@ -404,6 +404,7 @@ def remove_hints(cff):
]:
if hasattr(priv, k):
setattr(priv, k, None)
if removeUnusedSubrs:
remove_unused_subroutines(cff)

View File

@ -5,6 +5,7 @@ import copy
import os
import sys
import unittest
from io import BytesIO
class CffLibTest(DataFilesHandler):
@ -119,5 +120,17 @@ class CffLibTest(DataFilesHandler):
self.assertEqual(len(glyphOrder), len(set(glyphOrder)))
class CFFToCFF2Test(DataFilesHandler):
def test_conversion(self):
font_path = self.getpath("CFFToCFF2-1.otf")
font = TTFont(font_path)
from fontTools.cffLib.CFFToCFF2 import convertCFFToCFF2
convertCFFToCFF2(font)
f = BytesIO()
font.save(f)
if __name__ == "__main__":
sys.exit(unittest.main())

Binary file not shown.