Skip to content

Commit

Permalink
Merge pull request #2433 from mdboom/unicode-font-filenames
Browse files Browse the repository at this point in the history
Handle Unicode font filenames correctly/Fix crashing MacOSX backend
  • Loading branch information
mdboom committed Sep 24, 2013
2 parents 46b5123 + e2a49e0 commit b060f7c
Show file tree
Hide file tree
Showing 11 changed files with 95 additions and 72 deletions.
2 changes: 1 addition & 1 deletion lib/matplotlib/backends/backend_agg.py
Expand Up @@ -262,7 +262,7 @@ def _get_agg_font(self, prop):
font = RendererAgg._fontd.get(fname)
if font is None:
font = FT2Font(
str(fname),
fname,
hinting_factor=rcParams['text.hinting_factor'])
RendererAgg._fontd[fname] = font
RendererAgg._fontd[key] = font
Expand Down
11 changes: 6 additions & 5 deletions lib/matplotlib/backends/backend_pdf.py
Expand Up @@ -585,7 +585,7 @@ def fontName(self, fontprop):
self.fontNames[filename] = Fx
self.nextFont += 1
matplotlib.verbose.report(
'Assigning font %s = %s' % (Fx, filename),
'Assigning font %s = %r' % (Fx, filename),
'debug')

return Fx
Expand Down Expand Up @@ -701,7 +701,7 @@ def createType1Descriptor(self, t1font, fontfile):
if 0: flags |= 1 << 17 # TODO: small caps
if 0: flags |= 1 << 18 # TODO: force bold

ft2font = FT2Font(str(fontfile))
ft2font = FT2Font(fontfile)

