def __init__(self, text, glyph_set): feature_file = StringIO(text) parser_ = parser.Parser(feature_file, glyph_set, followIncludes=False) self._doc = parser_.parse() self.statements = self._doc.statements self._lines = text.splitlines(True) # keepends=True self._build_end_locations()
def merge(args): arabic = Font(args.arabicfile) to_ufo_propagate_font_anchors(None, arabic) latin = Font(args.latinfile) addPlaceHolders(arabic) unicodes = [] for glyph in arabic: unicodes.extend(glyph.unicodes) for name in latin.glyphOrder: if name in ("space", "nbspace", "CR", "NULL", ".notdef"): continue glyph = latin[name] assert glyph.name not in arabic, glyph.name assert glyph.unicodes not in unicodes, glyph.unicodes # Strip anchors from f_ ligatures, there are broken. # See https://github.com/googlei18n/glyphsLib/issues/313 if name.startswith("f_"): glyph.anchors = {} arabic.insertGlyph(glyph) # Copy kerning and groups. arabic.groups.update(latin.groups) arabic.kerning.update(latin.kerning) for attr in ("xHeight", "capHeight"): value = getattr(latin.info, attr) if value is not None: setattr(arabic.info, attr, getattr(latin.info, attr)) # Merge Arabic and Latin features, making sure languagesystem statements # come first. langsys = [] statements = [] for font in (arabic, latin): featurefile = UnicodeIO(tounicode(font.features.text)) fea = parser.Parser(featurefile, []).parse() langsys += [ s for s in fea.statements if isinstance(s, ast.LanguageSystemStatement) ] statements += [ s for s in fea.statements if not isinstance(s, ast.LanguageSystemStatement) ] # Drop GDEF table, we want to generate one based on final features. statements = [s for s in statements if not isinstance(s, ast.TableBlock)] # Make sure DFLT is the first. langsys = sorted(langsys, key=attrgetter("script")) fea.statements = langsys + statements arabic.features.text = fea.asFea() glyphOrder = arabic.glyphOrder + latin.glyphOrder # Make sure we have a fixed glyph order by using the original Arabic and # Latin glyph order, not whatever we end up with after adding glyphs. arabic.glyphOrder = sorted(arabic.glyphOrder, key=glyphOrder.index) # Set metadata arabic.info.versionMajor, arabic.info.versionMinor = map( int, args.version.split(".")) arabic.info.copyright = u"Copyright © 2015-%s The Reem Kufi Project Authors." % datetime.now( ).year return arabic
def merge(args): """Merges Arabic and Latin fonts together, and messages the combined font a bit. Returns the combined font.""" ufo = Font(args.arabicfile) to_ufo_propagate_font_anchors(None, ufo) latin = Font(args.latinfile) ufo.lib[POSTSCRIPT_NAMES] = {} # Save original glyph order, used below. glyphOrder = ufo.glyphOrder + latin.glyphOrder # Generate production glyph names for Arabic glyphs, in case it differs # from working names. This will be used by ufo2ft to set the final glyph # names in the font file. for glyph in ufo: if glyph.unicode is not None: if glyph.unicode < 0xffff: postName = "uni%04X" % glyph.unicode else: postName = "u%06X" % glyph.unicode if postName != glyph.name: ufo.lib[POSTSCRIPT_NAMES][glyph.name] = postName # Merge Arabic and Latin features, making sure languagesystem statements # come first. features = ufo.features langsys = [] statements = [] for font in (ufo, latin): featurefile = os.path.join(font.path, "features.fea") fea = parser.Parser(featurefile, font.glyphOrder).parse() langsys += [ s for s in fea.statements if isinstance(s, ast.LanguageSystemStatement) ] statements += [ s for s in fea.statements if not isinstance(s, ast.LanguageSystemStatement) ] # We will regenerate kern, mark and mkmk features, and aalt is useless. statements = [ s for s in statements if getattr(s, "name", None) not in ("aalt", "kern", "mark", "mkmk") ] # These will be regenerated as well statements = [ s for s in statements if not isinstance(s, ast.MarkClassDefinition) ] # Drop tables in fea, we don’t want them. statements = [s for s in statements if not isinstance(s, ast.TableBlock)] # Make sure DFLT is the first. langsys = sorted(langsys, key=attrgetter("script")) fea.statements = langsys + statements features.text = fea.asFea() features.text += generateStyleSets(ufo) # Source Sans Pro has different advance widths for space and NBSP # glyphs, fix it. latin["nbspace"].width = latin["space"].width # Set Latin production names ufo.lib[POSTSCRIPT_NAMES].update(latin.lib[POSTSCRIPT_NAMES]) # Copy Latin glyphs. for name in latin.glyphOrder: glyph = latin[name] # Remove anchors from spacing marks, otherwise ufo2ft will give them # mark glyph class which will cause HarfBuzz to zero their width. if glyph.unicode and unicodedata.category(unichr( glyph.unicode)) in ("Sk", "Lm"): for anchor in glyph.anchors: glyph.removeAnchor(anchor) # Add Arabic anchors to the dotted circle, we use an offset of 100 # units because the Latin anchors are too close to the glyph. offset = 100 if glyph.unicode == 0x25CC: for anchor in glyph.anchors: if anchor.name == "aboveLC": glyph.appendAnchor( dict(name="markAbove", x=anchor.x, y=anchor.y + offset)) glyph.appendAnchor( dict(name="hamzaAbove", x=anchor.x, y=anchor.y + offset)) if anchor.name == "belowLC": glyph.appendAnchor( dict(name="markBelow", x=anchor.x, y=anchor.y - offset)) glyph.appendAnchor( dict(name="hamzaBelow", x=anchor.x, y=anchor.y - offset)) # Break loudly if we have duplicated glyph in Latin and Arabic. # TODO should check duplicated Unicode values as well assert glyph.name not in ufo, glyph.name ufo.insertGlyph(glyph) # Copy kerning and groups. ufo.groups.update(latin.groups) ufo.kerning.update(latin.kerning) # We don’t set these in the Arabic font, so we just copy the Latin’s. for attr in ("xHeight", "capHeight"): value = getattr(latin.info, attr) if value is not None: setattr(ufo.info, attr, getattr(latin.info, attr)) # Make sure we don’t have glyphs with the same unicode value unicodes = [] for glyph in ufo: unicodes.extend(glyph.unicodes) duplicates = set([u for u in unicodes if unicodes.count(u) > 1]) assert len(duplicates) == 0, "Duplicate unicodes: %s " % ( ["%04X" % d for d in duplicates]) # Make sure we have a fixed glyph order by using the original Arabic and # Latin glyph order, not whatever we end up with after adding glyphs. ufo.glyphOrder = sorted(ufo.glyphOrder, key=glyphOrder.index) return ufo