Merge pull request #1752 from anthrotype/region-axis-count
enforce VarStore RegionAxisCount == fvar.AxisCount
This commit is contained in:
commit
5790f7f9af
@ -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:
|
||||||
|
@ -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):
|
||||||
|
@ -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'])
|
||||||
|
13
Tests/varLib/data/SingleMaster.designspace
Normal file
13
Tests/varLib/data/SingleMaster.designspace
Normal 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>
|
98
Tests/varLib/data/test_results/SingleMaster.ttx
Normal file
98
Tests/varLib/data/test_results/SingleMaster.ttx
Normal 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>
|
@ -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.
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user