Skip to content

Commit b060f7c

Browse files
committed
Merge pull request #2433 from mdboom/unicode-font-filenames
Handle Unicode font filenames correctly/Fix crashing MacOSX backend
2 parents 46b5123 + e2a49e0 commit b060f7c

11 files changed

+95
-72
lines changed

lib/matplotlib/backends/backend_agg.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -262,7 +262,7 @@ def _get_agg_font(self, prop):
262262
font = RendererAgg._fontd.get(fname)
263263
if font is None:
264264
font = FT2Font(
265-
str(fname),
265+
fname,
266266
hinting_factor=rcParams['text.hinting_factor'])
267267
RendererAgg._fontd[fname] = font
268268
RendererAgg._fontd[key] = font

lib/matplotlib/backends/backend_pdf.py

+6-5
Original file line numberDiff line numberDiff line change
@@ -585,7 +585,7 @@ def fontName(self, fontprop):
585585
self.fontNames[filename] = Fx
586586
self.nextFont += 1
587587
matplotlib.verbose.report(
588-
'Assigning font %s = %s' % (Fx, filename),
588+
'Assigning font %s = %r' % (Fx, filename),
589589
'debug')
590590

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

704-
ft2font = FT2Font(str(fontfile))
704+
ft2font = FT2Font(fontfile)
705705

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

764-
font = FT2Font(str(filename))
764+
font = FT2Font(filename)
765765
fonttype = rcParams['pdf.fonttype']
766766

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

846846
# Make the charprocs array (using ttconv to generate the
847847
# actual outlines)
848-
rawcharprocs = ttconv.get_pdf_charprocs(filename, glyph_ids)
848+
rawcharprocs = ttconv.get_pdf_charprocs(
849+
filename.encode(sys.getfilesystemencoding()), glyph_ids)
849850
charprocs = {}
850851
charprocsRef = {}
851852
for charname, stream in six.iteritems(rawcharprocs):
@@ -2003,7 +2004,7 @@ def _get_font_ttf(self, prop):
20032004
filename = findfont(prop)
20042005
font = self.truetype_font_cache.get(filename)
20052006
if font is None:
2006-
font = FT2Font(str(filename))
2007+
font = FT2Font(filename)
20072008
self.truetype_font_cache[filename] = font
20082009
self.truetype_font_cache[key] = font
20092010
font.clear()

lib/matplotlib/backends/backend_pgf.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
system_fonts = []
3434
for f in font_manager.findSystemFonts():
3535
try:
36-
system_fonts.append(FT2Font(str(f)).family_name)
36+
system_fonts.append(FT2Font(f).family_name)
3737
except RuntimeError:
3838
pass # some fonts on osx are known to fail, print?
3939
except:

lib/matplotlib/backends/backend_ps.py

+5-3
Original file line numberDiff line numberDiff line change
@@ -391,7 +391,7 @@ def _get_font_ttf(self, prop):
391391
fname = findfont(prop)
392392
font = self.fontd.get(fname)
393393
if font is None:
394-
font = FT2Font(str(fname))
394+
font = FT2Font(fname)
395395
self.fontd[fname] = font
396396
self.fontd[key] = font
397397
font.clear()
@@ -1131,7 +1131,7 @@ def print_figure_impl():
11311131
if not rcParams['ps.useafm']:
11321132
for font_filename, chars in six.itervalues(ps_renderer.used_characters):
11331133
if len(chars):
1134-
font = FT2Font(str(font_filename))
1134+
font = FT2Font(font_filename)
11351135
cmap = font.get_charmap()
11361136
glyph_ids = []
11371137
for c in chars:
@@ -1153,7 +1153,9 @@ def print_figure_impl():
11531153
raise RuntimeError("OpenType CFF fonts can not be saved using the internal Postscript backend at this time.\nConsider using the Cairo backend.")
11541154
else:
11551155
fh.flush()
1156-
convert_ttf_to_ps(font_filename, raw_fh, fonttype, glyph_ids)
1156+
convert_ttf_to_ps(
1157+
font_filename.encode(sys.getfilesystemencoding()),
1158+
raw_fh, fonttype, glyph_ids)
11571159
print("end", file=fh)
11581160
print("%%EndProlog", file=fh)
11591161

lib/matplotlib/backends/backend_svg.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -323,7 +323,7 @@ def _get_font(self, prop):
323323
fname = findfont(prop)
324324
font = self.fontd.get(fname)
325325
if font is None:
326-
font = FT2Font(str(fname))
326+
font = FT2Font(fname)
327327
self.fontd[fname] = font
328328
self.fontd[key] = font
329329
font.clear()

lib/matplotlib/font_manager.py

+25-15
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,6 @@
6262
parse_fontconfig_pattern, generate_fontconfig_pattern
6363

6464
USE_FONTCONFIG = False
65-
6665
verbose = matplotlib.verbose
6766

6867
font_scalings = {
@@ -269,16 +268,20 @@ def get_fontconfig_fonts(fontext='ttf'):
269268

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

278277
if pipe.returncode == 0:
279-
output = str(output)
280-
for line in output.split('\n'):
281-
fname = line.split(':')[0]
278+
# The line breaks between results are in ascii, but each entry
279+
# is in in sys.filesystemencoding().
280+
for fname in output.split(b'\n'):
281+
try:
282+
fname = six.text_type(fname, sys.getfilesystemencoding())
283+
except UnicodeDecodeError:
284+
continue
282285
if (os.path.splitext(fname)[1][1:] in fontext and
283286
os.path.exists(fname)):
284287
fontfiles[fname] = 1
@@ -570,7 +573,7 @@ def createFontList(fontfiles, fontext='ttf'):
570573
continue
571574
else:
572575
try:
573-
font = ft2font.FT2Font(str(fpath))
576+
font = ft2font.FT2Font(fpath)
574577
except RuntimeError:
575578
verbose.report("Could not open font file %s"%fpath)
576579
continue
@@ -720,7 +723,7 @@ def get_name(self):
720723
Return the name of the font that best matches the font
721724
properties.
722725
"""
723-
return ft2font.FT2Font(str(findfont(self))).family_name
726+
return ft2font.FT2Font(findfont(self)).family_name
724727

725728
def get_style(self):
726729
"""
@@ -1246,7 +1249,7 @@ def findfont(self, prop, fontext='ttf', directory=None,
12461249
else:
12471250
verbose.report(
12481251
'findfont: Matching %s to %s (%s) with score of %f' %
1249-
(prop, best_font.name, best_font.fname, best_score))
1252+
(prop, best_font.name, repr(best_font.fname), best_score))
12501253
result = best_font.fname
12511254

12521255
if not os.path.isfile(result):
@@ -1292,19 +1295,26 @@ def fc_match(pattern, fontext):
12921295
fontexts = get_fontext_synonyms(fontext)
12931296
ext = "." + fontext
12941297
try:
1295-
pipe = subprocess.Popen(['fc-match', '-sv', pattern], stdout=subprocess.PIPE)
1298+
pipe = subprocess.Popen(
1299+
['fc-match', '-s', '--format=%{file}\\n', pattern],
1300+
stdout=subprocess.PIPE)
12961301
output = pipe.communicate()[0]
12971302
except (OSError, IOError):
12981303
return None
1304+
1305+
# The bulk of the output from fc-list is ascii, so we keep the
1306+
# result in bytes and parse it as bytes, until we extract the
1307+
# filename, which is in sys.filesystemencoding().
12991308
if pipe.returncode == 0:
1300-
for match in _fc_match_regex.finditer(output):
1301-
file = match.group(1)
1302-
file = file.decode(sys.getfilesystemencoding())
1303-
if os.path.splitext(file)[1][1:] in fontexts:
1304-
return file
1309+
for fname in output.split(b'\n'):
1310+
try:
1311+
fname = six.text_type(fname, sys.getfilesystemencoding())
1312+
except UnicodeDecodeError:
1313+
continue
1314+
if os.path.splitext(fname)[1][1:] in fontexts:
1315+
return fname
13051316
return None
13061317

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

13101320
def findfont(prop, fontext='ttf'):

lib/matplotlib/mathtext.py

+9-18
Original file line numberDiff line numberDiff line change
@@ -566,7 +566,7 @@ def __init__(self, default_font_prop, mathtext_backend):
566566
self._fonts = {}
567567

568568
filename = findfont(default_font_prop)
569-
default_font = self.CachedFont(FT2Font(str(filename)))
569+
default_font = self.CachedFont(FT2Font(filename))
570570
self._fonts['default'] = default_font
571571
self._fonts['regular'] = default_font
572572

@@ -581,8 +581,8 @@ def _get_font(self, font):
581581
basename = font
582582

583583
cached_font = self._fonts.get(basename)
584-
if cached_font is None:
585-
font = FT2Font(str(basename))
584+
if cached_font is None and os.path.exists(basename):
585+
font = FT2Font(basename)
586586
cached_font = self.CachedFont(font)
587587
self._fonts[basename] = cached_font
588588
self._fonts[font.postscript_name] = cached_font
@@ -697,20 +697,14 @@ def _get_glyph(self, fontname, font_class, sym, fontsize):
697697
if fontname in self.fontmap and sym in latex_to_bakoma:
698698
basename, num = latex_to_bakoma[sym]
699699
slanted = (basename == "cmmi10") or sym in self._slanted_symbols
700-
try:
701-
cached_font = self._get_font(basename)
702-
except RuntimeError:
703-
pass
704-
else:
700+
cached_font = self._get_font(basename)
701+
if cached_font is not None:
705702
symbol_name = cached_font.font.get_glyph_name(num)
706703
num = cached_font.glyphmap[num]
707704
elif len(sym) == 1:
708705
slanted = (fontname == "it")
709-
try:
710-
cached_font = self._get_font(fontname)
711-
except RuntimeError:
712-
pass
713-
else:
706+
cached_font = self._get_font(fontname)
707+
if cached_font is not None:
714708
num = ord(sym)
715709
gid = cached_font.charmap.get(num)
716710
if gid is not None:
@@ -852,11 +846,8 @@ def _get_glyph(self, fontname, font_class, sym, fontsize):
852846

853847
slanted = (new_fontname == 'it') or sym in self._slanted_symbols
854848
found_symbol = False
855-
try:
856-
cached_font = self._get_font(new_fontname)
857-
except RuntimeError:
858-
pass
859-
else:
849+
cached_font = self._get_font(new_fontname)
850+
if cached_font is not None:
860851
try:
861852
glyphindex = cached_font.charmap[uniindex]
862853
found_symbol = True

lib/matplotlib/textpath.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ def _get_font(self, prop):
5656
find a ttf font.
5757
"""
5858
fname = font_manager.findfont(prop)
59-
font = FT2Font(str(fname))
59+
font = FT2Font(fname)
6060
font.set_size(self.FONT_SCALE, self.DPI)
6161

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

340340
if font_and_encoding is None:
341-
font = FT2Font(str(font_bunch.filename))
341+
font = FT2Font(font_bunch.filename)
342342

343343
for charmap_name, charmap_code in [("ADOBE_CUSTOM",
344344
1094992451),

0 commit comments

Comments
 (0)