diff --git a/src/cairo-ft-font.c b/src/cairo-ft-font.c index 5824f49e4..5e8c5811f 100644 --- a/src/cairo-ft-font.c +++ b/src/cairo-ft-font.c @@ -88,7 +88,7 @@ typedef struct _cairo_ft_font_face cairo_ft_font_face_t; struct _cairo_ft_unscaled_font { cairo_unscaled_font_t base; - cairo_bool_t from_face; /* from cairo_ft_font_face_create_for_ft_face()? */ + cairo_bool_t from_face; /* was the FT_Face provided by user? */ FT_Face face; /* provided or cached face */ /* only set if from_face is false */ @@ -280,16 +280,19 @@ _cairo_ft_unscaled_font_map_unlock (void) static void _cairo_ft_unscaled_font_init_key (cairo_ft_unscaled_font_t *key, char *filename, - int id) + int id, + FT_Face face) { unsigned long hash; key->filename = filename; key->id = id; + key->face = face; - /* 1607 is just an arbitrary prime. */ hash = _cairo_hash_string (filename); + /* the constants are just arbitrary primes */ hash += ((unsigned long) id) * 1607; + hash += ((unsigned long) face) * 2137; key->base.hash_entry.hash = hash; } @@ -339,7 +342,7 @@ _cairo_ft_unscaled_font_init (cairo_ft_unscaled_font_t *unscaled, if (filename_copy == NULL) return _cairo_error (CAIRO_STATUS_NO_MEMORY); - _cairo_ft_unscaled_font_init_key (unscaled, filename_copy, id); + _cairo_ft_unscaled_font_init_key (unscaled, filename_copy, id, face); } unscaled->have_scale = FALSE; @@ -382,35 +385,35 @@ _cairo_ft_unscaled_font_keys_equal (const void *key_a, const cairo_ft_unscaled_font_t *unscaled_a = key_a; const cairo_ft_unscaled_font_t *unscaled_b = key_b; - return (strcmp (unscaled_a->filename, unscaled_b->filename) == 0 && - unscaled_a->id == unscaled_b->id); + if (unscaled_a->id == unscaled_b->id && + unscaled_a->face == unscaled_b->face) + { + if (unscaled_a->filename == NULL && unscaled_a->filename == NULL) + return TRUE; + else if (unscaled_a->filename == NULL || unscaled_a->filename == NULL) + return FALSE; + else + return (strcmp (unscaled_a->filename, unscaled_b->filename) == 0); + } + + return FALSE; } /* Finds or creates a #cairo_ft_unscaled_font_t for the filename/id from * pattern. Returns a new reference to the unscaled font. */ static cairo_ft_unscaled_font_t * -_cairo_ft_unscaled_font_create_for_pattern (FcPattern *pattern) +_cairo_ft_unscaled_font_create_internal (char *filename, int id, FT_Face font_face) { cairo_ft_unscaled_font_t key, *unscaled; cairo_ft_unscaled_font_map_t *font_map; cairo_status_t status; - FcChar8 *fc_filename; - char *filename; - int id; - - if (FcPatternGetString (pattern, FC_FILE, 0, &fc_filename) != FcResultMatch) - goto UNWIND; - filename = (char *) fc_filename; - - if (FcPatternGetInteger (pattern, FC_INDEX, 0, &id) != FcResultMatch) - goto UNWIND; font_map = _cairo_ft_unscaled_font_map_lock (); if (font_map == NULL) goto UNWIND; - _cairo_ft_unscaled_font_init_key (&key, filename, id); + _cairo_ft_unscaled_font_init_key (&key, filename, id, font_face); /* Return existing unscaled font if it exists in the hash table. */ if (_cairo_hash_table_lookup (font_map->hash_table, &key.base.hash_entry, @@ -428,7 +431,7 @@ _cairo_ft_unscaled_font_create_for_pattern (FcPattern *pattern) goto UNWIND_FONT_MAP_LOCK; } - status = _cairo_ft_unscaled_font_init (unscaled, filename, id, NULL); + status = _cairo_ft_unscaled_font_init (unscaled, filename, id, font_face); if (status) goto UNWIND_UNSCALED_MALLOC; @@ -451,57 +454,66 @@ UNWIND: return NULL; } + +static cairo_ft_unscaled_font_t * +_cairo_ft_unscaled_font_create_for_pattern (FcPattern *pattern) +{ + FT_Face font_face = NULL; + 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 (FcPatternGetInteger (pattern, FC_INDEX, 0, &id) != FcResultMatch) + goto UNWIND; + } + + return _cairo_ft_unscaled_font_create_internal (filename, id, font_face); + +UNWIND: + return NULL; +} + static cairo_ft_unscaled_font_t * _cairo_ft_unscaled_font_create_from_face (FT_Face face) { - cairo_status_t status; - cairo_ft_unscaled_font_t *unscaled; - - unscaled = malloc (sizeof (cairo_ft_unscaled_font_t)); - if (unscaled == NULL) { - _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); - return NULL; - } - - status = _cairo_ft_unscaled_font_init (unscaled, NULL, 0, face); - if (status) { - free (unscaled); - return NULL; - } - - return unscaled; + return _cairo_ft_unscaled_font_create_internal (NULL, 0, face); } static void _cairo_ft_unscaled_font_destroy (void *abstract_font) { cairo_ft_unscaled_font_t *unscaled = abstract_font; + cairo_ft_unscaled_font_map_t *font_map; if (unscaled == NULL) return; + font_map = _cairo_ft_unscaled_font_map_lock (); + /* All created objects must have been mapped in the font map. */ + assert (font_map != NULL); + + _cairo_hash_table_remove (font_map->hash_table, + &unscaled->base.hash_entry); + if (unscaled->from_face) { /* See comments in _ft_font_face_destroy about the "zombie" state * for a _ft_font_face. */ if (unscaled->faces && !unscaled->faces->unscaled) cairo_font_face_destroy (&unscaled->faces->base); - - unscaled->face = NULL; } else { - cairo_ft_unscaled_font_map_t *font_map; - - font_map = _cairo_ft_unscaled_font_map_lock (); - /* All created objects must have been mapped in the font map. */ - assert (font_map != NULL); - - _cairo_hash_table_remove (font_map->hash_table, - &unscaled->base.hash_entry); - _font_map_release_face_lock_held (font_map, unscaled); - - _cairo_ft_unscaled_font_map_unlock (); } + unscaled->face = NULL; + + _cairo_ft_unscaled_font_map_unlock (); + _cairo_ft_unscaled_font_fini (unscaled); } @@ -2281,6 +2293,10 @@ _cairo_ft_font_face_scaled_font_create (void *abstract_face, * derived from a pattern where the user has called * cairo_ft_font_options_substitute(), so *just* use those load * flags and ignore the options. + * + * XXX two points about the above comment: + * 1. I don't see how the comment is relevant here, + * 2. What if the face is coming from FC_FT_FACE of a pattern? */ ft_options = font_face->ft_options; @@ -2484,6 +2500,17 @@ cairo_ft_font_options_substitute (const cairo_font_options_t *options, * appropriately to reflect the options in a #cairo_font_options_t, call * cairo_ft_font_options_substitute(). * + * 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. + * + * 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 + * time of the returned #cairo_font_face_t. See + * cairo_ft_font_face_create_for_ft_face() for an exmaple of how to couple + * the life time of the FT_Face to that of the cairo font-face. + * * Return value: a newly created #cairo_font_face_t. Free with * cairo_font_face_destroy() when you are done using it. **/