Ejemplo n.º 1
0
def makeNumerators(font):
    digits = ("zero", "one", "two", "three", "four", "five", "six", "seven",
              "eight", "nine", "uni0660", "uni0661", "uni0662", "uni0663",
              "uni0664", "uni0665", "uni0666", "uni0667", "uni0668", "uni0669",
              "uni06F0", "uni06F1", "uni06F2", "uni06F3", "uni06F4", "uni06F5",
              "uni06F6", "uni06F7", "uni06F8", "uni06F9", "uni06F4.urd",
              "uni06F6.urd", "uni06F7.urd")
    for name in digits:
        numr = font.createChar(-1, name + ".numr")
        small = font[name + ".small"]
        if not numr.isWorthOutputting():
            numr.clear()
            numr.addReference(small.glyphname, psMat.translate(0, 550))
            numr.width = small.width
Ejemplo n.º 2
0
def makeNumerators(font):
    digits = ("zero", "one", "two", "three", "four", "five", "six", "seven",
              "eight", "nine",
              "uni0660", "uni0661", "uni0662", "uni0663", "uni0664",
              "uni0665", "uni0666", "uni0667", "uni0668", "uni0669",
              "uni06F0", "uni06F1", "uni06F2", "uni06F3", "uni06F4",
              "uni06F5", "uni06F6", "uni06F7", "uni06F8", "uni06F9",
              "uni06F4.urd", "uni06F6.urd", "uni06F7.urd")
    for name in digits:
        numr = font.createChar(-1, name + ".numr")
        small = font[name + ".small"]
        if not numr.isWorthOutputting():
            numr.clear()
            numr.addReference(small.glyphname, psMat.translate(0, 550))
            numr.width = small.width
Ejemplo n.º 3
0
def test_translate(x, y):
    a = psMat.translate(x, y)
    print(x, y, a)

    if not isinstance(a, tuple):
        exit(10)
    if len(a) != 6:
        exit(20)
    for element in a:
        if not isinstance(element, float):
            exit(30)

    for i in range(0, 6):
        if 1000 * eps < abs(a[i] - (1, 0, 0, 1, x, y)[i]):
            exit(50)
Ejemplo n.º 4
0
def test_translate (x, y):
    a = psMat.translate (x, y)
    print (x, y, a)

    if not isinstance (a, tuple):
        exit (10)
    if len (a) != 6:
        exit (20)
    for element in a:
        if not isinstance (element, float):
            exit (30)

    for i in range (0, 6):
        if 1000 * eps < abs (a[i] - (1, 0, 0, 1, x, y)[i]):
            exit (50)
Ejemplo n.º 5
0
def scaleGlyph(glyph, amount):
    """Scales the glyph, but keeps it centered around its original bounding
    box.

    Logic copied (and simplified for our simple case) from code of FontForge
    transform dialog, since that logic is not exported to Python interface."""
    bbox = glyph.boundingBox()
    x = (bbox[0] + bbox[2]) / 2
    y = (bbox[1] + bbox[3]) / 2
    move = psMat.translate(-x, -y)
    scale = psMat.scale(amount)

    matrix = list(scale)
    matrix[4] = move[4] * scale[0] + x;
    matrix[5] = move[5] * scale[3] + y;

    glyph.transform(matrix)
Ejemplo n.º 6
0
def scaleGlyph(glyph, amount):
    """Scales the glyph, but keeps it centered around its original bounding
    box.

    Logic copied (and simplified for our simple case) from code of FontForge
    transform dialog, since that logic is not exported to Python interface."""
    bbox = glyph.boundingBox()
    x = (bbox[0] + bbox[2]) / 2
    y = (bbox[1] + bbox[3]) / 2
    move = psMat.translate(-x, -y)
    scale = psMat.scale(amount)

    matrix = list(scale)
    matrix[4] = move[4] * scale[0] + x
    matrix[5] = move[5] * scale[3] + y

    glyph.transform(matrix)
Ejemplo n.º 7
0
def makeQuran(infile, outfile, feafile, version):
    font = makeDesktop(infile, outfile, feafile, version, False, False)

    # fix metadata
    font.fontname = font.fontname.replace("-Regular", "Quran-Regular")
    font.familyname += " Quran"
    font.fullname += " Quran"

    digits = ("zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine")

    mergeLatin(font, feafile, glyphs=digits, quran=True)

    punct = (
        "period",
        "guillemotleft",
        "guillemotright",
        "braceleft",
        "bar",
        "braceright",
        "bracketleft",
        "bracketright",
        "parenleft",
        "parenright",
        "slash",
        "backslash",
    )

    for name in punct:
        if name + ".ara" in font:
            glyph = font[name + ".ara"]
            glyph.glyphname = name
            glyph.unicode = fontforge.unicodeFromName(name)

    # abuse U+065C as a below form of U+06EC, for Qaloon
    dotabove = font["uni06EC"]
    dotbelow = font["uni065C"]
    delta = dotbelow.boundingBox()[-1] - dotabove.boundingBox()[-1]
    dotbelow.references = []
    dotbelow.addReference(dotabove.glyphname, psMat.translate(0, delta))
    dotbelow.addAnchorPoint("TashkilTashkilBelow", "basemark", 220, dotbelow.boundingBox()[1] - 100)

    # scale some vowel marks and dots down a bit
    font["uni0651"].transform(psMat.scale(0.8))
    for mark in ("uni064B", "uni064C", "uni064E", "uni064F", "uni06E1"):
        font[mark].transform(psMat.scale(0.9))

    for dot in ("TwoDots.a", "ThreeDots.a", "vTwoDots.a"):
        font[dot].transform(psMat.scale(0.9))

    quran_glyphs = []

    # create dummy glyphs used for some coding hacks
    for i in range(1, 11):
        dummy = font.createChar(-1, "dummy%s" % i)
        dummy.width = 0
        quran_glyphs.append(dummy.glyphname)

    mergeFeatures(font, feafile)

    quran_glyphs += digits
    quran_glyphs += punct
    quran_glyphs += (
        "space",
        "uni060C",
        "uni0615",
        "uni0617",
        "uni0618",
        "uni0619",
        "uni061A",
        "uni061B",
        "uni061E",
        "uni061F",
        "uni0621",
        "uni0622",
        "uni0623",
        "uni0624",
        "uni0625",
        "uni0626",
        "uni0627",
        "uni0628",
        "uni0629",
        "uni062A",
        "uni062B",
        "uni062C",
        "uni062D",
        "uni062E",
        "uni062F",
        "uni0630",
        "uni0631",
        "uni0632",
        "uni0633",
        "uni0634",
        "uni0635",
        "uni0636",
        "uni0637",
        "uni0638",
        "uni0639",
        "uni063A",
        "uni0640",
        "uni0641",
        "uni0642",
        "uni0643",
        "uni0644",
        "uni0645",
        "uni0646",
        "uni0647",
        "uni0648",
        "uni0649",
        "uni064A",
        "uni064B",
        "uni064C",
        "uni064D",
        "uni064E",
        "uni064F",
        "uni0650",
        "uni0651",
        "uni0652",
        "uni0653",
        "uni0654",
        "uni0655",
        "uni0656",
        "uni0657",
        "uni0658",
        "uni065C",
        "uni0660",
        "uni0661",
        "uni0662",
        "uni0663",
        "uni0664",
        "uni0665",
        "uni0666",
        "uni0667",
        "uni0668",
        "uni0669",
        "uni066E",
        "uni066F",
        "uni06A1",
        "uni06BA",
        "uni0670",
        "uni0671",
        "uni067A",
        "uni06CC",
        "uni06D6",
        "uni06D7",
        "uni06D8",
        "uni06D9",
        "uni06DA",
        "uni06DB",
        "uni06DC",
        "uni06DD",
        "uni06DE",
        "uni06DF",
        "uni06E0",
        "uni06E1",
        "uni06E2",
        "uni06E3",
        "uni06E4",
        "uni06E5",
        "uni06E6",
        "uni06E7",
        "uni06E8",
        "uni06E9",
        "uni06EA",
        "uni06EB",
        "uni06EC",
        "uni06ED",
        "uni06F0",
        "uni06F1",
        "uni06F2",
        "uni06F3",
        "uni06F4",
        "uni06F5",
        "uni06F6",
        "uni06F7",
        "uni06F8",
        "uni06F9",
        "uni08F0",
        "uni08F1",
        "uni08F2",
        "uni2000",
        "uni2001",
        "uni2002",
        "uni2003",
        "uni2004",
        "uni2005",
        "uni2006",
        "uni2007",
        "uni2008",
        "uni2009",
        "uni200A",
        "uni200B",
        "uni200C",
        "uni200D",
        "uni200E",
        "uni200F",
        "uni2028",
        "uni2029",
        "uni202A",
        "uni202B",
        "uni202C",
        "uni202D",
        "uni202E",
        "uni202F",
        "uni25CC",
        "uniFDFA",
        "uniFDFD",
    )
    quran_glyphs += ("uni030A", "uni0325")  # ring above and below

    subsetFont(font, quran_glyphs, True)

    # set font ascent to the highest glyph in the font so that waqf marks don't
    # get truncated
    # we could have set os2_typoascent_add and hhea_ascent_add, but ff makes
    # the offset relative to em-size in the former and font bounds in the
    # later, but we want both to be relative to font bounds
    ymax = 0
    for glyph in font.glyphs():
        bb = glyph.boundingBox()
        if bb[-1] > ymax:
            ymax = bb[-1]

    font.os2_typoascent = font.hhea_ascent = ymax

    # create overline glyph to be used for sajda line, it is positioned
    # vertically at the level of the base of waqf marks
    overline_pos = font[0x06D7].boundingBox()[1]
    makeOverUnderline(font, under=False, o_pos=overline_pos)

    generateFont(font, outfile)
