[cairo-commit] src/cairo-font-face.c src/cairo-ft-font.c src/cairoint.h src/cairo-quartz-font.c src/cairo-scaled-font.c src/cairo-user-font.c src/cairo-win32-font.c

Behdad Esfahbod behdad at kemper.freedesktop.org
Wed Dec 17 12:13:51 PST 2008


 src/cairo-font-face.c   |  143 +++++++++---------
 src/cairo-ft-font.c     |  371 ++++++++++++++++++++++++++++--------------------
 src/cairo-quartz-font.c |  208 ++++++++++----------------
 src/cairo-scaled-font.c |   19 +-
 src/cairo-user-font.c   |   62 --------
 src/cairo-win32-font.c  |   20 --
 src/cairoint.h          |   40 ++---
 7 files changed, 412 insertions(+), 451 deletions(-)

New commits:
commit f7ab65e9b0c0f08be8d294e90131baa2decf1f1d
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Wed Dec 17 06:25:50 2008 -0500

    Clean up toy font face handling
    
    This commit moves the toy-to-real mapping from the scaled font creation
    time to font face creation.  A toy font face will keep an internal ref
    to an implementation face.  Then cairo_scaled_font_create() will simply
    substitute the implementation face before creating anything.
    
    This also modifies the cairo-ft toy creation in that we now create a
    non-resolved pattern and store it in a cairo-ft font-face.  We then
    do the resolving and unscaled font creation at scaled-font creation
    time.  This also means that cairo_ft_font_face_create_for_pattern()
    now accepts non-resolved patterns too, and does the right thing about
    them.  As much as that can be called right.
    
    Some testing of toy font creation performance is in order, as is testing
    win32 and quartz font backends.

