From adc5b2997eaebbae7b9de6952351d9563ac7aa6d Mon Sep 17 00:00:00 2001 From: Cosimo Lupo Date: Thu, 24 Oct 2019 12:51:48 +0100 Subject: [PATCH] [otBase|otTables] enforce VarStore RegionAxisCount == fvar.AxisCount even when there are no Regions and thus we can't take the length of VarRegionAxis array. This is to appease older versions of OTS which blindly enforce this rule and reject a VF that has, e.g., an empty HVAR table with no regions if the HVAR.VarStore.VarRegionList.RegionAxisCount != fvar.AxisCount. Fixes https://github.com/fonttools/fonttools/issues/1670 Related: https://github.com/fonttools/fonttools/pull/1671 https://github.com/googlefonts/fontmake/issues/565 https://github.com/khaledhosny/ots/pull/192 --- Lib/fontTools/ttLib/tables/otBase.py | 13 +++++++++++-- Lib/fontTools/ttLib/tables/otTables.py | 18 +++++++++++++++++- 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/Lib/fontTools/ttLib/tables/otBase.py b/Lib/fontTools/ttLib/tables/otBase.py index 521a98ebd..f4a39e5f3 100644 --- a/Lib/fontTools/ttLib/tables/otBase.py +++ b/Lib/fontTools/ttLib/tables/otBase.py @@ -498,6 +498,11 @@ class OTTableWriter(object): return OverflowErrorRecord( (self.tableTag, LookupListIndex, SubTableIndex, itemName, itemIndex) ) +class LiteralCount(int): + """A count value that should be taken literally, rather than recomputed on compile.""" + pass + + class CountReference(object): """A reference to a Count value, not a count of references.""" def __init__(self, table, name, size=None, value=None): @@ -690,8 +695,12 @@ class BaseTable(object): # table. We will later store it here. # We add a reference: by the time the data is assembled # the Count value will be filled in. - ref = writer.writeCountReference(table, conv.name, conv.staticSize) - table[conv.name] = None + if not isinstance(value, LiteralCount): + # we ignore the current count value since it's being recomputed, + # unless this is a LiteralCount, which is assumed to be already correct. + value = None + ref = writer.writeCountReference(table, conv.name, conv.staticSize, value) + table[conv.name] = value if conv.isPropagated: writer[conv.name] = ref elif conv.isLookupType: diff --git a/Lib/fontTools/ttLib/tables/otTables.py b/Lib/fontTools/ttLib/tables/otTables.py index 252d121ca..53f9fa82f 100644 --- a/Lib/fontTools/ttLib/tables/otTables.py +++ b/Lib/fontTools/ttLib/tables/otTables.py @@ -7,7 +7,7 @@ converter objects from otConverters.py. """ from fontTools.misc.py23 import * from fontTools.misc.textTools import pad, safeEval -from .otBase import BaseTable, FormatSwitchingBaseTable, ValueRecord +from .otBase import BaseTable, FormatSwitchingBaseTable, ValueRecord, LiteralCount import logging import struct @@ -687,6 +687,22 @@ class VarIdxMap(BaseTable): mapping[glyph] = (outer << 16) | inner +class VarRegionList(BaseTable): + + def preWrite(self, font): + # The OT spec says VarStore.VarRegionList.RegionAxisCount should always + # be equal to the fvar.axisCount, and OTS < v8.0.0 enforces this rule + # even when the VarRegionList is empty. We can't treat RegionAxisCount + # like a normal propagated count (== len(Region[i].VarRegionAxis)), + # otherwise it would default to 0 if VarRegionList is empty. + # Thus, we force it to always be equal to fvar.axisCount. + # https://github.com/khaledhosny/ots/pull/192 + fvarTable = font.get("fvar") + if fvarTable: + self.RegionAxisCount = LiteralCount(len(fvarTable.axes)) + return self.__dict__.copy() + + class SingleSubst(FormatSwitchingBaseTable): def populateDefaults(self, propagator=None):