Refactored and enhanced table order support:
- Rewrote sorting function, it was really quite buggy.
- Added reorderFontTables() functions, which reorders the
tables in a font at the sfnt level.
- TTFont.save() will now by default rewrite the font in the
optimized order. This is done through a temp file since
our dependency checking logic gets in the way of writing
the tables in a predefined order directly (if table A depends
on B, table B will always be compiled and written first, so
this prevents A from showing up in the file before B).
sfnt.py:
- removed closeStream option from SFNTWriter.close(); it's better
done by the caller (TTFont).
git-svn-id: svn://svn.code.sf.net/p/fonttools/code/trunk@475 4cde692c-a291-49d1-8350-778aa11640f8
diff --git a/Lib/fontTools/ttLib/__init__.py b/Lib/fontTools/ttLib/__init__.py
index a09c831..dccc055 100644
--- a/Lib/fontTools/ttLib/__init__.py
+++ b/Lib/fontTools/ttLib/__init__.py
@@ -42,7 +42,7 @@
"""
#
-# $Id: __init__.py,v 1.44 2004-11-16 09:12:30 jvr Exp $
+# $Id: __init__.py,v 1.45 2004-11-16 10:37:59 jvr Exp $
#
import sys
@@ -137,7 +137,7 @@
if self.reader is not None:
self.reader.close()
- def save(self, file, makeSuitcase=0):
+ def save(self, file, makeSuitcase=0, reorderTables=1):
"""Save the font to disk. Similarly to the constructor,
the 'file' argument can be either a pathname or a writable
file object.
@@ -165,13 +165,27 @@
if "GlyphOrder" in tags:
tags.remove("GlyphOrder")
numTables = len(tags)
- writer = sfnt.SFNTWriter(file, numTables, self.sfntVersion)
+ if reorderTables:
+ import tempfile
+ tmp = tempfile.TemporaryFile(prefix="ttx-fonttools")
+ else:
+ tmp = file
+ writer = sfnt.SFNTWriter(tmp, numTables, self.sfntVersion)
done = []
for tag in tags:
self._writeTable(tag, writer, done)
- writer.close(closeStream)
+ writer.close()
+
+ if reorderTables:
+ tmp.flush()
+ tmp.seek(0)
+ reorderFontTables(tmp, file)
+ tmp.close()
+
+ if closeStream:
+ file.close()
def saveXML(self, fileOrPath, progress=None,
tables=None, skipTables=None, splitTables=0, disassembleInstructions=1):
@@ -305,14 +319,10 @@
if key not in keys:
keys.append(key)
- if "glyf" in keys:
- tableSort = sortTTFFont
- elif "CFF " in keys:
- tableSort = sortOTFFont
- else:
- assert 0, "Font has neither glyf nor CFF table. Table list:" + str(keys)
- keys.sort(tableSort)
- return keys
+ if "GlyphOrder" in keys:
+ keys.remove("GlyphOrder")
+ keys = sortedTagList(keys)
+ return ["GlyphOrder"] + keys
def __len__(self):
return len(self.keys())
@@ -795,7 +805,7 @@
if tag == "OS/2":
return "OS_2"
elif tag == "GlyphOrder":
- return "GlyphOrder"
+ return tag
if re.match("[A-Za-z_][A-Za-z_0-9]* *$", tag):
return string.strip(tag)
else:
@@ -818,44 +828,47 @@
print msg + time.strftime(" (%H:%M:%S)", time.localtime(time.time()))
+# Table order as recommended in the OpenType specification 1.4
+TTFTableOrder = ["head", "hhea", "maxp", "OS/2", "hmtx", "LTSH", "VDMX",
+ "hdmx", "cmap", "fpgm", "prep", "cvt ", "loca", "glyf",
+ "kern", "name", "post", "gasp", "PCLT"]
-# Table sorting algorithm pre recommendations in OpenType Spec v1.4
-kTTFTableOrder = ["GlyphOrder", "head", "hhea", "maxp", "OS/2", "hmtx", "LTSH", "VDMX", "hdmx", "cmap", "fpgm", "prep", "cvt", "loca", "glyf", "kern", "name", "post", "gasp", "PCLT"]
-kOTFTableOrder = ["GlyphOrder", "head", "hhea", "maxp", "OS/2", "name", "cmap", "post", "CFF "]
-kNotInTableIndex = 10000 # an arbitrary value larger than will ever be a font.
-def sortFontTables(tag1, tag2, tableOrder):
- #No need to allow for two tags with the same name.
- if tag1 == "DSIG":
- ret = -1
- elif tag2 == "DSIG":
- ret = 1
- else:
- try:
- i1 = tableOrder.index(tag1)
- except ValueError:
- i1 = kNotInTableIndex
- try:
- i2 = tableOrder.index(tag2)
- except ValueError:
- i2 = kNotInTableIndex
-
- if i1 > i2:
- ret = 1
- elif i1 < i2:
- ret = -1
+OTFTableOrder = ["head", "hhea", "maxp", "OS/2", "name", "cmap", "post",
+ "CFF "]
+
+def sortedTagList(tagList, tableOrder=None):
+ """Return a sorted copy of tagList, sorted according to the OpenType
+ specification, or according to a custom tableOrder. If given and not
+ None, tableOrder needs to be a list of tag names.
+ """
+ tagList = list(tagList)
+ tagList.sort()
+ if tableOrder is None:
+ if "DSIG" in tagList:
+ # DSIG should be last (XXX spec reference?)
+ tagList.remove("DSIG")
+ tagList.append("DSIG")
+ if "CFF " in tagList:
+ tableOrder = OTFTableOrder
else:
- if tag1 < tag2:
- ret = 1
- elif tag1 < tag2:
- ret = -1
- else:
- ret = 0
- return ret
+ tableOrder = TTFTableOrder
+ orderedTables = []
+ for tag in tableOrder:
+ if tag in tagList:
+ orderedTables.append(tag)
+ tagList.remove(tag)
+ orderedTables.extend(tagList)
+ return orderedTables
-def sortTTFFont(tag1, tag2):
- return sortFontTables(tag1, tag2, kTTFTableOrder)
-
-
-def sortOTFFont(tag1, tag2):
- return sortFontTables(tag1, tag2, kOTFTableOrder)
+def reorderFontTables(inFile, outFile, tableOrder=None, checkChecksums=0):
+ """Rewrite a font file, ordering the tables as recommended by the
+ OpenType specification 1.4.
+ """
+ from fontTools.ttLib.sfnt import SFNTReader, SFNTWriter
+ reader = SFNTReader(inFile, checkChecksums=checkChecksums)
+ writer = SFNTWriter(outFile, reader.numTables, reader.sfntVersion)
+ tables = reader.keys()
+ for tag in sortedTagList(tables, tableOrder):
+ writer[tag] = reader[tag]
+ writer.close()
diff --git a/Lib/fontTools/ttLib/sfnt.py b/Lib/fontTools/ttLib/sfnt.py
index 0ce0ca0..e94a516 100644
--- a/Lib/fontTools/ttLib/sfnt.py
+++ b/Lib/fontTools/ttLib/sfnt.py
@@ -116,7 +116,7 @@
entry.checkSum = calcChecksum(data)
self.tables[tag] = entry
- def close(self, closeStream=1):
+ def close(self):
"""All tables must have been written to disk. Now write the
directory.
"""
@@ -138,8 +138,6 @@
self.calcMasterChecksum(directory)
self.file.seek(0)
self.file.write(directory)
- if closeStream:
- self.file.close()
def calcMasterChecksum(self, directory):
# calculate checkSumAdjustment