[cairo-commit] cairo/src cairo-atsui.h, 1.1, 1.2 cairo-ft-private.h, NONE, 1.1 cairo-ft.h, 1.1, 1.2 cairo-glitz.h, 1.1, 1.2 cairo-pdf.h, 1.1, 1.2 cairo-png.h, 1.1, 1.2 cairo-ps.h, 1.1, 1.2 cairo-quartz.h, 1.2, 1.3 cairo-xcb.h, 1.1, 1.2 cairo-xlib.h, 1.6, 1.7 cairo.h, 1.67, 1.68 cairo_cache.c, 1.6, 1.7 cairo_font.c, 1.30, 1.31 cairo_ft_font.c, 1.32, 1.33 cairo_gstate.c, 1.72, 1.73 cairo_pdf_surface.c, 1.7, 1.8 cairo_quartz_surface.c, 1.2, 1.3 cairo_xlib_surface.c, 1.37, 1.38 cairoint.h, 1.85, 1.86

Owen Taylor commit at pdx.freedesktop.org
Fri Jan 21 14:33:50 PST 2005


Committed by: otaylor

Update of /cvs/cairo/cairo/src
In directory gabe:/tmp/cvs-serv3974/src

Modified Files:
	cairo-atsui.h cairo-ft.h cairo-glitz.h cairo-pdf.h cairo-png.h 
	cairo-ps.h cairo-quartz.h cairo-xcb.h cairo-xlib.h cairo.h 
	cairo_cache.c cairo_font.c cairo_ft_font.c cairo_gstate.c 
	cairo_pdf_surface.c cairo_quartz_surface.c 
	cairo_xlib_surface.c cairoint.h 
Added Files:
	cairo-ft-private.h 
Log Message:
2005-01-16  Owen Taylor  <otaylor at redhat.com>

        Change cairo_font_t to refer to a font scaled to a particular
        output device resolution.

        * src/cairoint.h src/cairo_font.c src/cairo_ft_font.c
        src/cairo_xlib_surface.c src/cairo_pdf_surface.c src/cairo_gstate.c
        src/cairo.c: Switch many internal methods from handling
        cairo_unscaled_font_t and cairo_font_scale_t pairs to handling
        cairo_font_t.

        * src/cairo-ft-private.h src/cairo_ft_fontc: Add some internal
        interfaces for use by the FreeType backend.

        * src/cairo_gstate.c: Clear the gstate's current font when
        the transform or target surface changes.

        * src/cairo.h src/cairo_ft_font.c: Rename cairo_ft_font_pattern
        to cairo_ft_font_get_pattern().

        * src/cairo.h src/cairo_ft_font.c: Make cairo_ft_font_create()
        and cairo_ft_font_create_for_ft_face() take a font scale;
        make the latter take load_flags for FT_Load_Glyph() as well.
        Change cairo_ft_font_face() to Xft-style cairo_ft_font_lock_face,
        cairo_ft_font_unlock_face.

        * src/cairo_font.c: Remove the name/slant/weight=>unscaled font
        cache, it didn't work with the new cairo_font_t setup. If it turns
        out to be needed, it can be added back in some other form.

        * src/cairoint.h src/cairo_font.c: Add a 'flags' field
        to cairo_glyph_cache_key_t, we use it for load flags with
        freetype backend.

        * src/cairo_ft_font.c: Switch the caching to be from
        resolved fontconfig pattern => file; keep only a fixed number
        of FT_Face objects open at once, similar to FreeType.

        * src/cairo_font.c (cairo_font_glyph_extents) src/cairo_gstate.c
        src/cairoint.h: Add public cairo_font_glyph_extents, use it
        to implement _cairo_gstate_glyph_extents().

        * src/cairo_xlib_surface.c (_glyphset_cache_entry_reference):
        Add refcounting for glyph cache elements; there was an
        bug where elements got ejected from the cache and freed before
        they could be used.

        * src/cairoint.h src/cairo_cache.c (_cairo_cache_random_entry())
        New function to return a random entry in the cache matching a predicate;
        reuse the internals for the previous _random_live_entry().

        * src/cairoint.h src/cairo_cache.c (_cairo_cache_lookup()): Add an
        optional created_entry return value.

        * src/cairo_ft_font.c src/cairo_xlib_surface.c: Adapt to
        _cairo_cache_lookup() change.

        * src/cairo_cache.c (_cairo_cache_lookup()): Support max_memory == 0
        to indicate an unbounded cache.

        * src/cairoint.h src/cairo_cache.c (_cairo_cache_remove()): Add a
        function to manually remove entries from the cache.

        * doc/reference: Update for changes, document cairo_matrix_t,
        cairo_glyph_t, etc.

        * src/cairo.h src/cairo-atsui.h src/cairo-ft.h src/cairo-glitz.h
        src/cairo-pdf.h src/cairo-png.h src/cairo-ps.h src/cairo-quartz.h
        src/cairo-xcb.h src/cairo-xlib.h: Add CAIRO_BEGIN/END_DECLS for
        extern "C", use it on all public headers. Move header guards
        outermost.

        * src/cairo_quartz_surface.c: Fix encoding.


Index: cairo-atsui.h
===================================================================
RCS file: /cvs/cairo/cairo/src/cairo-atsui.h,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -d -r1.1 -r1.2
--- cairo-atsui.h	21 Jan 2005 04:36:25 -0000	1.1
+++ cairo-atsui.h	21 Jan 2005 22:33:48 -0000	1.2
@@ -33,18 +33,23 @@
  *	Calum Robinson <calumr at mac.com>
  */
 
-#include <cairo.h>
-
 #ifndef CAIRO_ATSUI_H
 #define CAIRO_ATSUI_H
+
+#include <cairo.h>
+
 #ifdef  CAIRO_HAS_ATSUI_FONT
 
 /* ATSUI platform-specific font interface */
 
 #include <Carbon/Carbon.h>
 
+CAIRO_BEGIN_DECLS
+
 cairo_font_t *
 cairo_atsui_font_create(ATSUStyle style);
 
+CAIRO_END_DECLS
+
 #endif /* CAIRO_HAS_ATSUI_FONT */
 #endif /* CAIRO_ATSUI_H */

--- NEW FILE: cairo-ft-private.h ---
(This appears to be a binary file; contents omitted.)

Index: cairo-ft.h
===================================================================
RCS file: /cvs/cairo/cairo/src/cairo-ft.h,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -d -r1.1 -r1.2
--- cairo-ft.h	20 Jan 2005 16:28:54 -0000	1.1
+++ cairo-ft.h	21 Jan 2005 22:33:48 -0000	1.2
@@ -1,6 +1,6 @@
 /* cairo - a vector graphics library with display and print output
  *
- * Copyright © 2002 University of Southern California
+ * Copyright © 2005 Red Hat, Inc
  *
  * This library is free software; you can redistribute it and/or
  * modify it either under the terms of the GNU Lesser General Public
@@ -27,17 +27,18 @@
  *
  * The Original Code is the cairo graphics library.
  *
- * The Initial Developer of the Original Code is University of Southern
- * California.
+ * The Initial Developer of the Original Code is Red Hat, Inc.
  *
  * Contributor(s):
- *	Carl D. Worth <cworth at isi.edu>
+ *      Graydon Hoare <graydon at redhat.com>
+ *	Owen Taylor <otaylor at redhat.com>
  */
 
-#include <cairo.h>
-
 #ifndef CAIRO_FT_H
 #define CAIRO_FT_H
+
+#include <cairo.h>
+
 #ifdef  CAIRO_HAS_FT_FONT
 
 /* Fontconfig/Freetype platform-specific font interface */
@@ -46,17 +47,27 @@
 #include <ft2build.h>
 #include FT_FREETYPE_H
 
+CAIRO_BEGIN_DECLS
+
 cairo_font_t *
-cairo_ft_font_create (FT_Library ft_library, FcPattern *pattern);
+cairo_ft_font_create (FcPattern      *pattern,
+		      cairo_matrix_t *scale);
 
 cairo_font_t *
-cairo_ft_font_create_for_ft_face (FT_Face face);
+cairo_ft_font_create_for_ft_face (FT_Face         face,
+				  int             load_flags,
+				  cairo_matrix_t *scale);
 
 FT_Face
-cairo_ft_font_face (cairo_font_t *ft_font);
+cairo_ft_font_lock_face (cairo_font_t *ft_font);
+
+void
+cairo_ft_font_unlock_face (cairo_font_t *ft_font);
 
 FcPattern *
-cairo_ft_font_pattern (cairo_font_t  *ft_font);
+cairo_ft_font_get_pattern (cairo_font_t  *ft_font);
+
+CAIRO_END_DECLS
 
 #endif /* CAIRO_HAS_FT_FONT */
 #endif /* CAIRO_FT_H */

Index: cairo-glitz.h
===================================================================
RCS file: /cvs/cairo/cairo/src/cairo-glitz.h,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -d -r1.1 -r1.2
--- cairo-glitz.h	20 Jan 2005 16:28:54 -0000	1.1
+++ cairo-glitz.h	21 Jan 2005 22:33:48 -0000	1.2
@@ -34,14 +34,17 @@
  *	Carl D. Worth <cworth at isi.edu>
  */
 
-#include <cairo.h>
-
 #ifndef CAIRO_GLITZ_H
 #define CAIRO_GLITZ_H
+
+#include <cairo.h>
+
 #ifdef  CAIRO_HAS_GLITZ_SURFACE
 
 #include <glitz.h>
 
+CAIRO_BEGIN_DECLS
+
 void
 cairo_set_target_glitz (cairo_t *cr,
 			glitz_surface_t *surface);
@@ -49,5 +52,7 @@
 cairo_surface_t *
 cairo_glitz_surface_create (glitz_surface_t *surface);
 
+CAIRO_END_DECLS
+
 #endif /* CAIRO_HAS_GLITZ_SURFACE */
 #endif /* CAIRO_GLITZ_H */

Index: cairo-pdf.h
===================================================================
RCS file: /cvs/cairo/cairo/src/cairo-pdf.h,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -d -r1.1 -r1.2
--- cairo-pdf.h	20 Jan 2005 16:28:54 -0000	1.1
+++ cairo-pdf.h	21 Jan 2005 22:33:48 -0000	1.2
@@ -34,14 +34,17 @@
  *	Carl D. Worth <cworth at isi.edu>
  */
 
-#include <cairo.h>
-
 #ifndef CAIRO_PDF_H
 #define CAIRO_PDF_H
+
+#include <cairo.h>
+
 #ifdef  CAIRO_HAS_PDF_SURFACE
 
 #include <stdio.h>
 
+CAIRO_BEGIN_DECLS
+
 void
 cairo_set_target_pdf (cairo_t	*cr,
 		      FILE	*file,
@@ -58,5 +61,7 @@
 			  double	x_pixels_per_inch,
 			  double	y_pixels_per_inch);
 
+CAIRO_END_DECLS
+
 #endif /* CAIRO_HAS_PDF_SURFACE */
 #endif /* CAIRO_PDF_H */

