From: <md...@us...> - 2007-08-27 19:34:32
|
Revision: 3742 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3742&view=rev Author: mdboom Date: 2007-08-27 12:34:23 -0700 (Mon, 27 Aug 2007) Log Message: ----------- Better fontconfig pattern standards compliance. Added experimental (may be removed) fontconfig support. Modified Paths: -------------- trunk/matplotlib/lib/matplotlib/font_manager.py trunk/matplotlib/lib/matplotlib/fontconfig_pattern.py Modified: trunk/matplotlib/lib/matplotlib/font_manager.py =================================================================== --- trunk/matplotlib/lib/matplotlib/font_manager.py 2007-08-27 19:33:45 UTC (rev 3741) +++ trunk/matplotlib/lib/matplotlib/font_manager.py 2007-08-27 19:34:23 UTC (rev 3742) @@ -48,6 +48,8 @@ except ImportError: import pickle +USE_FONTCONFIG = False + verbose = matplotlib.verbose font_scalings = {'xx-small': 0.579, 'x-small': 0.694, 'small': 0.833, @@ -84,13 +86,14 @@ "/System/Library/Fonts/" ] -home = os.environ.get('HOME') -if home is not None: - # user fonts on OSX - path = os.path.join(home, 'Library', 'Fonts') - OSXFontDirectories.append(path) - path = os.path.join(home, '.fonts') - X11FontDirectories.append(path) +if not USE_FONTCONFIG: + home = os.environ.get('HOME') + if home is not None: + # user fonts on OSX + path = os.path.join(home, 'Library', 'Fonts') + OSXFontDirectories.append(path) + path = os.path.join(home, '.fonts') + X11FontDirectories.append(path) def win32FontDirectory(): """Return the user-specified font directory for Win32.""" @@ -609,10 +612,10 @@ family = rcParams['font.' + rcParams['font.family']] if is_string_like(family): family = [family] - slant = rcParams['font.style'] - variant = rcParams['font.variant'] - weight = rcParams['font.weight'] - stretch = rcParams['font.stretch'] + slant = [rcParams['font.style']] + variant = [rcParams['font.variant']] + weight = [rcParams['font.weight']] + stretch = [rcParams['font.stretch']] size = [rcParams['font.size']] file = None @@ -675,32 +678,35 @@ def get_style(self): """Return the font style. Values are: normal, italic or oblique.""" - return self.__props.slant + return self.__props.slant[0] def get_variant(self): """Return the font variant. Values are: normal or small-caps.""" - return self.__props.variant + return self.__props.variant[0] def get_weight(self): """ Return the font weight. See the FontProperties class for a a list of possible values. """ - return self.__props.weight + return self.__props.weight[0] def get_stretch(self): """ Return the font stretch or width. Options are: normal, narrow, condensed, or wide. """ - return self.__props.stretch + return self.__props.stretch[0] def get_size(self): """Return the font size.""" return float(self.__props.size[0]) def get_file(self): - return self.__props.file + if self.__props.file is not None: + return self.__props.file[0] + else: + return None def get_fontconfig_pattern(self): return generate_fontconfig_pattern(self.__props.__dict__) @@ -723,7 +729,7 @@ else: if style not in ('normal', 'italic', 'oblique'): raise ValueError("style must be normal, italic or oblique") - self.__props.slant = style + self.__props.slant = [style] def set_variant(self, variant): """Set the font variant. Values are: normal or small-caps.""" @@ -732,7 +738,7 @@ else: if variant not in ('normal', 'small-caps'): raise ValueError("variant must be normal or small-caps") - self.__props.variant = variant + self.__props.variant = [variant] def set_weight(self, weight): """ @@ -745,7 +751,7 @@ if (weight not in weight_dict and weight not in weight_dict.keys()): raise ValueError("weight is invalid") - self.__props.weight = weight + self.__props.weight = [weight] def set_stretch(self, stretch): """ @@ -755,7 +761,7 @@ if stretch is None: self.__props.__dict__.pop('stretch', None) else: - self.__props.stretch = stretch + self.__props.stretch = [stretch] def set_size(self, size): """Set the font size.""" @@ -774,13 +780,19 @@ self.__props.size = size def set_file(self, file): - self.__props.file = file + if file is None: + self.__props.__dict__.pop('file', None) + else: + self.__props.file = [file] get_size_in_points = get_size def set_fontconfig_pattern(self, pattern): self.__props.__dict__ = self._parse_fontconfig_pattern(pattern) - + + def add_property_pair(self, key, val): + self.__props.setdefault(key, []).append(val) + def copy(self): """Return a deep copy of self""" return FontProperties(_init = self.__props.__dict__) @@ -1026,29 +1038,60 @@ return self.defaultFont return fname +if USE_FONTCONFIG and sys.platform != 'win32': + import re -_fmcache = os.path.join(get_configdir(), 'fontManager.cache') + def fc_match(pattern, fontext): + import commands + ext = "." + fontext + status, output = commands.getstatusoutput('fc-match -sv "%s"' % pattern) + if status == 0: + for match in _fc_match_regex.finditer(output): + file = match.group(1) + if os.path.splitext(file)[1] == ext: + return file + return None -fontManager = None + _fc_match_regex = re.compile(r'\sfile:\s+"(.*)"') + _fc_match_cache = {} + + def findfont(prop, fontext='ttf'): + if not is_string_like(prop): + prop = prop.get_fontconfig_pattern() + cached = _fc_match_cache.get(prop) + if cached is not None: + return cached -def _rebuild(): - global fontManager - fontManager = FontManager() - pickle_dump(fontManager, _fmcache) - verbose.report("generated new fontManager") + result = fc_match(prop, fontext) + if result is None: + result = fc_match(':', fontext) -try: - fontManager = pickle_load(_fmcache) - verbose.report("Using fontManager instance from %s" % _fmcache) -except: - _rebuild() + _fc_match_cache[prop] = result + return result -def findfont(prop, **kw): - global fontManager - font = fontManager.findfont(prop, **kw) - if not os.path.exists(font): - verbose.report("%s returned by pickled fontManager does not exist" % font) +else: + _fmcache = os.path.join(get_configdir(), 'fontManager.cache') + + fontManager = None + + def _rebuild(): + global fontManager + fontManager = FontManager() + pickle_dump(fontManager, _fmcache) + verbose.report("generated new fontManager") + + try: + fontManager = pickle_load(_fmcache) + verbose.report("Using fontManager instance from %s" % _fmcache) + except: _rebuild() - font = fontManager.findfont(prop, **kw) - return font + def findfont(prop, **kw): + global fontManager + font = fontManager.findfont(prop, **kw) + if not os.path.exists(font): + verbose.report("%s returned by pickled fontManager does not exist" % font) + _rebuild() + font = fontManager.findfont(prop, **kw) + return font + Modified: trunk/matplotlib/lib/matplotlib/fontconfig_pattern.py =================================================================== --- trunk/matplotlib/lib/matplotlib/fontconfig_pattern.py 2007-08-27 19:33:45 UTC (rev 3741) +++ trunk/matplotlib/lib/matplotlib/fontconfig_pattern.py 2007-08-27 19:34:23 UTC (rev 3742) @@ -19,7 +19,7 @@ """ import re from matplotlib.pyparsing import Literal, OneOrMore, ZeroOrMore, \ - Optional, Regex, StringEnd, ParseException + Optional, Regex, StringEnd, ParseException, Suppress family_punc = r'\\\-:,' family_unescape = re.compile(r'\\([%s])' % family_punc).sub @@ -89,8 +89,12 @@ ).setParseAction(self._point_sizes) property =( (name - + Literal('=') - + value) + + Suppress(Literal('=')) + + value + + ZeroOrMore( + Suppress(Literal(',')) + + value) + ) | name ).setParseAction(self._property) @@ -142,9 +146,11 @@ if len(tokens) == 1: if tokens[0] in self._constants: key, val = self._constants[tokens[0]] - elif len(tokens) == 3: - key, op, val = tokens - self._properties[key] = val + self._properties.setdefault(key, []).append(val) + else: + key = tokens[0] + val = tokens[1:] + self._properties.setdefault(key, []).extend(val) return [] parse_fontconfig_pattern = FontconfigPatternParser().parse @@ -156,14 +162,9 @@ families = '' size = '' for key, val in d.items(): - if key == 'family': - families = [family_escape(r'\\\1', name) for name in val] - families = ','.join(families) - elif key == 'size': - size = '-' + ','.join([str(x) for x in val]) - elif val is not None: - val = value_escape(r'\\\1', str(val)) - props.append(":%s=%s" % (key, val)) - props = ''.join(props) - - return ''.join([families, size, props]) + if val is not None and val != []: + val = [value_escape(r'\\\1', str(x)) for x in val if x is not None] + if val != []: + val = ','.join(val) + props.append(":%s=%s" % (key, val)) + return ''.join(props) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |