Revision: 4633
          http://matplotlib.svn.sourceforge.net/matplotlib/?rev=4633&view=rev
Author:   mdboom
Date:     2007-12-05 12:28:28 -0800 (Wed, 05 Dec 2007)

Log Message:
-----------
Fix bug where font files were opened many more times than they need to be.

Modified Paths:
--------------
    trunk/matplotlib/lib/matplotlib/backends/backend_agg.py
    trunk/matplotlib/lib/matplotlib/backends/backend_pdf.py
    trunk/matplotlib/lib/matplotlib/backends/backend_ps.py
    trunk/matplotlib/lib/matplotlib/backends/backend_svg.py
    trunk/matplotlib/lib/matplotlib/font_manager.py

Modified: trunk/matplotlib/lib/matplotlib/backends/backend_agg.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/backends/backend_agg.py     2007-12-05 
19:36:36 UTC (rev 4632)
+++ trunk/matplotlib/lib/matplotlib/backends/backend_agg.py     2007-12-05 
20:28:28 UTC (rev 4633)
@@ -80,7 +80,8 @@
 from matplotlib._pylab_helpers import Gcf
 from matplotlib.backend_bases import RendererBase,\
      GraphicsContextBase, FigureManagerBase, FigureCanvasBase
-from matplotlib.cbook import enumerate, is_string_like, exception_to_str
+from matplotlib.cbook import enumerate, is_string_like, exception_to_str, \
+    maxdict
 from matplotlib.figure import Figure
 from matplotlib.font_manager import findfont
 from matplotlib.ft2font import FT2Font, LOAD_FORCE_AUTOHINT
@@ -98,7 +99,8 @@
     """
 
     debug=1
-    texd = {}  # a cache of tex image rasters
+    texd = maxdict(50)  # a cache of tex image rasters
+    _fontd = maxdict(50)
     def __init__(self, width, height, dpi):
         if __debug__: verbose.report('RendererAgg.__init__', 'debug-annoying')
         RendererBase.__init__(self)
@@ -125,7 +127,6 @@
         self.copy_from_bbox = self._renderer.copy_from_bbox
         self.restore_region = self._renderer.restore_region
         self.mathtext_parser = MathTextParser('Agg')
-        self._fontd = {}
 
         self.bbox = lbwh_to_bbox(0,0, self.width, self.height)
         if __debug__: verbose.report('RendererAgg.__init__ done',
@@ -272,7 +273,10 @@
 
         if font is None:
             fname = findfont(prop)
-            font = FT2Font(str(fname))
+            font = self._fontd.get(fname)
+            if font is None:
+                font = FT2Font(str(fname))
+                self._fontd[fname] = font
             self._fontd[key] = font
 
         font.clear()

Modified: trunk/matplotlib/lib/matplotlib/backends/backend_pdf.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/backends/backend_pdf.py     2007-12-05 
19:36:36 UTC (rev 4632)
+++ trunk/matplotlib/lib/matplotlib/backends/backend_pdf.py     2007-12-05 
20:28:28 UTC (rev 4633)
@@ -25,7 +25,7 @@
 from matplotlib.backend_bases import RendererBase, GraphicsContextBase,\
      FigureManagerBase, FigureCanvasBase
 from matplotlib.cbook import Bunch, enumerate, is_string_like, reverse_dict, \
-    get_realpath_and_stat, is_writable_file_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.afm import AFM
@@ -1147,13 +1147,13 @@
         self.write("\nstartxref\n%d\n%%%%EOF\n" % self.startxref)
 
 class RendererPdf(RendererBase):
+    truetype_font_cache = maxdict(50)
+    afm_font_cache = maxdict(50)
 
     def __init__(self, file, dpi):
         RendererBase.__init__(self)
         self.file = file
         self.gc = self.new_gc()
-        self.truetype_font_cache = {}
-        self.afm_font_cache = {}
         self.file.used_characters = self.used_characters = {}
         self.mathtext_parser = MathTextParser("Pdf")
         self.image_magnification = dpi/72.0
@@ -1161,8 +1161,6 @@
 
     def finalize(self):
         self.gc.finalize()
-        del self.truetype_font_cache
-        del self.afm_font_cache
 
     def check_gc(self, gc, fillcolor=None):
         orig_fill = gc._fillcolor
@@ -1679,9 +1677,12 @@
         font = self.afm_font_cache.get(key)
         if font is None:
             filename = findfont(prop, fontext='afm')
-            fh = file(filename)
-            font = AFM(fh)
-            fh.close()
+            font = self.afm_font_cache.get(filename)
+            if font is None:
+                fh = file(filename)
+                font = AFM(fh)
+                self.afm_font_cache[filename] = font
+                fh.close()
             self.afm_font_cache[key] = font
         return font
 
@@ -1690,7 +1691,10 @@
         font = self.truetype_font_cache.get(key)
         if font is None:
             filename = findfont(prop)
-            font = FT2Font(str(filename))
+            font = self.truetype_font_cache.get(filename)
+            if font is None:
+                font = FT2Font(str(filename))
+                self.truetype_font_cache[filename] = font
             self.truetype_font_cache[key] = font
         font.clear()
         font.set_size(prop.get_size_in_points(), 72.0)

Modified: trunk/matplotlib/lib/matplotlib/backends/backend_ps.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/backends/backend_ps.py      2007-12-05 
19:36:36 UTC (rev 4632)
+++ trunk/matplotlib/lib/matplotlib/backends/backend_ps.py      2007-12-05 
20:28:28 UTC (rev 4633)
@@ -16,7 +16,7 @@
      FigureManagerBase, FigureCanvasBase
 
 from matplotlib.cbook import is_string_like, izip, get_realpath_and_stat, \
-    is_writable_file_like
+    is_writable_file_like, maxdict
 from matplotlib.figure import Figure
 
 from matplotlib.font_manager import findfont, is_opentype_cff_font
@@ -123,6 +123,9 @@
     context instance that controls the colors/styles.
     """
 
