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

Faster character mapping #5299

Merged
merged 4 commits into from
Oct 30, 2015
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
4 changes: 4 additions & 0 deletions INSTALL
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,10 @@ libpng 1.2 (or later)
``cycler`` 0.9 or later
Composable cycle class used for constructing style-cycles

`functools32`
Required for compatibility if running on versions of Python before
Python 3.2.


Optional GUI framework
^^^^^^^^^^^^^^^^^^^^^^
Expand Down
466 changes: 227 additions & 239 deletions lib/matplotlib/_mathtext_data.py

Large diffs are not rendered by default.

28 changes: 10 additions & 18 deletions lib/matplotlib/backends/backend_agg.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,13 @@
import numpy as np

from matplotlib import verbose, rcParams
from matplotlib.backend_bases import RendererBase,\
FigureManagerBase, FigureCanvasBase
from matplotlib.backend_bases import (RendererBase, FigureManagerBase,
FigureCanvasBase)
from matplotlib.cbook import is_string_like, maxdict, restrict_dict
from matplotlib.figure import Figure
from matplotlib.font_manager import findfont
from matplotlib.ft2font import FT2Font, LOAD_FORCE_AUTOHINT, LOAD_NO_HINTING, \
LOAD_DEFAULT, LOAD_NO_AUTOHINT
from matplotlib.font_manager import findfont, get_font
from matplotlib.ft2font import (LOAD_FORCE_AUTOHINT, LOAD_NO_HINTING,
LOAD_DEFAULT, LOAD_NO_AUTOHINT)
from matplotlib.mathtext import MathTextParser
from matplotlib.path import Path
from matplotlib.transforms import Bbox, BboxBase
Expand Down Expand Up @@ -81,7 +81,6 @@ class RendererAgg(RendererBase):
# renderer at a time

lock = threading.RLock()
_fontd = maxdict(50)
def __init__(self, width, height, dpi):
if __debug__: verbose.report('RendererAgg.__init__', 'debug-annoying')
RendererBase.__init__(self)
Expand Down Expand Up @@ -191,6 +190,7 @@ def draw_text(self, gc, x, y, s, prop, angle, ismath=False, mtext=None):

flags = get_hinting_flag()
font = self._get_agg_font(prop)

if font is None: return None
if len(s) == 1 and ord(s) > 127:
font.load_char(ord(s), flags=flags)
Expand Down Expand Up @@ -272,18 +272,10 @@ def _get_agg_font(self, prop):
if __debug__: verbose.report('RendererAgg._get_agg_font',
'debug-annoying')

key = hash(prop)
font = RendererAgg._fontd.get(key)

if font is None:
fname = findfont(prop)
font = RendererAgg._fontd.get(fname)
if font is None:
font = FT2Font(
fname,
hinting_factor=rcParams['text.hinting_factor'])
RendererAgg._fontd[fname] = font
RendererAgg._fontd[key] = font
fname = findfont(prop)
font = get_font(
fname,
hinting_factor=rcParams['text.hinting_factor'])

font.clear()
size = prop.get_size_in_points()
Expand Down
30 changes: 11 additions & 19 deletions lib/matplotlib/backends/backend_pdf.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,18 +29,18 @@
import matplotlib
from matplotlib import __version__, rcParams
from matplotlib._pylab_helpers import Gcf
from matplotlib.backend_bases import RendererBase, GraphicsContextBase,\
FigureManagerBase, FigureCanvasBase
from matplotlib.backend_bases import (RendererBase, GraphicsContextBase,
FigureManagerBase, FigureCanvasBase)
from matplotlib.backends.backend_mixed import MixedModeRenderer
from matplotlib.cbook import Bunch, is_string_like, \
get_realpath_and_stat, is_writable_file_like, maxdict
from matplotlib.cbook import (Bunch, is_string_like, get_realpath_and_stat,
is_writable_file_like, maxdict)
from matplotlib.figure import Figure
from matplotlib.font_manager import findfont, is_opentype_cff_font
from matplotlib.font_manager import findfont, is_opentype_cff_font, get_font
from matplotlib.afm import AFM
import matplotlib.type1font as type1font
import matplotlib.dviread as dviread
from matplotlib.ft2font import FT2Font, FIXED_WIDTH, ITALIC, LOAD_NO_SCALE, \
LOAD_NO_HINTING, KERNING_UNFITTED
from matplotlib.ft2font import (FIXED_WIDTH, ITALIC, LOAD_NO_SCALE,
LOAD_NO_HINTING, KERNING_UNFITTED)
from matplotlib.mathtext import MathTextParser
from matplotlib.transforms import Affine2D, BboxBase
from matplotlib.path import Path
Expand Down Expand Up @@ -757,7 +757,7 @@ def createType1Descriptor(self, t1font, fontfile):
if 0:
flags |= 1 << 18

ft2font = FT2Font(fontfile)
ft2font = get_font(fontfile)