Ejemplo n.º 8
0
def mergeLatin(font, feafile, italic=False, glyphs=None, quran=False):
    styles = {"Regular": "Roman", "Slanted": "Italic", "Bold": "Bold", "BoldSlanted": "BoldItalic"}

    style = styles[font.fontname.split("-")[1]]

    latinfile = "Crimson-%s.sfd" % style

    tmpfont = mkstemp(suffix=os.path.basename(latinfile))[1]
    latinfont = fontforge.open("sources/crimson/%s" % latinfile)

    validateGlyphs(latinfont)  # to flatten nested refs mainly

    if glyphs:
        latinglyphs = list(glyphs)
    else:
        # collect latin glyphs we want to keep
        latinglyphs = []

        # we want all glyphs in latin0-9 encodings
        for i in range(0, 9):
            latinfont.encoding = "latin%d" % i
            for glyph in latinfont.glyphs("encoding"):
                if glyph.encoding <= 255:
                    if glyph.glyphname not in latinglyphs:
                        latinglyphs.append(glyph.glyphname)
                elif glyph.unicode != -1 and glyph.unicode <= 0x017F:
                    # keep also Unicode Latin Extended-A block
                    if glyph.glyphname not in latinglyphs:
                        latinglyphs.append(glyph.glyphname)
                elif glyph.unicode == -1 and ".prop" in glyph.glyphname:
                    # proportional digits
                    latinglyphs.append(glyph.glyphname)

        # keep ligatures too
        ligatures = (
            "f_b",
            "f_f_b",
            "f_h",
            "f_f_h",
            "f_i",
            "f_f_i",
            "f_j",
            "f_f_j",
            "f_k",
            "f_f_k",
            "f_l",
            "f_f_l",
            "f_f",
        )

        # and Arabic romanisation characters
        romanisation = (
            "uni02BC",
            "uni02BE",
            "uni02BE",
            "amacron",
            "uni02BE",
            "amacron",
            "eacute",
            "uni1E6F",
            "ccedilla",
            "uni1E6F",
            "gcaron",
            "ycircumflex",
            "uni1E29",
            "uni1E25",
            "uni1E2B",
            "uni1E96",
            "uni1E0F",
            "dcroat",
            "scaron",
            "scedilla",
            "uni1E63",
            "uni1E11",
            "uni1E0D",
            "uni1E6D",
            "uni1E93",
            "dcroat",
            "uni02BB",
            "uni02BF",
            "rcaron",
            "grave",
            "gdotaccent",
            "gbreve",
            "umacron",
            "imacron",
            "amacron",
            "amacron",
            "uni02BE",
            "amacron",
            "uni02BE",
            "acircumflex",
            "amacron",
            "uni1E97",
            "tbar",
            "aacute",
            "amacron",
            "ygrave",
            "agrave",
            "uni02BE",
            "aacute",
            "Amacron",
            "Amacron",
            "Eacute",
            "uni1E6E",
            "Ccedilla",
            "uni1E6E",
            "Gcaron",
            "Ycircumflex",
            "uni1E28",
            "uni1E24",
            "uni1E2A",
            "uni1E0E",
            "Dcroat",
            "Scaron",
            "Scedilla",
            "uni1E62",
            "uni1E10",
            "uni1E0C",
            "uni1E6C",
            "uni1E92",
            "Dcroat",
            "Rcaron",
            "Gdotaccent",
            "Gbreve",
            "Umacron",
            "Imacron",
            "Amacron",
            "Amacron",
            "Amacron",
            "Acircumflex",
            "Amacron",
            "Tbar",
            "Aacute",
            "Amacron",
            "Ygrave",
            "Agrave",
            "Aacute",
        )

        # and some typographic characters
        typographic = (
            "uni2010",
            "uni2011",
            "figuredash",
            "endash",
            "emdash",
            "uni2015",
            "quoteleft",
            "quoteright",
            "quotesinglbase",
            "quotereversed",
            "quotedblleft",
            "quotedblright",
            "quotedblbase",
            "uni201F",
            "dagger",
            "daggerdbl",
            "bullet",
            "onedotenleader",
            "ellipsis",
            "uni202F",
            "perthousand",
            "minute",
            "second",
            "uni2038",
            "guilsinglleft",
            "guilsinglright",
            "uni203E",
            "fraction",
            "i.TRK",
            "minus",
            "uni2213",
            "radical",
            "uni2042",
        )

        for l in (ligatures, romanisation, typographic):
            for name in l:
                if name not in latinglyphs:
                    latinglyphs.append(name)

    if not quran:
        # we want our ring above and below in Quran font only
        for name in ("uni030A", "uni0325"):
            font[name].clear()

        latinglyphs += buildComposition(latinfont, latinglyphs)
    subsetFont(latinfont, latinglyphs)

    digits = ("zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine")

    # common characters that can be used in Arabic and Latin need to be handled
    # carefully in the slanted font so that right leaning italic is used with
    # Latin, and left leaning slanted is used with Arabic, using ltra and rtla
    # features respectively, for less OpenType savvy apps we make the default
    # upright so it works reasonably with bot scripts
    if italic:
        if "Bold" in style:
            upright = fontforge.open("sources/crimson/Crimson-Bold.sfd")
        else:
            upright = fontforge.open("sources/crimson/Crimson-Roman.sfd")

        shared = (
            "exclam",
            "quotedbl",
            "numbersign",
            "dollar",
            "percent",
            "quotesingle",
            "asterisk",
            "plus",
            "colon",
            "semicolon",
            "less",
            "equal",
            "greater",
            "question",
            "at",
            "asciicircum",
            "exclamdown",
            "section",
            "copyright",
            "logicalnot",
            "registered",
            "plusminus",
            "uni00B2",
            "uni00B3",
            "paragraph",
            "uni00B9",
            "ordmasculine",
            "onequarter",
            "onehalf",
            "threequarters",
            "questiondown",
            "quoteleft",
            "quoteright",
            "quotesinglbase",
            "quotereversed",
            "quotedblleft",
            "quotedblright",
            "quotedblbase",
            "uni201F",
            "dagger",
            "daggerdbl",
            "perthousand",
            "minute",
            "second",
            "guilsinglleft",
            "guilsinglright",
            "fraction",
            "uni2213",
        )

        for name in shared:
            glyph = latinfont[name]
            glyph.clear()
            upright.selection.select(name)
            upright.copy()
            latinfont.createChar(upright[name].encoding, name)
            latinfont.selection.select(name)
            latinfont.paste()

        for name in digits:
            glyph = latinfont[name]
            glyph.glyphname += ".ltr"
            glyph.unicode = -1
            upright.selection.select(name)
            upright.copy()
            latinfont.createChar(upright[name].encoding, name)
            latinfont.selection.select(name)
            latinfont.paste()

            rtl = latinfont.createChar(-1, name + ".rtl")
            rtl.addReference(name, italic)
            rtl.useRefsMetrics(name)

        for name in digits:
            pname = name + ".prop"
            upright.selection.select(pname)
            upright.copy()
            latinfont.createChar(-1, pname)
            latinfont.selection.select(pname)
            latinfont.paste()

        for name in digits:
            pname = name + ".prop"
            rtl = latinfont.createChar(-1, name + ".rtl" + ".prop")
            rtl.addReference(pname, italic)
            rtl.useRefsMetrics(pname)

    # copy kerning classes
    kern_lookups = {}
    if not quran:
        for lookup in latinfont.gpos_lookups:
            kern_lookups[lookup] = {}
            kern_lookups[lookup]["subtables"] = []
            kern_lookups[lookup]["type"], kern_lookups[lookup]["flags"] = latinfont.getLookupInfo(lookup)[:2]
            for subtable in latinfont.getLookupSubtables(lookup):
                if latinfont.isKerningClass(subtable):
                    kern_lookups[lookup]["subtables"].append((subtable, latinfont.getKerningClass(subtable)))

    for lookup in latinfont.gpos_lookups:
        latinfont.removeLookup(lookup)

    for lookup in latinfont.gsub_lookups:
        latinfont.removeLookup(lookup)

    latinfont.save(tmpfont)
    latinfont.close()

    font.mergeFonts(tmpfont)
    os.remove(tmpfont)

    if not quran:
        buildComposition(font, latinglyphs)

    # add Latin small and medium digits
    for name in digits:
        if italic:
            # they are only used in Arabic contexts, so always reference the
            # italic rtl variant
            refname = name + ".rtl"
        else:
            refname = name
        small = font.createChar(-1, name + ".small")
        small.clear()
        small.addReference(refname, psMat.scale(0.6))
        small.transform(psMat.translate(0, -40))
        small.width = 600
        centerGlyph(small)

        medium = font.createChar(-1, name + ".medium")
        medium.clear()
        medium.addReference(refname, psMat.scale(0.8))
        medium.transform(psMat.translate(0, 50))
        medium.width = 900
        centerGlyph(medium)

    for lookup in kern_lookups:
        font.addLookup(lookup, kern_lookups[lookup]["type"], kern_lookups[lookup]["flags"], (("kern", script_lang),))

        for subtable in kern_lookups[lookup]["subtables"]:
            first = []
            second = []
            offsets = subtable[1][2]

            # drop non-existing glyphs
            for new_klasses, klasses in ((first, subtable[1][0]), (second, subtable[1][1])):
                for klass in klasses:
                    new_klass = []
                    if klass:
                        for name in klass:
                            if name in font:
                                new_klass.append(name)
                    new_klasses.append(new_klass)

            # if either of the classes is empty, don’t bother with the subtable
            if any(first) and any(second):
                font.addKerningClass(lookup, subtable[0], first, second, offsets)