Index: cairo-png.h
===================================================================
RCS file: /cvs/cairo/cairo/src/cairo-png.h,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -d -r1.1 -r1.2
--- cairo-png.h	20 Jan 2005 16:28:54 -0000	1.1
+++ cairo-png.h	21 Jan 2005 22:33:48 -0000	1.2
@@ -34,14 +34,17 @@
  *	Carl D. Worth <cworth at isi.edu>
  */
 
-#include <cairo.h>
-
 #ifndef CAIRO_PNG_H
 #define CAIRO_PNG_H
-#ifdef  CAIRO_HAS_PNG_SURFACE
+
+#include <cairo.h>
+
+#ifdef CAIRO_HAS_PNG_SURFACE
 
 #include <stdio.h>
 
+CAIRO_BEGIN_DECLS
+
 void
 cairo_set_target_png (cairo_t	*cr,
 		      FILE	*file,
@@ -55,5 +58,7 @@
 			  int			width,
 			  int			height);
 
+CAIRO_END_DECLS
+
 #endif /* CAIRO_HAS_PNG_SURFACE */
 #endif /* CAIRO_PNG_H */

Index: cairo-ps.h
===================================================================
RCS file: /cvs/cairo/cairo/src/cairo-ps.h,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -d -r1.1 -r1.2
--- cairo-ps.h	20 Jan 2005 16:28:54 -0000	1.1
+++ cairo-ps.h	21 Jan 2005 22:33:48 -0000	1.2
@@ -34,14 +34,17 @@
  *	Carl D. Worth <cworth at isi.edu>
  */
 
-#include <cairo.h>
-
 #ifndef CAIRO_PS_H
 #define CAIRO_PS_H
+
+#include <cairo.h>
+
 #ifdef  CAIRO_HAS_PS_SURFACE
 
 #include <stdio.h>
 
+CAIRO_BEGIN_DECLS
+
 void
 cairo_set_target_ps (cairo_t	*cr,
 		     FILE	*file,
@@ -59,5 +62,7 @@
 			 double	x_pixels_per_inch,
 			 double	y_pixels_per_inch);
 
+CAIRO_END_DECLS
+
 #endif /* CAIRO_HAS_PS_SURFACE */
 #endif /* CAIRO_PS_H */

Index: cairo-quartz.h
===================================================================
RCS file: /cvs/cairo/cairo/src/cairo-quartz.h,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -d -r1.2 -r1.3
--- cairo-quartz.h	21 Jan 2005 04:36:25 -0000	1.2
+++ cairo-quartz.h	21 Jan 2005 22:33:48 -0000	1.3
@@ -34,14 +34,17 @@
  *	Carl D. Worth <cworth at isi.edu>
  */
 
-#include <cairo.h>
-
 #ifndef CAIRO_QUARTZ_H
 #define CAIRO_QUARTZ_H
+
+#include <cairo.h>
+
 #ifdef  CAIRO_HAS_QUARTZ_SURFACE
 
 #include <Carbon/Carbon.h>
 
+CAIRO_BEGIN_DECLS
+
 void
 cairo_set_target_quartz_context(   	cairo_t		*cr,
 					CGContextRef    context,
@@ -53,6 +56,8 @@
 				int		width,
 				int		height);
 
+CAIRO_END_DECLS
+
 #endif /* CAIRO_HAS_QUARTZ_SURFACE */
 #endif /* CAIRO_QUARTZ_H */
 

Index: cairo-xcb.h
===================================================================
RCS file: /cvs/cairo/cairo/src/cairo-xcb.h,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -d -r1.1 -r1.2
--- cairo-xcb.h	20 Jan 2005 16:28:54 -0000	1.1
+++ cairo-xcb.h	21 Jan 2005 22:33:48 -0000	1.2
@@ -34,15 +34,18 @@
  *	Carl D. Worth <cworth at isi.edu>
  */
 
-#include <cairo.h>
-
 #ifndef CAIRO_XCB_H
 #define CAIRO_XCB_H
+
+#include <cairo.h>
+
 #ifdef  CAIRO_HAS_XCB_SURFACE
 
 #include <X11/XCB/xcb.h>
 #include <X11/XCB/render.h>
 
+CAIRO_BEGIN_DECLS
+
 void
 cairo_set_target_xcb (cairo_t		*cr,
 		      XCBConnection	*dpy,
@@ -50,5 +53,7 @@
 		      XCBVISUALTYPE	*visual,
 		      cairo_format_t	format);
 
+CAIRO_END_DECLS
+
 #endif /* CAIRO_HAS_XCB_SURFACE */
 #endif /* CAIRO_XCB_H */

Index: cairo-xlib.h
===================================================================
RCS file: /cvs/cairo/cairo/src/cairo-xlib.h,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -d -r1.6 -r1.7
--- cairo-xlib.h	20 Jan 2005 16:28:54 -0000	1.6
+++ cairo-xlib.h	21 Jan 2005 22:33:48 -0000	1.7
@@ -34,14 +34,17 @@
  *	Carl D. Worth <cworth at isi.edu>
  */
 
-#include <cairo.h>
-
 #ifndef CAIRO_XLIB_H
 #define CAIRO_XLIB_H
+
+#include <cairo.h>
+
 #ifdef  CAIRO_HAS_XLIB_SURFACE
 
 #include <X11/extensions/Xrender.h>
 
+CAIRO_BEGIN_DECLS
+
 /* XXX: This shold be renamed to cairo_set_target_xlib to match the
  * other backends */
 void
@@ -66,6 +69,8 @@
 cairo_xlib_surface_set_size (cairo_surface_t *surface, int width, int height);
 */
 
+CAIRO_END_DECLS
+
 #endif /* CAIRO_HAS_XLIB_SURFACE */
 #endif /* CAIRO_XLIB_H */
 

Index: cairo.h
===================================================================
RCS file: /cvs/cairo/cairo/src/cairo.h,v
retrieving revision 1.67
retrieving revision 1.68
diff -u -d -r1.67 -r1.68
--- cairo.h	20 Jan 2005 16:28:54 -0000	1.67
+++ cairo.h	21 Jan 2005 22:33:48 -0000	1.68
@@ -37,18 +37,24 @@
 #ifndef CAIRO_H
 #define CAIRO_H
 
+#ifdef  __cplusplus
+# define CAIRO_BEGIN_DECLS  extern "C" {
+# define CAIRO_END_DECLS    }
+#else
+# define CAIRO_BEGIN_DECLS
+# define CAIRO_END_DECLS
+#endif
+
 #include <cairo-features.h>
 #include <pixman.h>
 
+CAIRO_BEGIN_DECLS
+
 typedef struct _cairo cairo_t;
 typedef struct _cairo_surface cairo_surface_t;
 typedef struct _cairo_matrix cairo_matrix_t;
 typedef struct _cairo_pattern cairo_pattern_t;
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 /* Functions for manipulating state objects */
 cairo_t *
 cairo_create (void);
@@ -423,12 +429,11 @@
 cairo_font_destroy (cairo_font_t *font);
 
 void
-cairo_font_set_transform (cairo_font_t *font, 
-			  cairo_matrix_t *matrix);
-
-void
-cairo_font_current_transform (cairo_font_t *font, 
-			      cairo_matrix_t *matrix);
+cairo_font_glyph_extents (cairo_font_t          *font,
+			  cairo_matrix_t        *font_matrix,
+			  cairo_glyph_t         *glyphs, 
+			  int                   num_glyphs,
+			  cairo_text_extents_t  *extents);
 
 /* Image functions */
 
@@ -724,8 +729,6 @@
 #define cairo_get_status_string		cairo_get_status_string_DEPRECATED_BY_cairo_status_string
 #endif
 
-#ifdef __cplusplus
-}
-#endif
+CAIRO_END_DECLS
 
 #endif /* CAIRO_H */

Index: cairo_cache.c
===================================================================
RCS file: /cvs/cairo/cairo/src/cairo_cache.c,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -d -r1.6 -r1.7
--- cairo_cache.c	11 Jan 2005 18:03:01 -0000	1.6
+++ cairo_cache.c	21 Jan 2005 22:33:48 -0000	1.7
@@ -94,9 +94,9 @@
  * a mostly-dead table.
  *
  * Generally you do not need to worry about freeing cache entries; the
- * cache will expire entries randomly as it experiences memory pressure. 
- * There is currently no explicit entry-removing call, though one can be 
- * added easily.
+ * cache will expire entries randomly as it experiences memory pressure.
+ * If max_memory is set, entries are not expired, and must be explicitely
+ * removed.
  *
  * This table is open-addressed with double hashing. Each table size is a
  * prime chosen to be a little more than double the high water mark for a
@@ -282,17 +282,51 @@
 }
 #endif
 
-static unsigned long
-_random_live_entry (cairo_cache_t *cache)
-{
-    unsigned long idx;
-    assert(cache != NULL);
-    do {
-	idx = rand () % cache->arrangement->size;
-    } while (! LIVE_ENTRY_P(cache, idx));
-    return idx;
-}
+/* Find a random in the cache matching the given predicate. We use the
+ * same algorithm as the probing algorithm to walk over the entries in
+ * the hash table in a pseudo-random order. Walking linearly would
+ * favor entries following gaps in the hash table. We could also
+ * call rand() repeatedly, which works well for almost-full tables,
+ * but degrades when the table is almost empty, or predicate
+ * returns false for most entries.
+ */
+static cairo_cache_entry_base_t **
+_random_entry (cairo_cache_t *cache,
+	       int (*predicate)(void*))
+{    
+    cairo_cache_entry_base_t **probe;
+    unsigned long hash;
+    unsigned long table_size, i, idx, step;
+    
+    _cache_sane_state (cache);
+
+    table_size = cache->arrangement->size;
+    hash = rand ();
+    idx = hash % table_size;
+    step = 0;
+
+    for (i = 0; i < table_size; ++i)
+    {
+	assert(idx < table_size);
+	probe = cache->entries + idx;
+
+	if (LIVE_ENTRY_P(cache, idx)
+	    && (!predicate || predicate (*probe)))
+	    return probe;
+
+	if (step == 0) { 	    
+	    step = hash % cache->arrangement->rehash;
+	    if (step == 0)
+		step = 1;
+	}
 
+	idx += step;
+	if (idx >= table_size)
+	    idx -= table_size;
+    }
+
+    return NULL;
+}
 
 /* public API follows */
 
@@ -356,8 +390,9 @@
 
 cairo_status_t
 _cairo_cache_lookup (cairo_cache_t *cache,
-		     void *key,
-		     void **entry_return)
+		     void          *key,
+		     void         **entry_return,
+		     int           *created_entry)
 {
 
     unsigned long idx;
@@ -392,6 +427,8 @@
 	cache->hits++;
 #endif
 	*entry_return = *slot;
+	if (created_entry)
+	    *created_entry = 0;
 	return status;
     }
 
@@ -401,19 +438,18 @@
 
     /* Build the new entry. */
     status = cache->backend->create_entry (cache, key, 
-					   entry_return);
+					   (void **)&new_entry);
     if (status != CAIRO_STATUS_SUCCESS)
 	return status;
 
