From 0f0148e54ab68e6e3d0691398ddf66e470465bf8 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Sun, 17 Dec 2023 17:39:13 -0700 Subject: [PATCH] [VARC/scaleUpem] Implement --- Lib/fontTools/ttLib/scaleUpem.py | 80 +- Lib/fontTools/varLib/multiVarStore.py | 11 + Tests/ttLib/data/varc-ac00-ac01-500upem.ttx | 3053 ++++++++----------- Tests/ttLib/scaleUpem_test.py | 7 + 4 files changed, 1328 insertions(+), 1823 deletions(-) diff --git a/Lib/fontTools/ttLib/scaleUpem.py b/Lib/fontTools/ttLib/scaleUpem.py index ff1cfa78b..84002d115 100644 --- a/Lib/fontTools/ttLib/scaleUpem.py +++ b/Lib/fontTools/ttLib/scaleUpem.py @@ -10,7 +10,10 @@ import fontTools.ttLib.tables.otTables as otTables from fontTools.cffLib import VarStoreData import fontTools.cffLib.specializer as cffSpecializer from fontTools.varLib import builder # for VarData.calculateNumShorts +from fontTools.varLib.multiVarStore import OnlineMultiVarStoreBuilder +from fontTools.misc.vector import Vector from fontTools.misc.fixedTools import otRound +from itertools import batched __all__ = ["scale_upem", "ScalerVisitor"] @@ -145,6 +148,13 @@ def visit(visitor, obj, attr, variations): @ScalerVisitor.register_attr(ttLib.getTableClass("VARC"), "table") def visit(visitor, obj, attr, varc): # VarComposite variations are a pain + + fvar = visitor.font["fvar"] + fvarAxes = [a.axisTag for a in fvar.axes] + + store = varc.MultiVarStore + storeBuilder = OnlineMultiVarStoreBuilder(fvarAxes) + for g in varc.VarCompositeGlyphs.glyphs: for component in g.components: t = component.transform @@ -153,7 +163,75 @@ def visit(visitor, obj, attr, varc): t.tCenterX = visitor.scale(t.tCenterX) t.tCenterY = visitor.scale(t.tCenterY) - # TODO: MultiVarStore + if component.flags & otTables.VarComponentFlags.AXIS_VALUES_HAVE_VARIATION: + varIdx = component.locationVarIndex + if varIdx == otTables.NO_VARIATION_INDEX: + continue + major = varIdx >> 16 + minor = varIdx & 0xFFFF + varData = store.MultiVarData[major] + vec = varData.Item[minor] + storeBuilder.setSupports(store.get_supports(major, fvar.axes)) + if vec.values: + m = len(vec.values) // varData.VarRegionCount + vec = list(batched(vec.values, m)) + vec = [Vector(v) for v in vec] + component.locationVarIndex = storeBuilder.storeDeltas(vec) + else: + component.transformVarIndex = otTables.NO_VARIATION_INDEX + + if component.flags & otTables.VarComponentFlags.TRANSFORM_HAS_VARIATION: + varIdx = component.transformVarIndex + if varIdx == otTables.NO_VARIATION_INDEX: + continue + major = varIdx >> 16 + minor = varIdx & 0xFFFF + vec = varData.Item[varIdx & 0xFFFF] + major = varIdx >> 16 + minor = varIdx & 0xFFFF + varData = store.MultiVarData[major] + vec = varData.Item[minor] + storeBuilder.setSupports(store.get_supports(major, fvar.axes)) + if vec.values: + m = len(vec.values) // varData.VarRegionCount + flags = component.flags + vec = list(batched(vec.values, m)) + newVec = [] + for v in vec: + v = list(v) + i = 0 + ## Scale translate & tCenter + if flags & otTables.VarComponentFlags.HAVE_TRANSLATE_X: + v[i] = visitor.scale(v[i]) + i += 1 + if flags & otTables.VarComponentFlags.HAVE_TRANSLATE_Y: + v[i] = visitor.scale(v[i]) + i += 1 + if flags & otTables.VarComponentFlags.HAVE_ROTATION: + i += 1 + if flags & otTables.VarComponentFlags.HAVE_SCALE_X: + i += 1 + if flags & otTables.VarComponentFlags.HAVE_SCALE_Y: + i += 1 + if flags & otTables.VarComponentFlags.HAVE_SKEW_X: + i += 1 + if flags & otTables.VarComponentFlags.HAVE_SKEW_Y: + i += 1 + if flags & otTables.VarComponentFlags.HAVE_TCENTER_X: + v[i] = visitor.scale(v[i]) + i += 1 + if flags & otTables.VarComponentFlags.HAVE_TCENTER_Y: + v[i] = visitor.scale(v[i]) + i += 1 + + newVec.append(Vector(v)) + vec = newVec + + component.transformVarIndex = storeBuilder.storeDeltas(vec) + else: + component.transformVarIndex = otTables.NO_VARIATION_INDEX + + varc.MultiVarStore = storeBuilder.finish() @ScalerVisitor.register_attr(ttLib.getTableClass("kern"), "kernTables") diff --git a/Lib/fontTools/varLib/multiVarStore.py b/Lib/fontTools/varLib/multiVarStore.py index b3440cc63..3cc78ae8e 100644 --- a/Lib/fontTools/varLib/multiVarStore.py +++ b/Lib/fontTools/varLib/multiVarStore.py @@ -205,6 +205,17 @@ def MultiVarStore_prune_regions(self, *, VarData="VarData"): ot.MultiVarStore.prune_regions = MultiVarStore_prune_regions ot.MultiVarStore.subset_varidxes = MultiVarStore_subset_varidxes +def MultiVarStore_get_supports(self, major, fvarAxes): + supports = [] + varData = self.MultiVarData[major] + for regionIdx in varData.VarRegionIndex: + region = self.VarRegionList.Region[regionIdx] + support = region.get_support(fvarAxes) + supports.append(support) + return supports + +ot.MultiVarStore.get_supports = MultiVarStore_get_supports + def VARC_collect_varidxes(self, varidxes): for glyph in self.VarCompositeGlyphs.glyphs: diff --git a/Tests/ttLib/data/varc-ac00-ac01-500upem.ttx b/Tests/ttLib/data/varc-ac00-ac01-500upem.ttx index db32c06eb..dd9cc2f4b 100644 --- a/Tests/ttLib/data/varc-ac00-ac01-500upem.ttx +++ b/Tests/ttLib/data/varc-ac00-ac01-500upem.ttx @@ -1,5 +1,5 @@ - + @@ -9,17 +9,22 @@ + + + + + - - + + - - - - + + + + @@ -34,9 +39,9 @@ - - - + + + @@ -50,66 +55,18 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + @@ -135,272 +92,131 @@ - + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + - - - - - - - - - - - - - - - - - - - + - - - - - - - - - - - - - - - - - - - - - - - - - + - butchered-hangul-serif + rcjk - smarties-variable + varc - 0000 + Weight - 0001 + OpticalSize - 0002 + 0000 - 0003 + 0001 - 0004 + 0002 - 0005 + 0003 - 0006 + 0004 - 0007 + 0005 - Weight + 0006 + + + 0007 + + + 0008 + + + 0009 + + + 0010 + + + 0011 + + + 0012 + + + 0013 + + + 0014 @@ -416,1638 +232,1231 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - 0000 - 0x1 - 0.0 - 0.0 - 1.0 + wght + 0x0 + 356.5 + 356.5 + 840.3 256 - + - 0001 - 0x1 + opsz + 0x0 0.0 0.0 1.0 257 - + - 0002 - 0x1 - 0.0 + 0000 + 0x0 + -1.0 0.0 1.0 258 - + - 0003 - 0x1 - 0.0 + 0001 + 0x0 + -1.0 0.0 1.0 259 - + - 0004 - 0x1 - 0.0 + 0002 + 0x0 + -1.0 0.0 1.0 260 - + - 0005 - 0x1 - 0.0 + 0003 + 0x0 + -1.0 0.0 1.0 261 - + - 0006 - 0x1 - 0.0 + 0004 + 0x0 + -1.0 0.0 1.0 262 - + - 0007 - 0x1 - 0.0 + 0005 + 0x0 + -1.0 0.0 1.0 263 - + - wght + 0006 0x0 - 200.0 - 200.0 - 900.0 + -1.0 + 0.0 + 1.0 264 + + + + 0007 + 0x0 + -1.0 + 0.0 + 1.0 + 265 + + + + + 0008 + 0x0 + -1.0 + 0.0 + 1.0 + 266 + + + + + 0009 + 0x0 + -1.0 + 0.0 + 1.0 + 267 + + + + + 0010 + 0x0 + -1.0 + 0.0 + 1.0 + 268 + + + + + 0011 + 0x0 + -1.0 + 0.0 + 1.0 + 269 + + + + + 0012 + 0x0 + -1.0 + 0.0 + 1.0 + 270 + + + + + 0013 + 0x0 + -1.0 + 0.0 + 1.0 + 271 + + + + + 0014 + 0x0 + -1.0 + 0.0 + 1.0 + 272 + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + - - - - - - - - + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Tests/ttLib/scaleUpem_test.py b/Tests/ttLib/scaleUpem_test.py index 6024758f3..524b7f1b0 100644 --- a/Tests/ttLib/scaleUpem_test.py +++ b/Tests/ttLib/scaleUpem_test.py @@ -1,5 +1,6 @@ from fontTools.ttLib import TTFont from fontTools.ttLib.scaleUpem import scale_upem +from io import BytesIO import difflib import os import shutil @@ -70,6 +71,12 @@ class ScaleUpemTest(unittest.TestCase): scale_upem(font, 500) + # Save / load to ensure calculated values are correct + # XXX This wans't needed before. So needs investigation. + iobytes = BytesIO() + font.save(iobytes) + # Just saving is enough to fix the numbers. Sigh... + expected_ttx_path = self.get_path("varc-ac00-ac01-500upem.ttx") self.expect_ttx(font, expected_ttx_path, tables)