Skip to content

Commit

Permalink
Merge pull request #816 from googlefonts/vf-fontinfo
Browse files Browse the repository at this point in the history
Apply DesignSpace variable-font's public.fontInfo lib key to variable fonts
  • Loading branch information
anthrotype authored Feb 2, 2024
2 parents 357ed94 + 2020a8d commit a1ea19b
Show file tree
Hide file tree
Showing 25 changed files with 670 additions and 10 deletions.
14 changes: 10 additions & 4 deletions Lib/ufo2ft/_compilers/baseCompiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,9 +97,11 @@ def compileOutlines(self, ufo, glyphSet):
outlineCompiler = self.outlineCompilerClass(ufo, glyphSet=glyphSet, **kwargs)
return outlineCompiler.compile()

def postprocess(self, ttf, ufo, glyphSet):
def postprocess(self, ttf, ufo, glyphSet, info=None):
if self.postProcessorClass is not None:
postProcessor = self.postProcessorClass(ttf, ufo, glyphSet=glyphSet)
postProcessor = self.postProcessorClass(
ttf, ufo, glyphSet=glyphSet, info=info
)
kwargs = prune_unknown_kwargs(self.__dict__, postProcessor.process)
ttf = postProcessor.process(**kwargs)
return ttf
Expand Down Expand Up @@ -249,7 +251,10 @@ def _compileNeededSources(self, designSpaceDoc):
f"No default source; expected default master at {default_location}."
f" Found master locations:\n{master_location_descriptions}"
)
vfNameToBaseUfo[vfName] = default_source.font
vfNameToBaseUfo[vfName] = (
default_source.font,
vfDoc.lib.get("public.fontInfo"),
)
for source in vfDoc.sources:
sourcesToCompile.add(source.name)

Expand Down Expand Up @@ -359,8 +364,9 @@ def compile_variable(self, designSpaceDoc):
designSpaceDoc, vfNameToTTFont, originalSources, originalGlyphsets
)
for vfName, varfont in list(vfNameToTTFont.items()):
ufo, info = vfNameToBaseUfo[vfName]
vfNameToTTFont[vfName] = self.postprocess(
varfont, vfNameToBaseUfo[vfName], glyphSet=None
varfont, ufo, glyphSet=None, info=info
)

return vfNameToTTFont
Expand Down
6 changes: 4 additions & 2 deletions Lib/ufo2ft/_compilers/otfCompiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,11 @@ def compileOutlines(self, ufo, glyphSet):
outlineCompiler = self.outlineCompilerClass(ufo, glyphSet=glyphSet, **kwargs)
return outlineCompiler.compile()

def postprocess(self, font, ufo, glyphSet):
def postprocess(self, font, ufo, glyphSet, info=None):
if self.postProcessorClass is not None:
postProcessor = self.postProcessorClass(font, ufo, glyphSet=glyphSet)
postProcessor = self.postProcessorClass(
font, ufo, glyphSet=glyphSet, info=info
)
kwargs = prune_unknown_kwargs(self.__dict__, postProcessor.process)
kwargs["optimizeCFF"] = self.optimizeCFF >= CFFOptimization.SUBROUTINIZE
font = postProcessor.process(**kwargs)
Expand Down
183 changes: 183 additions & 0 deletions Lib/ufo2ft/infoCompiler.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
"""
InfoCompiler is used to apply fontinfo overrides to an already compiled font.
This is used to apply fontinfo from a DesignSpace variable-font after merging
font sources into final variable font.
It builds a temporary font with the only the tables that can be modified with
fontinfo, then merge relevant table attributes it into the original font.
"""

import copy

from ufo2ft.outlineCompiler import BaseOutlineCompiler


class InfoCompiler(BaseOutlineCompiler):
info_tables = frozenset(
[
"head",
"hhea",
"name",
"OS/2",
"post",
"vhea",
"gasp",
]
)

def __init__(self, otf, ufo, info):
self.orig_otf = otf
tables = self.info_tables & set(otf.keys())

# Create a temporary UFO and sets its fontinfo to the union of the main
# UFO's fontinfo and the DesignSpace variable-font’s info.
temp_ufo = type(ufo)()
if hasattr(ufo.info, "getDataForSerialization"):
# defcon
data = ufo.info.getDataForSerialization()
data.update(info)
temp_ufo.info.setDataFromSerialization(data)
else:
# ufoLib2
temp_ufo.info = copy.copy(ufo.info)
for k, v in info.items():
setattr(temp_ufo.info, k, v)

