[otlLib] Move building of MarkLigPos from feaLib to otlLib

This commit is contained in:
Sascha Brawer 2016-01-22 14:50:17 +01:00
parent 036e2ce497
commit af48e43371
3 changed files with 129 additions and 13 deletions

View File

@ -984,7 +984,6 @@ class MarkLigPosBuilder(LookupBuilder):
def build(self): def build(self):
markClasses = self.buildMarkClasses_(self.marks) markClasses = self.buildMarkClasses_(self.marks)
markClassList = sorted(markClasses.keys(), key=markClasses.get)
marks = {mark: (markClasses[mc], anchor) marks = {mark: (markClasses[mc], anchor)
for mark, (mc, anchor) in self.marks.items()} for mark, (mc, anchor) in self.marks.items()}
ligs = {} ligs = {}
@ -992,16 +991,8 @@ class MarkLigPosBuilder(LookupBuilder):
ligs[lig] = [] ligs[lig] = []
for c in components: for c in components:
ligs[lig].append({markClasses[mc]: a for mc, a in c.items()}) ligs[lig].append({markClasses[mc]: a for mc, a in c.items()})
subtables = otl.buildMarkLigPos(marks, ligs, self.glyphMap)
st = otTables.MarkLigPos() return self.buildLookup_(subtables)
st.Format = 1
st.MarkCoverage = otl.buildCoverage(marks, self.glyphMap)
st.MarkArray = otl.buildMarkArray(marks, self.glyphMap)
st.ClassCount = max([mc for mc, _ in marks.values()]) + 1
st.LigatureCoverage = otl.buildCoverage(ligs, self.glyphMap)
st.LigatureArray = \
otl.buildLigatureArray(ligs, st.ClassCount, self.glyphMap)
return self.buildLookup_([st])
class MarkMarkPosBuilder(LookupBuilder): class MarkMarkPosBuilder(LookupBuilder):

View File

@ -211,7 +211,7 @@ def buildMarkArray(marks, glyphMap):
def buildMarkBasePos(marks, bases, glyphMap): def buildMarkBasePos(marks, bases, glyphMap):
"""Build a list of MarkBasePos subtables. """Build a list of MarkBasePos subtables.
a1, a2, a3, a4 = buildAnchor(500, 100), ... a1, a2, a3, a4, a5 = buildAnchor(500, 100), ...
marks = {"acute": (0, a1), "grave": (0, a1), "cedilla": (1, a2)} marks = {"acute": (0, a1), "grave": (0, a1), "cedilla": (1, a2)}
bases = {"a": {0: a3, 1: a5}, "b": {0: a4, 1: a5}} bases = {"a": {0: a3, 1: a5}, "b": {0: a4, 1: a5}}
""" """
@ -232,7 +232,7 @@ def buildMarkBasePos(marks, bases, glyphMap):
def buildMarkBasePosSubtable(marks, bases, glyphMap): def buildMarkBasePosSubtable(marks, bases, glyphMap):
"""Build a single MarkBasePos subtable. """Build a single MarkBasePos subtable.
a1, a2, a3, a4 = buildAnchor(500, 100), ... a1, a2, a3, a4, a5 = buildAnchor(500, 100), ...
marks = {"acute": (0, a1), "grave": (0, a1), "cedilla": (1, a2)} marks = {"acute": (0, a1), "grave": (0, a1), "cedilla": (1, a2)}
bases = {"a": {0: a3, 1: a5}, "b": {0: a4, 1: a5}} bases = {"a": {0: a3, 1: a5}, "b": {0: a4, 1: a5}}
""" """
@ -246,6 +246,37 @@ def buildMarkBasePosSubtable(marks, bases, glyphMap):
return self return self
def buildMarkLigPos(marks, ligs, glyphMap):
"""Build a list of MarkLigPos subtables.
a1, a2, a3, a4, a5 = buildAnchor(500, 100), ...
marks = {"acute": (0, a1), "grave": (0, a1), "cedilla": (1, a2)}
ligs = {"f_i": [{0: a3, 1: a5}, {0: a4, 1: a5}], "c_t": [{...}, {...}]}
"""
# TODO: Consider splitting into multiple subtables to save space,
# as with MarkBasePos, this would be a trade-off that would need
# profiling. And, depending on how typical fonts are structured,
# it might not be worth doing at all.
return [buildMarkLigPosSubtable(marks, ligs, glyphMap)]
def buildMarkLigPosSubtable(marks, ligs, glyphMap):
"""Build a single MarkLigPos subtable.
a1, a2, a3, a4, a5 = buildAnchor(500, 100), ...
marks = {"acute": (0, a1), "grave": (0, a1), "cedilla": (1, a2)}
ligs = {"f_i": [{0: a3, 1: a5}, {0: a4, 1: a5}], "c_t": [{...}, {...}]}
"""
self = ot.MarkLigPos()
self.Format = 1
self.MarkCoverage = buildCoverage(marks, glyphMap)
self.MarkArray = buildMarkArray(marks, glyphMap)
self.ClassCount = max([mc for mc, _ in marks.values()]) + 1
self.LigatureCoverage = buildCoverage(ligs, glyphMap)
self.LigatureArray = buildLigatureArray(ligs, self.ClassCount, glyphMap)
return self
def buildMarkRecord(classID, anchor): def buildMarkRecord(classID, anchor):
assert isinstance(classID, int) assert isinstance(classID, int)
assert isinstance(anchor, ot.Anchor) assert isinstance(anchor, ot.Anchor)

View File

@ -632,6 +632,100 @@ class BuilderTest(unittest.TestCase):
def test_buildMarkGlyphSetsDef_None(self): def test_buildMarkGlyphSetsDef_None(self):
self.assertIsNone(builder.buildMarkGlyphSetsDef(None, self.GLYPHMAP)) self.assertIsNone(builder.buildMarkGlyphSetsDef(None, self.GLYPHMAP))
def test_buildMarkLigPosSubtable(self):
anchor = builder.buildAnchor
marks = {
"acute": (0, anchor(300, 700)),
"cedilla": (1, anchor(300, -100)),
"grave": (0, anchor(300, 700))
}
bases = {
"f_i": [{}, {0: anchor(200, 400)}], # nothing on f; only 1 on i
"c_t": [
{0: anchor(500, 600), 1: anchor(500, -20)}, # c
{0: anchor(1300, 800), 1: anchor(1300, -20)} # t
]
}
table = builder.buildMarkLigPosSubtable(marks, bases, self.GLYPHMAP)
self.maxDiff = None
self.assertEqual(getXML(table.toXML),
'<MarkLigPos Format="1">'
' <MarkCoverage>'
' <Glyph value="grave"/>'
' <Glyph value="acute"/>'
' <Glyph value="cedilla"/>'
' </MarkCoverage>'
' <LigatureCoverage>'
' <Glyph value="f_i"/>'
' <Glyph value="c_t"/>'
' </LigatureCoverage>'
' <!-- ClassCount=2 -->'
' <MarkArray>'
' <!-- MarkCount=3 -->'
' <MarkRecord index="0">'
' <Class value="0"/>'
' <MarkAnchor Format="1">'
' <XCoordinate value="300"/>'
' <YCoordinate value="700"/>'
' </MarkAnchor>'
' </MarkRecord>'
' <MarkRecord index="1">'
' <Class value="0"/>'
' <MarkAnchor Format="1">'
' <XCoordinate value="300"/>'
' <YCoordinate value="700"/>'
' </MarkAnchor>'
' </MarkRecord>'
' <MarkRecord index="2">'
' <Class value="1"/>'
' <MarkAnchor Format="1">'
' <XCoordinate value="300"/>'
' <YCoordinate value="-100"/>'
' </MarkAnchor>'
' </MarkRecord>'
' </MarkArray>'
' <LigatureArray>'
' <!-- LigatureCount=2 -->'
' <LigatureAttach index="0">'
' <!-- ComponentCount=2 -->'
' <ComponentRecord index="0">'
' <LigatureAnchor index="0" empty="1"/>'
' <LigatureAnchor index="1" empty="1"/>'
' </ComponentRecord>'
' <ComponentRecord index="1">'
' <LigatureAnchor index="0" Format="1">'
' <XCoordinate value="200"/>'
' <YCoordinate value="400"/>'
' </LigatureAnchor>'
' <LigatureAnchor index="1" empty="1"/>'
' </ComponentRecord>'
' </LigatureAttach>'
' <LigatureAttach index="1">'
' <!-- ComponentCount=2 -->'
' <ComponentRecord index="0">'
' <LigatureAnchor index="0" Format="1">'
' <XCoordinate value="500"/>'
' <YCoordinate value="600"/>'
' </LigatureAnchor>'
' <LigatureAnchor index="1" Format="1">'
' <XCoordinate value="500"/>'
' <YCoordinate value="-20"/>'
' </LigatureAnchor>'
' </ComponentRecord>'
' <ComponentRecord index="1">'
' <LigatureAnchor index="0" Format="1">'
' <XCoordinate value="1300"/>'
' <YCoordinate value="800"/>'
' </LigatureAnchor>'
' <LigatureAnchor index="1" Format="1">'
' <XCoordinate value="1300"/>'
' <YCoordinate value="-20"/>'
' </LigatureAnchor>'
' </ComponentRecord>'
' </LigatureAttach>'
' </LigatureArray>'
'</MarkLigPos>')
def test_buildMarkRecord(self): def test_buildMarkRecord(self):
rec = builder.buildMarkRecord(17, builder.buildAnchor(500, -20)) rec = builder.buildMarkRecord(17, builder.buildAnchor(500, -20))
self.assertEqual(getXML(rec.toXML), self.assertEqual(getXML(rec.toXML),