295 lines
6.7 KiB
Python
295 lines
6.7 KiB
Python
|
import otCommon
|
||
|
|
||
|
|
||
|
class table_G_P_O_S_(otCommon.base_GPOS_GSUB):
|
||
|
|
||
|
def getLookupTypeClass(self, lookupType):
|
||
|
return lookupTypeClasses[lookupType]
|
||
|
|
||
|
|
||
|
class SinglePos:
|
||
|
|
||
|
def decompile(self, reader, otFont):
|
||
|
pass
|
||
|
|
||
|
def compile(self, otFont):
|
||
|
xxx
|
||
|
|
||
|
def toXML(self, xmlWriter, otFont):
|
||
|
xmlWriter.comment("XXX")
|
||
|
xmlWriter.newline()
|
||
|
|
||
|
def fromXML(self, (name, attrs, content), otFont):
|
||
|
xxx
|
||
|
|
||
|
|
||
|
class PairPos:
|
||
|
|
||
|
def decompile(self, reader, otFont):
|
||
|
self.format = reader.readUShort()
|
||
|
if self.format == 1:
|
||
|
self.decompileFormat1(reader, otFont)
|
||
|
elif self.format == 2:
|
||
|
self.decompileFormat2(reader, otFont)
|
||
|
else:
|
||
|
from fontTools import ttLib
|
||
|
raise ttLib.TTLibError, "unknown PairPos format: %d" % self.format
|
||
|
|
||
|
def decompileFormat1(self, reader, otFont):
|
||
|
coverage = reader.readTable(otCommon.CoverageTable, otFont)
|
||
|
glyphNames = coverage.glyphNames
|
||
|
valueFactory1 = ValueRecordFactory(reader.readUShort())
|
||
|
valueFactory2 = ValueRecordFactory(reader.readUShort())
|
||
|
self.pairs = pairs = {}
|
||
|
for i in range(reader.readUShort()):
|
||
|
firstGlyphName = glyphNames[i]
|
||
|
offset = reader.readOffset()
|
||
|
setData = reader.getSubString(offset)
|
||
|
set = PairSet()
|
||
|
set.decompile(setData, otFont, valueFactory1, valueFactory2)
|
||
|
pairs[firstGlyphName] = set.values
|
||
|
|
||
|
def decompileFormat2(self, reader, otFont):
|
||
|
coverage = reader.readTable(otCommon.CoverageTable, otFont)
|
||
|
glyphNames = coverage.glyphNames
|
||
|
valueFactory1 = ValueRecordFactory(reader.readUShort())
|
||
|
valueFactory2 = ValueRecordFactory(reader.readUShort())
|
||
|
self.classDef1 = reader.readTable(otCommon.ClassDefinitionTable, otFont)
|
||
|
self.classDef2 = reader.readTable(otCommon.ClassDefinitionTable, otFont)
|
||
|
class1Count = reader.readUShort()
|
||
|
class2Count = reader.readUShort()
|
||
|
self.pairs = pairs = {} # sparse matrix
|
||
|
for i in range(class1Count):
|
||
|
row = {}
|
||
|
for j in range(class2Count):
|
||
|
value1 = valueFactory1.getValueRecord(reader)
|
||
|
value2 = valueFactory2.getValueRecord(reader)
|
||
|
if value1 or value2:
|
||
|
row[j] = (value1, value2)
|
||
|
if row:
|
||
|
pairs[i] = row
|
||
|
|
||
|
def compile(self, otFont):
|
||
|
xxx
|
||
|
|
||
|
def toXML(self, xmlWriter, otFont):
|
||
|
if self.format == 1:
|
||
|
self.toXMLFormat1(xmlWriter, otFont)
|
||
|
elif self.format == 2:
|
||
|
self.toXMLFormat2(xmlWriter, otFont)
|
||
|
else:
|
||
|
from fontTools import ttLib
|
||
|
raise ttLib.TTLibError, "unknown PairPos format: %d" % self.format
|
||
|
|
||
|
def toXMLFormat1(self, xmlWriter, otFont):
|
||
|
pairs = self.pairs.items()
|
||
|
pairs.sort()
|
||
|
for firstGlyph, secondGlyphs in pairs:
|
||
|
for secondGlyph, value1, value2 in secondGlyphs:
|
||
|
#XXXXXXXXX
|
||
|
xmlWriter.begintag("Pair", first=firstGlyph, second=secondGlyph)
|
||
|
xmlWriter.newline()
|
||
|
if value1:
|
||
|
value1.toXML(xmlWriter, otFont)
|
||
|
if value2:
|
||
|
value2.toXML(xmlWriter, otFont)
|
||
|
xmlWriter.endtag("Pair")
|
||
|
xmlWriter.newline()
|
||
|
|
||
|
def toXMLFormat2(self, xmlWriter, otFont):
|
||
|
xmlWriter.comment("XXX")
|
||
|
xmlWriter.newline()
|
||
|
|
||
|
def fromXML(self, (name, attrs, content), otFont):
|
||
|
xxx
|
||
|
|
||
|
|
||
|
class PairSet:
|
||
|
|
||
|
def decompile(self, reader, otFont, valueFactory1, valueFactory2):
|
||
|
pairValueCount = reader.readUShort()
|
||
|
self.values = values = []
|
||
|
for j in range(pairValueCount):
|
||
|
secondGlyphID = reader.readUShort()
|
||
|
secondGlyphName = otFont.getGlyphName(secondGlyphID)
|
||
|
value1 = valueFactory1.getValueRecord(reader)
|
||
|
value2 = valueFactory2.getValueRecord(reader)
|
||
|
values.append((secondGlyphName, value1, value2))
|
||
|
|
||
|
def compile(self, otFont):
|
||
|
xxx
|
||
|
|
||
|
#
|
||
|
# ------------------
|
||
|
#
|
||
|
|
||
|
class CursivePos:
|
||
|
|
||
|
def decompile(self, reader, otFont):
|
||
|
pass
|
||
|
|
||
|
def compile(self, otFont):
|
||
|
xxx
|
||
|
|
||
|
def toXML(self, xmlWriter, otFont):
|
||
|
xmlWriter.comment("XXX")
|
||
|
xmlWriter.newline()
|
||
|
|
||
|
|
||
|
class MarkBasePos:
|
||
|
|
||
|
def decompile(self, reader, otFont):
|
||
|
pass
|
||
|
|
||
|
def compile(self, otFont):
|
||
|
xxx
|
||
|
|
||
|
def toXML(self, xmlWriter, otFont):
|
||
|
xmlWriter.comment("XXX")
|
||
|
xmlWriter.newline()
|
||
|
|
||
|
|
||
|
class MarkLigPos:
|
||
|
|
||
|
def decompile(self, reader, otFont):
|
||
|
pass
|
||
|
|
||
|
def compile(self, otFont):
|
||
|
xxx
|
||
|
|
||
|
def toXML(self, xmlWriter, otFont):
|
||
|
xmlWriter.comment("XXX")
|
||
|
xmlWriter.newline()
|
||
|
|
||
|
|
||
|
class MarkMarkPos:
|
||
|
|
||
|
def decompile(self, reader, otFont):
|
||
|
pass
|
||
|
|
||
|
def compile(self, otFont):
|
||
|
xxx
|
||
|
|
||
|
def toXML(self, xmlWriter, otFont):
|
||
|
xmlWriter.comment("XXX")
|
||
|
xmlWriter.newline()
|
||
|
|
||
|
|
||
|
class ContextPos:
|
||
|
|
||
|
def decompile(self, reader, otFont):
|
||
|
pass
|
||
|
|
||
|
def compile(self, otFont):
|
||
|
xxx
|
||
|
|
||
|
def toXML(self, xmlWriter, otFont):
|
||
|
xmlWriter.comment("XXX")
|
||
|
xmlWriter.newline()
|
||
|
|
||
|
|
||
|
class ChainContextPos:
|
||
|
|
||
|
def decompile(self, reader, otFont):
|
||
|
pass
|
||
|
|
||
|
def compile(self, otFont):
|
||
|
xxx
|
||
|
|
||
|
def toXML(self, xmlWriter, otFont):
|
||
|
xmlWriter.comment("XXX")
|
||
|
xmlWriter.newline()
|
||
|
|
||
|
|
||
|
lookupTypeClasses = {
|
||
|
1: SinglePos,
|
||
|
2: PairPos,
|
||
|
3: CursivePos,
|
||
|
4: MarkBasePos,
|
||
|
5: MarkLigPos,
|
||
|
6: MarkMarkPos,
|
||
|
7: ContextPos,
|
||
|
8: ChainContextPos,
|
||
|
}
|
||
|
|
||
|
|
||
|
valueRecordFormat = [
|
||
|
# Mask Name struct format char
|
||
|
(0x0001, "XPlacement", "h"),
|
||
|
(0x0002, "YPlacement", "h"),
|
||
|
(0x0004, "XAdvance", "h"),
|
||
|
(0x0008, "YAdvance", "h"),
|
||
|
(0x0010, "XPlaDevice", "H"),
|
||
|
(0x0020, "YPlaDevice", "H"),
|
||
|
(0x0040, "XAdvDevice", "H"),
|
||
|
(0x0080, "YAdvDevice", "H"),
|
||
|
# reserved:
|
||
|
(0x0100, "Reserved1", "H"),
|
||
|
(0x0200, "Reserved2", "H"),
|
||
|
(0x0400, "Reserved3", "H"),
|
||
|
(0x0800, "Reserved4", "H"),
|
||
|
(0x1000, "Reserved5", "H"),
|
||
|
(0x2000, "Reserved6", "H"),
|
||
|
(0x4000, "Reserved7", "H"),
|
||
|
(0x8000, "Reserved8", "H"),
|
||
|
]
|
||
|
|
||
|
|
||
|
class ValueRecordFactory:
|
||
|
|
||
|
def __init__(self, valueFormat):
|
||
|
format = ">"
|
||
|
names = []
|
||
|
for mask, name, formatChar in valueRecordFormat:
|
||
|
if valueFormat & mask:
|
||
|
names.append(name)
|
||
|
format = format + formatChar
|
||
|
self.names, self.format = names, format
|
||
|
self.size = 2 * len(names)
|
||
|
|
||
|
def getValueRecord(self, reader):
|
||
|
names = self.names
|
||
|
if not names:
|
||
|
return None
|
||
|
values = reader.readStruct(self.format, self.size)
|
||
|
values = map(int, values)
|
||
|
valueRecord = ValueRecord()
|
||
|
items = map(None, names, values)
|
||
|
for name, value in items:
|
||
|
setattr(valueRecord, name, value)
|
||
|
return valueRecord
|
||
|
|
||
|
|
||
|
class ValueRecord:
|
||
|
# see ValueRecordFactory
|
||
|
|
||
|
def __nonzero__(self):
|
||
|
for value in self.__dict__.values():
|
||
|
if value:
|
||
|
return 1
|
||
|
return 0
|
||
|
|
||
|
def toXML(self, xmlWriter, otFont):
|
||
|
simpleItems = []
|
||
|
for mask, name, format in valueRecordFormat[:4]: # "simple" values
|
||
|
if hasattr(self, name):
|
||
|
simpleItems.append((name, getattr(self, name)))
|
||
|
deviceItems = []
|
||
|
for mask, name, format in valueRecordFormat[4:8]: # device records
|
||
|
if hasattr(self, name):
|
||
|
deviceItems.append((name, getattr(self, name)))
|
||
|
if deviceItems:
|
||
|
xmlWriter.begintag("ValueRecord", simpleItems)
|
||
|
xmlWriter.newline()
|
||
|
for name, deviceRecord in deviceItems:
|
||
|
xxx
|
||
|
xmlWriter.endtag("ValueRecord")
|
||
|
xmlWriter.newline()
|
||
|
else:
|
||
|
xmlWriter.simpletag("ValueRecord", simpleItems)
|
||
|
xmlWriter.newline()
|
||
|
|
||
|
def __repr__(self):
|
||
|
return "<ValueRecord>"
|
||
|
|