Index: CHANGELOG
===================================================================
--- CHANGELOG	(revision 3020)
+++ CHANGELOG	(working copy)
@@ -1,3 +1,34 @@
+2007-02-14 Enhanced the PDF backend. This impacts several files and
+           direcotries in matplotlib:
+           
+           - Created a directory lib/matplotlib/mpl-data/fonts/pdfcorefonts,
+             holding AFM files for the 14 PDF core fonts. These fonts are
+             embedded in every PDF viewing applications.
+           
+           - setup.py: Added the directory pdfcorefonts to package_data.
+           
+           - lib/matplotlib/__init__.py: Added the default parameter 
+             'pdf.use14corefonts'. When True, the PDF backend use only
+             the 14 PDF core fonts.
+           
+           - lib/matplotlib/afm.py: Added some keywords found in recent 
+             AFM files. Added a little workaround to handle Euro symbol.
+           
+           - lib/matplotlib/fontmanager.py: Added support for 14 PDF
+             core fonts. These fonts have a dedicated cache (file 
+             pdfcorefont.cache), not the same as for other AFM files
+             (file .afmfont.cache). Also cleaned comments to conform to 
+             CODING_GUIDE.
+           
+           - lib/matplotlib/backends/backend_pdf.py:
+             Added support for 14 PDF core fonts.
+             Fixed some issues with incorrect character widths and
+             encodings (works only for the most common encoding, 
+             WinAnsiEncoding, defined by the official PDF Reference).
+             Removed parameter 'dpi' because it causes alignment issues
+             (the notion of DPI seems useless in a vectorial format, unless 
+             we use it for image magnification, like in backend_ps.py).
+
 2007-02-13 Added barcode demo- JDH
 
 2007-02-13 Added binary colormap to cm - JDH
Index: lib/matplotlib/__init__.py
===================================================================
--- lib/matplotlib/__init__.py	(revision 3020)
+++ lib/matplotlib/__init__.py	(working copy)
@@ -855,10 +855,11 @@
     'ps.papersize'      : [ 'letter', validate_ps_papersize], # Set the papersize/type
     'ps.useafm'         : [ False, validate_bool],  # Set PYTHONINSPECT
     'ps.usedistiller'   : [ False, validate_ps_distiller],  # use ghostscript or xpdf to distill ps output
-    'ps.distiller.res'  : [6000, validate_int],       # dpi
-    'pdf.compression'   : [6, validate_int],            # compression level from 0 to 9; 0 to disable
-    'svg.image_inline'  : [True, validate_bool],        # write raster image data directly into the svg file
-    'svg.image_noscale'  : [False, validate_bool],        # suppress scaling of raster data embedded in SVG
+    'ps.distiller.res'  : [6000, validate_int],     # dpi
+    'pdf.compression'   : [6, validate_int],        # compression level from 0 to 9; 0 to disable
+    'pdf.use14corefonts' : [False, validate_bool],  # use only the 14 PDF core fonts, embedded in every PDF viewing applications
+    'svg.image_inline'  : [True, validate_bool],    # write raster image data directly into the svg file
+    'svg.image_noscale'  : [False, validate_bool],  # suppress scaling of raster data embedded in SVG
     'plugins.directory' : ['.matplotlib_plugins', str], # where plugin directory is locate
 
     # mathtext settings
Index: lib/matplotlib/afm.py
===================================================================
--- lib/matplotlib/afm.py	(revision 3020)
+++ lib/matplotlib/afm.py	(working copy)
@@ -87,7 +87,10 @@
         'XHeight': _to_float,
         'Ascender': _to_float,
         'Descender': _to_float,
+        'StdHW': _to_float,
+        'StdVW': _to_float,
         'StartCharMetrics': _to_int,
+        'CharacterSet': _to_str,
         'Characters': _to_int,
         'Capheight': _to_int,
         }
@@ -111,7 +114,7 @@
             print >>sys.stderr, 'Value error parsing header in AFM:', key, val
             continue
         except KeyError: 
-            print >>sys.stderr, 'Key error converting in AFM'
+            print >>sys.stderr, 'Found an unknown keyword in AFM header (was %s)' % key
             continue
         if key=='StartCharMetrics': return d
     raise RuntimeError('Bad parse')
@@ -136,13 +139,17 @@
         line = line.rstrip()
         if line.startswith('EndCharMetrics'): return d
         vals = line.split(';')[:4]
-        if len(vals)!=4: raise RuntimeError('Bad char metrics line: %s'%line)
+        if len(vals) !=4 : raise RuntimeError('Bad char metrics line: %s' % line)
         num = _to_int(vals[0].split()[1])
-        if num==-1: continue
         wx = _to_float(vals[1].split()[1])
         name = vals[2].split()[1]
         bbox = _to_list_of_ints(vals[3][2:])
-        d[num] = (wx, name, bbox)
+        # Workaround: If the character name is 'Euro', give it the corresponding 
+        # character code, according to WinAnsiEncoding (see PDF Reference).
+        if name == 'Euro':
+            num = 128
+        if num != -1:
+            d[num] = (wx, name, bbox)
     raise RuntimeError('Bad parse')
 
 def _parse_kern_pairs(fh):
Index: lib/matplotlib/backends/backend_pdf.py
===================================================================
--- lib/matplotlib/backends/backend_pdf.py	(revision 3020)
+++ lib/matplotlib/backends/backend_pdf.py	(working copy)
@@ -20,9 +20,10 @@
 from matplotlib._pylab_helpers import Gcf
 from matplotlib.backend_bases import RendererBase, GraphicsContextBase,\
      FigureManagerBase, FigureCanvasBase
-from matplotlib.cbook import Bunch, enumerate, is_string_like
+from matplotlib.cbook import Bunch, enumerate, is_string_like, reverse_dict
 from matplotlib.figure import Figure
 from matplotlib.font_manager import fontManager
+from matplotlib.afm import AFM
 from matplotlib.ft2font import FT2Font, FIXED_WIDTH, ITALIC, LOAD_NO_SCALE
 from matplotlib.mathtext import math_parse_s_pdf
 from matplotlib.numerix import Float32, UInt8, fromstring, arange, infinity, isnan, asarray
