Merge pull request #1752 from anthrotype/region-axis-count

enforce VarStore RegionAxisCount == fvar.AxisCount
This commit is contained in:
Cosimo Lupo 2019-10-29 13:02:43 +00:00 committed by GitHub
commit 5790f7f9af
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 171 additions and 16 deletions

View File

@ -513,6 +513,8 @@ class CountReference(object):
table[name] = value table[name] = value
else: else:
assert table[name] == value, (name, table[name], value) assert table[name] == value, (name, table[name], value)
def getValue(self):
return self.table[self.name]
def getCountData(self): def getCountData(self):
v = self.table[self.name] v = self.table[self.name]
if v is None: v = 0 if v is None: v = 0
@ -690,8 +692,16 @@ class BaseTable(object):
# table. We will later store it here. # table. We will later store it here.
# We add a reference: by the time the data is assembled # We add a reference: by the time the data is assembled
# the Count value will be filled in. # the Count value will be filled in.
ref = writer.writeCountReference(table, conv.name, conv.staticSize) # We ignore the current count value since it will be recomputed,
table[conv.name] = None # unless it's a CountReference that was already initialized in a custom preWrite.
if isinstance(value, CountReference):
ref = value
ref.size = conv.staticSize
writer.writeData(ref)
table[conv.name] = ref.getValue()
else:
ref = writer.writeCountReference(table, conv.name, conv.staticSize)
table[conv.name] = None
if conv.isPropagated: if conv.isPropagated:
writer[conv.name] = ref writer[conv.name] = ref
elif conv.isLookupType: elif conv.isLookupType:

View File

@ -7,7 +7,7 @@ converter objects from otConverters.py.
""" """
from fontTools.misc.py23 import * from fontTools.misc.py23 import *
from fontTools.misc.textTools import pad, safeEval from fontTools.misc.textTools import pad, safeEval
from .otBase import BaseTable, FormatSwitchingBaseTable, ValueRecord from .otBase import BaseTable, FormatSwitchingBaseTable, ValueRecord, CountReference
import logging import logging
import struct import struct
@ -687,6 +687,25 @@ class VarIdxMap(BaseTable):
mapping[glyph] = (outer << 16) | inner 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 = len(fvarTable.axes)
return {
**self.__dict__,
"RegionAxisCount": CountReference(self.__dict__, "RegionAxisCount")
}
class SingleSubst(FormatSwitchingBaseTable): class SingleSubst(FormatSwitchingBaseTable):
def populateDefaults(self, propagator=None): def populateDefaults(self, propagator=None):

View File

@ -213,15 +213,13 @@ def _add_gvar(font, masterModel, master_ttfs, tolerance=0.5, optimize=True):
log.info("Generating gvar") log.info("Generating gvar")
assert "gvar" not in font assert "gvar" not in font
gvar = font["gvar"] = newTable('gvar')
gvar.version = 1
gvar.reserved = 0
gvar.variations = {}
glyf = font['glyf'] glyf = font['glyf']
# use hhea.ascent of base master as default vertical origin when vmtx is missing # use hhea.ascent of base master as default vertical origin when vmtx is missing
baseAscent = font['hhea'].ascent baseAscent = font['hhea'].ascent
variations = {}
for glyph in font.getGlyphOrder(): for glyph in font.getGlyphOrder():
isComposite = glyf[glyph].isComposite() isComposite = glyf[glyph].isComposite()
@ -241,7 +239,6 @@ def _add_gvar(font, masterModel, master_ttfs, tolerance=0.5, optimize=True):
del allControls del allControls
# Update gvar # Update gvar
gvar.variations[glyph] = []
deltas = model.getDeltas(allCoords) deltas = model.getDeltas(allCoords)
supports = model.supports supports = model.supports
assert len(deltas) == len(supports) assert len(deltas) == len(supports)
@ -280,7 +277,14 @@ def _add_gvar(font, masterModel, master_ttfs, tolerance=0.5, optimize=True):
if optimized_len < unoptimized_len: if optimized_len < unoptimized_len:
var = var_opt var = var_opt
gvar.variations[glyph].append(var) variations.setdefault(glyph, []).append(var)
if variations:
gvar = font["gvar"] = newTable('gvar')
gvar.version = 1
gvar.reserved = 0
gvar.variations = {g: variations.get(g, []) for g in font.getGlyphOrder()}
def _remove_TTHinting(font): def _remove_TTHinting(font):
for tag in ("cvar", "cvt ", "fpgm", "prep"): for tag in ("cvar", "cvt ", "fpgm", "prep"):
@ -350,19 +354,21 @@ def _merge_TTHinting(font, masterModel, master_ttfs, tolerance=0.5):
_remove_TTHinting(font) _remove_TTHinting(font)
return return
# We can build the cvar table now. variations = []
cvar = font["cvar"] = newTable('cvar')
cvar.version = 1
cvar.variations = []
deltas, supports = masterModel.getDeltasAndSupports(all_cvs) deltas, supports = masterModel.getDeltasAndSupports(all_cvs)
for i,(delta,support) in enumerate(zip(deltas[1:], supports[1:])): for i,(delta,support) in enumerate(zip(deltas[1:], supports[1:])):
delta = [otRound(d) for d in delta] delta = [otRound(d) for d in delta]
if all(abs(v) <= tolerance for v in delta): if all(abs(v) <= tolerance for v in delta):
continue continue
var = TupleVariation(support, delta) var = TupleVariation(support, delta)
cvar.variations.append(var) variations.append(var)
# We can build the cvar table now.
if variations:
cvar = font["cvar"] = newTable('cvar')
cvar.version = 1
cvar.variations = variations
_MetricsFields = namedtuple('_MetricsFields', _MetricsFields = namedtuple('_MetricsFields',
['tableTag', 'metricsTag', 'sb1', 'sb2', 'advMapping', 'vOrigMapping']) ['tableTag', 'metricsTag', 'sb1', 'sb2', 'advMapping', 'vOrigMapping'])