+    fontd = maxdict(50)
+    afmfontd = maxdict(50)
+
     def __init__(self, width, height, pswriter, dpi=72):
         RendererBase.__init__(self)
         self.width = width
@@ -143,8 +146,6 @@
         self.hatch = None
         self.image_magnification = dpi/72.0
 
-        self.fontd = {}
-        self.afmfontd = {}
         self.used_characters = {}
         self.mathtext_parser = MathTextParser("PS")
 
@@ -315,7 +316,11 @@
         key = hash(prop)
         font = self.afmfontd.get(key)
         if font is None:
-            font = AFM(file(findfont(prop, fontext='afm')))
+            fname = findfont(prop, fontext='afm')
+            font = self.afmfontd.get(fname)
+            if font is None:
+                font = AFM(file(findfont(prop, fontext='afm')))
+                self.afmfontd[fname] = font
             self.afmfontd[key] = font
         return font
 
@@ -324,13 +329,16 @@
         font = self.fontd.get(key)
         if font is None:
             fname = findfont(prop)
-            font = FT2Font(str(fname))
+            font = self.fontd.get(fname)
+            if font is None:
+                font = FT2Font(str(fname))
+                self.fontd[fname] = font
             self.fontd[key] = font
         font.clear()
         size = prop.get_size_in_points()
         font.set_size(size, 72.0)
         return font
-        
+
     def draw_arc(self, gc, rgbFace, x, y, width, height, angle1, angle2, 
rotation):
         """
         Draw an arc centered at x,y with width and height and angles
@@ -524,12 +532,12 @@
 
         ps_cmd = []
         ps_cmd.append('newpath')
-        
+
         while 1:
             code, xp, yp = path.vertex()
 
             #print code, xp, yp
-            
+
             if code == agg.path_cmd_stop:
                 ps_cmd.append('closepath') # Hack, path_cmd_end_poly not found
                 break
@@ -742,7 +750,7 @@
 
         elif isinstance(s, unicode):
             return self.draw_unicode(gc, x, y, s, prop, angle)
-        
+
         elif rcParams['ps.useafm']:
             font = self._get_font_afm(prop)
 
@@ -826,7 +834,7 @@
                     kern = 0
                 last_name = name
                 thisx += kern * scale
-                
+
                 lines.append('%f %f m /%s glyphshow'%(thisx, thisy, name))
 
                 thisx += width * scale
@@ -843,7 +851,7 @@
 grestore
     """ % locals()
             self._pswriter.write(ps)
-            
+
         else:
             font = self._get_font_ttf(prop)
 
@@ -949,7 +957,7 @@
             write("stroke\n")
         else:
             write("newpath\n")
-            
+
         if cliprect:
             write("grestore\n")
 
@@ -999,16 +1007,16 @@
 
     filetypes = {'ps'  : 'Postscript',
                  'eps' : 'Encapsulated Postscript'}
-    
+
     def get_default_filetype(self):
         return 'ps'
-    
+
     def print_ps(self, outfile, *args, **kwargs):
         return self._print_ps(outfile, 'ps', *args, **kwargs)
 
     def print_eps(self, outfile, *args, **kwargs):
         return self._print_ps(outfile, 'eps', *args, **kwargs)
-    
+
     def _print_ps(self, outfile, format, *args, **kwargs):
         papertype = kwargs.get("papertype", rcParams['ps.papersize'])
         papertype = papertype.lower()
