[feaLib] Compile zero values to different formats based on context

If a zero value appears in a SinglePos statement, feaLib continues to
produce ValueRecords of format 0. But if a zero value appears in a
PairPos statement inside a horizontal compilation context, feaLib now
produces ValueRecords of format 4. Likewise, if a zero value appears
in a PairPos statement inside a vertical compilation context, feaLib
now produces ValueRecords of format 8.

The OpenType Feature Syntax specification is completely silent about this,
but the new behavior matches that of makeotf.

https://github.com/fonttools/fonttools/issues/633
This commit is contained in:
Sascha Brawer 2017-02-16 15:06:02 +01:00
parent 790c93d5cf
commit 7c67e4a63d
6 changed files with 180 additions and 7 deletions

View File

@ -1012,7 +1012,7 @@ _VALUEREC_ATTRS = {
}
def makeOpenTypeValueRecord(v):
def makeOpenTypeValueRecord(v, pairPosContext):
"""ast.ValueRecord --> (otBase.ValueRecord, int ValueFormat)"""
if v is None:
return None, 0
@ -1022,7 +1022,8 @@ def makeOpenTypeValueRecord(v):
val = getattr(v, astName, None)
if val:
vr[otName] = otl.buildDevice(dict(val)) if isDevice else val
if pairPosContext and not vr:
vr = {"YAdvance": 0} if v.vertical else {"XAdvance": 0}
valRec = otl.buildValue(vr)
return valRec, valRec.getFormat()
@ -1420,8 +1421,8 @@ class PairPosBuilder(LookupBuilder):
'Already defined position for pair %s %s at %s:%d:%d'
% (glyph1, glyph2, otherLoc[0], otherLoc[1], otherLoc[2]),
location)
val1, _ = makeOpenTypeValueRecord(value1)
val2, _ = makeOpenTypeValueRecord(value2)
val1, _ = makeOpenTypeValueRecord(value1, pairPosContext=True)
val2, _ = makeOpenTypeValueRecord(value2, pairPosContext=True)
self.glyphPairs[key] = (val1, val2)
self.locations[key] = location
@ -1442,8 +1443,10 @@ class PairPosBuilder(LookupBuilder):
if builder is not None:
builder.addSubtableBreak()
continue
val1, valFormat1 = makeOpenTypeValueRecord(value1)
val2, valFormat2 = makeOpenTypeValueRecord(value2)
val1, valFormat1 = makeOpenTypeValueRecord(
value1, pairPosContext=True)
val2, valFormat2 = makeOpenTypeValueRecord(
value2, pairPosContext=True)
builder = builders.get((valFormat1, valFormat2))
if builder is None:
builder = ClassPairPosSubtableBuilder(
@ -1466,7 +1469,8 @@ class SinglePosBuilder(LookupBuilder):
self.mapping = {} # glyph -> otTables.ValueRecord
def add_pos(self, location, glyph, valueRecord):
otValueRecord, _ = makeOpenTypeValueRecord(valueRecord)
otValueRecord, _ = makeOpenTypeValueRecord(
valueRecord, pairPosContext=False)
curValue = self.mapping.get(glyph)
if curValue is not None and curValue != otValueRecord:
otherLoc = self.locations[glyph]

View File

@ -66,6 +66,7 @@ class BuilderTest(unittest.TestCase):
bug512 bug568
name size size2 multiple_feature_blocks omitted_GlyphClassDef
ZeroValue_SinglePos
ZeroValue_PairPos_horizontal ZeroValue_PairPos_vertical
""".split()
def __init__(self, methodName):

View File

@ -0,0 +1,9 @@
# For PairPos statements in horizontal compilation contexts,
# zero values should get compiled to ValueRecord format 4.
# https://github.com/fonttools/fonttools/issues/633
feature kern {
pos A 0 A 0;
pos A 0 B <0 0 0 0>;
pos B <0 0 0 0> A 0;
pos B <0 0 0 0> B <0 0 0 0>;
} kern;

View File

@ -0,0 +1,75 @@
<?xml version="1.0" encoding="UTF-8"?>
<ttFont sfntVersion="true" ttLibVersion="3.0">
<GPOS>
<Version value="0x00010000"/>
<ScriptList>
<!-- ScriptCount=1 -->
<ScriptRecord index="0">
<ScriptTag value="DFLT"/>
<Script>
<DefaultLangSys>
<ReqFeatureIndex value="65535"/>
<!-- FeatureCount=1 -->
<FeatureIndex index="0" value="0"/>
</DefaultLangSys>
<!-- LangSysCount=0 -->
</Script>
</ScriptRecord>
</ScriptList>
<FeatureList>
<!-- FeatureCount=1 -->
<FeatureRecord index="0">
<FeatureTag value="kern"/>
<Feature>
<!-- LookupCount=1 -->
<LookupListIndex index="0" value="0"/>
</Feature>
</FeatureRecord>
</FeatureList>
<LookupList>
<!-- LookupCount=1 -->
<Lookup index="0">
<LookupType value="2"/>
<LookupFlag value="0"/>
<!-- SubTableCount=1 -->
<PairPos index="0" Format="1">
<Coverage>
<Glyph value="A"/>
<Glyph value="B"/>
</Coverage>
<ValueFormat1 value="4"/>
<ValueFormat2 value="4"/>
<!-- PairSetCount=2 -->
<PairSet index="0">
<!-- PairValueCount=2 -->
<PairValueRecord index="0">
<SecondGlyph value="A"/>
<Value1 XAdvance="0"/>
<Value2 XAdvance="0"/>
</PairValueRecord>
<PairValueRecord index="1">
<SecondGlyph value="B"/>
<Value1 XAdvance="0"/>
<Value2 XAdvance="0"/>
</PairValueRecord>
</PairSet>
<PairSet index="1">
<!-- PairValueCount=2 -->
<PairValueRecord index="0">
<SecondGlyph value="A"/>
<Value1 XAdvance="0"/>
<Value2 XAdvance="0"/>
</PairValueRecord>
<PairValueRecord index="1">
<SecondGlyph value="B"/>
<Value1 XAdvance="0"/>
<Value2 XAdvance="0"/>
</PairValueRecord>
</PairSet>
</PairPos>
</Lookup>
</LookupList>
</GPOS>
</ttFont>

View File

@ -0,0 +1,9 @@
# For PairPos statements in vertical compilation contexts,
# zero values should get compiled to ValueRecord format 8.
# https://github.com/fonttools/fonttools/issues/633
feature vkrn {
pos A 0 A 0;
pos A 0 B <0 0 0 0>;
pos B <0 0 0 0> A 0;
pos B <0 0 0 0> B <0 0 0 0>;
} vkrn;

View File

@ -0,0 +1,75 @@
<?xml version="1.0" encoding="UTF-8"?>
<ttFont sfntVersion="true" ttLibVersion="3.0">
<GPOS>
<Version value="0x00010000"/>
<ScriptList>
<!-- ScriptCount=1 -->
<ScriptRecord index="0">
<ScriptTag value="DFLT"/>
<Script>
<DefaultLangSys>
<ReqFeatureIndex value="65535"/>
<!-- FeatureCount=1 -->
<FeatureIndex index="0" value="0"/>
</DefaultLangSys>
<!-- LangSysCount=0 -->
</Script>
</ScriptRecord>
</ScriptList>
<FeatureList>
<!-- FeatureCount=1 -->
<FeatureRecord index="0">
<FeatureTag value="vkrn"/>
<Feature>
<!-- LookupCount=1 -->
<LookupListIndex index="0" value="0"/>
</Feature>
</FeatureRecord>
</FeatureList>
<LookupList>
<!-- LookupCount=1 -->
<Lookup index="0">
<LookupType value="2"/>
<LookupFlag value="0"/>
<!-- SubTableCount=1 -->
<PairPos index="0" Format="1">
<Coverage>
<Glyph value="A"/>
<Glyph value="B"/>
</Coverage>
<ValueFormat1 value="8"/>
<ValueFormat2 value="8"/>
<!-- PairSetCount=2 -->
<PairSet index="0">
<!-- PairValueCount=2 -->
<PairValueRecord index="0">
<SecondGlyph value="A"/>
<Value1 YAdvance="0"/>
<Value2 YAdvance="0"/>
</PairValueRecord>
<PairValueRecord index="1">
<SecondGlyph value="B"/>
<Value1 YAdvance="0"/>
<Value2 YAdvance="0"/>
</PairValueRecord>
</PairSet>
<PairSet index="1">
<!-- PairValueCount=2 -->
<PairValueRecord index="0">
<SecondGlyph value="A"/>
<Value1 YAdvance="0"/>
<Value2 YAdvance="0"/>
</PairValueRecord>
<PairValueRecord index="1">
<SecondGlyph value="B"/>
<Value1 YAdvance="0"/>
<Value2 YAdvance="0"/>
</PairValueRecord>
</PairSet>
</PairPos>
</Lookup>
</LookupList>
</GPOS>
</ttFont>