Work in progress on CFF, GPOS and GSUB. Since it's only partly working, it's diasabled by default.
git-svn-id: svn://svn.code.sf.net/p/fonttools/code/trunk@189 4cde692c-a291-49d1-8350-778aa11640f8
This commit is contained in:
parent
2a9c630193
commit
a36fd88a20
@ -2,6 +2,12 @@ import DefaultTable
|
||||
from fontTools import cffLib
|
||||
|
||||
|
||||
# temporary switch:
|
||||
# - if true use possibly incomplete compile/decompile/toXML/fromXML implementation
|
||||
# - if false use DefaultTable, ie. dump as hex.
|
||||
TESTING_CFF = 0
|
||||
|
||||
|
||||
class table_C_F_F_(DefaultTable.DefaultTable):
|
||||
|
||||
def __init__(self, tag):
|
||||
@ -28,11 +34,11 @@ class table_C_F_F_(DefaultTable.DefaultTable):
|
||||
self.cff.fonts[self.cff.fontNames[0]].setGlyphOrder(glyphOrder)
|
||||
|
||||
def toXML(self, writer, otFont, progress=None):
|
||||
if "disableCFFdump":
|
||||
if TESTING_CFF:
|
||||
self.cff.toXML(writer, progress)
|
||||
else:
|
||||
# dump as hex as long as we can't compile
|
||||
DefaultTable.DefaultTable.toXML(self, writer, otFont)
|
||||
else:
|
||||
self.cff.toXML(writer, progress)
|
||||
|
||||
#def fromXML(self, (name, attrs, content), otFont):
|
||||
# xxx
|
||||
|
@ -10,17 +10,39 @@ class table_G_P_O_S_(otCommon.base_GPOS_GSUB):
|
||||
class SinglePos:
|
||||
|
||||
def decompile(self, reader, otFont):
|
||||
pass
|
||||
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 compile(self, otFont):
|
||||
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("XXX")
|
||||
xmlWriter.comment("NotImplemented")
|
||||
xmlWriter.newline()
|
||||
|
||||
def fromXML(self, (name, attrs, content), otFont):
|
||||
xxx
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
class PairPos:
|
||||
@ -43,11 +65,8 @@ class PairPos:
|
||||
self.pairs = pairs = {}
|
||||
for i in range(reader.readUShort()):
|
||||
firstGlyphName = glyphNames[i]
|
||||
offset = reader.readOffset()
|
||||
setData = reader.getSubString(offset)
|
||||
set = PairSet()
|
||||
set.decompile(setData, otFont, valueFactory1, valueFactory2)
|
||||
pairs[firstGlyphName] = set.values
|
||||
set = reader.readTable(PairSet, otFont, valueFactory1, valueFactory2)
|
||||
pairs[firstGlyphName] = set.getValues()
|
||||
|
||||
def decompileFormat2(self, reader, otFont):
|
||||
coverage = reader.readTable(otCommon.CoverageTable, otFont)
|
||||
@ -62,14 +81,48 @@ class PairPos:
|
||||
for i in range(class1Count):
|
||||
row = {}
|
||||
for j in range(class2Count):
|
||||
value1 = valueFactory1.getValueRecord(reader)
|
||||
value2 = valueFactory2.getValueRecord(reader)
|
||||
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, otFont):
|
||||
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):
|
||||
@ -86,38 +139,56 @@ class PairPos:
|
||||
pairs.sort()
|
||||
for firstGlyph, secondGlyphs in pairs:
|
||||
for secondGlyph, value1, value2 in secondGlyphs:
|
||||
#XXXXXXXXX
|
||||
xmlWriter.begintag("Pair", first=firstGlyph, second=secondGlyph)
|
||||
xmlWriter.newline()
|
||||
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("XXX")
|
||||
xmlWriter.comment("NotImplemented")
|
||||
xmlWriter.newline()
|
||||
|
||||
def fromXML(self, (name, attrs, content), otFont):
|
||||
xxx
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
class PairSet:
|
||||
|
||||
def decompile(self, reader, otFont, valueFactory1, valueFactory2):
|
||||
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 = valueFactory1.getValueRecord(reader)
|
||||
value2 = valueFactory2.getValueRecord(reader)
|
||||
value1 = self.valueFactory1.readValueRecord(reader, otFont)
|
||||
value2 = self.valueFactory2.readValueRecord(reader, otFont)
|
||||
values.append((secondGlyphName, value1, value2))
|
||||
|
||||
def compile(self, otFont):
|
||||
xxx
|
||||
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)
|
||||
|
||||
|
||||
#
|
||||
# ------------------
|
||||
@ -126,81 +197,180 @@ class PairSet:
|
||||
class CursivePos:
|
||||
|
||||
def decompile(self, reader, otFont):
|
||||
pass
|
||||
xxx
|
||||
|
||||
def compile(self, otFont):
|
||||
def compile(self, writer, otFont):
|
||||
xxx
|
||||
|
||||
def toXML(self, xmlWriter, otFont):
|
||||
xmlWriter.comment("XXX")
|
||||
xmlWriter.comment("NotImplemented")
|
||||
xmlWriter.newline()
|
||||
|
||||
|
||||
class MarkBasePos:
|
||||
|
||||
def decompile(self, reader, otFont):
|
||||
pass
|
||||
xxx
|
||||
|
||||
def compile(self, otFont):
|
||||
def compile(self, writer, otFont):
|
||||
xxx
|
||||
|
||||
def toXML(self, xmlWriter, otFont):
|
||||
xmlWriter.comment("XXX")
|
||||
xmlWriter.comment("NotImplemented")
|
||||
xmlWriter.newline()
|
||||
|
||||
|
||||
class MarkLigPos:
|
||||
|
||||
def decompile(self, reader, otFont):
|
||||
pass
|
||||
xxx
|
||||
|
||||
def compile(self, otFont):
|
||||
def compile(self, writer, otFont):
|
||||
xxx
|
||||
|
||||
def toXML(self, xmlWriter, otFont):
|
||||
xmlWriter.comment("XXX")
|
||||
xmlWriter.comment("NotImplemented")
|
||||
xmlWriter.newline()
|
||||
|
||||
|
||||
class MarkMarkPos:
|
||||
|
||||
def decompile(self, reader, otFont):
|
||||
pass
|
||||
xxx
|
||||
|
||||
def compile(self, otFont):
|
||||
def compile(self, writer, otFont):
|
||||
xxx
|
||||
|
||||
def toXML(self, xmlWriter, otFont):
|
||||
xmlWriter.comment("XXX")
|
||||
xmlWriter.comment("NotImplemented")
|
||||
xmlWriter.newline()
|
||||
|
||||
|
||||
class ContextPos:
|
||||
|
||||
def decompile(self, reader, otFont):
|
||||
pass
|
||||
xxx
|
||||
|
||||
def compile(self, otFont):
|
||||
def compile(self, writer, otFont):
|
||||
xxx
|
||||
|
||||
def toXML(self, xmlWriter, otFont):
|
||||
xmlWriter.comment("XXX")
|
||||
xmlWriter.comment("NotImplemented")
|
||||
xmlWriter.newline()
|
||||
|
||||
|
||||
class ChainContextPos:
|
||||
|
||||
def decompile(self, reader, otFont):
|
||||
pass
|
||||
xxx
|
||||
|
||||
def compile(self, otFont):
|
||||
def compile(self, writer, otFont):
|
||||
xxx
|
||||
|
||||
def toXML(self, xmlWriter, otFont):
|
||||
xmlWriter.comment("XXX")
|
||||
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,
|
||||
@ -212,83 +382,3 @@ lookupTypeClasses = {
|
||||
8: ChainContextPos,
|
||||
}
|
||||
|
||||
|
||||
valueRecordFormat = [
|
||||
# Mask Name struct format char
|
||||
(0x0001, "XPlacement", "h"),
|
||||
(0x0002, "YPlacement", "h"),
|
||||
(0x0004, "XAdvance", "h"),
|
||||
(0x0008, "YAdvance", "h"),
|
||||
(0x0010, "XPlaDevice", "H"),
|
||||
(0x0020, "YPlaDevice", "H"),
|
||||
(0x0040, "XAdvDevice", "H"),
|
||||
(0x0080, "YAdvDevice", "H"),
|
||||
# reserved:
|
||||
(0x0100, "Reserved1", "H"),
|
||||
(0x0200, "Reserved2", "H"),
|
||||
(0x0400, "Reserved3", "H"),
|
||||
(0x0800, "Reserved4", "H"),
|
||||
(0x1000, "Reserved5", "H"),
|
||||
(0x2000, "Reserved6", "H"),
|
||||
(0x4000, "Reserved7", "H"),
|
||||
(0x8000, "Reserved8", "H"),
|
||||
]
|
||||
|
||||
|
||||
class ValueRecordFactory:
|
||||
|
||||
def __init__(self, valueFormat):
|
||||
format = ">"
|
||||
names = []
|
||||
for mask, name, formatChar in valueRecordFormat:
|
||||
if valueFormat & mask:
|
||||
names.append(name)
|
||||
format = format + formatChar
|
||||
self.names, self.format = names, format
|
||||
self.size = 2 * len(names)
|
||||
|
||||
def getValueRecord(self, reader):
|
||||
names = self.names
|
||||
if not names:
|
||||
return None
|
||||
values = reader.readStruct(self.format, self.size)
|
||||
values = map(int, values)
|
||||
valueRecord = ValueRecord()
|
||||
items = map(None, names, values)
|
||||
for name, value in items:
|
||||
setattr(valueRecord, name, value)
|
||||
return valueRecord
|
||||
|
||||
|
||||
class ValueRecord:
|
||||
# see ValueRecordFactory
|
||||
|
||||
def __nonzero__(self):
|
||||
for value in self.__dict__.values():
|
||||
if value:
|
||||
return 1
|
||||
return 0
|
||||
|
||||
def toXML(self, xmlWriter, otFont):
|
||||
simpleItems = []
|
||||
for mask, name, format in valueRecordFormat[:4]: # "simple" values
|
||||
if hasattr(self, name):
|
||||
simpleItems.append((name, getattr(self, name)))
|
||||
deviceItems = []
|
||||
for mask, name, format in valueRecordFormat[4:8]: # device records
|
||||
if hasattr(self, name):
|
||||
deviceItems.append((name, getattr(self, name)))
|
||||
if deviceItems:
|
||||
xmlWriter.begintag("ValueRecord", simpleItems)
|
||||
xmlWriter.newline()
|
||||
for name, deviceRecord in deviceItems:
|
||||
xxx
|
||||
xmlWriter.endtag("ValueRecord")
|
||||
xmlWriter.newline()
|
||||
else:
|
||||
xmlWriter.simpletag("ValueRecord", simpleItems)
|
||||
xmlWriter.newline()
|
||||
|
||||
def __repr__(self):
|
||||
return "<ValueRecord>"
|
||||
|
||||
|
@ -41,9 +41,33 @@ class SingleSubst:
|
||||
input = glyphNames[i]
|
||||
substitutions[input] = output
|
||||
|
||||
def compile(self, otFont):
|
||||
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()
|
||||
@ -52,7 +76,7 @@ class SingleSubst:
|
||||
xmlWriter.newline()
|
||||
|
||||
def fromXML(self, (name, attrs, content), otFont):
|
||||
xxx
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
class MultipleSubst:
|
||||
@ -67,9 +91,9 @@ class MultipleSubst:
|
||||
self.substitutions = substitutions = {}
|
||||
for i in range(sequenceCount):
|
||||
sequence = reader.readTable(Sequence, otFont)
|
||||
substitutions[glyphNames[i]] = sequence.glyphs
|
||||
substitutions[glyphNames[i]] = sequence.getGlyphs()
|
||||
|
||||
def compile(self, otFont):
|
||||
def compile(self, writer, otFont):
|
||||
xxx
|
||||
|
||||
def toXML(self, xmlWriter, otFont):
|
||||
@ -83,12 +107,15 @@ class MultipleSubst:
|
||||
|
||||
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, otFont):
|
||||
def compile(self, writer, otFont):
|
||||
xxx
|
||||
|
||||
|
||||
@ -102,16 +129,30 @@ class AlternateSubst:
|
||||
coverage = reader.readTable(otCommon.CoverageTable, otFont)
|
||||
glyphNames = coverage.getGlyphNames()
|
||||
alternateSetCount = reader.readUShort()
|
||||
self.alternateSet = alternateSet = {}
|
||||
self.alternateSets = alternateSets = {}
|
||||
for i in range(alternateSetCount):
|
||||
set = reader.readTable(AlternateSet, otFont)
|
||||
alternateSet[glyphNames[i]] = set.glyphs
|
||||
alternateSets[glyphNames[i]] = set.getGlyphs()
|
||||
|
||||
def compile(self, otFont):
|
||||
xxx
|
||||
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.alternateSet.items()
|
||||
alternates = self.alternateSets.items()
|
||||
alternates.sort()
|
||||
for input, substList in alternates:
|
||||
xmlWriter.begintag("AlternateSet", [("in", input)])
|
||||
@ -125,22 +166,31 @@ class AlternateSubst:
|
||||
|
||||
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, otFont):
|
||||
xxx
|
||||
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):
|
||||
format = reader.readUShort()
|
||||
if format <> 1:
|
||||
self.format = reader.readUShort()
|
||||
if self.format <> 1:
|
||||
from fontTools import ttLib
|
||||
raise ttLib.TTLibError, "unknown LigatureSubst format: %d" % format
|
||||
raise ttLib.TTLibError, "unknown LigatureSubst format: %d" % self.format
|
||||
coverage = reader.readTable(otCommon.CoverageTable, otFont)
|
||||
glyphNames = coverage.getGlyphNames()
|
||||
ligSetCount = reader.readUShort()
|
||||
@ -148,11 +198,33 @@ class LigatureSubst:
|
||||
for i in range(ligSetCount):
|
||||
firstGlyph = glyphNames[i]
|
||||
ligSet = reader.readTable(LigatureSet, otFont)
|
||||
for ligatureGlyph, components in ligSet.ligatures:
|
||||
ligatures.append(((firstGlyph,) + tuple(components)), ligatureGlyph)
|
||||
for components, ligatureGlyph in ligSet.getLigatures():
|
||||
ligatures.append((((firstGlyph,) + tuple(components)), ligatureGlyph))
|
||||
|
||||
def compile(self, otFont):
|
||||
xxx
|
||||
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
|
||||
@ -163,19 +235,39 @@ class LigatureSubst:
|
||||
|
||||
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.ligatureGlyph, lig.components))
|
||||
ligatures.append(lig.get())
|
||||
|
||||
def compile(self, otFont):
|
||||
xxx
|
||||
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()
|
||||
@ -183,8 +275,12 @@ class Ligature:
|
||||
for i in range(compCount-1):
|
||||
components.append(otFont.getGlyphName(reader.readUShort()))
|
||||
|
||||
def compile(self, otFont):
|
||||
xxx
|
||||
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:
|
||||
@ -219,11 +315,11 @@ class ContextSubst:
|
||||
lookupRecord.decompile(reader, otFont)
|
||||
substitutions.append((coverage[i].getGlyphNames(), lookupRecord))
|
||||
|
||||
def compile(self, otFont):
|
||||
def compile(self, writer, otFont):
|
||||
xxx
|
||||
|
||||
def toXML(self, xmlWriter, otFont):
|
||||
xmlWriter.comment("XXX")
|
||||
xmlWriter.comment("NotImplemented")
|
||||
xmlWriter.newline()
|
||||
|
||||
|
||||
@ -242,19 +338,63 @@ class ChainContextSubst:
|
||||
raise ttLib.TTLibError, "unknown ChainContextSubst format: %d" % self.format
|
||||
|
||||
def decompileFormat1(self, reader, otFont):
|
||||
pass
|
||||
XXX
|
||||
|
||||
def decompileFormat2(self, reader, otFont):
|
||||
pass
|
||||
XXX
|
||||
|
||||
def decompileFormat3(self, reader, otFont):
|
||||
pass
|
||||
backtrackGlyphCount = reader.readUShort()
|
||||
backtrackCoverage = reader.readTableArray(backtrackGlyphCount, otCommon.CoverageTable, otFont)
|
||||
self.backtrack = otCommon.unpackCoverageArray(backtrackCoverage)
|
||||
|
||||
def compile(self, otFont):
|
||||
xxx
|
||||
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 = reader.readTableArray(substCount, SubstLookupRecord, otFont)
|
||||
|
||||
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))
|
||||
writer.writeTableArray(self.substitutions, otFont)
|
||||
|
||||
def toXML(self, xmlWriter, otFont):
|
||||
xmlWriter.comment("XXX")
|
||||
xmlWriter.comment("NotImplemented")
|
||||
xmlWriter.newline()
|
||||
|
||||
|
||||
@ -278,6 +418,7 @@ class SubstLookupRecord:
|
||||
self.sequenceIndex = reader.readUShort()
|
||||
self.lookupListIndex = reader.readUShort()
|
||||
|
||||
def compile(self, otFont):
|
||||
xxx
|
||||
def compile(self, writer, otFont):
|
||||
writer.writeUShort(self.sequenceIndex)
|
||||
writer.writeUShort(self.lookupListIndex)
|
||||
|
||||
|
@ -1,10 +1,16 @@
|
||||
"""ttLib.tables.otCommon.py -- Various data structures used by various OpenType tables.
|
||||
"""
|
||||
"""fontTools.ttLib.tables.otCommon.py -- Various data structures used
|
||||
by various OpenType tables."""
|
||||
|
||||
import struct, sstruct
|
||||
import string
|
||||
import DefaultTable
|
||||
from fontTools import ttLib
|
||||
|
||||
# temporary switch:
|
||||
# - if true use possibly incomplete compile/decompile/toXML/fromXML implementation
|
||||
# - if false use DefaultTable, ie. dump as hex.
|
||||
TESTING_OT = 0
|
||||
|
||||
|
||||
class base_GPOS_GSUB(DefaultTable.DefaultTable):
|
||||
|
||||
@ -13,8 +19,7 @@ class base_GPOS_GSUB(DefaultTable.DefaultTable):
|
||||
version = 0x00010000
|
||||
|
||||
def decompile(self, data, otFont):
|
||||
self.data = data # while work is in progress, dump as hex
|
||||
return
|
||||
#self.data = data # handy for debugging
|
||||
reader = OTTableReader(data)
|
||||
self.version = reader.readLong()
|
||||
if self.version <> 0x00010000:
|
||||
@ -25,10 +30,12 @@ class base_GPOS_GSUB(DefaultTable.DefaultTable):
|
||||
self.lookupList = reader.readTable(LookupList, otFont, self.tableTag)
|
||||
|
||||
def compile(self, otFont):
|
||||
return self.data
|
||||
|
||||
|
||||
class Dummy:
|
||||
writer = OTTableWriter()
|
||||
writer.writeLong(self.version)
|
||||
writer.writeTable(self.scriptList, otFont)
|
||||
writer.writeTable(self.featureList, otFont)
|
||||
writer.writeTable(self.lookupList, otFont)
|
||||
return writer.getData()
|
||||
|
||||
def toXML(self, xmlWriter, otFont):
|
||||
names = [("ScriptList", "scriptList"),
|
||||
@ -45,9 +52,13 @@ class Dummy:
|
||||
xmlWriter.newline()
|
||||
|
||||
def fromXML(self, (name, attrs, content), otFont):
|
||||
xxx
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
if not TESTING_OT:
|
||||
# disable the GPOS/GSUB code, dump as hex.
|
||||
base_GPOS_GSUB = DefaultTable.DefaultTable
|
||||
|
||||
#
|
||||
# Script List and subtables
|
||||
#
|
||||
@ -61,8 +72,9 @@ class ScriptList:
|
||||
scriptCount = reader.readUShort()
|
||||
self.scripts = reader.readTagList(scriptCount, Script, otFont)
|
||||
|
||||
def compile(self, otFont):
|
||||
XXXXXX
|
||||
def compile(self, writer, otFont):
|
||||
writer.writeUShort(len(self.scripts))
|
||||
writer.writeTagList(self.scripts, otFont)
|
||||
|
||||
def toXML(self, xmlWriter, otFont):
|
||||
for tag, script in self.scripts:
|
||||
@ -73,19 +85,20 @@ class ScriptList:
|
||||
xmlWriter.newline()
|
||||
|
||||
def fromXML(self, (name, attrs, content), otFont):
|
||||
xxx
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
class Script:
|
||||
|
||||
def decompile(self, reader, otFont):
|
||||
self.defaultLangSystem = None
|
||||
self.defaultLangSystem = reader.readTable(LanguageSystem, otFont)
|
||||
langSysCount = reader.readUShort()
|
||||
self.languageSystems = reader.readTagList(langSysCount, LanguageSystem, otFont)
|
||||
|
||||
def compile(self, otFont):
|
||||
XXXXX
|
||||
def compile(self, writer, otFont):
|
||||
writer.writeTable(self.defaultLangSystem, otFont)
|
||||
writer.writeUShort(len(self.languageSystems))
|
||||
writer.writeTagList(self.languageSystems, otFont)
|
||||
|
||||
def toXML(self, xmlWriter, otFont):
|
||||
xmlWriter.begintag("DefaultLanguageSystem")
|
||||
@ -109,8 +122,11 @@ class LanguageSystem:
|
||||
featureCount = reader.readUShort()
|
||||
self.featureIndex = reader.readUShortArray(featureCount)
|
||||
|
||||
def compile(self, otFont):
|
||||
xxx
|
||||
def compile(self, writer, otFont):
|
||||
writer.writeUShort(self.lookupOrder)
|
||||
writer.writeUShort(self.reqFeatureIndex)
|
||||
writer.writeUShort(len(self.featureIndex))
|
||||
writer.writeUShortArray(self.featureIndex)
|
||||
|
||||
def toXML(self, xmlWriter, otFont):
|
||||
xmlWriter.simpletag("LookupOrder", value=self.lookupOrder)
|
||||
@ -135,8 +151,9 @@ class FeatureList:
|
||||
featureCount = reader.readUShort()
|
||||
self.features = reader.readTagList(featureCount, Feature, otFont)
|
||||
|
||||
def compile(self, otFont):
|
||||
XXXXX
|
||||
def compile(self, writer, otFont):
|
||||
writer.writeUShort(len(self.features))
|
||||
writer.writeTagList(self.features, otFont)
|
||||
|
||||
def toXML(self, xmlWriter, otFont):
|
||||
for index in range(len(self.features)):
|
||||
@ -148,7 +165,7 @@ class FeatureList:
|
||||
xmlWriter.newline()
|
||||
|
||||
def fromXML(self, (name, attrs, content), otFont):
|
||||
xxx
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
class Feature:
|
||||
@ -158,8 +175,10 @@ class Feature:
|
||||
lookupCount = reader.readUShort()
|
||||
self.lookupListIndex = reader.readUShortArray(lookupCount)
|
||||
|
||||
def compile(self, otFont):
|
||||
XXXXX
|
||||
def compile(self, writer, otFont):
|
||||
writer.writeUShort(self.featureParams)
|
||||
writer.writeUShort(len(self.lookupListIndex))
|
||||
writer.writeUShortArray(self.lookupListIndex)
|
||||
|
||||
def toXML(self, xmlWriter, otFont):
|
||||
xmlWriter.simpletag("FeatureParams", value=hex(self.featureParams))
|
||||
@ -169,7 +188,7 @@ class Feature:
|
||||
xmlWriter.newline()
|
||||
|
||||
def fromXML(self, (name, attrs, content), otFont):
|
||||
xxx
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
#
|
||||
@ -183,12 +202,11 @@ class LookupList:
|
||||
|
||||
def decompile(self, reader, otFont):
|
||||
lookupCount = reader.readUShort()
|
||||
self.lookup = lookup = []
|
||||
for i in range(lookupCount):
|
||||
lookup.append(reader.readTable(LookupTable, otFont, self.parentTag))
|
||||
self.lookup = reader.readTableArray(lookupCount, LookupTable, otFont, self.parentTag)
|
||||
|
||||
def compile(self, otFont):
|
||||
XXXXX
|
||||
def compile(self, writer, otFont):
|
||||
writer.writeUShort(len(self.lookup))
|
||||
writer.writeTableArray(self.lookup, otFont)
|
||||
|
||||
def toXML(self, xmlWriter, otFont):
|
||||
for i in range(len(self.lookup)):
|
||||
@ -202,7 +220,7 @@ class LookupList:
|
||||
xmlWriter.newline()
|
||||
|
||||
def fromXML(self, (name, attrs, content), otFont):
|
||||
xxx
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
class LookupTable:
|
||||
@ -215,13 +233,14 @@ class LookupTable:
|
||||
self.lookupType = reader.readUShort()
|
||||
self.lookupFlag = reader.readUShort()
|
||||
subTableCount = reader.readUShort()
|
||||
self.subTables = subTables = []
|
||||
lookupTypeClass = parentTable.getLookupTypeClass(self.lookupType)
|
||||
for i in range(subTableCount):
|
||||
subTables.append(reader.readTable(lookupTypeClass, otFont))
|
||||
self.subTables = reader.readTableArray(subTableCount, lookupTypeClass, otFont)
|
||||
|
||||
def compile(self, otFont):
|
||||
XXXXXX
|
||||
def compile(self, writer, otFont):
|
||||
writer.writeUShort(self.lookupType)
|
||||
writer.writeUShort(self.lookupFlag)
|
||||
writer.writeUShort(len(self.subTables))
|
||||
writer.writeTableArray(self.subTables, otFont)
|
||||
|
||||
def __repr__(self):
|
||||
if not hasattr(self, "lookupTypeName"):
|
||||
@ -241,7 +260,7 @@ class LookupTable:
|
||||
xmlWriter.newline()
|
||||
|
||||
def fromXML(self, (name, attrs, content), otFont):
|
||||
xxx
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
#
|
||||
@ -256,6 +275,14 @@ class CoverageTable:
|
||||
def getGlyphNames(self):
|
||||
return self.glyphNames
|
||||
|
||||
def setGlyphNames(self, glyphNames, otFont):
|
||||
glyphIDs = map(otFont.getGlyphID, glyphNames)
|
||||
glyphIDs = map(None, glyphIDs, glyphNames)
|
||||
glyphIDs.sort()
|
||||
self.glyphNames = map(lambda (x, y): y, glyphIDs)
|
||||
self.glyphIDs = map(lambda (x, y): x, glyphIDs)
|
||||
return self.glyphNames
|
||||
|
||||
def makeGlyphNames(self, otFont):
|
||||
self.glyphNames = map(lambda i, o=otFont.getGlyphOrder(): o[i], self.glyphIDs)
|
||||
|
||||
@ -286,49 +313,66 @@ class CoverageTable:
|
||||
for glyphID in range(startID, endID + 1):
|
||||
glyphIDs.append(glyphID)
|
||||
|
||||
def compile(self, otFont):
|
||||
# brute force ;-)
|
||||
data1 = self.compileFormat1(otFont)
|
||||
data2 = self.compileFormat2(otFont)
|
||||
if len(data1) <= len(data2):
|
||||
format = 1
|
||||
reader = data1
|
||||
def compile(self, writer, otFont):
|
||||
# figure out which format is more compact, doing so by brute force...
|
||||
|
||||
# compile format 1
|
||||
writer1 = OTTableWriter()
|
||||
writer1.writeUShort(1)
|
||||
self.compileFormat1(writer1, otFont)
|
||||
data1 = writer1.getData()
|
||||
|
||||
# compile format 2
|
||||
writer2 = OTTableWriter()
|
||||
writer2.writeUShort(2)
|
||||
self.compileFormat2(writer2, otFont)
|
||||
data2 = writer2.getData()
|
||||
|
||||
if len(data1) < len(data2):
|
||||
writer.writeRaw(data1)
|
||||
else:
|
||||
format = 2
|
||||
reader = data2
|
||||
return struct.pack(">H", format) + reader
|
||||
writer.writeRaw(data2)
|
||||
|
||||
def compileFormat1(self, otFont):
|
||||
xxxxx
|
||||
glyphIDs = map(otFont.getGlyphID, self.glyphNames)
|
||||
data = pack(">H", len(glyphIDs))
|
||||
pack = struct.pack
|
||||
for glyphID in glyphIDs:
|
||||
data = data + pack(">H", glyphID)
|
||||
return data
|
||||
def compileFormat1(self, writer, otFont):
|
||||
writer.writeUShort(len(self.glyphIDs))
|
||||
writer.writeUShortArray(self.glyphIDs)
|
||||
|
||||
def compileFormat2(self, otFont):
|
||||
xxxxx
|
||||
glyphIDs = map(otFont.getGlyphID, self.glyphNames)
|
||||
def compileFormat2(self, writer, otFont):
|
||||
ranges = []
|
||||
lastID = startID = glyphIDs[0]
|
||||
lastID = startID = self.glyphIDs[0]
|
||||
startCoverageIndex = 0
|
||||
glyphCount = len(glyphIDs)
|
||||
glyphCount = len(self.glyphIDs)
|
||||
for i in range(1, glyphCount+1):
|
||||
if i == glyphCount:
|
||||
glyphID = 0x1ffff # arbitrary, but larger than 0x10000
|
||||
else:
|
||||
glyphID = glyphIDs[i]
|
||||
glyphID = self.glyphIDs[i]
|
||||
if glyphID <> (lastID + 1):
|
||||
ranges.append((startID, lastID, startCoverageIndex))
|
||||
startCoverageIndex = i
|
||||
startID = glyphID
|
||||
lastID = glyphID
|
||||
ranges.sort() # sort by startID
|
||||
rangeData = ""
|
||||
writer.writeUShort(len(ranges))
|
||||
for startID, endID, startCoverageIndex in ranges:
|
||||
rangeData = rangeData + struct.pack(">HHH", startID, endID, startCoverageIndex)
|
||||
return pack(">H", len(ranges)) + rangeData
|
||||
writer.writeUShort(startID)
|
||||
writer.writeUShort(endID)
|
||||
writer.writeUShort(startCoverageIndex)
|
||||
|
||||
|
||||
def unpackCoverageArray(coverageArray):
|
||||
coverageArray = coverageArray[:]
|
||||
for i in range(len(coverageArray)):
|
||||
coverageArray[i] = coverageArray[i].getGlyphNames()
|
||||
return coverageArray
|
||||
|
||||
def buildCoverageArray(coverageArray, otFont):
|
||||
coverageArray = coverageArray[:]
|
||||
for i in range(len(coverageArray)):
|
||||
coverage = CoverageTable()
|
||||
coverage.setGlyphNames(coverageArray[i], otFont)
|
||||
coverageArray[i] = coverage
|
||||
return coverageArray
|
||||
|
||||
|
||||
class ClassDefinitionTable:
|
||||
@ -374,7 +418,8 @@ class ClassDefinitionTable:
|
||||
glyphName = otFont.getGlyphName(glyphID)
|
||||
classDefs.append((glyphName, classValue))
|
||||
|
||||
def compile(self, otFont):
|
||||
def compile(self, writer, otFont):
|
||||
XXX
|
||||
# brute force again
|
||||
data1 = self.compileFormat1(otFont)
|
||||
data2 = self.compileFormat2(otFont)
|
||||
@ -387,6 +432,7 @@ class ClassDefinitionTable:
|
||||
return struct.pack(">H", format) + data
|
||||
|
||||
def compileFormat1(self, otFont):
|
||||
XXX
|
||||
items = map(lambda (glyphName, classValue), getGlyphID=otFont.getGlyphID:
|
||||
(getGlyphID(glyphName), classValue), self.glyphs.items())
|
||||
items.sort()
|
||||
@ -402,6 +448,7 @@ class ClassDefinitionTable:
|
||||
return struct.pack(">H", endGlyphID - startGlyphID + 1) + data
|
||||
|
||||
def compileFormat2(self, otFont):
|
||||
XXX
|
||||
items = map(lambda (glyphName, classValue), getGlyphID=otFont.getGlyphID:
|
||||
(getGlyphID(glyphName), classValue), self.glyphs.items())
|
||||
items.sort()
|
||||
@ -436,11 +483,9 @@ class ClassDefinitionTable:
|
||||
class DeviceTable:
|
||||
|
||||
def decompile(self, reader, otFont):
|
||||
xxxxxx
|
||||
self.startSize = unpack_uint16(reader[:2])
|
||||
endSize = unpack_uint16(reader[2:4])
|
||||
deltaFormat = unpack_uint16(reader[4:6])
|
||||
reader = reader[6:]
|
||||
self.startSize = reader.readUShort()
|
||||
endSize = reader.readUShort()
|
||||
deltaFormat = reader.readUShort()
|
||||
if deltaFormat == 1:
|
||||
bits = 2
|
||||
elif deltaFormat == 2:
|
||||
@ -457,7 +502,7 @@ class DeviceTable:
|
||||
shift = 1 << bits
|
||||
for i in range(0, deltaCount, numCount):
|
||||
offset = 2*i/numCount
|
||||
chunk = unpack_uint16(reader[offset:offset+2])
|
||||
chunk = reader.readUShort()
|
||||
deltas = []
|
||||
for j in range(numCount):
|
||||
delta = chunk & mask
|
||||
@ -469,7 +514,9 @@ class DeviceTable:
|
||||
deltaValues = deltaValues + deltas
|
||||
self.deltaValues = deltaValues[:deltaCount]
|
||||
|
||||
def compile(self, otFont):
|
||||
def compile(self, writer, otFont):
|
||||
raise NotImplementedError
|
||||
# XXX
|
||||
deltaValues = self.deltaValues
|
||||
startSize = self.startSize
|
||||
endSize = startSize + len(deltaValues) - 1
|
||||
@ -515,6 +562,15 @@ class OTTableReader:
|
||||
self.offset = offset
|
||||
self.pos = offset
|
||||
|
||||
def readTable(self, tableClass, otFont, *args):
|
||||
offset = self.readOffset()
|
||||
if offset == 0:
|
||||
return None
|
||||
newReader = self.getSubString(offset)
|
||||
table = apply(tableClass, args)
|
||||
table.decompile(newReader, otFont)
|
||||
return table
|
||||
|
||||
def readUShort(self):
|
||||
pos = self.pos
|
||||
newpos = pos + 2
|
||||
@ -549,14 +605,12 @@ class OTTableReader:
|
||||
def readUShortArray(self, count):
|
||||
return self.readArray(count, "H")
|
||||
|
||||
readOffsetArray = readUShortArray
|
||||
|
||||
def readShortArray(self, count):
|
||||
return self.readArray(count, "h")
|
||||
|
||||
def readArray(self, count, format):
|
||||
assert format in "Hh"
|
||||
from array import array
|
||||
assert format in "Hh"
|
||||
pos = self.pos
|
||||
newpos = pos + 2 * count
|
||||
a = array(format)
|
||||
@ -566,15 +620,6 @@ class OTTableReader:
|
||||
self.pos = newpos
|
||||
return a.tolist()
|
||||
|
||||
def readTable(self, tableClass, otFont, *args):
|
||||
offset = self.readOffset()
|
||||
if offset == 0:
|
||||
return None
|
||||
newReader = self.getSubString(offset)
|
||||
table = apply(tableClass, args)
|
||||
table.decompile(newReader, otFont)
|
||||
return table
|
||||
|
||||
def readTableArray(self, count, tableClass, otFont, *args):
|
||||
list = []
|
||||
for i in range(count):
|
||||
@ -608,3 +653,86 @@ class OTTableReader:
|
||||
self.pos = self.pos + n
|
||||
|
||||
|
||||
class OTTableWriter:
|
||||
|
||||
def __init__(self):
|
||||
self.items = []
|
||||
|
||||
def getData(self):
|
||||
items = self.items[:]
|
||||
offset = 0
|
||||
for item in items:
|
||||
if hasattr(item, "getData"):
|
||||
offset = offset + 2 # sizeof(Offset)
|
||||
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] = packOffset(cache[subTableData])
|
||||
else:
|
||||
items[i] = packOffset(offset)
|
||||
subTables.append(subTableData)
|
||||
cache[subTableData] = offset
|
||||
offset = offset + len(subTableData)
|
||||
return string.join(items, "") + string.join(subTables, "")
|
||||
|
||||
def writeTable(self, subTable, otFont):
|
||||
if subTable is None:
|
||||
self.writeUShort(0)
|
||||
else:
|
||||
subWriter = self.__class__()
|
||||
self.items.append(subWriter)
|
||||
subTable.compile(subWriter, otFont)
|
||||
|
||||
def writeUShort(self, value):
|
||||
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 writeUShortArray(self, array):
|
||||
return self.writeArray(array, "H")
|
||||
|
||||
def writeShortArray(self, array):
|
||||
return self.writeArray(array, "h")
|
||||
|
||||
def writeArray(self, list, format):
|
||||
from array import array
|
||||
assert format in "Hh"
|
||||
a = array(format, list)
|
||||
if ttLib.endian <> 'big':
|
||||
a.byteswap()
|
||||
self.items.append(a.tostring())
|
||||
|
||||
def writeTableArray(self, list, otFont):
|
||||
for subTable in list:
|
||||
self.writeTable(subTable, otFont)
|
||||
|
||||
def writeTagList(self, list, otFont):
|
||||
for tag, subTable in list:
|
||||
self.writeTag(tag)
|
||||
self.writeTable(subTable, otFont)
|
||||
|
||||
def writeStruct(self, format, values):
|
||||
data = apply(struct.pack, (format,) + values)
|
||||
self.items.append(data)
|
||||
|
||||
def writeRaw(self, data):
|
||||
self.items.append(data)
|
||||
|
||||
|
||||
def packOffset(offset):
|
||||
return struct.pack(">H", offset)
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user