cmap format 1 support, contributed by rroberts

git-svn-id: svn://svn.code.sf.net/p/fonttools/code/trunk@554 4cde692c-a291-49d1-8350-778aa11640f8
This commit is contained in:
jvr 2008-05-16 15:07:09 +00:00
parent 7487a3a7fb
commit 0cb8a08d89

View File

@ -30,6 +30,9 @@ class table__c_m_a_p(DefaultTable.DefaultTable):
format, length = struct.unpack(">HH", data[offset:offset+4])
if format in [8,10,12]:
format, reserved, length = struct.unpack(">HHL", data[offset:offset+8])
elif format in [14]:
format, length = struct.unpack(">HL", data[offset:offset+6])
if not length:
print "Error: cmap subtable is reported as having zero length: platformID %s, platEncID %s, format %s offset %s. Skipping table." % (platformID, platEncID,format, offset)
continue
@ -1039,6 +1042,214 @@ class cmap_format_12(CmapSubtable):
cmap[safeEval(attrs["code"])] = attrs["name"]
def cvtToUVS(threeByteString):
if sys.byteorder <> "big":
data = "\0" +threeByteString
else:
data = threeByteString + "\0"
val, = struct.unpack(">L", data)
return val
def cvtFromUVS(val):
if sys.byteorder <> "big":
threeByteString = struct.pack(">L", val)[1:]
else:
threeByteString = struct.pack(">L", val)[:3]
return threeByteString
def cmpUVSListEntry(first, second):
uv1, glyphName1 = first
uv2, glyphName2 = second
if (glyphName1 == None) and (glyphName2 != None):
return -1
elif (glyphName2 == None) and (glyphName1 != None):
return 1
ret = cmp(uv1, uv2)
if ret:
return ret
return cmp(glyphName1, glyphName2)
class cmap_format_14(CmapSubtable):
def decompileHeader(self, data, ttFont):
format, length, numVarSelectorRecords = struct.unpack(">HLL", data[:10])
self.data = data[10:]
self.length = length
self.numVarSelectorRecords = numVarSelectorRecords
self.ttFont = ttFont
self.language = 0xFF # has no language.
def decompile(self, data, ttFont):
if data != None and ttFont != None:
self.decompileHeader(data, ttFont)
else:
assert( (data == None and (ttFont == None), "Need both data and ttFont arguments"))
data = self.data
self.cmap = {} # so that clients that expect this to exist in a cmap table won't fail.
uvsDict = {}
recOffset = 0
for n in range(self.numVarSelectorRecords):
uvs, defOVSOffset, nonDefUVSOffset = struct.unpack(">3sLL", data[recOffset:recOffset +11])
recOffset += 11
varUVS = cvtToUVS(uvs)
if defOVSOffset:
startOffset = defOVSOffset - 10
numValues, = struct.unpack(">L", data[startOffset:startOffset+4])
startOffset +=4
for r in range(numValues):
uv, addtlCnt = struct.unpack(">3sB", data[startOffset:startOffset+4])
startOffset += 4
firstBaseUV = cvtToUVS(uv)
cnt = addtlCnt+1
baseUVList = range(firstBaseUV, firstBaseUV+cnt)
glyphList = [None]*cnt
localUVList = zip(baseUVList, glyphList)
try:
uvsDict[varUVS].extend(localUVList)
except KeyError:
uvsDict[varUVS] = localUVList
if nonDefUVSOffset:
startOffset = nonDefUVSOffset - 10
numRecs, = struct.unpack(">L", data[startOffset:startOffset+4])
startOffset +=4
localUVList = []
for r in range(numRecs):
uv, gid = struct.unpack(">3sH", data[startOffset:startOffset+5])
startOffset += 5
uv = cvtToUVS(uv)
glyphName = self.ttFont.getGlyphName(gid)
localUVList.append( [uv, glyphName] )
try:
uvsDict[varUVS].extend(localUVList)
except KeyError:
uvsDict[varUVS] = localUVList
self.uvsDict = uvsDict
def toXML(self, writer, ttFont):
writer.begintag(self.__class__.__name__, [
("platformID", self.platformID),
("platEncID", self.platEncID),
("format", self.format),
("length", self.length),
("numVarSelectorRecords", self.numVarSelectorRecords),
])
writer.newline()
uvsDict = self.uvsDict
uvsList = uvsDict.keys()
uvsList.sort()
for uvs in uvsList:
uvList = uvsDict[uvs]
uvList.sort(cmpUVSListEntry)
for uv, gname in uvList:
if gname == None:
gname = "None"
# I use the arg rather than th keyword syntax in order to preserve the attribute order.
writer.simpletag("map", [ ("uvs",hex(uvs)), ("uv",hex(uv)), ("name", gname)] )
writer.newline()
writer.endtag(self.__class__.__name__)
writer.newline()
def fromXML(self, (name, attrs, content), ttFont):
self.format = safeEval(attrs["format"])
self.length = safeEval(attrs["length"])
self.numVarSelectorRecords = safeEval(attrs["numVarSelectorRecords"])
self.language = 0xFF # provide a value so that CmapSubtable.__cmp__() won't fail
if not hasattr(self, "cmap"):
self.cmap = {} # so that clients that expect this to exist in a cmap table won't fail.
if not hasattr(self, "uvsDict"):
self.uvsDict = {}
uvsDict = self.uvsDict
for element in content:
if type(element) <> TupleType:
continue
name, attrs, content = element
if name <> "map":
continue
uvs = safeEval(attrs["uvs"])
uv = safeEval(attrs["uv"])
gname = attrs["name"]
if gname == "None":
gname = None
try:
uvsDict[uvs].append( [uv, gname])
except KeyError:
uvsDict[uvs] = [ [uv, gname] ]
def compile(self, ttFont):
if self.data:
return struct.pack(">HLL", self.format, self.length , self.numVarSelectorRecords) + self.data
uvsDict = self.uvsDict
uvsList = uvsDict.keys()
uvsList.sort()
self.numVarSelectorRecords = len(uvsList)
offset = 10 + self.numVarSelectorRecords*11 # current value is end of VarSelectorRecords block.
data = []
varSelectorRecords =[]
for uvs in uvsList:
entryList = uvsDict[uvs]
defList = filter(lambda entry: entry[1] == None, entryList)
if defList:
defList = map(lambda entry: entry[0], defList)
defOVSOffset = offset
defList.sort()
lastUV = defList[0]
cnt = -1
defRecs = []
for defEntry in defList:
cnt +=1
if (lastUV+cnt) != defEntry:
rec = struct.pack(">3sB", cvtFromUVS(lastUV), cnt-1)
lastUV = defEntry
defRecs.append(rec)
cnt = 0
rec = struct.pack(">3sB", cvtFromUVS(lastUV), cnt)
defRecs.append(rec)
numDefRecs = len(defRecs)
data.append(struct.pack(">L", numDefRecs))
data.extend(defRecs)
offset += 4 + numDefRecs*4
else:
defOVSOffset = 0
ndefList = filter(lambda entry: entry[1] != None, entryList)
if ndefList:
nonDefUVSOffset = offset
ndefList.sort()
numNonDefRecs = len(ndefList)
data.append(struct.pack(">L", numNonDefRecs))
offset += 4 + numNonDefRecs*5
for uv, gname in ndefList:
gid = ttFont.getGlyphID(gname)
ndrec = struct.pack(">3sH", cvtFromUVS(uv), gid)
data.append(ndrec)
else:
nonDefUVSOffset = 0
vrec = struct.pack(">3sLL", cvtFromUVS(uvs), defOVSOffset, nonDefUVSOffset)
varSelectorRecords.append(vrec)
data = "".join(varSelectorRecords) + "".join(data)
self.length = 10 + len(data)
headerdata = struct.pack(">HLL", self.format, self.length , self.numVarSelectorRecords)
self.data = headerdata + data
return self.data
class cmap_format_unknown(CmapSubtable):
def toXML(self, writer, ttFont):
@ -1080,4 +1291,5 @@ cmap_classes = {
4: cmap_format_4,
6: cmap_format_6,
12: cmap_format_12,
14: cmap_format_14,
}