From 028054b3e7eef1de905a3fbaf3510dd73def88d1 Mon Sep 17 00:00:00 2001 From: James Evans Date: Wed, 12 Aug 2015 10:55:10 -0700 Subject: [PATCH 1/2] This was making invalid fontconfig strings (as per the fontconfig documentation). This added a leading ':' character when there shouldn't have been one. the 'family' parameter was being improperly escaped. This was adding 'family=' for the 'family' parameter when it shouldn't be there. The result was that FontConfig would generate a pattern, but couldn't correctly read it back in. This has now been fixed. --- lib/matplotlib/fontconfig_pattern.py | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/lib/matplotlib/fontconfig_pattern.py b/lib/matplotlib/fontconfig_pattern.py index dbc9871a1dde..e7fc146c2a42 100644 --- a/lib/matplotlib/fontconfig_pattern.py +++ b/lib/matplotlib/fontconfig_pattern.py @@ -179,12 +179,21 @@ def generate_fontconfig_pattern(d): props = [] families = '' size = '' - for key in 'family style variant weight stretch file size'.split(): + # Handle 'family' first and escape it properly + family = d.get_family() + if family: + if type(family) == list: + family = [ family_escape( r'\\\1', str(x)) for x in family if x ] + if family: + family = ','.join( family ) + props.append( "%s" % family ) + + for key in [ 'style', 'variant', 'weight', 'stretch', 'file', 'size' ]: val = getattr(d, 'get_' + key)() - if val is not None and val != []: + if val: if type(val) == list: - val = [value_escape(r'\\\1', str(x)) for x in val if x is not None] - if val != []: + val = [value_escape(r'\\\1', str(x)) for x in val if x] + if val: val = ','.join(val) props.append(":%s=%s" % (key, val)) return ''.join(props) From 209e5151433b02111474f8a0ac400fd567c54100 Mon Sep 17 00:00:00 2001 From: James Evans Date: Mon, 17 Aug 2015 14:22:16 -0700 Subject: [PATCH 2/2] Updated to match mpl style requirements. Added a test case. --- lib/matplotlib/fontconfig_pattern.py | 8 ++-- lib/matplotlib/tests/test_fontconfig.py | 50 +++++++++++++++++++++++++ 2 files changed, 54 insertions(+), 4 deletions(-) create mode 100644 lib/matplotlib/tests/test_fontconfig.py diff --git a/lib/matplotlib/fontconfig_pattern.py b/lib/matplotlib/fontconfig_pattern.py index e7fc146c2a42..356785752d94 100644 --- a/lib/matplotlib/fontconfig_pattern.py +++ b/lib/matplotlib/fontconfig_pattern.py @@ -183,12 +183,12 @@ def generate_fontconfig_pattern(d): family = d.get_family() if family: if type(family) == list: - family = [ family_escape( r'\\\1', str(x)) for x in family if x ] + family = [family_escape( r'\\\1', str(x)) for x in family if x] if family: - family = ','.join( family ) - props.append( "%s" % family ) + family = ','.join(family) + props.append("%s" % family) - for key in [ 'style', 'variant', 'weight', 'stretch', 'file', 'size' ]: + for key in ['style', 'variant', 'weight', 'stretch', 'file', 'size']: val = getattr(d, 'get_' + key)() if val: if type(val) == list: diff --git a/lib/matplotlib/tests/test_fontconfig.py b/lib/matplotlib/tests/test_fontconfig.py new file mode 100644 index 000000000000..e5cba0887f38 --- /dev/null +++ b/lib/matplotlib/tests/test_fontconfig.py @@ -0,0 +1,50 @@ +from __future__ import (absolute_import, division, print_function, + unicode_literals) + +from nose.tools import assert_equal +from matplotlib.externals import six + +import os + +from matplotlib.font_manager import FontProperties +from matplotlib.fontconfig_pattern import generate_fontconfig_pattern +from matplotlib.fontconfig_pattern import parse_fontconfig_pattern + + +def check_fonts_same(f1, f2): + assert_equal(f1.get_family(), f2.get_family()) + assert_equal(f1.get_style(), f2.get_style()) + assert_equal(f1.get_variant(), f2.get_variant()) + assert_equal(f1.get_weight(), f2.get_weight()) + assert_equal(f1.get_stretch(), f2.get_stretch()) + assert_equal(f1.get_size(), f2.get_size()) + + +def do_test(font, expected): + # First convert the mpl FontProperties to a fontconfig string + fc = generate_fontconfig_pattern(font) + + # make sure it is what we expected + assert_equal(fc, expected) + + # now make sure we can convert it back + newfont = parse_fontconfig_pattern(fc) + + # ensure the new font property maches the old one + check_fonts_same(font, newfont) + + +def test_fontconfig(): + s1 ="u'sans\\-serif:style=normal:variant=normal:weight=normal:stretch=normal:size=12.0'" + f1 = FontProperties() + do_test(f1, s1) + + s2 ="u'serif:style=normal:variant=normal:weight=normal:stretch=normal:size=12.0'" + f2 = FontProperties(family = 'serif') + do_test(f2, s2) + + s1 ="u'sans\\-serif:style=normal:variant=normal:weight=bold:stretch=normal:size=24.0'" + f3 = FontProperties(size=24, weight="bold") + f3.set_family(None) + do_test(f3, s3) +