[feaLib] Emit SinglePos (GPOS type 1) in format 2 when this is more compact
This commit is contained in:
parent
f129f658c9
commit
117683680e
@ -600,20 +600,56 @@ class SinglePosBuilder(LookupBuilder):
|
|||||||
for glyphs in values.values():
|
for glyphs in values.values():
|
||||||
glyphs.sort(key=self.font.getGlyphID)
|
glyphs.sort(key=self.font.getGlyphID)
|
||||||
|
|
||||||
|
# Make a list of (glyphs, (otBase.ValueRecord, int valueFormat)).
|
||||||
|
# Glyphs with the same otBase.ValueRecord are grouped into one item.
|
||||||
|
values = [(glyphs, makeOpenTypeValueRecord(valrec))
|
||||||
|
for valrec, glyphs in values.items()]
|
||||||
|
|
||||||
|
# Find out which glyphs should be encoded as SinglePos format 2.
|
||||||
|
# Format 2 is more compact than format 1 when multiple glyphs
|
||||||
|
# have different values but share the same integer valueFormat.
|
||||||
|
format2 = {} # valueFormat --> [(glyph, value), (glyph, value), ...]
|
||||||
|
for glyphs, (value, valueFormat) in values:
|
||||||
|
if len(glyphs) == 1:
|
||||||
|
glyph = glyphs[0]
|
||||||
|
format2.setdefault(valueFormat, []).append((glyph, value))
|
||||||
|
|
||||||
|
# Only use format 2 if multiple glyphs share the same valueFormat.
|
||||||
|
# Otherwise, format 1 is more compact.
|
||||||
|
format2 = [(valueFormat, valueList)
|
||||||
|
for valueFormat, valueList in format2.items()
|
||||||
|
if len(valueList) > 1]
|
||||||
|
format2.sort()
|
||||||
|
format2Glyphs = set() # {"A", "B", "C"}
|
||||||
|
for _, valueList in format2:
|
||||||
|
for (glyph, _) in valueList:
|
||||||
|
format2Glyphs.add(glyph)
|
||||||
|
for valueFormat, valueList in format2:
|
||||||
|
valueList.sort(key=lambda x: self.font.getGlyphID(x[0]))
|
||||||
|
st = otTables.SinglePos()
|
||||||
|
subtables.append(st)
|
||||||
|
st.Format = 2
|
||||||
|
st.ValueFormat = valueFormat
|
||||||
|
st.Coverage = otTables.Coverage()
|
||||||
|
st.Coverage.glyphs = [glyph for glyph, _value in valueList]
|
||||||
|
st.ValueCount = len(valueList)
|
||||||
|
st.Value = [value for _glyph, value in valueList]
|
||||||
|
|
||||||
# To make the ordering of our subtables deterministic,
|
# To make the ordering of our subtables deterministic,
|
||||||
# we sort subtables by the first glyph ID in their coverage.
|
# we sort subtables by the first glyph ID in their coverage.
|
||||||
# Not doing this would be OK for OpenType, but testing the
|
# Not doing this would be OK for OpenType, but testing the
|
||||||
# compiler would be harder with non-deterministic output.
|
# compiler would be harder with non-deterministic output.
|
||||||
values = list(values.items())
|
values.sort(key=lambda x: self.font.getGlyphID(x[0][0]))
|
||||||
values.sort(key=lambda x: self.font.getGlyphID(x[1][0]))
|
|
||||||
|
|
||||||
for valrec, glyphs in values:
|
for glyphs, (value, valueFormat) in values:
|
||||||
|
if len(glyphs) == 1 and glyphs[0] in format2Glyphs:
|
||||||
|
continue # already emitted as part of a format 2 subtable
|
||||||
st = otTables.SinglePos()
|
st = otTables.SinglePos()
|
||||||
subtables.append(st)
|
subtables.append(st)
|
||||||
st.Format = 1
|
st.Format = 1
|
||||||
st.Coverage = otTables.Coverage()
|
st.Coverage = otTables.Coverage()
|
||||||
st.Coverage.glyphs = glyphs
|
st.Coverage.glyphs = glyphs
|
||||||
st.Value, st.ValueFormat = makeOpenTypeValueRecord(valrec)
|
st.Value, st.ValueFormat = value, valueFormat
|
||||||
|
|
||||||
lookup = otTables.Lookup()
|
lookup = otTables.Lookup()
|
||||||
lookup.SubTable = subtables
|
lookup.SubTable = subtables
|
||||||
|
8
Lib/fontTools/feaLib/testdata/GPOS_1.fea
vendored
8
Lib/fontTools/feaLib/testdata/GPOS_1.fea
vendored
@ -20,10 +20,18 @@ feature kern {
|
|||||||
<device 11 -8, 14 7> <device 13 8, 15 1>
|
<device 11 -8, 14 7> <device 13 8, 15 1>
|
||||||
>;
|
>;
|
||||||
position four 400;
|
position four 400;
|
||||||
|
position four.oldstyle 401;
|
||||||
position five <-80 0 -160 0>;
|
position five <-80 0 -160 0>;
|
||||||
position six -200;
|
position six -200;
|
||||||
position @sevenEightNine -100;
|
position @sevenEightNine -100;
|
||||||
|
|
||||||
|
pos P <1 0 800 0>;
|
||||||
|
pos Q <1 0 801 0>;
|
||||||
|
pos R <1 0 802 0>;
|
||||||
|
pos S <1 1 803 0>;
|
||||||
|
pos T <1 1 804 0>;
|
||||||
|
pos U <1 1 805 0>;
|
||||||
|
|
||||||
# The AFDKO makeotf tool accepts re-definitions of previously defined
|
# The AFDKO makeotf tool accepts re-definitions of previously defined
|
||||||
# single adjustment positionings, provided the re-definition is using
|
# single adjustment positionings, provided the re-definition is using
|
||||||
# the same value. We replicate this behavior.
|
# the same value. We replicate this behavior.
|
||||||
|
60
Lib/fontTools/feaLib/testdata/GPOS_1.ttx
vendored
60
Lib/fontTools/feaLib/testdata/GPOS_1.ttx
vendored
@ -53,8 +53,44 @@
|
|||||||
<Lookup index="0">
|
<Lookup index="0">
|
||||||
<!-- LookupType=1 -->
|
<!-- LookupType=1 -->
|
||||||
<LookupFlag value="0"/>
|
<LookupFlag value="0"/>
|
||||||
<!-- SubTableCount=6 -->
|
<!-- SubTableCount=7 -->
|
||||||
<SinglePos index="0" Format="1">
|
<SinglePos index="0" Format="2">
|
||||||
|
<Coverage>
|
||||||
|
<Glyph value="four"/>
|
||||||
|
<Glyph value="six"/>
|
||||||
|
<Glyph value="four.oldstyle"/>
|
||||||
|
</Coverage>
|
||||||
|
<ValueFormat value="4"/>
|
||||||
|
<!-- ValueCount=3 -->
|
||||||
|
<Value index="0" XAdvance="400"/>
|
||||||
|
<Value index="1" XAdvance="-200"/>
|
||||||
|
<Value index="2" XAdvance="401"/>
|
||||||
|
</SinglePos>
|
||||||
|
<SinglePos index="1" Format="2">
|
||||||
|
<Coverage>
|
||||||
|
<Glyph value="P"/>
|
||||||
|
<Glyph value="Q"/>
|
||||||
|
<Glyph value="R"/>
|
||||||
|
</Coverage>
|
||||||
|
<ValueFormat value="5"/>
|
||||||
|
<!-- ValueCount=3 -->
|
||||||
|
<Value index="0" XPlacement="1" XAdvance="800"/>
|
||||||
|
<Value index="1" XPlacement="1" XAdvance="801"/>
|
||||||
|
<Value index="2" XPlacement="1" XAdvance="802"/>
|
||||||
|
</SinglePos>
|
||||||
|
<SinglePos index="2" Format="2">
|
||||||
|
<Coverage>
|
||||||
|
<Glyph value="S"/>
|
||||||
|
<Glyph value="T"/>
|
||||||
|
<Glyph value="U"/>
|
||||||
|
</Coverage>
|
||||||
|
<ValueFormat value="7"/>
|
||||||
|
<!-- ValueCount=3 -->
|
||||||
|
<Value index="0" XPlacement="1" YPlacement="1" XAdvance="803"/>
|
||||||
|
<Value index="1" XPlacement="1" YPlacement="1" XAdvance="804"/>
|
||||||
|
<Value index="2" XPlacement="1" YPlacement="1" XAdvance="805"/>
|
||||||
|
</SinglePos>
|
||||||
|
<SinglePos index="3" Format="1">
|
||||||
<Coverage>
|
<Coverage>
|
||||||
<Glyph value="one"/>
|
<Glyph value="one"/>
|
||||||
<Glyph value="two"/>
|
<Glyph value="two"/>
|
||||||
@ -64,21 +100,7 @@
|
|||||||
<ValueFormat value="5"/>
|
<ValueFormat value="5"/>
|
||||||
<Value XPlacement="-80" XAdvance="-160"/>
|
<Value XPlacement="-80" XAdvance="-160"/>
|
||||||
</SinglePos>
|
</SinglePos>
|
||||||
<SinglePos index="1" Format="1">
|
<SinglePos index="4" Format="1">
|
||||||
<Coverage>
|
|
||||||
<Glyph value="four"/>
|
|
||||||
</Coverage>
|
|
||||||
<ValueFormat value="4"/>
|
|
||||||
<Value XAdvance="400"/>
|
|
||||||
</SinglePos>
|
|
||||||
<SinglePos index="2" Format="1">
|
|
||||||
<Coverage>
|
|
||||||
<Glyph value="six"/>
|
|
||||||
</Coverage>
|
|
||||||
<ValueFormat value="4"/>
|
|
||||||
<Value XAdvance="-200"/>
|
|
||||||
</SinglePos>
|
|
||||||
<SinglePos index="3" Format="1">
|
|
||||||
<Coverage>
|
<Coverage>
|
||||||
<Glyph value="seven"/>
|
<Glyph value="seven"/>
|
||||||
<Glyph value="eight"/>
|
<Glyph value="eight"/>
|
||||||
@ -87,7 +109,7 @@
|
|||||||
<ValueFormat value="4"/>
|
<ValueFormat value="4"/>
|
||||||
<Value XAdvance="-100"/>
|
<Value XAdvance="-100"/>
|
||||||
</SinglePos>
|
</SinglePos>
|
||||||
<SinglePos index="4" Format="1">
|
<SinglePos index="5" Format="1">
|
||||||
<Coverage>
|
<Coverage>
|
||||||
<Glyph value="A"/>
|
<Glyph value="A"/>
|
||||||
<Glyph value="B"/>
|
<Glyph value="B"/>
|
||||||
@ -114,7 +136,7 @@
|
|||||||
</XAdvDevice>
|
</XAdvDevice>
|
||||||
</Value>
|
</Value>
|
||||||
</SinglePos>
|
</SinglePos>
|
||||||
<SinglePos index="5" Format="1">
|
<SinglePos index="6" Format="1">
|
||||||
<Coverage>
|
<Coverage>
|
||||||
<Glyph value="C"/>
|
<Glyph value="C"/>
|
||||||
</Coverage>
|
</Coverage>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user