-    new_entry = (cairo_cache_entry_base_t *) (*entry_return);
-
     /* Store the hash value in case the backend forgot. */
     new_entry->hashcode = cache->backend->hash (cache, key);
 
     /* Make some entries die if we're under memory pressure. */
     while (cache->live_entries > 0 &&
+	   cache->max_memory > 0 &&
 	   ((cache->max_memory - cache->used_memory) < new_entry->memory)) {
-	idx = _random_live_entry (cache);
+	idx =  _random_entry (cache, NULL) - cache->entries;
 	assert (idx < cache->arrangement->size);
 	_entry_destroy (cache, idx);
     }
@@ -425,7 +461,6 @@
     status = _resize_cache (cache, cache->live_entries + 1);
     if (status != CAIRO_STATUS_SUCCESS) {
 	cache->backend->destroy_entry (cache, new_entry);
-	*entry_return = NULL;
 	return status;
     }
 
@@ -439,9 +474,38 @@
 
     _cache_sane_state (cache);
 
+    *entry_return = new_entry;
+    if (created_entry)
+      *created_entry = 1;
+    
     return status;
 }
 
+cairo_status_t
+_cairo_cache_remove (cairo_cache_t *cache,
+		     void          *key)
+{
+    cairo_cache_entry_base_t **slot;
+
+    _cache_sane_state (cache);
+
+    /* See if we have an entry in the table already. */
+    slot = _find_exact_live_entry_for (cache, key);
+    if (slot != NULL)
+      	_entry_destroy (cache, slot - cache->entries);
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+void *
+_cairo_cache_random_entry (cairo_cache_t *cache,
+			   int (*predicate)(void*))
+{
+    cairo_cache_entry_base_t **slot = _random_entry (cache, predicate);
+
+    return *slot;
+}
+
 unsigned long
 _cairo_hash_string (const char *c)
 {

Index: cairo_font.c
===================================================================
RCS file: /cvs/cairo/cairo/src/cairo_font.c,v
retrieving revision 1.30
retrieving revision 1.31
diff -u -d -r1.30 -r1.31
--- cairo_font.c	13 Jan 2005 14:50:23 -0000	1.30
+++ cairo_font.c	21 Jan 2005 22:33:48 -0000	1.31
@@ -1,6 +1,7 @@
 /* cairo - a vector graphics library with display and print output
  *
  * Copyright © 2002 University of Southern California
+ * Copyright © 2005 Red Hat Inc.
  *
  * This library is free software; you can redistribute it and/or
  * modify it either under the terms of the GNU Lesser General Public
@@ -32,264 +33,85 @@
  *
  * Contributor(s):
  *	Carl D. Worth <cworth at isi.edu>
+ *      Graydon Hoare <graydon at redhat.com>
+ *      Owen Taylor <otaylor at redhat.com>
  */
 
 #include "cairoint.h"
 
-/* First we implement a global font cache for named fonts. */
-
-typedef struct {
-    cairo_cache_entry_base_t base;
-    const char *family;
-    cairo_font_slant_t slant;
-    cairo_font_weight_t weight;    
-} cairo_font_cache_key_t;
-
-typedef struct {
-    cairo_font_cache_key_t key;
-    cairo_unscaled_font_t *unscaled;
-} cairo_font_cache_entry_t;
-
-static unsigned long
-_font_cache_hash (void *cache, void *key)
-{
-    unsigned long hash;
-    cairo_font_cache_key_t *in;
-    in = (cairo_font_cache_key_t *) key;
-
-    /* 1607 and 1451 are just a couple random primes. */
-    hash = _cairo_hash_string (in->family);
-    hash += ((unsigned long) in->slant) * 1607;
-    hash += ((unsigned long) in->weight) * 1451;
-    return hash;
-}
-
-
-static int
-_font_cache_keys_equal (void *cache,
-			void *k1,
-			void *k2)
-{
-    cairo_font_cache_key_t *a, *b;
-    a = (cairo_font_cache_key_t *) k1;
-    b = (cairo_font_cache_key_t *) k2;
-    
-    return (strcmp (a->family, b->family) == 0) 
-	&& (a->weight == b->weight)
-	&& (a->slant == b->slant);
-}
-
-
-static cairo_status_t
-_font_cache_create_entry (void *cache,
-			  void *key,
-			  void **return_value)
-{
-    const cairo_font_backend_t *backend = CAIRO_FONT_BACKEND_DEFAULT;
-    cairo_font_cache_key_t *k;
-    cairo_font_cache_entry_t *entry;
-    k = (cairo_font_cache_key_t *) key;
-
-    /* XXX: The current freetype backend may return NULL, (for example
-     * if no fonts are installed), but I would like to guarantee that
-     * the toy API always returns at least *some* font, so I would
-     * like to build in some sort fo font here, (even a really lame,
-     * ugly one if necessary). */
-
-    entry = malloc (sizeof (cairo_font_cache_entry_t));
-    if (entry == NULL)
-	goto FAIL;
-
-    entry->key.slant = k->slant;
-    entry->key.weight = k->weight;
-    entry->key.family = strdup(k->family);
-    if (entry->key.family == NULL)
-	goto FREE_ENTRY;
-
-    entry->unscaled = backend->create (k->family, k->slant, k->weight);
-    if (entry->unscaled == NULL)
-	goto FREE_FAMILY;
-    
-    /* Not sure how to measure backend font mem; use a simple count for now.*/
-    entry->key.base.memory = 1;
-    *return_value = entry;
-    return CAIRO_STATUS_SUCCESS;
-    
- FREE_FAMILY:
-    free ((void *) entry->key.family);
-
- FREE_ENTRY:
-    free (entry);
-   
- FAIL:
-    return CAIRO_STATUS_NO_MEMORY;
-}
-
-static void
-_font_cache_destroy_entry (void *cache,
-			   void *entry)
-{
-    cairo_font_cache_entry_t *e;
-    
-    e = (cairo_font_cache_entry_t *) entry;
-    _cairo_unscaled_font_destroy (e->unscaled);
-    free ((void *) e->key.family);
-    free (e);
-}
-
-static void 
-_font_cache_destroy_cache (void *cache)
-{
-    free (cache);
-}
-
-static const cairo_cache_backend_t cairo_font_cache_backend = {
-    _font_cache_hash,
-    _font_cache_keys_equal,
-    _font_cache_create_entry,
-    _font_cache_destroy_entry,
-    _font_cache_destroy_cache
-};
-
-static void
-_lock_global_font_cache (void)
-{
-    /* FIXME: implement locking. */
-}
-
-static void
-_unlock_global_font_cache (void)
-{
-    /* FIXME: implement locking. */
-}
-
-static cairo_cache_t *
-_global_font_cache = NULL;
-
-static cairo_cache_t *
-_get_global_font_cache (void)
-{
-    if (_global_font_cache == NULL) {
-	_global_font_cache = malloc (sizeof (cairo_cache_t));
-	
-	if (_global_font_cache == NULL)
-	    goto FAIL;
-	
-	if (_cairo_cache_init (_global_font_cache,
-			       &cairo_font_cache_backend,
-			       CAIRO_FONT_CACHE_NUM_FONTS_DEFAULT))
-	    goto FAIL;
-    }
-
-    return _global_font_cache;
-    
- FAIL:
-    if (_global_font_cache)
-	free (_global_font_cache);
-    _global_font_cache = NULL;
-    return NULL;
-}
-
-
 /* Now the internal "unscaled + scale" font API */
 
-cairo_unscaled_font_t *
-_cairo_unscaled_font_create (const char           *family, 
-			     cairo_font_slant_t   slant, 
-			     cairo_font_weight_t  weight)
+cairo_private cairo_status_t
+_cairo_font_create (const char           *family, 
+		    cairo_font_slant_t   slant, 
+		    cairo_font_weight_t  weight,
+		    cairo_font_scale_t   *sc,
+		    cairo_font_t         **font)
 {
-    cairo_cache_t * cache;
-    cairo_font_cache_key_t key;
-    cairo_font_cache_entry_t *font;
-    cairo_status_t status;
-
-    _lock_global_font_cache ();
-    cache = _get_global_font_cache ();
-    if (cache == NULL) {
-	_unlock_global_font_cache ();
-	return NULL;
-    }
-
-    key.family = family;
-    key.slant = slant;
-    key.weight = weight;
-    
-    status = _cairo_cache_lookup (cache, &key, (void **) &font);
-    if (status) {
-	_unlock_global_font_cache ();
-	return NULL;
-    }
+    const cairo_font_backend_t *backend = CAIRO_FONT_BACKEND_DEFAULT;
 
-    _cairo_unscaled_font_reference (font->unscaled);
-    _unlock_global_font_cache ();
-    return font->unscaled;
+    return backend->create (family, slant, weight, sc, font);
 }
 
 void
-_cairo_font_init (cairo_font_t *scaled, 
-		  cairo_font_scale_t *scale, 
-		  cairo_unscaled_font_t *unscaled)
+_cairo_font_init (cairo_font_t               *font, 
+		  cairo_font_scale_t         *scale,
+		  const cairo_font_backend_t *backend)
 {
-    scaled->scale = *scale;
-    scaled->unscaled = unscaled;
-    scaled->refcount = 1;
+    font->scale = *scale;
+    font->refcount = 1;
+    font->backend = backend;
 }
 
-cairo_status_t
-_cairo_unscaled_font_init (cairo_unscaled_font_t 	*font, 
-			   const cairo_font_backend_t	*backend)
+void
+_cairo_unscaled_font_init (cairo_unscaled_font_t      *font, 
+			   const cairo_font_backend_t *backend)
 {
     font->refcount = 1;
     font->backend = backend;
-    return CAIRO_STATUS_SUCCESS;
 }
 
-
 cairo_status_t
-_cairo_unscaled_font_text_to_glyphs (cairo_unscaled_font_t 	*font,
-				     cairo_font_scale_t 	*scale,
-				     const unsigned char 	*utf8, 
-				     cairo_glyph_t 		**glyphs, 
-				     int 			*num_glyphs)
+_cairo_font_text_to_glyphs (cairo_font_t           *font,
+			    const unsigned char    *utf8, 
+			    cairo_glyph_t 	  **glyphs, 
+			    int 		   *num_glyphs)
 {
-    return font->backend->text_to_glyphs (font, scale, utf8, glyphs, num_glyphs);
+    return font->backend->text_to_glyphs (font, utf8, glyphs, num_glyphs);
 }
 
 cairo_status_t
-_cairo_unscaled_font_glyph_extents (cairo_unscaled_font_t	*font,
-				    cairo_font_scale_t 		*scale,			   
-				    cairo_glyph_t 		*glyphs,
-				    int 			num_glyphs,
-				    cairo_text_extents_t 	*extents)
+_cairo_font_glyph_extents (cairo_font_t	        *font,
+			   cairo_glyph_t 	*glyphs,
+			   int 			num_glyphs,
+			   cairo_text_extents_t *extents)
 {
-    return font->backend->glyph_extents(font, scale, glyphs, num_glyphs, extents);
+    return font->backend->glyph_extents(font, glyphs, num_glyphs, extents);
 }
 
 
 cairo_status_t
-_cairo_unscaled_font_glyph_bbox (cairo_unscaled_font_t	*font,
-				 cairo_font_scale_t	*scale,
-				 cairo_glyph_t          *glyphs,
-				 int                    num_glyphs,
-				 cairo_box_t		*bbox)
+_cairo_font_glyph_bbox (cairo_font_t	*font,
+			cairo_glyph_t  *glyphs,
+			int             num_glyphs,
+			cairo_box_t	*bbox)
 {
-    return font->backend->glyph_bbox (font, scale, glyphs, num_glyphs, bbox);
+    return font->backend->glyph_bbox (font, glyphs, num_glyphs, bbox);
 }
 
 cairo_status_t
-_cairo_unscaled_font_show_glyphs (cairo_unscaled_font_t	*font,
-				  cairo_font_scale_t	*scale,
-				  cairo_operator_t       operator,
-				  cairo_surface_t        *source,
-				  cairo_surface_t        *surface,
-				  int                    source_x,
-				  int                    source_y,
-				  cairo_glyph_t          *glyphs,
-				  int                    num_glyphs)
+_cairo_font_show_glyphs (cairo_font_t	        *font,
+			 cairo_operator_t       operator,
+			 cairo_surface_t        *source,
+			 cairo_surface_t        *surface,
+			 int                    source_x,
+			 int                    source_y,
+			 cairo_glyph_t          *glyphs,
+			 int                    num_glyphs)
 {
     cairo_status_t status;
     if (surface->backend->show_glyphs != NULL) {
-	status = surface->backend->show_glyphs (font, scale, operator, source, 
+	status = surface->backend->show_glyphs (font, operator, source, 
 						surface, source_x, source_y,
 						glyphs, num_glyphs);
 	if (status == CAIRO_STATUS_SUCCESS)
@@ -297,27 +119,32 @@
     }
 
     /* Surface display routine either does not exist or failed. */
-    return font->backend->show_glyphs (font, scale, operator, source, 
+    return font->backend->show_glyphs (font, operator, source, 
 				       surface, source_x, source_y,
 				       glyphs, num_glyphs);
 }
 
 cairo_status_t
-_cairo_unscaled_font_glyph_path (cairo_unscaled_font_t	*font,
-				 cairo_font_scale_t 	*scale,
-				 cairo_glyph_t		*glyphs, 
-				 int			num_glyphs,
-				 cairo_path_t        	*path)
+_cairo_font_glyph_path (cairo_font_t	   *font,
+			cairo_glyph_t	   *glyphs, 
+			int		    num_glyphs,
+			cairo_path_t       *path)
 {
-    return font->backend->glyph_path (font, scale, glyphs, num_glyphs, path);
+    return font->backend->glyph_path (font, glyphs, num_glyphs, path);
+}
+
+void
+_cairo_font_get_glyph_cache_key (cairo_font_t            *font,
+				 cairo_glyph_cache_key_t *key)
+{
+  font->backend->get_glyph_cache_key (font, key);
 }
 
 cairo_status_t
-_cairo_unscaled_font_font_extents (cairo_unscaled_font_t	*font,
-				   cairo_font_scale_t		*scale,
-				   cairo_font_extents_t		*extents)
+_cairo_font_font_extents (cairo_font_t	       *font,
+			  cairo_font_extents_t *extents)
 {
-    return font->backend->font_extents(font, scale, extents);
+    return font->backend->font_extents (font, extents);
 }
 
 void
@@ -332,8 +159,7 @@
     if (--(font->refcount) > 0)
 	return;
 
-    if (font->backend)
-	font->backend->destroy (font);
+    font->backend->destroy_unscaled_font (font);
 }
 
 
@@ -352,37 +178,97 @@
     if (--(font->refcount) > 0)
 	return;
 
-    if (font->unscaled)
-	_cairo_unscaled_font_destroy (font->unscaled);
-
-    free (font);
+    font->backend->destroy_font (font);
 }
 
 void
-cairo_font_set_transform (cairo_font_t *font, 
-			  cairo_matrix_t *matrix)
+cairo_font_glyph_extents (cairo_font_t          *font,
+			  cairo_matrix_t        *font_matrix,
+			  cairo_glyph_t         *glyphs, 
+			  int                   num_glyphs,
+			  cairo_text_extents_t  *extents)
 {
-    double dummy;
-    cairo_matrix_get_affine (matrix,
-			     &font->scale.matrix[0][0],
-			     &font->scale.matrix[0][1],
-			     &font->scale.matrix[1][0],
-			     &font->scale.matrix[1][1],
-			     &dummy, &dummy);    
-}
+    cairo_status_t status = CAIRO_STATUS_SUCCESS;
+    cairo_glyph_t origin_glyph;
+    cairo_text_extents_t origin_extents;
+    int i;
+    double min_x = 0.0, min_y = 0.0, max_x = 0.0, max_y = 0.0;
+    double x_pos = 0.0, y_pos = 0.0;
+    int set = 0;
 
-void
-cairo_font_current_transform (cairo_font_t *font, 
-			      cairo_matrix_t *matrix)
-{
-    cairo_matrix_set_affine (matrix,
-			     font->scale.matrix[0][0],
-			     font->scale.matrix[0][1],
-			     font->scale.matrix[1][0],
-			     font->scale.matrix[1][1],
-			     0, 0);
-}
+    if (!num_glyphs)
+    {
+	extents->x_bearing = 0.0;
+	extents->y_bearing = 0.0;
+	extents->width = 0.0;
+	extents->height = 0.0;
+	extents->x_advance = 0.0;
+	extents->y_advance = 0.0;
+	
+	return;
+    }
+
+    for (i = 0; i < num_glyphs; i++)
+    {
+	double		x, y;
+	double		wm, hm;
+	
+	origin_glyph = glyphs[i];
+	origin_glyph.x = 0.0;
+	origin_glyph.y = 0.0;
+	status = _cairo_font_glyph_extents (font,
+					    &origin_glyph, 1,
+					    &origin_extents);
+	
+	/*
+	 * Transform font space metrics into user space metrics
+	 * by running the corners through the font matrix and
+	 * expanding the bounding box as necessary
+	 */
+	x = origin_extents.x_bearing;
+	y = origin_extents.y_bearing;
+	cairo_matrix_transform_point (font_matrix,
+				      &x, &y);
 
+	for (hm = 0.0; hm <= 1.0; hm += 1.0)
+	    for (wm = 0.0; wm <= 1.0; wm += 1.0)
+	    {
+		x = origin_extents.x_bearing + origin_extents.width * wm;
+		y = origin_extents.y_bearing + origin_extents.height * hm;
+		cairo_matrix_transform_point (font_matrix,
+					      &x, &y);
+		x += glyphs[i].x;
+		y += glyphs[i].y;
+		if (!set)
+		{
+		    min_x = max_x = x;
+		    min_y = max_y = y;
+		    set = 1;
+		}
+		else
+		{
+		    if (x < min_x) min_x = x;
+		    if (x > max_x) max_x = x;
+		    if (y < min_y) min_y = y;
+		    if (y > max_y) max_y = y;
+		}
+	    }
+
+	x = origin_extents.x_advance;
+	y = origin_extents.y_advance;
+	cairo_matrix_transform_point (font_matrix,
+				      &x, &y);
+	x_pos = glyphs[i].x + x;
+	y_pos = glyphs[i].y + y;
+    }
+
+    extents->x_bearing = min_x - glyphs[0].x;
+    extents->y_bearing = min_y - glyphs[0].y;
+    extents->width = max_x - min_x;
+    extents->height = max_y - min_y;
+    extents->x_advance = x_pos - glyphs[0].x;
+    extents->y_advance = y_pos - glyphs[0].y;
+}
 
 /* Now we implement functions to access a default global image & metrics
  * cache. 
@@ -398,7 +284,8 @@
 	^ ((unsigned long) in->scale.matrix[0][0]) 
 	^ ((unsigned long) in->scale.matrix[0][1]) 
 	^ ((unsigned long) in->scale.matrix[1][0]) 
-	^ ((unsigned long) in->scale.matrix[1][1]) 
+	^ ((unsigned long) in->scale.matrix[1][1])
+        ^ (in->flags * 1451) /* 1451 is just an abitrary prime */
 	^ in->index;
 }
 
