2121 * integrate screen dpi w/ ppi and text
2222"""
2323from __future__ import division
24-
24+ import threading
2525import numpy as np
2626
2727from matplotlib import verbose , rcParams
@@ -51,19 +51,19 @@ class RendererAgg(RendererBase):
5151 # multiple figures are created we can reuse them. This helps with
5252 # a bug on windows where the creation of too many figures leads to
5353 # too many open file handles. However, storing them at the class
54- # level is not thread safe. The solution here is to cache the
55- # fonts at class level, but for a given renderer to slurp them
56- # down into the instance cache "_fontd_instance" from the
57- # "_fontd_class" in a call to pre_draw_hook (managed by the
58- # FigureCanvas) and to restore them to the fontd_class in the
59- # post_draw_hook.
60- _fontd_class = maxdict (50 )
54+ # level is not thread safe. The solution here is to let the
55+ # FigureCanvas acquire a lock on the fontd at the start of the
56+ # draw, and release it when it is done. This allows multiple
57+ # renderers to share the cached fonts, but only one figure can
58+ # draw at at time and so the font cache is used by only one
59+ # renderer at a time
60+
61+ lock = threading .Lock ()
62+ _fontd = maxdict (50 )
6163 def __init__ (self , width , height , dpi ):
6264 if __debug__ : verbose .report ('RendererAgg.__init__' , 'debug-annoying' )
6365 RendererBase .__init__ (self )
6466 self .texd = maxdict (50 ) # a cache of tex image rasters
65- self ._fontd_instance = maxdict (50 )
66-
6767
6868 self .dpi = dpi
6969 self .width = width
@@ -82,15 +82,6 @@ def __init__(self, width, height, dpi):
8282 if __debug__ : verbose .report ('RendererAgg.__init__ done' ,
8383 'debug-annoying' )
8484
85- def pre_draw_hook (self ):
86- 'called by FigureCanvas right before draw; slurp in the class level cache'
87- self ._fontd_instance = RendererAgg ._fontd_class
88- RendererAgg ._fontd_class = {}
89-
90- def post_draw_hook (self ):
91- 'called by FigureCanvas right after draw; restore the class level cache'
92- RendererAgg ._fontd_class = self ._fontd_instance
93- self ._fontd_instance = {}
9485
9586 def _get_hinting_flag (self ):
9687 if rcParams ['text.hinting' ]:
@@ -238,16 +229,16 @@ def _get_agg_font(self, prop):
238229 'debug-annoying' )
239230
240231 key = hash (prop )
241- font = self . _fontd_instance .get (key )
232+ font = RendererAgg . _fontd .get (key )
242233
243234 if font is None :
244235 fname = findfont (prop )
245- font = self . _fontd_instance .get (fname )
236+ font = RendererAgg . _fontd .get (fname )
246237 if font is None :
247238 font = FT2Font (str (fname ))
248- self . _fontd_instance [fname ] = font
239+ RendererAgg . _fontd [fname ] = font
249240
250- self . _fontd_instance [key ] = font
241+ RendererAgg . _fontd [key ] = font
251242
252243 font .clear ()
253244 size = prop .get_size_in_points ()
@@ -423,9 +414,15 @@ def draw(self):
423414 if __debug__ : verbose .report ('FigureCanvasAgg.draw' , 'debug-annoying' )
424415
425416 self .renderer = self .get_renderer ()
426- self .renderer .pre_draw_hook ()
427- self .figure .draw (self .renderer )
428- self .renderer .post_draw_hook ()
417+ # acquire a lock on the shared font cache
418+ RendererAgg .lock .acquire ()
419+
420+ try :
421+ self .figure .draw (self .renderer )
422+ finally :
423+ RendererAgg .lock .release ()
424+
425+
429426
430427 def get_renderer (self ):
431428 l , b , w , h = self .figure .bbox .bounds
0 commit comments