@@ -1017,7 +1025,7 @@
         elif papertype not in papersize:
             raise RuntimeError( '%s is not a valid papertype. Use one \
                     of %s'% (papertype, ', '.join( papersize.keys() )) )
-            
+
         orientation = kwargs.get("orientation", "portrait").lower()
         if orientation == 'landscape': isLandscape = True
         elif orientation == 'portrait': isLandscape = False
@@ -1027,14 +1035,14 @@
         dpi = kwargs.get("dpi", 72)
         facecolor = kwargs.get("facecolor", "w")
         edgecolor = kwargs.get("edgecolor", "w")
-        
+
         if rcParams['text.usetex']:
             self._print_figure_tex(outfile, format, dpi, facecolor, edgecolor,
                                    orientation, isLandscape, papertype)
         else:
             self._print_figure(outfile, format, dpi, facecolor, edgecolor,
                                orientation, isLandscape, papertype)
-            
+
     def _print_figure(self, outfile, format, dpi=72, facecolor='w', 
edgecolor='w',
                       orientation='portrait', isLandscape=False, 
papertype=None):
         """
@@ -1643,5 +1651,5 @@
 -0.552284749831 -1.0 -1.0 -0.552284749831 -1.0 0.0 curveto
 closepath
     } bind def""",
-    
+
 ]

Modified: trunk/matplotlib/lib/matplotlib/backends/backend_svg.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/backends/backend_svg.py     2007-12-05 
19:36:36 UTC (rev 4632)
+++ trunk/matplotlib/lib/matplotlib/backends/backend_svg.py     2007-12-05 
20:28:28 UTC (rev 4633)
@@ -5,7 +5,7 @@
 from matplotlib import verbose, __version__, rcParams
 from matplotlib.backend_bases import RendererBase, GraphicsContextBase,\
      FigureManagerBase, FigureCanvasBase
-from matplotlib.cbook import is_string_like, is_writable_file_like
+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
@@ -27,6 +27,7 @@
 _capstyle_d = {'projecting' : 'square', 'butt' : 'butt', 'round': 'round',}
 class RendererSVG(RendererBase):
     FONT_SCALE = 100.0
+    fontd = maxdict(50)
 
     def __init__(self, width, height, svgwriter, basename=None):
         self.width=width
@@ -41,7 +42,6 @@
         self._clipd = {}
         self._char_defs = {}
         self.mathtext_parser = MathTextParser('SVG')
-        self.fontd = {}
         svgwriter.write(svgProlog%(width,height,width,height))
 
     def _draw_svg_element(self, element, details, gc, rgbFace):
@@ -60,7 +60,10 @@
         font = self.fontd.get(key)
         if font is None:
             fname = findfont(prop)
-            font = FT2Font(str(fname))
+            font = self.fontd.get(fname)
+            if font is None:
+                font = FT2Font(str(fname))
+                self.fontd[fname] = font
             self.fontd[key] = font
         font.clear()
         size = prop.get_size_in_points()
@@ -245,7 +248,7 @@
         font = self._get_font(prop)
         font.set_text(s, 0.0, flags=LOAD_NO_HINTING)
         y -= font.get_descent() / 64.0
-        
+
         fontsize = prop.get_size_in_points()
         color = rgb2hex(gc.get_rgb())
 
@@ -386,7 +389,7 @@
             for font, fontsize, thetext, new_x, new_y_mtc, metrics in 
svg_glyphs:
                 new_y = - new_y_mtc
                 style = "font-size: %f; font-family: %s" % (fontsize, 
font.family_name)
-                
+
                 svg.append('<tspan style="%s"' % style)
                 xadvance = metrics.advance
                 svg.append(' textLength="%s"' % xadvance)
@@ -468,7 +471,7 @@
         else:
             raise ValueError("filename must be a path or a file-like object")
         return self._print_svg(filename, svgwriter, fh_to_close)
-            
+
     def print_svgz(self, filename, *args, **kwargs):
         if is_string_like(filename):
             gzipwriter = gzip.GzipFile(filename, 'w')
@@ -479,7 +482,7 @@
         else:
             raise ValueError("filename must be a path or a file-like object")
         return self._print_svg(filename, svgwriter, fh_to_close)
-    
+
     def _print_svg(self, filename, svgwriter, fh_to_close=None):
         self.figure.dpi.set(72)
         width, height = self.figure.get_size_inches()
@@ -490,10 +493,10 @@
         renderer.finish()
         if fh_to_close is not None:
             svgwriter.close()
-        
+
     def get_default_filetype(self):
         return 'svg'
-        
+
 class FigureManagerSVG(FigureManagerBase):
     pass
 

Modified: trunk/matplotlib/lib/matplotlib/font_manager.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/font_manager.py     2007-12-05 19:36:36 UTC 
(rev 4632)
+++ trunk/matplotlib/lib/matplotlib/font_manager.py     2007-12-05 20:28:28 UTC 
(rev 4633)
@@ -36,7 +36,7 @@
 import os, sys, glob, shutil
 from sets import Set
 import matplotlib
-from matplotlib import afm 
+from matplotlib import afm
 from matplotlib import ft2font
 from matplotlib import rcParams, get_home, get_configdir
 from matplotlib.cbook import is_string_like
@@ -49,7 +49,7 @@
     import pickle
 
 USE_FONTCONFIG = False
-    
+
 verbose = matplotlib.verbose
 
 font_scalings = {'xx-small': 0.579, 'x-small': 0.694, 'small': 0.833,
@@ -98,7 +98,7 @@
 def get_fontext_synonyms(fontext):
     return {'ttf': ('ttf', 'otf'),
             'afm': ('afm',)}[fontext]
-        
+
 def win32FontDirectory():
     """Return the user-specified font directory for Win32."""
 
@@ -126,7 +126,7 @@
         directory = win32FontDirectory()
 
     fontext = get_fontext_synonyms(fontext)
-        
+
     key, items = None, {}
     for fontdir in MSFontDirectories:
         try:
@@ -178,7 +178,7 @@
         directory = OSXFontDirectory()
 
     fontext = get_fontext_synonyms(fontext)
-        
+
     files = []
     for path in directory:
         if fontext is None:
@@ -214,7 +214,7 @@
         return {}
 
     fontext = get_fontext_synonyms(fontext)
-    
+
     fontfiles = {}
     status, output = commands.getstatusoutput("fc-list file")
     if status == 0:
@@ -236,7 +236,7 @@
     """
     fontfiles = {}
     fontexts = get_fontext_synonyms(fontext)
-    
+
     if fontpaths is None:
         if sys.platform == 'win32':
             fontdir = win32FontDirectory()
@@ -635,7 +635,7 @@
         stretch = [rcParams['font.stretch']]
         size = [rcParams['font.size']]
         file = None
-        
+
     def __init__(self,
                  family = None,
                  style  = None,
@@ -653,7 +653,7 @@
         if _init is not None:
             self.__props.__dict__.update(_init)
             return
-        
+
         if is_string_like(family):
             # Treat family as a fontconfig pattern if it is the only
             # parameter provided.
@@ -674,16 +674,16 @@
         self.set_stretch(stretch)
         self.set_file(fname)
         self.set_size(size)
-            
+
     def _parse_fontconfig_pattern(self, pattern):
         return parse_fontconfig_pattern(pattern)
 
     def __hash__(self):
-        return hash(repr(self.__props))
+        return hash(repr(self.__props.__dict__))
 
     def __str__(self):
         return self.get_fontconfig_pattern()
-                              
+
     def get_family(self):
         """Return a list of font names that comprise the font family.
         """
@@ -727,7 +727,7 @@
 
     def get_fontconfig_pattern(self):
         return generate_fontconfig_pattern(self.__props.__dict__)
-    
+
     def set_family(self, family):
         """
         Change the font family.  May be either an alias (generic name
@@ -741,7 +741,7 @@
                 family = [family]
             self.__props.family = family
     set_name = set_family
-            
+
     def set_style(self, style):
         """Set the font style.  Values are: normal, italic or oblique."""
         if style is None:
@@ -812,7 +812,7 @@
 
     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__)
@@ -862,7 +862,7 @@
     def __init__(self, size=None, weight='normal'):
         self.__default_weight = weight
         self.default_size = size
-        
+
         paths = [os.path.join(rcParams['datapath'],'fonts','ttf'),
                  os.path.join(rcParams['datapath'],'fonts','afm')]
 
@@ -1076,8 +1076,8 @@
             _is_opentype_cff_font_cache[filename] = result
         return result
     return False
-        
-    
+
+
 if USE_FONTCONFIG and sys.platform != 'win32':
     import re
 
@@ -1095,7 +1095,7 @@
 
     _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()


This was sent by the SourceForge.net collaborative development platform, the 
world's largest Open Source development site.

-------------------------------------------------------------------------
SF.Net email is sponsored by: The Future of Linux Business White Paper
from Novell.  From the desktop to the data center, Linux is going
mainstream.  Let it simplify your IT future.
http://altfarm.mediaplex.com/ad/ck/8857-50307-18918-4
_______________________________________________
Matplotlib-checkins mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/matplotlib-checkins

Reply via email to