diff --git a/src/cairo-font-face.c b/src/cairo-font-face.c
index a78c2aa..8481b12 100644
--- a/src/cairo-font-face.c
+++ b/src/cairo-font-face.c
@@ -56,7 +56,8 @@ const cairo_toy_font_face_t _cairo_font_face_nil = {
     CAIRO_FONT_FAMILY_DEFAULT,		/* family */
     TRUE,				/* owns_family */
     CAIRO_FONT_SLANT_DEFAULT,		/* slant */
-    CAIRO_FONT_WEIGHT_DEFAULT		/* weight */
+    CAIRO_FONT_WEIGHT_DEFAULT,		/* weight */
+    NULL				/* impl_face */
 };
 
 static const cairo_toy_font_face_t _cairo_font_face_null_pointer = {
@@ -70,7 +71,8 @@ static const cairo_toy_font_face_t _cairo_font_face_null_pointer = {
     CAIRO_FONT_FAMILY_DEFAULT,		/* family */
     TRUE,				/* owns_family */
     CAIRO_FONT_SLANT_DEFAULT,		/* slant */
-    CAIRO_FONT_WEIGHT_DEFAULT		/* weight */
+    CAIRO_FONT_WEIGHT_DEFAULT,		/* weight */
+    NULL				/* impl_face */
 };
 
 static const cairo_toy_font_face_t _cairo_font_face_invalid_string = {
@@ -84,7 +86,8 @@ static const cairo_toy_font_face_t _cairo_font_face_invalid_string = {
     CAIRO_FONT_FAMILY_DEFAULT,		/* family */
     TRUE,				/* owns_family */
     CAIRO_FONT_SLANT_DEFAULT,		/* slant */
-    CAIRO_FONT_WEIGHT_DEFAULT		/* weight */
+    CAIRO_FONT_WEIGHT_DEFAULT,		/* weight */
+    NULL				/* impl_face */
 };
 
 static const cairo_toy_font_face_t _cairo_font_face_invalid_slant = {
@@ -98,7 +101,8 @@ static const cairo_toy_font_face_t _cairo_font_face_invalid_slant = {
     CAIRO_FONT_FAMILY_DEFAULT,		/* family */
     TRUE,				/* owns_family */
     CAIRO_FONT_SLANT_DEFAULT,		/* slant */
-    CAIRO_FONT_WEIGHT_DEFAULT		/* weight */
+    CAIRO_FONT_WEIGHT_DEFAULT,		/* weight */
+    NULL				/* impl_face */
 };
 
 static const cairo_toy_font_face_t _cairo_font_face_invalid_weight = {
@@ -112,7 +116,8 @@ static const cairo_toy_font_face_t _cairo_font_face_invalid_weight = {
     CAIRO_FONT_FAMILY_DEFAULT,		/* family */
     TRUE,				/* owns_family */
     CAIRO_FONT_SLANT_DEFAULT,		/* slant */
-    CAIRO_FONT_WEIGHT_DEFAULT		/* weight */
+    CAIRO_FONT_WEIGHT_DEFAULT,		/* weight */
+    NULL				/* impl_face */
 };
 
 cairo_status_t
@@ -223,6 +228,9 @@ slim_hidden_def (cairo_font_face_destroy);
 cairo_font_type_t
 cairo_font_face_get_type (cairo_font_face_t *font_face)
 {
+    if (CAIRO_REFERENCE_COUNT_IS_INVALID (&font_face->ref_count))
+	return CAIRO_FONT_TYPE_TOY;
+
     return font_face->backend->type;
 }
 
@@ -389,6 +397,41 @@ _cairo_toy_font_face_init_key (cairo_toy_font_face_t *key,
     key->base.hash_entry.hash = hash;
 }
 
+static cairo_font_face_t *
+_cairo_toy_font_face_create_impl_face (cairo_toy_font_face_t *font_face)
+{
+    const cairo_font_face_backend_t * backend = CAIRO_FONT_FACE_BACKEND_DEFAULT;
+    cairo_font_face_t *impl_font_face;
+    cairo_status_t status;
+
+    if (font_face->base.status)
+	return NULL;
+
+    if (backend->create_for_toy == NULL ||
+	(CAIRO_FONT_FACE_BACKEND_DEFAULT != &_cairo_user_font_face_backend &&
+	 0 == strcmp (font_face->family, CAIRO_USER_FONT_FAMILY_DEFAULT)))
+    {
+	backend = &_cairo_user_font_face_backend;
+    }
+
+    if (backend->create_for_toy == NULL) {
+	ASSERT_NOT_REACHED;
+	return NULL;
+    }
+
+    status = backend->create_for_toy (font_face, &impl_font_face);
+
+    if (_cairo_font_face_set_error (&font_face->base, status))
+	return NULL;
+
+    if (_cairo_font_face_set_error (&font_face->base, impl_font_face->status)) {
+	cairo_font_face_destroy (impl_font_face);
+	return NULL;
+    }
+
+    return impl_font_face;
+}
+
 static cairo_status_t
 _cairo_toy_font_face_init (cairo_toy_font_face_t *font_face,
 			   const char	         *family,
@@ -405,8 +448,12 @@ _cairo_toy_font_face_init (cairo_toy_font_face_t *font_face,
 				      slant, weight);
     font_face->owns_family = TRUE;
 
+    font_face->impl_face = NULL;
+
     _cairo_font_face_init (&font_face->base, &_cairo_toy_font_face_backend);
 
+    font_face->impl_face = _cairo_toy_font_face_create_impl_face (font_face);
+
     return CAIRO_STATUS_SUCCESS;
 }
 
@@ -417,6 +464,9 @@ _cairo_toy_font_face_fini (cairo_toy_font_face_t *font_face)
      * away the const qualifer. */
     assert (font_face->owns_family);
     free ((char*) font_face->family);
+
+    if (font_face->impl_face)
+	cairo_font_face_destroy (font_face->impl_face);
 }
 
 static int
@@ -570,81 +620,17 @@ _cairo_toy_font_face_destroy (void *abstract_face)
 }
 
 static cairo_status_t
-_cairo_toy_font_face_scaled_font_get_implementation (void                *abstract_font_face,
-						     cairo_font_face_t **font_face_out)
-{
-    cairo_toy_font_face_t *font_face = abstract_font_face;
-    cairo_status_t status;
-
-    if (font_face->base.status)
-	return font_face->base.status;
-
-    if (CAIRO_SCALED_FONT_BACKEND_DEFAULT != &_cairo_user_scaled_font_backend &&
-	0 != strcmp (font_face->family, CAIRO_USER_FONT_FAMILY_DEFAULT))
-    {
-	const cairo_scaled_font_backend_t * backend = CAIRO_SCALED_FONT_BACKEND_DEFAULT;
-
-	if (backend->get_implementation == NULL) {
-	    *font_face_out = &font_face->base;
-	    return CAIRO_STATUS_SUCCESS;
-	}
-
-	status = backend->get_implementation (font_face,
-					      font_face_out);
-
-	if (status != CAIRO_INT_STATUS_UNSUPPORTED)
-	    return _cairo_font_face_set_error (&font_face->base, status);
-    }
-
-    status = _cairo_user_scaled_font_backend.get_implementation (font_face,
-								 font_face_out);
-
-    return _cairo_font_face_set_error (&font_face->base, status);
-}
-
-static cairo_status_t
 _cairo_toy_font_face_scaled_font_create (void                *abstract_font_face,
 					 const cairo_matrix_t       *font_matrix,
 					 const cairo_matrix_t       *ctm,
 					 const cairo_font_options_t *options,
 					 cairo_scaled_font_t	   **scaled_font)
 {
-    cairo_toy_font_face_t *font_face = abstract_font_face;
-    cairo_status_t status;
-
-    if (font_face->base.status)
-	return font_face->base.status;
+    cairo_toy_font_face_t *font_face = (cairo_toy_font_face_t *) abstract_font_face;
 
-    status = cairo_font_options_status ((cairo_font_options_t *) options);
-    if (unlikely (status))
-	return status;
+    ASSERT_NOT_REACHED;
 
-    if (CAIRO_SCALED_FONT_BACKEND_DEFAULT != &_cairo_user_scaled_font_backend &&
-	0 != strcmp (font_face->family, CAIRO_USER_FONT_FAMILY_DEFAULT))
-    {
-	const cairo_scaled_font_backend_t * backend = CAIRO_SCALED_FONT_BACKEND_DEFAULT;
-
-	*scaled_font = NULL;
-	status =  backend->create_toy (font_face,
-				       font_matrix,
-				       ctm,
-				       options,
-				       scaled_font);
-
-	if (status != CAIRO_INT_STATUS_UNSUPPORTED)
-	    return _cairo_font_face_set_error (&font_face->base, status);
-
-	if (*scaled_font)
-	    cairo_scaled_font_destroy (*scaled_font);
-    }
-
-    status = _cairo_user_scaled_font_backend.create_toy (font_face,
-							 font_matrix,
-							 ctm,
-							 options,
-							 scaled_font);
-
-    return _cairo_font_face_set_error (&font_face->base, status);
+    return _cairo_font_face_set_error (&font_face->base, CAIRO_STATUS_FONT_TYPE_MISMATCH);
 }
 
 static cairo_bool_t
@@ -653,6 +639,17 @@ _cairo_font_face_is_toy (cairo_font_face_t *font_face)
     return font_face->backend == &_cairo_toy_font_face_backend;
 }
 
+cairo_font_face_t *
+_cairo_toy_font_face_get_implementation (cairo_font_face_t *font_face)
+{
+    cairo_toy_font_face_t *toy_font_face = (cairo_toy_font_face_t *) font_face;
+    if (! _cairo_font_face_is_toy (font_face)) {
+	if (_cairo_font_face_set_error (font_face, CAIRO_STATUS_FONT_TYPE_MISMATCH))
+	    return NULL;
+    }
+    return toy_font_face->impl_face ? toy_font_face->impl_face : font_face;
+}
+
 /**
  * cairo_toy_font_face_get_family:
  * @font_face: A toy font face
@@ -722,8 +719,8 @@ slim_hidden_def (cairo_toy_font_face_get_weight);
 
 static const cairo_font_face_backend_t _cairo_toy_font_face_backend = {
     CAIRO_FONT_TYPE_TOY,
+    NULL,					/* create_for_toy */
     _cairo_toy_font_face_destroy,
-    _cairo_toy_font_face_scaled_font_get_implementation,
     _cairo_toy_font_face_scaled_font_create
 };
 
diff --git a/src/cairo-ft-font.c b/src/cairo-ft-font.c
index 773f6ea..bc23a3d 100644
--- a/src/cairo-ft-font.c
+++ b/src/cairo-ft-font.c
@@ -134,13 +134,25 @@ typedef struct _cairo_ft_options {
 
 struct _cairo_ft_font_face {
     cairo_font_face_t base;
+
     cairo_ft_unscaled_font_t *unscaled;
     cairo_ft_options_t ft_options;
     cairo_ft_font_face_t *next;
+
+    FcPattern *pattern; /* if pattern is set, the above fields will be NULL */
 };
 
 static const cairo_unscaled_font_backend_t cairo_ft_unscaled_font_backend;
 
+static cairo_status_t
+_cairo_ft_resolve_pattern (FcPattern		      *pattern,
+			   const cairo_matrix_t       *font_matrix,
+			   const cairo_matrix_t       *ctm,
+			   const cairo_font_options_t *options,
+			   cairo_ft_unscaled_font_t  **unscaled,
+			   cairo_ft_options_t	      *ft_options);
+
+
 /*
  * We maintain a hash table to map file/id => #cairo_ft_unscaled_font_t.
  * The hash table itself isn't limited in size. However, we limit the
@@ -469,21 +481,20 @@ _cairo_ft_unscaled_font_create_for_pattern (FcPattern *pattern)
     char *filename = NULL;
     int id = 0;
 
-    if (FcPatternGetFTFace (pattern, FC_FT_FACE, 0, &font_face) != FcResultMatch) {
-	FcChar8 *fc_filename = NULL;
-
-	if (FcPatternGetString (pattern, FC_FILE, 0, &fc_filename) != FcResultMatch)
-	    goto UNWIND;
-	filename = (char *) fc_filename;
+    if (FcPatternGetFTFace (pattern, FC_FT_FACE, 0, &font_face) == FcResultMatch)
+	goto DONE;
 
-	if (FcPatternGetInteger (pattern, FC_INDEX, 0, &id) != FcResultMatch)
-	    goto UNWIND;
+    if (FcPatternGetString (pattern, FC_FILE, 0, (FcChar8 **) &filename) == FcResultMatch) {
+	/* If FC_INDEX is not set, we just use 0 */
+        FcPatternGetInteger (pattern, FC_INDEX, 0, &id);
+	goto DONE;
     }
 
