diff --git a/Lib/fontTools/ttLib/tables/otTables.py b/Lib/fontTools/ttLib/tables/otTables.py index aca3b6d76..13f0881f1 100644 --- a/Lib/fontTools/ttLib/tables/otTables.py +++ b/Lib/fontTools/ttLib/tables/otTables.py @@ -317,6 +317,107 @@ class LigatureMorphAction(AATAction): xmlWriter.newline() +class InsertionMorphAction(AATAction): + staticSize = 8 + + _FLAGS = ["SetMark", "DontAdvance", + "CurrentIsKashidaLike", "MarkedIsKashidaLike", + "CurrentInsertBefore", "MarkedInsertBefore"] + + def __init__(self): + self.NewState = 0 + for flag in self._FLAGS: + setattr(self, flag, False) + self.ReservedFlags = 0 + self.CurrentInsertionAction, self.MarkedInsertionAction = [], [] + + def compile(self, writer, font, actionIndex): + assert actionIndex is not None + writer.writeUShort(self.NewState) + flags = self.ReservedFlags + if self.SetMark: flags |= 0x8000 + if self.DontAdvance: flags |= 0x4000 + if self.CurrentIsKashidaLike: flags |= 0x2000 + if self.MarkedIsKashidaLike: flags |= 0x1000 + if self.CurrentInsertBefore: flags |= 0x0800 + if self.MarkedInsertBefore: flags |= 0x0400 + flags |= len(self.CurrentInsertionAction) << 5 + flags |= len(self.MarkedInsertionAction) + writer.writeUShort(flags) + if len(self.CurrentInsertionAction) > 0: + currentIndex = actionIndex[ + tuple(self.CurrentInsertionAction)] + else: + currentIndex = 0xFFFF + writer.writeUShort(currentIndex) + if len(self.MarkedInsertionAction) > 0: + markedIndex = actionIndex[ + tuple(self.MarkedInsertionAction)] + else: + markedIndex = 0xFFFF + writer.writeUShort(markedIndex) + + def decompile(self, reader, font, actionReader): + assert actionReader is not None + self.NewState = reader.readUShort() + flags = reader.readUShort() + self.SetMark = bool(flags & 0x8000) + self.DontAdvance = bool(flags & 0x4000) + self.CurrentIsKashidaLike = bool(flags & 0x2000) + self.MarkedIsKashidaLike = bool(flags & 0x1000) + self.CurrentInsertBefore = bool(flags & 0x0800) + self.MarkedInsertBefore = bool(flags & 0x0400) + self.CurrentInsertionAction = self._decompileInsertionAction( + actionReader, font, + index=reader.readUShort(), + count=((flags & 0x03E0) >> 5)) + self.MarkedInsertionAction = self._decompileInsertionAction( + actionReader, font, + index=reader.readUShort(), + count=(flags & 0x001F)) + + def _decompileInsertionAction(self, actionReader, font, index, count): + if index == 0xFFFF or count == 0: + return [] + reader = actionReader.getSubReader( + actionReader.pos + index * 2) + return [font.getGlyphName(glyphID) + for glyphID in reader.readUShortArray(count)] + + def toXML(self, xmlWriter, font, attrs, name): + xmlWriter.begintag(name, **attrs) + xmlWriter.newline() + xmlWriter.simpletag("NewState", value=self.NewState) + xmlWriter.newline() + self._writeFlagsToXML(xmlWriter) + for g in self.CurrentInsertionAction: + xmlWriter.simpletag("CurrentInsertionAction", glyph=g) + xmlWriter.newline() + for g in self.MarkedInsertionAction: + xmlWriter.simpletag("MarkedInsertionAction", glyph=g) + xmlWriter.newline() + xmlWriter.endtag(name) + xmlWriter.newline() + + def fromXML(self, name, attrs, content, font): + self.__init__() + content = [t for t in content if isinstance(t, tuple)] + for eltName, eltAttrs, eltContent in content: + if eltName == "NewState": + self.NewState = safeEval(eltAttrs["value"]) + elif eltName == "Flags": + for flag in eltAttrs["value"].split(","): + self._setFlag(flag.strip()) + elif eltName == "CurrentInsertionAction": + self.CurrentInsertionAction.append( + eltAttrs["glyph"]) + elif eltName == "MarkedInsertionAction": + self.MarkedInsertionAction.append( + eltAttrs["glyph"]) + else: + assert False, eltName + + class FeatureParams(BaseTable): def compile(self, writer, font): diff --git a/Tests/ttLib/tables/otTables_test.py b/Tests/ttLib/tables/otTables_test.py index 369b02be4..05aabb489 100644 --- a/Tests/ttLib/tables/otTables_test.py +++ b/Tests/ttLib/tables/otTables_test.py @@ -448,6 +448,43 @@ class LigatureMorphActionTest(unittest.TestCase): ]) +class InsertionMorphActionTest(unittest.TestCase): + MORPH_ACTION_XML = [ + '', + ' ', # 0x1234 = 4660 + ' ', + ' ', + ' ', + ' ', + ' ', + ' ', + '' + ] + + def setUp(self): + self.font = FakeFont(['.notdef', 'A', 'B', 'C', 'D']) + self.maxDiff = None + + def testDecompileToXML(self): + a = otTables.InsertionMorphAction() + actionReader = OTTableReader( + deHexStr("DEAD BEEF 0002 0001 0004 0002 0003 DEAD BEEF")) + a.decompile(OTTableReader(deHexStr("1234 FC43 0005 0002")), + self.font, actionReader) + toXML = lambda w, f: a.toXML(w, f, {"Test": "Foo"}, "Transition") + self.assertEqual(getXML(toXML, self.font), self.MORPH_ACTION_XML) + + def testCompileFromXML(self): + a = otTables.InsertionMorphAction() + for name, attrs, content in parseXML(self.MORPH_ACTION_XML): + a.fromXML(name, attrs, content, self.font) + writer = OTTableWriter() + a.compile(writer, self.font, + actionIndex={('B', 'C'): 9, ('B', 'A', 'D'): 7}) + self.assertEqual(hexStr(writer.getAllData()), "1234fc4300090007") + + if __name__ == "__main__": import sys sys.exit(unittest.main())