summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/doc/fonts/amiri/tools
diff options
context:
space:
mode:
Diffstat (limited to 'Master/texmf-dist/doc/fonts/amiri/tools')
-rwxr-xr-xMaster/texmf-dist/doc/fonts/amiri/tools/build.py279
-rwxr-xr-xMaster/texmf-dist/doc/fonts/amiri/tools/runtest.py6
2 files changed, 255 insertions, 30 deletions
diff --git a/Master/texmf-dist/doc/fonts/amiri/tools/build.py b/Master/texmf-dist/doc/fonts/amiri/tools/build.py
index 7bef39cb1a5..77ca98604e9 100755
--- a/Master/texmf-dist/doc/fonts/amiri/tools/build.py
+++ b/Master/texmf-dist/doc/fonts/amiri/tools/build.py
@@ -3,7 +3,7 @@
#
# build.py - Amiri font build utility
#
-# Written in 2010-2011 by Khaled Hosny <khaledhosny@eglug.org>
+# Written in 2010-2012 by Khaled Hosny <khaledhosny@eglug.org>
#
# To the extent possible under law, the author have dedicated all copyright
# and related and neighboring rights to this software to the public domain
@@ -18,6 +18,7 @@ import psMat
import sys
import os
import getopt
+import math
from tempfile import mkstemp
from fontTools.ttLib import TTFont
@@ -78,7 +79,7 @@ def cleanAnchors(font):
lookup = font.getLookupOfSubtable(subtable)
font.removeLookup(lookup)
-def flattenNestedReferences(font, ref, new_transform=None):
+def flattenNestedReferences(font, ref, new_transform=(1, 0, 0, 1, 0, 0)):
"""Flattens nested references by replacing them with the ultimate reference
and applying any transformation matrices involved, so that the final font
has only simple composite glyphs. This to work around what seems to be an
@@ -92,13 +93,11 @@ def flattenNestedReferences(font, ref, new_transform=None):
if glyph.references and glyph.foreground.isEmpty():
for nested_ref in glyph.references:
for i in flattenNestedReferences(font, nested_ref, transform):
- new_ref.append(i)
+ matrix = psMat.compose(i[1], new_transform)
+ new_ref.append((i[0], matrix))
else:
- if new_transform:
- matrix = psMat.compose(transform, new_transform)
- new_ref.append((name, matrix))
- else:
- new_ref.append(ref)
+ matrix = psMat.compose(transform, new_transform)
+ new_ref.append((name, matrix))
return new_ref
@@ -106,12 +105,10 @@ def validateGlyphs(font):
"""Fixes some common FontForge validation warnings, currently handles:
* wrong direction
* flipped references
- * missing points at extrema
In addition to flattening nested references."""
wrong_dir = 0x8
flipped_ref = 0x10
- missing_extrema = 0x20
for glyph in font.glyphs():
state = glyph.validate(True)
refs = []
@@ -121,8 +118,6 @@ def validateGlyphs(font):
glyph.correctDirection()
if state & wrong_dir:
glyph.correctDirection()
- if state & missing_extrema:
- glyph.addExtrema("all")
for ref in glyph.references:
for i in flattenNestedReferences(font, ref):
@@ -169,7 +164,14 @@ def makeCss(infiles, outfile):
out.close()
def generateFont(font, outfile, hack=False):
- flags = ("opentype", "dummy-dsig", "round")
+ flags = ("opentype", "dummy-dsig", "round", "omit-instructions")
+
+ font.selection.all()
+ font.correctReferences()
+ font.selection.none()
+
+ # fix some common font issues
+ validateGlyphs(font)
if hack:
# ff takes long to write the file, so generate to tmp file then rename
@@ -259,13 +261,226 @@ def makeOverUnderline(font):
font.addContextualSubtable(context_lookup_name, context_lookup_name + str(width), 'coverage', rule)
+def centerGlyph(glyph):
+ width = glyph.width
+ glyph.right_side_bearing = glyph.left_side_bearing = (glyph.right_side_bearing + glyph.left_side_bearing)/2
+ glyph.width = width
+
+def buildLatinExtras(font, italic):
+ for ltr, rtl in (("question", "uni061F"), ("radical", "radical.rtlm")):
+ font[rtl].clear()
+ font[rtl].addReference(ltr, psMat.scale(-1, 1))
+ font[rtl].left_side_bearing = font[ltr].right_side_bearing
+ font[rtl].right_side_bearing = font[ltr].left_side_bearing
+
+ # slanted arabic question mark
+ if italic:
+ question = font.createChar(-1, "uni061F.rtl")
+ question.addReference("uni061F", italic)
+ question.useRefsMetrics("uni061F")
+
+ for name in ("zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine"):
+ 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)
+
+def mergeLatin(font, italic=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/sources/%s" %latinfile)
+ latinfont.em = 2048
+
+ validateGlyphs(latinfont) # to flatten nested refs mainly
+
+ # 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)
+
+ # keep ligatures too
+ ligatures = ("f_f", "f_i", "f_f_i", "f_l", "f_f_l", "f_b", "f_f_b", "f_k",
+ "f_f_k", "f_h", "f_f_h", "f_j", "f_f_j", "T_h")
+
+ # and Arabic romanisation characters
+ romanisation = ("afii57929", "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",
+ "afii00208", "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)
+
+ # keep any glyph referenced by previous glyphs
+ for name in latinglyphs:
+ if name in latinfont:
+ glyph = latinfont[name]
+ for ref in glyph.references:
+ latinglyphs.append(ref[0])
+ else:
+ print 'Font ‘%s’ is missing glyph: %s' %(font.fontname, name)
+
+ # remove everything else
+ for glyph in latinfont.glyphs():
+ if glyph.glyphname not in latinglyphs:
+ latinfont.removeGlyph(glyph)
+
+ # 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/sources/Crimson-Bold.sfd")
+ else:
+ upright = fontforge.open("sources/crimson/sources/Crimson-Roman.sfd")
+ upright.em = 2048
+
+ shared = ("exclam", "quotedbl", "numbersign", "dollar", "percent",
+ "quotesingle", "parenleft", "parenright", "asterisk", "plus",
+ "slash", "zero", "one", "two", "three", "four", "five",
+ "six", "seven", "eight", "nine", "colon", "semicolon",
+ "less", "equal", "greater", "question", "at", "bracketleft",
+ "backslash", "bracketright", "asciicircum", "braceleft",
+ "bar", "braceright", "brokenbar", "section", "copyright",
+ "guillemotleft", "logicalnot", "registered", "plusminus",
+ "uni00B2", "uni00B3", "paragraph", "uni00B9", "ordmasculine",
+ "guillemotright", "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.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)
+
+ # 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"], dummy = latinfont.getLookupInfo(lookup)
+ 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)
+
+ buildLatinExtras(font, italic)
+
+ # we want to merge features after merging the latin font because many
+ # referenced glyphs are in the latin font
+ if font.sfd_path:
+ feafile = os.path.splitext(font.sfd_path)[0] + '.fea'
+ mergeFeatures(font, feafile)
+
+ font.mergeFeature("sources/latin_gsub.fea")
+
+ if italic:
+ font.mergeFeature("sources/italic_ltra.fea")
+ font.mergeFeature("sources/italic_rtla.fea")
+
+ for lookup in kern_lookups:
+ font.addLookup(lookup,
+ kern_lookups[lookup]["type"],
+ kern_lookups[lookup]["flags"],
+ (('kern',
+ (
+ ('DFLT', ('dflt',)),
+ ('latn', ('dflt', 'TRK ')),
+ )
+ ),)
+ )
+
+ for subtable in kern_lookups[lookup]["subtables"]:
+ font.addKerningClass(lookup, subtable[0], subtable[1][0], subtable[1][1], subtable[1][2])
+
def makeWeb(infile, outfile):
"""If we are building a web version then try to minimise file size"""
# "short-post" generates a post table without glyph names to save some KBs
# since glyph names are only needed for PDF's as readers use them to
# "guess" characters when copying text, which is of little use in web fonts.
- flags = ("opentype", "short-post")
+ flags = ("opentype", "short-post", "omit-instructions")
font = fontforge.open(infile)
@@ -333,10 +548,9 @@ def makeWeb(infile, outfile):
os.remove(tmpfont)
-def makeSlanted(infile, outfile, slant):
- import math
+def makeSlanted(infile, outfile, version, slant):
- font = fontforge.open(infile)
+ font = makeDesktop(infile, outfile, version, False, False)
# compute amout of skew, magic formula copied from fontforge sources
skew = psMat.skew(-slant * math.pi/180.0)
@@ -355,9 +569,11 @@ def makeSlanted(infile, outfile, slant):
font.fontname = font.fontname.replace("Regular", "Slanted")
font.appendSFNTName("Arabic (Egypt)", "SubFamily", "مائل")
+ mergeLatin(font, skew)
+
generateFont(font, outfile)
-def makeDesktop(infile, outfile, version):
+def makeDesktop(infile, outfile, version, latin=True, generate=True):
font = fontforge.open(infile)
if version:
@@ -366,16 +582,21 @@ def makeDesktop(infile, outfile, version):
# remove anchors that are not needed in the production font
cleanAnchors(font)
- # fix some common font issues
- validateGlyphs(font)
+ #makeOverUnderline(font)
- if font.sfd_path:
- feafile = os.path.splitext(font.sfd_path)[0] + '.fea'
- mergeFeatures(font, feafile)
+ # sample text to be used by font viewers
+ sample = 'صِفْ خَلْقَ خَوْدٍ كَمِثْلِ ٱلشَّمْسِ إِذْ بَزَغَتْ يَحْظَىٰ ٱلضَّجِيعُ بِهَا نَجْلَاءَ مِعْطَارِ.'
- #makeOverUnderline(font)
+ for lang in ('Arabic (Egypt)', 'English (US)'):
+ font.appendSFNTName(lang, 'Sample Text', sample)
- generateFont(font, outfile, True)
+ if latin:
+ mergeLatin(font)
+
+ if generate:
+ generateFont(font, outfile, True)
+ else:
+ return font
def usage(extramessage, code):
if extramessage:
@@ -431,9 +652,11 @@ if __name__ == "__main__":
makeCss(infile, outfile)
elif web:
makeWeb(infile, outfile)
- elif slant:
- makeSlanted(infile, outfile, slant)
else:
if not version:
usage("No version specified", -1)
- makeDesktop(infile, outfile, version)
+
+ if slant:
+ makeSlanted(infile, outfile, version, slant)
+ else:
+ makeDesktop(infile, outfile, version)
diff --git a/Master/texmf-dist/doc/fonts/amiri/tools/runtest.py b/Master/texmf-dist/doc/fonts/amiri/tools/runtest.py
index 4ea7ff34076..3b4f24f6e18 100755
--- a/Master/texmf-dist/doc/fonts/amiri/tools/runtest.py
+++ b/Master/texmf-dist/doc/fonts/amiri/tools/runtest.py
@@ -36,8 +36,10 @@ def runTest(test, font):
def initTest(test, font):
out = ""
for row in test:
+ text = row[4]
+ row[4] = ('\\' in row[4]) and row[4].decode('unicode-escape') or row[4]
result = runHB(row, font)
- out += "%s;%s\n" %(";".join(row), result)
+ out += "%s;%s;%s\n" %(";".join(row[:4]), text, result)
return out
@@ -59,9 +61,9 @@ if __name__ == '__main__':
test.append(row)
if init:
+ fontname = 'amiri-regular.ttf'
outname = testname+".test"
outfd = open(outname, "w")
- outfd.write("# %s\n" %fontname)
outfd.write(initTest(test, fontname))
outfd.close()
sys.exit(0)