descriptor = {
'Type': Name('FontDescriptor'),
Expand Down Expand Up @@ -817,7 +817,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(filename)
font = get_font(filename)
fonttype = rcParams['pdf.fonttype']

def cvt(length, upe=font.units_per_EM, nearest=True):
Expand Down Expand Up @@ -1526,7 +1526,6 @@ def writeTrailer(self):


class RendererPdf(RendererBase):
truetype_font_cache = maxdict(50)
afm_font_cache = maxdict(50)

def __init__(self, file, image_dpi):
Expand Down Expand Up @@ -2126,15 +2125,8 @@ def _get_font_afm(self, prop):
return font

def _get_font_ttf(self, prop):
key = hash(prop)
font = self.truetype_font_cache.get(key)
if font is None:
filename = findfont(prop)
font = self.truetype_font_cache.get(filename)
if font is None:
font = FT2Font(filename)
self.truetype_font_cache[filename] = font
self.truetype_font_cache[key] = font
filename = findfont(prop)
font = get_font(filename)
font.clear()
font.set_size(prop.get_size_in_points(), 72)
return font
Expand Down
3 changes: 1 addition & 2 deletions lib/matplotlib/backends/backend_pgf.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,9 @@
system_fonts = []
if sys.platform.startswith('win'):
from matplotlib import font_manager
from matplotlib.ft2font import FT2Font
for f in font_manager.win32InstalledFonts():
try:
system_fonts.append(FT2Font(str(f)).family_name)
system_fonts.append(font_manager.get_font(str(f)).family_name)
except:
pass # unknown error, skip this font
else:
Expand Down
18 changes: 5 additions & 13 deletions lib/matplotlib/backends/backend_ps.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ def _fn_name(): return sys._getframe(1).f_code.co_name
is_writable_file_like, maxdict, file_requires_unicode
from matplotlib.figure import Figure

from matplotlib.font_manager import findfont, is_opentype_cff_font
from matplotlib.ft2font import FT2Font, KERNING_DEFAULT, LOAD_NO_HINTING
from matplotlib.font_manager import findfont, is_opentype_cff_font, get_font
from matplotlib.ft2font import KERNING_DEFAULT, LOAD_NO_HINTING
from matplotlib.ttconv import convert_ttf_to_ps
from matplotlib.mathtext import MathTextParser
from matplotlib._mathtext_data import uni2type1
Expand Down Expand Up @@ -199,7 +199,6 @@ class RendererPS(RendererBase):
context instance that controls the colors/styles.
"""

fontd = maxdict(50)
afmfontd = maxdict(50)

def __init__(self, width, height, pswriter, imagedpi=72):
Expand Down Expand Up @@ -393,15 +392,8 @@ def _get_font_afm(self, prop):
return font

def _get_font_ttf(self, prop):
key = hash(prop)
font = self.fontd.get(key)
if font is None:
fname = findfont(prop)
font = self.fontd.get(fname)
if font is None:
font = FT2Font(fname)
self.fontd[fname] = font
self.fontd[key] = font
fname = findfont(prop)
font = get_font(fname)
font.clear()
size = prop.get_size_in_points()
font.set_size(size, 72.0)
Expand Down Expand Up @@ -1145,7 +1137,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(font_filename)
font = get_font(font_filename)
cmap = font.get_charmap()
glyph_ids = []
for c in chars:
Expand Down
17 changes: 5 additions & 12 deletions lib/matplotlib/backends/backend_svg.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@
from matplotlib.cbook import is_string_like, is_writable_file_like, maxdict
from matplotlib.colors import rgb2hex
from matplotlib.figure import Figure
from matplotlib.font_manager import findfont, FontProperties
from matplotlib.ft2font import FT2Font, KERNING_DEFAULT, LOAD_NO_HINTING
from matplotlib.font_manager import findfont, FontProperties, get_font
from matplotlib.ft2font import KERNING_DEFAULT, LOAD_NO_HINTING
from matplotlib.mathtext import MathTextParser
from matplotlib.path import Path
from matplotlib import _path
Expand Down Expand Up @@ -326,15 +326,8 @@ def _make_flip_transform(self, transform):
.translate(0.0, self.height))

def _get_font(self, prop):
key = hash(prop)
font = self.fontd.get(key)
if font is None:
fname = findfont(prop)
font = self.fontd.get(fname)
if font is None:
font = FT2Font(fname)
self.fontd[fname] = font
self.fontd[key] = font
fname = findfont(prop)
font = get_font(fname)
font.clear()
size = prop.get_size_in_points()
font.set_size(size, 72.0)
Expand Down Expand Up @@ -495,7 +488,7 @@ def _write_svgfonts(self):
writer = self.writer
writer.start('defs')
for font_fname, chars in six.iteritems(self._fonts):
font = FT2Font(font_fname)
font = get_font(font_fname)
font.set_size(72, 72)
sfnt = font.get_sfnt()
writer.start('font', id=sfnt[(1, 0, 0, 4)])
Expand Down
13 changes: 11 additions & 2 deletions lib/matplotlib/font_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,12 @@
from matplotlib.fontconfig_pattern import \
parse_fontconfig_pattern, generate_fontconfig_pattern

try:
from functools import lru_cache
except ImportError:
from functools32 import lru_cache


USE_FONTCONFIG = False
verbose = matplotlib.verbose

Expand Down Expand Up @@ -733,7 +739,7 @@ def get_name(self):
Return the name of the font that best matches the font
properties.
"""
return ft2font.FT2Font(findfont(self)).family_name
return get_font(findfont(self)).family_name

def get_style(self):
"""
Expand Down Expand Up @@ -1336,7 +1342,6 @@ def findfont(self, prop, fontext='ttf', directory=None,
_lookup_cache[fontext].set(prop, result)
return result


_is_opentype_cff_font_cache = {}
def is_opentype_cff_font(filename):
"""
Expand All @@ -1357,6 +1362,10 @@ def is_opentype_cff_font(filename):
fontManager = None
_fmcache = None


get_font = lru_cache(64)(ft2font.FT2Font)


# The experimental fontconfig-based backend.
if USE_FONTCONFIG and sys.platform != 'win32':
import re
Expand Down