View File

@ -0,0 +1,13 @@
<?xml version='1.0' encoding='utf-8'?>
<designspace format="3">
<axes>
<axis default="400" maximum="400" minimum="400" name="weight" tag="wght" />
</axes>
<sources>
<source familyname="Test Family" filename="master_ufo/TestFamily-Master0.ufo" name="master_0">
<location>
<dimension name="weight" xvalue="400" />
</location>
</source>
</sources>
</designspace>

View File

@ -0,0 +1,98 @@
<?xml version="1.0" encoding="UTF-8"?>
<ttFont sfntVersion="\x00\x01\x00\x00" ttLibVersion="4.0">
<GDEF>
<Version value="0x00010003"/>
<GlyphClassDef Format="2">
<ClassDef glyph="uni0024" class="1"/>
<ClassDef glyph="uni0024.nostroke" class="1"/>
<ClassDef glyph="uni0041" class="1"/>
<ClassDef glyph="uni0061" class="1"/>
</GlyphClassDef>
</GDEF>
<HVAR>
<Version value="0x00010000"/>
<VarStore Format="1">
<Format value="1"/>
<VarRegionList>
<!-- RegionAxisCount=1 -->
<!-- RegionCount=0 -->
</VarRegionList>
<!-- VarDataCount=1 -->
<VarData index="0">
<!-- ItemCount=6 -->
<NumShorts value="0"/>
<!-- VarRegionCount=0 -->
<Item index="0" value="[]"/>
<Item index="1" value="[]"/>
<Item index="2" value="[]"/>
<Item index="3" value="[]"/>
<Item index="4" value="[]"/>
<Item index="5" value="[]"/>
</VarData>
</VarStore>
</HVAR>
<STAT>
<Version value="0x00010001"/>
<DesignAxisRecordSize value="8"/>
<!-- DesignAxisCount=1 -->
<DesignAxisRecord>
<Axis index="0">
<AxisTag value="wght"/>
<AxisNameID value="256"/> <!-- Weight -->
<AxisOrdering value="0"/>
</Axis>
</DesignAxisRecord>
<!-- AxisValueCount=0 -->
<ElidedFallbackNameID value="2"/> <!-- Regular -->
</STAT>
<fvar>
<!-- Weight -->
<Axis>
<AxisTag>wght</AxisTag>
<Flags>0x0</Flags>
<MinValue>400.0</MinValue>
<DefaultValue>400.0</DefaultValue>
<MaxValue>400.0</MaxValue>
<AxisNameID>256</AxisNameID>
</Axis>
</fvar>
<name>
<namerecord nameID="256" platformID="1" platEncID="0" langID="0x0" unicode="True">
Weight
</namerecord>
<namerecord nameID="1" platformID="3" platEncID="1" langID="0x409">
Test Family
</namerecord>
<namerecord nameID="2" platformID="3" platEncID="1" langID="0x409">
Regular
</namerecord>
<namerecord nameID="3" platformID="3" platEncID="1" langID="0x409">
Version 1.001;ADBO;Test Family Regular
</namerecord>
<namerecord nameID="4" platformID="3" platEncID="1" langID="0x409">
Test Family
</namerecord>
<namerecord nameID="5" platformID="3" platEncID="1" langID="0x409">
Version 1.001
</namerecord>
<namerecord nameID="6" platformID="3" platEncID="1" langID="0x409">
TestFamily-Master0
</namerecord>
<namerecord nameID="9" platformID="3" platEncID="1" langID="0x409">
Frank Grießhammer
</namerecord>
<namerecord nameID="17" platformID="3" platEncID="1" langID="0x409">
Master 0
</namerecord>
<namerecord nameID="256" platformID="3" platEncID="1" langID="0x409">
Weight
</namerecord>
</name>
</ttFont>

View File

@ -584,6 +584,15 @@ class BuildTest(unittest.TestCase):
self.expect_ttx(varfont, expected_ttx_path, tables) self.expect_ttx(varfont, expected_ttx_path, tables)
self.check_ttx_dump(varfont, expected_ttx_path, tables, suffix) self.check_ttx_dump(varfont, expected_ttx_path, tables, suffix)
def test_varlib_build_single_master(self):
self._run_varlib_build_test(
designspace_name='SingleMaster',
font_name='TestFamily',
tables=['GDEF', 'HVAR', 'MVAR', 'STAT', 'fvar', 'cvar', 'gvar', 'name'],
expected_ttx_name='SingleMaster',
save_before_dump=True,
)
def test_kerning_merging(self): def test_kerning_merging(self):
"""Test the correct merging of class-based pair kerning. """Test the correct merging of class-based pair kerning.