@@ -43,6 +44,17 @@
 # and outputs the necessary commands.  GraphicsContextPdf represents
 # the graphics state, and its "delta" method returns the commands that
 # modify the state.
+
+# Add "pdf.use14corefonts: True" in your configuration file to use only
+# the 14 PDF core fonts. These fonts do not need to be embedded; every 
+# PDF viewing application is required to have them. This results in very
+# light PDF files you can use directly in LaTeX or ConTeXt documents
+# generated with pdfTeX, without any conversion.
+
+# These fonts are: Helvetica, Helvetica-Bold, Helvetica-Oblique, 
+# Helvetica-BoldOblique, Courier, Courier-Bold, Courier-Oblique, 
+# Courier-BoldOblique, Times-Roman, Times-Bold, Times-Italic, 
+# Times-BoldItalic, Symbol, ZapfDingbats.
 #
 # Some tricky points: 
 #
@@ -64,7 +76,7 @@
 # * the alpha channel of images
 # * image compression could be improved (PDF supports png-like compression) 
 # * encoding of fonts, including mathtext fonts and unicode support
-# * Type 1 and Base-14 font support (i.e., "pdf.use_afm") 
+# * Type 1 font support (i.e., "pdf.use_afm") 
 # * TTF support has lots of small TODOs, e.g. how do you know if a font  
 #   is serif/sans-serif, or symbolic/non-symbolic? 
 # * draw_markers, draw_line_collection, etc. 
@@ -118,11 +130,10 @@
     # represented as Name objects.
     elif isinstance(obj, dict):
         r = ["<<"]
-        r.extend(["%s %s" % (Name(key).pdfRepr(),
-                             pdfRepr(val))
+        r.extend(["%s %s" % (Name(key).pdfRepr(), pdfRepr(val))
                   for key, val in obj.items()])
         r.append(">>")
-        return fill(r)
+        return '\n'.join(r)
 
     # Lists.
     elif isinstance(obj, (list, tuple)):
@@ -301,10 +312,9 @@
 class PdfFile:
     """PDF file with one page."""
 
-    def __init__(self, width, height, dpi, filename):
+    def __init__(self, width, height, filename):
         self.nextObject = 1     # next free object id
         self.xrefTable = [ [0, 65535, 'the zero object'] ]
-        self.dpi = dpi
         fh = file(filename, 'wb')
         self.fh = fh
         self.currentstream = None # stream object to write to, if any
@@ -418,49 +428,49 @@
         self.currentstream.end()
         self.currentstream = None
 
-    # These fonts do not need to be embedded; every PDF viewing
-    # application is required to have them.
-    base14 = [ 'Times-Roman', 'Times-Bold', 'Times-Italic',
-               'Times-BoldItalic', 'Symbol', 'ZapfDingbats' ] + \
-             [ prefix + postfix
-               for prefix in 'Helvetica', 'Courier'
-               for postfix in '', '-Bold', '-Oblique', '-BoldOblique' ]
-
     def fontName(self, fontprop):
         if is_string_like(fontprop):
             filename = fontprop
+        elif rcParams['pdf.use14corefonts']:
+            filename = fontManager.findfont(fontprop, fontext='afm')
         else:
             filename = fontManager.findfont(fontprop)
-        Fx = self.fontNames.get(filename, None)
+        
+        Fx = self.fontNames.get(filename)
         if Fx is None:
             Fx = Name('F%d' % self.nextFont)
             self.fontNames[filename] = Fx
             self.nextFont += 1
+        
         return Fx
 
     def writeFonts(self):
         fonts = {}
         for filename, Fx in self.fontNames.items():
-            # TODO: The following test is wrong, since findfont really
-            # returns a file name. Think about how to allow users to
-            # specify the base14 fonts (does fontManager know anything
-            # about them?).
-            if filename in self.base14:
-                fontdict = { 'Subtype': Name('Type1'),
-                             'BaseFont': Name(filename) }
-                # etc...
+            if filename.endswith('.afm'):
+                fontdictObject = self._write_afm_font(filename)
             else:
                 fontdictObject = self.embedTTF(filename)
             fonts[Fx] = fontdictObject
             #print >>sys.stderr, filename
-
         self.writeObject(self.fontObject, fonts)
-
+    
+    def _write_afm_font(self, filename):
+        font = AFM(file(filename))
+        fontname = font.get_fontname()
+        fontdict = { 'Type': Name('Font'),
+                     'Subtype': Name('Type1'),
+                     'BaseFont': Name(fontname),
+                     'Encoding': Name('WinAnsiEncoding') }
+        fontdictObject = self.reserveObject('font dictionary')
+        self.writeObject(fontdictObject, fontdict)
+        return fontdictObject
+    
     def embedTTF(self, filename):
         """Embed the TTF font from the named file into the document."""
-
-        font = FT2Font(filename)
-
+        
+        font = FT2Font(str(filename))
+        
         def cvt(length, upe=font.units_per_EM, nearest=True):
             "Convert font coordinates to PDF glyph coordinates"
             value = length / upe * 1000
@@ -469,7 +479,7 @@
             # boxes and the like
             if value < 0: return floor(value)
             else: return ceil(value)
-
+        
         # You are lost in a maze of TrueType tables, all different...
         ps_name = Name(font.get_sfnt()[(1,0,0,6)])
         pclt = font.get_sfnt_table('pclt') \
@@ -478,35 +488,33 @@
             or { 'italicAngle': (0,0) }
         ff = font.face_flags
         sf = font.style_flags
-        charmap = font.get_charmap()
-        chars = sorted(charmap.keys())
-        firstchar, lastchar = chars[0], chars[-1]
-
-        # Get widths
-        widths = [ cvt(font.load_char(i, flags=LOAD_NO_SCALE).horiAdvance)
-                   for i in range(firstchar, lastchar+1) ]
-        # Remove redundant widths from end and beginning; doing the
-        # end first helps reduce LastChar, which apparently needs to
-        # be less than 256 or acroread complains.
-        missingwidth = widths[-1]
-        while len(widths)>1 and widths[-1] == missingwidth:
-            lastchar -= 1
-            widths.pop()
-        while len(widths)>1 and widths[0] == missingwidth:
-            firstchar += 1
-            widths.pop(0)
-
+        
+        # Get widths for the 256 characters of PDF encoding "WinAnsiEncoding" (similar to
+        # Python encoding "cp1252"). According to the PDF Reference, a simple font, based on
+        # single-byte characters, can't manage more than 256 characters, contrary to a
+        # composite font, based on multi-byte characters.
+        
+        from encodings import cp1252
+        firstchar, lastchar = 0, 255
+        def get_char_width(charcode):
+            unicode = cp1252.decoding_map[charcode] or 0
+            width = font.load_char(unicode, flags=LOAD_NO_SCALE).horiAdvance
+            return cvt(width)
+        widths = [ get_char_width(charcode) for charcode in range(firstchar, lastchar+1) ]
+        
         widthsObject = self.reserveObject('font widths')
         fontdescObject = self.reserveObject('font descriptor')
+        # TODO: "WinAnsiEncoding" could become a parameter of PdfFile. The PDF encoding 
+        # "WinAnsiEncoding" matches the Pyhton enconding "cp1252" used in method 
+        # RenderedPdf.draw_text and RenderedPdf.get_text_width_height to encode Unicode strings.
         fontdict = { 'Type': Name('Font'),
                      'Subtype': Name('TrueType'),
-                     'Encoding': Name('WinAnsiEncoding'), # ???
+                     'Encoding': Name('WinAnsiEncoding'),
                      'BaseFont': ps_name,
                      'FirstChar': firstchar,
                      'LastChar': lastchar,
                      'Widths': widthsObject,
                      'FontDescriptor': fontdescObject }
-        # TODO: Encoding?
 
         flags = 0
         symbolic = False #ps_name.name in ('Cmsy10', 'Cmmi10', 'Cmex10')
@@ -518,7 +526,7 @@
         if 0: flags |= 1 << 16 # TODO: all caps
         if 0: flags |= 1 << 17 # TODO: small caps
         if 0: flags |= 1 << 18 # TODO: force bold
-
+            
         descriptor = {
             'Type': Name('FontDescriptor'),
             'FontName': ps_name,
@@ -530,22 +538,21 @@
             'XHeight': cvt(pclt['xHeight']),
             'ItalicAngle': post['italicAngle'][1], # ???
             'FontFile2': self.reserveObject('font file'),
-            'MaxWidth': max(widths+[missingwidth]),
-            'MissingWidth': missingwidth,
+            'MaxWidth': max(widths),
             'StemV': 0 # ???
-            }
-
+        }
+        
         # Other FontDescriptor keys include:
         # /FontFamily /Times (optional)
         # /FontStretch /Normal (optional)
         # /FontFile (stream for type 1 font)
         # /CharSet (used when subsetting type1 fonts)
-
+        
         # Make an Identity-H encoded CID font for CM fonts? (Doesn't quite work)
         if False:
             del fontdict['Widths'], fontdict['FontDescriptor'], \
                 fontdict['LastChar'], fontdict['FirstChar']
-
+            
             fontdict['Subtype'] = Name('Type0')
             fontdict['Encoding'] = Name('Identity-H')
             fontdict2Object = self.reserveObject('descendant font')
@@ -555,15 +562,14 @@
                           'Subtype': Name('CIDFontType2'),
                           'BaseFont': ps_name,
                           'W': widthsObject,
-                          'DW': missingwidth,
                           'CIDSystemInfo': { 'Registry': 'Adobe', 
                                              'Ordering': 'Identity', 
                                              'Supplement': 0 },
                           'FontDescriptor': fontdescObject }
             self.writeObject(fontdict2Object, fontdict2)
