am 5d0db7f2
: am 5455ddc4
: Merge "Add a script to rename fonts for SDK. [DO NOT MERGE]" into jb-mr1.1-dev
* commit '5d0db7f2ff4a16a40bbdba9b1ae9b4434554bced': Add a script to rename fonts for SDK. [DO NOT MERGE]
This commit is contained in:
9
tools/layoutlib/rename_font/README
Normal file
9
tools/layoutlib/rename_font/README
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
This tool is used to rename the PS name encoded inside the ttf font that we ship
|
||||||
|
with the SDK. There is bug in Java that returns incorrect results for
|
||||||
|
java.awt.Font#layoutGlyphVector() if two fonts with same name but differnt
|
||||||
|
versions are loaded. As a workaround, we rename all the fonts that we ship with
|
||||||
|
the SDK by appending the font version to its name.
|
||||||
|
|
||||||
|
|
||||||
|
The build_font.py copies all files from input_dir to output_dir while renaming
|
||||||
|
the font files (*.ttf) in the process.
|
BIN
tools/layoutlib/rename_font/Roboto-Regular.ttf
Normal file
BIN
tools/layoutlib/rename_font/Roboto-Regular.ttf
Normal file
Binary file not shown.
154
tools/layoutlib/rename_font/build_font.py
Executable file
154
tools/layoutlib/rename_font/build_font.py
Executable file
@ -0,0 +1,154 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
# Copyright (C) 2014 The Android Open Source Project
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the 'License');
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an 'AS IS' BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
|
||||||
|
"""
|
||||||
|
Rename the PS name of all fonts in the input directories and copy them to the
|
||||||
|
output directory.
|
||||||
|
|
||||||
|
Usage: build_font.py /path/to/input_fonts1/ /path/to/input_fonts2/ /path/to/output_fonts/
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
import sys
|
||||||
|
# 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'
|
||||||
|
|
||||||
|
def main(argv):
|
||||||
|
if len(argv) < 2:
|
||||||
|
sys.exit('Usage: build_font.py /path/to/input_fonts/ /path/to/out/dir/')
|
||||||
|
for directory in argv:
|
||||||
|
if not os.path.isdir(directory):
|
||||||
|
sys.exit(directory + ' is not a valid directory')
|
||||||
|
global dest_dir
|
||||||
|
dest_dir = argv[-1]
|
||||||
|
src_dirs = argv[:-1]
|
||||||
|
cwd = os.getcwd()
|
||||||
|
os.chdir(dest_dir)
|
||||||
|
files = glob.glob('*')
|
||||||
|
for filename in files:
|
||||||
|
os.remove(filename)
|
||||||
|
os.chdir(cwd)
|
||||||
|
input_fonts = list()
|
||||||
|
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)
|
||||||
|
if '.git' in dirnames:
|
||||||
|
# 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
|
||||||
|
# the path to the output file. The file name is the fontfilename.ttx
|
||||||
|
ttx_path = os.path.join(dest_dir, filename)
|
||||||
|
ttx_path = ttx_path[:-1] + 'x'
|
||||||
|
try:
|
||||||
|
# run ttx to generate an xml file in the output folder which represents all
|
||||||
|
# its info
|
||||||
|
ttx_args = ['-q', '-d', dest_dir, input_path]
|
||||||
|
ttx.main(ttx_args)
|
||||||
|
# now parse the xml file to change its PS name.
|
||||||
|
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' )
|
||||||
|
# generate the udpated font now.
|
||||||
|
ttx_args = ['-q', '-d', dest_dir, ttx_path]
|
||||||
|
ttx.main(ttx_args)
|
||||||
|
except InvalidFontException:
|
||||||
|
# In case of invalid fonts, we exit.
|
||||||
|
print filename + ' is not a valid font'
|
||||||
|
raise
|
||||||
|
except Exception as e:
|
||||||
|
print 'Error converting font: ' + filename
|
||||||
|
print e
|
||||||
|
# Some fonts are too big to be handled by the ttx library.
|
||||||
|
# Just copy paste them.
|
||||||
|
shutil.copy(input_path, dest_dir)
|
||||||
|
try:
|
||||||
|
# delete the temp ttx file is it exists.
|
||||||
|
os.remove(ttx_path)
|
||||||
|
except OSError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def get_font_info(tag):
|
||||||
|
ps_name = None
|
||||||
|
ps_version = None
|
||||||
|
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):
|
||||||
|
for namerecord in tag.iter('namerecord'):
|
||||||
|
if 'nameID' in namerecord.attrib:
|
||||||
|
if namerecord.attrib['nameID'] == '6':
|
||||||
|
namerecord.text = name
|
||||||
|
|
||||||
|
def sanitize(string):
|
||||||
|
return re.sub(r'[^\w-]+', '', string)
|
||||||
|
|
||||||
|
def get_version(string):
|
||||||
|
# The string must begin with 'Version n.nn '
|
||||||
|
# to extract n.nn, we return the second entry in the split strings.
|
||||||
|
string = string.strip()
|
||||||
|
if not string.startswith('Version '):
|
||||||
|
raise InvalidFontException('mal-formed font version')
|
||||||
|
return sanitize(string.split()[1])
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main(sys.argv[1:])
|
44
tools/layoutlib/rename_font/test.py
Executable file
44
tools/layoutlib/rename_font/test.py
Executable file
@ -0,0 +1,44 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
"""Tests build_font.py by renaming a font.
|
||||||
|
|
||||||
|
The test copies Roboto-Regular.ttf to a tmp directory and ask build_font.py to rename it and put in another dir.
|
||||||
|
We then use ttx to dump the new font to its xml and check if rename was successful
|
||||||
|
|
||||||
|
To test locally, use:
|
||||||
|
PYTHONPATH="$PYTHONPATH:/path/to/android/checkout/external/fonttools/Lib" ./test.py
|
||||||
|
"""
|
||||||
|
|
||||||
|
import unittest
|
||||||
|
import build_font
|
||||||
|
|
||||||
|
from fontTools import ttx
|
||||||
|
import os
|
||||||
|
import xml.etree.ElementTree as etree
|
||||||
|
import shutil
|
||||||
|
import tempfile
|
||||||
|
|
||||||
|
class MyTest(unittest.TestCase):
|
||||||
|
def test(self):
|
||||||
|
font_name = "Roboto-Regular.ttf"
|
||||||
|
srcdir = tempfile.mkdtemp()
|
||||||
|
print "srcdir: " + srcdir
|
||||||
|
shutil.copy(font_name, srcdir)
|
||||||
|
destdir = tempfile.mkdtemp()
|
||||||
|
print "destdir: " + destdir
|
||||||
|
self.assertTrue(build_font.main([srcdir, destdir]) is None)
|
||||||
|
out_path = os.path.join(destdir, font_name)
|
||||||
|
ttx.main([out_path])
|
||||||
|
ttx_path = out_path[:-1] + "x"
|
||||||
|
tree = etree.parse(ttx_path)
|
||||||
|
root = tree.getroot()
|
||||||
|
name_tag = root.find('name')
|
||||||
|
[f_name, f_version] = build_font.get_font_info(name_tag)
|
||||||
|
shutil.rmtree(srcdir)
|
||||||
|
shutil.rmtree(destdir)
|
||||||
|
self.assertEqual(f_name, "Roboto-Regular1200310")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
Reference in New Issue
Block a user