+    return NULL;
+
+DONE:
     return _cairo_ft_unscaled_font_create_internal (font_face != NULL, filename, id, font_face);
 
-UNWIND:
-    return NULL;
 }
 
 static cairo_ft_unscaled_font_t *
@@ -1282,7 +1293,7 @@ typedef struct _cairo_ft_scaled_font {
     cairo_ft_options_t ft_options;
 } cairo_ft_scaled_font_t;
 
-const cairo_scaled_font_backend_t _cairo_ft_scaled_font_backend;
+static const cairo_scaled_font_backend_t _cairo_ft_scaled_font_backend;
 
 /* The load flags passed to FT_Load_Glyph control aspects like hinting and
  * antialiasing. Here we compute them from the fields of a FcPattern.
@@ -1608,121 +1619,6 @@ _cairo_scaled_font_is_ft (cairo_scaled_font_t *scaled_font)
     return scaled_font->backend == &_cairo_ft_scaled_font_backend;
 }
 
-static cairo_status_t
-_cairo_ft_scaled_font_create_toy (cairo_toy_font_face_t	      *toy_face,
-				  const cairo_matrix_t	      *font_matrix,
-				  const cairo_matrix_t	      *ctm,
-				  const cairo_font_options_t  *font_options,
-				  cairo_scaled_font_t	     **font)
-{
-    FcPattern *pattern, *resolved;
-    cairo_ft_unscaled_font_t *unscaled;
-    FcResult result;
-    int fcslant;
-    int fcweight;
-    cairo_matrix_t scale;
-    cairo_status_t status;
-    cairo_ft_font_transform_t sf;
-    cairo_ft_options_t ft_options;
-
-    cairo_matrix_multiply (&scale, font_matrix, ctm);
-    status = _compute_transform (&sf, &scale);
-    if (unlikely (status))
-	return status;
-
-    pattern = FcPatternCreate ();
-    if (!pattern)
-	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-
-    if (!FcPatternAddString (pattern,
-		             FC_FAMILY, (unsigned char *) toy_face->family))
-    {
-	status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
-	goto FREE_PATTERN;
-    }
-
-    switch (toy_face->slant)
-    {
-    case CAIRO_FONT_SLANT_ITALIC:
-        fcslant = FC_SLANT_ITALIC;
-        break;
-    case CAIRO_FONT_SLANT_OBLIQUE:
-	fcslant = FC_SLANT_OBLIQUE;
-        break;
-    case CAIRO_FONT_SLANT_NORMAL:
-    default:
-        fcslant = FC_SLANT_ROMAN;
-        break;
-    }
-
-    if (!FcPatternAddInteger (pattern, FC_SLANT, fcslant)) {
-	status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
-	goto FREE_PATTERN;
-    }
-
-    switch (toy_face->weight)
-    {
-    case CAIRO_FONT_WEIGHT_BOLD:
-        fcweight = FC_WEIGHT_BOLD;
-        break;
-    case CAIRO_FONT_WEIGHT_NORMAL:
-    default:
-        fcweight = FC_WEIGHT_MEDIUM;
-        break;
-    }
-
-    if (!FcPatternAddInteger (pattern, FC_WEIGHT, fcweight)) {
-	status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
-	goto FREE_PATTERN;
-    }
-
-    if (! FcPatternAddDouble (pattern, FC_PIXEL_SIZE, sf.y_scale)) {
-	status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
-	goto FREE_PATTERN;
-    }
-
-    if (! FcConfigSubstitute (NULL, pattern, FcMatchPattern)) {
-	status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
-	goto FREE_PATTERN;
-    }
-
-    status = _cairo_ft_font_options_substitute (font_options, pattern);
-    if (unlikely (status))
-	goto FREE_PATTERN;
-
-    FcDefaultSubstitute (pattern);
-
-    resolved = FcFontMatch (NULL, pattern, &result);
-    if (!resolved) {
-	status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
-	goto FREE_PATTERN;
-    }
-
-    unscaled = _cairo_ft_unscaled_font_create_for_pattern (resolved);
-    if (!unscaled) {
-	status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
-	goto FREE_RESOLVED;
-    }
-
-    _get_pattern_ft_options (resolved, &ft_options);
-
-    status = _cairo_ft_scaled_font_create (unscaled,
-					   &toy_face->base,
-					   font_matrix, ctm,
-					   font_options, ft_options,
-					   font);
-
-    _cairo_unscaled_font_destroy (&unscaled->base);
-
- FREE_RESOLVED:
-    FcPatternDestroy (resolved);
-
- FREE_PATTERN:
-    FcPatternDestroy (pattern);
-
-    return status;
-}
-
 static void
 _cairo_ft_scaled_font_fini (void *abstract_font)
 {
@@ -2212,10 +2108,8 @@ _cairo_ft_index_to_ucs4(void	        *abstract_font,
     return CAIRO_STATUS_SUCCESS;
 }
 
-const cairo_scaled_font_backend_t _cairo_ft_scaled_font_backend = {
+static const cairo_scaled_font_backend_t _cairo_ft_scaled_font_backend = {
     CAIRO_FONT_TYPE_FT,
-    NULL,
-    _cairo_ft_scaled_font_create_toy,
     _cairo_ft_scaled_font_fini,
     _cairo_ft_scaled_glyph_init,
     NULL,			/* text_to_glyphs */
