Ejemplo n.º 1
0
def _add_MVAR(font, model, master_ttfs, axisTags):

    log.info("Generating MVAR")

    store_builder = varStore.OnlineVarStoreBuilder(axisTags)
    store_builder.setModel(model)

    records = []
    lastTableTag = None
    fontTable = None
    tables = None
    for tag, (tableTag, itemName) in sorted(MVAR_ENTRIES.items(),
                                            key=lambda kv: kv[1]):
        if tableTag != lastTableTag:
            tables = fontTable = None
            if tableTag in font:
                # TODO Check all masters have same table set?
                fontTable = font[tableTag]
                tables = [master[tableTag] for master in master_ttfs]
            lastTableTag = tableTag
        if tables is None:
            continue

        # TODO support gasp entries

        master_values = [getattr(table, itemName) for table in tables]
        if _all_equal(master_values):
            base, varIdx = master_values[0], None
        else:
            base, varIdx = store_builder.storeMasters(master_values)
        setattr(fontTable, itemName, base)

        if varIdx is None:
            continue
        log.info('	%s: %s.%s	%s', tag, tableTag, itemName, master_values)
        rec = ot.MetricsValueRecord()
        rec.ValueTag = tag
        rec.VarIdx = varIdx
        records.append(rec)

    assert "MVAR" not in font
    if records:
        store = store_builder.finish()
        # Optimize
        mapping = store.optimize()
        for rec in records:
            rec.VarIdx = mapping[rec.VarIdx]

        MVAR = font["MVAR"] = newTable('MVAR')
        mvar = MVAR.table = ot.MVAR()
        mvar.Version = 0x00010000
        mvar.Reserved = 0
        mvar.VarStore = store
        # XXX these should not be hard-coded but computed automatically
        mvar.ValueRecordSize = 8
        mvar.ValueRecordCount = len(records)
        mvar.ValueRecord = sorted(records, key=lambda r: r.ValueTag)
Ejemplo n.º 2
0
 def __init__(self, model, axisTags, font):
     Merger.__init__(self, font)
     self.store_builder = varStore.OnlineVarStoreBuilder(axisTags)
     self.setModel(model)
Ejemplo n.º 3
0
def _add_MVAR(font, masterModel, master_ttfs, axisTags):

    log.info("Generating MVAR")

    store_builder = varStore.OnlineVarStoreBuilder(axisTags)

    records = []
    lastTableTag = None
    fontTable = None
    tables = None
    # HACK: we need to special-case post.underlineThickness and .underlinePosition
    # and unilaterally/arbitrarily define a sentinel value to distinguish the case
    # when a post table is present in a given master simply because that's where
    # the glyph names in TrueType must be stored, but the underline values are not
    # meant to be used for building MVAR's deltas. The value of -0x8000 (-36768)
    # the minimum FWord (int16) value, was chosen for its unlikelyhood to appear
    # in real-world underline position/thickness values.
    specialTags = {"unds": -0x8000, "undo": -0x8000}

    for tag, (tableTag, itemName) in sorted(MVAR_ENTRIES.items(),
                                            key=lambda kv: kv[1]):
        # For each tag, fetch the associated table from all fonts (or not when we are
        # still looking at a tag from the same tables) and set up the variation model
        # for them.
        if tableTag != lastTableTag:
            tables = fontTable = None
            if tableTag in font:
                fontTable = font[tableTag]
                tables = []
                for master in master_ttfs:
                    if tableTag not in master or (
                            tag in specialTags
                            and getattr(master[tableTag],
                                        itemName) == specialTags[tag]):
                        tables.append(None)
                    else:
                        tables.append(master[tableTag])
                model, tables = masterModel.getSubModel(tables)
                store_builder.setModel(model)
            lastTableTag = tableTag

        if tables is None:  # Tag not applicable to the master font.
            continue

        # TODO support gasp entries

        master_values = [getattr(table, itemName) for table in tables]
        if models.allEqual(master_values):
            base, varIdx = master_values[0], None
        else:
            base, varIdx = store_builder.storeMasters(master_values)
        setattr(fontTable, itemName, base)

        if varIdx is None:
            continue
        log.info('	%s: %s.%s	%s', tag, tableTag, itemName, master_values)
        rec = ot.MetricsValueRecord()
        rec.ValueTag = tag
        rec.VarIdx = varIdx
        records.append(rec)

    assert "MVAR" not in font
    if records:
        store = store_builder.finish()
        # Optimize
        mapping = store.optimize()
        for rec in records:
            rec.VarIdx = mapping[rec.VarIdx]

        MVAR = font["MVAR"] = newTable('MVAR')
        mvar = MVAR.table = ot.MVAR()
        mvar.Version = 0x00010000
        mvar.Reserved = 0
        mvar.VarStore = store
        # XXX these should not be hard-coded but computed automatically
        mvar.ValueRecordSize = 8
        mvar.ValueRecordCount = len(records)
        mvar.ValueRecord = sorted(records, key=lambda r: r.ValueTag)
