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):
|
||||
|
||||
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,
|
||||
}
|
||||
|
||||
class table_G_P_O_S_(BaseTTXConverter):
|
||||
pass
|
||||
|
@ -1,467 +1,5 @@
|
||||
import otCommon
|
||||
from otBase import BaseTTXConverter
|
||||
|
||||
|
||||
class table_G_S_U_B_(otCommon.base_GPOS_GSUB):
|
||||
|
||||
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)])
|
||||
|
||||
class table_G_S_U_B_(BaseTTXConverter):
|
||||
pass
|
||||
|
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