Esempio n. 1
0
def parseGDEF(lines, font):
    container = ttLib.getTableClass('GDEF')()
    log.debug("Parsing GDEF")
    self = ot.GDEF()
    fields = {
        'class definition begin':
        ('GlyphClassDef',
         lambda lines, font: parseClassDef(lines, font, klass=ot.GlyphClassDef)
         ),
        'attachment list begin': ('AttachList', parseAttachList),
        'carets begin': ('LigCaretList', parseCaretList),
        'mark attachment class definition begin':
        ('MarkAttachClassDef', lambda lines, font: parseClassDef(
            lines, font, klass=ot.MarkAttachClassDef)),
        'markfilter set definition begin':
        ('MarkGlyphSetsDef', parseMarkFilteringSets),
    }
    for attr, parser in fields.values():
        setattr(self, attr, None)
    while lines.peek() is not None:
        typ = lines.peek()[0].lower()
        if typ not in fields:
            log.debug('Skipping %s', typ)
            next(lines)
            continue
        attr, parser = fields[typ]
        assert getattr(self, attr) is None, attr
        setattr(self, attr, parser(lines, font))
    self.Version = 0x00010000 if self.MarkGlyphSetsDef is None else 0x00010002
    container.table = self
    return container
Esempio n. 2
0
def parseGSUBGPOS(lines, font, tableTag):
    container = ttLib.getTableClass(tableTag)()
    lookupMap = DeferredMapping()
    featureMap = DeferredMapping()
    assert tableTag in ('GSUB', 'GPOS')
    log.debug("Parsing %s", tableTag)
    self = getattr(ot, tableTag)()
    self.Version = 0x00010000
    fields = {
        'script table begin':
        ('ScriptList', lambda lines: parseScriptList(lines, featureMap)),
        'feature table begin':
        ('FeatureList',
         lambda lines: parseFeatureList(lines, lookupMap, featureMap)),
        'lookup': ('LookupList', None),
    }
    for attr, parser in fields.values():
        setattr(self, attr, None)
    while lines.peek() is not None:
        typ = lines.peek()[0].lower()
        if typ not in fields:
            log.debug('Skipping %s', lines.peek())
            next(lines)
            continue
        attr, parser = fields[typ]
        if typ == 'lookup':
            if self.LookupList is None:
                self.LookupList = ot.LookupList()
                self.LookupList.Lookup = []
            _, name, _ = lines.peek()
            lookup = parseLookup(lines, tableTag, font, lookupMap)
            if lookupMap is not None:
                assert name not in lookupMap, "Duplicate lookup name: %s" % name
                lookupMap[name] = len(self.LookupList.Lookup)
            else:
                assert int(name) == len(
                    self.LookupList.Lookup), "%d %d" % (name, len(self.Lookup))
            self.LookupList.Lookup.append(lookup)
        else:
            assert getattr(self, attr) is None, attr
            setattr(self, attr, parser(lines))
    if self.LookupList:
        self.LookupList.LookupCount = len(self.LookupList.Lookup)
    if lookupMap is not None:
        lookupMap.applyDeferredMappings()
    if featureMap is not None:
        featureMap.applyDeferredMappings()
    container.table = self
    return container