descriptor = {
'Type': Name('FontDescriptor'),
Expand Down Expand Up @@ -761,7 +761,7 @@ def _get_xobject_symbol_name(self, filename, symbol_name):
def embedTTF(self, filename, characters):
"""Embed the TTF font from the named file into the document."""

font = FT2Font(str(filename))
font = FT2Font(filename)
fonttype = rcParams['pdf.fonttype']

def cvt(length, upe=font.units_per_EM, nearest=True):
Expand Down Expand Up @@ -845,7 +845,8 @@ def get_char_width(charcode):

# Make the charprocs array (using ttconv to generate the
# actual outlines)
rawcharprocs = ttconv.get_pdf_charprocs(filename, glyph_ids)
rawcharprocs = ttconv.get_pdf_charprocs(
filename.encode(sys.getfilesystemencoding()), glyph_ids)
charprocs = {}
charprocsRef = {}
for charname, stream in six.iteritems(rawcharprocs):
Expand Down Expand Up @@ -2003,7 +2004,7 @@ def _get_font_ttf(self, prop):
filename = findfont(prop)
font = self.truetype_font_cache.get(filename)
if font is None:
font = FT2Font(str(filename))
font = FT2Font(filename)
self.truetype_font_cache[filename] = font
self.truetype_font_cache[key] = font
font.clear()
Expand Down
2 changes: 1 addition & 1 deletion lib/matplotlib/backends/backend_pgf.py
Expand Up @@ -33,7 +33,7 @@
system_fonts = []
for f in font_manager.findSystemFonts():
try:
system_fonts.append(FT2Font(str(f)).family_name)
system_fonts.append(FT2Font(f).family_name)
except RuntimeError:
pass # some fonts on osx are known to fail, print?
except:
Expand Down
8 changes: 5 additions & 3 deletions lib/matplotlib/backends/backend_ps.py
Expand Up @@ -391,7 +391,7 @@ def _get_font_ttf(self, prop):
fname = findfont(prop)
font = self.fontd.get(fname)
if font is None:
font = FT2Font(str(fname))
font = FT2Font(fname)
self.fontd[fname] = font
self.fontd[key] = font
font.clear()
Expand Down Expand Up @@ -1131,7 +1131,7 @@ def print_figure_impl():
if not rcParams['ps.useafm']:
for font_filename, chars in six.itervalues(ps_renderer.used_characters):
if len(chars):
font = FT2Font(str(font_filename))
font = FT2Font(font_filename)
cmap = font.get_charmap()
glyph_ids = []
for c in chars:
Expand All @@ -1153,7 +1153,9 @@ def print_figure_impl():
raise RuntimeError("OpenType CFF fonts can not be saved using the internal Postscript backend at this time.\nConsider using the Cairo backend.")
else:
fh.flush()
convert_ttf_to_ps(font_filename, raw_fh, fonttype, glyph_ids)
convert_ttf_to_ps(
font_filename.encode(sys.getfilesystemencoding()),
raw_fh, fonttype, glyph_ids)
print("end", file=fh)
print("%%EndProlog", file=fh)

Expand Down
2 changes: 1 addition & 1 deletion lib/matplotlib/backends/backend_svg.py
Expand Up @@ -323,7 +323,7 @@ def _get_font(self, prop):
fname = findfont(prop)
font = self.fontd.get(fname)
if font is None:
font = FT2Font(str(fname))
font = FT2Font(fname)
self.fontd[fname] = font
self.fontd[key] = font
font.clear()
Expand Down
40 changes: 25 additions & 15 deletions lib/matplotlib/font_manager.py
Expand Up @@ -62,7 +62,6 @@
parse_fontconfig_pattern, generate_fontconfig_pattern

USE_FONTCONFIG = False

verbose = matplotlib.verbose

font_scalings = {
Expand Down Expand Up @@ -269,16 +268,20 @@ def get_fontconfig_fonts(fontext='ttf'):

fontfiles = {}
try:
pipe = subprocess.Popen(['fc-list', '', 'file'], stdout=subprocess.PIPE)
pipe = subprocess.Popen(['fc-list', '--format=%{file}\\n'], stdout=subprocess.PIPE)
output = pipe.communicate()[0]
except (OSError, IOError):
# Calling fc-list did not work, so we'll just return nothing
return fontfiles

if pipe.returncode == 0:
output = str(output)
for line in output.split('\n'):
fname = line.split(':')[0]
# The line breaks between results are in ascii, but each entry
# is in in sys.filesystemencoding().
for fname in output.split(b'\n'):
try:
fname = six.text_type(fname, sys.getfilesystemencoding())
except UnicodeDecodeError:
continue
if (os.path.splitext(fname)[1][1:] in fontext and
os.path.exists(fname)):
fontfiles[fname] = 1
Expand Down Expand Up @@ -570,7 +573,7 @@ def createFontList(fontfiles, fontext='ttf'):
continue
else:
try:
font = ft2font.FT2Font(str(fpath))
font = ft2font.FT2Font(fpath)
except RuntimeError:
verbose.report("Could not open font file %s"%fpath)
continue
Expand Down Expand Up @@ -720,7 +723,7 @@ def get_name(self):
Return the name of the font that best matches the font
properties.
"""
return ft2font.FT2Font(str(findfont(self))).family_name
return ft2font.FT2Font(findfont(self)).family_name

def get_style(self):
"""
Expand Down Expand Up @@ -1246,7 +1249,7 @@ def findfont(self, prop, fontext='ttf', directory=None,
else:
verbose.report(
'findfont: Matching %s to %s (%s) with score of %f' %
(prop, best_font.name, best_font.fname, best_score))
(prop, best_font.name, repr(best_font.fname), best_score))
result = best_font.fname

if not os.path.isfile(result):
Expand Down Expand Up @@ -1292,19 +1295,26 @@ def fc_match(pattern, fontext):
fontexts = get_fontext_synonyms(fontext)
ext = "." + fontext
try:
pipe = subprocess.Popen(['fc-match', '-sv', pattern], stdout=subprocess.PIPE)
pipe = subprocess.Popen(
['fc-match', '-s', '--format=%{file}\\n', pattern],
stdout=subprocess.PIPE)
output = pipe.communicate()[0]
except (OSError, IOError):
return None

# The bulk of the output from fc-list is ascii, so we keep the
# result in bytes and parse it as bytes, until we extract the
# filename, which is in sys.filesystemencoding().
if pipe.returncode == 0:
for match in _fc_match_regex.finditer(output):
file = match.group(1)
file = file.decode(sys.getfilesystemencoding())
if os.path.splitext(file)[1][1:] in fontexts:
return file
for fname in output.split(b'\n'):
try:
fname = six.text_type(fname, sys.getfilesystemencoding())
except UnicodeDecodeError:
continue
if os.path.splitext(fname)[1][1:] in fontexts:
return fname
return None

_fc_match_regex = re.compile(br'\sfile:\s+"([^"]*)"')
_fc_match_cache = {}

def findfont(prop, fontext='ttf'):
Expand Down
27 changes: 9 additions & 18 deletions lib/matplotlib/mathtext.py
Expand Up @@ -566,7 +566,7 @@ def __init__(self, default_font_prop, mathtext_backend):
self._fonts = {}

filename = findfont(default_font_prop)
default_font = self.CachedFont(FT2Font(str(filename)))
default_font = self.CachedFont(FT2Font(filename))
self._fonts['default'] = default_font
self._fonts['regular'] = default_font

Expand All @@ -581,8 +581,8 @@ def _get_font(self, font):
basename = font

cached_font = self._fonts.get(basename)
if cached_font is None:
font = FT2Font(str(basename))
if cached_font is None and os.path.exists(basename):
font = FT2Font(basename)
cached_font = self.CachedFont(font)
self._fonts[basename] = cached_font
self._fonts[font.postscript_name] = cached_font
Expand Down Expand Up @@ -697,20 +697,14 @@ def _get_glyph(self, fontname, font_class, sym, fontsize):
if fontname in self.fontmap and sym in latex_to_bakoma:
basename, num = latex_to_bakoma[sym]
slanted = (basename == "cmmi10") or sym in self._slanted_symbols
try:
cached_font = self._get_font(basename)
except RuntimeError:
pass
else:
cached_font = self._get_font(basename)
if cached_font is not None:
symbol_name = cached_font.font.get_glyph_name(num)
num = cached_font.glyphmap[num]
elif len(sym) == 1:
slanted = (fontname == "it")
try:
cached_font = self._get_font(fontname)
except RuntimeError:
pass
else:
cached_font = self._get_font(fontname)
if cached_font is not None:
num = ord(sym)
gid = cached_font.charmap.get(num)
if gid is not None:
Expand Down Expand Up @@ -852,11 +846,8 @@ def _get_glyph(self, fontname, font_class, sym, fontsize):

slanted = (new_fontname == 'it') or sym in self._slanted_symbols
found_symbol = False
try:
cached_font = self._get_font(new_fontname)
except RuntimeError:
pass
else:
cached_font = self._get_font(new_fontname)
if cached_font is not None:
try:
glyphindex = cached_font.charmap[uniindex]
found_symbol = True
Expand Down
4 changes: 2 additions & 2 deletions lib/matplotlib/textpath.py
Expand Up @@ -56,7 +56,7 @@ def _get_font(self, prop):
find a ttf font.
"""
fname = font_manager.findfont(prop)
font = FT2Font(str(fname))
font = FT2Font(fname)
font.set_size(self.FONT_SCALE, self.DPI)

return font
Expand Down Expand Up @@ -338,7 +338,7 @@ def get_glyphs_tex(self, prop, s, glyph_map=None,
font_bunch = self.tex_font_map[dvifont.texname]

if font_and_encoding is None:
font = FT2Font(str(font_bunch.filename))
font = FT2Font(font_bunch.filename)

for charmap_name, charmap_code in [("ADOBE_CUSTOM",
1094992451),
Expand Down

0 comments on commit b060f7c

Please sign in to comment.