Completely revamped OT support; this time it works and is complete. XML output is not yet as pretty as can be.
git-svn-id: svn://svn.code.sf.net/p/fonttools/code/trunk@208 4cde692c-a291-49d1-8350-778aa11640f8
This commit is contained in:
parent
6fc514edf3
commit
d4d151390d
5
Lib/fontTools/ttLib/tables/B_A_S_E_.py
Normal file
5
Lib/fontTools/ttLib/tables/B_A_S_E_.py
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
from otBase import BaseTTXConverter
|
||||||
|
|
||||||
|
|
||||||
|
class table_B_A_S_E_(BaseTTXConverter):
|
||||||
|
pass
|
5
Lib/fontTools/ttLib/tables/G_D_E_F_.py
Normal file
5
Lib/fontTools/ttLib/tables/G_D_E_F_.py
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
from otBase import BaseTTXConverter
|
||||||
|
|
||||||
|
|
||||||
|
class table_G_D_E_F_(BaseTTXConverter):
|
||||||
|
pass
|
@ -1,384 +1,5 @@
|
|||||||
import otCommon
|
from otBase import BaseTTXConverter
|
||||||
|
|
||||||
|
|
||||||
class table_G_P_O_S_(otCommon.base_GPOS_GSUB):
|
class table_G_P_O_S_(BaseTTXConverter):
|
||||||
|
pass
|
||||||
def getLookupTypeClass(self, lookupType):
|
|
||||||
return lookupTypeClasses[lookupType]
|
|
||||||
|
|
||||||
|
|
||||||
class SinglePos:
|
|
||||||
|
|
||||||
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 SinglePos format: %d" % self.format
|
|
||||||
|
|
||||||
def decompileFormat1(self, reader, otFont):
|
|
||||||
coverage = reader.readTable(otCommon.CoverageTable, otFont)
|
|
||||||
valueFactory = ValueRecordFactory(reader.readUShort())
|
|
||||||
self.coverage = coverage.getGlyphNames()
|
|
||||||
self.value = valueFactory.readValueRecord(reader, otFont)
|
|
||||||
|
|
||||||
def decompileFormat2(self, reader, otFont):
|
|
||||||
coverage = reader.readTable(otCommon.CoverageTable, otFont)
|
|
||||||
valueFactory = ValueRecordFactory(reader.readUShort())
|
|
||||||
valueCount = reader.readUShort()
|
|
||||||
glyphNames = coverage.getGlyphNames()
|
|
||||||
self.pos = pos = {}
|
|
||||||
for i in range(valueCount):
|
|
||||||
pos[glyphNames[i]] = valueFactory.readValueRecord(reader, otFont)
|
|
||||||
|
|
||||||
def compile(self, writer, otFont):
|
|
||||||
xxx
|
|
||||||
|
|
||||||
def toXML(self, xmlWriter, otFont):
|
|
||||||
xmlWriter.comment("NotImplemented")
|
|
||||||
xmlWriter.newline()
|
|
||||||
|
|
||||||
def fromXML(self, (name, attrs, content), otFont):
|
|
||||||
raise NotImplementedError
|
|
||||||
|
|
||||||
|
|
||||||
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]
|
|
||||||
set = reader.readTable(PairSet, otFont, valueFactory1, valueFactory2)
|
|
||||||
pairs[firstGlyphName] = set.getValues()
|
|
||||||
|
|
||||||
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.readValueRecord(reader, otFont)
|
|
||||||
value2 = valueFactory2.readValueRecord(reader, otFont)
|
|
||||||
if value1 or value2:
|
|
||||||
row[j] = (value1, value2)
|
|
||||||
if row:
|
|
||||||
pairs[i] = row
|
|
||||||
|
|
||||||
def compile(self, writer, otFont):
|
|
||||||
if self.format == 1:
|
|
||||||
self.compileFormat1(writer, otFont)
|
|
||||||
elif self.format == 2:
|
|
||||||
self.compileFormat2(writer, otFont)
|
|
||||||
else:
|
|
||||||
from fontTools import ttLib
|
|
||||||
raise ttLib.TTLibError, "unknown PairPos format: %d" % self.format
|
|
||||||
|
|
||||||
def compileFormat1(self, writer, otFont):
|
|
||||||
pairs = self.pairs
|
|
||||||
glyphNames = pairs.keys()
|
|
||||||
coverage = otCommon.CoverageTable()
|
|
||||||
glyphNames = coverage.setGlyphNames(glyphNames, otFont)
|
|
||||||
writer.writeTable(coverage, otFont)
|
|
||||||
# dumb approach: just take the first pair and grab the value.
|
|
||||||
dummy, sample1, sample2 = pairs[pairs.keys()[0]][0]
|
|
||||||
valueFormat1 = valueFormat2 = 0
|
|
||||||
if sample1:
|
|
||||||
valueFormat1 = sample1.getFormat()
|
|
||||||
if sample2:
|
|
||||||
valueFormat2 = sample2.getFormat()
|
|
||||||
writer.writeUShort(valueFormat1)
|
|
||||||
writer.writeUShort(valueFormat2)
|
|
||||||
|
|
||||||
valueFactory1 = ValueRecordFactory(valueFormat1)
|
|
||||||
valueFactory2 = ValueRecordFactory(valueFormat2)
|
|
||||||
|
|
||||||
writer.writeUShort(len(pairs))
|
|
||||||
for glyphName in glyphNames:
|
|
||||||
set = PairSet(valueFactory1, valueFactory2)
|
|
||||||
set.setValues(pairs[glyphName])
|
|
||||||
writer.writeTable(set, otFont)
|
|
||||||
|
|
||||||
def compileFormat2(self, writer, 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:
|
|
||||||
xmlWriter.begintag("Pair", pair=firstGlyph+","+secondGlyph)
|
|
||||||
if value1:
|
|
||||||
value1.toXML(xmlWriter, otFont)
|
|
||||||
else:
|
|
||||||
xmlWriter.simpletag("Value")
|
|
||||||
if value2:
|
|
||||||
value2.toXML(xmlWriter, otFont)
|
|
||||||
#else: # the second value can be omitted
|
|
||||||
# xmlWriter.simpletag("Value")
|
|
||||||
xmlWriter.endtag("Pair")
|
|
||||||
xmlWriter.newline()
|
|
||||||
|
|
||||||
def toXMLFormat2(self, xmlWriter, otFont):
|
|
||||||
xmlWriter.comment("NotImplemented")
|
|
||||||
xmlWriter.newline()
|
|
||||||
|
|
||||||
def fromXML(self, (name, attrs, content), otFont):
|
|
||||||
raise NotImplementedError
|
|
||||||
|
|
||||||
|
|
||||||
class PairSet:
|
|
||||||
|
|
||||||
def __init__(self, valueFactory1=None, valueFactory2=None):
|
|
||||||
self.valueFactory1 = valueFactory1
|
|
||||||
self.valueFactory2 = valueFactory2
|
|
||||||
|
|
||||||
def getValues(self):
|
|
||||||
return self.values
|
|
||||||
|
|
||||||
def setValues(self, values):
|
|
||||||
self.values = values
|
|
||||||
|
|
||||||
def decompile(self, reader, otFont):
|
|
||||||
pairValueCount = reader.readUShort()
|
|
||||||
self.values = values = []
|
|
||||||
for j in range(pairValueCount):
|
|
||||||
secondGlyphID = reader.readUShort()
|
|
||||||
secondGlyphName = otFont.getGlyphName(secondGlyphID)
|
|
||||||
value1 = self.valueFactory1.readValueRecord(reader, otFont)
|
|
||||||
value2 = self.valueFactory2.readValueRecord(reader, otFont)
|
|
||||||
values.append((secondGlyphName, value1, value2))
|
|
||||||
|
|
||||||
def compile(self, writer, otFont):
|
|
||||||
values = self.values
|
|
||||||
writer.writeUShort(len(values))
|
|
||||||
for secondGlyphName, value1, value2 in values:
|
|
||||||
writer.writeUShort(otFont.getGlyphID(secondGlyphName))
|
|
||||||
self.valueFactory1.writeValuerecord(value1, writer, otFont)
|
|
||||||
self.valueFactory2.writeValuerecord(value2, writer, otFont)
|
|
||||||
|
|
||||||
|
|
||||||
#
|
|
||||||
# ------------------
|
|
||||||
#
|
|
||||||
|
|
||||||
class CursivePos:
|
|
||||||
|
|
||||||
def decompile(self, reader, otFont):
|
|
||||||
xxx
|
|
||||||
|
|
||||||
def compile(self, writer, otFont):
|
|
||||||
xxx
|
|
||||||
|
|
||||||
def toXML(self, xmlWriter, otFont):
|
|
||||||
xmlWriter.comment("NotImplemented")
|
|
||||||
xmlWriter.newline()
|
|
||||||
|
|
||||||
|
|
||||||
class MarkBasePos:
|
|
||||||
|
|
||||||
def decompile(self, reader, otFont):
|
|
||||||
xxx
|
|
||||||
|
|
||||||
def compile(self, writer, otFont):
|
|
||||||
xxx
|
|
||||||
|
|
||||||
def toXML(self, xmlWriter, otFont):
|
|
||||||
xmlWriter.comment("NotImplemented")
|
|
||||||
xmlWriter.newline()
|
|
||||||
|
|
||||||
|
|
||||||
class MarkLigPos:
|
|
||||||
|
|
||||||
def decompile(self, reader, otFont):
|
|
||||||
xxx
|
|
||||||
|
|
||||||
def compile(self, writer, otFont):
|
|
||||||
xxx
|
|
||||||
|
|
||||||
def toXML(self, xmlWriter, otFont):
|
|
||||||
xmlWriter.comment("NotImplemented")
|
|
||||||
xmlWriter.newline()
|
|
||||||
|
|
||||||
|
|
||||||
class MarkMarkPos:
|
|
||||||
|
|
||||||
def decompile(self, reader, otFont):
|
|
||||||
xxx
|
|
||||||
|
|
||||||
def compile(self, writer, otFont):
|
|
||||||
xxx
|
|
||||||
|
|
||||||
def toXML(self, xmlWriter, otFont):
|
|
||||||
xmlWriter.comment("NotImplemented")
|
|
||||||
xmlWriter.newline()
|
|
||||||
|
|
||||||
|
|
||||||
class ContextPos:
|
|
||||||
|
|
||||||
def decompile(self, reader, otFont):
|
|
||||||
xxx
|
|
||||||
|
|
||||||
def compile(self, writer, otFont):
|
|
||||||
xxx
|
|
||||||
|
|
||||||
def toXML(self, xmlWriter, otFont):
|
|
||||||
xmlWriter.comment("NotImplemented")
|
|
||||||
xmlWriter.newline()
|
|
||||||
|
|
||||||
|
|
||||||
class ChainContextPos:
|
|
||||||
|
|
||||||
def decompile(self, reader, otFont):
|
|
||||||
xxx
|
|
||||||
|
|
||||||
def compile(self, writer, otFont):
|
|
||||||
xxx
|
|
||||||
|
|
||||||
def toXML(self, xmlWriter, otFont):
|
|
||||||
xmlWriter.comment("NotImplemented")
|
|
||||||
xmlWriter.newline()
|
|
||||||
|
|
||||||
|
|
||||||
valueRecordFormat = [
|
|
||||||
# Mask Name isDevice struct format char
|
|
||||||
(0x0001, "XPlacement", 0, "h"),
|
|
||||||
(0x0002, "YPlacement", 0, "h"),
|
|
||||||
(0x0004, "XAdvance", 0, "h"),
|
|
||||||
(0x0008, "YAdvance", 0, "h"),
|
|
||||||
(0x0010, "XPlaDevice", 1, "H"),
|
|
||||||
(0x0020, "YPlaDevice", 1, "H"),
|
|
||||||
(0x0040, "XAdvDevice", 1, "H"),
|
|
||||||
(0x0080, "YAdvDevice", 1, "H"),
|
|
||||||
# reserved:
|
|
||||||
(0x0100, "Reserved1", 0, "H"),
|
|
||||||
(0x0200, "Reserved2", 0, "H"),
|
|
||||||
(0x0400, "Reserved3", 0, "H"),
|
|
||||||
(0x0800, "Reserved4", 0, "H"),
|
|
||||||
(0x1000, "Reserved5", 0, "H"),
|
|
||||||
(0x2000, "Reserved6", 0, "H"),
|
|
||||||
(0x4000, "Reserved7", 0, "H"),
|
|
||||||
(0x8000, "Reserved8", 0, "H"),
|
|
||||||
]
|
|
||||||
|
|
||||||
valueRecordFormatDict = {}
|
|
||||||
for mask, name, isDevice, format in valueRecordFormat:
|
|
||||||
valueRecordFormatDict[name] = mask, isDevice, format
|
|
||||||
|
|
||||||
|
|
||||||
class ValueRecordFactory:
|
|
||||||
|
|
||||||
def __init__(self, valueFormat):
|
|
||||||
format = ">"
|
|
||||||
names = []
|
|
||||||
for mask, name, isDevice, formatChar in valueRecordFormat:
|
|
||||||
if valueFormat & mask:
|
|
||||||
names.append((name, isDevice))
|
|
||||||
format = format + formatChar
|
|
||||||
self.names, self.format = names, format
|
|
||||||
self.size = 2 * len(names)
|
|
||||||
|
|
||||||
def readValueRecord(self, reader, otFont):
|
|
||||||
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, isDevice), value in items:
|
|
||||||
if isDevice:
|
|
||||||
if value:
|
|
||||||
device = otCommon.DeviceTable()
|
|
||||||
device.decompile(reader.getSubString(value), otFont)
|
|
||||||
else:
|
|
||||||
device = None
|
|
||||||
setattr(valueRecord, name, device)
|
|
||||||
else:
|
|
||||||
setattr(valueRecord, name, value)
|
|
||||||
return valueRecord
|
|
||||||
|
|
||||||
def writeValuerecord(self, valueRecord, writer, otFont):
|
|
||||||
values = []
|
|
||||||
for (name, isDevice) in self.names:
|
|
||||||
if isDevice:
|
|
||||||
raise NotImplementedError
|
|
||||||
else:
|
|
||||||
values.append(valueRecord.__dict__.get(name, 0))
|
|
||||||
writer.writeStruct(self.format, tuple(values))
|
|
||||||
|
|
||||||
|
|
||||||
class ValueRecord:
|
|
||||||
# see ValueRecordFactory
|
|
||||||
|
|
||||||
def getFormat(self):
|
|
||||||
format = 0
|
|
||||||
for name in self.__dict__.keys():
|
|
||||||
format = format | valueRecordFormatDict[name][0]
|
|
||||||
return format
|
|
||||||
|
|
||||||
def toXML(self, xmlWriter, otFont):
|
|
||||||
simpleItems = []
|
|
||||||
for mask, name, isDevice, format in valueRecordFormat[:4]: # "simple" values
|
|
||||||
if hasattr(self, name):
|
|
||||||
simpleItems.append((name, getattr(self, name)))
|
|
||||||
deviceItems = []
|
|
||||||
for mask, name, isDevice, format in valueRecordFormat[4:8]: # device records
|
|
||||||
if hasattr(self, name):
|
|
||||||
deviceItems.append((name, getattr(self, name)))
|
|
||||||
if deviceItems:
|
|
||||||
xmlWriter.begintag("Value", simpleItems)
|
|
||||||
xmlWriter.newline()
|
|
||||||
for name, deviceRecord in deviceItems:
|
|
||||||
xxx
|
|
||||||
xmlWriter.endtag("Value")
|
|
||||||
else:
|
|
||||||
xmlWriter.simpletag("Value", simpleItems)
|
|
||||||
|
|
||||||
def __repr__(self):
|
|
||||||
return "<ValueRecord>"
|
|
||||||
|
|
||||||
|
|
||||||
lookupTypeClasses = {
|
|
||||||
1: SinglePos,
|
|
||||||
2: PairPos,
|
|
||||||
3: CursivePos,
|
|
||||||
4: MarkBasePos,
|
|
||||||
5: MarkLigPos,
|
|
||||||
6: MarkMarkPos,
|
|
||||||
7: ContextPos,
|
|
||||||
8: ChainContextPos,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
@ -1,467 +1,5 @@
|
|||||||
import otCommon
|
from otBase import BaseTTXConverter
|
||||||
|
|
||||||
|
|
||||||
class table_G_S_U_B_(otCommon.base_GPOS_GSUB):
|
class table_G_S_U_B_(BaseTTXConverter):
|
||||||
|
pass
|
||||||
def getLookupTypeClass(self, lookupType):
|
|
||||||
return lookupTypeClasses[lookupType]
|
|
||||||
|
|
||||||
|
|
||||||
class SingleSubst:
|
|
||||||
|
|
||||||
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 SingleSub format: %d" % self.format
|
|
||||||
|
|
||||||
def decompileFormat1(self, reader, otFont):
|
|
||||||
coverage = reader.readTable(otCommon.CoverageTable, otFont)
|
|
||||||
glyphIDs = coverage.getGlyphIDs()
|
|
||||||
glyphNames = coverage.getGlyphNames()
|
|
||||||
self.substitutions = substitutions = {}
|
|
||||||
deltaGlyphID = reader.readShort()
|
|
||||||
for i in range(len(glyphIDs)):
|
|
||||||
input = glyphNames[i]
|
|
||||||
output = otFont.getGlyphName(glyphIDs[i] + deltaGlyphID)
|
|
||||||
substitutions[input] = output
|
|
||||||
|
|
||||||
def decompileFormat2(self, reader, otFont):
|
|
||||||
coverage = reader.readTable(otCommon.CoverageTable, otFont)
|
|
||||||
glyphNames = coverage.getGlyphNames()
|
|
||||||
glyphCount = reader.readUShort()
|
|
||||||
self.substitutions = substitutions = {}
|
|
||||||
for i in range(glyphCount):
|
|
||||||
glyphID = reader.readUShort()
|
|
||||||
output = otFont.getGlyphName(glyphID)
|
|
||||||
input = glyphNames[i]
|
|
||||||
substitutions[input] = output
|
|
||||||
|
|
||||||
def compile(self, writer, otFont):
|
|
||||||
writer.writeUShort(self.format)
|
|
||||||
if self.format == 1:
|
|
||||||
self.compileFormat1(writer, otFont)
|
|
||||||
elif self.format == 2:
|
|
||||||
self.compileFormat2(writer, otFont)
|
|
||||||
else:
|
|
||||||
from fontTools import ttLib
|
|
||||||
raise ttLib.TTLibError, "unknown SingleSub format: %d" % self.format
|
|
||||||
|
|
||||||
def compileFormat1(self, writer, otFont):
|
|
||||||
xxx
|
|
||||||
|
|
||||||
def compileFormat2(self, writer, otFont):
|
|
||||||
substitutions = self.substitutions
|
|
||||||
coverage = otCommon.CoverageTable()
|
|
||||||
glyphNames = substitutions.keys()
|
|
||||||
glyphNames = coverage.setGlyphNames(glyphNames, otFont)
|
|
||||||
|
|
||||||
writer.writeTable(coverage, otFont)
|
|
||||||
writer.writeUShort(len(substitutions))
|
|
||||||
|
|
||||||
for i in range(len(substitutions)):
|
|
||||||
glyphName = glyphNames[i]
|
|
||||||
output = substitutions[glyphName]
|
|
||||||
writer.writeUShort(otFont.getGlyphID(output))
|
|
||||||
|
|
||||||
def toXML(self, xmlWriter, otFont):
|
|
||||||
substitutions = self.substitutions.items()
|
|
||||||
substitutions.sort()
|
|
||||||
for input, output in substitutions:
|
|
||||||
xmlWriter.simpletag("Subst", [("in", input), ("out", output)])
|
|
||||||
xmlWriter.newline()
|
|
||||||
|
|
||||||
def fromXML(self, (name, attrs, content), otFont):
|
|
||||||
raise NotImplementedError
|
|
||||||
|
|
||||||
|
|
||||||
class MultipleSubst:
|
|
||||||
|
|
||||||
def decompile(self, reader, otFont):
|
|
||||||
format = reader.readUShort()
|
|
||||||
if format <> 1:
|
|
||||||
from fontTools import ttLib
|
|
||||||
raise ttLib.TTLibError, "unknown MultipleSubst format: %d" % format
|
|
||||||
glyphNames = reader.readTable(otCommon.CoverageTable, otFont).getGlyphNames()
|
|
||||||
sequenceCount = reader.readUShort()
|
|
||||||
self.substitutions = substitutions = {}
|
|
||||||
for i in range(sequenceCount):
|
|
||||||
sequence = reader.readTable(Sequence, otFont)
|
|
||||||
substitutions[glyphNames[i]] = sequence.getGlyphs()
|
|
||||||
|
|
||||||
def compile(self, writer, otFont):
|
|
||||||
xxx
|
|
||||||
|
|
||||||
def toXML(self, xmlWriter, otFont):
|
|
||||||
import string
|
|
||||||
items = self.substitutions.items()
|
|
||||||
items.sort()
|
|
||||||
for input, output in items:
|
|
||||||
xmlWriter.simpletag("Subst", [("in", input), ("out", string.join(output, ","))])
|
|
||||||
xmlWriter.newline()
|
|
||||||
|
|
||||||
|
|
||||||
class Sequence:
|
|
||||||
|
|
||||||
def getGlyphs(self):
|
|
||||||
return self.glyphs
|
|
||||||
|
|
||||||
def decompile(self, reader, otFont):
|
|
||||||
self.glyphs = []
|
|
||||||
for i in range(reader.readUShort()):
|
|
||||||
self.glyphs.append(otFont.getGlyphName(reader.readUShort()))
|
|
||||||
|
|
||||||
def compile(self, writer, otFont):
|
|
||||||
xxx
|
|
||||||
|
|
||||||
|
|
||||||
class AlternateSubst:
|
|
||||||
|
|
||||||
def decompile(self, reader, otFont):
|
|
||||||
format = reader.readUShort()
|
|
||||||
if format <> 1:
|
|
||||||
from fontTools import ttLib
|
|
||||||
raise ttLib.TTLibError, "unknown AlternateSubst format: %d" % format
|
|
||||||
coverage = reader.readTable(otCommon.CoverageTable, otFont)
|
|
||||||
glyphNames = coverage.getGlyphNames()
|
|
||||||
alternateSetCount = reader.readUShort()
|
|
||||||
self.alternateSets = alternateSets = {}
|
|
||||||
for i in range(alternateSetCount):
|
|
||||||
set = reader.readTable(AlternateSet, otFont)
|
|
||||||
alternateSets[glyphNames[i]] = set.getGlyphs()
|
|
||||||
|
|
||||||
def compile(self, writer, otFont):
|
|
||||||
writer.writeUShort(1) # format = 1
|
|
||||||
alternateSets = self.alternateSets
|
|
||||||
alternateSetCount = len(alternateSets)
|
|
||||||
glyphNames = alternateSets.keys()
|
|
||||||
coverage = otCommon.CoverageTable()
|
|
||||||
glyphNames = coverage.setGlyphNames(glyphNames, otFont)
|
|
||||||
|
|
||||||
writer.writeTable(coverage, otFont)
|
|
||||||
writer.writeUShort(alternateSetCount)
|
|
||||||
|
|
||||||
for i in range(alternateSetCount):
|
|
||||||
glyphName = glyphNames[i]
|
|
||||||
set = AlternateSet()
|
|
||||||
set.setGlyphs(alternateSets[glyphName])
|
|
||||||
writer.writeTable(set, otFont)
|
|
||||||
|
|
||||||
def toXML(self, xmlWriter, otFont):
|
|
||||||
alternates = self.alternateSets.items()
|
|
||||||
alternates.sort()
|
|
||||||
for input, substList in alternates:
|
|
||||||
xmlWriter.begintag("AlternateSet", [("in", input)])
|
|
||||||
xmlWriter.newline()
|
|
||||||
for output in substList:
|
|
||||||
xmlWriter.simpletag("Subst", out=output)
|
|
||||||
xmlWriter.newline()
|
|
||||||
xmlWriter.endtag("AlternateSet")
|
|
||||||
xmlWriter.newline()
|
|
||||||
|
|
||||||
|
|
||||||
class AlternateSet:
|
|
||||||
|
|
||||||
def getGlyphs(self):
|
|
||||||
return self.glyphs
|
|
||||||
|
|
||||||
def setGlyphs(self, glyphs):
|
|
||||||
self.glyphs = glyphs
|
|
||||||
|
|
||||||
def decompile(self, reader, otFont):
|
|
||||||
glyphCount = reader.readUShort()
|
|
||||||
glyphIDs = reader.readUShortArray(glyphCount)
|
|
||||||
self.glyphs = map(otFont.getGlyphName, glyphIDs)
|
|
||||||
|
|
||||||
def compile(self, writer, otFont):
|
|
||||||
glyphs = self.glyphs
|
|
||||||
writer.writeUShort(len(glyphs))
|
|
||||||
glyphIDs = map(otFont.getGlyphID, glyphs)
|
|
||||||
writer.writeUShortArray(glyphIDs)
|
|
||||||
|
|
||||||
|
|
||||||
class LigatureSubst:
|
|
||||||
|
|
||||||
def decompile(self, reader, otFont):
|
|
||||||
self.format = reader.readUShort()
|
|
||||||
if self.format <> 1:
|
|
||||||
from fontTools import ttLib
|
|
||||||
raise ttLib.TTLibError, "unknown LigatureSubst format: %d" % self.format
|
|
||||||
coverage = reader.readTable(otCommon.CoverageTable, otFont)
|
|
||||||
glyphNames = coverage.getGlyphNames()
|
|
||||||
ligSetCount = reader.readUShort()
|
|
||||||
self.ligatures = ligatures = []
|
|
||||||
for i in range(ligSetCount):
|
|
||||||
firstGlyph = glyphNames[i]
|
|
||||||
ligSet = reader.readTable(LigatureSet, otFont)
|
|
||||||
for components, ligatureGlyph in ligSet.getLigatures():
|
|
||||||
ligatures.append((((firstGlyph,) + tuple(components)), ligatureGlyph))
|
|
||||||
|
|
||||||
def compile(self, writer, otFont):
|
|
||||||
lastGlyph = None
|
|
||||||
sets = {}
|
|
||||||
currentSet = None
|
|
||||||
for input, output in self.ligatures:
|
|
||||||
firstGlyph = input[0]
|
|
||||||
if firstGlyph <> lastGlyph:
|
|
||||||
assert not sets.has_key(firstGlyph)
|
|
||||||
currentSet = LigatureSet()
|
|
||||||
sets[firstGlyph] = currentSet
|
|
||||||
lastGlyph = firstGlyph
|
|
||||||
currentSet.appendLigature(input[1:], output)
|
|
||||||
|
|
||||||
glyphNames = sets.keys()
|
|
||||||
coverage = otCommon.CoverageTable()
|
|
||||||
glyphNames = coverage.setGlyphNames(glyphNames, otFont)
|
|
||||||
|
|
||||||
writer.writeUShort(self.format)
|
|
||||||
writer.writeTable(coverage, otFont)
|
|
||||||
writer.writeUShort(len(sets))
|
|
||||||
|
|
||||||
for i in range(len(glyphNames)):
|
|
||||||
set = sets[glyphNames[i]]
|
|
||||||
writer.writeTable(set, otFont)
|
|
||||||
|
|
||||||
def toXML(self, xmlWriter, otFont):
|
|
||||||
import string
|
|
||||||
for input, output in self.ligatures:
|
|
||||||
xmlWriter.simpletag("Subst", [("in", string.join(input, ",")), ("out", output)])
|
|
||||||
xmlWriter.newline()
|
|
||||||
|
|
||||||
|
|
||||||
class LigatureSet:
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
self.ligatures = []
|
|
||||||
|
|
||||||
def getLigatures(self):
|
|
||||||
return self.ligatures
|
|
||||||
|
|
||||||
def appendLigature(self, components, ligatureGlyph):
|
|
||||||
self.ligatures.append((components, ligatureGlyph))
|
|
||||||
|
|
||||||
def decompile(self, reader, otFont):
|
|
||||||
ligatureCount = reader.readUShort()
|
|
||||||
self.ligatures = ligatures = []
|
|
||||||
for i in range(ligatureCount):
|
|
||||||
lig = reader.readTable(Ligature, otFont)
|
|
||||||
ligatures.append(lig.get())
|
|
||||||
|
|
||||||
def compile(self, writer, otFont):
|
|
||||||
writer.writeUShort(len(self.ligatures))
|
|
||||||
|
|
||||||
for components, output in self.ligatures:
|
|
||||||
lig = Ligature()
|
|
||||||
lig.set(components, output)
|
|
||||||
writer.writeTable(lig, otFont)
|
|
||||||
|
|
||||||
|
|
||||||
class Ligature:
|
|
||||||
|
|
||||||
def get(self):
|
|
||||||
return self.components, self.ligatureGlyph
|
|
||||||
|
|
||||||
def set(self, components, ligatureGlyph):
|
|
||||||
self.components, self.ligatureGlyph = components, ligatureGlyph
|
|
||||||
|
|
||||||
def decompile(self, reader, otFont):
|
|
||||||
self.ligatureGlyph = otFont.getGlyphName(reader.readUShort())
|
|
||||||
compCount = reader.readUShort()
|
|
||||||
self.components = components = []
|
|
||||||
for i in range(compCount-1):
|
|
||||||
components.append(otFont.getGlyphName(reader.readUShort()))
|
|
||||||
|
|
||||||
def compile(self, writer, otFont):
|
|
||||||
ligGlyphID = otFont.getGlyphID(self.ligatureGlyph)
|
|
||||||
writer.writeUShort(ligGlyphID)
|
|
||||||
writer.writeUShort(len(self.components) + 1)
|
|
||||||
for compo in self.components:
|
|
||||||
writer.writeUShort(otFont.getGlyphID(compo))
|
|
||||||
|
|
||||||
|
|
||||||
class ContextSubst:
|
|
||||||
|
|
||||||
def decompile(self, reader, otFont):
|
|
||||||
format = reader.readUShort()
|
|
||||||
if format == 1:
|
|
||||||
self.decompileFormat1(reader, otFont)
|
|
||||||
elif format == 2:
|
|
||||||
self.decompileFormat2(reader, otFont)
|
|
||||||
elif format == 3:
|
|
||||||
self.decompileFormat3(reader, otFont)
|
|
||||||
else:
|
|
||||||
from fontTools import ttLib
|
|
||||||
raise ttLib.TTLibError, "unknown ContextSubst format: %d" % format
|
|
||||||
|
|
||||||
def decompileFormat1(self, reader, otFont):
|
|
||||||
xxx
|
|
||||||
|
|
||||||
def decompileFormat2(self, reader, otFont):
|
|
||||||
xxx
|
|
||||||
|
|
||||||
def decompileFormat3(self, reader, otFont):
|
|
||||||
glyphCount = reader.readUShort()
|
|
||||||
substCount = reader.readUShort()
|
|
||||||
coverage = []
|
|
||||||
for i in range(glyphCount):
|
|
||||||
coverage.append(reader.readTable(otCommon.CoverageTable, otFont))
|
|
||||||
self.substitutions = substitutions = []
|
|
||||||
for i in range(substCount):
|
|
||||||
lookupRecord = SubstLookupRecord()
|
|
||||||
lookupRecord.decompile(reader, otFont)
|
|
||||||
substitutions.append((coverage[i].getGlyphNames(), lookupRecord))
|
|
||||||
|
|
||||||
def compile(self, writer, otFont):
|
|
||||||
xxx
|
|
||||||
|
|
||||||
def toXML(self, xmlWriter, otFont):
|
|
||||||
xmlWriter.comment("NotImplemented")
|
|
||||||
xmlWriter.newline()
|
|
||||||
|
|
||||||
|
|
||||||
class ChainContextSubst:
|
|
||||||
|
|
||||||
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)
|
|
||||||
elif self.format == 3:
|
|
||||||
self.decompileFormat3(reader, otFont)
|
|
||||||
else:
|
|
||||||
from fontTools import ttLib
|
|
||||||
raise ttLib.TTLibError, "unknown ChainContextSubst format: %d" % self.format
|
|
||||||
|
|
||||||
def decompileFormat1(self, reader, otFont):
|
|
||||||
XXX
|
|
||||||
|
|
||||||
def decompileFormat2(self, reader, otFont):
|
|
||||||
XXX
|
|
||||||
|
|
||||||
def decompileFormat3(self, reader, otFont):
|
|
||||||
backtrackGlyphCount = reader.readUShort()
|
|
||||||
backtrackCoverage = reader.readTableArray(backtrackGlyphCount, otCommon.CoverageTable, otFont)
|
|
||||||
self.backtrack = otCommon.unpackCoverageArray(backtrackCoverage)
|
|
||||||
|
|
||||||
inputGlyphCount = reader.readUShort()
|
|
||||||
inputCoverage = reader.readTableArray(inputGlyphCount, otCommon.CoverageTable, otFont)
|
|
||||||
self.input = otCommon.unpackCoverageArray(inputCoverage)
|
|
||||||
|
|
||||||
lookaheadGlyphCount = reader.readUShort()
|
|
||||||
lookaheadCoverage = reader.readTableArray(lookaheadGlyphCount, otCommon.CoverageTable, otFont)
|
|
||||||
self.lookahead = otCommon.unpackCoverageArray(lookaheadCoverage)
|
|
||||||
|
|
||||||
substCount = reader.readUShort()
|
|
||||||
self.substitutions = []
|
|
||||||
for i in range(substCount):
|
|
||||||
lookupRecord = SubstLookupRecord()
|
|
||||||
lookupRecord.decompile(reader, otFont)
|
|
||||||
self.substitutions.append(lookupRecord)
|
|
||||||
|
|
||||||
# print "XXX", [len(x) for x in self.backtrack], self.substitutions
|
|
||||||
|
|
||||||
def compile(self, writer, otFont):
|
|
||||||
writer.writeUShort(self.format)
|
|
||||||
if self.format == 1:
|
|
||||||
self.compileFormat1(writer, otFont)
|
|
||||||
elif self.format == 2:
|
|
||||||
self.compileFormat2(writer, otFont)
|
|
||||||
elif self.format == 3:
|
|
||||||
self.compileFormat3(writer, otFont)
|
|
||||||
else:
|
|
||||||
from fontTools import ttLib
|
|
||||||
raise ttLib.TTLibError, "unknown ChainContextSubst format: %d" % self.format
|
|
||||||
|
|
||||||
def compileFormat1(self, writer, otFont):
|
|
||||||
XXX
|
|
||||||
|
|
||||||
def compileFormat2(self, writer, otFont):
|
|
||||||
XXX
|
|
||||||
|
|
||||||
def compileFormat3(self, writer, otFont):
|
|
||||||
writer.writeUShort(len(self.backtrack))
|
|
||||||
backtrack = otCommon.buildCoverageArray(self.backtrack, otFont)
|
|
||||||
writer.writeTableArray(backtrack, otFont)
|
|
||||||
|
|
||||||
writer.writeUShort(len(self.input))
|
|
||||||
input = otCommon.buildCoverageArray(self.input, otFont)
|
|
||||||
writer.writeTableArray(input, otFont)
|
|
||||||
|
|
||||||
writer.writeUShort(len(self.lookahead))
|
|
||||||
lookahead = otCommon.buildCoverageArray(self.lookahead, otFont)
|
|
||||||
writer.writeTableArray(lookahead, otFont)
|
|
||||||
|
|
||||||
writer.writeUShort(len(self.substitutions))
|
|
||||||
for lookupRecord in self.substitutions:
|
|
||||||
lookupRecord.compile(writer, otFont)
|
|
||||||
|
|
||||||
def toXML(self, xmlWriter, otFont):
|
|
||||||
# XXXX this is for format 3?!
|
|
||||||
xmlWriter.begintag("Backtrack")
|
|
||||||
xmlWriter.newline()
|
|
||||||
for g in self.backtrack:
|
|
||||||
xmlWriter.simpletag("glyph", values=",".join(g))
|
|
||||||
xmlWriter.newline()
|
|
||||||
xmlWriter.endtag("Backtrack")
|
|
||||||
xmlWriter.newline()
|
|
||||||
|
|
||||||
xmlWriter.begintag("Input")
|
|
||||||
xmlWriter.newline()
|
|
||||||
for g in self.input:
|
|
||||||
xmlWriter.simpletag("glyph", values=",".join(g))
|
|
||||||
xmlWriter.newline()
|
|
||||||
xmlWriter.endtag("Input")
|
|
||||||
xmlWriter.newline()
|
|
||||||
|
|
||||||
xmlWriter.begintag("Lookahead")
|
|
||||||
xmlWriter.newline()
|
|
||||||
for g in self.lookahead:
|
|
||||||
xmlWriter.simpletag("glyph", values=",".join(g))
|
|
||||||
xmlWriter.newline()
|
|
||||||
xmlWriter.endtag("Lookahead")
|
|
||||||
xmlWriter.newline()
|
|
||||||
|
|
||||||
xmlWriter.begintag("Subst")
|
|
||||||
xmlWriter.newline()
|
|
||||||
for subst in self.substitutions:
|
|
||||||
subst.toXML(xmlWriter, otFont)
|
|
||||||
xmlWriter.newline()
|
|
||||||
xmlWriter.endtag("Subst")
|
|
||||||
xmlWriter.newline()
|
|
||||||
|
|
||||||
|
|
||||||
lookupTypeClasses = {
|
|
||||||
1: SingleSubst,
|
|
||||||
2: MultipleSubst,
|
|
||||||
3: AlternateSubst,
|
|
||||||
4: LigatureSubst,
|
|
||||||
5: ContextSubst,
|
|
||||||
6: ChainContextSubst,
|
|
||||||
# 7: ExtensionSubst, # ugh...
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#
|
|
||||||
# Shared classes
|
|
||||||
#
|
|
||||||
|
|
||||||
class SubstLookupRecord:
|
|
||||||
|
|
||||||
def decompile(self, reader, otFont):
|
|
||||||
self.sequenceIndex = reader.readUShort()
|
|
||||||
self.lookupListIndex = reader.readUShort()
|
|
||||||
|
|
||||||
def compile(self, writer, otFont):
|
|
||||||
writer.writeUShort(self.sequenceIndex)
|
|
||||||
writer.writeUShort(self.lookupListIndex)
|
|
||||||
|
|
||||||
def toXML(self, xmlWriter, otFont):
|
|
||||||
xmlWriter.simpletag("SubstLookupRecord",
|
|
||||||
[('sequenceIndex', self.sequenceIndex),
|
|
||||||
('lookupListIndex', self.lookupListIndex)])
|
|
||||||
|
|
||||||
|
5
Lib/fontTools/ttLib/tables/J_S_T_F_.py
Normal file
5
Lib/fontTools/ttLib/tables/J_S_T_F_.py
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
from otBase import BaseTTXConverter
|
||||||
|
|
||||||
|
|
||||||
|
class table_J_S_T_F_(BaseTTXConverter):
|
||||||
|
pass
|
479
Lib/fontTools/ttLib/tables/otBase.py
Normal file
479
Lib/fontTools/ttLib/tables/otBase.py
Normal file
@ -0,0 +1,479 @@
|
|||||||
|
from DefaultTable import DefaultTable
|
||||||
|
import otData
|
||||||
|
import struct
|
||||||
|
from types import TupleType
|
||||||
|
|
||||||
|
|
||||||
|
class BaseTTXConverter(DefaultTable):
|
||||||
|
|
||||||
|
def decompile(self, data, font):
|
||||||
|
import otTables
|
||||||
|
reader = OTTableReader(data, self.tableTag)
|
||||||
|
tableClass = getattr(otTables, self.tableTag)
|
||||||
|
self.table = tableClass()
|
||||||
|
self.table.decompile(reader, font)
|
||||||
|
|
||||||
|
def compile(self, font):
|
||||||
|
writer = OTTableWriter(self.tableTag)
|
||||||
|
self.table.compile(writer, font)
|
||||||
|
return writer.getData()
|
||||||
|
|
||||||
|
def toXML(self, writer, font):
|
||||||
|
self.table.toXML2(writer, font)
|
||||||
|
|
||||||
|
def fromXML(self, (name, attrs, content), font):
|
||||||
|
import otTables
|
||||||
|
if not hasattr(self, "table"):
|
||||||
|
tableClass = getattr(otTables, self.tableTag)
|
||||||
|
self.table = tableClass()
|
||||||
|
self.table.fromXML((name, attrs, content), font)
|
||||||
|
|
||||||
|
|
||||||
|
class OTTableReader:
|
||||||
|
|
||||||
|
def __init__(self, data, tableType, offset=0, valueFormat=None, cachingStats=None):
|
||||||
|
self.data = data
|
||||||
|
self.offset = offset
|
||||||
|
self.pos = offset
|
||||||
|
self.tableType = tableType
|
||||||
|
if valueFormat is None:
|
||||||
|
valueFormat = (ValueRecordFactory(), ValueRecordFactory())
|
||||||
|
self.valueFormat = valueFormat
|
||||||
|
self.cachingStats = cachingStats
|
||||||
|
|
||||||
|
def getSubReader(self, offset):
|
||||||
|
offset = self.offset + offset
|
||||||
|
if self.cachingStats is not None:
|
||||||
|
try:
|
||||||
|
self.cachingStats[offset] = self.cachingStats[offset] + 1
|
||||||
|
except KeyError:
|
||||||
|
self.cachingStats[offset] = 1
|
||||||
|
|
||||||
|
subReader = self.__class__(self.data, self.tableType, offset,
|
||||||
|
self.valueFormat, self.cachingStats)
|
||||||
|
return subReader
|
||||||
|
|
||||||
|
def readUShort(self):
|
||||||
|
pos = self.pos
|
||||||
|
newpos = pos + 2
|
||||||
|
value = struct.unpack(">H", self.data[pos:newpos])[0]
|
||||||
|
self.pos = newpos
|
||||||
|
return value
|
||||||
|
|
||||||
|
def readShort(self):
|
||||||
|
pos = self.pos
|
||||||
|
newpos = pos + 2
|
||||||
|
value = struct.unpack(">h", self.data[pos:newpos])[0]
|
||||||
|
self.pos = newpos
|
||||||
|
return value
|
||||||
|
|
||||||
|
def readLong(self):
|
||||||
|
pos = self.pos
|
||||||
|
newpos = pos + 4
|
||||||
|
value = struct.unpack(">l", self.data[pos:newpos])[0]
|
||||||
|
self.pos = newpos
|
||||||
|
return value
|
||||||
|
|
||||||
|
def readTag(self):
|
||||||
|
pos = self.pos
|
||||||
|
newpos = pos + 4
|
||||||
|
value = self.data[pos:newpos]
|
||||||
|
assert len(value) == 4
|
||||||
|
self.pos = newpos
|
||||||
|
return value
|
||||||
|
|
||||||
|
def readStruct(self, format, size=None):
|
||||||
|
if size is None:
|
||||||
|
size = struct.calcsize(format)
|
||||||
|
else:
|
||||||
|
assert size == struct.calcsize(format)
|
||||||
|
pos = self.pos
|
||||||
|
newpos = pos + size
|
||||||
|
values = struct.unpack(format, self.data[pos:newpos])
|
||||||
|
self.pos = newpos
|
||||||
|
return values
|
||||||
|
|
||||||
|
def setValueFormat(self, format, which):
|
||||||
|
self.valueFormat[which].setFormat(format)
|
||||||
|
|
||||||
|
def readValueRecord(self, font, which):
|
||||||
|
return self.valueFormat[which].readValueRecord(self, font)
|
||||||
|
|
||||||
|
|
||||||
|
class OTTableWriter:
|
||||||
|
|
||||||
|
def __init__(self, tableType, valueFormat=None):
|
||||||
|
self.items = []
|
||||||
|
self.tableType = tableType
|
||||||
|
if valueFormat is None:
|
||||||
|
valueFormat = ValueRecordFactory(), ValueRecordFactory()
|
||||||
|
self.valueFormat = valueFormat
|
||||||
|
|
||||||
|
def getSubWriter(self):
|
||||||
|
return self.__class__(self.tableType, self.valueFormat)
|
||||||
|
|
||||||
|
def getData(self):
|
||||||
|
items = list(self.items)
|
||||||
|
offset = 0
|
||||||
|
for item in items:
|
||||||
|
if hasattr(item, "getData") or hasattr(item, "getCount"):
|
||||||
|
offset = offset + 2 # sizeof(UShort)
|
||||||
|
else:
|
||||||
|
offset = offset + len(item)
|
||||||
|
subTables = []
|
||||||
|
cache = {}
|
||||||
|
for i in range(len(items)):
|
||||||
|
item = items[i]
|
||||||
|
if hasattr(item, "getData"):
|
||||||
|
subTableData = item.getData()
|
||||||
|
if cache.has_key(subTableData):
|
||||||
|
items[i] = packUShort(cache[subTableData])
|
||||||
|
else:
|
||||||
|
items[i] = packUShort(offset)
|
||||||
|
subTables.append(subTableData)
|
||||||
|
cache[subTableData] = offset
|
||||||
|
offset = offset + len(subTableData)
|
||||||
|
elif hasattr(item, "getCount"):
|
||||||
|
items[i] = item.getCount()
|
||||||
|
return "".join(items + subTables)
|
||||||
|
|
||||||
|
def writeUShort(self, value):
|
||||||
|
assert 0 <= value < 0x10000
|
||||||
|
self.items.append(struct.pack(">H", value))
|
||||||
|
|
||||||
|
def writeShort(self, value):
|
||||||
|
self.items.append(struct.pack(">h", value))
|
||||||
|
|
||||||
|
def writeLong(self, value):
|
||||||
|
self.items.append(struct.pack(">l", value))
|
||||||
|
|
||||||
|
def writeTag(self, tag):
|
||||||
|
assert len(tag) == 4
|
||||||
|
self.items.append(tag)
|
||||||
|
|
||||||
|
def writeSubTable(self, subWriter):
|
||||||
|
self.items.append(subWriter)
|
||||||
|
|
||||||
|
def writeCountReference(self, table, name):
|
||||||
|
self.items.append(CountReference(table, name))
|
||||||
|
|
||||||
|
def writeStruct(self, format, values):
|
||||||
|
data = apply(struct.pack, (format,) + values)
|
||||||
|
self.items.append(data)
|
||||||
|
|
||||||
|
def setValueFormat(self, format, which):
|
||||||
|
self.valueFormat[which].setFormat(format)
|
||||||
|
|
||||||
|
def writeValueRecord(self, value, font, which):
|
||||||
|
return self.valueFormat[which].writeValueRecord(self, font, value)
|
||||||
|
|
||||||
|
|
||||||
|
class CountReference:
|
||||||
|
def __init__(self, table, name):
|
||||||
|
self.table = table
|
||||||
|
self.name = name
|
||||||
|
def getCount(self):
|
||||||
|
return packUShort(self.table[self.name])
|
||||||
|
|
||||||
|
|
||||||
|
def packUShort(offset):
|
||||||
|
assert 0 <= offset < 0x10000
|
||||||
|
return struct.pack(">H", offset)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class BaseTable:
|
||||||
|
|
||||||
|
def getConverters(self):
|
||||||
|
return self.converters
|
||||||
|
|
||||||
|
def getConverterByName(self, name):
|
||||||
|
return self.convertersByName[name]
|
||||||
|
|
||||||
|
def decompile(self, reader, font, tableStack=None):
|
||||||
|
if tableStack is None:
|
||||||
|
tableStack = TableStack()
|
||||||
|
table = {}
|
||||||
|
self.__rawTable = table # for debugging
|
||||||
|
tableStack.push(table)
|
||||||
|
for conv in self.getConverters():
|
||||||
|
if conv.name == "SubTable":
|
||||||
|
conv = conv.getConverter(reader.tableType,
|
||||||
|
table["LookupType"])
|
||||||
|
if conv.repeat:
|
||||||
|
l = []
|
||||||
|
for i in range(tableStack.getValue(conv.repeat) + conv.repeatOffset):
|
||||||
|
l.append(conv.read(reader, font, tableStack))
|
||||||
|
table[conv.name] = l
|
||||||
|
else:
|
||||||
|
table[conv.name] = conv.read(reader, font, tableStack)
|
||||||
|
tableStack.pop()
|
||||||
|
self.postRead(table, font)
|
||||||
|
del self.__rawTable # succeeded, get rid of debugging info
|
||||||
|
|
||||||
|
def compile(self, writer, font, tableStack=None):
|
||||||
|
if tableStack is None:
|
||||||
|
tableStack = TableStack()
|
||||||
|
table = self.preWrite(font)
|
||||||
|
tableStack.push(table)
|
||||||
|
for conv in self.getConverters():
|
||||||
|
value = table.get(conv.name)
|
||||||
|
if conv.repeat:
|
||||||
|
if value is None:
|
||||||
|
value = [] # XXXXXX
|
||||||
|
tableStack.storeValue(conv.repeat, len(value) - conv.repeatOffset)
|
||||||
|
for item in value:
|
||||||
|
conv.write(writer, font, tableStack, item)
|
||||||
|
elif conv.isCount:
|
||||||
|
# Special-case Count values.
|
||||||
|
# Assumption: a Count field will *always* precede
|
||||||
|
# the actual array.
|
||||||
|
# We need a default value, as it may be set later by a nested
|
||||||
|
# table. TableStack.storeValue() will then find it here.
|
||||||
|
table[conv.name] = None
|
||||||
|
# We add a reference: by the time the data is assembled
|
||||||
|
# the Count value will be filled in.
|
||||||
|
writer.writeCountReference(table, conv.name)
|
||||||
|
else:
|
||||||
|
conv.write(writer, font, tableStack, value)
|
||||||
|
tableStack.pop()
|
||||||
|
|
||||||
|
def postRead(self, table, font):
|
||||||
|
self.__dict__.update(table)
|
||||||
|
|
||||||
|
def preWrite(self, font):
|
||||||
|
return self.__dict__.copy()
|
||||||
|
|
||||||
|
def toXML(self, xmlWriter, font, attrs=None):
|
||||||
|
tableName = self.__class__.__name__
|
||||||
|
if attrs is None:
|
||||||
|
attrs = []
|
||||||
|
if hasattr(self, "Format"):
|
||||||
|
attrs = attrs + [("Format", str(self.Format))]
|
||||||
|
xmlWriter.begintag(tableName, attrs)
|
||||||
|
xmlWriter.newline()
|
||||||
|
self.toXML2(xmlWriter, font)
|
||||||
|
xmlWriter.endtag(tableName)
|
||||||
|
xmlWriter.newline()
|
||||||
|
|
||||||
|
def toXML2(self, xmlWriter, font):
|
||||||
|
# Simpler variant of toXML, *only* for the top level tables (like GPOS, GSUB).
|
||||||
|
# This is because in TTX our parent writes our main tag, and in otBase.py we
|
||||||
|
# do it ourselves. I think I'm getting schizophrenic...
|
||||||
|
for conv in self.getConverters():
|
||||||
|
value = getattr(self, conv.name)
|
||||||
|
if not conv.repeat:
|
||||||
|
conv.xmlWrite(xmlWriter, font, value, conv.name, [])
|
||||||
|
else:
|
||||||
|
for i in range(len(value)):
|
||||||
|
item = value[i]
|
||||||
|
conv.xmlWrite(xmlWriter, font, item, conv.name, [("index", i)])
|
||||||
|
|
||||||
|
def fromXML(self, (name, attrs, content), font):
|
||||||
|
try:
|
||||||
|
conv = self.getConverterByName(name)
|
||||||
|
except KeyError:
|
||||||
|
print self, name, attrs, content
|
||||||
|
raise # XXX on KeyError, raise nice error
|
||||||
|
value = conv.xmlRead(attrs, content, font)
|
||||||
|
name = conv.name
|
||||||
|
if conv.repeat:
|
||||||
|
try:
|
||||||
|
seq = getattr(self, name)
|
||||||
|
except AttributeError:
|
||||||
|
seq = []
|
||||||
|
setattr(self, name, seq)
|
||||||
|
seq.append(value)
|
||||||
|
else:
|
||||||
|
setattr(self, name, value)
|
||||||
|
|
||||||
|
def __cmp__(self, other):
|
||||||
|
# this is only for debugging, so it's ok to barf
|
||||||
|
# when 'other' has no __dict__ or __class__
|
||||||
|
rv = cmp(self.__class__, other.__class__)
|
||||||
|
if not rv:
|
||||||
|
rv = cmp(self.__dict__, other.__dict__)
|
||||||
|
return rv
|
||||||
|
else:
|
||||||
|
return rv
|
||||||
|
|
||||||
|
|
||||||
|
class FormatSwitchingBaseTable(BaseTable):
|
||||||
|
|
||||||
|
def getConverters(self):
|
||||||
|
return self.converters[self.Format]
|
||||||
|
|
||||||
|
def getConverterByName(self, name):
|
||||||
|
return self.convertersByName[self.Format][name]
|
||||||
|
|
||||||
|
def decompile(self, reader, font, tableStack=None):
|
||||||
|
self.Format = reader.readUShort()
|
||||||
|
assert self.Format <> 0, (self, reader.pos, len(reader.data))
|
||||||
|
BaseTable.decompile(self, reader, font, tableStack)
|
||||||
|
|
||||||
|
def compile(self, writer, font, tableStack=None):
|
||||||
|
writer.writeUShort(self.Format)
|
||||||
|
BaseTable.compile(self, writer, font, tableStack)
|
||||||
|
|
||||||
|
|
||||||
|
valueRecordFormat = [
|
||||||
|
# Mask Name isDevice signed
|
||||||
|
(0x0001, "XPlacement", 0, 1),
|
||||||
|
(0x0002, "YPlacement", 0, 1),
|
||||||
|
(0x0004, "XAdvance", 0, 1),
|
||||||
|
(0x0008, "YAdvance", 0, 1),
|
||||||
|
(0x0010, "XPlaDevice", 1, 0),
|
||||||
|
(0x0020, "YPlaDevice", 1, 0),
|
||||||
|
(0x0040, "XAdvDevice", 1, 0),
|
||||||
|
(0x0080, "YAdvDevice", 1, 0),
|
||||||
|
# reserved:
|
||||||
|
(0x0100, "Reserved1", 0, 0),
|
||||||
|
(0x0200, "Reserved2", 0, 0),
|
||||||
|
(0x0400, "Reserved3", 0, 0),
|
||||||
|
(0x0800, "Reserved4", 0, 0),
|
||||||
|
(0x1000, "Reserved5", 0, 0),
|
||||||
|
(0x2000, "Reserved6", 0, 0),
|
||||||
|
(0x4000, "Reserved7", 0, 0),
|
||||||
|
(0x8000, "Reserved8", 0, 0),
|
||||||
|
]
|
||||||
|
|
||||||
|
def _buildDict():
|
||||||
|
d = {}
|
||||||
|
for mask, name, isDevice, signed in valueRecordFormat:
|
||||||
|
d[name] = mask, isDevice, signed
|
||||||
|
return d
|
||||||
|
|
||||||
|
valueRecordFormatDict = _buildDict()
|
||||||
|
|
||||||
|
|
||||||
|
class ValueRecordFactory:
|
||||||
|
|
||||||
|
def setFormat(self, valueFormat):
|
||||||
|
format = []
|
||||||
|
for mask, name, isDevice, signed in valueRecordFormat:
|
||||||
|
if valueFormat & mask:
|
||||||
|
format.append((name, isDevice, signed))
|
||||||
|
self.format = format
|
||||||
|
|
||||||
|
def readValueRecord(self, reader, font):
|
||||||
|
format = self.format
|
||||||
|
if not format:
|
||||||
|
return None
|
||||||
|
valueRecord = ValueRecord()
|
||||||
|
for name, isDevice, signed in format:
|
||||||
|
if signed:
|
||||||
|
value = reader.readShort()
|
||||||
|
else:
|
||||||
|
value = reader.readUShort()
|
||||||
|
if isDevice:
|
||||||
|
if value:
|
||||||
|
import otTables
|
||||||
|
subReader = reader.getSubReader(value)
|
||||||
|
value = getattr(otTables, name)()
|
||||||
|
value.decompile(subReader, font)
|
||||||
|
else:
|
||||||
|
value = None
|
||||||
|
setattr(valueRecord, name, value)
|
||||||
|
return valueRecord
|
||||||
|
|
||||||
|
def writeValueRecord(self, writer, font, valueRecord):
|
||||||
|
for name, isDevice, signed in self.format:
|
||||||
|
value = getattr(valueRecord, name, 0)
|
||||||
|
if isDevice:
|
||||||
|
if value:
|
||||||
|
subWriter = writer.getSubWriter()
|
||||||
|
writer.writeSubTable(subWriter)
|
||||||
|
value.compile(subWriter, font)
|
||||||
|
else:
|
||||||
|
writer.writeUShort(0)
|
||||||
|
elif signed:
|
||||||
|
writer.writeShort(value)
|
||||||
|
else:
|
||||||
|
writer.writeUShort(value)
|
||||||
|
|
||||||
|
|
||||||
|
class ValueRecord:
|
||||||
|
|
||||||
|
# see ValueRecordFactory
|
||||||
|
|
||||||
|
def getFormat(self):
|
||||||
|
format = 0
|
||||||
|
for name in self.__dict__.keys():
|
||||||
|
format = format | valueRecordFormatDict[name][0]
|
||||||
|
return format
|
||||||
|
|
||||||
|
def toXML(self, xmlWriter, font, valueName, attrs=None):
|
||||||
|
if attrs is None:
|
||||||
|
simpleItems = []
|
||||||
|
else:
|
||||||
|
simpleItems = list(attrs)
|
||||||
|
for mask, name, isDevice, format in valueRecordFormat[:4]: # "simple" values
|
||||||
|
if hasattr(self, name):
|
||||||
|
simpleItems.append((name, getattr(self, name)))
|
||||||
|
deviceItems = []
|
||||||
|
for mask, name, isDevice, format in valueRecordFormat[4:8]: # device records
|
||||||
|
if hasattr(self, name):
|
||||||
|
device = getattr(self, name)
|
||||||
|
if device is not None:
|
||||||
|
deviceItems.append((name, device))
|
||||||
|
if deviceItems:
|
||||||
|
xmlWriter.begintag(valueName, simpleItems)
|
||||||
|
xmlWriter.newline()
|
||||||
|
for name, deviceRecord in deviceItems:
|
||||||
|
if deviceRecord is not None:
|
||||||
|
deviceRecord.toXML(xmlWriter, font)
|
||||||
|
xmlWriter.endtag(valueName)
|
||||||
|
xmlWriter.newline()
|
||||||
|
else:
|
||||||
|
xmlWriter.simpletag(valueName, simpleItems)
|
||||||
|
xmlWriter.newline()
|
||||||
|
|
||||||
|
def fromXML(self, (name, attrs, content), font):
|
||||||
|
import otTables
|
||||||
|
for k, v in attrs.items():
|
||||||
|
setattr(self, k, int(v))
|
||||||
|
for element in content:
|
||||||
|
if type(element) <> TupleType:
|
||||||
|
continue
|
||||||
|
name, attrs, content = element
|
||||||
|
value = getattr(otTables, name)()
|
||||||
|
for elem2 in content:
|
||||||
|
if type(elem2) <> TupleType:
|
||||||
|
continue
|
||||||
|
value.fromXML(elem2, font)
|
||||||
|
setattr(self, name, value)
|
||||||
|
|
||||||
|
def __cmp__(self, other):
|
||||||
|
# this is only for debugging, so it's ok to barf
|
||||||
|
# when 'other' has no __dict__ or __class__
|
||||||
|
rv = cmp(self.__class__, other.__class__)
|
||||||
|
if not rv:
|
||||||
|
rv = cmp(self.__dict__, other.__dict__)
|
||||||
|
return rv
|
||||||
|
else:
|
||||||
|
return rv
|
||||||
|
|
||||||
|
|
||||||
|
class TableStack:
|
||||||
|
def __init__(self):
|
||||||
|
self.stack = []
|
||||||
|
def push(self, table):
|
||||||
|
self.stack.insert(0, table)
|
||||||
|
def pop(self):
|
||||||
|
self.stack.pop(0)
|
||||||
|
def getTop(self):
|
||||||
|
return self.stack[0]
|
||||||
|
def getValue(self, name):
|
||||||
|
return self.__findTable(name)[name]
|
||||||
|
def storeValue(self, name, value):
|
||||||
|
table = self.__findTable(name)
|
||||||
|
if table[name] is None:
|
||||||
|
table[name] = value
|
||||||
|
else:
|
||||||
|
assert table[name] == value, (table[name], value)
|
||||||
|
def __findTable(self, name):
|
||||||
|
for table in self.stack:
|
||||||
|
if table.has_key(name):
|
||||||
|
return table
|
||||||
|
raise KeyError, name
|
||||||
|
|
265
Lib/fontTools/ttLib/tables/otConverters.py
Normal file
265
Lib/fontTools/ttLib/tables/otConverters.py
Normal file
@ -0,0 +1,265 @@
|
|||||||
|
from types import TupleType
|
||||||
|
from fontTools.misc.textTools import safeEval
|
||||||
|
|
||||||
|
|
||||||
|
def buildConverterList(tableSpec, tableNamespace):
|
||||||
|
converters = []
|
||||||
|
convertersByName = {}
|
||||||
|
for tp, name, repeat, repeatOffset, descr in tableSpec:
|
||||||
|
if name.startswith("ValueFormat"):
|
||||||
|
assert tp == "uint16"
|
||||||
|
converterClass = ValueFormat
|
||||||
|
elif name == "DeltaValue":
|
||||||
|
assert tp == "uint16"
|
||||||
|
converterClass = DeltaValue
|
||||||
|
elif name.endswith("Count"):
|
||||||
|
assert tp == "uint16"
|
||||||
|
converterClass = Count
|
||||||
|
elif name == "SubTable":
|
||||||
|
converterClass = SubTable
|
||||||
|
else:
|
||||||
|
converterClass = converterMapping[tp]
|
||||||
|
tableClass = tableNamespace.get(name)
|
||||||
|
conv = converterClass(name, repeat, repeatOffset, tableClass)
|
||||||
|
if name == "SubTable":
|
||||||
|
conv.lookupTypes = tableNamespace['lookupTypes']
|
||||||
|
# also create reverse mapping
|
||||||
|
for t in conv.lookupTypes.values():
|
||||||
|
for cls in t.values():
|
||||||
|
convertersByName[cls.__name__] = Table("SubTable", repeat, repeatOffset, cls)
|
||||||
|
converters.append(conv)
|
||||||
|
assert not convertersByName.has_key(name)
|
||||||
|
convertersByName[name] = conv
|
||||||
|
return converters, convertersByName
|
||||||
|
|
||||||
|
|
||||||
|
class BaseConverter:
|
||||||
|
|
||||||
|
def __init__(self, name, repeat, repeatOffset, tableClass):
|
||||||
|
self.name = name
|
||||||
|
self.repeat = repeat
|
||||||
|
self.repeatOffset = repeatOffset
|
||||||
|
self.tableClass = tableClass
|
||||||
|
self.isCount = name.endswith("Count")
|
||||||
|
|
||||||
|
def read(self, reader, font, tableStack):
|
||||||
|
raise NotImplementedError, self
|
||||||
|
|
||||||
|
def write(self, writer, font, tableStack, value):
|
||||||
|
raise NotImplementedError, self
|
||||||
|
|
||||||
|
def xmlWrite(self, xmlWriter, font, value, name, attrs):
|
||||||
|
raise NotImplementedError, self
|
||||||
|
|
||||||
|
def xmlRead(self, attrs, content, font):
|
||||||
|
raise NotImplementedError, self
|
||||||
|
|
||||||
|
|
||||||
|
class SimpleValue(BaseConverter):
|
||||||
|
def xmlWrite(self, xmlWriter, font, value, name, attrs):
|
||||||
|
xmlWriter.simpletag(name, attrs + [("value", value)])
|
||||||
|
xmlWriter.newline()
|
||||||
|
def xmlRead(self, attrs, content, font):
|
||||||
|
return attrs["value"]
|
||||||
|
|
||||||
|
class IntValue(SimpleValue):
|
||||||
|
def xmlRead(self, attrs, content, font):
|
||||||
|
return int(attrs["value"])
|
||||||
|
|
||||||
|
class Long(IntValue):
|
||||||
|
def read(self, reader, font, tableStack):
|
||||||
|
return reader.readLong()
|
||||||
|
def write(self, writer, font, tableStack, value):
|
||||||
|
writer.writeLong(value)
|
||||||
|
|
||||||
|
class Short(IntValue):
|
||||||
|
def read(self, reader, font, tableStack):
|
||||||
|
return reader.readShort()
|
||||||
|
def write(self, writer, font, tableStack, value):
|
||||||
|
writer.writeShort(value)
|
||||||
|
|
||||||
|
class UShort(IntValue):
|
||||||
|
def read(self, reader, font, tableStack):
|
||||||
|
return reader.readUShort()
|
||||||
|
def write(self, writer, font, tableStack, value):
|
||||||
|
writer.writeUShort(value)
|
||||||
|
|
||||||
|
class Count(Short):
|
||||||
|
def xmlWrite(self, xmlWriter, font, value, name, attrs):
|
||||||
|
xmlWriter.comment("%s=%s" % (name, value))
|
||||||
|
xmlWriter.newline()
|
||||||
|
|
||||||
|
class Tag(SimpleValue):
|
||||||
|
def read(self, reader, font, tableStack):
|
||||||
|
return reader.readTag()
|
||||||
|
def write(self, writer, font, tableStack, value):
|
||||||
|
writer.writeTag(value)
|
||||||
|
|
||||||
|
class GlyphID(SimpleValue):
|
||||||
|
def read(self, reader, font, tableStack):
|
||||||
|
return font.getGlyphName(reader.readUShort())
|
||||||
|
def write(self, writer, font, tableStack, value):
|
||||||
|
writer.writeUShort(font.getGlyphID(value))
|
||||||
|
|
||||||
|
class Struct(BaseConverter):
|
||||||
|
|
||||||
|
def read(self, reader, font, tableStack):
|
||||||
|
table = self.tableClass()
|
||||||
|
table.decompile(reader, font, tableStack)
|
||||||
|
return table
|
||||||
|
|
||||||
|
def write(self, writer, font, tableStack, value):
|
||||||
|
value.compile(writer, font, tableStack)
|
||||||
|
|
||||||
|
def xmlWrite(self, xmlWriter, font, value, name, attrs):
|
||||||
|
if value is None:
|
||||||
|
pass # NULL table, ignore
|
||||||
|
else:
|
||||||
|
value.toXML(xmlWriter, font, attrs)
|
||||||
|
|
||||||
|
def xmlRead(self, attrs, content, font):
|
||||||
|
table = self.tableClass()
|
||||||
|
Format = attrs.get("Format")
|
||||||
|
if Format is not None:
|
||||||
|
table.Format = int(Format)
|
||||||
|
for element in content:
|
||||||
|
if type(element) <> TupleType:
|
||||||
|
continue
|
||||||
|
name, attrs, content = element
|
||||||
|
table.fromXML((name, attrs, content), font)
|
||||||
|
return table
|
||||||
|
|
||||||
|
|
||||||
|
class Table(Struct):
|
||||||
|
|
||||||
|
def read(self, reader, font, tableStack):
|
||||||
|
offset = reader.readUShort()
|
||||||
|
if offset == 0:
|
||||||
|
return None
|
||||||
|
if offset <= 3:
|
||||||
|
# XXX hack to work around buggy pala.ttf
|
||||||
|
print "*** Warning: offset is not 0, yet suspiciously low (%s). table: %s" \
|
||||||
|
% (offset, self.tableClass.__name__)
|
||||||
|
return None
|
||||||
|
subReader = reader.getSubReader(offset)
|
||||||
|
table = self.tableClass()
|
||||||
|
table.decompile(subReader, font, tableStack)
|
||||||
|
return table
|
||||||
|
|
||||||
|
def write(self, writer, font, tableStack, value):
|
||||||
|
if value is None:
|
||||||
|
writer.writeUShort(0)
|
||||||
|
else:
|
||||||
|
subWriter = writer.getSubWriter()
|
||||||
|
writer.writeSubTable(subWriter)
|
||||||
|
value.compile(subWriter, font, tableStack)
|
||||||
|
|
||||||
|
|
||||||
|
class SubTable(Table):
|
||||||
|
def getConverter(self, tableType, lookupType):
|
||||||
|
lookupTypes = self.lookupTypes[tableType]
|
||||||
|
tableClass = lookupTypes[lookupType]
|
||||||
|
return Table(self.name, self.repeat, self.repeatOffset, tableClass)
|
||||||
|
|
||||||
|
|
||||||
|
class ValueFormat(IntValue):
|
||||||
|
def __init__(self, name, repeat, repeatOffset, tableClass):
|
||||||
|
BaseConverter.__init__(self, name, repeat, repeatOffset, tableClass)
|
||||||
|
self.which = name[-1] == "2"
|
||||||
|
def read(self, reader, font, tableStack):
|
||||||
|
format = reader.readUShort()
|
||||||
|
reader.setValueFormat(format, self.which)
|
||||||
|
return format
|
||||||
|
def write(self, writer, font, tableStack, format):
|
||||||
|
writer.writeUShort(format)
|
||||||
|
writer.setValueFormat(format, self.which)
|
||||||
|
|
||||||
|
class ValueRecord(ValueFormat):
|
||||||
|
def read(self, reader, font, tableStack):
|
||||||
|
return reader.readValueRecord(font, self.which)
|
||||||
|
def write(self, writer, font, tableStack, value):
|
||||||
|
writer.writeValueRecord(value, font, self.which)
|
||||||
|
def xmlWrite(self, xmlWriter, font, value, name, attrs):
|
||||||
|
if value is None:
|
||||||
|
pass # NULL table, ignore
|
||||||
|
else:
|
||||||
|
value.toXML(xmlWriter, font, self.name, attrs)
|
||||||
|
def xmlRead(self, attrs, content, font):
|
||||||
|
from otBase import ValueRecord
|
||||||
|
value = ValueRecord()
|
||||||
|
value.fromXML((None, attrs, content), font)
|
||||||
|
return value
|
||||||
|
|
||||||
|
|
||||||
|
class DeltaValue(BaseConverter):
|
||||||
|
|
||||||
|
def read(self, reader, font, tableStack):
|
||||||
|
table = tableStack.getTop()
|
||||||
|
StartSize = table["StartSize"]
|
||||||
|
EndSize = table["EndSize"]
|
||||||
|
DeltaFormat = table["DeltaFormat"]
|
||||||
|
assert DeltaFormat in (1, 2, 3), "illegal DeltaFormat"
|
||||||
|
nItems = EndSize - StartSize + 1
|
||||||
|
nBits = 1 << DeltaFormat
|
||||||
|
minusOffset = 1 << nBits
|
||||||
|
mask = (1 << nBits) - 1
|
||||||
|
signMask = 1 << (nBits - 1)
|
||||||
|
|
||||||
|
DeltaValue = []
|
||||||
|
tmp, shift = 0, 0
|
||||||
|
for i in range(nItems):
|
||||||
|
if shift == 0:
|
||||||
|
tmp, shift = reader.readUShort(), 16
|
||||||
|
shift = shift - nBits
|
||||||
|
value = (tmp >> shift) & mask
|
||||||
|
if value & signMask:
|
||||||
|
value = value - minusOffset
|
||||||
|
DeltaValue.append(value)
|
||||||
|
return DeltaValue
|
||||||
|
|
||||||
|
def write(self, writer, font, tableStack, value):
|
||||||
|
table = tableStack.getTop()
|
||||||
|
StartSize = table["StartSize"]
|
||||||
|
EndSize = table["EndSize"]
|
||||||
|
DeltaFormat = table["DeltaFormat"]
|
||||||
|
DeltaValue = table["DeltaValue"]
|
||||||
|
assert DeltaFormat in (1, 2, 3), "illegal DeltaFormat"
|
||||||
|
nItems = EndSize - StartSize + 1
|
||||||
|
nBits = 1 << DeltaFormat
|
||||||
|
assert len(DeltaValue) == nItems
|
||||||
|
mask = (1 << nBits) - 1
|
||||||
|
|
||||||
|
tmp, shift = 0, 16
|
||||||
|
for value in DeltaValue:
|
||||||
|
shift = shift - nBits
|
||||||
|
tmp = tmp | ((value & mask) << shift)
|
||||||
|
if shift == 0:
|
||||||
|
writer.writeUShort(tmp)
|
||||||
|
tmp, shift = 0, 16
|
||||||
|
if shift <> 16:
|
||||||
|
writer.writeUShort(tmp)
|
||||||
|
|
||||||
|
def xmlWrite(self, xmlWriter, font, value, name, attrs):
|
||||||
|
xmlWriter.simpletag(name, attrs + [("value", value)])
|
||||||
|
xmlWriter.newline()
|
||||||
|
|
||||||
|
def xmlRead(self, attrs, content, font):
|
||||||
|
return safeEval(attrs["value"])
|
||||||
|
|
||||||
|
|
||||||
|
converterMapping = {
|
||||||
|
# type class
|
||||||
|
"int16": Short,
|
||||||
|
"uint16": UShort,
|
||||||
|
"ULONG": Long,
|
||||||
|
"Tag": Tag,
|
||||||
|
"GlyphID": GlyphID,
|
||||||
|
"struct": Struct,
|
||||||
|
"Offset": Table,
|
||||||
|
"ValueRecord": ValueRecord,
|
||||||
|
}
|
||||||
|
|
||||||
|
# equivalents:
|
||||||
|
converterMapping["USHORT"] = converterMapping["uint16"]
|
||||||
|
converterMapping["Fixed"] = converterMapping["fixed32"] = converterMapping["ULONG"]
|
||||||
|
|
791
Lib/fontTools/ttLib/tables/otData.py
Normal file
791
Lib/fontTools/ttLib/tables/otData.py
Normal file
@ -0,0 +1,791 @@
|
|||||||
|
otData = [
|
||||||
|
|
||||||
|
#
|
||||||
|
# common (generated from chapter2.htm)
|
||||||
|
#
|
||||||
|
|
||||||
|
('ScriptList', [
|
||||||
|
('uint16', 'ScriptCount', None, None, 'Number of ScriptRecords'),
|
||||||
|
('struct', 'ScriptRecord', 'ScriptCount', 0, 'Array of ScriptRecords -listed alphabetically by ScriptTag'),
|
||||||
|
]),
|
||||||
|
|
||||||
|
('ScriptRecord', [
|
||||||
|
('Tag', 'ScriptTag', None, None, '4-byte ScriptTag identifier'),
|
||||||
|
('Offset', 'Script', None, None, 'Offset to Script table-from beginning of ScriptList'),
|
||||||
|
]),
|
||||||
|
|
||||||
|
('Script', [
|
||||||
|
('Offset', 'DefaultLangSys', None, None, 'Offset to DefaultLangSys table-from beginning of Script table-may be NULL'),
|
||||||
|
('uint16', 'LangSysCount', None, None, 'Number of LangSysRecords for this script-excluding the DefaultLangSys'),
|
||||||
|
('struct', 'LangSysRecord', 'LangSysCount', 0, 'Array of LangSysRecords-listed alphabetically by LangSysTag'),
|
||||||
|
]),
|
||||||
|
|
||||||
|
('LangSysRecord', [
|
||||||
|
('Tag', 'LangSysTag', None, None, '4-byte LangSysTag identifier'),
|
||||||
|
('Offset', 'LangSys', None, None, 'Offset to LangSys table-from beginning of Script table'),
|
||||||
|
]),
|
||||||
|
|
||||||
|
('LangSys', [
|
||||||
|
('Offset', 'LookupOrder', None, None, '= NULL (reserved for an offset to a reordering table)'),
|
||||||
|
('uint16', 'ReqFeatureIndex', None, None, 'Index of a feature required for this language system- if no required features = 0xFFFF'),
|
||||||
|
('uint16', 'FeatureCount', None, None, 'Number of FeatureIndex values for this language system-excludes the required feature'),
|
||||||
|
('uint16', 'FeatureIndex', 'FeatureCount', 0, 'Array of indices into the FeatureList-in arbitrary order'),
|
||||||
|
]),
|
||||||
|
|
||||||
|
('FeatureList', [
|
||||||
|
('uint16', 'FeatureCount', None, None, 'Number of FeatureRecords in this table'),
|
||||||
|
('struct', 'FeatureRecord', 'FeatureCount', 0, 'Array of FeatureRecords-zero-based (first feature has FeatureIndex = 0)-listed alphabetically by FeatureTag'),
|
||||||
|
]),
|
||||||
|
|
||||||
|
('FeatureRecord', [
|
||||||
|
('Tag', 'FeatureTag', None, None, '4-byte feature identification tag'),
|
||||||
|
('Offset', 'Feature', None, None, 'Offset to Feature table-from beginning of FeatureList'),
|
||||||
|
]),
|
||||||
|
|
||||||
|
('Feature', [
|
||||||
|
('Offset', 'FeatureParams', None, None, '= NULL (reserved for offset to FeatureParams)'),
|
||||||
|
('uint16', 'LookupCount', None, None, 'Number of LookupList indices for this feature'),
|
||||||
|
('uint16', 'LookupListIndex', 'LookupCount', 0, 'Array of LookupList indices for this feature -zero-based (first lookup is LookupListIndex = 0)'),
|
||||||
|
]),
|
||||||
|
|
||||||
|
('LookupList', [
|
||||||
|
('uint16', 'LookupCount', None, None, 'Number of lookups in this table'),
|
||||||
|
('Offset', 'Lookup', 'LookupCount', 0, 'Array of offsets to Lookup tables-from beginning of LookupList -zero based (first lookup is Lookup index = 0)'),
|
||||||
|
]),
|
||||||
|
|
||||||
|
('Lookup', [
|
||||||
|
('uint16', 'LookupType', None, None, 'Different enumerations for GSUB and GPOS'),
|
||||||
|
('uint16', 'LookupFlag', None, None, 'Lookup qualifiers'),
|
||||||
|
('uint16', 'SubTableCount', None, None, 'Number of SubTables for this lookup'),
|
||||||
|
('Offset', 'SubTable', 'SubTableCount', 0, 'Array of offsets to SubTables-from beginning of Lookup table'),
|
||||||
|
]),
|
||||||
|
|
||||||
|
('CoverageFormat1', [
|
||||||
|
('uint16', 'CoverageFormat', None, None, 'Format identifier-format = 1'),
|
||||||
|
('uint16', 'GlyphCount', None, None, 'Number of glyphs in the GlyphArray'),
|
||||||
|
('GlyphID', 'GlyphArray', 'GlyphCount', 0, 'Array of GlyphIDs-in numerical order'),
|
||||||
|
]),
|
||||||
|
|
||||||
|
('CoverageFormat2', [
|
||||||
|
('uint16', 'CoverageFormat', None, None, 'Format identifier-format = 2'),
|
||||||
|
('uint16', 'RangeCount', None, None, 'Number of RangeRecords'),
|
||||||
|
('struct', 'RangeRecord', 'RangeCount', 0, 'Array of glyph ranges-ordered by Start GlyphID'),
|
||||||
|
]),
|
||||||
|
|
||||||
|
('RangeRecord', [
|
||||||
|
('GlyphID', 'Start', None, None, 'First GlyphID in the range'),
|
||||||
|
('GlyphID', 'End', None, None, 'Last GlyphID in the range'),
|
||||||
|
('uint16', 'StartCoverageIndex', None, None, 'Coverage Index of first GlyphID in range'),
|
||||||
|
]),
|
||||||
|
|
||||||
|
('ClassDefFormat1', [
|
||||||
|
('uint16', 'ClassFormat', None, None, 'Format identifier-format = 1'),
|
||||||
|
('GlyphID', 'StartGlyph', None, None, 'First GlyphID of the ClassValueArray'),
|
||||||
|
('uint16', 'GlyphCount', None, None, 'Size of the ClassValueArray'),
|
||||||
|
('uint16', 'ClassValueArray', 'GlyphCount', 0, 'Array of Class Values-one per GlyphID'),
|
||||||
|
]),
|
||||||
|
|
||||||
|
('ClassDefFormat2', [
|
||||||
|
('uint16', 'ClassFormat', None, None, 'Format identifier-format = 2'),
|
||||||
|
('uint16', 'ClassRangeCount', None, None, 'Number of ClassRangeRecords'),
|
||||||
|
('struct', 'ClassRangeRecord', 'ClassRangeCount', 0, 'Array of ClassRangeRecords-ordered by Start GlyphID'),
|
||||||
|
]),
|
||||||
|
|
||||||
|
('ClassRangeRecord', [
|
||||||
|
('GlyphID', 'Start', None, None, 'First GlyphID in the range'),
|
||||||
|
('GlyphID', 'End', None, None, 'Last GlyphID in the range'),
|
||||||
|
('uint16', 'Class', None, None, 'Applied to all glyphs in the range'),
|
||||||
|
]),
|
||||||
|
|
||||||
|
('Device', [
|
||||||
|
('uint16', 'StartSize', None, None, 'Smallest size to correct-in ppem'),
|
||||||
|
('uint16', 'EndSize', None, None, 'Largest size to correct-in ppem'),
|
||||||
|
('uint16', 'DeltaFormat', None, None, 'Format of DeltaValue array data: 1, 2, or 3'),
|
||||||
|
('uint16', 'DeltaValue', '', 0, 'Array of compressed data'),
|
||||||
|
]),
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# gpos (generated from gpos.htm)
|
||||||
|
#
|
||||||
|
|
||||||
|
('GPOS', [
|
||||||
|
('Fixed', 'Version', None, None, 'Version of the GPOS table-initially = 0x00010000'),
|
||||||
|
('Offset', 'ScriptList', None, None, 'Offset to ScriptList table-from beginning of GPOS table'),
|
||||||
|
('Offset', 'FeatureList', None, None, 'Offset to FeatureList table-from beginning of GPOS table'),
|
||||||
|
('Offset', 'LookupList', None, None, 'Offset to LookupList table-from beginning of GPOS table'),
|
||||||
|
]),
|
||||||
|
|
||||||
|
('SinglePosFormat1', [
|
||||||
|
('uint16', 'PosFormat', None, None, 'Format identifier-format = 1'),
|
||||||
|
('Offset', 'Coverage', None, None, 'Offset to Coverage table-from beginning of SinglePos subtable'),
|
||||||
|
('uint16', 'ValueFormat', None, None, 'Defines the types of data in the ValueRecord'),
|
||||||
|
('ValueRecord', 'Value', None, None, 'Defines positioning value(s)-applied to all glyphs in the Coverage table'),
|
||||||
|
]),
|
||||||
|
|
||||||
|
('SinglePosFormat2', [
|
||||||
|
('uint16', 'PosFormat', None, None, 'Format identifier-format = 2'),
|
||||||
|
('Offset', 'Coverage', None, None, 'Offset to Coverage table-from beginning of SinglePos subtable'),
|
||||||
|
('uint16', 'ValueFormat', None, None, 'Defines the types of data in the ValueRecord'),
|
||||||
|
('uint16', 'ValueCount', None, None, 'Number of ValueRecords'),
|
||||||
|
('ValueRecord', 'Value', 'ValueCount', 0, 'Array of ValueRecords-positioning values applied to glyphs'),
|
||||||
|
]),
|
||||||
|
|
||||||
|
('PairPosFormat1', [
|
||||||
|
('uint16', 'PosFormat', None, None, 'Format identifier-format = 1'),
|
||||||
|
('Offset', 'Coverage', None, None, 'Offset to Coverage table-from beginning of PairPos subtable-only the first glyph in each pair'),
|
||||||
|
('uint16', 'ValueFormat1', None, None, 'Defines the types of data in ValueRecord1-for the first glyph in the pair -may be zero (0)'),
|
||||||
|
('uint16', 'ValueFormat2', None, None, 'Defines the types of data in ValueRecord2-for the second glyph in the pair -may be zero (0)'),
|
||||||
|
('uint16', 'PairSetCount', None, None, 'Number of PairSet tables'),
|
||||||
|
('Offset', 'PairSet', 'PairSetCount', 0, 'Array of offsets to PairSet tables-from beginning of PairPos subtable-ordered by Coverage Index'),
|
||||||
|
]),
|
||||||
|
|
||||||
|
('PairSet', [
|
||||||
|
('uint16', 'PairValueCount', None, None, 'Number of PairValueRecords'),
|
||||||
|
('struct', 'PairValueRecord', 'PairValueCount', 0, 'Array of PairValueRecords-ordered by GlyphID of the second glyph'),
|
||||||
|
]),
|
||||||
|
|
||||||
|
('PairValueRecord', [
|
||||||
|
('GlyphID', 'SecondGlyph', None, None, 'GlyphID of second glyph in the pair-first glyph is listed in the Coverage table'),
|
||||||
|
('ValueRecord', 'Value1', None, None, 'Positioning data for the first glyph in the pair'),
|
||||||
|
('ValueRecord', 'Value2', None, None, 'Positioning data for the second glyph in the pair'),
|
||||||
|
]),
|
||||||
|
|
||||||
|
('PairPosFormat2', [
|
||||||
|
('uint16', 'PosFormat', None, None, 'Format identifier-format = 2'),
|
||||||
|
('Offset', 'Coverage', None, None, 'Offset to Coverage table-from beginning of PairPos subtable-for the first glyph of the pair'),
|
||||||
|
('uint16', 'ValueFormat1', None, None, 'ValueRecord definition-for the first glyph of the pair-may be zero (0)'),
|
||||||
|
('uint16', 'ValueFormat2', None, None, 'ValueRecord definition-for the second glyph of the pair-may be zero (0)'),
|
||||||
|
('Offset', 'ClassDef1', None, None, 'Offset to ClassDef table-from beginning of PairPos subtable-for the first glyph of the pair'),
|
||||||
|
('Offset', 'ClassDef2', None, None, 'Offset to ClassDef table-from beginning of PairPos subtable-for the second glyph of the pair'),
|
||||||
|
('uint16', 'Class1Count', None, None, 'Number of classes in ClassDef1 table-includes Class0'),
|
||||||
|
('uint16', 'Class2Count', None, None, 'Number of classes in ClassDef2 table-includes Class0'),
|
||||||
|
('struct', 'Class1Record', 'Class1Count', 0, 'Array of Class1 records-ordered by Class1'),
|
||||||
|
]),
|
||||||
|
|
||||||
|
('Class1Record', [
|
||||||
|
('struct', 'Class2Record', 'Class2Count', 0, 'Array of Class2 records-ordered by Class2'),
|
||||||
|
]),
|
||||||
|
|
||||||
|
('Class2Record', [
|
||||||
|
('ValueRecord', 'Value1', None, None, 'Positioning for first glyph-empty if ValueFormat1 = 0'),
|
||||||
|
('ValueRecord', 'Value2', None, None, 'Positioning for second glyph-empty if ValueFormat2 = 0'),
|
||||||
|
]),
|
||||||
|
|
||||||
|
('CursivePosFormat1', [
|
||||||
|
('uint16', 'PosFormat', None, None, 'Format identifier-format = 1'),
|
||||||
|
('Offset', 'Coverage', None, None, 'Offset to Coverage table-from beginning of CursivePos subtable'),
|
||||||
|
('uint16', 'EntryExitCount', None, None, 'Number of EntryExit records'),
|
||||||
|
('struct', 'EntryExitRecord', 'EntryExitCount', 0, 'Array of EntryExit records-in Coverage Index order'),
|
||||||
|
]),
|
||||||
|
|
||||||
|
('EntryExitRecord', [
|
||||||
|
('Offset', 'EntryAnchor', None, None, 'Offset to EntryAnchor table-from beginning of CursivePos subtable-may be NULL'),
|
||||||
|
('Offset', 'ExitAnchor', None, None, 'Offset to ExitAnchor table-from beginning of CursivePos subtable-may be NULL'),
|
||||||
|
]),
|
||||||
|
|
||||||
|
('MarkBasePosFormat1', [
|
||||||
|
('uint16', 'PosFormat', None, None, 'Format identifier-format = 1'),
|
||||||
|
('Offset', 'MarkCoverage', None, None, 'Offset to MarkCoverage table-from beginning of MarkBasePos subtable'),
|
||||||
|
('Offset', 'BaseCoverage', None, None, 'Offset to BaseCoverage table-from beginning of MarkBasePos subtable'),
|
||||||
|
('uint16', 'ClassCount', None, None, 'Number of classes defined for marks'),
|
||||||
|
('Offset', 'MarkArray', None, None, 'Offset to MarkArray table-from beginning of MarkBasePos subtable'),
|
||||||
|
('Offset', 'BaseArray', None, None, 'Offset to BaseArray table-from beginning of MarkBasePos subtable'),
|
||||||
|
]),
|
||||||
|
|
||||||
|
('BaseArray', [
|
||||||
|
('uint16', 'BaseCount', None, None, 'Number of BaseRecords'),
|
||||||
|
('struct', 'BaseRecord', 'BaseCount', 0, 'Array of BaseRecords-in order of BaseCoverage Index'),
|
||||||
|
]),
|
||||||
|
|
||||||
|
('BaseRecord', [
|
||||||
|
('Offset', 'BaseAnchor', 'ClassCount', 0, 'Array of offsets (one per class) to Anchor tables-from beginning of BaseArray table-ordered by class-zero-based'),
|
||||||
|
]),
|
||||||
|
|
||||||
|
('MarkLigPosFormat1', [
|
||||||
|
('uint16', 'PosFormat', None, None, 'Format identifier-format = 1'),
|
||||||
|
('Offset', 'MarkCoverage', None, None, 'Offset to Mark Coverage table-from beginning of MarkLigPos subtable'),
|
||||||
|
('Offset', 'LigatureCoverage', None, None, 'Offset to Ligature Coverage table-from beginning of MarkLigPos subtable'),
|
||||||
|
('uint16', 'ClassCount', None, None, 'Number of defined mark classes'),
|
||||||
|
('Offset', 'MarkArray', None, None, 'Offset to MarkArray table-from beginning of MarkLigPos subtable'),
|
||||||
|
('Offset', 'LigatureArray', None, None, 'Offset to LigatureArray table-from beginning of MarkLigPos subtable'),
|
||||||
|
]),
|
||||||
|
|
||||||
|
('LigatureArray', [
|
||||||
|
('uint16', 'LigatureCount', None, None, 'Number of LigatureAttach table offsets'),
|
||||||
|
('Offset', 'LigatureAttach', 'LigatureCount', 0, 'Array of offsets to LigatureAttach tables-from beginning of LigatureArray table-ordered by LigatureCoverage Index'),
|
||||||
|
]),
|
||||||
|
|
||||||
|
('LigatureAttach', [
|
||||||
|
('uint16', 'ComponentCount', None, None, 'Number of ComponentRecords in this ligature'),
|
||||||
|
('struct', 'ComponentRecord', 'ComponentCount', 0, 'Array of Component records-ordered in writing direction'),
|
||||||
|
]),
|
||||||
|
|
||||||
|
('ComponentRecord', [
|
||||||
|
('Offset', 'LigatureAnchor', 'ClassCount', 0, 'Array of offsets (one per class) to Anchor tables-from beginning of LigatureAttach table-ordered by class-NULL if a component does not have an attachment for a class-zero-based array'),
|
||||||
|
]),
|
||||||
|
|
||||||
|
('MarkMarkPosFormat1', [
|
||||||
|
('uint16', 'PosFormat', None, None, 'Format identifier-format = 1'),
|
||||||
|
('Offset', 'Mark1Coverage', None, None, 'Offset to Combining Mark Coverage table-from beginning of MarkMarkPos subtable'),
|
||||||
|
('Offset', 'Mark2Coverage', None, None, 'Offset to Base Mark Coverage table-from beginning of MarkMarkPos subtable'),
|
||||||
|
('uint16', 'ClassCount', None, None, 'Number of Combining Mark classes defined'),
|
||||||
|
('Offset', 'Mark1Array', None, None, 'Offset to MarkArray table for Mark1-from beginning of MarkMarkPos subtable'),
|
||||||
|
('Offset', 'Mark2Array', None, None, 'Offset to Mark2Array table for Mark2-from beginning of MarkMarkPos subtable'),
|
||||||
|
]),
|
||||||
|
|
||||||
|
('Mark2Array', [
|
||||||
|
('uint16', 'Mark2Count', None, None, 'Number of Mark2 records'),
|
||||||
|
('struct', 'Mark2Record', 'Mark2Count', 0, 'Array of Mark2 records-in Coverage order'),
|
||||||
|
]),
|
||||||
|
|
||||||
|
('Mark2Record', [
|
||||||
|
('Offset', 'Mark2Anchor', 'ClassCount', 0, 'Array of offsets (one per class) to Anchor tables-from beginning of Mark2Array table-zero-based array'),
|
||||||
|
]),
|
||||||
|
|
||||||
|
('PosLookupRecord', [
|
||||||
|
('uint16', 'SequenceIndex', None, None, 'Index to input glyph sequence-first glyph = 0'),
|
||||||
|
('uint16', 'LookupListIndex', None, None, 'Lookup to apply to that position-zero-based'),
|
||||||
|
]),
|
||||||
|
|
||||||
|
('ContextPosFormat1', [
|
||||||
|
('uint16', 'PosFormat', None, None, 'Format identifier-format = 1'),
|
||||||
|
('Offset', 'Coverage', None, None, 'Offset to Coverage table-from beginning of ContextPos subtable'),
|
||||||
|
('uint16', 'PosRuleSetCount', None, None, 'Number of PosRuleSet tables'),
|
||||||
|
('Offset', 'PosRuleSet', 'PosRuleSetCount', 0, 'Array of offsets to PosRuleSet tables-from beginning of ContextPos subtable-ordered by Coverage Index'),
|
||||||
|
]),
|
||||||
|
|
||||||
|
('PosRuleSet', [
|
||||||
|
('uint16', 'PosRuleCount', None, None, 'Number of PosRule tables'),
|
||||||
|
('Offset', 'PosRule', 'PosRuleCount', 0, 'Array of offsets to PosRule tables-from beginning of PosRuleSet-ordered by preference'),
|
||||||
|
]),
|
||||||
|
|
||||||
|
('PosRule', [
|
||||||
|
('uint16', 'GlyphCount', None, None, 'Number of glyphs in the Input glyph sequence'),
|
||||||
|
('uint16', 'PosCount', None, None, 'Number of PosLookupRecords'),
|
||||||
|
('GlyphID', 'Input', 'GlyphCount', -1, 'Array of input GlyphIDs-starting with the second glyph'),
|
||||||
|
('struct', 'PosLookupRecord', 'PosCount', 0, 'Array of positioning lookups-in design order'),
|
||||||
|
]),
|
||||||
|
|
||||||
|
('ContextPosFormat2', [
|
||||||
|
('uint16', 'PosFormat', None, None, 'Format identifier-format = 2'),
|
||||||
|
('Offset', 'Coverage', None, None, 'Offset to Coverage table-from beginning of ContextPos subtable'),
|
||||||
|
('Offset', 'ClassDef', None, None, 'Offset to ClassDef table-from beginning of ContextPos subtable'),
|
||||||
|
('uint16', 'PosClassSetCnt', None, None, 'Number of PosClassSet tables'),
|
||||||
|
('Offset', 'PosClassSet', 'PosClassSetCnt', 0, 'Array of offsets to PosClassSet tables-from beginning of ContextPos subtable-ordered by class-may be NULL'),
|
||||||
|
]),
|
||||||
|
|
||||||
|
('PosClassSet', [
|
||||||
|
('uint16', 'PosClassRuleCnt', None, None, 'Number of PosClassRule tables'),
|
||||||
|
('Offset', 'PosClassRule', 'PosClassRuleCnt', 0, 'Array of offsets to PosClassRule tables-from beginning of PosClassSet-ordered by preference'),
|
||||||
|
]),
|
||||||
|
|
||||||
|
('PosClassRule', [
|
||||||
|
('uint16', 'GlyphCount', None, None, 'Number of glyphs to be matched'),
|
||||||
|
('uint16', 'PosCount', None, None, 'Number of PosLookupRecords'),
|
||||||
|
('uint16', 'Class', 'GlyphCount', -1, 'Array of classes-beginning with the second class-to be matched to the input glyph sequence'),
|
||||||
|
('struct', 'PosLookupRecord', 'PosCount', 0, 'Array of positioning lookups-in design order'),
|
||||||
|
]),
|
||||||
|
|
||||||
|
('ContextPosFormat3', [
|
||||||
|
('uint16', 'PosFormat', None, None, 'Format identifier-format = 3'),
|
||||||
|
('uint16', 'GlyphCount', None, None, 'Number of glyphs in the input sequence'),
|
||||||
|
('uint16', 'PosCount', None, None, 'Number of PosLookupRecords'),
|
||||||
|
('Offset', 'Coverage', 'GlyphCount', 0, 'Array of offsets to Coverage tables-from beginning of ContextPos subtable'),
|
||||||
|
('struct', 'PosLookupRecord', 'PosCount', 0, 'Array of positioning lookups-in design order'),
|
||||||
|
]),
|
||||||
|
|
||||||
|
('ChainContextPosFormat1', [
|
||||||
|
('uint16', 'PosFormat', None, None, 'Format identifier-format = 1'),
|
||||||
|
('Offset', 'Coverage', None, None, 'Offset to Coverage table-from beginning of ContextPos subtable'),
|
||||||
|
('uint16', 'ChainPosRuleSetCount', None, None, 'Number of ChainPosRuleSet tables'),
|
||||||
|
('Offset', 'ChainPosRuleSet', 'ChainPosRuleSetCount', 0, 'Array of offsets to ChainPosRuleSet tables-from beginning of ContextPos subtable-ordered by Coverage Index'),
|
||||||
|
]),
|
||||||
|
|
||||||
|
('ChainPosRuleSet', [
|
||||||
|
('uint16', 'ChainPosRuleCount', None, None, 'Number of ChainPosRule tables'),
|
||||||
|
('Offset', 'ChainPosRule', 'ChainPosRuleCount', 0, 'Array of offsets to ChainPosRule tables-from beginning of ChainPosRuleSet-ordered by preference'),
|
||||||
|
]),
|
||||||
|
|
||||||
|
('ChainPosRule', [
|
||||||
|
('uint16', 'BacktrackGlyphCount', None, None, 'Total number of glyphs in the backtrack sequence (number of glyphs to be matched before the first glyph)'),
|
||||||
|
('GlyphID', 'Backtrack', 'BacktrackGlyphCount', 0, "Array of backtracking GlyphID's (to be matched before the input sequence)"),
|
||||||
|
('uint16', 'InputGlyphCount', None, None, 'Total number of glyphs in the input sequence (includes the first glyph)'),
|
||||||
|
('GlyphID', 'Input', 'InputGlyphCount', -1, 'Array of input GlyphIDs (start with second glyph)'),
|
||||||
|
('uint16', 'LookaheadGlyphCount', None, None, 'Total number of glyphs in the look ahead sequence (number of glyphs to be matched after the input sequence)'),
|
||||||
|
('GlyphID', 'LookAhead', 'LookAheadGlyphCount', 0, "Array of lookahead GlyphID's (to be matched after the input sequence)"),
|
||||||
|
('uint16', 'PosCount', None, None, 'Number of PosLookupRecords'),
|
||||||
|
('struct', 'PosLookupRecord', 'PosCount', 0, 'Array of PosLookupRecords (in design order)'),
|
||||||
|
]),
|
||||||
|
|
||||||
|
('ChainContextPosFormat2', [
|
||||||
|
('uint16', 'PosFormat', None, None, 'Format identifier-format = 2'),
|
||||||
|
('Offset', 'Coverage', None, None, 'Offset to Coverage table-from beginning of ChainContextPos subtable'),
|
||||||
|
('Offset', 'BacktrackClassDef', None, None, 'Offset to ClassDef table containing backtrack sequence context-from beginning of ChainContextPos subtable'),
|
||||||
|
('Offset', 'InputClassDef', None, None, 'Offset to ClassDef table containing input sequence context-from beginning of ChainContextPos subtable'),
|
||||||
|
('Offset', 'LookaheadClassDef', None, None, 'Offset to ClassDef table containing lookahead sequence context-from beginning of ChainContextPos subtable'),
|
||||||
|
('uint16', 'ChainPosClassSetCnt', None, None, 'Number of ChainPosClassSet tables'),
|
||||||
|
('Offset', 'ChainPosClassSet', 'ChainPosClassSetCnt', 0, 'Array of offsets to ChainPosClassSet tables-from beginning of ChainContextPos subtable-ordered by input class-may be NULL'),
|
||||||
|
]),
|
||||||
|
|
||||||
|
('ChainPosClassSet', [
|
||||||
|
('uint16', 'ChainPosClassRuleCnt', None, None, 'Number of ChainPosClassRule tables'),
|
||||||
|
('Offset', 'ChainPosClassRule', 'ChainPosClassRuleCnt', 0, 'Array of offsets to ChainPosClassRule tables-from beginning of ChainPosClassSet-ordered by preference'),
|
||||||
|
]),
|
||||||
|
|
||||||
|
('ChainPosClassRule', [
|
||||||
|
('uint16', 'BacktrackGlyphCount', None, None, 'Total number of glyphs in the backtrack sequence (number of glyphs to be matched before the first glyph)'),
|
||||||
|
('uint16', 'Backtrack', 'BacktrackGlyphCount', 0, 'Array of backtracking classes(to be matched before the input sequence)'),
|
||||||
|
('uint16', 'InputGlyphCount', None, None, 'Total number of classes in the input sequence (includes the first class)'),
|
||||||
|
('uint16', 'Input', 'InputGlyphCount', -1, 'Array of input classes(start with second class; to be matched with the input glyph sequence)'),
|
||||||
|
('uint16', 'LookaheadGlyphCount', None, None, 'Total number of classes in the look ahead sequence (number of classes to be matched after the input sequence)'),
|
||||||
|
('uint16', 'LookAhead', 'LookAheadGlyphCount', 0, 'Array of lookahead classes(to be matched after the input sequence)'),
|
||||||
|
('uint16', 'PosCount', None, None, 'Number of PosLookupRecords'),
|
||||||
|
('struct', 'PosLookupRecord', 'ChainPosCount', 0, 'Array of PosLookupRecords (in design order)'),
|
||||||
|
]),
|
||||||
|
|
||||||
|
('ChainContextPosFormat3', [
|
||||||
|
('uint16', 'PosFormat', None, None, 'Format identifier-format = 3'),
|
||||||
|
('uint16', 'BacktrackGlyphCount', None, None, 'Number of glyphs in the backtracking sequence'),
|
||||||
|
('Offset', 'BacktrackCoverage', 'BacktrackGlyphCount', 0, 'Array of offsets to coverage tables in backtracking sequence, in glyph sequence order'),
|
||||||
|
('uint16', 'InputGlyphCount', None, None, 'Number of glyphs in input sequence'),
|
||||||
|
('Offset', 'InputCoverage', 'InputGlyphCount', 0, 'Array of offsets to coverage tables in input sequence, in glyph sequence order'),
|
||||||
|
('uint16', 'LookaheadGlyphCount', None, None, 'Number of glyphs in lookahead sequence'),
|
||||||
|
('Offset', 'LookaheadCoverage', 'LookaheadGlyphCount', 0, 'Array of offsets to coverage tables in lookahead sequence, in glyph sequence order'),
|
||||||
|
('uint16', 'PosCount', None, None, 'Number of PosLookupRecords'),
|
||||||
|
('struct', 'PosLookupRecord', 'PosCount', 0, 'Array of PosLookupRecords,in design order'),
|
||||||
|
]),
|
||||||
|
|
||||||
|
('ExtensionPosFormat1', [
|
||||||
|
('USHORT', 'PosFormat', None, None, 'Format identifier. Set to 1.'),
|
||||||
|
('USHORT', 'ExtensionLookupType', None, None, 'Lookup type of subtable referenced by ExtensionOffset (i.e. the extension subtable).'),
|
||||||
|
('ULONG', 'ExtensionOffset', None, None, 'Offset to the extension subtable, of lookup type ExtensionLookupType, relative to the start of the ExtensionPosFormat1 subtable.'),
|
||||||
|
]),
|
||||||
|
|
||||||
|
('ValueRecord', [
|
||||||
|
('int16', 'XPlacement', None, None, 'Horizontal adjustment for placement-in design units'),
|
||||||
|
('int16', 'YPlacement', None, None, 'Vertical adjustment for placement-in design units'),
|
||||||
|
('int16', 'XAdvance', None, None, 'Horizontal adjustment for advance-in design units (only used for horizontal writing)'),
|
||||||
|
('int16', 'YAdvance', None, None, 'Vertical adjustment for advance-in design units (only used for vertical writing)'),
|
||||||
|
('Offset', 'XPlaDevice', None, None, 'Offset to Device table for horizontal placement-measured from beginning of PosTable (may be NULL)'),
|
||||||
|
('Offset', 'YPlaDevice', None, None, 'Offset to Device table for vertical placement-measured from beginning of PosTable (may be NULL)'),
|
||||||
|
('Offset', 'XAdvDevice', None, None, 'Offset to Device table for horizontal advance-measured from beginning of PosTable (may be NULL)'),
|
||||||
|
('Offset', 'YAdvDevice', None, None, 'Offset to Device table for vertical advance-measured from beginning of PosTable (may be NULL)'),
|
||||||
|
]),
|
||||||
|
|
||||||
|
('AnchorFormat1', [
|
||||||
|
('uint16', 'AnchorFormat', None, None, 'Format identifier-format = 1'),
|
||||||
|
('int16', 'XCoordinate', None, None, 'Horizontal value-in design units'),
|
||||||
|
('int16', 'YCoordinate', None, None, 'Vertical value-in design units'),
|
||||||
|
]),
|
||||||
|
|
||||||
|
('AnchorFormat2', [
|
||||||
|
('uint16', 'AnchorFormat', None, None, 'Format identifier-format = 2'),
|
||||||
|
('int16', 'XCoordinate', None, None, 'Horizontal value-in design units'),
|
||||||
|
('int16', 'YCoordinate', None, None, 'Vertical value-in design units'),
|
||||||
|
('uint16', 'AnchorPoint', None, None, 'Index to glyph contour point'),
|
||||||
|
]),
|
||||||
|
|
||||||
|
('AnchorFormat3', [
|
||||||
|
('uint16', 'AnchorFormat', None, None, 'Format identifier-format = 3'),
|
||||||
|
('int16', 'XCoordinate', None, None, 'Horizontal value-in design units'),
|
||||||
|
('int16', 'YCoordinate', None, None, 'Vertical value-in design units'),
|
||||||
|
('Offset', 'XDeviceTable', None, None, 'Offset to Device table for X coordinate- from beginning of Anchor table (may be NULL)'),
|
||||||
|
('Offset', 'YDeviceTable', None, None, 'Offset to Device table for Y coordinate- from beginning of Anchor table (may be NULL)'),
|
||||||
|
]),
|
||||||
|
|
||||||
|
('MarkArray', [
|
||||||
|
('uint16', 'MarkCount', None, None, 'Number of MarkRecords'),
|
||||||
|
('struct', 'MarkRecord', 'MarkCount', 0, 'Array of MarkRecords-in Coverage order'),
|
||||||
|
]),
|
||||||
|
|
||||||
|
('MarkRecord', [
|
||||||
|
('uint16', 'Class', None, None, 'Class defined for this mark'),
|
||||||
|
('Offset', 'MarkAnchor', None, None, 'Offset to Anchor table-from beginning of MarkArray table'),
|
||||||
|
]),
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# gsub (generated from gsub.htm)
|
||||||
|
#
|
||||||
|
|
||||||
|
('GSUB', [
|
||||||
|
('Fixed', 'Version', None, None, 'Version of the GSUB table-initially set to 0x00010000'),
|
||||||
|
('Offset', 'ScriptList', None, None, 'Offset to ScriptList table-from beginning of GSUB table'),
|
||||||
|
('Offset', 'FeatureList', None, None, 'Offset to FeatureList table-from beginning of GSUB table'),
|
||||||
|
('Offset', 'LookupList', None, None, 'Offset to LookupList table-from beginning of GSUB table'),
|
||||||
|
]),
|
||||||
|
|
||||||
|
('SingleSubstFormat1', [
|
||||||
|
('uint16', 'SubstFormat', None, None, 'Format identifier-format = 1'),
|
||||||
|
('Offset', 'Coverage', None, None, 'Offset to Coverage table-from beginning of Substitution table'),
|
||||||
|
('int16', 'DeltaGlyphID', None, None, 'Add to original GlyphID to get substitute GlyphID'),
|
||||||
|
]),
|
||||||
|
|
||||||
|
('SingleSubstFormat2', [
|
||||||
|
('uint16', 'SubstFormat', None, None, 'Format identifier-format = 2'),
|
||||||
|
('Offset', 'Coverage', None, None, 'Offset to Coverage table-from beginning of Substitution table'),
|
||||||
|
('uint16', 'GlyphCount', None, None, 'Number of GlyphIDs in the Substitute array'),
|
||||||
|
('GlyphID', 'Substitute', 'GlyphCount', 0, 'Array of substitute GlyphIDs-ordered by Coverage Index'),
|
||||||
|
]),
|
||||||
|
|
||||||
|
('MultipleSubstFormat1', [
|
||||||
|
('uint16', 'SubstFormat', None, None, 'Format identifier-format = 1'),
|
||||||
|
('Offset', 'Coverage', None, None, 'Offset to Coverage table-from beginning of Substitution table'),
|
||||||
|
('uint16', 'SequenceCount', None, None, 'Number of Sequence table offsets in the Sequence array'),
|
||||||
|
('Offset', 'Sequence', 'SequenceCount', 0, 'Array of offsets to Sequence tables-from beginning of Substitution table-ordered by Coverage Index'),
|
||||||
|
]),
|
||||||
|
|
||||||
|
('Sequence', [
|
||||||
|
('uint16', 'GlyphCount', None, None, 'Number of GlyphIDs in the Substitute array. This should always be greater than 0.'),
|
||||||
|
('GlyphID', 'Substitute', 'GlyphCount', 0, 'String of GlyphIDs to substitute'),
|
||||||
|
]),
|
||||||
|
|
||||||
|
('AlternateSubstFormat1', [
|
||||||
|
('uint16', 'SubstFormat', None, None, 'Format identifier-format = 1'),
|
||||||
|
('Offset', 'Coverage', None, None, 'Offset to Coverage table-from beginning of Substitution table'),
|
||||||
|
('uint16', 'AlternateSetCount', None, None, 'Number of AlternateSet tables'),
|
||||||
|
('Offset', 'AlternateSet', 'AlternateSetCount', 0, 'Array of offsets to AlternateSet tables-from beginning of Substitution table-ordered by Coverage Index'),
|
||||||
|
]),
|
||||||
|
|
||||||
|
('AlternateSet', [
|
||||||
|
('uint16', 'GlyphCount', None, None, 'Number of GlyphIDs in the Alternate array'),
|
||||||
|
('GlyphID', 'Alternate', 'GlyphCount', 0, 'Array of alternate GlyphIDs-in arbitrary order'),
|
||||||
|
]),
|
||||||
|
|
||||||
|
('LigatureSubstFormat1', [
|
||||||
|
('uint16', 'SubstFormat', None, None, 'Format identifier-format = 1'),
|
||||||
|
('Offset', 'Coverage', None, None, 'Offset to Coverage table-from beginning of Substitution table'),
|
||||||
|
('uint16', 'LigSetCount', None, None, 'Number of LigatureSet tables'),
|
||||||
|
('Offset', 'LigatureSet', 'LigSetCount', 0, 'Array of offsets to LigatureSet tables-from beginning of Substitution table-ordered by Coverage Index'),
|
||||||
|
]),
|
||||||
|
|
||||||
|
('LigatureSet', [
|
||||||
|
('uint16', 'LigatureCount', None, None, 'Number of Ligature tables'),
|
||||||
|
('Offset', 'Ligature', 'LigatureCount', 0, 'Array of offsets to Ligature tables-from beginning of LigatureSet table-ordered by preference'),
|
||||||
|
]),
|
||||||
|
|
||||||
|
('Ligature', [
|
||||||
|
('GlyphID', 'LigGlyph', None, None, 'GlyphID of ligature to substitute'),
|
||||||
|
('uint16', 'CompCount', None, None, 'Number of components in the ligature'),
|
||||||
|
('GlyphID', 'Component', 'CompCount', -1, 'Array of component GlyphIDs-start with the second component-ordered in writing direction'),
|
||||||
|
]),
|
||||||
|
|
||||||
|
('SubstLookupRecord', [
|
||||||
|
('uint16', 'SequenceIndex', None, None, 'Index into current glyph sequence-first glyph = 0'),
|
||||||
|
('uint16', 'LookupListIndex', None, None, 'Lookup to apply to that position-zero-based'),
|
||||||
|
]),
|
||||||
|
|
||||||
|
('ContextSubstFormat1', [
|
||||||
|
('uint16', 'SubstFormat', None, None, 'Format identifier-format = 1'),
|
||||||
|
('Offset', 'Coverage', None, None, 'Offset to Coverage table-from beginning of Substitution table'),
|
||||||
|
('uint16', 'SubRuleSetCount', None, None, 'Number of SubRuleSet tables-must equal GlyphCount in Coverage table'),
|
||||||
|
('Offset', 'SubRuleSet', 'SubRuleSetCount', 0, 'Array of offsets to SubRuleSet tables-from beginning of Substitution table-ordered by Coverage Index'),
|
||||||
|
]),
|
||||||
|
|
||||||
|
('SubRuleSet', [
|
||||||
|
('uint16', 'SubRuleCount', None, None, 'Number of SubRule tables'),
|
||||||
|
('Offset', 'SubRule', 'SubRuleCount', 0, 'Array of offsets to SubRule tables-from beginning of SubRuleSet table-ordered by preference'),
|
||||||
|
]),
|
||||||
|
|
||||||
|
('SubRule', [
|
||||||
|
('uint16', 'GlyphCount', None, None, 'Total number of glyphs in input glyph sequence-includes the first glyph'),
|
||||||
|
('uint16', 'SubstCount', None, None, 'Number of SubstLookupRecords'),
|
||||||
|
('GlyphID', 'Input', 'GlyphCount', -1, 'Array of input GlyphIDs-start with second glyph'),
|
||||||
|
('struct', 'SubstLookupRecord', 'SubstCount', 0, 'Array of SubstLookupRecords-in design order'),
|
||||||
|
]),
|
||||||
|
|
||||||
|
('ContextSubstFormat2', [
|
||||||
|
('uint16', 'SubstFormat', None, None, 'Format identifier-format = 2'),
|
||||||
|
('Offset', 'Coverage', None, None, 'Offset to Coverage table-from beginning of Substitution table'),
|
||||||
|
('Offset', 'ClassDef', None, None, 'Offset to glyph ClassDef table-from beginning of Substitution table'),
|
||||||
|
('uint16', 'SubClassSetCnt', None, None, 'Number of SubClassSet tables'),
|
||||||
|
('Offset', 'SubClassSet', 'SubClassSetCnt', 0, 'Array of offsets to SubClassSet tables-from beginning of Substitution table-ordered by class-may be NULL'),
|
||||||
|
]),
|
||||||
|
|
||||||
|
('SubClassSet', [
|
||||||
|
('uint16', 'SubClassRuleCnt', None, None, 'Number of SubClassRule tables'),
|
||||||
|
('Offset', 'SubClassRule', 'SubClassRuleCount', 0, 'Array of offsets to SubClassRule tables-from beginning of SubClassSet-ordered by preference'),
|
||||||
|
]),
|
||||||
|
|
||||||
|
('SubClassRule', [
|
||||||
|
('uint16', 'GlyphCount', None, None, 'Total number of classes specified for the context in the rule-includes the first class'),
|
||||||
|
('uint16', 'SubstCount', None, None, 'Number of SubstLookupRecords'),
|
||||||
|
('uint16', 'Class', 'GlyphCount', -1, 'Array of classes-beginning with the second class-to be matched to the input glyph class sequence'),
|
||||||
|
('struct', 'SubstLookupRecord', 'SubstCount', 0, 'Array of Substitution lookups-in design order'),
|
||||||
|
]),
|
||||||
|
|
||||||
|
('ContextSubstFormat3', [
|
||||||
|
('uint16', 'SubstFormat', None, None, 'Format identifier-format = 3'),
|
||||||
|
('uint16', 'GlyphCount', None, None, 'Number of glyphs in the input glyph sequence'),
|
||||||
|
('uint16', 'SubstCount', None, None, 'Number of SubstLookupRecords'),
|
||||||
|
('Offset', 'Coverage', 'GlyphCount', 0, 'Array of offsets to Coverage table-from beginning of Substitution table-in glyph sequence order'),
|
||||||
|
('struct', 'SubstLookupRecord', 'SubstCount', 0, 'Array of SubstLookupRecords-in design order'),
|
||||||
|
]),
|
||||||
|
|
||||||
|
('ChainContextSubstFormat1', [
|
||||||
|
('uint16', 'SubstFormat', None, None, 'Format identifier-format = 1'),
|
||||||
|
('Offset', 'Coverage', None, None, 'Offset to Coverage table-from beginning of Substitution table'),
|
||||||
|
('uint16', 'ChainSubRuleSetCount', None, None, 'Number of ChainSubRuleSet tables-must equal GlyphCount in Coverage table'),
|
||||||
|
('Offset', 'ChainSubRuleSet', 'ChainSubRuleSetCount', 0, 'Array of offsets to ChainSubRuleSet tables-from beginning of Substitution table-ordered by Coverage Index'),
|
||||||
|
]),
|
||||||
|
|
||||||
|
('ChainSubRuleSet', [
|
||||||
|
('uint16', 'ChainSubRuleCount', None, None, 'Number of ChainSubRule tables'),
|
||||||
|
('Offset', 'ChainSubRule', 'ChainSubRuleCount', 0, 'Array of offsets to ChainSubRule tables-from beginning of ChainSubRuleSet table-ordered by preference'),
|
||||||
|
]),
|
||||||
|
|
||||||
|
('ChainSubRule', [
|
||||||
|
('uint16', 'BacktrackGlyphCount', None, None, 'Total number of glyphs in the backtrack sequence (number of glyphs to be matched before the first glyph)'),
|
||||||
|
('GlyphID', 'Backtrack', 'BacktrackGlyphCount', 0, "Array of backtracking GlyphID's (to be matched before the input sequence)"),
|
||||||
|
('uint16', 'InputGlyphCount', None, None, 'Total number of glyphs in the input sequence (includes the first glyph)'),
|
||||||
|
('GlyphID', 'Input', 'InputGlyphCount', -1, 'Array of input GlyphIDs (start with second glyph)'),
|
||||||
|
('uint16', 'LookaheadGlyphCount', None, None, 'Total number of glyphs in the look ahead sequence (number of glyphs to be matched after the input sequence)'),
|
||||||
|
('GlyphID', 'Lookahead', 'LookAheadGlyphCount', 0, "Array of lookahead GlyphID's (to be matched after the input sequence)"),
|
||||||
|
('uint16', 'SubstCount', None, None, 'Number of SubstLookupRecords'),
|
||||||
|
('struct', 'SubstLookupRecord', 'SubstCount', 0, 'Array of SubstLookupRecords (in design order)'),
|
||||||
|
]),
|
||||||
|
|
||||||
|
('ChainContextSubstFormat2', [
|
||||||
|
('uint16', 'SubstFormat', None, None, 'Format identifier-format = 2'),
|
||||||
|
('Offset', 'Coverage', None, None, 'Offset to Coverage table-from beginning of Substitution table'),
|
||||||
|
('Offset', 'BacktrackClassDef', None, None, 'Offset to glyph ClassDef table containing backtrack sequence data-from beginning of Substitution table'),
|
||||||
|
('Offset', 'InputClassDef', None, None, 'Offset to glyph ClassDef table containing input sequence data-from beginning of Substitution table'),
|
||||||
|
('Offset', 'LookaheadClassDef', None, None, 'Offset to glyph ClassDef table containing lookahead sequence data-from beginning of Substitution table'),
|
||||||
|
('uint16', 'ChainSubClassSetCnt', None, None, 'Number of ChainSubClassSet tables'),
|
||||||
|
('Offset', 'ChainSubClassSet', 'ChainSubClassSetCnt', 0, 'Array of offsets to ChainSubClassSet tables-from beginning of Substitution table-ordered by input class-may be NULL'),
|
||||||
|
]),
|
||||||
|
|
||||||
|
('ChainSubClassSet', [
|
||||||
|
('uint16', 'ChainSubClassRuleCnt', None, None, 'Number of ChainSubClassRule tables'),
|
||||||
|
('Offset', 'ChainSubClassRule', 'ChainSubClassRuleCount', 0, 'Array of offsets to ChainSubClassRule tables-from beginning of ChainSubClassSet-ordered by preference'),
|
||||||
|
]),
|
||||||
|
|
||||||
|
('ChainSubClassRule', [
|
||||||
|
('uint16', 'BacktrackGlyphCount', None, None, 'Total number of glyphs in the backtrack sequence (number of glyphs to be matched before the first glyph)'),
|
||||||
|
('uint16', 'Backtrack', 'BacktrackGlyphCount', 0, 'Array of backtracking classes(to be matched before the input sequence)'),
|
||||||
|
('uint16', 'InputGlyphCount', None, None, 'Total number of classes in the input sequence (includes the first class)'),
|
||||||
|
('uint16', 'Input', 'InputGlyphCount', -1, 'Array of input classes(start with second class; to be matched with the input glyph sequence)'),
|
||||||
|
('uint16', 'LookaheadGlyphCount', None, None, 'Total number of classes in the look ahead sequence (number of classes to be matched after the input sequence)'),
|
||||||
|
('uint16', 'LookAhead', 'LookAheadGlyphCount', 0, 'Array of lookahead classes(to be matched after the input sequence)'),
|
||||||
|
('uint16', 'SubstCount', None, None, 'Number of SubstLookupRecords'),
|
||||||
|
('struct', 'SubstLookupRecord', 'SubstCount', 0, 'Array of SubstLookupRecords (in design order)'),
|
||||||
|
]),
|
||||||
|
|
||||||
|
('ChainContextSubstFormat3', [
|
||||||
|
('uint16', 'SubstFormat', None, None, 'Format identifier-format = 3'),
|
||||||
|
('uint16', 'BacktrackGlyphCount', None, None, 'Number of glyphs in the backtracking sequence'),
|
||||||
|
('Offset', 'BacktrackCoverage', 'BacktrackGlyphCount', 0, 'Array of offsets to coverage tables in backtracking sequence, in glyph sequence order'),
|
||||||
|
('uint16', 'InputGlyphCount', None, None, 'Number of glyphs in input sequence'),
|
||||||
|
('Offset', 'InputCoverage', 'InputGlyphCount', 0, 'Array of offsets to coverage tables in input sequence, in glyph sequence order'),
|
||||||
|
('uint16', 'LookaheadGlyphCount', None, None, 'Number of glyphs in lookahead sequence'),
|
||||||
|
('Offset', 'LookaheadCoverage', 'LookaheadGlyphCount', 0, 'Array of offsets to coverage tables in lookahead sequence, in glyph sequence order'),
|
||||||
|
('uint16', 'SubstCount', None, None, 'Number of SubstLookupRecords'),
|
||||||
|
('struct', 'SubstLookupRecord', 'SubstCount', 0, 'Array of SubstLookupRecords, in design order'),
|
||||||
|
]),
|
||||||
|
|
||||||
|
('ExtensionSubstFormat1', [
|
||||||
|
('USHORT', 'SubstFormat', None, None, 'Format identifier. Set to 1.'),
|
||||||
|
('USHORT', 'ExtensionLookupType', None, None, 'Lookup type of subtable referenced by ExtensionOffset (i.e. the extension subtable).'),
|
||||||
|
('ULONG', 'ExtensionOffset', None, None, 'Offset to the extension subtable, of lookup type ExtensionLookupType, relative to the start of the ExtensionSubstFormat1 subtable.'),
|
||||||
|
]),
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# gdef (generated from gdef.htm)
|
||||||
|
#
|
||||||
|
|
||||||
|
('GDEF', [
|
||||||
|
('Fixed', 'Version', None, None, 'Version of the GDEF table-initially 0x00010000'),
|
||||||
|
('Offset', 'GlyphClassDef', None, None, 'Offset to class definition table for glyph type-from beginning of GDEF header (may be NULL)'),
|
||||||
|
('Offset', 'AttachList', None, None, 'Offset to list of glyphs with attachment points-from beginning of GDEF header (may be NULL)'),
|
||||||
|
('Offset', 'LigCaretList', None, None, 'Offset to list of positioning points for ligature carets-from beginning of GDEF header (may be NULL)'),
|
||||||
|
('Offset', 'MarkAttachClassDef', None, None, 'Offset to class definition table for mark attachment type-from beginning of GDEF header (may be NULL)'),
|
||||||
|
]),
|
||||||
|
|
||||||
|
('AttachList', [
|
||||||
|
('Offset', 'Coverage', None, None, 'Offset to Coverage table - from beginning of AttachList table'),
|
||||||
|
('uint16', 'GlyphCount', None, None, 'Number of glyphs with attachment points'),
|
||||||
|
('Offset', 'AttachPoint', 'GlyphCount', 0, 'Array of offsets to AttachPoint tables-from beginning of AttachList table-in Coverage Index order'),
|
||||||
|
]),
|
||||||
|
|
||||||
|
('AttachPoint', [
|
||||||
|
('uint16', 'PointCount', None, None, 'Number of attachment points on this glyph'),
|
||||||
|
('uint16', 'PointIndex', 'PointCount', 0, 'Array of contour point indices -in increasing numerical order'),
|
||||||
|
]),
|
||||||
|
|
||||||
|
('LigCaretList', [
|
||||||
|
('Offset', 'Coverage', None, None, 'Offset to Coverage table - from beginning of LigCaretList table'),
|
||||||
|
('uint16', 'LigGlyphCount', None, None, 'Number of ligature glyphs'),
|
||||||
|
('Offset', 'LigGlyph', 'LigGlyphCount', 0, 'Array of offsets to LigGlyph tables-from beginning of LigCaretList table-in Coverage Index order'),
|
||||||
|
]),
|
||||||
|
|
||||||
|
('LigGlyph', [
|
||||||
|
('uint16', 'CaretCount', None, None, 'Number of CaretValues for this ligature (components - 1)'),
|
||||||
|
('Offset', 'CaretValue', 'CaretCount', 0, 'Array of offsets to CaretValue tables-from beginning of LigGlyph table-in increasing coordinate order'),
|
||||||
|
]),
|
||||||
|
|
||||||
|
('CaretValueFormat1', [
|
||||||
|
('uint16', 'CaretValueFormat', None, None, 'Format identifier-format = 1'),
|
||||||
|
('int16', 'Coordinate', None, None, 'X or Y value, in design units'),
|
||||||
|
]),
|
||||||
|
|
||||||
|
('CaretValueFormat2', [
|
||||||
|
('uint16', 'CaretValueFormat', None, None, 'Format identifier-format = 2'),
|
||||||
|
('uint16', 'CaretValuePoint', None, None, 'Contour point index on glyph'),
|
||||||
|
]),
|
||||||
|
|
||||||
|
('CaretValueFormat3', [
|
||||||
|
('uint16', 'CaretValueFormat', None, None, 'Format identifier-format = 3'),
|
||||||
|
('int16', 'Coordinate', None, None, 'X or Y value, in design units'),
|
||||||
|
('Offset', 'DeviceTable', None, None, 'Offset to Device table for X or Y value-from beginning of CaretValue table'),
|
||||||
|
]),
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# base (generated from base.htm)
|
||||||
|
#
|
||||||
|
|
||||||
|
('BASE', [
|
||||||
|
('fixed32', 'Version', None, None, 'Version of the BASE table-initially 0x00010000'),
|
||||||
|
('Offset', 'HorizAxis', None, None, 'Offset to horizontal Axis table-from beginning of BASE table-may be NULL'),
|
||||||
|
('Offset', 'VertAxis', None, None, 'Offset to vertical Axis table-from beginning of BASE table-may be NULL'),
|
||||||
|
]),
|
||||||
|
|
||||||
|
('Axis', [
|
||||||
|
('Offset', 'BaseTagList', None, None, 'Offset to BaseTagList table-from beginning of Axis table-may be NULL'),
|
||||||
|
('Offset', 'BaseScriptList', None, None, 'Offset to BaseScriptList table-from beginning of Axis table'),
|
||||||
|
]),
|
||||||
|
|
||||||
|
('BaseTagList', [
|
||||||
|
('uint16', 'BaseTagCount', None, None, 'Number of baseline identification tags in this text direction-may be zero (0)'),
|
||||||
|
('Tag', 'BaselineTag', 'BaseTagCount', 0, 'Array of 4-byte baseline identification tags-must be in alphabetical order'),
|
||||||
|
]),
|
||||||
|
|
||||||
|
('BaseScriptList', [
|
||||||
|
('uint16', 'BaseScriptCount', None, None, 'Number of BaseScriptRecords defined'),
|
||||||
|
('struct', 'BaseScriptRecord', 'BaseScriptCount', 0, 'Array of BaseScriptRecords-in alphabetical order by BaseScriptTag'),
|
||||||
|
]),
|
||||||
|
|
||||||
|
('BaseScriptRecord', [
|
||||||
|
('Tag', 'BaseScriptTag', None, None, '4-byte script identification tag'),
|
||||||
|
('Offset', 'BaseScript', None, None, 'Offset to BaseScript table-from beginning of BaseScriptList'),
|
||||||
|
]),
|
||||||
|
|
||||||
|
('BaseScript', [
|
||||||
|
('Offset', 'BaseValues', None, None, 'Offset to BaseValues table-from beginning of BaseScript table-may be NULL'),
|
||||||
|
('Offset', 'DefaultMinMax', None, None, 'Offset to MinMax table- from beginning of BaseScript table-may be NULL'),
|
||||||
|
('uint16', 'BaseLangSysCount', None, None, 'Number of BaseLangSysRecords defined-may be zero (0)'),
|
||||||
|
('struct', 'BaseLangSysRecord', 'BaseLangSysCount', 0, 'Array of BaseLangSysRecords-in alphabetical order by BaseLangSysTag'),
|
||||||
|
]),
|
||||||
|
|
||||||
|
('BaseLangSysRecord', [
|
||||||
|
('Tag', 'BaseLangSysTag', None, None, '4-byte language system identification tag'),
|
||||||
|
('Offset', 'MinMax', None, None, 'Offset to MinMax table-from beginning of BaseScript table'),
|
||||||
|
]),
|
||||||
|
|
||||||
|
('BaseValues', [
|
||||||
|
('uint16', 'DefaultIndex', None, None, 'Index number of default baseline for this script-equals index position of baseline tag in BaselineArray of the BaseTagList'),
|
||||||
|
('uint16', 'BaseCoordCount', None, None, 'Number of BaseCoord tables defined-should equal BaseTagCount in the BaseTagList'),
|
||||||
|
('Offset', 'BaseCoord', 'BaseCoordCount', 0, 'Array of offsets to BaseCoord-from beginning of BaseValues table-order matches BaselineTag array in the BaseTagList'),
|
||||||
|
]),
|
||||||
|
|
||||||
|
('MinMax', [
|
||||||
|
('Offset', 'MinCoord', None, None, 'Offset to BaseCoord table-defines minimum extent value-from the beginning of MinMax table-may be NULL'),
|
||||||
|
('Offset', 'MaxCoord', None, None, 'Offset to BaseCoord table-defines maximum extent value-from the beginning of MinMax table-may be NULL'),
|
||||||
|
('uint16', 'FeatMinMaxCount', None, None, 'Number of FeatMinMaxRecords-may be zero (0)'),
|
||||||
|
('struct', 'FeatMinMaxRecord', 'FeatMinMaxCount', 0, 'Array of FeatMinMaxRecords-in alphabetical order, by FeatureTableTag'),
|
||||||
|
]),
|
||||||
|
|
||||||
|
('FeatMinMaxRecord', [
|
||||||
|
('Tag', 'FeatureTableTag', None, None, '4-byte feature identification tag-must match FeatureTag in FeatureList'),
|
||||||
|
('Offset', 'MinCoord', None, None, 'Offset to BaseCoord table-defines minimum extent value-from beginning of MinMax table-may be NULL'),
|
||||||
|
('Offset', 'MaxCoord', None, None, 'Offset to BaseCoord table-defines maximum extent value-from beginning of MinMax table-may be NULL'),
|
||||||
|
]),
|
||||||
|
|
||||||
|
('BaseCoordFormat1', [
|
||||||
|
('uint16', 'BaseCoordFormat', None, None, 'Format identifier-format = 1'),
|
||||||
|
('int16', 'Coordinate', None, None, 'X or Y value, in design units'),
|
||||||
|
]),
|
||||||
|
|
||||||
|
('BaseCoordFormat2', [
|
||||||
|
('uint16', 'BaseCoordFormat', None, None, 'Format identifier-format = 2'),
|
||||||
|
('int16', 'Coordinate', None, None, 'X or Y value, in design units'),
|
||||||
|
('GlyphID', 'ReferenceGlyph', None, None, 'GlyphID of control glyph'),
|
||||||
|
('uint16', 'BaseCoordPoint', None, None, 'Index of contour point on the ReferenceGlyph'),
|
||||||
|
]),
|
||||||
|
|
||||||
|
('BaseCoordFormat3', [
|
||||||
|
('uint16', 'BaseCoordFormat', None, None, 'Format identifier-format = 3'),
|
||||||
|
('int16', 'Coordinate', None, None, 'X or Y value, in design units'),
|
||||||
|
('Offset', 'DeviceTable', None, None, 'Offset to Device table for X or Y value'),
|
||||||
|
]),
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# jstf (generated from jstf.htm)
|
||||||
|
#
|
||||||
|
|
||||||
|
('JSTF', [
|
||||||
|
('fixed32', 'Version', None, None, 'Version of the JSTF table-initially set to 0x00010000'),
|
||||||
|
('uint16', 'JstfScriptCount', None, None, 'Number of JstfScriptRecords in this table'),
|
||||||
|
('struct', 'JstfScriptRecord', 'JstfScriptCount', 0, 'Array of JstfScriptRecords-in alphabetical order, by JstfScriptTag'),
|
||||||
|
]),
|
||||||
|
|
||||||
|
('JstfScriptRecord', [
|
||||||
|
('Tag', 'JstfScriptTag', None, None, '4-byte JstfScript identification'),
|
||||||
|
('Offset', 'JstfScript', None, None, 'Offset to JstfScript table-from beginning of JSTF Header'),
|
||||||
|
]),
|
||||||
|
|
||||||
|
('JstfScript', [
|
||||||
|
('Offset', 'ExtenderGlyph', None, None, 'Offset to ExtenderGlyph table-from beginning of JstfScript table-may be NULL'),
|
||||||
|
('Offset', 'DefJstfLangSys', None, None, 'Offset to Default JstfLangSys table-from beginning of JstfScript table-may be NULL'),
|
||||||
|
('uint16', 'JstfLangSysCount', None, None, 'Number of JstfLangSysRecords in this table- may be zero (0)'),
|
||||||
|
('struct', 'JstfLangSysRecord', 'JstfLangSysCount', 0, 'Array of JstfLangSysRecords-in alphabetical order, by JstfLangSysTag'),
|
||||||
|
]),
|
||||||
|
|
||||||
|
('JstfLangSysRecord', [
|
||||||
|
('Tag', 'JstfLangSysTag', None, None, '4-byte JstfLangSys identifier'),
|
||||||
|
('Offset', 'JstfLangSys', None, None, 'Offset to JstfLangSys table-from beginning of JstfScript table'),
|
||||||
|
]),
|
||||||
|
|
||||||
|
('ExtenderGlyph', [
|
||||||
|
('uint16', 'GlyphCount', None, None, 'Number of Extender Glyphs in this script'),
|
||||||
|
('GlyphID', 'ExtenderGlyph', 'GlyphCount', 0, 'GlyphIDs-in increasing numerical order'),
|
||||||
|
]),
|
||||||
|
|
||||||
|
('JstfLangSys', [
|
||||||
|
('uint16', 'JstfPriorityCnt', None, None, 'Number of JstfPriority tables'),
|
||||||
|
('Offset', 'JstfPriority', 'JstfPriorityCnt', 0, 'Array of offsets to JstfPriority tables-from beginning of JstfLangSys table-in priority order'),
|
||||||
|
]),
|
||||||
|
|
||||||
|
('JstfPriority', [
|
||||||
|
('Offset', 'ShrinkageEnableGSUB', None, None, 'Offset to Shrinkage Enable JstfGSUBModList table-from beginning of JstfPriority table-may be NULL'),
|
||||||
|
('Offset', 'ShrinkageDisableGSUB', None, None, 'Offset to Shrinkage Disable JstfGSUBModList table-from beginning of JstfPriority table-may be NULL'),
|
||||||
|
('Offset', 'ShrinkageEnableGPOS', None, None, 'Offset to Shrinkage Enable JstfGPOSModList table-from beginning of JstfPriority table-may be NULL'),
|
||||||
|
('Offset', 'ShrinkageDisableGPOS', None, None, 'Offset to Shrinkage Disable JstfGPOSModList table-from beginning of JstfPriority table-may be NULL'),
|
||||||
|
('Offset', 'ShrinkageJstfMax', None, None, 'Offset to Shrinkage JstfMax table-from beginning of JstfPriority table -may be NULL'),
|
||||||
|
('Offset', 'ExtensionEnableGSUB', None, None, 'Offset to Extension Enable JstfGSUBModList table-may be NULL'),
|
||||||
|
('Offset', 'ExtensionDisableGSUB', None, None, 'Offset to Extension Disable JstfGSUBModList table-from beginning of JstfPriority table-may be NULL'),
|
||||||
|
('Offset', 'ExtensionEnableGPOS', None, None, 'Offset to Extension Enable JstfGSUBModList table-may be NULL'),
|
||||||
|
('Offset', 'ExtensionDisableGPOS', None, None, 'Offset to Extension Disable JstfGSUBModList table-from beginning of JstfPriority table-may be NULL'),
|
||||||
|
('Offset', 'ExtensionJstfMax', None, None, 'Offset to Extension JstfMax table-from beginning of JstfPriority table -may be NULL'),
|
||||||
|
]),
|
||||||
|
|
||||||
|
('JstfGSUBModList', [
|
||||||
|
('uint16', 'LookupCount', None, None, 'Number of lookups for this modification'),
|
||||||
|
('uint16', 'GSUBLookupIndex', 'LookupCount', 0, 'Array of LookupIndex identifiers in GSUB-in increasing numerical order'),
|
||||||
|
]),
|
||||||
|
|
||||||
|
('JstfGPOSModList', [
|
||||||
|
('uint16', 'LookupCount', None, None, 'Number of lookups for this modification'),
|
||||||
|
('uint16', 'GPOSLookupIndex', 'LookupCount', 0, 'Array of LookupIndex identifiers in GPOS-in increasing numerical order'),
|
||||||
|
]),
|
||||||
|
|
||||||
|
('JstfMax', [
|
||||||
|
('uint16', 'LookupCount', None, None, 'Number of lookup Indices for this modification'),
|
||||||
|
('Offset', 'Lookup', 'LookupCount', 0, 'Array of offsets to GPOS-type lookup tables-from beginning of JstfMax table-in design order'),
|
||||||
|
]),
|
||||||
|
|
||||||
|
]
|
||||||
|
|
111
Lib/fontTools/ttLib/tables/otTables.py
Normal file
111
Lib/fontTools/ttLib/tables/otTables.py
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
"""fontTools.ttLib.tables.otTables -- A collection of classes representing the various
|
||||||
|
OpenType subtables.
|
||||||
|
|
||||||
|
Most are constructed upon import from data in otData.py. Most smartness is contained
|
||||||
|
in otBase.BaseTable.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from otBase import BaseTable, FormatSwitchingBaseTable
|
||||||
|
|
||||||
|
|
||||||
|
class LookupOrder(BaseTable):
|
||||||
|
"""Dummy class; this table isn't defined, but is used, and is always NULL."""
|
||||||
|
|
||||||
|
class FeatureParams(BaseTable):
|
||||||
|
"""Dummy class; this table isn't defined, but is used, and is always NULL."""
|
||||||
|
|
||||||
|
|
||||||
|
_equivalents = [
|
||||||
|
('MarkArray', ("Mark1Array",)),
|
||||||
|
('LangSys', ('DefaultLangSys',)),
|
||||||
|
('Coverage', ('MarkCoverage', 'BaseCoverage', 'LigatureCoverage', 'Mark1Coverage',
|
||||||
|
'Mark2Coverage', 'BacktrackCoverage', 'InputCoverage',
|
||||||
|
'LookaheadCoverage')),
|
||||||
|
('ClassDef', ('ClassDef1', 'ClassDef2', 'BacktrackClassDef', 'InputClassDef',
|
||||||
|
'LookaheadClassDef', 'GlyphClassDef', 'MarkAttachClassDef')),
|
||||||
|
('Anchor', ('EntryAnchor', 'ExitAnchor', 'BaseAnchor', 'LigatureAnchor',
|
||||||
|
'Mark2Anchor', 'MarkAnchor')),
|
||||||
|
('Device', ('XPlaDevice', 'YPlaDevice', 'XAdvDevice', 'YAdvDevice',
|
||||||
|
'XDeviceTable', 'YDeviceTable', 'DeviceTable')),
|
||||||
|
('Axis', ('HorizAxis', 'VertAxis',)),
|
||||||
|
('MinMax', ('DefaultMinMax',)),
|
||||||
|
('BaseCoord', ('MinCoord', 'MaxCoord',)),
|
||||||
|
('JstfLangSys', ('DefJstfLangSys',)),
|
||||||
|
('JstfGSUBModList', ('ShrinkageEnableGSUB', 'ShrinkageDisableGSUB', 'ExtensionEnableGSUB',
|
||||||
|
'ExtensionDisableGSUB',)),
|
||||||
|
('JstfGPOSModList', ('ShrinkageEnableGPOS', 'ShrinkageDisableGPOS', 'ExtensionEnableGPOS',
|
||||||
|
'ExtensionDisableGPOS',)),
|
||||||
|
('JstfMax', ('ShrinkageJstfMax', 'ExtensionJstfMax',)),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def _buildClasses():
|
||||||
|
import new, re
|
||||||
|
from otData import otData
|
||||||
|
|
||||||
|
formatPat = re.compile("([A-Za-z0-9]+)Format(\d+)$")
|
||||||
|
namespace = globals()
|
||||||
|
|
||||||
|
# populate module with classes
|
||||||
|
for name, table in otData:
|
||||||
|
baseClass = BaseTable
|
||||||
|
m = formatPat.match(name)
|
||||||
|
if m:
|
||||||
|
# XxxFormatN subtable, we only add the "base" table
|
||||||
|
name = m.group(1)
|
||||||
|
baseClass = FormatSwitchingBaseTable
|
||||||
|
if not namespace.has_key(name):
|
||||||
|
cls = new.classobj(name, (baseClass,), {})
|
||||||
|
namespace[name] = cls
|
||||||
|
|
||||||
|
for base, alts in _equivalents:
|
||||||
|
base = namespace[base]
|
||||||
|
for alt in alts:
|
||||||
|
namespace[alt] = new.classobj(alt, (base,), {})
|
||||||
|
|
||||||
|
global lookupTypes
|
||||||
|
lookupTypes = {
|
||||||
|
'GSUB': {
|
||||||
|
1: SingleSubst,
|
||||||
|
2: MultipleSubst,
|
||||||
|
3: AlternateSubst,
|
||||||
|
4: LigatureSubst,
|
||||||
|
5: ContextSubst,
|
||||||
|
6: ChainContextSubst,
|
||||||
|
7: ExtensionSubst,
|
||||||
|
},
|
||||||
|
'GPOS': {
|
||||||
|
1: SinglePos,
|
||||||
|
2: PairPos,
|
||||||
|
3: CursivePos,
|
||||||
|
4: MarkBasePos,
|
||||||
|
5: MarkLigPos,
|
||||||
|
6: MarkMarkPos,
|
||||||
|
7: ContextPos,
|
||||||
|
8: ChainContextPos,
|
||||||
|
9: ExtensionPos,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
lookupTypes['JSTF'] = lookupTypes['GPOS'] # JSTF contains GPOS
|
||||||
|
|
||||||
|
# add converters to classes
|
||||||
|
from otConverters import buildConverterList
|
||||||
|
for name, table in otData:
|
||||||
|
m = formatPat.match(name)
|
||||||
|
if m:
|
||||||
|
# XxxFormatN subtable, add converter to "base" table
|
||||||
|
name, format = m.groups()
|
||||||
|
format = int(format)
|
||||||
|
cls = namespace[name]
|
||||||
|
if not hasattr(cls, "converters"):
|
||||||
|
cls.converters = {}
|
||||||
|
cls.convertersByName = {}
|
||||||
|
converters, convertersByName = buildConverterList(table[1:], namespace)
|
||||||
|
cls.converters[format] = converters
|
||||||
|
cls.convertersByName[format] = convertersByName
|
||||||
|
else:
|
||||||
|
cls = namespace[name]
|
||||||
|
cls.converters, cls.convertersByName = buildConverterList(table, namespace)
|
||||||
|
|
||||||
|
|
||||||
|
_buildClasses()
|
Loading…
x
Reference in New Issue
Block a user