-
+            
             widths = [ firstchar, widths ]
-
+        
         fontdictObject = self.reserveObject('font dictionary')
         length1Object = self.reserveObject('decoded length of a font')
         self.writeObject(fontdictObject, fontdict)
@@ -581,7 +587,7 @@
             self.currentstream.write(data)
         self.endStream()
         self.writeObject(length1Object, length1)
-
+        
         return fontdictObject
 
     def alphaState(self, alpha):
@@ -635,21 +641,21 @@
                 self.output(rgb[0], rgb[1], rgb[2], Op.setrgb_nonstroke,
                             0, 0, sidelen, sidelen, Op.rectangle,
                             Op.fill)
-            if lst[2]:          # -
+            if lst[2]:                # -
                 for j in arange(0.0, sidelen, density/lst[2]):
                     self.output(0, j, Op.moveto,
                                 sidelen, j, Op.lineto)
-            if lst[3]:          # /
+            if lst[3]:                # /
                 for j in arange(0.0, sidelen, density/lst[3]):
                     self.output(0, j, Op.moveto,
                                 sidelen-j, sidelen, Op.lineto,
                                 sidelen-j, 0, Op.moveto,
                                 sidelen, j, Op.lineto)
-            if lst[4]:          # |
+            if lst[4]:                # |
                 for j in arange(0.0, sidelen, density/lst[4]):
                     self.output(j, 0, Op.moveto,
                                 j, sidelen, Op.lineto)
-            if lst[5]:          # \
+            if lst[5]:                # \
                 for j in arange(sidelen, 0.0, -density/lst[5]):
                     self.output(sidelen, j, Op.moveto,
                                 j, sidelen, Op.lineto,
@@ -825,12 +831,9 @@
     def __init__(self, file):
         self.file = file
         self.gc = self.new_gc()
-        self.fonts = {}
-        self.dpi_factor = 72.0/file.dpi
+        self.truetype_font_cache = {}
+        self.afm_font_cache = {}
 
-    def points_to_pixels(self, points):
-        return points / self.dpi_factor
-
     def finalize(self):
         self.gc.finalize()
 
@@ -855,11 +858,6 @@
         If the color rgbFace is not None, fill the arc with it.
         """
         # source: agg_bezier_arc.cpp in agg23
-
-        x *= self.dpi_factor
-        y *= self.dpi_factor
-        width *= self.dpi_factor
-        height *= self.dpi_factor
         
         def arc_to_bezier(cx, cy, rx, ry, angle1, sweep):
             halfsweep = sweep / 2.0
@@ -873,7 +871,7 @@
                         cy + ry * (pxi * sn + pyi * cs))
                        for pxi, pyi in zip(px, py) ]
             return reduce(lambda x, y: x + y, result)
-
+        
         epsilon = 0.01
         angle1 *= pi/180.0
         angle2 *= pi/180.0
@@ -906,21 +904,18 @@
         self.check_gc(gc)
 
         h, w = im.get_size_out()
-        d = self.dpi_factor
         imob = self.file.imageObject(im)
-        self.file.output(Op.gsave, d*w, 0, 0, d*h, d*x, d*y, Op.concat_matrix,
+        self.file.output(Op.gsave, w, 0, 0, h, x, y, Op.concat_matrix,
                          imob, Op.use_xobject, Op.grestore)
 
     def draw_line(self, gc, x1, y1, x2, y2):
         if isnan(x1) or isnan(x2) or isnan(y1) or isnan(y2):
             return
-        d = self.dpi_factor
         self.check_gc(gc)
-        self.file.output(d*x1, d*y1, Op.moveto,
-                         d*x2, d*y2, Op.lineto, self.gc.paint())
+        self.file.output(x1, y1, Op.moveto,
+                         x2, y2, Op.lineto, self.gc.paint())
 
     def draw_lines(self, gc, x, y, transform=None):
-        d = self.dpi_factor
         self.check_gc(gc)
         if transform is not None:
             x, y = transform.seq_x_y(x, y)
@@ -930,16 +925,15 @@
             if nan_at[i]:
                 next_op = Op.moveto
             else:
-                self.file.output(d*x[i], d*y[i], next_op)
+                self.file.output(x[i], y[i], next_op)
                 next_op = Op.lineto
         self.file.output(self.gc.paint())
 
     def draw_point(self, gc, x, y):
         print >>sys.stderr, "draw_point called"
 
-        d = self.dpi_factor
         self.check_gc(gc, gc._rgb)
-        self.file.output(d*x, d*y, d, d,
+        self.file.output(x, y, 1, 1,
                          Op.rectangle, Op.fill_stroke)
 
     def draw_polygon(self, gcEdge, rgbFace, points):
@@ -963,16 +957,14 @@
                 return
 
         self.check_gc(gcEdge, rgbFace)
-        d = self.dpi_factor
-        self.file.output(d*points[0][0], d*points[0][1], Op.moveto)
+        self.file.output(points[0][0], points[0][1], Op.moveto)
         for x,y in points[1:]:
-            self.file.output(d*x, d*y, Op.lineto)
+            self.file.output(x, y, Op.lineto)
         self.file.output(self.gc.close_and_paint())
 
     def draw_rectangle(self, gcEdge, rgbFace, x, y, width, height):
         self.check_gc(gcEdge, rgbFace)
-        d = self.dpi_factor
-        self.file.output(d*x, d*y, d*width, d*height, Op.rectangle)
+        self.file.output(x, y, width, height, Op.rectangle)
         self.file.output(self.gc.paint())
 
     def draw_markers(self, gc, path, rgbFace, x, y, trans):
@@ -980,7 +972,6 @@
         fillp = rgbFace is not None
         marker = self.file.markerObject(path, fillp, self.gc._linewidth)
         x, y = trans.numerix_x_y(asarray(x), asarray(y))
-        x, y = self.dpi_factor * x, self.dpi_factor * y
         nan_at = isnan(x) | isnan(y)
 
         self.file.output(Op.gsave)
@@ -994,19 +985,18 @@
         self.file.output(Op.grestore)
 
     def _setup_textpos(self, x, y, angle, oldx=0, oldy=0, oldangle=0):
-        d = self.dpi_factor
         if angle == oldangle == 0:
-            self.file.output(d*(x-oldx), d*(y-oldy), Op.textpos)
+            self.file.output(x - oldx, y - oldy, Op.textpos)
         else:
             angle = angle / 180.0 * pi
             self.file.output( cos(angle), sin(angle),
                              -sin(angle), cos(angle),
-                              d*x,        d*y,         Op.textmatrix)
+                              x,        y,         Op.textmatrix)
 
     def draw_mathtext(self, gc, x, y, s, prop, angle):
         # TODO: fix positioning and encoding
         fontsize = prop.get_size_in_points()
-        width, height, pswriter = math_parse_s_pdf(s, self.file.dpi, fontsize)
+        width, height, pswriter = math_parse_s_pdf(s, 72, fontsize)
 
         self.check_gc(gc, gc._rgb)
         self.file.output(Op.begin_text)
@@ -1028,7 +1018,7 @@
             #if fontname.endswith('cmsy10.ttf') or \
             #fontname.endswith('cmmi10.ttf') or \
             #fontname.endswith('cmex10.ttf'):
-            #   string = '\0' + chr(glyph)
+            #        string = '\0' + chr(glyph)
 
             string = chr(glyph)
             self.file.output(string, Op.show)
@@ -1036,43 +1026,71 @@
 
     def draw_text(self, gc, x, y, s, prop, angle, ismath=False):
         # TODO: combine consecutive texts into one BT/ET delimited section
-        #       unicode
+        
         if isinstance(s, unicode):
-            s = s.encode('ascii', 'replace')
+            s = s.encode('cp1252', 'replace')
+        
         if ismath: return self.draw_mathtext(gc, x, y, s, prop, angle)
         self.check_gc(gc, gc._rgb)
-
-        font = self._get_font_ttf(prop)
-        font.set_text(s, 0.0)
-        y += font.get_descent() / 64.0
-
+        
+        if rcParams['pdf.use14corefonts']:
+            font = self._get_font_afm(prop)
+            l, b, w, h = font.get_str_bbox(s)
+            fontsize = prop.get_size_in_points()
+            y -= b * fontsize / 1000
+        else:
+            font = self._get_font_ttf(prop)
+            font.set_text(s, 0.0)
+            y += font.get_descent() / 64.0
+        
         self.file.output(Op.begin_text, 
                          self.file.fontName(prop),
                          prop.get_size_in_points(),
                          Op.selectfont)
-
+        
         self._setup_textpos(x, y, angle)
         self.file.output(s, Op.show, Op.end_text)
 
     def get_text_width_height(self, s, prop, ismath):
-
+        if isinstance(s, unicode):
+            s = s.encode('cp1252', 'replace')
+        
         if ismath:
             fontsize = prop.get_size_in_points()
-            w, h, pswriter = math_parse_s_pdf(s, self.file.dpi, fontsize)
+            w, h, pswriter = math_parse_s_pdf(s, 72, fontsize)
+            
+        elif rcParams['pdf.use14corefonts']:
+            font = self._get_font_afm(prop)
+            l, b, w, h = font.get_str_bbox(s)
+            fontsize = prop.get_size_in_points()
+            w *= fontsize / 1000
+            h *= fontsize / 1000
+            
         else:
             font = self._get_font_ttf(prop)
             font.set_text(s, 0.0)
             w, h = font.get_width_height()
-            factor = 1.0/(self.dpi_factor*64.0)
-            w *= factor
-            h *= factor
+            w /= 64.0
+            h /= 64.0
+            
         return w, h
 
+    def _get_font_afm(self, prop):
+        key = hash(prop)
+        font = self.afm_font_cache.get(key)
+        if font is None:
+            filename = fontManager.findfont(prop, fontext='afm')
+            font = AFM(file(filename))
+            self.afm_font_cache[key] = font
+        return font
+
     def _get_font_ttf(self, prop):
-        font = self.fonts.get(prop)
+        key = hash(prop)
+        font = self.truetype_font_cache.get(key)
         if font is None:
-            font = FT2Font(fontManager.findfont(prop))
-            self.fonts[prop] = font
+            filename = fontManager.findfont(prop)
+            font = FT2Font(str(filename))
+            self.truetype_font_cache[key] = font
         font.clear()
         font.set_size(prop.get_size_in_points(), 72.0)
         return font
@@ -1081,16 +1099,12 @@
         return False
 
     def get_canvas_width_height(self):
-        d = self.dpi_factor/72.0
-        return d*self.file.width, d*self.file.height
+        return self.file.width / 72.0, self.file.height / 72.0
 
     def new_gc(self):
         return GraphicsContextPdf(self.file)
 
-    def points_to_pixels(self, points):
-        return points
 
-
 class GraphicsContextPdf(GraphicsContextBase):
 
     def __init__(self, file):
@@ -1205,14 +1219,12 @@
 
     def cliprect_cmd(self, cliprect):
         """Set clip rectangle. Calls self.pop() and self.push()."""
-        d = 72.0/self.file.dpi
-
         cmds = []
         while self._cliprect != cliprect and self.parent is not None:
             cmds.extend(self.pop())
         if self._cliprect != cliprect:
             cmds.extend(self.push() + 
-                        [d*t for t in cliprect] + 
+                        [t for t in cliprect] + 
                         [Op.rectangle, Op.clip, Op.endpath])
         return cmds
 
@@ -1286,9 +1298,6 @@
       figure - A Figure instance
     """
 
-#     def __init__(self, figure):
-#       FigureCanvasBase.__init__(self, figure)
-
     def draw(self):
         pass
 
@@ -1301,12 +1310,8 @@
         hardcopy.
 
         orientation - only currently applies to PostScript printing.
-
-        dpi - used for images
         """
-        if dpi is None:
-            dpi = rcParams['savefig.dpi']
-        self.figure.dpi.set(dpi)
+        self.figure.dpi.set(72) # ignore the dpi kwarg
         self.figure.set_facecolor(facecolor)
         self.figure.set_edgecolor(edgecolor)
         width, height = self.figure.get_size_inches()
@@ -1315,7 +1320,7 @@
         if ext == '': 
             filename += '.pdf'
 
-        file = PdfFile(width, height, dpi, filename)
+        file = PdfFile(width, height, filename)
         renderer = RendererPdf(file)
         self.figure.draw(renderer)
         renderer.finalize()

Property changes on: lib\matplotlib\backends\backend_pdf.py
___________________________________________________________________
Name: svn:eol-style
   + native

Index: lib/matplotlib/font_manager.py
===================================================================
--- lib/matplotlib/font_manager.py	(revision 3020)
+++ lib/matplotlib/font_manager.py	(working copy)
@@ -98,12 +98,12 @@
     return None
 
 def win32InstalledFonts(directory=None, fontext='ttf'):
+    """
+    Search for fonts in the specified font directory, or use the
+    system directories if none given.  A list of TrueType fonts are
+    returned by default with AFM fonts as an option.
+    """
 
-    """Search for fonts in the specified font directory, or use the
-system directories if none given.  A list of TrueType fonts are
-returned by default with AFM fonts as an option.
-"""
-
     import _winreg
     if directory is None:
         directory = win32FontDirectory()
@@ -180,12 +180,11 @@
     return fontpaths
 
 def findSystemFonts(fontpaths=None, fontext='ttf'):
-
-    """Search for fonts in the specified font paths, or use the system
-paths if none given.  A list of TrueType fonts are returned by default
-with AFM fonts as an option.
-"""
-
+    """
+    Search for fonts in the specified font paths, or use the system
+    paths if none given.  A list of TrueType fonts are returned by default
+    with AFM fonts as an option.
+    """
     fontfiles = {}
 
     if fontpaths is None:
@@ -218,10 +217,10 @@
     return [fname for fname in fontfiles.keys() if os.path.exists(fname)]
 
 def weight_as_number(weight):
-    """Return the weight property as a numeric value.  String values
-are converted to their corresponding numeric value.
-"""
-
+    """
+    Return the weight property as a numeric value.  String values
+    are converted to their corresponding numeric value.
+    """
     if isinstance(weight, str):
         try:
             weight = weight_dict[weight.lower()]
@@ -235,9 +234,10 @@
 
 
 class FontKey(object):
-    """A class for storing Font properties.  It is used when populating
-the font dictionary.
-"""
+    """
+    A class for storing Font properties.  It is used when populating
+    the font dictionary.
+    """
 
     def __init__(self,
                  name   ='',
@@ -259,7 +259,8 @@
 
 
 def ttfFontProperty(font):
-    """A function for populating the FontKey by extracting information
+    """
+    A function for populating the FontKey by extracting information
     from the TrueType font file.
     """
     name = font.family_name
@@ -351,9 +352,10 @@
 
 
 def afmFontProperty(font):
-    """A function for populating the FontKey by extracting information
-from the AFM font file.
-"""
+    """
+    A function for populating the FontKey by extracting information
+    from the AFM font file.
+    """
 
     name = font.get_familyname()
 
@@ -408,11 +410,11 @@
 
 
 def add_filename(fontdict, prop, fname):
-    """A function to add a font file name to the font dictionary using
-the FontKey properties.  If a font property has no dictionary, then
-create it.
-"""
-
+    """
+    A function to add a font file name to the font dictionary using
+    the FontKey properties.  If a font property has no dictionary, then
+    create it.
+    """
     try:
         size = str(float(prop.size))
     except ValueError:
@@ -428,10 +430,11 @@
 
 
 def createFontDict(fontfiles, fontext='ttf'):
-    """A function to create a dictionary of font file paths.  The
-default is to create a dictionary for TrueType fonts.  An AFM font
-dictionary can optionally be created.
-"""
+    """
+    A function to create a dictionary of font file paths.  The
+    default is to create a dictionary for TrueType fonts.  An AFM font
+    dictionary can optionally be created.
+    """
 
     fontdict = {}
     #  Add fonts from list of known font files.
@@ -483,10 +486,11 @@
     return fontdict
 
 def setWeights(font):
-    """A function to populate missing values in a font weight
-dictionary.  This proceedure is necessary since the font finding
-algorithm always matches on the weight property.
-"""
+    """
+    A function to populate missing values in a font weight
+    dictionary.  This proceedure is necessary since the font finding
+    algorithm always matches on the weight property.
+    """
 
     # !!!!  Not completely correct
     temp = font.copy()
@@ -530,60 +534,60 @@
 
 
 class FontProperties:
-    """A class for storing and manipulating font properties.
+    """
+    A class for storing and manipulating font properties.
 
-The font properties are those described in the W3C Cascading Style
-Sheet, Level 1 (CSS1; http://www.w3.org/TR/1998/REC-CSS2-19980512/)
-font specification.  The six properties are:
+    The font properties are those described in the W3C Cascading Style
+    Sheet, Level 1 (CSS1; http://www.w3.org/TR/1998/REC-CSS2-19980512/)
+    font specification.  The six properties are:
 
-  family  - A list of font names in decreasing order of priority.
-            The last item is the default font name and is given the
-            name of the font family, either serif, sans-serif,
-            cursive, fantasy, and monospace.
-  style   - Either normal, italic or oblique.
-  variant - Either normal or small-caps.
-  stretch - Either an absolute value of ultra-condensed, extra-
-            condensed, condensed, semi-condensed, normal, semi-
-            expanded, expanded, extra-expanded or ultra-expanded;
-            or a relative value of narrower or wider.
-            This property is currently not implemented and is set to
-            normal.
-  weight  - A numeric value in the range 100, 200, 300, ..., 900.
-  size    - Either an absolute value of xx-small, x-small, small,
-            medium, large, x-large, xx-large; or a relative value
-            of smaller or larger; or an absolute font size, e.g. 12;
-            or scalable.
+      family  - A list of font names in decreasing order of priority.
+                The last item is the default font name and is given the
+                name of the font family, either serif, sans-serif,
+                cursive, fantasy, and monospace.
+      style   - Either normal, italic or oblique.
+      variant - Either normal or small-caps.
+      stretch - Either an absolute value of ultra-condensed, extra-
+                condensed, condensed, semi-condensed, normal, semi-
+                expanded, expanded, extra-expanded or ultra-expanded;
+                or a relative value of narrower or wider.
+                This property is currently not implemented and is set to
+                normal.
+      weight  - A numeric value in the range 100, 200, 300, ..., 900.
+      size    - Either an absolute value of xx-small, x-small, small,
+                medium, large, x-large, xx-large; or a relative value
+                of smaller or larger; or an absolute font size, e.g. 12;
+                or scalable.
 
-The default font property for TrueType fonts is: sans-serif, normal,
-normal, normal, 400, scalable.
+    The default font property for TrueType fonts is: sans-serif, normal,
+    normal, normal, 400, scalable.
 
-The preferred usage of font sizes is to use the absolute values, e.g.
-large, instead of absolute font sizes, e.g. 12.  This approach allows
-all text sizes to be made larger or smaller based on the font manager's
-default font size, i.e. by using the set_default_size() method of the
-font manager.
+    The preferred usage of font sizes is to use the absolute values, e.g.
+    large, instead of absolute font sizes, e.g. 12.  This approach allows
+    all text sizes to be made larger or smaller based on the font manager's
+    default font size, i.e. by using the set_default_size() method of the
+    font manager.
 
+    Examples:
 
-Examples:
+      #  Load default font properties
+      >>> p = FontProperties()
+      >>> p.get_family()
+      ['Bitstream Vera Sans', 'Lucida Grande', 'Verdana', 'Geneva', 'Lucida', 'Arial', 'Helvetica', 'sans-serif']
 
-  #  Load default font properties
-  >>> p = FontProperties()
-  >>> p.get_family()
-  ['Bitstream Vera Sans', 'Lucida Grande', 'Verdana', 'Geneva', 'Lucida', 'Arial', 'Helvetica', 'sans-serif']
+      #  Change font family to 'fantasy'
+      >>> p.set_family('fantasy')
+      >>> p.get_family()
+      ['Comic Sans MS', 'Chicago', 'Charcoal', 'Impact', 'Western', 'fantasy']
 
-  #  Change font family to 'fantasy'
-  >>> p.set_family('fantasy')
-  >>> p.get_family()
-  ['Comic Sans MS', 'Chicago', 'Charcoal', 'Impact', 'Western', 'fantasy']
+      #  Make these fonts highest priority in font family
+      >>> p.set_name(['foo', 'fantasy', 'bar', 'baz'])
+      Font name 'fantasy' is a font family. It is being deleted from the list.
+      >>> p.get_family()
+      ['foo', 'bar', 'baz', 'Comic Sans MS', 'Chicago', 'Charcoal', 'Impact', 'Western', 'fantasy']
 
-  #  Make these fonts highest priority in font family
-  >>> p.set_name(['foo', 'fantasy', 'bar', 'baz'])
-  Font name 'fantasy' is a font family. It is being deleted from the list.
-  >>> p.get_family()
-  ['foo', 'bar', 'baz', 'Comic Sans MS', 'Chicago', 'Charcoal', 'Impact', 'Western', 'fantasy']
+    """
 
-"""
-
     def __init__(self,
                  family = None,
                  style  = None,
@@ -629,42 +633,40 @@
         return self.__family
 
     def get_name(self):
-        """Return the name of the font that best matches the font
-properties.
-"""
+        """Return the name of the font that best matches the font properties."""
         return ft2font.FT2Font(str(fontManager.findfont(self))).family_name
 
     def get_style(self):
-        """Return the font style.  Values are: normal, italic or oblique.
-        """
+        """Return the font style.  Values are: normal, italic or oblique."""
         return self.__style
 
     def get_variant(self):
-        """Return the font variant.  Values are: normal or small-caps.
-        """
+        """Return the font variant.  Values are: normal or small-caps."""
         return self.__variant
 
     def get_weight(self):
-        """Return the font weight.  See the FontProperties class for a
-a list of possible values.
-"""
+        """
+        Return the font weight.  See the FontProperties class for a
+        a list of possible values.
+        """
         return self.__weight
 
     def get_stretch(self):
-        """Return the font stretch or width.  Options are: normal,
-narrow, condensed, or wide.
-"""
+        """
+        Return the font stretch or width.  Options are: normal,
+        narrow, condensed, or wide.
+        """
         return self.__stretch
 
     def get_size(self):
-        """Return the font size.
-        """
+        """Return the font size."""
         return self.__size
 
     def set_family(self, family):
-        """Change the font family.  Options are: serif, sans-serif, cursive,
-fantasy, or monospace."""
-
+        """
+        Change the font family.  Options are: serif, sans-serif, cursive,
+        fantasy, or monospace.
+        """
         try:
             self.__family = rcParams['font.'+family]
             if isinstance(self.__family, str):
@@ -673,13 +675,13 @@
             raise KeyError, '%s - use serif, sans-serif, cursive, fantasy, or monospace.' % family
 
     def set_name(self, names):
+        """
+        Add one or more font names to the font family list.  If the
+    font name is already in the list, then the font is given a higher
+    priority in the font family list.  To change the font family, use the
+    set_family() method.
+    """
 
-        """Add one or more font names to the font family list.  If the
-font name is already in the list, then the font is given a higher
-priority in the font family list.  To change the font family, use the
-set_family() method.
-"""
-
         msg = "Font name '%s' is a font family. It is being deleted from the list."
         font_family = ['serif', 'sans-serif', 'cursive', 'fantasy',
                        'monospace']
@@ -702,36 +704,36 @@
         self.__family = names + self.__family
 
     def set_style(self, style):
-        """Set the font style.  Values are: normal, italic or oblique.
-        """
+        """Set the font style.  Values are: normal, italic or oblique."""
         self.__style = style
 
     def set_variant(self, variant):
-        """Set the font variant.  Values are: normal or small-caps.
-        """
+        """Set the font variant.  Values are: normal or small-caps."""
         self.__variant = variant
 
     def set_weight(self, weight):
-        """Set the font weight.  See the FontProperties class for a
-a list of possible values.
-"""
+        """
+        Set the font weight.  See the FontProperties class for a
+        a list of possible values.
+        """
         self.__weight = weight
 
     def set_stretch(self, stretch):
-        """Set the font stretch or width.  Options are: normal, narrow,
-condensed, or wide.
-"""
+        """
+        Set the font stretch or width.  Options are: normal, narrow,
+        condensed, or wide.
+        """
         self.__stretch = stretch
 
     def set_size(self, size):
-        """Set the font size.
-        """
+        """Set the font size."""
         self.__size = size
 
     def get_size_in_points(self, parent_size=None):
-        """Return the size property as a numeric value.  String values
-are converted to their corresponding numeric value.
-"""
+        """
+        Return the size property as a numeric value.  String values
+        are converted to their corresponding numeric value.
+        """
         if self.__size in font_scalings.keys():
             size = fontManager.get_default_size()*font_scalings[self.__size]
         elif self.__size == 'larger':
@@ -764,21 +766,21 @@
     return fnames
 
 class FontManager:
+    """
+    On import, the FontManager creates a dictionary of TrueType
+    fonts based on the font properties: name, style, variant, weight,
+    stretch, and size.  The findfont() method searches this dictionary
+    for a font file name that exactly matches the font properties of the
+    specified text.  If none is found, a default font is returned.  By
+    updating the dictionary with the properties of the found font, the
+    font dictionary can act like a font cache.
+    """
 
-    """On import, the FontManager creates a dictionary of TrueType
-fonts based on the font properties: name, style, variant, weight,
-stretch, and size.  The findfont() method searches this dictionary
-for a font file name that exactly matches the font properties of the
-specified text.  If none is found, a default font is returned.  By
-updating the dictionary with the properties of the found font, the
-font dictionary can act like a font cache.
-"""
-
     def __init__(self, size=None, weight='normal'):
         if not size : size = rcParams['font.size']
         self.__default_size = size
         self.__default_weight = weight
-
+        
         paths = [os.path.join(rcParams['datapath'],'fonts','ttf'),
                  os.path.join(rcParams['datapath'],'fonts','afm')]
 
@@ -812,22 +814,17 @@
 """Saving TTF font cache for non-PS backends to %s.
 Delete this file to have matplotlib rebuild the cache."""
 
-
-
         oldcache = os.path.join(get_home(), 'ttffont.cache')
         ttfcache = os.path.join(get_configdir(), 'ttffont.cache')
         if os.path.exists(oldcache):
             print >> sys.stderr, 'Moving old ttfcache location "%s" to new location "%s"'%(oldcache, ttfcache)
             shutil.move(oldcache, ttfcache)
 
-
-
         try:
             import cPickle as pickle
         except ImportError:
             import pickle
 
-
         def rebuild():
             self.ttfdict = createFontDict(self.ttffiles)
             pickle.dump(self.ttfdict, file(ttfcache, 'w'))
@@ -845,14 +842,11 @@
                     break
             verbose.report('loaded ttfcache file %s'%ttfcache)
 
-
-
         #self.ttfdict = createFontDict(self.ttffiles)
 
         #  Load AFM fonts for PostScript
         #  Only load file names at this stage, the font dictionary will be
         #  created when needed.
-
         self.afmfiles = findSystemFonts(paths, fontext='afm') + \
                         findSystemFonts(fontext='afm')
         self.afmdict = {}
@@ -874,30 +868,27 @@
         self.__default_size = size
 
     def update_fonts(self, filenames):
-        """Update the font dictionary with new font files.
-Currently not implemented."""
+        """
+        Update the font dictionary with new font files.
+        Currently not implemented.
+        """
         #  !!!!  Needs implementing
         raise NotImplementedError
 
-
     def findfont(self, prop, fontext='ttf'):
+        """
+        Search the font dictionary for a font that exactly or closely
+        matches the specified font properties.  See the FontProperties class
+        for a description.
 
-        """Search the font dictionary for a font that exactly or closely
-matches the specified font properties.  See the FontProperties class
-for a description.
-
-The properties are searched in the following order: name, style,
-variant, weight, stretch, and size.  The font weight always matches
-returning the closest weight, and the font size always matches for
-scalable fonts.  An oblique style font will be used inplace of a
-missing italic style font if present.  See the W3C Cascading Style
-Sheet, Level 1 (CSS1; http://www.w3.org/TR/1998/REC-CSS2-19980512/)
-documentation for a description of the font finding algorithm.
-"""
-        cache_message = \
-"""Saving AFM font cache for PS backend to %s.
-Delete this file to have matplotlib rebuild the cache."""
-
+        The properties are searched in the following order: name, style,
+        variant, weight, stretch, and size.  The font weight always matches
+        returning the closest weight, and the font size always matches for
+        scalable fonts.  An oblique style font will be used inplace of a
+        missing italic style font if present.  See the W3C Cascading Style
+        Sheet, Level 1 (CSS1; http://www.w3.org/TR/1998/REC-CSS2-19980512/)
+        documentation for a description of the font finding algorithm.
+        """
         debug = False
         if prop.fname is not None:
             fname = prop.fname
@@ -906,17 +897,7 @@
 
         if fontext == 'afm':
             if len(self.afmdict) == 0:
-                afmcache = os.path.join(get_configdir(), '.afmfont.cache')
-                try:
-                    import cPickle as pickle
-                except ImportError:
-                    import pickle
-                try:
-                    self.afmdict = pickle.load(file(afmcache))
-                except:
-                    self.afmdict = createFontDict(self.afmfiles, fontext='afm')
-                    pickle.dump(self.afmdict, file(afmcache, 'w'))
-                    verbose.report(cache_message % afmcache)
+                self.afmdict = self._get_afm_font_dict()
             fontdict = self.afmdict
         else:
             fontdict = self.ttfdict
@@ -928,7 +909,6 @@
         stretch = prop.get_stretch()
         size    = str(prop.get_size_in_points())
 
-
         try:
             fname = fontdict[name][style][variant][weight][stretch][size]
             verbose.report('\tfindfont cached %(name)s, %(style)s, %(variant)s, %(weight)s, %(stretch)s, %(size)s'%locals(), 'debug')
@@ -991,4 +971,42 @@
 
         return self.defaultFont
 
+    def _get_afm_font_dict(self):
+        try:
+            import cPickle as pickle
+        except ImportError:
+            import pickle
+        
+        cache_message = "Saving AFM font cache for PS and PDF backends to %s.\n" \
+                        "Delete this file to have matplotlib rebuild the cache."
+        
+        if rcParams['pdf.use14corefonts']:
+            # Load only the 14 PDF core fonts. These fonts do not need to be 
+            # embedded; every PDF viewing application is required to have them:
+            # Helvetica, Helvetica-Bold, Helvetica-Oblique, Helvetica-BoldOblique, 
+            # Courier, Courier-Bold, Courier-Oblique, Courier-BoldOblique, 
+            # Times-Roman, Times-Bold, Times-Italic, Times-BoldItalic, Symbol, 
+            # ZapfDingbats.
+            afmcache = os.path.join(get_configdir(), 'pdfcorefont.cache')
+            try:
+                fontdict = pickle.load(file(afmcache))
+            except:
+                afmpath = os.path.join(rcParams['datapath'],'fonts','pdfcorefonts')
+                afmfiles = findSystemFonts(afmpath, fontext='afm')
+                fontdict = createFontDict(afmfiles, fontext='afm')
+                pickle.dump(fontdict, file(afmcache, 'w'))
+                verbose.report(cache_message % afmcache)
+        else:
+            # Load all available AFM fonts
+            afmcache = os.path.join(get_configdir(), '.afmfont.cache')
+            try:
+                fontdict = pickle.load(file(afmcache))
+            except:
+                fontdict = createFontDict(self.afmfiles, fontext='afm')
+                pickle.dump(fontdict, file(afmcache, 'w'))
+                verbose.report(cache_message % afmcache)
+        
+        return fontdict
+
+
 fontManager = FontManager()
Index: setup.py
===================================================================
--- setup.py	(revision 3020)
+++ setup.py	(working copy)
@@ -77,6 +77,8 @@
 
 # Specify all the required mpl data
 package_data = {'matplotlib':['mpl-data/fonts/afm/*.afm',
+                              'mpl-data/fonts/pdfcorefonts/*.afm',
+                              'mpl-data/fonts/pdfcorefonts/*.txt',
                               'mpl-data/fonts/ttf/*.ttf',
                               'mpl-data/images/*.xpm',
                               'mpl-data/images/*.svg',
