Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Invalidate font manager when rcParam family lists change. #3077

Merged
merged 3 commits into from May 22, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
56 changes: 47 additions & 9 deletions lib/matplotlib/font_manager.py
Expand Up @@ -952,7 +952,45 @@ def pickle_load(filename):
data = pickle.load(fh)
return data

class FontManager:

class TempCache(object):
"""
A class to store temporary caches that are (a) not saved to disk
and (b) invalidated whenever certain font-related
rcParams---namely the family lookup lists---are changed or the
font cache is reloaded. This avoids the expensive linear search
through all fonts every time a font is looked up.
"""
# A list of rcparam names that, when changed, invalidated this
# cache.
invalidating_rcparams = (
'font.serif', 'font.sans-serif', 'font.cursive', 'font.fantasy',
'font.monospace')

def __init__(self):
self._lookup_cache = {}
self._last_rcParams = self.make_rcparams_key()

def make_rcparams_key(self):
return [id(fontManager)] + [
rcParams[param] for param in self.invalidating_rcparams]

def get(self, prop):
key = self.make_rcparams_key()
if key != self._last_rcParams:
self._lookup_cache = {}
self._last_rcParams = key
return self._lookup_cache.get(prop)

def set(self, prop, value):
key = self.make_rcparams_key()
if key != self._last_rcParams:
self._lookup_cache = {}
self._last_rcParams = key
self._lookup_cache[prop] = value


class FontManager(object):
"""
On import, the :class:`FontManager` singleton instance creates a
list of TrueType fonts based on the font properties: name, style,
Expand Down Expand Up @@ -1015,9 +1053,6 @@ def __init__(self, size=None, weight='normal'):
else:
self.defaultFont['afm'] = None

self.ttf_lookup_cache = {}
self.afm_lookup_cache = {}

def get_default_weight(self):
"""
Return the default font weight.
Expand Down Expand Up @@ -1200,15 +1235,13 @@ def findfont(self, prop, fontext='ttf', directory=None,
return fname

if fontext == 'afm':
font_cache = self.afm_lookup_cache
fontlist = self.afmlist
else:
font_cache = self.ttf_lookup_cache
fontlist = self.ttflist

if directory is None:
cached = font_cache.get(hash(prop))
if cached:
cached = _lookup_cache[fontext].get(prop)
if cached is not None:
return cached

best_score = 1e64
Expand Down Expand Up @@ -1266,7 +1299,7 @@ def findfont(self, prop, fontext='ttf', directory=None,
raise ValueError("No valid font could be found")

if directory is None:
font_cache[hash(prop)] = result
_lookup_cache[fontext].set(prop, result)
return result


Expand Down Expand Up @@ -1348,6 +1381,11 @@ def findfont(prop, fontext='ttf'):

fontManager = None

_lookup_cache = {
'ttf': TempCache(),
'afm': TempCache()
}

def _rebuild():
global fontManager
fontManager = FontManager()
Expand Down
6 changes: 1 addition & 5 deletions lib/matplotlib/tests/test_font_manager.py
Expand Up @@ -6,18 +6,14 @@

import os

from matplotlib.font_manager import findfont, FontProperties, _rebuild
from matplotlib.font_manager import findfont, FontProperties
from matplotlib import rc_context


def test_font_priority():
with rc_context(rc={
'font.sans-serif':
['cmmi10', 'Bitstream Vera Sans']}):
# force the font manager to rebuild it self
_rebuild()
font = findfont(
FontProperties(family=["sans-serif"]))
assert_equal(os.path.basename(font), 'cmmi10.ttf')
# force it again
_rebuild()