super().__init__(temp_ufo, tables=tables, glyphSet={}, glyphOrder=[])

def compile(self):
super().compile()
if "gasp" in self.tables:
self.setupTable_gasp()
return self.orig_otf

@staticmethod
def makeMissingRequiredGlyphs(*args, **kwargs):
return

def makeFontBoundingBox(self):
from ufo2ft.outlineCompiler import EMPTY_BOUNDING_BOX

return EMPTY_BOUNDING_BOX

def _set_attrs(self, tag, attrs):
temp = self.otf[tag]
orig = self.orig_otf[tag]
for attr in attrs:
if (value := getattr(temp, attr, None)) is not None:
setattr(orig, attr, value)

def setupTable_head(self):
super().setupTable_head()
self._set_attrs(
"head",
{
"fontRevision",
"unitsPerEm",
"created",
"macStyle",
"flags",
"lowestRecPPEM",
},
)

def setupTable_hhea(self):
super().setupTable_hhea()
self._set_attrs(
"hhea",
{
"ascent",
"descent",
"lineGap",
"caretSlopeRise",
"caretSlopeRun",
"caretOffset",
},
)

def setupTable_vhea(self):
super().setupTable_vhea()
self._set_attrs(
"vhea",
{
"ascent",
"descent",
"lineGap",
"caretSlopeRise",
"caretSlopeRun",
"caretOffset",
},
)

def setupTable_OS2(self):
super().setupTable_OS2()
self._set_attrs(
"OS/2",
{
"usWeightClass",
"usWidthClass",
"fsType",
"ySubscriptXSize",
"ySubscriptYSize",
"ySubscriptYOffset",
"ySubscriptXOffset",
"ySuperscriptXSize",
"ySuperscriptYSize",
"ySuperscriptYOffset",
"ySuperscriptXOffset",
"yStrikeoutSize",
"yStrikeoutPosition",
"sFamilyClass",
"panose",
"ulUnicodeRange1",
"ulUnicodeRange2",
"ulUnicodeRange3",
"ulUnicodeRange4",
"achVendID",
"fsSelection",
"sTypoAscender",
"sTypoDescender",
"sTypoLineGap",
"usWinAscent",
"usWinDescent",
"ulCodePageRange1",
"ulCodePageRange2",
"sxHeight",
"sCapHeight",
},
)

def setupTable_post(self):
super().setupTable_post()
self._set_attrs(
"post",
{
"italicAngle",
"underlinePosition",
"underlineThickness",
"isFixedPitch",
},
)

def setupTable_name(self):
super().setupTable_name()
temp = self.otf["name"]
orig = self.orig_otf["name"]
temp_names = {
(n.nameID, n.platformID, n.platEncID, n.langID): n for n in temp.names
}
orig_names = {
(n.nameID, n.platformID, n.platEncID, n.langID): n for n in orig.names
}
orig_names.update(temp_names)
orig.names = list(orig_names.values())

def setupTable_gasp(self):
from ufo2ft.instructionCompiler import InstructionCompiler

instructionCompiler = InstructionCompiler(self.ufo, self.otf)
instructionCompiler.setupTable_gasp()
self._set_attrs("gasp", {"gaspRange"})

def setupTable_maxp(self):
return
2 changes: 1 addition & 1 deletion Lib/ufo2ft/outlineCompiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -643,7 +643,7 @@ def adjustOffset(offset, angle):
os2.ulUnicodeRange2 = intListToNum(uniRanges, 32, 32)
os2.ulUnicodeRange3 = intListToNum(uniRanges, 64, 32)
os2.ulUnicodeRange4 = intListToNum(uniRanges, 96, 32)
else:
elif "cmap" in self.otf:
os2.recalcUnicodeRanges(self.otf)

# codepage ranges
Expand Down
17 changes: 15 additions & 2 deletions Lib/ufo2ft/postProcessor.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,10 @@ class SubroutinizerBackend(enum.Enum):
2: SubroutinizerBackend.CFFSUBR,
}

