Spaces:
Runtime error
Runtime error
File size: 6,981 Bytes
9cddcfd |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 |
""" TSI{0,1,2,3,5} are private tables used by Microsoft Visual TrueType (VTT)
tool to store its hinting source data.
TSI1 contains the text of the glyph programs in the form of low-level assembly
code, as well as the 'extra' programs 'fpgm', 'ppgm' (i.e. 'prep'), and 'cvt'.
"""
from . import DefaultTable
from fontTools.misc.loggingTools import LogMixin
from fontTools.misc.textTools import strjoin, tobytes, tostr
class table_T_S_I__1(LogMixin, DefaultTable.DefaultTable):
extras = {0xFFFA: "ppgm", 0xFFFB: "cvt", 0xFFFC: "reserved", 0xFFFD: "fpgm"}
indextable = "TSI0"
def decompile(self, data, ttFont):
totalLength = len(data)
indextable = ttFont[self.indextable]
for indices, isExtra in zip(
(indextable.indices, indextable.extra_indices), (False, True)
):
programs = {}
for i, (glyphID, textLength, textOffset) in enumerate(indices):
if isExtra:
name = self.extras[glyphID]
else:
name = ttFont.getGlyphName(glyphID)
if textOffset > totalLength:
self.log.warning("textOffset > totalLength; %r skipped" % name)
continue
if textLength < 0x8000:
# If the length stored in the record is less than 32768, then use
# that as the length of the record.
pass
elif textLength == 0x8000:
# If the length is 32768, compute the actual length as follows:
isLast = i == (len(indices) - 1)
if isLast:
if isExtra:
# For the last "extra" record (the very last record of the
# table), the length is the difference between the total
# length of the TSI1 table and the textOffset of the final
# record.
nextTextOffset = totalLength
else:
# For the last "normal" record (the last record just prior
# to the record containing the "magic number"), the length
# is the difference between the textOffset of the record
# following the "magic number" (0xFFFE) record (i.e. the
# first "extra" record), and the textOffset of the last
# "normal" record.
nextTextOffset = indextable.extra_indices[0][2]
else:
# For all other records with a length of 0x8000, the length is
# the difference between the textOffset of the record in
# question and the textOffset of the next record.
nextTextOffset = indices[i + 1][2]
assert nextTextOffset >= textOffset, "entries not sorted by offset"
if nextTextOffset > totalLength:
self.log.warning(
"nextTextOffset > totalLength; %r truncated" % name
)
nextTextOffset = totalLength
textLength = nextTextOffset - textOffset
else:
from fontTools import ttLib
raise ttLib.TTLibError(
"%r textLength (%d) must not be > 32768" % (name, textLength)
)
text = data[textOffset : textOffset + textLength]
assert len(text) == textLength
text = tostr(text, encoding="utf-8")
if text:
programs[name] = text
if isExtra:
self.extraPrograms = programs
else:
self.glyphPrograms = programs
def compile(self, ttFont):
if not hasattr(self, "glyphPrograms"):
self.glyphPrograms = {}
self.extraPrograms = {}
data = b""
indextable = ttFont[self.indextable]
glyphNames = ttFont.getGlyphOrder()
indices = []
for i in range(len(glyphNames)):
if len(data) % 2:
data = (
data + b"\015"
) # align on 2-byte boundaries, fill with return chars. Yum.
name = glyphNames[i]
if name in self.glyphPrograms:
text = tobytes(self.glyphPrograms[name], encoding="utf-8")
else:
text = b""
textLength = len(text)
if textLength >= 0x8000:
textLength = 0x8000
indices.append((i, textLength, len(data)))
data = data + text
extra_indices = []
codes = sorted(self.extras.items())
for i in range(len(codes)):
if len(data) % 2:
data = (
data + b"\015"
) # align on 2-byte boundaries, fill with return chars.
code, name = codes[i]
if name in self.extraPrograms:
text = tobytes(self.extraPrograms[name], encoding="utf-8")
else:
text = b""
textLength = len(text)
if textLength >= 0x8000:
textLength = 0x8000
extra_indices.append((code, textLength, len(data)))
data = data + text
indextable.set(indices, extra_indices)
return data
def toXML(self, writer, ttFont):
names = sorted(self.glyphPrograms.keys())
writer.newline()
for name in names:
text = self.glyphPrograms[name]
if not text:
continue
writer.begintag("glyphProgram", name=name)
writer.newline()
writer.write_noindent(text.replace("\r", "\n"))
writer.newline()
writer.endtag("glyphProgram")
writer.newline()
writer.newline()
extra_names = sorted(self.extraPrograms.keys())
for name in extra_names:
text = self.extraPrograms[name]
if not text:
continue
writer.begintag("extraProgram", name=name)
writer.newline()
writer.write_noindent(text.replace("\r", "\n"))
writer.newline()
writer.endtag("extraProgram")
writer.newline()
writer.newline()
def fromXML(self, name, attrs, content, ttFont):
if not hasattr(self, "glyphPrograms"):
self.glyphPrograms = {}
self.extraPrograms = {}
lines = strjoin(content).replace("\r", "\n").split("\n")
text = "\r".join(lines[1:-1])
if name == "glyphProgram":
self.glyphPrograms[attrs["name"]] = text
elif name == "extraProgram":
self.extraPrograms[attrs["name"]] = text
|