@@ -412,6 +299,7 @@
     b = (cairo_glyph_cache_key_t *) k2;
     return (a->index == b->index)
 	&& (a->unscaled == b->unscaled)
+	&& (a->flags == b->flags)
 	&& (a->scale.matrix[0][0] == b->scale.matrix[0][0])
 	&& (a->scale.matrix[0][1] == b->scale.matrix[0][1])
 	&& (a->scale.matrix[1][0] == b->scale.matrix[1][0])

Index: cairo_ft_font.c
===================================================================
RCS file: /cvs/cairo/cairo/src/cairo_ft_font.c,v
retrieving revision 1.32
retrieving revision 1.33
diff -u -d -r1.32 -r1.33
--- cairo_ft_font.c	20 Jan 2005 16:28:54 -0000	1.32
+++ cairo_ft_font.c	21 Jan 2005 22:33:48 -0000	1.33
@@ -1,29 +1,40 @@
-/*
- * Copyright © 2003 Red Hat Inc.
+/* cairo - a vector graphics library with display and print output
  *
- * Permission to use, copy, modify, distribute, and sell this software and
- * its documentation for any purpose is hereby granted without fee,
- * provided that the above copyright notice appear in all copies and that
- * both that copyright notice and this permission notice appear in
- * supporting documentation, and that the name of Red Hat Inc. not be used
- * in advertising or publicity pertaining to distribution of the software
- * without specific, written prior permission. Red Hat Inc. makes no
[...1415 lines suppressed...]
+{
+    cairo_ft_font_t *font = (cairo_ft_font_t *) font;
+
+    return (cairo_unscaled_font_t *)font->unscaled;
+}
+
+/* This differs from _cairo_ft_scaled_font_lock_face in that it doesn't
+ * set the scale on the face, but just returns it at the last scale.
+ */
+FT_Face
+_cairo_ft_unscaled_font_lock_face (cairo_unscaled_font_t *unscaled_font)
+{
+    return _ft_unscaled_font_lock_face ((ft_unscaled_font_t *)unscaled_font);
+}
+
+void
+_cairo_ft_unscaled_font_unlock_face (cairo_unscaled_font_t *unscaled_font)
+{
+    _ft_unscaled_font_unlock_face ((ft_unscaled_font_t *)unscaled_font);
+}

Index: cairo_gstate.c
===================================================================
RCS file: /cvs/cairo/cairo/src/cairo_gstate.c,v
retrieving revision 1.72
retrieving revision 1.73
diff -u -d -r1.72 -r1.73
--- cairo_gstate.c	19 Jan 2005 20:12:42 -0000	1.72
+++ cairo_gstate.c	21 Jan 2005 22:33:48 -0000	1.73
@@ -45,6 +45,8 @@
 					     cairo_operator_t operator,
 					     cairo_surface_t *dst,
 					     cairo_traps_t *traps);
+static void
+_cairo_gstate_unset_font (cairo_gstate_t *gstate);
 
 cairo_gstate_t *
 _cairo_gstate_create ()
@@ -77,9 +79,11 @@
     gstate->num_dashes = 0;
     gstate->dash_offset = 0.0;
 
-    gstate->font = _cairo_unscaled_font_create (CAIRO_FONT_FAMILY_DEFAULT,
-						CAIRO_FONT_SLANT_DEFAULT,
-						CAIRO_FONT_WEIGHT_DEFAULT);
+    gstate->font_family = NULL;
+    gstate->font_slant = CAIRO_FONT_SLANT_DEFAULT;
+    gstate->font_weight = CAIRO_FONT_WEIGHT_DEFAULT;
+
+    gstate->font = NULL;
 
     gstate->surface = NULL;
 
@@ -118,9 +122,15 @@
 	memcpy (gstate->dash, other->dash, other->num_dashes * sizeof (double));
     }
 
+    if (other->font_family) {
+	gstate->font_family = strdup (other->font_family);
+	if (!gstate->font_family)
+	    goto CLEANUP_DASH;
+    }
+
     if (other->font) {
 	gstate->font = other->font;
-	_cairo_unscaled_font_reference (gstate->font);
+	cairo_font_reference (gstate->font);
     }
 
     if (other->clip.region)
@@ -148,18 +158,29 @@
     _cairo_path_fini (&gstate->path);
 
   CLEANUP_FONT:
-    _cairo_unscaled_font_destroy (gstate->font);
+    cairo_font_destroy (gstate->font);
+    gstate->font = NULL;
+    
+    if (gstate->font_family) {
+	free (gstate->font_family);
+	gstate->font_family = NULL;
+    }
 
+  CLEANUP_DASH:
     free (gstate->dash);
     gstate->dash = NULL;
 
-    return status;
+    return CAIRO_STATUS_NO_MEMORY;
 }
 
 void
 _cairo_gstate_fini (cairo_gstate_t *gstate)
 {
-    _cairo_unscaled_font_destroy (gstate->font);
+    if (gstate->font_family)
+	free (gstate->font_family);
+
+    if (gstate->font)
+	cairo_font_destroy (gstate->font);
 
     if (gstate->surface)
 	cairo_surface_destroy (gstate->surface);
@@ -323,6 +344,8 @@
 {
     double scale;
 
+    _cairo_gstate_unset_font (gstate);
+
     if (gstate->surface)
 	cairo_surface_destroy (gstate->surface);
 
@@ -549,6 +572,8 @@
 {
     cairo_matrix_t tmp;
 
+    _cairo_gstate_unset_font (gstate);
+    
     _cairo_matrix_set_translate (&tmp, tx, ty);
     cairo_matrix_multiply (&gstate->ctm, &tmp, &gstate->ctm);
 
@@ -566,6 +591,8 @@
     if (sx == 0 || sy == 0)
 	return CAIRO_STATUS_INVALID_MATRIX;
 
+    _cairo_gstate_unset_font (gstate);
+    
     _cairo_matrix_set_scale (&tmp, sx, sy);
     cairo_matrix_multiply (&gstate->ctm, &tmp, &gstate->ctm);
 
@@ -580,6 +607,8 @@
 {
     cairo_matrix_t tmp;
 
+    _cairo_gstate_unset_font (gstate);
+    
     _cairo_matrix_set_rotate (&tmp, angle);
     cairo_matrix_multiply (&gstate->ctm, &tmp, &gstate->ctm);
 
@@ -595,6 +624,8 @@
 {
     cairo_matrix_t tmp;
 
+    _cairo_gstate_unset_font (gstate);
+    
     cairo_matrix_copy (&tmp, matrix);
     cairo_matrix_multiply (&gstate->ctm, &tmp, &gstate->ctm);
 
@@ -610,6 +641,8 @@
 {
     cairo_status_t status;
 
+    _cairo_gstate_unset_font (gstate);
+    
     cairo_matrix_copy (&gstate->ctm, matrix);
 
     cairo_matrix_copy (&gstate->ctm_inverse, matrix);
@@ -627,6 +660,8 @@
     if (scale == 0)
 	scale = 1;
 
+    _cairo_gstate_unset_font (gstate);
+    
     cairo_matrix_set_identity (&gstate->font_matrix);
 
     cairo_matrix_set_identity (&gstate->ctm);
@@ -640,6 +675,8 @@
 cairo_status_t
 _cairo_gstate_identity_matrix (cairo_gstate_t *gstate)
 {
+    _cairo_gstate_unset_font (gstate);
+    
     cairo_matrix_set_identity (&gstate->ctm);
     cairo_matrix_set_identity (&gstate->ctm_inverse);
 
@@ -2121,6 +2158,14 @@
     return CAIRO_STATUS_SUCCESS;
 }
 
+static void
+_cairo_gstate_unset_font (cairo_gstate_t *gstate)
+{
+    if (gstate->font) {
+	cairo_font_destroy (gstate->font);
+	gstate->font = NULL;
+    }
+}
 
 cairo_status_t
 _cairo_gstate_select_font (cairo_gstate_t       *gstate, 
@@ -2128,12 +2173,17 @@
 			   cairo_font_slant_t   slant, 
 			   cairo_font_weight_t  weight)
 {
-    if (gstate->font)
-	_cairo_unscaled_font_destroy (gstate->font);
+    char *new_family;
 
-    gstate->font = _cairo_unscaled_font_create (family, slant, weight);
-    if (gstate->font == NULL)
+    new_family = strdup (family);
+    if (!new_family)
 	return CAIRO_STATUS_NO_MEMORY;
+    
+    _cairo_gstate_unset_font (gstate);
+    
+    gstate->font_family = new_family;
+    gstate->font_slant = slant;
+    gstate->font_weight = weight;
 
     cairo_matrix_set_identity (&gstate->font_matrix);
   
@@ -2144,6 +2194,8 @@
 _cairo_gstate_scale_font (cairo_gstate_t *gstate, 
 			  double scale)
 {
+    _cairo_gstate_unset_font (gstate);
+
     return cairo_matrix_scale (&gstate->font_matrix, scale, scale);
 }
 
@@ -2153,6 +2205,9 @@
 {
     cairo_matrix_t tmp;
     double a, b, c, d, tx, ty;
+
+    _cairo_gstate_unset_font (gstate);
+
     cairo_matrix_get_affine (matrix, &a, &b, &c, &d, &tx, &ty);
     cairo_matrix_set_affine (&tmp, a, b, c, d, 0, 0);
     return cairo_matrix_multiply (&gstate->font_matrix, &gstate->font_matrix, &tmp);
@@ -2160,28 +2215,10 @@
 
 
 cairo_status_t
-_cairo_gstate_current_font (cairo_gstate_t *gstate, 
-			    cairo_font_t **font)
+_cairo_gstate_current_font (cairo_gstate_t *gstate, 			    cairo_font_t **font)
 {
-    cairo_font_scale_t scale;
-    cairo_font_t *scaled;
-    double dummy;
-
-    scaled = malloc (sizeof (cairo_font_t));
-    if (scaled == NULL)
-	return CAIRO_STATUS_NO_MEMORY;
-
-    cairo_matrix_get_affine (&gstate->font_matrix,
-			     &scale.matrix[0][0],
-			     &scale.matrix[0][1],
-			     &scale.matrix[1][0],
-			     &scale.matrix[1][1],
-			     &dummy, &dummy);
-
-    _cairo_font_init (scaled, &scale, gstate->font);
-    _cairo_unscaled_font_reference (gstate->font);
-
-    *font = scaled;
+    *font = gstate->font;
+    cairo_font_reference (*font);
 
     return CAIRO_STATUS_SUCCESS;
 }
@@ -2190,6 +2227,8 @@
 _cairo_gstate_set_font_transform (cairo_gstate_t *gstate, 
 				  cairo_matrix_t *matrix)
 {
+    _cairo_gstate_unset_font (gstate);
+
     cairo_matrix_copy (&gstate->font_matrix, matrix);
 }
 
@@ -2214,12 +2253,10 @@
  * independently scale the user coordinate system *or* the font matrix, in
  * order to adjust the rendered size of the font.
  *
- * If the user asks for a permanent reference to "a font", they are given a
- * handle to a structure holding a scale matrix and an unscaled font. This
- * effectively decouples the font from further changes to user space. Even
- * if the user then "sets" the current cairo_t font to the handle they were
- * passed, further changes to the cairo_t CTM will not affect externally
- * held references to the font.
+ * The only font type exposed to the user is cairo_font_t which is a
+ * a font specialized to a particular scale matrix, CTM, and target
+ * surface. The user is responsible for not using a cairo_font_t
+ * after changing the parameters; doing so will produce garbled metrics.
  *
  *
  * The font's view
@@ -2279,9 +2316,9 @@
  *
  */
 
-static void
-_build_font_scale (cairo_gstate_t *gstate,
-		   cairo_font_scale_t *sc)
+void
+_cairo_gstate_current_font_scale (cairo_gstate_t     *gstate,
+				  cairo_font_scale_t *sc)
 {
     cairo_matrix_t tmp;
     double dummy;
@@ -2294,17 +2331,47 @@
 			     &dummy, &dummy);
 }
 
+static cairo_status_t
+_cairo_gstate_ensure_font (cairo_gstate_t *gstate)
+{
+    cairo_font_scale_t sc;
+    cairo_status_t status;
+    const char *family;
+    
+    if (gstate->font)
+	return CAIRO_STATUS_SUCCESS;
+    
+    _cairo_gstate_current_font_scale (gstate, &sc);
+
+    if (gstate->font_family)
+	family = gstate->font_family;
+    else
+	family = CAIRO_FONT_FAMILY_DEFAULT;
+    
+    status = _cairo_font_create (family,
+				 gstate->font_slant,
+				 gstate->font_weight,
+				 &sc,
+				 &gstate->font);
+
+    if (status)
+	return status;
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
 cairo_status_t
 _cairo_gstate_current_font_extents (cairo_gstate_t *gstate, 
 				    cairo_font_extents_t *extents)
 {
     cairo_int_status_t status;
-    cairo_font_scale_t sc;
     double  font_scale_x, font_scale_y;
 
-    _build_font_scale (gstate, &sc);
-
-    status = _cairo_unscaled_font_font_extents (gstate->font, &sc, extents);
+    status = _cairo_gstate_ensure_font (gstate);
+    if (status)
+	return status;
+    
+    status = _cairo_font_font_extents (gstate->font, extents);
 
     _cairo_matrix_compute_scale_factors (&gstate->font_matrix,
 					 &font_scale_x, &font_scale_y,
@@ -2331,14 +2398,15 @@
 			      int *nglyphs)
 {
     cairo_status_t status;
-    cairo_font_scale_t sc;
 
     cairo_point_t point; 
     double origin_x, origin_y;
     int i;
 
-    _build_font_scale (gstate, &sc);
-
+    status = _cairo_gstate_ensure_font (gstate);
+    if (status)
+	return status;
+    
     status = _cairo_path_current_point (&gstate->path, &point);
     if (status == CAIRO_STATUS_NO_CURRENT_POINT) {
 	origin_x = 0.0;
@@ -2350,8 +2418,8 @@
 				      &origin_x, &origin_y);
     }
 
-    status = _cairo_unscaled_font_text_to_glyphs (gstate->font, 
-						  &sc, utf8, glyphs, nglyphs);
+    status = _cairo_font_text_to_glyphs (gstate->font, 
+					 utf8, glyphs, nglyphs);
 
     if (status || !glyphs || !nglyphs || !(*glyphs) || !(nglyphs))
 	return status;
@@ -2373,18 +2441,13 @@
 
 cairo_status_t
 _cairo_gstate_set_font (cairo_gstate_t *gstate, 
-			cairo_font_t *font)
+			cairo_font_t   *font)
 {
     if (gstate->font != NULL)    
-	_cairo_unscaled_font_destroy (gstate->font);
-    gstate->font = font->unscaled;
-    _cairo_unscaled_font_reference (gstate->font);
-    cairo_matrix_set_affine (&gstate->font_matrix,
-			     font->scale.matrix[0][0],
-			     font->scale.matrix[0][1],
-			     font->scale.matrix[1][0],
-			     font->scale.matrix[1][1],
-			     0, 0);
+	cairo_font_destroy (gstate->font);
+    gstate->font = font;
+    cairo_font_reference (gstate->font);
+    
     return CAIRO_STATUS_SUCCESS;
 }
 
@@ -2394,90 +2457,18 @@
 			     int num_glyphs,
 			     cairo_text_extents_t *extents)
 {
-    cairo_status_t status = CAIRO_STATUS_SUCCESS;
-    cairo_glyph_t origin_glyph;
-    cairo_text_extents_t origin_extents;
-    cairo_font_scale_t sc;
-    int i;
-    double min_x = 0.0, min_y = 0.0, max_x = 0.0, max_y = 0.0;
-    double x_pos = 0.0, y_pos = 0.0;
-    int set = 0;
-
-    if (!num_glyphs)
-    {
-	extents->x_bearing = 0.0;
-	extents->y_bearing = 0.0;
-	extents->width = 0.0;
-	extents->height = 0.0;
-	extents->x_advance = 0.0;
-	extents->y_advance = 0.0;
-	return CAIRO_STATUS_SUCCESS;
-    }
-
-    _build_font_scale (gstate, &sc);
-
-    for (i = 0; i < num_glyphs; i++)
-    {
-	double		x, y;
-	double		wm, hm;
-	
-	origin_glyph = glyphs[i];
-	origin_glyph.x = 0.0;
-	origin_glyph.y = 0.0;
-	status = _cairo_unscaled_font_glyph_extents (gstate->font, &sc,
-						     &origin_glyph, 1,
-						     &origin_extents);
-	
-	/*
-	 * Transform font space metrics into user space metrics
-	 * by running the corners through the font matrix and
-	 * expanding the bounding box as necessary
-	 */
-	x = origin_extents.x_bearing;
-	y = origin_extents.y_bearing;
-	cairo_matrix_transform_point (&gstate->font_matrix,
-				      &x, &y);
-
-	for (hm = 0.0; hm <= 1.0; hm += 1.0)
-	    for (wm = 0.0; wm <= 1.0; wm += 1.0)
-	    {
-		x = origin_extents.x_bearing + origin_extents.width * wm;
-		y = origin_extents.y_bearing + origin_extents.height * hm;
-		cairo_matrix_transform_point (&gstate->font_matrix,
-					      &x, &y);
-		x += glyphs[i].x;
-		y += glyphs[i].y;
-		if (!set)
-		{
-		    min_x = max_x = x;
-		    min_y = max_y = y;
-		    set = 1;
-		}
-		else
-		{
-		    if (x < min_x) min_x = x;
-		    if (x > max_x) max_x = x;
-		    if (y < min_y) min_y = y;
-		    if (y > max_y) max_y = y;
-		}
-	    }
+    cairo_status_t status;
 
-	x = origin_extents.x_advance;
-	y = origin_extents.y_advance;
-	cairo_matrix_transform_point (&gstate->font_matrix,
-				      &x, &y);
-	x_pos = glyphs[i].x + x;
-	y_pos = glyphs[i].y + y;
-    }
+    status = _cairo_gstate_ensure_font (gstate);
+    if (status)
+	return status;
 
-    extents->x_bearing = min_x - glyphs[0].x;
-    extents->y_bearing = min_y - glyphs[0].y;
-    extents->width = max_x - min_x;
-    extents->height = max_y - min_y;
-    extents->x_advance = x_pos - glyphs[0].x;
-    extents->y_advance = y_pos - glyphs[0].y;
+    cairo_font_glyph_extents (gstate->font,
+			      &gstate->font_matrix,
+			      glyphs, num_glyphs,
+			      extents);
 
-    return status;
+    return CAIRO_STATUS_SUCCESS;
 }
 
 cairo_status_t
@@ -2488,12 +2479,13 @@
     cairo_status_t status;
     int i;
     cairo_glyph_t *transformed_glyphs = NULL;
-    cairo_font_scale_t sc;
     cairo_pattern_t pattern;
     cairo_box_t bbox;
 
-    _build_font_scale (gstate, &sc);
-
+    status = _cairo_gstate_ensure_font (gstate);
+    if (status)
+	return status;
+    
     transformed_glyphs = malloc (num_glyphs * sizeof(cairo_glyph_t));
     if (transformed_glyphs == NULL)
 	return CAIRO_STATUS_NO_MEMORY;
@@ -2507,9 +2499,9 @@
     }
     
     _cairo_pattern_init_copy (&pattern, gstate->pattern);
-    status = _cairo_unscaled_font_glyph_bbox (gstate->font, &sc, 
-					      transformed_glyphs, num_glyphs, 
-					      &bbox);
+    status = _cairo_font_glyph_bbox (gstate->font,
+				     transformed_glyphs, num_glyphs, 
+				     &bbox);
     if (status)
 	goto CLEANUP_GLYPHS;
 
@@ -2565,14 +2557,13 @@
 	    transformed_glyphs[i].y -= draw_extents->y1;
 	}
 
-	status = _cairo_unscaled_font_show_glyphs (gstate->font, 
-						   &sc,
-						   CAIRO_OPERATOR_ADD, 
-						   pattern.source, intermediate,
-						   draw_extents->x1 - pattern.source_offset.x,
-						   draw_extents->y1 - pattern.source_offset.y,
-						   transformed_glyphs, num_glyphs);
-
+	status = _cairo_font_show_glyphs (gstate->font, 
+					  CAIRO_OPERATOR_ADD, 
+					  pattern.source, intermediate,
+					  draw_extents->x1 - pattern.source_offset.x,
+					  draw_extents->y1 - pattern.source_offset.y,
+					  transformed_glyphs, num_glyphs);
+	
 	if (status)
 	    goto BAIL2;
 
@@ -2610,13 +2601,12 @@
     }
     else
     {
-	status = _cairo_unscaled_font_show_glyphs (gstate->font, 
-						   &sc,
-						   gstate->operator, pattern.source,
-						   gstate->surface,
-						   -pattern.source_offset.x,
-						   -pattern.source_offset.y,
-						   transformed_glyphs, num_glyphs);
+	status = _cairo_font_show_glyphs (gstate->font, 
+					  gstate->operator, pattern.source,
+					  gstate->surface,
+					  -pattern.source_offset.x,
+					  -pattern.source_offset.y,
+					  transformed_glyphs, num_glyphs);
     }
     
     _cairo_pattern_fini (&pattern);
@@ -2635,9 +2625,6 @@
     cairo_status_t status;
     int i;
     cairo_glyph_t *transformed_glyphs = NULL;
-    cairo_font_scale_t sc;
-
-    _build_font_scale (gstate, &sc);
 
     transformed_glyphs = malloc (num_glyphs * sizeof(cairo_glyph_t));
     if (transformed_glyphs == NULL)
@@ -2651,9 +2638,9 @@
 				      &(transformed_glyphs[i].y));
     }
 
-    status = _cairo_unscaled_font_glyph_path (gstate->font, &sc,
-					      transformed_glyphs, num_glyphs,
-					      &gstate->path);
+    status = _cairo_font_glyph_path (gstate->font,
+				     transformed_glyphs, num_glyphs,
+				     &gstate->path);
 
     free (transformed_glyphs);
     return status;

Index: cairo_pdf_surface.c
===================================================================
RCS file: /cvs/cairo/cairo/src/cairo_pdf_surface.c,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -d -r1.7 -r1.8
--- cairo_pdf_surface.c	20 Jan 2005 16:28:54 -0000	1.7
+++ cairo_pdf_surface.c	21 Jan 2005 22:33:48 -0000	1.8
@@ -36,9 +36,8 @@
 
 #include "cairoint.h"
 #include "cairo-pdf.h"
-/* XXX: This seems broken to me. What about users without freetype
- * that want to use a cairo PDF surface? */
-#include "cairo-ft.h"
+/* XXX: Eventually, we need to handle other font backends */
+#include "cairo-ft-private.h"
 
 #include <ft2build.h>
 #include FT_FREETYPE_H
@@ -300,19 +299,15 @@
 }
 
 static cairo_pdf_font_t *
-cairo_pdf_ft_font_create (cairo_pdf_document_t	*document,
-			  cairo_unscaled_font_t	*unscaled_font,
-			  cairo_font_scale_t	*scale)
+cairo_pdf_ft_font_create (cairo_pdf_document_t  *document,
+			  cairo_unscaled_font_t *unscaled_font)
 {
-    cairo_font_t scaled_font;
     FT_Face face;
     cairo_pdf_ft_font_t *font;
     unsigned long size;
     int i, j;
 
-    /* FIXME: Why do I have to pass a scaled font to get the FT_Face? */
-    _cairo_font_init (&scaled_font, scale, unscaled_font);
-    face = cairo_ft_font_face (&scaled_font);
+    face = _cairo_ft_unscaled_font_lock_face (unscaled_font);
 
     /* We currently only support freetype truetype fonts. */
     size = 0;
@@ -333,7 +328,8 @@
     if (_cairo_array_grow_by (&font->output, 4096) != CAIRO_STATUS_SUCCESS)
 	goto fail1;
 
-    font->face = face;
+    font->base.unscaled_font = unscaled_font;
+    _cairo_unscaled_font_reference (unscaled_font);
     font->glyphs = calloc (face->num_glyphs + 1, sizeof (ft_subset_glyph_t));
     if (font->glyphs == NULL)
 	goto fail2;
@@ -364,6 +360,8 @@
     if (font->base.widths == NULL)
 	goto fail5;
 
+    _cairo_ft_unscaled_font_unlock_face (unscaled_font);
+
     font->status = CAIRO_STATUS_SUCCESS;
 
     return &font->base;
@@ -764,12 +762,15 @@
     unsigned long start, end, next, checksum;
     int i;
 
+    font->face = _cairo_ft_unscaled_font_lock_face (font->base.unscaled_font);
+
     if (cairo_pdf_ft_font_write_offset_table (font))
-	return font->status;
+	goto fail;
 
     start = cairo_pdf_ft_font_align_output (font);
     end = start;
 
+    end = 0;
     for (i = 0; i < ARRAY_LENGTH (truetype_tables); i++) {
 	if (truetype_tables[i].write (font, truetype_tables[i].tag))
 	    goto fail;
@@ -789,6 +790,9 @@
     *length = _cairo_array_num_elements (&font->output);
 
  fail:
+    _cairo_ft_unscaled_font_unlock_face (font->base.unscaled_font);      
+    font->face = NULL;
+
     return font->status;
 }
 
@@ -1704,36 +1708,37 @@
 
 static cairo_pdf_font_t *
 _cairo_pdf_document_get_font (cairo_pdf_document_t	*document,
-			      cairo_unscaled_font_t	*unscaled_font,
-			      cairo_font_scale_t	*scale)
+			      cairo_font_t	        *font)
 {
-    cairo_pdf_font_t *font;
+    cairo_unscaled_font_t *unscaled_font;
+    cairo_pdf_font_t *pdf_font;
     unsigned int num_fonts, i;
 
+    unscaled_font = _cairo_ft_font_get_unscaled_font (font);
+
     num_fonts = _cairo_array_num_elements (&document->fonts);
     for (i = 0; i < num_fonts; i++) {
-	_cairo_array_copy_element (&document->fonts, i, &font);
-	if (font->unscaled_font == unscaled_font)
-	    return font;
+	_cairo_array_copy_element (&document->fonts, i, &pdf_font);
+	if (pdf_font->unscaled_font == unscaled_font)
+	    return pdf_font;
     }
 
     /* FIXME: Figure out here which font backend is in use and call
      * the appropriate constructor. */
-    font = cairo_pdf_ft_font_create (document, unscaled_font, scale);
+    pdf_font = cairo_pdf_ft_font_create (document, unscaled_font);
     if (font == NULL)
 	return NULL;
 
-    if (_cairo_array_append (&document->fonts, &font, 1) == NULL) {
-	cairo_pdf_font_destroy (font);
+    if (_cairo_array_append (&document->fonts, &pdf_font, 1) == NULL) {
+	cairo_pdf_font_destroy (pdf_font);
 	return NULL;
     }
 
-    return font;
+    return pdf_font;
 }
 
 static cairo_status_t
-_cairo_pdf_surface_show_glyphs (cairo_unscaled_font_t	*font,
-				cairo_font_scale_t	*scale,
+_cairo_pdf_surface_show_glyphs (cairo_font_t	        *font,
 				cairo_operator_t	operator,
 				cairo_surface_t		*source,
 				void			*abstract_surface,
@@ -1748,7 +1753,7 @@
     cairo_pdf_font_t *pdf_font;
     int i, index;
 
-    pdf_font = _cairo_pdf_document_get_font (document, font, scale);
+    pdf_font = _cairo_pdf_document_get_font (document, font);
     if (pdf_font == NULL)
 	return CAIRO_STATUS_NO_MEMORY;
 
@@ -1761,10 +1766,10 @@
 
 	fprintf (file,
 		 " %f %f %f %f %f %f Tm (%c) Tj",
-		 scale->matrix[0][0],
-		 scale->matrix[0][1],
-		 scale->matrix[1][0],
-		 -scale->matrix[1][1],
+		 font->scale.matrix[0][0],
+		 font->scale.matrix[0][1],
+		 font->scale.matrix[1][0],
+		 -font->scale.matrix[1][1],
 		 glyphs[i].x,
 		 glyphs[i].y,
                  index);

Index: cairo_quartz_surface.c
===================================================================
RCS file: /cvs/cairo/cairo/src/cairo_quartz_surface.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -d -r1.2 -r1.3
--- cairo_quartz_surface.c	21 Jan 2005 04:36:25 -0000	1.2
+++ cairo_quartz_surface.c	21 Jan 2005 22:33:48 -0000	1.3
@@ -1,6 +1,6 @@
 /* cairo - a vector graphics library with display and print output
  *
- * Copyright © 2004 Calum Robinson
+ * Copyright © 2004 Calum Robinson
  *
  * This library is free software; you can redistribute it and/or
  * modify it either under the terms of the GNU Lesser General Public

Index: cairo_xlib_surface.c
===================================================================
RCS file: /cvs/cairo/cairo/src/cairo_xlib_surface.c,v
retrieving revision 1.37
retrieving revision 1.38
diff -u -d -r1.37 -r1.38
--- cairo_xlib_surface.c	20 Jan 2005 16:28:54 -0000	1.37
+++ cairo_xlib_surface.c	21 Jan 2005 22:33:48 -0000	1.38
@@ -694,8 +694,7 @@
 }
 
 static cairo_status_t
-_cairo_xlib_surface_show_glyphs (cairo_unscaled_font_t  *font,
-				 cairo_font_scale_t	*scale,
+_cairo_xlib_surface_show_glyphs (cairo_font_t           *font,
 				 cairo_operator_t       operator,
 				 cairo_surface_t        *source,
 				 void			*abstract_surface,
@@ -824,6 +823,7 @@
 } glyphset_cache_t;
 
 typedef struct {
+    int refcount;
     cairo_glyph_cache_key_t key;
     Glyph glyph;
     XGlyphInfo info;
@@ -854,17 +854,18 @@
     _cairo_lock_global_image_glyph_cache ();
     im_cache = _cairo_get_global_image_glyph_cache ();
 
-    if (g == NULL || v == NULL ||g == NULL || im_cache == NULL) {
+    if (g == NULL || v == NULL || im_cache == NULL) {
 	_cairo_unlock_global_image_glyph_cache ();
 	return CAIRO_STATUS_NO_MEMORY;
     }
 
-    status = _cairo_cache_lookup (im_cache, key, (void **) (&im));
+    status = _cairo_cache_lookup (im_cache, key, (void **) (&im), NULL);
     if (status != CAIRO_STATUS_SUCCESS || im == NULL) {
 	_cairo_unlock_global_image_glyph_cache ();
 	return CAIRO_STATUS_NO_MEMORY;
     }
 
+    v->refcount = 1;
     v->key = *k;
     _cairo_unscaled_font_reference (v->key.unscaled);
 
@@ -925,6 +926,12 @@
     return CAIRO_STATUS_SUCCESS;
 }
 
+static void
+_glyphset_cache_entry_reference (glyphset_cache_entry_t *e)
+{
+    e->refcount++;
+}
+
 static void 
 _xlib_glyphset_cache_destroy_cache (void *cache)
 {
@@ -940,6 +947,9 @@
     g = (glyphset_cache_t *) cache;
     v = (glyphset_cache_entry_t *) entry;
 
+    if (--v->refcount > 0)
+	return;
+
     _cairo_unscaled_font_destroy (v->key.unscaled);
     XRenderFreeGlyphs (g->display, g->glyphset, &(v->glyph), 1);
     free (v);	
@@ -1014,8 +1024,7 @@
 #define N_STACK_BUF 1024
 
 static cairo_status_t
-_cairo_xlib_surface_show_glyphs32 (cairo_unscaled_font_t  *font,
-				   cairo_font_scale_t	  *scale,
+_cairo_xlib_surface_show_glyphs32 (cairo_font_t           *font,
 				   cairo_operator_t       operator,
 				   glyphset_cache_t 	  *g,
 				   cairo_glyph_cache_key_t *key,
@@ -1092,8 +1101,7 @@
 
 
 static cairo_status_t
-_cairo_xlib_surface_show_glyphs16 (cairo_unscaled_font_t  *font,
-				   cairo_font_scale_t	  *scale,
+_cairo_xlib_surface_show_glyphs16 (cairo_font_t           *font,
 				   cairo_operator_t       operator,
 				   glyphset_cache_t 	  *g,
 				   cairo_glyph_cache_key_t *key,
@@ -1169,10 +1177,9 @@
 }
 
 static cairo_status_t
-_cairo_xlib_surface_show_glyphs8 (cairo_unscaled_font_t  *font,
-				  cairo_font_scale_t	  *scale,
+_cairo_xlib_surface_show_glyphs8 (cairo_font_t           *font,
 				  cairo_operator_t       operator,
-				  glyphset_cache_t 	  *g,
+				  glyphset_cache_t 	 *g,
 				  cairo_glyph_cache_key_t *key,
 				  cairo_xlib_surface_t   *src,
 				  cairo_xlib_surface_t   *self,
@@ -1247,8 +1254,7 @@
 
 
 static cairo_status_t
-_cairo_xlib_surface_show_glyphs (cairo_unscaled_font_t  *font,
-				 cairo_font_scale_t	*scale,
+_cairo_xlib_surface_show_glyphs (cairo_font_t           *font,
 				 cairo_operator_t       operator,
 				 cairo_surface_t        *source,
 				 void		        *abstract_surface,
@@ -1305,15 +1311,23 @@
 
     /* Work out the index size to use. */
     elt_size = 8;
-    key.scale = *scale;
-    key.unscaled = font;
+    _cairo_font_get_glyph_cache_key (font, &key);
 
     for (i = 0; i < num_glyphs; ++i) {
 	key.index = glyphs[i].index;
-	status = _cairo_cache_lookup (&g->base, &key, (void **) (&entries[i]));
+	status = _cairo_cache_lookup (&g->base, &key, (void **) (&entries[i]), NULL);
 	if (status != CAIRO_STATUS_SUCCESS || entries[i] == NULL) 
 	    goto UNLOCK;
 
+	/* Referencing the glyph entries we use prevents them from
+	 * being freed if lookup of later entries causes them to
+	 * be ejected from the cache. It would be more efficient
+	 * (though more complex) to prevent them from being ejected
+	 * from the cache at all, so they could get reused later
+	 * in the same string.
+	 */
+	_glyphset_cache_entry_reference (entries[i]);
+
 	if (elt_size == 8 && entries[i]->glyph > 0xff)
 	    elt_size = 16;
 	if (elt_size == 16 && entries[i]->glyph > 0xffff) {
@@ -1325,18 +1339,21 @@
     /* Call the appropriate sub-function. */
 
     if (elt_size == 8)
-	status = _cairo_xlib_surface_show_glyphs8 (font, scale, operator, g, &key, src, self,
+	status = _cairo_xlib_surface_show_glyphs8 (font, operator, g, &key, src, self,
 						    source_x, source_y, 
 						   glyphs, entries, num_glyphs);
     else if (elt_size == 16)
-	status = _cairo_xlib_surface_show_glyphs16 (font, scale, operator, g, &key, src, self,
+	status = _cairo_xlib_surface_show_glyphs16 (font, operator, g, &key, src, self,
 						    source_x, source_y, 
 						    glyphs, entries, num_glyphs);
     else 
-	status = _cairo_xlib_surface_show_glyphs32 (font, scale, operator, g, &key, src, self,
+	status = _cairo_xlib_surface_show_glyphs32 (font, operator, g, &key, src, self,
 						    source_x, source_y, 
 						    glyphs, entries, num_glyphs);
 
+    for (i = 0; i < num_glyphs; ++i)
+	_xlib_glyphset_cache_destroy_entry (g, entries[i]);
+
     _unlock_xlib_glyphset_caches ();
 
     if (tmp != NULL) {

Index: cairoint.h
===================================================================
RCS file: /cvs/cairo/cairo/src/cairoint.h,v
retrieving revision 1.85
retrieving revision 1.86
diff -u -d -r1.85 -r1.86
--- cairoint.h	20 Jan 2005 16:28:54 -0000	1.85
+++ cairoint.h	21 Jan 2005 22:33:48 -0000	1.86
@@ -373,43 +373,49 @@
 
 cairo_private cairo_status_t
 _cairo_cache_lookup (cairo_cache_t *cache,
-		     void *key,
-		     void **entry_return);
+		     void          *key,
+		     void         **entry_return,
+		     int           *created_entry);
+
+cairo_private cairo_status_t
+_cairo_cache_remove (cairo_cache_t *cache,
+		     void          *key);
+
+cairo_private void *
+_cairo_cache_random_entry (cairo_cache_t *cache,
+			   int (*predicate) (void*));
 
 cairo_private unsigned long
 _cairo_hash_string (const char *c);
 
 #define CAIRO_IMAGE_GLYPH_CACHE_MEMORY_DEFAULT 0x100000
 #define CAIRO_XLIB_GLYPH_CACHE_MEMORY_DEFAULT 0x100000
-#define CAIRO_FONT_CACHE_NUM_FONTS_DEFAULT 20
-#define CAIRO_FT_CACHE_NUM_FONTS_DEFAULT 20
 
 typedef struct {
-    double matrix[2][2];
+  double matrix[2][2];
 } cairo_font_scale_t;
 
 struct _cairo_font_backend;
 
+/*
+ * A cairo_unscaled_font_t is just an opaque handle we use in the
+ * glyph cache.
+ */
 typedef struct {
     int refcount;
     const struct _cairo_font_backend *backend;
 } cairo_unscaled_font_t;
 
-/* 
- * A cairo_font contains a pointer to a cairo_unscaled_font_t and a scale
- * matrix. These are the things the user holds references to.
- */
-
 struct _cairo_font {
     int refcount;
-    cairo_font_scale_t scale;
-    cairo_unscaled_font_t *unscaled;
+    cairo_font_scale_t scale;	/* font space => device space */
+    const struct _cairo_font_backend *backend;
 };
 
-/* cairo_font.c is responsible for two global caches: 
+/* cairo_font.c is responsible for a global glyph cache: 
  *  
- *   - font entries:  [[[base], name, weight, slant], cairo_unscaled_font_t ]
- *   - glyph entries: [[[base], cairo_font_t, index], image, size, extents  ]
+ *   - glyph entries: [[[base], cairo_unscaled_font_t, scale, flags, index],
+ *                     image, size, extents]
  *
  * Surfaces may build their own glyph caches if they have surface-specific
  * glyph resources to maintain; those caches can feed off of the global
@@ -420,6 +426,7 @@
     cairo_cache_entry_base_t base;
     cairo_unscaled_font_t *unscaled;
     cairo_font_scale_t scale;
+    int flags;
     unsigned long index;
 } cairo_glyph_cache_key_t;
 
@@ -452,36 +459,34 @@
 /* the font backend interface */
 
 typedef struct _cairo_font_backend {
-    cairo_unscaled_font_t *(*create) (const char		*family,
+    cairo_status_t (*create)         (const char		*family,
 				      cairo_font_slant_t	slant,
-				      cairo_font_weight_t	weight);
+				      cairo_font_weight_t	weight,
+				      cairo_font_scale_t	*scale,
+				      cairo_font_t              **font);
 				    
-    void (*destroy)		     (void			*font);
+    void (*destroy_font)              (void			*font);
+    void (*destroy_unscaled_font)     (void			*font);
 
     cairo_status_t (*font_extents)   (void			*font,
-				      cairo_font_scale_t	*scale,
 				      cairo_font_extents_t	*extents);
 
     cairo_status_t (*text_to_glyphs) (void                      *font,
-				      cairo_font_scale_t	*scale,
 				      const unsigned char	*utf8,
 				      cairo_glyph_t		**glyphs, 
 				      int			*num_glyphs);
 
     cairo_status_t (*glyph_extents)  (void			*font,
-				      cairo_font_scale_t	*scale,
 				      cairo_glyph_t		*glyphs, 
 				      int			num_glyphs,
 				      cairo_text_extents_t	*extents);
 
     cairo_status_t (*glyph_bbox)    (void			*font,
-				     cairo_font_scale_t		*scale,
 				     const cairo_glyph_t	*glyphs,
 				     int			num_glyphs,
 				     cairo_box_t		*bbox);
   
     cairo_status_t (*show_glyphs)    (void			*font,
-				      cairo_font_scale_t	*scale,
 				      cairo_operator_t		operator,
 				      cairo_surface_t		*source,
 				      cairo_surface_t     	*surface,
@@ -491,10 +496,11 @@
 				      int			num_glyphs);
   
     cairo_status_t (*glyph_path)     (void			*font,
-				      cairo_font_scale_t	*scale,
 				      cairo_glyph_t		*glyphs, 
 				      int			num_glyphs,
 				      cairo_path_t		*path);
+    void (*get_glyph_cache_key)      (void                      *font,
+				      cairo_glyph_cache_key_t   *key);
 
     cairo_status_t (*create_glyph) (cairo_image_glyph_cache_entry_t *entry);
 
@@ -603,8 +609,7 @@
      * surface, using image surfaces as glyphs. 
      */    
     cairo_status_t 
-    (*show_glyphs)		(cairo_unscaled_font_t		*font,
-				 cairo_font_scale_t		*scale,
+    (*show_glyphs)		(cairo_font_t		        *font,
 				 cairo_operator_t		operator,
 				 cairo_surface_t		*source,
 				 void				*surface,
@@ -797,7 +802,11 @@
     int num_dashes;
     double dash_offset;
 
-    cairo_unscaled_font_t *font;
+    char *font_family; /* NULL means CAIRO_FONT_FAMILY_DEFAULT; */
+    cairo_font_slant_t font_slant; 
+    cairo_font_weight_t font_weight;
+
+    cairo_font_t *font;		/* Specific to the current CTM */
 
     cairo_surface_t *surface;
 
@@ -1119,6 +1128,10 @@
 _cairo_gstate_scale_font (cairo_gstate_t *gstate, 
 			  double scale);
 
+cairo_private void
+_cairo_gstate_current_font_scale (cairo_gstate_t     *gstate,
+				  cairo_font_scale_t *sc);
+    
 cairo_private cairo_status_t
 _cairo_gstate_transform_font (cairo_gstate_t *gstate, 
 			      cairo_matrix_t *matrix);
@@ -1184,19 +1197,21 @@
 
 /* cairo_font.c */
 
-cairo_private cairo_unscaled_font_t *
-_cairo_unscaled_font_create (const char           *family, 
-			     cairo_font_slant_t   slant, 
-			     cairo_font_weight_t  weight);
+cairo_private cairo_status_t
+_cairo_font_create (const char           *family, 
+		    cairo_font_slant_t   slant, 
+		    cairo_font_weight_t  weight,
+		    cairo_font_scale_t   *sc,
+		    cairo_font_t         **font);
 
 cairo_private void
-_cairo_font_init (cairo_font_t 			*scaled, 
-		  cairo_font_scale_t 		*scale,
-		  cairo_unscaled_font_t 	*unscaled);
+_cairo_font_init (cairo_font_t 		     *font, 
+		  cairo_font_scale_t 	     *scale,
+		  const cairo_font_backend_t *backend);
 
-cairo_private cairo_status_t
-_cairo_unscaled_font_init (cairo_unscaled_font_t		*font, 
-			   const struct _cairo_font_backend 	*backend);
+cairo_private void
+_cairo_unscaled_font_init (cairo_unscaled_font_t	    *font, 
+			   const struct _cairo_font_backend *backend);
 
 cairo_private void
 _cairo_unscaled_font_reference (cairo_unscaled_font_t *font);
@@ -1205,48 +1220,52 @@
 _cairo_unscaled_font_destroy (cairo_unscaled_font_t *font);
 
 cairo_private cairo_status_t
-_cairo_unscaled_font_font_extents (cairo_unscaled_font_t 	*font, 
-				   cairo_font_scale_t 		*scale,
-				   cairo_font_extents_t		*extents);
+_cairo_font_font_extents (cairo_font_t 	       *font, 
+			  cairo_font_extents_t *extents);
 
 cairo_private cairo_status_t
-_cairo_unscaled_font_text_to_glyphs (cairo_unscaled_font_t	*font,
-				     cairo_font_scale_t 	*scale,
-				     const unsigned char 	*utf8, 
-				     cairo_glyph_t 		**glyphs, 
-				     int 			*num_glyphs);
+_cairo_font_text_to_glyphs (cairo_font_t	 *font,
+			    const unsigned char  *utf8, 
+			    cairo_glyph_t 	**glyphs, 
+			    int 		 *num_glyphs);
 
 cairo_private cairo_status_t
-_cairo_unscaled_font_glyph_extents (cairo_unscaled_font_t	*font,
-				    cairo_font_scale_t 		*scale,
-				    cairo_glyph_t 		*glyphs,
-				    int 			num_glyphs,
-				    cairo_text_extents_t 	*extents);
+_cairo_font_glyph_extents (cairo_font_t	        *font,
+			   cairo_glyph_t 	*glyphs,
+			   int 			num_glyphs,
+			   cairo_text_extents_t *extents);
 
 cairo_private cairo_status_t
-_cairo_unscaled_font_glyph_bbox (cairo_unscaled_font_t          *font,
-				 cairo_font_scale_t 		*size,
-				 cairo_glyph_t           	*glyphs,
-				 int                     	num_glyphs,
-				 cairo_box_t			*bbox);
+_cairo_font_glyph_bbox (cairo_font_t          *font,
+			cairo_glyph_t         *glyphs,
+			int                   num_glyphs,
+			cairo_box_t	      *bbox);
 
 cairo_private cairo_status_t
-_cairo_unscaled_font_show_glyphs (cairo_unscaled_font_t         *font,
-				  cairo_font_scale_t		*size,
-				  cairo_operator_t       	operator,
-				  cairo_surface_t        	*source,
-				  cairo_surface_t        	*surface,
-				  int                    	source_x,
-				  int                    	source_y,
-				  cairo_glyph_t          	*glyphs,
-				  int                    	num_glyphs);
+_cairo_font_show_glyphs (cairo_font_t        *font,
+			 cairo_operator_t    operator,
+			 cairo_surface_t     *source,
+			 cairo_surface_t     *surface,
+			 int                 source_x,
+			 int                 source_y,
+			 cairo_glyph_t       *glyphs,
+			 int                 num_glyphs);
 
 cairo_private cairo_status_t
-_cairo_unscaled_font_glyph_path (cairo_unscaled_font_t          	*font,
-				 cairo_font_scale_t		*size,
-				 cairo_glyph_t           	*glyphs, 
-				 int                     	num_glyphs,
-				 cairo_path_t            	*path);
+_cairo_font_glyph_path (cairo_font_t        *font,
+			cairo_glyph_t       *glyphs, 
+			int                 num_glyphs,
+			cairo_path_t        *path);
+
+cairo_private cairo_status_t
+_cairo_font_glyph_path (cairo_font_t        *font,
+			cairo_glyph_t       *glyphs, 
+			int                 num_glyphs,
+			cairo_path_t        *path);
+
+cairo_private void
+_cairo_font_get_glyph_cache_key (cairo_font_t            *font,
+				 cairo_glyph_cache_key_t *key);
 
 /* cairo_hull.c */
 cairo_private cairo_status_t




More information about the cairo-commit mailing list