def __init__(self, otf, ufo, glyphSet=None):
def __init__(self, otf, ufo, glyphSet=None, info=None):
self.ufo = ufo
self.glyphSet = glyphSet if glyphSet is not None else ufo

self.info = info
self.otf = otf

self._postscriptNames = ufo.lib.get("public.postscriptNames")
Expand Down Expand Up @@ -103,6 +103,9 @@ def process(

self.process_glyph_names(useProductionNames)

if self.info:
self.apply_fontinfo()

return self.otf

def process_cff(self, *, optimizeCFF=True, cffVersion=None, subroutinizer=None):
Expand Down Expand Up @@ -357,6 +360,16 @@ def _subroutinize_with_cffsubr(cls, otf, cffVersion):

return cffsubr.subroutinize(otf, cff_version=cffVersion, keep_glyph_names=False)

def apply_fontinfo(self):
"""Apply the fontinfo data from the DesignSpace variable-font's lib to
the compiled font."""
from ufo2ft.infoCompiler import InfoCompiler

logger.info("Applying variable-font info from DesignSpace lib")

compiler = InfoCompiler(self.otf, self.ufo, self.info)
compiler.compile()


# Adapted from fontTools.cff.specializer.programToCommands
# https://github.com/fonttools/fonttools/blob/babca16
Expand Down
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,4 @@ cffsubr==0.3.0
skia-pathops==0.8.0.post1

# alternative UFO implementation
ufoLib2==0.16.0
ufoLib2[converters]==0.16.0
36 changes: 36 additions & 0 deletions tests/data/TestVarFont-Bold.ufo/fontinfo.plist
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>ascender</key>
<integer>600</integer>
<key>capHeight</key>
<integer>700</integer>
<key>descender</key>
<integer>-400</integer>
<key>familyName</key>
<string>TestVarFont</string>
<key>italicAngle</key>
<integer>0</integer>
<key>openTypeHeadCreated</key>
<string>2022/07/26 14:49:29</string>
<key>openTypeOS2Type</key>
<array>
<integer>3</integer>
</array>
<key>postscriptUnderlinePosition</key>
<integer>-100</integer>
<key>postscriptUnderlineThickness</key>
<integer>50</integer>
<key>styleName</key>
<string>Bold</string>
<key>unitsPerEm</key>
<integer>1000</integer>
<key>versionMajor</key>
<integer>1</integer>
<key>versionMinor</key>
<integer>0</integer>
<key>xHeight</key>
<integer>500</integer>
</dict>
</plist>
15 changes: 15 additions & 0 deletions tests/data/TestVarFont-Bold.ufo/glyphs/alef-ar.fina.glif
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?xml version='1.0' encoding='UTF-8'?>
<glyph name="alef-ar.fina" format="2">
<advance width="410"/>
<unicode hex="0627"/>
<outline>
<contour>
<point x="280" y="601" type="line"/>
<point x="280" y="160" type="line"/>
<point x="470" y="160" type="line"/>
<point x="470" y="0" type="line"/>
<point x="120" y="0" type="line"/>
<point x="120" y="569" type="line"/>
</contour>
</outline>
</glyph>
10 changes: 10 additions & 0 deletions tests/data/TestVarFont-Bold.ufo/glyphs/contents.plist
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>alef-ar.fina</key>
<string>alef-ar.fina.glif</string>
<key>space</key>
<string>space.glif</string>
</dict>
</plist>
7 changes: 7 additions & 0 deletions tests/data/TestVarFont-Bold.ufo/glyphs/space.glif
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?xml version='1.0' encoding='UTF-8'?>
<glyph name="space" format="2">
<advance width="600"/>
<unicode hex="0020"/>
<outline>
</outline>
</glyph>
10 changes: 10 additions & 0 deletions tests/data/TestVarFont-Bold.ufo/layercontents.plist
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<array>
<array>
<string>public.default</string>
<string>glyphs</string>
</array>
</array>
</plist>
16 changes: 16 additions & 0 deletions tests/data/TestVarFont-Bold.ufo/lib.plist
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>public.glyphOrder</key>
<array>
<string>space</string>
<string>alef-ar.fina</string>
</array>
<key>public.postscriptNames</key>
<dict>
<key>alef-ar.fina</key>
<string>uniFE8E</string>
</dict>
</dict>
</plist>
Loading

0 comments on commit a1ea19b

Please sign in to comment.