[otlLib] Implement otlLib.getSinglePosSubtable()

https://github.com/behdad/fonttools/issues/468
This commit is contained in:
Sascha Brawer 2016-01-19 15:38:33 +01:00
parent 6ea91c9e7a
commit ce7cc432f2
2 changed files with 56 additions and 24 deletions

View File

@ -134,9 +134,8 @@ def buildSinglePos(mapping, glyphMap):
# a SinglePos format 1 subtable; that is the most compact form. # a SinglePos format 1 subtable; that is the most compact form.
for key, glyphs in coverages.items(): for key, glyphs in coverages.items():
if len(glyphs) > 1: if len(glyphs) > 1:
valueFormat, value = key[0], values[key] format1Mapping = {g: values[key] for g in glyphs}
result.append(_buildSinglePosFormat1( result.append(buildSinglePosSubtable(format1Mapping, glyphMap))
valueFormat, glyphs, value, glyphMap))
handled.add(key) handled.add(key)
# In the remaining ValueRecords, look for those whose valueFormat # In the remaining ValueRecords, look for those whose valueFormat
@ -146,8 +145,7 @@ def buildSinglePos(mapping, glyphMap):
f2 = [k for k in keys if k not in handled] f2 = [k for k in keys if k not in handled]
if len(f2) > 1: if len(f2) > 1:
format2Mapping = {coverages[k][0]: values[k] for k in f2} format2Mapping = {coverages[k][0]: values[k] for k in f2}
result.append(_buildSinglePosFormat2( result.append(buildSinglePosSubtable(format2Mapping, glyphMap))
valueFormat, format2Mapping, glyphMap))
handled.update(f2) handled.update(f2)
# The remaining ValueRecords are singletons in the sense that # The remaining ValueRecords are singletons in the sense that
@ -155,9 +153,9 @@ def buildSinglePos(mapping, glyphMap):
# is unique as well. We encode these in format 1 again. # is unique as well. We encode these in format 1 again.
for key, glyphs in coverages.items(): for key, glyphs in coverages.items():
if key not in handled: if key not in handled:
valueFormat, value = key[0], values[key] assert len(glyphs) == 1, glyphs
result.append(_buildSinglePosFormat1( st = buildSinglePosSubtable({glyphs[0]: values[key]}, glyphMap)
valueFormat, glyphs, value, glyphMap)) result.append(st)
# When the OpenType layout engine traverses the subtables, it will # When the OpenType layout engine traverses the subtables, it will
# stop after the first matching subtable. Therefore, we sort the # stop after the first matching subtable. Therefore, we sort the
@ -171,20 +169,22 @@ def buildSinglePos(mapping, glyphMap):
return result return result
def _buildSinglePosFormat1(valueFormat, glyphs, value, glyphMap): def buildSinglePosSubtable(values, glyphMap):
t = ot.SinglePos() """{glyphName: otBase.ValueRecord} --> otTables.SinglePos"""
t.Format, t.ValueFormat, t.Value = 1, valueFormat, value self = ot.SinglePos()
t.Coverage = buildCoverage(glyphs, glyphMap) self.Coverage = buildCoverage(values.keys(), glyphMap)
return t valueRecords = [values[g] for g in self.Coverage.glyphs]
self.ValueFormat = 0
for v in valueRecords:
def _buildSinglePosFormat2(valueFormat, mapping, glyphMap): self.ValueFormat |= v.getFormat()
t = ot.SinglePos() if all(v == valueRecords[0] for v in valueRecords):
t.Format, t.ValueFormat = 2, valueFormat self.Format = 1
t.Coverage = buildCoverage(mapping.keys(), glyphMap) self.Value = valueRecords[0]
t.Value = [mapping[g] for g in t.Coverage.glyphs] else:
t.ValueCount = len(t.Value) self.Format = 2
return t self.Value = valueRecords
self.ValueCount = len(self.Value)
return self
def _getSinglePosTableKey(subtable, glyphMap): def _getSinglePosTableKey(subtable, glyphMap):

View File

@ -125,7 +125,6 @@ class BuilderTest(unittest.TestCase):
'</Device>') '</Device>')
def test_buildSinglePos(self): def test_buildSinglePos(self):
self.maxDiff = None
subtables = builder.buildSinglePos({ subtables = builder.buildSinglePos({
"one": builder.buildValue({"XPlacement": 500}), "one": builder.buildValue({"XPlacement": 500}),
"two": builder.buildValue({"XPlacement": 500}), "two": builder.buildValue({"XPlacement": 500}),
@ -134,7 +133,7 @@ class BuilderTest(unittest.TestCase):
"five": builder.buildValue({"XPlacement": 500}), "five": builder.buildValue({"XPlacement": 500}),
"six": builder.buildValue({"YPlacement": -6}), "six": builder.buildValue({"YPlacement": -6}),
}, self.GLYPHMAP) }, self.GLYPHMAP)
self.assertEqual(''.join([getXML(t.toXML) for t in subtables[:3]]), self.assertEqual(''.join([getXML(t.toXML) for t in subtables]),
'<SinglePos Format="1">' '<SinglePos Format="1">'
' <Coverage>' ' <Coverage>'
' <Glyph value="one"/>' ' <Glyph value="one"/>'
@ -162,6 +161,39 @@ class BuilderTest(unittest.TestCase):
' <Value YPlacement="-6"/>' ' <Value YPlacement="-6"/>'
'</SinglePos>') '</SinglePos>')
def test_buildSinglePosSubtable_format1(self):
subtable = builder.buildSinglePosSubtable({
"one": builder.buildValue({"XPlacement": 777}),
"two": builder.buildValue({"XPlacement": 777}),
}, self.GLYPHMAP)
self.assertEqual(getXML(subtable.toXML),
'<SinglePos Format="1">'
' <Coverage>'
' <Glyph value="one"/>'
' <Glyph value="two"/>'
' </Coverage>'
' <ValueFormat value="1"/>'
' <Value XPlacement="777"/>'
'</SinglePos>')
def test_buildSinglePosSubtable_format2(self):
subtable = builder.buildSinglePosSubtable({
"one": builder.buildValue({"XPlacement": 777}),
"two": builder.buildValue({"YPlacement": -888}),
}, self.GLYPHMAP)
self.maxDiff = None
self.assertEqual(getXML(subtable.toXML),
'<SinglePos Format="2">'
' <Coverage>'
' <Glyph value="one"/>'
' <Glyph value="two"/>'
' </Coverage>'
' <ValueFormat value="3"/>'
' <!-- ValueCount=2 -->'
' <Value index="0" XPlacement="777"/>'
' <Value index="1" YPlacement="-888"/>'
'</SinglePos>')
def test_buildValue(self): def test_buildValue(self):
value = builder.buildValue({"XPlacement": 7, "YPlacement": 23}) value = builder.buildValue({"XPlacement": 7, "YPlacement": 23})
func = lambda writer, font: value.toXML(writer, font, valueName="Val") func = lambda writer, font: value.toXML(writer, font, valueName="Val")