Esempio n. 3
0
def parseCmap(lines, font):
    container = ttLib.getTableClass('cmap')()
    log.debug("Parsing cmap")
    tables = []
    while lines.peek() is not None:
        lines.expect('cmap subtable %d' % len(tables))
        platId, encId, fmt, lang = [
            parseCmapId(lines, field)
            for field in ('platformID', 'encodingID', 'format', 'language')
        ]
        table = cmap_classes[fmt](fmt)
        table.platformID = platId
        table.platEncID = encId
        table.language = lang
        table.cmap = {}
        line = next(lines)
        while line[0] != 'end subtable':
            table.cmap[int(line[0], 16)] = line[1]
            line = next(lines)
        tables.append(table)
    container.tableVersion = 0
    container.tables = tables
    return container
    def merge(self, fontfiles):
        """Merges fonts together.

		Args:
			fontfiles: A list of file names to be merged

		Returns:
			A :class:`fontemon_blender_addon.fontTools.ttLib.TTFont` object. Call the ``save`` method on
			this to write it out to an OTF file.
		"""
        mega = ttLib.TTFont()

        #
        # Settle on a mega glyph order.
        #
        fonts = [ttLib.TTFont(fontfile) for fontfile in fontfiles]
        glyphOrders = [font.getGlyphOrder() for font in fonts]
        megaGlyphOrder = self._mergeGlyphOrders(glyphOrders)
        # Reload fonts and set new glyph names on them.
        # TODO Is it necessary to reload font?  I think it is.  At least
        # it's safer, in case tables were loaded to provide glyph names.
        fonts = [ttLib.TTFont(fontfile) for fontfile in fontfiles]
        for font, glyphOrder in zip(fonts, glyphOrders):
            font.setGlyphOrder(glyphOrder)
        mega.setGlyphOrder(megaGlyphOrder)

        for font in fonts:
            self._preMerge(font)

        self.fonts = fonts
        self.duplicateGlyphsPerFont = [{} for _ in fonts]

        allTags = reduce(set.union, (list(font.keys()) for font in fonts),
                         set())
        allTags.remove('GlyphOrder')

        # Make sure we process cmap before GSUB as we have a dependency there.
        if 'GSUB' in allTags:
            allTags.remove('GSUB')
            allTags = ['GSUB'] + list(allTags)
        if 'cmap' in allTags:
            allTags.remove('cmap')
            allTags = ['cmap'] + list(allTags)

        for tag in allTags:
            with timer("merge '%s'" % tag):
                tables = [font.get(tag, NotImplemented) for font in fonts]

                log.info("Merging '%s'.", tag)
                clazz = ttLib.getTableClass(tag)
                table = clazz(tag).merge(self, tables)
                # XXX Clean this up and use:  table = mergeObjects(tables)

                if table is not NotImplemented and table is not False:
                    mega[tag] = table
                    log.info("Merged '%s'.", tag)
                else:
                    log.info("Dropped '%s'.", tag)

        del self.duplicateGlyphsPerFont
        del self.fonts

        self._postMerge(mega)

        return mega
@_add_method(DefaultTable, allowDefaultTable=True)
def merge(self, m, tables):
    if not hasattr(self, 'mergeMap'):
        log.info("Don't know how to merge '%s'.", self.tableTag)
        return NotImplemented

    logic = self.mergeMap

    if isinstance(logic, dict):
        return m.mergeObjects(self, self.mergeMap, tables)
    else:
        return logic(tables)


ttLib.getTableClass('maxp').mergeMap = {
    '*': max,
    'tableTag': equal,
    'tableVersion': equal,
    'numGlyphs': sum,
    'maxStorage': first,
    'maxFunctionDefs': first,
    'maxInstructionDefs': first,
    # TODO When we correctly merge hinting data, update these values:
    # maxFunctionDefs, maxInstructionDefs, maxSizeOfInstructions
}

