def test_Vector(): v = Vector([100, 200]) assert v == Vector([100, 200]) assert v == [100, 200] assert v + Vector([1, 2]) == [101, 202] assert v - Vector([1, 2]) == [99, 198] assert v * 2 == [200, 400] assert v * 0.5 == [50, 100] assert v / 2 == [50, 100]
def _merge_TTHinting(font, model, master_ttfs, tolerance=0.5): log.info("Merging TT hinting") assert "cvar" not in font # Check that the existing hinting is compatible # fpgm and prep table for tag in ("fpgm", "prep"): all_pgms = [m[tag].program for m in master_ttfs if tag in m] if len(all_pgms) == 0: continue if tag in font: font_pgm = font[tag].program else: font_pgm = Program() if any(pgm != font_pgm for pgm in all_pgms): log.warning("Masters have incompatible %s tables, hinting is discarded." % tag) _remove_TTHinting(font) return # glyf table for name, glyph in font["glyf"].glyphs.items(): all_pgms = [ m["glyf"][name].program for m in master_ttfs if hasattr(m["glyf"][name], "program") ] if not any(all_pgms): continue glyph.expand(font["glyf"]) if hasattr(glyph, "program"): font_pgm = glyph.program else: font_pgm = Program() if any(pgm != font_pgm for pgm in all_pgms if pgm): log.warning("Masters have incompatible glyph programs in glyph '%s', hinting is discarded." % name) _remove_TTHinting(font) return # cvt table all_cvs = [Vector(m["cvt "].values) for m in master_ttfs if "cvt " in m] if len(all_cvs) == 0: # There is no cvt table to make a cvar table from, we're done here. return if len(all_cvs) != len(master_ttfs): log.warning("Some masters have no cvt table, hinting is discarded.") _remove_TTHinting(font) return num_cvt0 = len(all_cvs[0]) if (any(len(c) != num_cvt0 for c in all_cvs)): log.warning("Masters have incompatible cvt tables, hinting is discarded.") _remove_TTHinting(font) return # We can build the cvar table now. cvar = font["cvar"] = newTable('cvar') cvar.version = 1 cvar.variations = [] deltas = model.getDeltas(all_cvs) supports = model.supports for i,(delta,support) in enumerate(zip(deltas[1:], supports[1:])): delta = [int(round(d)) for d in delta] if all(abs(v) <= tolerance for v in delta): continue var = TupleVariation(support, delta) cvar.variations.append(var)
def compile_instructions(font, ship=True, keep_cvar=False): if "glyf" not in font: raise VTTLibError("Missing 'glyf' table; not a TrueType font") if "TSI1" not in font: raise VTTLibError("The font contains no 'TSI1' table") if keep_cvar and "cvar" not in font: raise VTTLibError( "The keep_cvar parameter is set, but the cvar table is missing from the font" ) control_program = get_extra_assembly(font, "cvt") set_cvt_table(font, control_program) if "TSIC" in font and not keep_cvar: # Compile TSIC tsic = font["TSIC"].table cvts = font["cvt "].values # Gather the full set of cvts (not just those in TSIC) for all locations cvt_sets = [Vector(cvts)] for record in tsic.Record: cvt_local = { i: v for i, v in zip(record.CVTArray, record.CVTValueArray) } cvt_set = [ cvt_local[i] if i in cvt_local else cvt for i, cvt in enumerate(cvts) ] cvt_sets.append(Vector(cvt_set)) # Compute variations locs = [{axis_tag: 0.0 for axis_tag in tsic.AxisArray}] # default instance locs += [{ axis_tag: val for axis_tag, val in zip(tsic.AxisArray, loc.Axis) } for loc in tsic.RecordLocations] model = models.VariationModel(locs) variations = [] deltas, supports = model.getDeltasAndSupports(cvt_sets) for i, (delta, support) in enumerate(zip(deltas[1:], supports[1:])): delta = [otRound(d) for d in delta] if all(abs(v) <= 0.5 for v in delta): continue # Remove any deltas that weren't specified in TSIC at this location # TODO: Just replace optimizaton with getting rid of 0 deltas? tsic_rec_index = model.reverseMapping[ i + 1] - 1 # Map back to TSIC records delta = [ d if j in tsic.Record[tsic_rec_index].CVTArray and d != 0 else None for j, d in enumerate(delta) ] var = TupleVariation(support, delta) variations.append(var) if variations: cvar = font["cvar"] = newTable("cvar") cvar.version = 1 cvar.variations = variations for tag in ("prep", "fpgm"): if tag not in font: font[tag] = newTable(tag) data = get_extra_assembly(font, tag) font[tag].program = make_program(data, tag) glyph_order = font.getGlyphOrder() glyf_table = font["glyf"] for glyph_name in glyph_order: try: data = get_glyph_assembly(font, glyph_name) except KeyError: continue program, components = make_glyph_program(data, glyph_name) if program or components: glyph = glyf_table[glyph_name] if components: if not glyph.isComposite(): log.warning( "Glyph '%s' contains components in VTT assembly but " "not in glyf table; drop assembly and skip " "compilation" % glyph_name) set_glyph_assembly(font, glyph_name, "") else: check_composite_info(glyph_name, glyph, components, glyph_order) set_components_flags(glyph, components) if program: glyph.program = program if ship: for tag in ("TSI%s" % i for i in (0, 1, 2, 3, 5, "C")): if tag in font: del font[tag]
def _merge_TTHinting(font, masterModel, master_ttfs, tolerance=0.5): log.info("Merging TT hinting") assert "cvar" not in font # Check that the existing hinting is compatible # fpgm and prep table for tag in ("fpgm", "prep"): all_pgms = [m[tag].program for m in master_ttfs if tag in m] if len(all_pgms) == 0: continue if tag in font: font_pgm = font[tag].program else: font_pgm = Program() if any(pgm != font_pgm for pgm in all_pgms): log.warning( "Masters have incompatible %s tables, hinting is discarded." % tag) _remove_TTHinting(font) return # glyf table for name, glyph in font["glyf"].glyphs.items(): all_pgms = [ m["glyf"][name].program for m in master_ttfs if name in m['glyf'] and hasattr(m["glyf"][name], "program") ] if not any(all_pgms): continue glyph.expand(font["glyf"]) if hasattr(glyph, "program"): font_pgm = glyph.program else: font_pgm = Program() if any(pgm != font_pgm for pgm in all_pgms if pgm): log.warning( "Masters have incompatible glyph programs in glyph '%s', hinting is discarded." % name) # TODO Only drop hinting from this glyph. _remove_TTHinting(font) return # cvt table all_cvs = [ Vector(m["cvt "].values) if 'cvt ' in m else None for m in master_ttfs ] nonNone_cvs = models.nonNone(all_cvs) if not nonNone_cvs: # There is no cvt table to make a cvar table from, we're done here. return if not models.allEqual(len(c) for c in nonNone_cvs): log.warning( "Masters have incompatible cvt tables, hinting is discarded.") _remove_TTHinting(font) return variations = [] deltas, supports = masterModel.getDeltasAndSupports(all_cvs) for i, (delta, support) in enumerate(zip(deltas[1:], supports[1:])): delta = [otRound(d) for d in delta] if all(abs(v) <= tolerance for v in delta): continue var = TupleVariation(support, delta) variations.append(var) # We can build the cvar table now. if variations: cvar = font["cvar"] = newTable('cvar') cvar.version = 1 cvar.variations = variations