Ejemplo n.º 9
0
def makeQuran(infile, outfile, feafile, version):
    font = makeDesktop(infile, outfile, feafile, version, False, False)

    # fix metadata
    font.fontname = font.fontname.replace("-Regular", "Quran-Regular")
    font.familyname += " Quran"
    font.fullname += " Quran"

    digits = ("zero", "one", "two", "three", "four", "five", "six", "seven",
              "eight", "nine")

    mergeLatin(font, feafile, glyphs=digits, quran=True)

    punct = ("period", "guillemotleft", "guillemotright", "braceleft", "bar",
             "braceright", "bracketleft", "bracketright", "parenleft",
             "parenright", "slash", "backslash")

    for name in punct:
        if name + ".ara" in font:
            glyph = font[name + ".ara"]
            glyph.glyphname = name
            glyph.unicode = fontforge.unicodeFromName(name)

    # abuse U+065C as a below form of U+06EC, for Qaloon
    dotabove = font["uni06EC"]
    dotbelow = font["uni065C"]
    delta = dotbelow.boundingBox()[-1] - dotabove.boundingBox()[-1]
    dotbelow.references = []
    dotbelow.addReference(dotabove.glyphname, psMat.translate(0, delta))
    dotbelow.addAnchorPoint("TashkilTashkilBelow", "basemark", 220,
                            dotbelow.boundingBox()[1] - 100)

    # scale some vowel marks and dots down a bit
    scaleGlyph(font["uni0651"], 0.8)
    for mark in ("uni064B", "uni064C", "uni064E", "uni064F", "uni06E1"):
        scaleGlyph(font[mark], 0.9)

    for dot in ("TwoDots.a", "ThreeDots.a", "vTwoDots.a"):
        scaleGlyph(font[dot], 0.9)

    quran_glyphs = []
    for glyph in font.glyphs():
        if glyph.name.startswith("dummy"):
            quran_glyphs.append(glyph.name)

    mergeFeatures(font, feafile)

    quran_glyphs += digits
    quran_glyphs += punct
    quran_glyphs += (
        "space", "uni060C", "uni0615", "uni0617", "uni0618", "uni0619",
        "uni061A", "uni061B", "uni061E", "uni061F", "uni0621", "uni0622",
        "uni0623", "uni0624", "uni0625", "uni0626", "uni0627", "uni0628",
        "uni0629", "uni062A", "uni062B", "uni062C", "uni062D", "uni062E",
        "uni062F", "uni0630", "uni0631", "uni0632", "uni0633", "uni0634",
        "uni0635", "uni0636", "uni0637", "uni0638", "uni0639", "uni063A",
        "uni0640", "uni0641", "uni0642", "uni0643", "uni0644", "uni0645",
        "uni0646", "uni0647", "uni0648", "uni0649", "uni064A", "uni064B",
        "uni064C", "uni064D", "uni064E", "uni064F", "uni0650", "uni0651",
        "uni0652", "uni0653", "uni0654", "uni0655", "uni0656", "uni0657",
        "uni0658", "uni065C", "uni0660", "uni0661", "uni0662", "uni0663",
        "uni0664", "uni0665", "uni0666", "uni0667", "uni0668", "uni0669",
        "uni066E", "uni066F", "uni06A1", "uni06BA", "uni0670", "uni0671",
        "uni067A", "uni06CC", "uni06D6", "uni06D7", "uni06D8", "uni06D9",
        "uni06DA", "uni06DB", "uni06DC", "uni06DD", "uni06DE", "uni06DF",
        "uni06E0", "uni06E1", "uni06E2", "uni06E3", "uni06E4", "uni06E5",
        "uni06E6", "uni06E7", "uni06E8", "uni06E9", "uni06EA", "uni06EB",
        "uni06EC", "uni06ED", "uni06F0", "uni06F1", "uni06F2", "uni06F3",
        "uni06F4", "uni06F5", "uni06F6", "uni06F7", "uni06F8", "uni06F9",
        "uni08F0", "uni08F1", "uni08F2", "uni2000", "uni2001", "uni2002",
        "uni2003", "uni2004", "uni2005", "uni2006", "uni2007", "uni2008",
        "uni2009", "uni200A", "uni200B", "uni200C", "uni200D", "uni200E",
        "uni200F", "uni2028", "uni2029", "uni202A", "uni202B", "uni202C",
        "uni202D", "uni202E", "uni202F", "uni25CC", "uniFD3E", "uniFD3F",
        "uniFDFA", "uniFDFD")
    quran_glyphs += ("uni030A", "uni0325")  # ring above and below

    subsetFont(font, quran_glyphs, True)

    # set font ascent to the highest glyph in the font so that waqf marks don't
    # get truncated
    # we could have set os2_typoascent_add and hhea_ascent_add, but ff makes
    # the offset relative to em-size in the former and font bounds in the
    # later, but we want both to be relative to font bounds
    ymax = 0
    for glyph in font.glyphs():
        bb = glyph.boundingBox()
        if bb[-1] > ymax:
            ymax = bb[-1]

    font.os2_typoascent = font.hhea_ascent = ymax

    # create overline glyph to be used for sajda line, it is positioned
    # vertically at the level of the base of waqf marks
    overline_pos = font[0x06D7].boundingBox()[1]
    makeOverUnderline(font, under=False, o_pos=overline_pos)

    generateFont(font, outfile)