headFlagsMergeBitMap = {
    'size': 16,
    '*': bitwise_or,
    1: bitwise_and,  # Baseline at y = 0
from fontemon_blender_addon.fontTools.misc.py23 import *
from fontemon_blender_addon.fontTools import ttLib

superclass = ttLib.getTableClass("fpgm")


class table__p_r_e_p(superclass):
    pass
Esempio n. 7
0
        self.components = components

    def op_endchar(self, index):
        args = self.popall()
        if len(args) >= 4:
            from fontemon_blender_addon.fontTools.encodings.StandardEncoding import StandardEncoding
            # endchar can do seac accent bulding; The T2 spec says it's deprecated,
            # but recent software that shall remain nameless does output it.
            adx, ady, bchar, achar = args[-4:]
            baseGlyph = StandardEncoding[bchar]
            accentGlyph = StandardEncoding[achar]
            self.components.add(baseGlyph)
            self.components.add(accentGlyph)


@_add_method(ttLib.getTableClass('CFF '))
def closure_glyphs(self, s):
    cff = self.cff
    assert len(cff) == 1
    font = cff[cff.keys()[0]]
    glyphSet = font.CharStrings

    decompose = s.glyphs
    while decompose:
        components = set()
        for g in decompose:
            if g not in glyphSet:
                continue
            gl = glyphSet[g]

            subrs = getattr(gl.private, "Subrs", [])
Esempio n. 8
0
from fontemon_blender_addon.fontTools.misc.py23 import *
from fontemon_blender_addon.fontTools import ttLib

superclass = ttLib.getTableClass("hmtx")


class table__v_m_t_x(superclass):

    headerTag = 'vhea'
    advanceName = 'height'
    sideBearingName = 'tsb'
    numberOfMetricsName = 'numberOfVMetrics'
""" TSI{0,1,2,3,5} are private tables used by Microsoft Visual TrueType (VTT)
tool to store its hinting source data.

TSI3 contains the text of the glyph programs in the form of 'VTTTalk' code.
"""
from fontemon_blender_addon.fontTools.misc.py23 import *
from fontemon_blender_addon.fontTools import ttLib

superclass = ttLib.getTableClass("TSI1")


class table_T_S_I__3(superclass):

    extras = {
        0xfffa: "reserved0",
        0xfffb: "reserved1",
        0xfffc: "reserved2",
        0xfffd: "reserved3"
    }

    indextable = "TSI2"
 def _startElementHandler(self, name, attrs):
     if self.stackSize == 1 and self.contentOnly:
         # We already know the table we're parsing, skip
         # parsing the table tag and continue to
         # stack '2' which begins parsing content
         self.contentStack.append([])
         self.stackSize = 2
         return
     stackSize = self.stackSize
     self.stackSize = stackSize + 1
     subFile = attrs.get("src")
     if subFile is not None:
         if hasattr(self.file, 'name'):
             # if file has a name, get its parent directory
             dirname = os.path.dirname(self.file.name)
         else:
             # else fall back to using the current working directory
             dirname = os.getcwd()
         subFile = os.path.join(dirname, subFile)
     if not stackSize:
         if name != "ttFont":
             raise TTXParseError("illegal root tag: %s" % name)
         sfntVersion = attrs.get("sfntVersion")
         if sfntVersion is not None:
             if len(sfntVersion) != 4:
                 sfntVersion = safeEval('"' + sfntVersion + '"')
             self.ttFont.sfntVersion = sfntVersion
         self.contentStack.append([])
     elif stackSize == 1:
         if subFile is not None:
             subReader = XMLReader(subFile, self.ttFont, self.progress)
             subReader.read()
             self.contentStack.append([])
             return
         tag = ttLib.xmlToTag(name)
         msg = "Parsing '%s' table..." % tag
         if self.progress:
             self.progress.setLabel(msg)
         log.info(msg)
         if tag == "GlyphOrder":
             tableClass = ttLib.GlyphOrder
         elif "ERROR" in attrs or ('raw' in attrs
                                   and safeEval(attrs['raw'])):
             tableClass = DefaultTable
         else:
             tableClass = ttLib.getTableClass(tag)
             if tableClass is None:
                 tableClass = DefaultTable
         if tag == 'loca' and tag in self.ttFont:
             # Special-case the 'loca' table as we need the
             #    original if the 'glyf' table isn't recompiled.
             self.currentTable = self.ttFont[tag]
         else:
             self.currentTable = tableClass(tag)
             self.ttFont[tag] = self.currentTable
         self.contentStack.append([])
     elif stackSize == 2 and subFile is not None:
         subReader = XMLReader(subFile,
                               self.ttFont,
                               self.progress,
                               contentOnly=True)
         subReader.read()
         self.contentStack.append([])
         self.root = subReader.root
     elif stackSize == 2:
         self.contentStack.append([])
         self.root = (name, attrs, self.contentStack[-1])
     else:
         l = []
         self.contentStack[-1].append((name, attrs, l))
         self.contentStack.append(l)