Ejemplo n.º 4
0
def _get_advance_metrics(font,
                         masterModel,
                         master_ttfs,
                         axisTags,
                         glyphOrder,
                         advMetricses,
                         vOrigMetricses=None):

    vhAdvanceDeltasAndSupports = {}
    vOrigDeltasAndSupports = {}
    for glyph in glyphOrder:
        vhAdvances = [
            metrics[glyph][0] if glyph in metrics else None
            for metrics in advMetricses
        ]
        vhAdvanceDeltasAndSupports[glyph] = masterModel.getDeltasAndSupports(
            vhAdvances, round=round)

    singleModel = models.allEqual(
        id(v[1]) for v in vhAdvanceDeltasAndSupports.values())

    if vOrigMetricses:
        singleModel = False
        for glyph in glyphOrder:
            # We need to supply a vOrigs tuple with non-None default values
            # for each glyph. vOrigMetricses contains values only for those
            # glyphs which have a non-default vOrig.
            vOrigs = [
                metrics[glyph] if glyph in metrics else defaultVOrig
                for metrics, defaultVOrig in vOrigMetricses
            ]
            vOrigDeltasAndSupports[glyph] = masterModel.getDeltasAndSupports(
                vOrigs, round=round)

    directStore = None
    if singleModel:
        # Build direct mapping
        supports = next(iter(vhAdvanceDeltasAndSupports.values()))[1][1:]
        varTupleList = builder.buildVarRegionList(supports, axisTags)
        varTupleIndexes = list(range(len(supports)))
        varData = builder.buildVarData(varTupleIndexes, [], optimize=False)
        for glyphName in glyphOrder:
            varData.addItem(vhAdvanceDeltasAndSupports[glyphName][0],
                            round=noRound)
        varData.optimize()
        directStore = builder.buildVarStore(varTupleList, [varData])

    # Build optimized indirect mapping
    storeBuilder = varStore.OnlineVarStoreBuilder(axisTags)
    advMapping = {}
    for glyphName in glyphOrder:
        deltas, supports = vhAdvanceDeltasAndSupports[glyphName]
        storeBuilder.setSupports(supports)
        advMapping[glyphName] = storeBuilder.storeDeltas(deltas, round=noRound)

    if vOrigMetricses:
        vOrigMap = {}
        for glyphName in glyphOrder:
            deltas, supports = vOrigDeltasAndSupports[glyphName]
            storeBuilder.setSupports(supports)
            vOrigMap[glyphName] = storeBuilder.storeDeltas(deltas,
                                                           round=noRound)

    indirectStore = storeBuilder.finish()
    mapping2 = indirectStore.optimize()
    advMapping = [mapping2[advMapping[g]] for g in glyphOrder]
    advanceMapping = builder.buildVarIdxMap(advMapping, glyphOrder)

    if vOrigMetricses:
        vOrigMap = [mapping2[vOrigMap[g]] for g in glyphOrder]

    useDirect = False
    vOrigMapping = None
    if directStore:
        # Compile both, see which is more compact

        writer = OTTableWriter()
        directStore.compile(writer, font)
        directSize = len(writer.getAllData())

        writer = OTTableWriter()
        indirectStore.compile(writer, font)
        advanceMapping.compile(writer, font)
        indirectSize = len(writer.getAllData())

        useDirect = directSize < indirectSize

    if useDirect:
        metricsStore = directStore
        advanceMapping = None
    else:
        metricsStore = indirectStore
        if vOrigMetricses:
            vOrigMapping = builder.buildVarIdxMap(vOrigMap, glyphOrder)

    return metricsStore, advanceMapping, vOrigMapping
Ejemplo n.º 5
0
def _add_HVAR(font, masterModel, master_ttfs, axisTags):

    log.info("Generating HVAR")

    glyphOrder = font.getGlyphOrder()

    hAdvanceDeltasAndSupports = {}
    metricses = [m["hmtx"].metrics for m in master_ttfs]
    for glyph in glyphOrder:
        hAdvances = [
            metrics[glyph][0] if glyph in metrics else None
            for metrics in metricses
        ]
        hAdvanceDeltasAndSupports[glyph] = masterModel.getDeltasAndSupports(
            hAdvances)

    singleModel = models.allEqual(
        id(v[1]) for v in hAdvanceDeltasAndSupports.values())

    directStore = None
    if singleModel:
        # Build direct mapping

        supports = next(iter(hAdvanceDeltasAndSupports.values()))[1][1:]
        varTupleList = builder.buildVarRegionList(supports, axisTags)
        varTupleIndexes = list(range(len(supports)))
        varData = builder.buildVarData(varTupleIndexes, [], optimize=False)
        for glyphName in glyphOrder:
            varData.addItem(hAdvanceDeltasAndSupports[glyphName][0])
        varData.optimize()
        directStore = builder.buildVarStore(varTupleList, [varData])

    # Build optimized indirect mapping
    storeBuilder = varStore.OnlineVarStoreBuilder(axisTags)
    mapping = {}
    for glyphName in glyphOrder:
        deltas, supports = hAdvanceDeltasAndSupports[glyphName]
        storeBuilder.setSupports(supports)
        mapping[glyphName] = storeBuilder.storeDeltas(deltas)
    indirectStore = storeBuilder.finish()
    mapping2 = indirectStore.optimize()
    mapping = [mapping2[mapping[g]] for g in glyphOrder]
    advanceMapping = builder.buildVarIdxMap(mapping, glyphOrder)

    use_direct = False
    if directStore:
        # Compile both, see which is more compact

        writer = OTTableWriter()
        directStore.compile(writer, font)
        directSize = len(writer.getAllData())

        writer = OTTableWriter()
        indirectStore.compile(writer, font)
        advanceMapping.compile(writer, font)
        indirectSize = len(writer.getAllData())

        use_direct = directSize < indirectSize

    # Done; put it all together.
    assert "HVAR" not in font
    HVAR = font["HVAR"] = newTable('HVAR')
    hvar = HVAR.table = ot.HVAR()
    hvar.Version = 0x00010000
    hvar.LsbMap = hvar.RsbMap = None
    if use_direct:
        hvar.VarStore = directStore
        hvar.AdvWidthMap = None
    else:
        hvar.VarStore = indirectStore
        hvar.AdvWidthMap = advanceMapping