Ejemplo n.º 10
0
def mergeLatin(font, feafile, italic=False, glyphs=None, quran=False):
    styles = {
        "Regular": "regular",
        "Slanted": "italic",
        "Bold": "bold",
        "BoldSlanted": "bolditalic"
    }

    style = styles[font.fontname.split("-")[1]]

    latinfile = "amirilatin-%s.sfdir" % style

    from tempfile import mkstemp
    tmpfont = mkstemp(
        suffix=os.path.basename(latinfile).replace("sfdir", "sfd"))[1]
    latinfont = fontforge.open("sources/latin/%s" % latinfile)

    validateGlyphs(latinfont)  # to flatten nested refs mainly

    if glyphs:
        latinglyphs = list(glyphs)
    else:
        # collect latin glyphs we want to keep
        latinglyphs = []

        # we want all glyphs in latin0-9 encodings
        for i in range(0, 9):
            latinfont.encoding = 'latin%d' % i
            for glyph in latinfont.glyphs("encoding"):
                if glyph.encoding <= 255:
                    if glyph.glyphname not in latinglyphs:
                        latinglyphs.append(glyph.glyphname)
                elif glyph.unicode != -1 and glyph.unicode <= 0x017F:
                    # keep also Unicode Latin Extended-A block
                    if glyph.glyphname not in latinglyphs:
                        latinglyphs.append(glyph.glyphname)
                elif glyph.unicode == -1 and '.prop' in glyph.glyphname:
                    # proportional digits
                    latinglyphs.append(glyph.glyphname)

        # keep ligatures too
        ligatures = ("f_b", "f_f_b", "f_h", "f_f_h", "f_i", "f_f_i", "f_j",
                     "f_f_j", "f_k", "f_f_k", "f_l", "f_f_l", "f_f")

        # and Arabic romanisation characters
        romanisation = ("uni02BC", "uni02BE", "uni02BE", "amacron", "uni02BE",
                        "amacron", "eacute", "uni1E6F", "ccedilla", "uni1E6F",
                        "gcaron", "ycircumflex", "uni1E29", "uni1E25",
                        "uni1E2B", "uni1E96", "uni1E0F", "dcroat", "scaron",
                        "scedilla", "uni1E63", "uni1E11", "uni1E0D", "uni1E6D",
                        "uni1E93", "dcroat", "uni02BB", "uni02BF", "rcaron",
                        "grave", "gdotaccent", "gbreve", "umacron", "imacron",
                        "amacron", "amacron", "uni02BE", "amacron", "uni02BE",
                        "acircumflex", "amacron", "uni1E97", "tbar", "aacute",
                        "amacron", "ygrave", "agrave", "uni02BE", "aacute",
                        "Amacron", "Amacron", "Eacute", "uni1E6E", "Ccedilla",
                        "uni1E6E", "Gcaron", "Ycircumflex", "uni1E28",
                        "uni1E24", "uni1E2A", "uni1E0E", "Dcroat", "Scaron",
                        "Scedilla", "uni1E62", "uni1E10", "uni1E0C", "uni1E6C",
                        "uni1E92", "Dcroat", "Rcaron", "Gdotaccent", "Gbreve",
                        "Umacron", "Imacron", "Amacron", "Amacron", "Amacron",
                        "Acircumflex", "Amacron", "Tbar", "Aacute", "Amacron",
                        "Ygrave", "Agrave", "Aacute")

        # and some typographic characters
        typographic = ("uni2010", "uni2011", "figuredash", "endash", "emdash",
                       "uni2015", "quoteleft", "quoteright", "quotesinglbase",
                       "quotereversed", "quotedblleft", "quotedblright",
                       "quotedblbase", "uni201F", "dagger", "daggerdbl",
                       "bullet", "onedotenleader", "ellipsis", "uni202F",
                       "perthousand", "minute", "second", "uni2038",
                       "guilsinglleft", "guilsinglright", "uni203E",
                       "fraction", "i.TRK", "minus", "uni2213", "radical",
                       "uni2042")

        for l in (ligatures, romanisation, typographic):
            for name in l:
                if name not in latinglyphs:
                    latinglyphs.append(name)

    if not quran:
        # we want our ring above and below in Quran font only
        for name in ("uni030A", "uni0325"):
            font[name].clear()

        latinglyphs += buildComposition(latinfont, latinglyphs)
    subsetFont(latinfont, latinglyphs)

    digits = ("zero", "one", "two", "three", "four", "five", "six", "seven",
              "eight", "nine")

    # common characters that can be used in Arabic and Latin need to be handled
    # carefully in the slanted font so that right leaning italic is used with
    # Latin, and left leaning slanted is used with Arabic, using ltra and rtla
    # features respectively, for less OpenType savvy apps we make the default
    # upright so it works reasonably with bot scripts
    if italic:
        if "bold" in style:
            upright = fontforge.open("sources/latin/amirilatin-bold.sfdir")
        else:
            upright = fontforge.open("sources/latin/amirilatin-regular.sfdir")

        shared = ("exclam", "quotedbl", "numbersign", "dollar", "percent",
                  "quotesingle", "asterisk", "plus", "colon", "semicolon",
                  "less", "equal", "greater", "question", "at", "asciicircum",
                  "exclamdown", "section", "copyright", "logicalnot",
                  "registered", "plusminus", "uni00B2", "uni00B3", "paragraph",
                  "uni00B9", "ordmasculine", "onequarter", "onehalf",
                  "threequarters", "questiondown", "quoteleft", "quoteright",
                  "quotesinglbase", "quotereversed", "quotedblleft",
                  "quotedblright", "quotedblbase", "uni201F", "dagger",
                  "daggerdbl", "perthousand", "minute", "second",
                  "guilsinglleft", "guilsinglright", "fraction", "uni2213")

        for name in shared:
            glyph = latinfont[name]
            glyph.clear()
            upright.selection.select(name)
            upright.copy()
            latinfont.createChar(upright[name].encoding, name)
            latinfont.selection.select(name)
            latinfont.paste()

        for name in digits:
            glyph = latinfont[name]
            glyph.glyphname += '.ltr'
            glyph.unicode = -1
            upright.selection.select(name)
            upright.copy()
            latinfont.createChar(upright[name].encoding, name)
            latinfont.selection.select(name)
            latinfont.paste()

            rtl = latinfont.createChar(-1, name + ".rtl")
            rtl.addReference(name, italic)
            rtl.useRefsMetrics(name)

        for name in digits:
            pname = name + ".prop"
            glyph = latinfont[pname]
            glyph.glyphname = name + '.ltr.prop'
            glyph.unicode = -1
            upright.selection.select(pname)
            upright.copy()
            latinfont.createChar(-1, pname)
            latinfont.selection.select(pname)
            latinfont.paste()

            rtl = latinfont.createChar(-1, name + ".rtl" + ".prop")
            rtl.addReference(pname, italic)
            rtl.useRefsMetrics(pname)

    # copy kerning classes
    kern_lookups = {}
    if not quran:
        for lookup in latinfont.gpos_lookups:
            kern_lookups[lookup] = {}
            kern_lookups[lookup]["subtables"] = []
            kern_lookups[lookup]["type"], kern_lookups[lookup][
                "flags"] = latinfont.getLookupInfo(lookup)[:2]
            for subtable in latinfont.getLookupSubtables(lookup):
                if latinfont.isKerningClass(subtable):
                    kern_lookups[lookup]["subtables"].append(
                        (subtable, latinfont.getKerningClass(subtable)))

    for lookup in latinfont.gpos_lookups:
        latinfont.removeLookup(lookup)

    for lookup in latinfont.gsub_lookups:
        latinfont.removeLookup(lookup)

    latinfont.save(tmpfont)
    latinfont.close()

    font.mergeFonts(tmpfont)
    os.remove(tmpfont)

    if not quran:
        buildComposition(font, latinglyphs)

    # add Latin small and medium digits
    for name in digits:
        if italic:
            # they are only used in Arabic contexts, so always reference the
            # italic rtl variant
            refname = name + ".rtl"
        else:
            refname = name
        small = font.createChar(-1, name + ".small")
        if not small.isWorthOutputting():
            small.clear()
            small.addReference(refname, psMat.scale(0.6))
            small.transform(psMat.translate(0, -40))
            small.width = 600
            centerGlyph(small)

        medium = font.createChar(-1, name + ".medium")
        if not medium.isWorthOutputting():
            medium.clear()
            medium.addReference(refname, psMat.scale(0.8))
            medium.transform(psMat.translate(0, 50))
            medium.width = 900
            centerGlyph(medium)

    for lookup in kern_lookups:
        font.addLookup(lookup, kern_lookups[lookup]["type"],
                       kern_lookups[lookup]["flags"],
                       (('kern', script_lang), ))

        for subtable in kern_lookups[lookup]["subtables"]:
            first = []
            second = []
            offsets = subtable[1][2]

            # drop non-existing glyphs
            for new_klasses, klasses in ((first, subtable[1][0]),
                                         (second, subtable[1][1])):
                for klass in klasses:
                    new_klass = []
                    if klass:
                        for name in klass:
                            if name in font:
                                new_klass.append(name)
                    new_klasses.append(new_klass)

            # if either of the classes is empty, don’t bother with the subtable
            if any(first) and any(second):
                font.addKerningClass(lookup, subtable[0], first, second,
                                     offsets)
