Beispiel #1
0
 def test_updateGlyphOrder_rename(self):
     font = Font(getTestFontPath())
     self.assertEqual(font.glyphOrder, [])
     font.glyphOrder = sorted(font.keys())
     self.assertEqual(font.glyphOrder, ["A", "B", "C"])
     font.updateGlyphOrder(addedGlyph="new", removedGlyph="B")
     self.assertEqual(font.glyphOrder, ["A", "new", "C"])
Beispiel #2
0
 def test_updateGlyphOrder_remove(self):
     font = Font(getTestFontPath())
     self.assertEqual(font.glyphOrder, [])
     font.glyphOrder = ["test"]
     self.assertEqual(font.glyphOrder, ["test"])
     font.updateGlyphOrder(removedGlyph="test")
     self.assertEqual(font.glyphOrder, [])
Beispiel #3
0
 def test_updateGlyphOrder_remove(self):
     font = Font(getTestFontPath())
     self.assertEqual(font.glyphOrder, [])
     font.glyphOrder = ["test"]
     self.assertEqual(font.glyphOrder, ["test"])
     font.updateGlyphOrder(removedGlyph="test")
     self.assertEqual(font.glyphOrder, [])
Beispiel #4
0
 def test_updateGlyphOrder_rename(self):
     font = Font(getTestFontPath())
     self.assertEqual(font.glyphOrder, [])
     font.glyphOrder = sorted(font.keys())
     self.assertEqual(font.glyphOrder, ["A", "B", "C"])
     font.updateGlyphOrder(addedGlyph="new", removedGlyph="B")
     self.assertEqual(font.glyphOrder, ["A", "new", "C"])
Beispiel #5
0
 def test_glyphOrder(self):
     font = Font(getTestFontPath())
     self.assertEqual(font.glyphOrder, [])
     font.glyphOrder = sorted(font.keys())
     self.assertEqual(font.glyphOrder, ["A", "B", "C"])
     layer = font.layers["public.default"]
     layer.newGlyph("X")
     self.assertEqual(sorted(layer.keys()), ["A", "B", "C", "X"])
     self.assertEqual(font.glyphOrder, ["A", "B", "C", "X"])
     del layer["A"]
     self.assertEqual(font.glyphOrder, ["A", "B", "C", "X"])
     del layer["X"]
     self.assertEqual(font.glyphOrder, ["A", "B", "C"])
Beispiel #6
0
 def test_glyphOrder(self):
     font = Font(getTestFontPath())
     self.assertEqual(font.glyphOrder, [])
     font.glyphOrder = sorted(font.keys())
     self.assertEqual(font.glyphOrder, ["A", "B", "C"])
     layer = font.layers.defaultLayer
     layer.newGlyph("X")
     self.assertEqual(sorted(layer.keys()), ["A", "B", "C", "X"])
     self.assertEqual(font.glyphOrder, ["A", "B", "C", "X"])
     del layer["A"]
     self.assertEqual(font.glyphOrder, ["A", "B", "C", "X"])
     del layer["X"]
     self.assertEqual(font.glyphOrder, ["A", "B", "C"])
     layer["B"].name = "Y"
     self.assertEqual(font.glyphOrder, ["A", "Y", "C"])
Beispiel #7
0
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
Beispiel #8
0
def merge(args):
    """Merges Arabic and Latin fonts together, and messages the combined font a
    bit. Returns the combined font."""

    ufo = Font(args.arabicfile)

    propagate_font_anchors(ufo)

    latin = Font(args.latinfile)
    # Parse the GlyphOrderAndAliasDB file for Unicode values and production
    # glyph names of the Latin glyphs.
    goadb = GOADBParser(
        os.path.dirname(args.latinfile) + "/../GlyphOrderAndAliasDB")

    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

    # Populate the font’s feature text, we keep our main feature file out of
    # the UFO to share it between the fonts.
    features = ufo.features
    with open(args.feature_file) as feafile:
        fea = feafile.read()
        # Set Latin language system, ufo2ft will use it when generating kern
        # feature.
        features.text += fea.replace("#{languagesystems}",
                                     "languagesystem latn dflt;")
    features.text += generateStyleSets(ufo)

    for glyph in latin:
        if glyph.name in goadb.encodings:
            glyph.unicode = goadb.encodings[glyph.name]

    # Source Sans Pro has different advance widths for space and NBSP
    # glyphs, fix it.
    latin["nbspace"].width = latin["space"].width

    glyphs, components = collectGlyphs(latin, args.latin_subset)

    counter = Counter(components)
    uniqueComponents = set()
    for name in counter:
        if name not in glyphs:
            latin[name].unicode = None
        if counter[name] == 1:
            uniqueComponents.add(name)
        else:
            glyphs.add(name)

    # Set Latin production names
    ufo.lib[POSTSCRIPT_NAMES].update(goadb.names)

    # Copy Latin glyphs.
    for name in glyphs:
        glyph = latin[name]
        for component in glyph.components:
            if component.baseGlyph in uniqueComponents:
                glyph.decomposeComponent(component)
        # 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))

    # MutatorMath does not like multiple unicodes and will drop it entirely,
    # turning the glyph unencoded:
    # https://github.com/LettError/MutatorMath/issues/85
    for glyph in ufo:
        assert not " " in glyph.unicodes

    # 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
Beispiel #9
0
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
Beispiel #10
0
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