Rebase morx branch to current master
This commit is contained in:
parent
6eb807b55f
commit
483bb67b60
7
Lib/fontTools/ttLib/tables/_m_o_r_x.py
Normal file
7
Lib/fontTools/ttLib/tables/_m_o_r_x.py
Normal 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
|
@ -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]
|
||||
|
@ -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),
|
||||
|
@ -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())
|
||||
|
Loading…
x
Reference in New Issue
Block a user