Ejemplo n.º 11
0
def mergeLatin(font, latinfile, glyphs=None):
    tmpfont = mkstemp(
        suffix=os.path.basename(latinfile).replace("ufo", "sfd"))[1]
    latinfont = fontforge.open(latinfile)

    validateGlyphs(latinfont)  # to flatten nested refs mainly
    latinglyphs = [name for name in latinfont]

    # The Latin font is already subsetted to only contain glyphs that take
    # precedence over glyphs in the Arabic if there are overlapping glyphs.
    # To give the glyphs of the latin precedence, we need to remove the
    # existing glyphs from the Arabic.
    overlapping = {name for name in font} & {name for name in latinfont}
    for name in overlapping:
        # Maybe font.removeGlyph(name) is the better strategy than font[name].clear()
        # As it seems that the newly merged glyphs don't set all properties
        # of the glyph new on font.mergeFonts(latin)
        # If there are no references, removeGlyph should be better (there
        # were none when writing this)
        font.removeGlyph(name)

    compositions = buildComposition(latinfont, latinglyphs)
    latinglyphs += compositions
    subsetFont(latinfont, latinglyphs)

    digits = ("zero", "one", "two", "three", "four", "five", "six", "seven",
              "eight", "nine")

    # copy kerning classes
    kern_lookups = {}
    for lookup in latinfont.gpos_lookups:
        kern_lookups[lookup] = {}
        kern_lookups[lookup]["subtables"] = []
        kern_lookups[lookup]["type"], kern_lookups[lookup][
            "flags"] = latinfont.getLookupInfo(lookup)[:2]
        for subtable in latinfont.getLookupSubtables(lookup):
            if latinfont.isKerningClass(subtable):
                kern_lookups[lookup]["subtables"].append(
                    (subtable, latinfont.getKerningClass(subtable)))

    for lookup in latinfont.gpos_lookups:
        latinfont.removeLookup(lookup)

    for lookup in latinfont.gsub_lookups:
        latinfont.removeLookup(lookup)

    latinfont.save(tmpfont)
    latinfont.close()

    font.mergeFonts(tmpfont)
    os.remove(tmpfont)

    copyAnchors(font, latinfile)

    buildComposition(font, latinglyphs)

    # add Latin small and medium digits
    for name in digits:
        refname = name
        small = font.createChar(-1, name + ".small")
        #if not small.isWorthOutputting():
        small.clear()
        small.addReference(refname, psMat.scale(0.6))
        small.transform(psMat.translate(0, 180))
        small.width = 650
        centerGlyph(small)

        medium = font.createChar(-1, name + ".medium")
        #if not medium.isWorthOutputting():
        medium.clear()
        medium.addReference(refname, psMat.scale(0.8))
        medium.transform(psMat.translate(0, 200))
        medium.width = 900
        centerGlyph(medium)

    for lookup in kern_lookups:
        font.addLookup(lookup, kern_lookups[lookup]["type"],
                       kern_lookups[lookup]["flags"],
                       (('kern', script_lang), ))

        for subtable in kern_lookups[lookup]["subtables"]:
            first = []
            second = []
            offsets = subtable[1][2]

            # drop non-existing glyphs
            for new_klasses, klasses in ((first, subtable[1][0]),
                                         (second, subtable[1][1])):
                for klass in klasses:
                    new_klass = []
                    if klass:
                        for name in klass:
                            if name in font:
                                new_klass.append(name)
                    new_klasses.append(new_klass)

            # if either of the classes is empty, don’t bother with the subtable
            if any(first) and any(second):
                font.addKerningClass(lookup, subtable[0], first, second,
                                     offsets)