@@ -2227,6 +2121,72 @@ const cairo_scaled_font_backend_t _cairo_ft_scaled_font_backend = {
 
 /* #cairo_ft_font_face_t */
 
+static cairo_font_face_t *
+_cairo_ft_font_face_create_for_pattern (FcPattern *pattern);
+
+static cairo_status_t
+_cairo_ft_font_face_create_for_toy (cairo_toy_font_face_t   *toy_face,
+				    cairo_font_face_t      **font_face)
+{
+    FcPattern *pattern;
+    int fcslant;
+    int fcweight;
+    cairo_status_t status = CAIRO_STATUS_SUCCESS;
+
+    pattern = FcPatternCreate ();
+    if (!pattern)
+	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+    if (!FcPatternAddString (pattern,
+		             FC_FAMILY, (unsigned char *) toy_face->family))
+    {
+	status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+	goto FREE_PATTERN;
+    }
+
+    switch (toy_face->slant)
+    {
+    case CAIRO_FONT_SLANT_ITALIC:
+        fcslant = FC_SLANT_ITALIC;
+        break;
+    case CAIRO_FONT_SLANT_OBLIQUE:
+	fcslant = FC_SLANT_OBLIQUE;
+        break;
+    case CAIRO_FONT_SLANT_NORMAL:
+    default:
+        fcslant = FC_SLANT_ROMAN;
+        break;
+    }
+
+    if (!FcPatternAddInteger (pattern, FC_SLANT, fcslant)) {
+	status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+	goto FREE_PATTERN;
+    }
+
+    switch (toy_face->weight)
+    {
+    case CAIRO_FONT_WEIGHT_BOLD:
+        fcweight = FC_WEIGHT_BOLD;
+        break;
+    case CAIRO_FONT_WEIGHT_NORMAL:
+    default:
+        fcweight = FC_WEIGHT_MEDIUM;
+        break;
+    }
+
+    if (!FcPatternAddInteger (pattern, FC_WEIGHT, fcweight)) {
+	status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+	goto FREE_PATTERN;
+    }
+
+    *font_face = _cairo_ft_font_face_create_for_pattern (pattern);
+
+ FREE_PATTERN:
+    FcPatternDestroy (pattern);
+
+    return status;
+}
+
 static void
 _cairo_ft_font_face_destroy (void *abstract_face)
 {
@@ -2283,6 +2243,9 @@ _cairo_ft_font_face_destroy (void *abstract_face)
 	_cairo_unscaled_font_destroy (&font_face->unscaled->base);
 	font_face->unscaled = NULL;
     }
+
+    if (font_face->pattern)
+	FcPatternDestroy (font_face->pattern);
 }
 
 static cairo_status_t
