Source code for fontTools.ttLib.tables.S__i_l_f

from fontTools.misc import sstruct
from fontTools.misc.fixedTools import floatToFixedToStr
from fontTools.misc.textTools import byteord, safeEval

# from itertools import *
from . import DefaultTable
from . import grUtils
from array import array
from functools import reduce
import struct, re, sys

Silf_hdr_format = """
    >
    version:            16.16F
"""

Silf_hdr_format_3 = """
    >
    version:            16.16F
    compilerVersion:    L
    numSilf:            H
                        x
                        x
"""

Silf_part1_format_v3 = """
    >
    ruleVersion:        16.16F
    passOffset:         H
    pseudosOffset:      H
"""

Silf_part1_format = """
    >
    maxGlyphID:         H
    extraAscent:        h
    extraDescent:       h
    numPasses:          B
    iSubst:             B
    iPos:               B
    iJust:              B
    iBidi:              B
    flags:              B
    maxPreContext:      B
    maxPostContext:     B
    attrPseudo:         B
    attrBreakWeight:    B
    attrDirectionality: B
    attrMirroring:      B
    attrSkipPasses:     B
    numJLevels:         B
"""

Silf_justify_format = """
    >
    attrStretch:        B
    attrShrink:         B
    attrStep:           B
    attrWeight:         B
    runto:              B
                        x
                        x
                        x
"""

Silf_part2_format = """
    >
    numLigComp:         H
    numUserDefn:        B
    maxCompPerLig:      B
    direction:          B
    attCollisions:      B
                        x
                        x
                        x
    numCritFeatures:    B
"""

Silf_pseudomap_format = """
    >
    unicode:            L
    nPseudo:            H
"""

Silf_pseudomap_format_h = """
    >
    unicode:            H
    nPseudo:            H
"""

Silf_classmap_format = """
    >
    numClass:           H
    numLinear:          H
"""

Silf_lookupclass_format = """
    >
    numIDs:             H
    searchRange:        H
    entrySelector:      H
    rangeShift:         H
"""

Silf_lookuppair_format = """
    >
    glyphId:            H
    index:              H
"""

Silf_pass_format = """
    >
    flags:              B
    maxRuleLoop:        B
    maxRuleContext:     B
    maxBackup:          B
    numRules:           H
    fsmOffset:          H
    pcCode:             L
    rcCode:             L
    aCode:              L
    oDebug:             L
    numRows:            H
    numTransitional:    H
    numSuccess:         H
    numColumns:         H
"""

