summaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rwxr-xr-xtools/layoutlib/rename_font/build_font.py164
-rwxr-xr-xtools/layoutlib/rename_font/test.py5
2 files changed, 120 insertions, 49 deletions
diff --git a/tools/layoutlib/rename_font/build_font.py b/tools/layoutlib/rename_font/build_font.py
index bd9b14c..c747d92 100755
--- a/tools/layoutlib/rename_font/build_font.py
+++ b/tools/layoutlib/rename_font/build_font.py
@@ -22,19 +22,45 @@ Usage: build_font.py /path/to/input_fonts1/ /path/to/input_fonts2/ /path/to/outp
"""
+import glob
+from multiprocessing import Pool
+import os
+import re
+import shutil
import sys
+import xml.etree.ElementTree as etree
+
+# Prevent .pyc files from being created.
+sys.dont_write_bytecode = True
+
# fontTools is available at platform/external/fonttools
from fontTools import ttx
-import re
-import os
-import xml.etree.ElementTree as etree
-import shutil
-import glob
-from multiprocessing import Pool
# global variable
dest_dir = '/tmp'
+
+class FontInfo(object):
+ family = None
+ style = None
+ version = None
+ ends_in_regular = False
+ fullname = None
+
+
+class InvalidFontException(Exception):
+ pass
+
+
+# These constants represent the value of nameID parameter in the namerecord for
+# different information.
+# see http://scripts.sil.org/cms/scripts/page.php?item_id=IWS-Chapter08#3054f18b
+NAMEID_FAMILY = 1
+NAMEID_STYLE = 2
+NAMEID_FULLNAME = 4
+NAMEID_VERSION = 5
+
+
def main(argv):
if len(argv) < 2:
sys.exit('Usage: build_font.py /path/to/input_fonts/ /path/to/out/dir/')
@@ -54,23 +80,20 @@ def main(argv):
for src_dir in src_dirs:
for dirname, dirnames, filenames in os.walk(src_dir):
for filename in filenames:
- input_path = os.path.join(dirname, filename)
- extension = os.path.splitext(filename)[1].lower()
- if (extension == '.ttf'):
- input_fonts.append(input_path)
- elif (extension == '.xml'):
- shutil.copy(input_path, dest_dir)
+ input_path = os.path.join(dirname, filename)
+ extension = os.path.splitext(filename)[1].lower()
+ if extension == '.ttf':
+ input_fonts.append(input_path)
+ elif extension == '.xml':
+ shutil.copy(input_path, dest_dir)
if '.git' in dirnames:
- # don't go into any .git directories.
- dirnames.remove('.git')
+ # don't go into any .git directories.
+ dirnames.remove('.git')
# Create as many threads as the number of CPUs
pool = Pool(processes=None)
pool.map(convert_font, input_fonts)
-class InvalidFontException(Exception):
- pass
-
def convert_font(input_path):
filename = os.path.basename(input_path)
print 'Converting font: ' + filename
@@ -86,11 +109,8 @@ def convert_font(input_path):
tree = etree.parse(ttx_path)
root = tree.getroot()
for name in root.iter('name'):
- [old_ps_name, version] = get_font_info(name)
- if old_ps_name is not None and version is not None:
- new_ps_name = old_ps_name + version
- update_name(name, new_ps_name)
- tree.write(ttx_path, xml_declaration=True, encoding='utf-8' )
+ update_tag(name, get_font_info(name))
+ tree.write(ttx_path, xml_declaration=True, encoding='utf-8')
# generate the udpated font now.
ttx_args = ['-q', '-d', dest_dir, ttx_path]
ttx.main(ttx_args)
@@ -110,37 +130,83 @@ def convert_font(input_path):
except OSError:
pass
+
def get_font_info(tag):
- ps_name = None
- ps_version = None
+ """ Returns a list of FontInfo representing the various sets of namerecords
+ found in the name table of the font. """
+ fonts = []
+ font = None
+ last_name_id = sys.maxint
for namerecord in tag.iter('namerecord'):
if 'nameID' in namerecord.attrib:
- # if the tag has nameID=6, it is the postscript name of the font.
- # see: http://scripts.sil.org/cms/scripts/page.php?item_id=IWS-Chapter08#3054f18b
- if namerecord.attrib['nameID'] == '6':
- if ps_name is not None:
- if not sanitize(namerecord.text) == ps_name:
- raise InvalidFontException('found multiple possibilities of the font name')
- else:
- ps_name = sanitize(namerecord.text)
- # nameID=5 means the font version
- if namerecord.attrib['nameID'] == '5':
- if ps_version is not None:
- if not ps_version == get_version(namerecord.text):
- raise InvalidFontException('found multiple possibilities of the font version')
- else:
- ps_version = get_version(namerecord.text)
- return [ps_name, ps_version]
-
-
-def update_name(tag, name):
+ name_id = int(namerecord.attrib['nameID'])
+ # A new font should be created for each platform, encoding and language
+ # id. But, since the nameIDs are sorted, we use the easy approach of
+ # creating a new one when the nameIDs reset.
+ if name_id <= last_name_id and font is not None:
+ fonts.append(font)
+ font = None
+ last_name_id = name_id
+ if font is None:
+ font = FontInfo()
+ if name_id == NAMEID_FAMILY:
+ font.family = namerecord.text.strip()
+ if name_id == NAMEID_STYLE:
+ font.style = namerecord.text.strip()
+ if name_id == NAMEID_FULLNAME:
+ font.ends_in_regular = ends_in_regular(namerecord.text)
+ font.fullname = namerecord.text.strip()
+ if name_id == NAMEID_VERSION:
+ font.version = get_version(namerecord.text)
+ if font is not None:
+ fonts.append(font)
+ return fonts
+
+
+def update_tag(tag, fonts):
+ last_name_id = sys.maxint
+ fonts_iterator = fonts.__iter__()
+ font = None
for namerecord in tag.iter('namerecord'):
if 'nameID' in namerecord.attrib:
- if namerecord.attrib['nameID'] == '6':
- namerecord.text = name
+ name_id = int(namerecord.attrib['nameID'])
+ if name_id <= last_name_id:
+ font = fonts_iterator.next()
+ font = update_font_name(font)
+ last_name_id = name_id
+ if name_id == NAMEID_FAMILY:
+ namerecord.text = font.family
+ if name_id == NAMEID_FULLNAME:
+ namerecord.text = font.fullname
+
+
+def update_font_name(font):
+ """ Compute the new font family name and font fullname. If the font has a
+ valid version, it's sanitized and appended to the font family name. The
+ font fullname is then created by joining the new family name and the
+ style. If the style is 'Regular', it is appended only if the original font
+ had it. """
+ if font.family is None or font.style is None:
+ raise InvalidFontException('Font doesn\'t have proper family name or style')
+ if font.version is not None:
+ new_family = font.family + font.version
+ else:
+ new_family = font.family
+ if font.style is 'Regular' and not font.ends_in_regular:
+ font.fullname = new_family
+ else:
+ font.fullname = new_family + ' ' + font.style
+ font.family = new_family
+ return font
+
+
+def ends_in_regular(string):
+ """ According to the specification, the font fullname should not end in
+ 'Regular' for plain fonts. However, some fonts don't obey this rule. We
+ keep the style info, to minimize the diff. """
+ string = string.strip().split()[-1]
+ return string is 'Regular'
-def sanitize(string):
- return re.sub(r'[^\w-]+', '', string)
def get_version(string):
# The string must begin with 'Version n.nn '
@@ -150,5 +216,9 @@ def get_version(string):
raise InvalidFontException('mal-formed font version')
return sanitize(string.split()[1])
+
+def sanitize(string):
+ return re.sub(r'[^\w-]+', '', string)
+
if __name__ == '__main__':
main(sys.argv[1:])
diff --git a/tools/layoutlib/rename_font/test.py b/tools/layoutlib/rename_font/test.py
index b0b69d8..2ffddf4 100755
--- a/tools/layoutlib/rename_font/test.py
+++ b/tools/layoutlib/rename_font/test.py
@@ -33,10 +33,11 @@ class MyTest(unittest.TestCase):
tree = etree.parse(ttx_path)
root = tree.getroot()
name_tag = root.find('name')
- [f_name, f_version] = build_font.get_font_info(name_tag)
+ fonts = build_font.get_font_info(name_tag)
shutil.rmtree(srcdir)
shutil.rmtree(destdir)
- self.assertEqual(f_name, "Roboto-Regular1200310")
+ self.assertEqual(fonts[0].family, "Roboto1200310")
+ self.assertEqual(fonts[0].fullname, "Roboto1200310 Regular")