@@ -2292,8 +2255,9 @@ _cairo_ft_font_face_scaled_font_create (void                     *abstract_face,
 					const cairo_font_options_t *options,
 					cairo_scaled_font_t       **scaled_font)
 {
-    cairo_ft_font_face_t *font_face = abstract_face;
-    cairo_ft_options_t ft_options;
+    cairo_ft_font_face_t      *font_face = abstract_face;
+    cairo_ft_unscaled_font_t  *unscaled = NULL;
+    cairo_ft_options_t         ft_options;
 
     /* The handling of font options is different depending on how the
      * font face was created. When the user creates a font face with
@@ -2309,23 +2273,67 @@ _cairo_ft_font_face_scaled_font_create (void                     *abstract_face,
      * 2. What if the face is coming from FC_FT_FACE of a pattern?
      */
 
-    ft_options = font_face->ft_options;
+    /* If we have an unresolved pattern, resolve it and create
+     * unscaled font.  Otherwise, use the ones stored in font_face.
+     */
+    if (font_face->pattern) {
+	cairo_status_t status;
+
+	status = _cairo_ft_resolve_pattern (font_face->pattern,
+					    font_matrix,
+					    ctm,
+					    options,
+					    &unscaled,
+					    &ft_options);
+	if (unlikely (status))
+		return status;
+
+    } else {
+	unscaled = font_face->unscaled;
+	ft_options = font_face->ft_options;
+    }
 
-    return  _cairo_ft_scaled_font_create (font_face->unscaled,
+    return  _cairo_ft_scaled_font_create (unscaled,
 					  &font_face->base,
 					  font_matrix, ctm,
 					  options, ft_options,
 					  scaled_font);
 }
 
-static const cairo_font_face_backend_t _cairo_ft_font_face_backend = {
+const cairo_font_face_backend_t _cairo_ft_font_face_backend = {
     CAIRO_FONT_TYPE_FT,
+    _cairo_ft_font_face_create_for_toy,
     _cairo_ft_font_face_destroy,
-    NULL, /* direct implementation */
     _cairo_ft_font_face_scaled_font_create
 };
 
 static cairo_font_face_t *
+_cairo_ft_font_face_create_for_pattern (FcPattern *pattern)
+{
+    cairo_ft_font_face_t *font_face;
+
+    font_face = malloc (sizeof (cairo_ft_font_face_t));
+    if (unlikely (!font_face)) {
+	_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
+	return (cairo_font_face_t *)&_cairo_font_face_nil;
+    }
+
+    font_face->unscaled = NULL;
+    font_face->next = NULL;
+
+    font_face->pattern = FcPatternDuplicate (pattern);
+    if (unlikely (!pattern)) {
+	free (font_face);
+	_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
+	return (cairo_font_face_t *)&_cairo_font_face_nil;
+    }
+
+    _cairo_font_face_init (&font_face->base, &_cairo_ft_font_face_backend);
+
+    return &font_face->base;
+}
+
+static cairo_font_face_t *
 _cairo_ft_font_face_create (cairo_ft_unscaled_font_t *unscaled,
 			    cairo_ft_options_t	     *ft_options)
 {
@@ -2351,7 +2359,7 @@ _cairo_ft_font_face_create (cairo_ft_unscaled_font_t *unscaled,
 
     /* No match found, create a new one */
     font_face = malloc (sizeof (cairo_ft_font_face_t));
-    if (!font_face) {
+    if (unlikely (!font_face)) {
 	_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
 	return (cairo_font_face_t *)&_cairo_font_face_nil;
     }
@@ -2364,6 +2372,8 @@ _cairo_ft_font_face_create (cairo_ft_unscaled_font_t *unscaled,
     font_face->next = unscaled->faces;
     unscaled->faces = font_face;
 
+    font_face->pattern = NULL;
+
     _cairo_font_face_init (&font_face->base, &_cairo_ft_font_face_backend);
 
     return &font_face->base;
@@ -2488,15 +2498,76 @@ cairo_ft_font_options_substitute (const cairo_font_options_t *options,
     _cairo_ft_font_options_substitute (options, pattern);
 }
 
+static cairo_status_t
+_cairo_ft_resolve_pattern (FcPattern		      *pattern,
+			   const cairo_matrix_t       *font_matrix,
+			   const cairo_matrix_t       *ctm,
+			   const cairo_font_options_t *font_options,
+			   cairo_ft_unscaled_font_t  **unscaled,
+			   cairo_ft_options_t	      *ft_options)
+{
+    cairo_status_t status;
+
+    cairo_matrix_t scale;
+    FcPattern *resolved;
+    cairo_ft_font_transform_t sf;
+    FcResult result;
+
+    scale = *ctm;
+    scale.x0 = scale.y0 = 0;
+    cairo_matrix_multiply (&scale,
+                           font_matrix,
+                           &scale);
+
+    status = _compute_transform (&sf, &scale);
+    if (status)
+	return status;
+
+    pattern = FcPatternDuplicate (pattern);
+
+    if (! FcPatternAddDouble (pattern, FC_PIXEL_SIZE, sf.y_scale)) {
+	status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+	goto FREE_PATTERN;
+    }
+
+    if (! FcConfigSubstitute (NULL, pattern, FcMatchPattern)) {
+	status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+	goto FREE_PATTERN;
+    }
+
+    status = _cairo_ft_font_options_substitute (font_options, pattern);
+    if (status)
+	goto FREE_PATTERN;
+
+    FcDefaultSubstitute (pattern);
+
+    resolved = FcFontMatch (NULL, pattern, &result);
+    if (!resolved) {
+	status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+	goto FREE_PATTERN;
+    }
+
+    *unscaled = _cairo_ft_unscaled_font_create_for_pattern (resolved);
+    if (!*unscaled) {
+	status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+	goto FREE_RESOLVED;
+    }
+
+    _get_pattern_ft_options (resolved, ft_options);
+
+FREE_RESOLVED:
+    FcPatternDestroy (resolved);
+
+FREE_PATTERN:
+    FcPatternDestroy (pattern);
+
+    return status;
+}
+
 /**
  * cairo_ft_font_face_create_for_pattern:
- * @pattern: A fully resolved fontconfig
- *   pattern. A pattern can be resolved, by, among other things, calling
- *   FcConfigSubstitute(), FcDefaultSubstitute(), then
- *   FcFontMatch(). Cairo will call FcPatternReference() on this
- *   pattern, so you should not further modify the pattern, but you can
- *   release your reference to the pattern with FcPatternDestroy() if
- *   you no longer need to access it.
+ * @pattern: A fontconfig pattern.  Cairo makes a copy of the pattern
+ * if it needs to.  You are free to modify or free @pattern after this call.
  *
  * Creates a new font face for the FreeType font backend based on a
  * fontconfig pattern. This font can then be used with
@@ -2513,8 +2584,13 @@ cairo_ft_font_options_substitute (const cairo_font_options_t *options,
  *
  * The pattern's FC_FT_FACE element is inspected first and if that is set,
  * that will be the FreeType font face associated with the returned cairo
- * font face.  Otherwise the FC_FILE and FC_INDEX elements of @pattern are
- * used to load a font face from file.
+ * font face.  Otherwise the FC_FILE element is checked.  If it's set,
+ * that and the value of the FC_INDEX element (defaults to zero) of @pattern
+ * are used to load a font face from file.
+ *
+ * If both steps from the previous paragraph fails, @pattern will be passed
+ * to FcConfigSubstitute, FcDefaultSubstitute, and finally FcFontMatch,
+ * and the resulting font pattern is used.
  *
  * If the FC_FT_FACE element of @pattern is set, the user is responsible
  * for making sure that the referenced FT_Face remains valid for the life
@@ -2534,8 +2610,9 @@ cairo_ft_font_face_create_for_pattern (FcPattern *pattern)
 
     unscaled = _cairo_ft_unscaled_font_create_for_pattern (pattern);
     if (unlikely (unscaled == NULL)) {
-	_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
-	return (cairo_font_face_t *)&_cairo_font_face_nil;
+	/* Store the pattern.  We will resolve it and create unscaled
+	 * font when creating scaled fonts */
+	return _cairo_ft_font_face_create_for_pattern (pattern);
     }
 
     _get_pattern_ft_options (pattern, &ft_options);
diff --git a/src/cairo-quartz-font.c b/src/cairo-quartz-font.c
index 2bca372..a54dacd 100644
--- a/src/cairo-quartz-font.c
+++ b/src/cairo-quartz-font.c
@@ -131,6 +131,77 @@ struct _cairo_quartz_font_face {
  * font face backend
  */
 
+static cairo_status_t
+_cairo_quartz_font_face_create_for_toy (cairo_toy_font_face_t   *toy_face,
+					cairo_font_face_t      **font_face)
+{
+    const char *family = toy_face->family;
+    char *full_name = malloc(strlen(family) + 64); // give us a bit of room to tack on Bold, Oblique, etc.
+    CFStringRef cgFontName = NULL;
+    CGFontRef cgFont = NULL;
+    int loop;
+
+    quartz_font_ensure_symbols();
+    if (! _cairo_quartz_font_symbols_present)
+	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+    /* handle CSS-ish faces */
+    if (!strcmp(family, "serif") || !strcmp(family, "Times Roman"))
+	family = "Times";
+    else if (!strcmp(family, "sans-serif") || !strcmp(family, "sans"))
+	family = "Helvetica";
+    else if (!strcmp(family, "cursive"))
+	family = "Apple Chancery";
+    else if (!strcmp(family, "fantasy"))
+	family = "Papyrus";
+    else if (!strcmp(family, "monospace") || !strcmp(family, "mono"))
+	family = "Courier";
+
+    /* Try to build up the full name, e.g. "Helvetica Bold Oblique" first,
+     * then drop the bold, then drop the slant, then drop both.. finally
+     * just use "Helvetica".  And if Helvetica doesn't exist, give up.
+     */
+    for (loop = 0; loop < 5; loop++) {
+	if (loop == 4)
+	    family = "Helvetica";
+
+	strcpy (full_name, family);
+
+	if (loop < 3 && (loop & 1) == 0) {
+	    if (toy_face->weight == CAIRO_FONT_WEIGHT_BOLD)
+		strcat (full_name, " Bold");
+	}
+
+	if (loop < 3 && (loop & 2) == 0) {
+	    if (toy_face->slant == CAIRO_FONT_SLANT_ITALIC)
+		strcat (full_name, " Italic");
+	    else if (toy_face->slant == CAIRO_FONT_SLANT_OBLIQUE)
+		strcat (full_name, " Oblique");
+	}
+
+	if (CGFontCreateWithFontNamePtr) {
+	    cgFontName = CFStringCreateWithCString (NULL, full_name, kCFStringEncodingASCII);
+	    cgFont = CGFontCreateWithFontNamePtr (cgFontName);
+	    CFRelease (cgFontName);
+	} else {
+	    cgFont = CGFontCreateWithNamePtr (full_name);
+	}
+
+	if (cgFont)
+	    break;
+    }
+
+    if (!cgFont) {
+	/* Give up */
+	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+    }
+
+    *font_face = cairo_quartz_font_face_create_for_cgfont (cgFont);
+    CGFontRelease (cgFont);
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
 static void
 _cairo_quartz_font_face_destroy (void *abstract_face)
 {
@@ -224,6 +295,7 @@ FINISH:
 
 static const cairo_font_face_backend_t _cairo_quartz_font_face_backend = {
     CAIRO_FONT_TYPE_QUARTZ,
+    _cairo_quartz_font_face_create_for_toy,
     _cairo_quartz_font_face_destroy,
     NULL, /* direct implementation */
     _cairo_quartz_font_face_scaled_font_create
@@ -277,130 +349,8 @@ _cairo_quartz_scaled_to_face (void *abstract_font)
     return (cairo_quartz_font_face_t*) font_face;
 }
 
-static cairo_status_t
-_cairo_quartz_font_get_implementation (cairo_toy_font_face_t *toy_face,
-				       cairo_scaled_font_t **font_face_out)
-{
-    static cairo_user_data_key_t impl_font_face_key;
-    cairo_font_face_t *face;
-    cairo_status_t status;
-    const char *family = toy_face->family;
-    char *full_name = malloc(strlen(family) + 64); // give us a bit of room to tack on Bold, Oblique, etc.
-    CFStringRef cgFontName = NULL;
-    CGFontRef cgFont = NULL;
-    int loop;
-
-    face = cairo_font_face_get_user_data (&toy_face->base,
-					  &impl_font_face_key);
-    if (face) {
-	*font_face_out = face;
-	return CAIRO_STATUS_SUCCESS;
-    }
-
-    quartz_font_ensure_symbols();
-    if (! _cairo_quartz_font_symbols_present)
-	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-
-    /* handle CSS-ish faces */
-    if (!strcmp(family, "serif") || !strcmp(family, "Times Roman"))
-	family = "Times";
-    else if (!strcmp(family, "sans-serif") || !strcmp(family, "sans"))
-	family = "Helvetica";
-    else if (!strcmp(family, "cursive"))
-	family = "Apple Chancery";
-    else if (!strcmp(family, "fantasy"))
-	family = "Papyrus";
-    else if (!strcmp(family, "monospace") || !strcmp(family, "mono"))
-	family = "Courier";
-
-    /* Try to build up the full name, e.g. "Helvetica Bold Oblique" first,
-     * then drop the bold, then drop the slant, then drop both.. finally
-     * just use "Helvetica".  And if Helvetica doesn't exist, give up.
-     */
-    for (loop = 0; loop < 5; loop++) {
-	if (loop == 4)
-	    family = "Helvetica";
-
-	strcpy (full_name, family);
-
-	if (loop < 3 && (loop & 1) == 0) {
-	    if (toy_face->weight == CAIRO_FONT_WEIGHT_BOLD)
-		strcat (full_name, " Bold");
-	}
-
-	if (loop < 3 && (loop & 2) == 0) {
-	    if (toy_face->slant == CAIRO_FONT_SLANT_ITALIC)
-		strcat (full_name, " Italic");
-	    else if (toy_face->slant == CAIRO_FONT_SLANT_OBLIQUE)
-		strcat (full_name, " Oblique");
-	}
-
-	if (CGFontCreateWithFontNamePtr) {
-	    cgFontName = CFStringCreateWithCString (NULL, full_name, kCFStringEncodingASCII);
-	    cgFont = CGFontCreateWithFontNamePtr (cgFontName);
-	    CFRelease (cgFontName);
-	} else {
-	    cgFont = CGFontCreateWithNamePtr (full_name);
-	}
-
-	if (cgFont)
-	    break;
-    }
-
-    if (!cgFont) {
-	/* Give up */
-	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-    }
-
-    face = cairo_quartz_font_face_create_for_cgfont (cgFont);
-    CGFontRelease (cgFont);
-
-    if (face->status)
-	return face->status;
-
-    status = cairo_font_face_set_user_data (&toy_face->base,
-					    &impl_font_face_key,
-					    face,
-					    (cairo_destroy_func_t) cairo_font_face_destroy);
-
-    if (status) {
-	cairo_font_face_destroy (face);
-	return status;
-    }
-
-    *font_face_out = face;
-    return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_quartz_font_create_toy (cairo_toy_font_face_t *toy_face,
-			       const cairo_matrix_t *font_matrix,
-			       const cairo_matrix_t *ctm,
-			       const cairo_font_options_t *options,
-			       cairo_scaled_font_t **font_out)
-{
-    cairo_font_face_t *face;
-    cairo_scaled_font_t *scaled_font;
-    cairo_status_t status;
-
-    status = _cairo_quartz_font_get_implementation (toy_face, &face);
-    if (status)
-	return status;
-
-    status = _cairo_quartz_font_face_scaled_font_create (face,
-							 font_matrix, ctm,
-							 options,
-							 &scaled_font);
-    cairo_font_face_destroy (face);
-    if (status)
-	return status;
-
-    *font_out = scaled_font;
-    return CAIRO_STATUS_SUCCESS;
-}
-
 static void
-_cairo_quartz_font_fini(void *abstract_font)
+_cairo_quartz_scaled_font_fini(void *abstract_font)
 {
 }
 
@@ -740,9 +690,9 @@ _cairo_quartz_init_glyph_surface (cairo_quartz_scaled_font_t *font,
 }
 
 static cairo_int_status_t
-_cairo_quartz_font_scaled_glyph_init (void *abstract_font,
-				      cairo_scaled_glyph_t *scaled_glyph,
-				      cairo_scaled_glyph_info_t info)
+_cairo_quartz_scaled_glyph_init (void *abstract_font,
+				 cairo_scaled_glyph_t *scaled_glyph,
+				 cairo_scaled_glyph_info_t info)
 {
     cairo_quartz_scaled_font_t *font = (cairo_quartz_scaled_font_t *) abstract_font;
     cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
@@ -775,10 +725,8 @@ _cairo_quartz_ucs4_to_index (void *abstract_font,
 
 const cairo_scaled_font_backend_t _cairo_quartz_scaled_font_backend = {
     CAIRO_FONT_TYPE_QUARTZ,
-    _cairo_quartz_font_get_implementation,
-    _cairo_quartz_font_create_toy,
-    _cairo_quartz_font_fini,
-    _cairo_quartz_font_scaled_glyph_init,
+    _cairo_quartz_scaled_font_fini,
+    _cairo_quartz_scaled_glyph_init,
     NULL, /* text_to_glyphs */
     _cairo_quartz_ucs4_to_index,
     NULL, /* show_glyphs */
diff --git a/src/cairo-scaled-font.c b/src/cairo-scaled-font.c
index 570fd38..4d43c35 100644
--- a/src/cairo-scaled-font.c
+++ b/src/cairo-scaled-font.c
@@ -206,7 +206,7 @@ static const cairo_scaled_font_t _cairo_scaled_font_nil = {
     NULL,			/* glyphs */
     NULL,			/* surface_backend */
     NULL,			/* surface_private */
-    CAIRO_SCALED_FONT_BACKEND_DEFAULT,
+    NULL			/* backend */
 };
 
 /**
@@ -774,7 +774,6 @@ cairo_scaled_font_create (cairo_font_face_t          *font_face,
 			  const cairo_font_options_t *options)
 {
     cairo_status_t status;
-    cairo_font_face_t *impl_face;
     cairo_scaled_font_map_t *font_map;
     cairo_scaled_font_t key, *old = NULL, *scaled_font = NULL;
 
@@ -788,19 +787,19 @@ cairo_scaled_font_create (cairo_font_face_t          *font_face,
     /* Note that degenerate ctm or font_matrix *are* allowed.
      * We want to support a font size of 0. */
 
-    if (font_face->backend->get_implementation != NULL) {
-	/* indirect implementation, lookup the face that is used for the key */
-	status = font_face->backend->get_implementation (font_face, &impl_face);
-	if (unlikely (status))
-	    return _cairo_scaled_font_create_in_error (status);
-    } else
-	impl_face = font_face;
+    if (font_face->backend->type == CAIRO_FONT_TYPE_TOY) {
+	/* indirect implementation, lookup the face that is used for the toy face */
+	font_face = _cairo_toy_font_face_get_implementation (font_face);
+
+	if (unlikely (font_face->status))
+	    return _cairo_scaled_font_create_in_error (font_face->status);
+    }
 
     font_map = _cairo_scaled_font_map_lock ();
     if (unlikely (font_map == NULL))
 	return _cairo_scaled_font_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
 
-    _cairo_scaled_font_init_key (&key, impl_face,
+    _cairo_scaled_font_init_key (&key, font_face,
 				 font_matrix, ctm, options);
     scaled_font = font_map->mru_scaled_font;
     if (scaled_font != NULL &&
diff --git a/src/cairo-user-font.c b/src/cairo-user-font.c
index 6670b53..9bfdedc 100644
--- a/src/cairo-user-font.c
+++ b/src/cairo-user-font.c
@@ -336,64 +336,16 @@ _cairo_user_font_face_scaled_font_create (void                        *abstract_
 					  cairo_scaled_font_t        **scaled_font);
 
 static cairo_status_t
-_cairo_user_scaled_font_get_implementation (cairo_toy_font_face_t *toy_face,
-					    cairo_font_face_t **font_face_out)
+_cairo_user_font_face_create_for_toy (cairo_toy_font_face_t   *toy_face,
+				      cairo_font_face_t      **font_face)
 {
-    static cairo_user_data_key_t twin_font_face_key;
-
-    cairo_font_face_t *face;
-    cairo_status_t status;
-
-    face = cairo_font_face_get_user_data (&toy_face->base,
-					  &twin_font_face_key);
-    if (!face) {
-	face = _cairo_font_face_twin_create (cairo_toy_font_face_get_slant (&toy_face->base),
-					     cairo_toy_font_face_get_weight (&toy_face->base));
-
-	status = cairo_font_face_set_user_data (&toy_face->base,
-						&twin_font_face_key,
-						face,
-						(cairo_destroy_func_t) cairo_font_face_destroy);
-
-	if (unlikely (status)) {
-	    cairo_font_face_destroy (face);
-	    return status;
-	}
-    }
-
-    *font_face_out = face;
-    return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_user_scaled_font_create_toy (cairo_toy_font_face_t     *toy_face,
-				    const cairo_matrix_t      *font_matrix,
-				    const cairo_matrix_t      *ctm,
-				    const cairo_font_options_t *font_options,
-				    cairo_scaled_font_t	     **font)
-{
-    cairo_font_face_t *face;
-    cairo_status_t status;
-
-    status = _cairo_user_scaled_font_get_implementation (toy_face, &face);
-    if (unlikely (status))
-	return status;
-
-    status = _cairo_user_font_face_scaled_font_create (face,
-						       font_matrix,
-						       ctm,
-						       font_options,
-						       font);
-    if (unlikely (status))
-	return status;
-
+    *font_face = _cairo_font_face_twin_create (cairo_toy_font_face_get_slant (&toy_face->base),
+					       cairo_toy_font_face_get_weight (&toy_face->base));
     return CAIRO_STATUS_SUCCESS;
 }
 
-const cairo_scaled_font_backend_t _cairo_user_scaled_font_backend = {
+static const cairo_scaled_font_backend_t _cairo_user_scaled_font_backend = {
     CAIRO_FONT_TYPE_USER,
-    _cairo_user_scaled_font_get_implementation,
-    _cairo_user_scaled_font_create_toy,	/* create_toy */
     NULL,	/* scaled_font_fini */
     _cairo_user_scaled_glyph_init,
     _cairo_user_text_to_glyphs,
@@ -515,10 +467,10 @@ _cairo_user_font_face_scaled_font_create (void                        *abstract_
     return status;
 }
 
-static const cairo_font_face_backend_t _cairo_user_font_face_backend = {
+const cairo_font_face_backend_t _cairo_user_font_face_backend = {
     CAIRO_FONT_TYPE_USER,
+    _cairo_user_font_face_create_for_toy,
     NULL,	/* destroy */
-    NULL,       /* direct implementation */
     _cairo_user_font_face_scaled_font_create
 };
 
diff --git a/src/cairo-win32-font.c b/src/cairo-win32-font.c
index 3da64a6..e4bd7ff 100644
--- a/src/cairo-win32-font.c
+++ b/src/cairo-win32-font.c
@@ -519,11 +519,8 @@ _cairo_win32_scaled_font_done_unscaled_font (cairo_scaled_font_t *scaled_font)
 /* implement the font backend interface */
 
 static cairo_status_t
-_cairo_win32_scaled_font_create_toy (cairo_toy_font_face_t *toy_face,
-				     const cairo_matrix_t        *font_matrix,
-				     const cairo_matrix_t        *ctm,
-				     const cairo_font_options_t  *options,
-				     cairo_scaled_font_t        **scaled_font_out)
+_cairo_win32_font_face_create_for_toy (cairo_toy_font_face_t   *toy_face,
+				       cairo_font_face_t      **font_face)
 {
     LOGFONTW logfont;
     uint16_t *face_name;
@@ -542,6 +539,7 @@ _cairo_win32_scaled_font_create_toy (cairo_toy_font_face_t *toy_face,
 
     memcpy (logfont.lfFaceName, face_name, sizeof (uint16_t) * (face_name_len + 1));
     free (face_name);
+    logfont.lfFaceName[ARRAY_LENGTH (logfont.lfFaceName) - 1] = 0;
 
     logfont.lfHeight = 0;	/* filled in later */
     logfont.lfWidth = 0;	/* filled in later */
@@ -581,12 +579,9 @@ _cairo_win32_scaled_font_create_toy (cairo_toy_font_face_t *toy_face,
     logfont.lfQuality = DEFAULT_QUALITY; /* filled in later */
     logfont.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
 
-    if (!logfont.lfFaceName)
-	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+    *font_face = cairo_win32_font_face_create_for_logfontw (logfont);
 
-    return _win32_scaled_font_create (&logfont, NULL, &toy_face->base,
-			              font_matrix, ctm, options,
-				      scaled_font_out);
+    return CAIRO_STATUS_SUCCESS;
 }
 
 static void
@@ -1836,8 +1831,6 @@ _cairo_win32_scaled_font_init_glyph_path (cairo_win32_scaled_font_t *scaled_font
 
 const cairo_scaled_font_backend_t _cairo_win32_scaled_font_backend = {
     CAIRO_FONT_TYPE_WIN32,
-    NULL,
-    _cairo_win32_scaled_font_create_toy,
     _cairo_win32_scaled_font_fini,
     _cairo_win32_scaled_font_glyph_init,
     NULL, /* _cairo_win32_scaled_font_text_to_glyphs, FIXME */
@@ -1905,6 +1898,7 @@ _cairo_win32_font_face_scaled_font_create (void			*abstract_face,
 
 static const cairo_font_face_backend_t _cairo_win32_font_face_backend = {
     CAIRO_FONT_TYPE_WIN32,
+    _cairo_win32_font_face_create_for_toy,
     _cairo_win32_font_face_destroy,
     NULL, /* direct implementation */
     _cairo_win32_font_face_scaled_font_create
@@ -1913,7 +1907,7 @@ static const cairo_font_face_backend_t _cairo_win32_font_face_backend = {
 /**
  * cairo_win32_font_face_create_for_logfontw_hfont:
  * @logfont: A #LOGFONTW structure specifying the font to use.
- *   If hfont is null then the lfHeight, lfWidth, lfOrientation and lfEscapement
+ *   If @font is %NULL then the lfHeight, lfWidth, lfOrientation and lfEscapement
  *   fields of this structure are ignored. Otherwise lfWidth, lfOrientation and
  *   lfEscapement must be zero.
  * @font: An #HFONT that can be used when the font matrix is a scale by
diff --git a/src/cairoint.h b/src/cairoint.h
index 7f90037..6ae68d0 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -400,6 +400,8 @@ typedef struct _cairo_toy_font_face {
     cairo_bool_t owns_family;
     cairo_font_slant_t slant;
     cairo_font_weight_t weight;
+
+    cairo_font_face_t *impl_face; /* The non-toy font face this actually uses */
 } cairo_toy_font_face_t;
 
 typedef enum _cairo_scaled_glyph_info {
@@ -428,17 +430,6 @@ typedef struct _cairo_scaled_font_subset {
 struct _cairo_scaled_font_backend {
     cairo_font_type_t type;
 
-    cairo_warn cairo_status_t
-    (*get_implementation)  (cairo_toy_font_face_t	*toy_face,
-			    cairo_font_face_t	       **font_face);
-
-    cairo_warn cairo_status_t
-    (*create_toy)  (cairo_toy_font_face_t	*toy_face,
-		    const cairo_matrix_t	*font_matrix,
-		    const cairo_matrix_t	*ctm,
-		    const cairo_font_options_t	*options,
-		    cairo_scaled_font_t	       **scaled_font);
-
     void
     (*fini)		(void			*scaled_font);
 
@@ -498,6 +489,10 @@ struct _cairo_scaled_font_backend {
 struct _cairo_font_face_backend {
     cairo_font_type_t	type;
 
+    cairo_warn cairo_status_t
+    (*create_for_toy)  (cairo_toy_font_face_t	*toy_face,
+			cairo_font_face_t      **font_face);
+
     /* The destroy() function is allowed to resurrect the font face
      * by re-referencing. This is needed for the FreeType backend.
      */
@@ -505,10 +500,6 @@ struct _cairo_font_face_backend {
     (*destroy)     (void			*font_face);
 
     cairo_warn cairo_status_t
-    (*get_implementation)  (void			*font_face,
-			    cairo_font_face_t	       **font_face_out);
-
-    cairo_warn cairo_status_t
     (*scaled_font_create) (void				*font_face,
 			   const cairo_matrix_t		*font_matrix,
 			   const cairo_matrix_t		*ctm,
@@ -516,24 +507,24 @@ struct _cairo_font_face_backend {
 			   cairo_scaled_font_t	       **scaled_font);
 };
 
-extern const cairo_private struct _cairo_scaled_font_backend _cairo_user_scaled_font_backend;
+extern const cairo_private struct _cairo_font_face_backend _cairo_user_font_face_backend;
 
 /* concrete font backends */
 #if CAIRO_HAS_FT_FONT
 
-extern const cairo_private struct _cairo_scaled_font_backend _cairo_ft_scaled_font_backend;
+extern const cairo_private struct _cairo_font_face_backend _cairo_ft_font_face_backend;
 
 #endif
 
 #if CAIRO_HAS_WIN32_FONT
 
-extern const cairo_private struct _cairo_scaled_font_backend _cairo_win32_scaled_font_backend;
+extern const cairo_private struct _cairo_font_face_backend _cairo_win32_font_face_backend;
 
 #endif
 
 #if CAIRO_HAS_QUARTZ_FONT
 
-extern const cairo_private struct _cairo_scaled_font_backend _cairo_quartz_scaled_font_backend;
+extern const cairo_private struct _cairo_font_face_backend _cairo_quartz_font_face_backend;
 
 #endif
 
@@ -982,22 +973,22 @@ typedef struct _cairo_traps {
 #if   CAIRO_HAS_WIN32_FONT
 
 #define CAIRO_FONT_FAMILY_DEFAULT CAIRO_WIN32_FONT_FAMILY_DEFAULT
-#define CAIRO_SCALED_FONT_BACKEND_DEFAULT &_cairo_win32_scaled_font_backend
+#define CAIRO_FONT_FACE_BACKEND_DEFAULT &_cairo_win32_font_face_backend
 
 #elif CAIRO_HAS_QUARTZ_FONT
 
 #define CAIRO_FONT_FAMILY_DEFAULT CAIRO_QUARTZ_FONT_FAMILY_DEFAULT
-#define CAIRO_SCALED_FONT_BACKEND_DEFAULT &_cairo_quartz_scaled_font_backend
+#define CAIRO_FONT_FACE_BACKEND_DEFAULT &_cairo_quartz_font_face_backend
 
 #elif CAIRO_HAS_FT_FONT
 
 #define CAIRO_FONT_FAMILY_DEFAULT CAIRO_FT_FONT_FAMILY_DEFAULT
-#define CAIRO_SCALED_FONT_BACKEND_DEFAULT &_cairo_ft_scaled_font_backend
+#define CAIRO_FONT_FACE_BACKEND_DEFAULT &_cairo_ft_font_face_backend
 
 #else
 
 #define CAIRO_FONT_FAMILY_DEFAULT CAIRO_FT_FONT_FAMILY_DEFAULT
-#define CAIRO_SCALED_FONT_BACKEND_DEFAULT &_cairo_user_scaled_font_backend
+#define CAIRO_FONT_FACE_BACKEND_DEFAULT &_cairo_user_font_face_backend
 
 #endif
 
@@ -1392,6 +1383,9 @@ _cairo_unscaled_font_reference (cairo_unscaled_font_t *font);
 cairo_private void
 _cairo_unscaled_font_destroy (cairo_unscaled_font_t *font);
 
+cairo_private cairo_font_face_t *
+_cairo_toy_font_face_get_implementation (cairo_font_face_t *font_face);
+
 /* cairo-font-face-twin.c */
 
 cairo_private cairo_font_face_t *


More information about the cairo-commit mailing list