aCode_info = (
    ("NOP", 0),
    ("PUSH_BYTE", "b"),
    ("PUSH_BYTE_U", "B"),
    ("PUSH_SHORT", ">h"),
    ("PUSH_SHORT_U", ">H"),
    ("PUSH_LONG", ">L"),
    ("ADD", 0),
    ("SUB", 0),
    ("MUL", 0),
    ("DIV", 0),
    ("MIN", 0),
    ("MAX", 0),
    ("NEG", 0),
    ("TRUNC8", 0),
    ("TRUNC16", 0),
    ("COND", 0),
    ("AND", 0),  # x10
    ("OR", 0),
    ("NOT", 0),
    ("EQUAL", 0),
    ("NOT_EQ", 0),
    ("LESS", 0),
    ("GTR", 0),
    ("LESS_EQ", 0),
    ("GTR_EQ", 0),
    ("NEXT", 0),
    ("NEXT_N", "b"),
    ("COPY_NEXT", 0),
    ("PUT_GLYPH_8BIT_OBS", "B"),
    ("PUT_SUBS_8BIT_OBS", "bBB"),
    ("PUT_COPY", "b"),
    ("INSERT", 0),
    ("DELETE", 0),  # x20
    ("ASSOC", -1),
    ("CNTXT_ITEM", "bB"),
    ("ATTR_SET", "B"),
    ("ATTR_ADD", "B"),
    ("ATTR_SUB", "B"),
    ("ATTR_SET_SLOT", "B"),
    ("IATTR_SET_SLOT", "BB"),
    ("PUSH_SLOT_ATTR", "Bb"),
    ("PUSH_GLYPH_ATTR_OBS", "Bb"),
    ("PUSH_GLYPH_METRIC", "Bbb"),
    ("PUSH_FEAT", "Bb"),
    ("PUSH_ATT_TO_GATTR_OBS", "Bb"),
    ("PUSH_ATT_TO_GLYPH_METRIC", "Bbb"),
    ("PUSH_ISLOT_ATTR", "Bbb"),
    ("PUSH_IGLYPH_ATTR", "Bbb"),
    ("POP_RET", 0),  # x30
    ("RET_ZERO", 0),
    ("RET_TRUE", 0),
    ("IATTR_SET", "BB"),
    ("IATTR_ADD", "BB"),
    ("IATTR_SUB", "BB"),
    ("PUSH_PROC_STATE", "B"),
    ("PUSH_VERSION", 0),
    ("PUT_SUBS", ">bHH"),
    ("PUT_SUBS2", 0),
    ("PUT_SUBS3", 0),
    ("PUT_GLYPH", ">H"),
    ("PUSH_GLYPH_ATTR", ">Hb"),
    ("PUSH_ATT_TO_GLYPH_ATTR", ">Hb"),
    ("BITOR", 0),
    ("BITAND", 0),
    ("BITNOT", 0),  # x40
    ("BITSET", ">HH"),
    ("SET_FEAT", "Bb"),
)
aCode_map = dict([(x[0], (i, x[1])) for i, x in enumerate(aCode_info)])


[docs] def disassemble(aCode): codelen = len(aCode) pc = 0 res = [] while pc < codelen: opcode = byteord(aCode[pc : pc + 1]) if opcode > len(aCode_info): instr = aCode_info[0] else: instr = aCode_info[opcode] pc += 1 if instr[1] != 0 and pc >= codelen: return res if instr[1] == -1: count = byteord(aCode[pc]) fmt = "%dB" % count pc += 1 elif instr[1] == 0: fmt = "" else: fmt = instr[1] if fmt == "": res.append(instr[0]) continue parms = struct.unpack_from(fmt, aCode[pc:]) res.append(instr[0] + "(" + ", ".join(map(str, parms)) + ")") pc += struct.calcsize(fmt) return res
instre = re.compile(r"^\s*([^(]+)\s*(?:\(([^)]+)\))?")
[docs] def assemble(instrs): res = b"" for inst in instrs: m = instre.match(inst) if not m or not m.group(1) in aCode_map: continue opcode, parmfmt = aCode_map[m.group(1)] res += struct.pack("B", opcode) if m.group(2): if parmfmt == 0: continue parms = [int(x) for x in re.split(r",\s*", m.group(2))] if parmfmt == -1: l = len(parms) res += struct.pack(("%dB" % (l + 1)), l, *parms) else: res += struct.pack(parmfmt, *parms) return res
[docs] def writecode(tag, writer, instrs): writer.begintag(tag) writer.newline() for l in disassemble(instrs): writer.write(l) writer.newline() writer.endtag(tag) writer.newline()
[docs] def readcode(content): res = [] for e in content_string(content).split("\n"): e = e.strip() if not len(e): continue res.append(e) return assemble(res)
attrs_info = ( "flags", "extraAscent", "extraDescent", "maxGlyphID", "numLigComp", "numUserDefn", "maxCompPerLig", "direction", "lbGID", ) attrs_passindexes = ("iSubst", "iPos", "iJust", "iBidi") attrs_contexts = ("maxPreContext", "maxPostContext") attrs_attributes = ( "attrPseudo", "attrBreakWeight", "attrDirectionality", "attrMirroring", "attrSkipPasses", "attCollisions", ) pass_attrs_info = ( "flags", "maxRuleLoop", "maxRuleContext", "maxBackup", "minRulePreContext", "maxRulePreContext", "collisionThreshold", ) pass_attrs_fsm = ("numRows", "numTransitional", "numSuccess", "numColumns")
[docs] def writesimple(tag, self, writer, *attrkeys): attrs = dict([(k, getattr(self, k)) for k in attrkeys]) writer.simpletag(tag, **attrs) writer.newline()
[docs] def getSimple(self, attrs, *attr_list): for k in attr_list: if k in attrs: setattr(self, k, int(safeEval(attrs[k])))
[docs] def content_string(contents): res = "" for element in contents: if isinstance(element, tuple): continue res += element return res.strip()
[docs] def wrapline(writer, dat, length=80): currline = "" for d in dat: if len(currline) > length: writer.write(currline[:-1]) writer.newline() currline = "" currline += d + " " if len(currline): writer.write(currline[:-1]) writer.newline()
class _Object: pass
[docs] class table_S__i_l_f(DefaultTable.DefaultTable): """Silf table support""" def __init__(self, tag=None): DefaultTable.DefaultTable.__init__(self, tag) self.silfs = []
[docs] def decompile(self, data, ttFont): sstruct.unpack2(Silf_hdr_format, data, self) self.version = float(floatToFixedToStr(self.version, precisionBits=16)) if self.version >= 5.0: (data, self.scheme) = grUtils.decompress(data) sstruct.unpack2(Silf_hdr_format_3, data, self) base = sstruct.calcsize(Silf_hdr_format_3) elif self.version < 3.0: self.numSilf = struct.unpack(">H", data[4:6]) self.scheme = 0 self.compilerVersion = 0 base = 8 else: self.scheme = 0 sstruct.unpack2(Silf_hdr_format_3, data, self) base = sstruct.calcsize(Silf_hdr_format_3) silfoffsets = struct.unpack_from((">%dL" % self.numSilf), data[base:]) for offset in silfoffsets: s = Silf() self.silfs.append(s) s.decompile(data[offset:], ttFont, self.version)
[docs] def compile(self, ttFont): self.numSilf = len(self.silfs) if self.version < 3.0: hdr = sstruct.pack(Silf_hdr_format, self) hdr += struct.pack(">HH", self.numSilf, 0) else: hdr = sstruct.pack(Silf_hdr_format_3, self) offset = len(hdr) + 4 * self.numSilf data = b"" for s in self.silfs: hdr += struct.pack(">L", offset) subdata = s.compile(ttFont, self.version) offset += len(subdata) data += subdata if self.version >= 5.0: return grUtils.compress(self.scheme, hdr + data) return hdr + data
[docs] def toXML(self, writer, ttFont): writer.comment("Attributes starting with _ are informative only") writer.newline() writer.simpletag( "version", version=self.version, compilerVersion=self.compilerVersion, compressionScheme=self.scheme, ) writer.newline() for s in self.silfs: writer.begintag("silf") writer.newline() s.toXML(writer, ttFont, self.version) writer.endtag("silf") writer.newline()
[docs] def fromXML(self, name, attrs, content, ttFont): if name == "version": self.scheme = int(safeEval(attrs["compressionScheme"])) self.version = float(safeEval(attrs["version"])) self.compilerVersion = int(safeEval(attrs["compilerVersion"])) return if name == "silf": s = Silf() self.silfs.append(s) for element in content: if not isinstance(element, tuple): continue tag, attrs, subcontent = element s.fromXML(tag, attrs, subcontent, ttFont, self.version)
[docs] class Silf(object): """A particular Silf subtable""" def __init__(self): self.passes = [] self.scriptTags = [] self.critFeatures = [] self.jLevels = [] self.pMap = {}
[docs] def decompile(self, data, ttFont, version=2.0): if version >= 3.0: _, data = sstruct.unpack2(Silf_part1_format_v3, data, self) self.ruleVersion = float( floatToFixedToStr(self.ruleVersion, precisionBits=16) ) _, data = sstruct.unpack2(Silf_part1_format, data, self) for jlevel in range(self.numJLevels): j, data = sstruct.unpack2(Silf_justify_format, data, _Object()) self.jLevels.append(j) _, data = sstruct.unpack2(Silf_part2_format, data, self) if self.numCritFeatures: self.critFeatures = struct.unpack_from( (">%dH" % self.numCritFeatures), data ) data = data[self.numCritFeatures * 2 + 1 :] (numScriptTag,) = struct.unpack_from("B", data) if numScriptTag: self.scriptTags = [ struct.unpack("4s", data[x : x + 4])[0].decode("ascii") for x in range(1, 1 + 4 * numScriptTag, 4) ] data = data[1 + 4 * numScriptTag :] (self.lbGID,) = struct.unpack(">H", data[:2]) if self.numPasses: self.oPasses = struct.unpack( (">%dL" % (self.numPasses + 1)), data[2 : 6 + 4 * self.numPasses] ) data = data[6 + 4 * self.numPasses :] (numPseudo,) = struct.unpack(">H", data[:2]) for i in range(numPseudo): if version >= 3.0: pseudo = sstruct.unpack( Silf_pseudomap_format, data[8 + 6 * i : 14 + 6 * i], _Object() ) else: pseudo = sstruct.unpack( Silf_pseudomap_format_h, data[8 + 4 * i : 12 + 4 * i], _Object() ) self.pMap[pseudo.unicode] = ttFont.getGlyphName(pseudo.nPseudo) data = data[8 + 6 * numPseudo :] currpos = ( sstruct.calcsize(Silf_part1_format) + sstruct.calcsize(Silf_justify_format) * self.numJLevels + sstruct.calcsize(Silf_part2_format) + 2 * self.numCritFeatures + 1 + 1 + 4 * numScriptTag + 6 + 4 * self.numPasses + 8 + 6 * numPseudo ) if version >= 3.0: currpos += sstruct.calcsize(Silf_part1_format_v3) self.classes = Classes() self.classes.decompile(data, ttFont, version) for i in range(self.numPasses): p = Pass() self.passes.append(p) p.decompile( data[self.oPasses[i] - currpos : self.oPasses[i + 1] - currpos], ttFont, version, )
[docs] def compile(self, ttFont, version=2.0): self.numPasses = len(self.passes) self.numJLevels = len(self.jLevels) self.numCritFeatures = len(self.critFeatures) numPseudo = len(self.pMap) data = b"" if version >= 3.0: hdroffset = sstruct.calcsize(Silf_part1_format_v3) else: hdroffset = 0 data += sstruct.pack(Silf_part1_format, self) for j in self.jLevels: data += sstruct.pack(Silf_justify_format, j) data += sstruct.pack(Silf_part2_format, self) if self.numCritFeatures: data += struct.pack((">%dH" % self.numCritFeaturs), *self.critFeatures) data += struct.pack("BB", 0, len(self.scriptTags)) if len(self.scriptTags): tdata = [struct.pack("4s", x.encode("ascii")) for x in self.scriptTags] data += b"".join(tdata) data += struct.pack(">H", self.lbGID) self.passOffset = len(data) data1 = grUtils.bininfo(numPseudo, 6) currpos = hdroffset + len(data) + 4 * (self.numPasses + 1) self.pseudosOffset = currpos + len(data1) for u, p in sorted(self.pMap.items()): data1 += struct.pack( (">LH" if version >= 3.0 else ">HH"), u, ttFont.getGlyphID(p) ) data1 += self.classes.compile(ttFont, version) currpos += len(data1) data2 = b"" datao = b"" for i, p in enumerate(self.passes): base = currpos + len(data2) datao += struct.pack(">L", base) data2 += p.compile(ttFont, base, version) datao += struct.pack(">L", currpos + len(data2)) if version >= 3.0: data3 = sstruct.pack(Silf_part1_format_v3, self) else: data3 = b"" return data3 + data + datao + data1 + data2
[docs] def toXML(self, writer, ttFont, version=2.0): if version >= 3.0: writer.simpletag("version", ruleVersion=self.ruleVersion) writer.newline() writesimple("info", self, writer, *attrs_info) writesimple("passindexes", self, writer, *attrs_passindexes) writesimple("contexts", self, writer, *attrs_contexts) writesimple("attributes", self, writer, *attrs_attributes) if len(self.jLevels): writer.begintag("justifications") writer.newline() jformat, jnames, jfixes = sstruct.getformat(Silf_justify_format) for i, j in enumerate(self.jLevels): attrs = dict([(k, getattr(j, k)) for k in jnames]) writer.simpletag("justify", **attrs) writer.newline() writer.endtag("justifications") writer.newline() if len(self.critFeatures): writer.begintag("critFeatures") writer.newline() writer.write(" ".join(map(str, self.critFeatures))) writer.newline() writer.endtag("critFeatures") writer.newline() if len(self.scriptTags): writer.begintag("scriptTags") writer.newline() writer.write(" ".join(self.scriptTags)) writer.newline() writer.endtag("scriptTags") writer.newline() if self.pMap: writer.begintag("pseudoMap") writer.newline() for k, v in sorted(self.pMap.items()): writer.simpletag("pseudo", unicode=hex(k), pseudo=v) writer.newline() writer.endtag("pseudoMap") writer.newline() self.classes.toXML(writer, ttFont, version) if len(self.passes): writer.begintag("passes") writer.newline() for i, p in enumerate(self.passes): writer.begintag("pass", _index=i) writer.newline() p.toXML(writer, ttFont, version) writer.endtag("pass") writer.newline() writer.endtag("passes") writer.newline()
[docs] def fromXML(self, name, attrs, content, ttFont, version=2.0): if name == "version": self.ruleVersion = float(safeEval(attrs.get("ruleVersion", "0"))) if name == "info": getSimple(self, attrs, *attrs_info) elif name == "passindexes": getSimple(self, attrs, *attrs_passindexes) elif name == "contexts": getSimple(self, attrs, *attrs_contexts) elif name == "attributes": getSimple(self, attrs, *attrs_attributes) elif name == "justifications": for element in content: if not isinstance(element, tuple): continue (tag, attrs, subcontent) = element if tag == "justify": j = _Object() for k, v in attrs.items(): setattr(j, k, int(v)) self.jLevels.append(j) elif name == "critFeatures": self.critFeatures = [] element = content_string(content) self.critFeatures.extend(map(int, element.split())) elif name == "scriptTags": self.scriptTags = [] element = content_string(content) for n in element.split(): self.scriptTags.append(n) elif name == "pseudoMap": self.pMap = {} for element in content: if not isinstance(element, tuple): continue (tag, attrs, subcontent) = element if tag == "pseudo": k = int(attrs["unicode"], 16) v = attrs["pseudo"] self.pMap[k] = v elif name == "classes": self.classes = Classes() for element in content: if not isinstance(element, tuple): continue tag, attrs, subcontent = element self.classes.fromXML(tag, attrs, subcontent, ttFont, version) elif name == "passes": for element in content: if not isinstance(element, tuple): continue tag, attrs, subcontent = element if tag == "pass": p = Pass() for e in subcontent: if not isinstance(e, tuple): continue p.fromXML(e[0], e[1], e[2], ttFont, version) self.passes.append(p)
[docs] class Classes(object): def __init__(self): self.linear = [] self.nonLinear = []
[docs] def decompile(self, data, ttFont, version=2.0): sstruct.unpack2(Silf_classmap_format, data, self) if version >= 4.0: oClasses = struct.unpack( (">%dL" % (self.numClass + 1)), data[4 : 8 + 4 * self.numClass] ) else: oClasses = struct.unpack( (">%dH" % (self.numClass + 1)), data[4 : 6 + 2 * self.numClass] ) for s, e in zip(oClasses[: self.numLinear], oClasses[1 : self.numLinear + 1]): self.linear.append( ttFont.getGlyphName(x) for x in struct.unpack((">%dH" % ((e - s) / 2)), data[s:e]) ) for s, e in zip( oClasses[self.numLinear : self.numClass], oClasses[self.numLinear + 1 : self.numClass + 1], ): nonLinids = [ struct.unpack(">HH", data[x : x + 4]) for x in range(s + 8, e, 4) ] nonLin = dict([(ttFont.getGlyphName(x[0]), x[1]) for x in nonLinids]) self.nonLinear.append(nonLin)
[docs] def compile(self, ttFont, version=2.0): data = b"" oClasses = [] if version >= 4.0: offset = 8 + 4 * (len(self.linear) + len(self.nonLinear)) else: offset = 6 + 2 * (len(self.linear) + len(self.nonLinear)) for l in self.linear: oClasses.append(len(data) + offset) gs = [ttFont.getGlyphID(x) for x in l] data += struct.pack((">%dH" % len(l)), *gs) for l in self.nonLinear: oClasses.append(len(data) + offset) gs = [(ttFont.getGlyphID(x[0]), x[1]) for x in l.items()] data += grUtils.bininfo(len(gs)) data += b"".join([struct.pack(">HH", *x) for x in sorted(gs)]) oClasses.append(len(data) + offset) self.numClass = len(oClasses) - 1 self.numLinear = len(self.linear) return ( sstruct.pack(Silf_classmap_format, self) + struct.pack( ((">%dL" if version >= 4.0 else ">%dH") % len(oClasses)), *oClasses ) + data )
[docs] def toXML(self, writer, ttFont, version=2.0): writer.begintag("classes") writer.newline() writer.begintag("linearClasses") writer.newline() for i, l in enumerate(self.linear): writer.begintag("linear", _index=i) writer.newline() wrapline(writer, l) writer.endtag("linear") writer.newline() writer.endtag("linearClasses") writer.newline() writer.begintag("nonLinearClasses") writer.newline() for i, l in enumerate(self.nonLinear): writer.begintag("nonLinear", _index=i + self.numLinear) writer.newline() for inp, ind in l.items(): writer.simpletag("map", glyph=inp, index=ind) writer.newline() writer.endtag("nonLinear") writer.newline() writer.endtag("nonLinearClasses") writer.newline() writer.endtag("classes") writer.newline()
[docs] def fromXML(self, name, attrs, content, ttFont, version=2.0): if name == "linearClasses": for element in content: if not isinstance(element, tuple): continue tag, attrs, subcontent = element if tag == "linear": l = content_string(subcontent).split() self.linear.append(l) elif name == "nonLinearClasses": for element in content: if not isinstance(element, tuple): continue tag, attrs, subcontent = element if tag == "nonLinear": l = {} for e in subcontent: if not isinstance(e, tuple): continue tag, attrs, subsubcontent = e if tag == "map": l[attrs["glyph"]] = int(safeEval(attrs["index"])) self.nonLinear.append(l)
[docs] class Pass(object): def __init__(self): self.colMap = {} self.rules = [] self.rulePreContexts = [] self.ruleSortKeys = [] self.ruleConstraints = [] self.passConstraints = b"" self.actions = [] self.stateTrans = [] self.startStates = []
[docs] def decompile(self, data, ttFont, version=2.0): _, data = sstruct.unpack2(Silf_pass_format, data, self) (numRange, _, _, _) = struct.unpack(">4H", data[:8]) data = data[8:] for i in range(numRange): (first, last, col) = struct.unpack(">3H", data[6 * i : 6 * i + 6]) for g in range(first, last + 1): self.colMap[ttFont.getGlyphName(g)] = col data = data[6 * numRange :] oRuleMap = struct.unpack_from((">%dH" % (self.numSuccess + 1)), data) data = data[2 + 2 * self.numSuccess :] rules = struct.unpack_from((">%dH" % oRuleMap[-1]), data) self.rules = [rules[s:e] for (s, e) in zip(oRuleMap, oRuleMap[1:])] data = data[2 * oRuleMap[-1] :] (self.minRulePreContext, self.maxRulePreContext) = struct.unpack("BB", data[:2]) numStartStates = self.maxRulePreContext - self.minRulePreContext + 1 self.startStates = struct.unpack( (">%dH" % numStartStates), data[2 : 2 + numStartStates * 2] ) data = data[2 + numStartStates * 2 :] self.ruleSortKeys = struct.unpack( (">%dH" % self.numRules), data[: 2 * self.numRules] ) data = data[2 * self.numRules :] self.rulePreContexts = struct.unpack( ("%dB" % self.numRules), data[: self.numRules] ) data = data[self.numRules :] (self.collisionThreshold, pConstraint) = struct.unpack(">BH", data[:3]) oConstraints = list( struct.unpack( (">%dH" % (self.numRules + 1)), data[3 : 5 + self.numRules * 2] ) ) data = data[5 + self.numRules * 2 :] oActions = list( struct.unpack((">%dH" % (self.numRules + 1)), data[: 2 + self.numRules * 2]) ) data = data[2 * self.numRules + 2 :] for i in range(self.numTransitional): a = array( "H", data[i * self.numColumns * 2 : (i + 1) * self.numColumns * 2] ) if sys.byteorder != "big": a.byteswap() self.stateTrans.append(a) data = data[self.numTransitional * self.numColumns * 2 + 1 :] self.passConstraints = data[:pConstraint] data = data[pConstraint:] for i in range(len(oConstraints) - 2, -1, -1): if oConstraints[i] == 0: oConstraints[i] = oConstraints[i + 1] self.ruleConstraints = [ (data[s:e] if (e - s > 1) else b"") for (s, e) in zip(oConstraints, oConstraints[1:]) ] data = data[oConstraints[-1] :] self.actions = [ (data[s:e] if (e - s > 1) else "") for (s, e) in zip(oActions, oActions[1:]) ] data = data[oActions[-1] :]
# not using debug
[docs] def compile(self, ttFont, base, version=2.0): # build it all up backwards oActions = reduce( lambda a, x: (a[0] + len(x), a[1] + [a[0]]), self.actions + [b""], (0, []) )[1] oConstraints = reduce( lambda a, x: (a[0] + len(x), a[1] + [a[0]]), self.ruleConstraints + [b""], (1, []), )[1] constraintCode = b"\000" + b"".join(self.ruleConstraints) transes = [] for t in self.stateTrans: if sys.byteorder != "big": t.byteswap() transes.append(t.tobytes()) if sys.byteorder != "big": t.byteswap() if not len(transes): self.startStates = [0] oRuleMap = reduce( lambda a, x: (a[0] + len(x), a[1] + [a[0]]), self.rules + [[]], (0, []) )[1] passRanges = [] gidcolmap = dict([(ttFont.getGlyphID(x[0]), x[1]) for x in self.colMap.items()]) for e in grUtils.entries(gidcolmap, sameval=True): if e[1]: passRanges.append((e[0], e[0] + e[1] - 1, e[2][0])) self.numRules = len(self.actions) self.fsmOffset = ( sstruct.calcsize(Silf_pass_format) + 8 + len(passRanges) * 6 + len(oRuleMap) * 2 + 2 * oRuleMap[-1] + 2 + 2 * len(self.startStates) + 3 * self.numRules + 3 + 4 * self.numRules + 4 ) self.pcCode = ( self.fsmOffset + 2 * self.numTransitional * self.numColumns + 1 + base ) self.rcCode = self.pcCode + len(self.passConstraints) self.aCode = self.rcCode + len(constraintCode) self.oDebug = 0 # now generate output data = sstruct.pack(Silf_pass_format, self) data += grUtils.bininfo(len(passRanges), 6) data += b"".join(struct.pack(">3H", *p) for p in passRanges) data += struct.pack((">%dH" % len(oRuleMap)), *oRuleMap) flatrules = reduce(lambda a, x: a + x, self.rules, []) data += struct.pack((">%dH" % oRuleMap[-1]), *flatrules) data += struct.pack("BB", self.minRulePreContext, self.maxRulePreContext) data += struct.pack((">%dH" % len(self.startStates)), *self.startStates) data += struct.pack((">%dH" % self.numRules), *self.ruleSortKeys) data += struct.pack(("%dB" % self.numRules), *self.rulePreContexts) data += struct.pack(">BH", self.collisionThreshold, len(self.passConstraints)) data += struct.pack((">%dH" % (self.numRules + 1)), *oConstraints) data += struct.pack((">%dH" % (self.numRules + 1)), *oActions) return ( data + b"".join(transes) + struct.pack("B", 0) + self.passConstraints + constraintCode + b"".join(self.actions) )
[docs] def toXML(self, writer, ttFont, version=2.0): writesimple("info", self, writer, *pass_attrs_info) writesimple("fsminfo", self, writer, *pass_attrs_fsm) writer.begintag("colmap") writer.newline() wrapline( writer, [ "{}={}".format(*x) for x in sorted( self.colMap.items(), key=lambda x: ttFont.getGlyphID(x[0]) ) ], ) writer.endtag("colmap") writer.newline() writer.begintag("staterulemap") writer.newline() for i, r in enumerate(self.rules): writer.simpletag( "state", number=self.numRows - self.numSuccess + i, rules=" ".join(map(str, r)), ) writer.newline() writer.endtag("staterulemap") writer.newline() writer.begintag("rules") writer.newline() for i in range(len(self.actions)): writer.begintag( "rule", index=i, precontext=self.rulePreContexts[i], sortkey=self.ruleSortKeys[i], ) writer.newline() if len(self.ruleConstraints[i]): writecode("constraint", writer, self.ruleConstraints[i]) writecode("action", writer, self.actions[i]) writer.endtag("rule") writer.newline() writer.endtag("rules") writer.newline() if len(self.passConstraints): writecode("passConstraint", writer, self.passConstraints) if len(self.stateTrans): writer.begintag("fsm") writer.newline() writer.begintag("starts") writer.write(" ".join(map(str, self.startStates))) writer.endtag("starts") writer.newline() for i, s in enumerate(self.stateTrans): writer.begintag("row", _i=i) # no newlines here writer.write(" ".join(map(str, s))) writer.endtag("row") writer.newline() writer.endtag("fsm") writer.newline()
[docs] def fromXML(self, name, attrs, content, ttFont, version=2.0): if name == "info": getSimple(self, attrs, *pass_attrs_info) elif name == "fsminfo": getSimple(self, attrs, *pass_attrs_fsm) elif name == "colmap": e = content_string(content) for w in e.split(): x = w.split("=") if len(x) != 2 or x[0] == "" or x[1] == "": continue self.colMap[x[0]] = int(x[1]) elif name == "staterulemap": for e in content: if not isinstance(e, tuple): continue tag, a, c = e if tag == "state": self.rules.append([int(x) for x in a["rules"].split(" ")]) elif name == "rules": for element in content: if not isinstance(element, tuple): continue tag, a, c = element if tag != "rule": continue self.rulePreContexts.append(int(a["precontext"])) self.ruleSortKeys.append(int(a["sortkey"])) con = b"" act = b"" for e in c: if not isinstance(e, tuple): continue tag, a, subc = e if tag == "constraint": con = readcode(subc) elif tag == "action": act = readcode(subc) self.actions.append(act) self.ruleConstraints.append(con) elif name == "passConstraint": self.passConstraints = readcode(content) elif name == "fsm": for element in content: if not isinstance(element, tuple): continue tag, a, c = element if tag == "row": s = array("H") e = content_string(c) s.extend(map(int, e.split())) self.stateTrans.append(s) elif tag == "starts": s = [] e = content_string(c) s.extend(map(int, e.split())) self.startStates = s