Rebase morx branch to current master

This commit is contained in:
Sascha Brawer 2017-06-07 10:49:47 +02:00
parent 6eb807b55f
commit 483bb67b60
4 changed files with 202 additions and 2 deletions

View File

@ -0,0 +1,7 @@
from __future__ import print_function, division, absolute_import
from fontTools.misc.py23 import *
from .otBase import BaseTTXConverter
class table__m_o_r_x(BaseTTXConverter):
pass

View File

@ -604,6 +604,9 @@ class BaseTable(object):
table["ExtensionLookupType"])
if conv.name == "FeatureParams":
conv = conv.getConverter(reader["FeatureTag"])
if conv.name == "SubStruct":
conv = conv.getConverter(reader.globalState.tableType,
table["MorphType"])
if conv.repeat:
if conv.repeat in table:
countValue = table[conv.repeat]

View File

@ -23,13 +23,15 @@ def buildConverters(tableSpec, tableNamespace):
if name.startswith("ValueFormat"):
assert tp == "uint16"
converterClass = ValueFormat
elif name.endswith("Count"):
elif name.endswith("Count") or name == "MorphType":
assert tp in ("uint16", "uint32")
converterClass = ComputedUShort if tp == 'uint16' else ComputedULong
elif name == "SubTable":
converterClass = SubTable
elif name == "ExtSubTable":
converterClass = ExtSubTable
elif name == "SubStruct":
converterClass = SubStruct
elif name == "FeatureParams":
converterClass = FeatureParams
else:
@ -43,7 +45,7 @@ def buildConverters(tableSpec, tableNamespace):
conv = converterClass(name, repeat, aux, tableClass=tableClass)
else:
conv = converterClass(name, repeat, aux)
if name in ["SubTable", "ExtSubTable"]:
if name in ["SubTable", "ExtSubTable", "SubStruct"]:
conv.lookupTypes = tableNamespace['lookupTypes']
# also create reverse mapping
for t in conv.lookupTypes.values():
@ -170,6 +172,11 @@ class ULong(IntValue):
def write(self, writer, font, tableDict, value, repeatIndex=None):
writer.writeULong(value)
class Flags32(ULong):
def xmlWrite(self, xmlWriter, font, value, name, attrs):
xmlWriter.simpletag(name, attrs + [("value", "0x%08X" % value)])
xmlWriter.newline()
class Short(IntValue):
staticSize = 2
def read(self, reader, font, tableDict):
@ -409,6 +416,25 @@ class Struct(BaseConverter):
return "Struct of " + repr(self.tableClass)
class StructWithLength(Struct):
def read(self, reader, font, tableDict):
pos = reader.pos
table = self.tableClass()
table.decompile(reader, font)
reader.seek(pos + table.StructLength)
return table
def write(self, writer, font, tableDict, value, repeatIndex=None):
value.compile(writer, font)
assert 0, "Fix length"
class SubStruct(Struct):
def getConverter(self, tableType, lookupType):
tableClass = self.lookupTypes[tableType][lookupType]
return self.__class__(self.name, self.repeat, self.aux, tableClass)
class Table(Struct):
longOffset = False
@ -511,6 +537,88 @@ class ValueRecord(ValueFormat):
return value
class AATLookup(BaseConverter):
def read(self, reader, font, tableDict):
format = reader.readUShort()
if format == 0:
glyphs = font.getGlyphOrder()
mapping = self.readFormat0(reader, len(glyphs))
elif format == 2:
mapping = self.readFormat2(reader)
elif format == 4:
mapping = self.readFormat4(reader)
elif format == 6:
mapping = self.readFormat6(reader)
elif format == 8:
mapping = self.readFormat8(reader)
else:
assert False, "unsupported lookup format: %d" % format
return {font.getGlyphName(k):font.getGlyphName(v)
for k, v in mapping.items() if k != v}
def readFormat0(self, reader, numGlyphs):
data = reader.readUShortArray(numGlyphs)
return {k:v for (k,v) in enumerate(data)}
def readFormat2(self, reader):
mapping = {}
pos = reader.pos - 2 # start of table is at UShort for format
size = reader.readUShort()
assert size == 6, size
for i in range(reader.readUShort()):
reader.seek(pos + i * size + 12)
last = reader.readUShort()
first = reader.readUShort()
value = reader.readUShort()
if last != 0xFFFF:
for k in range(first, last + 1):
mapping[k] = value
return mapping
def readFormat4(self, reader):
mapping = {}
pos = reader.pos - 2 # start of table is at UShort for format
size = reader.readUShort()
assert size == 6, size
for i in range(reader.readUShort()):
reader.seek(pos + i * size + 12)
last = reader.readUShort()
first = reader.readUShort()
offset = reader.readUShort()
if last != 0xFFFF:
dataReader = reader.getSubReader(pos + offset)
data = dataReader.readUShortArray(last - first + 1)
for k, v in enumerate(data):
mapping[first + k] = v
return mapping
def readFormat6(self, reader):
mapping = {}
pos = reader.pos - 2 # start of table is at UShort for format
size = reader.readUShort()
assert size == 4, size
for i in range(reader.readUShort()):
reader.seek(pos + i * size + 12)
glyph = reader.readUShort()
value = reader.readUShort()
if glyph != 0xFFFF:
mapping[glyph] = value
return mapping
def readFormat8(self, reader):
first = reader.readUShort()
count = reader.readUShort()
data = reader.readUShortArray(count)
return {(first + k):v for (k, v) in enumerate(data)}
def xmlWrite(self, xmlWriter, font, value, name, attrs):
items = sorted(value.items())
for inGlyph, outGlyph in items:
xmlWriter.simpletag("Substitution",
[("in", inGlyph), ("out", outGlyph)])
xmlWriter.newline()
class DeltaValue(BaseConverter):
def read(self, reader, font, tableDict):
@ -660,6 +768,7 @@ converterMapping = {
"uint24": UInt24,
"uint32": ULong,
"char64": Char64,
"Flags32": Flags32,
"Version": Version,
"Tag": Tag,
"GlyphID": GlyphID,
@ -674,6 +783,10 @@ converterMapping = {
"DeltaValue": DeltaValue,
"VarIdxMapValue": VarIdxMapValue,
"VarDataValue": VarDataValue,
# AAT
"AATLookup": AATLookup,
"MorphChain": StructWithLength,
"MorphSubtable":StructWithLength,
# "Template" types
"OffsetTo": lambda C: partial(Table, tableClass=C),
"LOffsetTo": lambda C: partial(LTable, tableClass=C),

View File

@ -174,6 +174,83 @@ class UInt8Test(unittest.TestCase):
self.assertEqual(xml, '<Foo attr="v" value="251"/>')
class AATLookupTest(unittest.TestCase):
font = FakeFont(".notdef A B C D E F G H".split())
converter = otConverters.AATLookup("AATLookup", 0, None, None)
def __init__(self, methodName):
unittest.TestCase.__init__(self, methodName)
# Python 3 renamed assertRaisesRegexp to assertRaisesRegex,
# and fires deprecation warnings if a program uses the old name.
if not hasattr(self, "assertRaisesRegex"):
self.assertRaisesRegex = self.assertRaisesRegexp
def test_readFormat0(self):
reader = OTTableReader(deHexStr("0000 0000 0001 0002 0000 7D00 0001"))
self.assertEqual(self.converter.read(reader, self.font, None), {
"C": ".notdef",
"D": "glyph32000",
"E": "A"
})
def test_readFormat2(self):
reader = OTTableReader(deHexStr(
"0002 0006 0003 000C 0001 0006 "
"0002 0001 0003 " # glyph A..B: map to C
"0007 0005 0008 " # glyph E..G: map to H
"FFFF FFFF FFFF")) # end of search table
self.assertEqual(self.converter.read(reader, self.font, None), {
"A": "C",
"B": "C",
"E": "H",
"F": "H",
"G": "H",
})
def test_readFormat4(self):
reader = OTTableReader(deHexStr(
"0004 0006 0003 000C 0001 0006 "
"0002 0001 001E " # glyph 1..2: mapping at offset 0x1E
"0005 0004 001E " # glyph 4..5: mapping at offset 0x1E
"FFFF FFFF FFFF " # end of search table
"0007 0008")) # offset 0x18: glyphs [7, 8] = [G, H]
self.assertEqual(self.converter.read(reader, self.font, None), {
"A": "G",
"B": "H",
"D": "G",
"E": "H",
})
def test_readFormat6(self):
reader = OTTableReader(deHexStr(
"0006 0004 0003 0008 0001 0004 "
"0003 0001 " # C --> A
"0005 0002 " # E --> B
"FFFF FFFF")) # end of search table
self.assertEqual(self.converter.read(reader, self.font, None), {
"C": "A",
"E": "B",
})
def test_readFormat8(self):
reader = OTTableReader(deHexStr(
"0008 "
"0003 0003 " # first: C, count: 3
"0007 0001 0002")) # [G, A, B]
self.assertEqual(self.converter.read(reader, self.font, None), {
"C": "G",
"D": "A",
"E": "B",
})
def test_readUnknownFormat(self):
reader = OTTableReader(deHexStr("0009"))
self.assertRaisesRegex(
AssertionError,
"unsupported lookup format: 9",
self.converter.read, reader, self.font, None)
if __name__ == "__main__":
import sys
sys.exit(unittest.main())