summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorKarl Tomlinson <karlt+@karlt.net>2009-05-14 11:46:29 +0100
committerChris Wilson <chris@chris-wilson.co.uk>2009-05-15 21:31:02 +0100
commit0238fe2cafea2e1ed19bb222117bd73ee6898d4d (patch)
tree3941a52c122a845a63e5c0568b2f88a5e340e3a8 /src
parentd6f6ec9082c86b9fd9e2389b9627f08a91c2cdd3 (diff)
[ft] Resolve mutual referencing problems with zombie faces
Bug 21706 -- zombie ft_font_face / ft_unscaled_font mutual referencing problems [http://bugs.freedesktop.org/show_bug.cgi?id=21706] There can be more than one zombie font_face belonging to an unscaled_font, but only the first is destroyed. This leaks the client's FT_Face (and associated font data) as release of the FT_Face depends on release of the font_face. (The reason why Firefox ends up with two different font_faces for one unscaled_font is that load_flags for faces with artificial oblique have FT_LOAD_NO_BITMAP set. https://bugzilla.mozilla.org/show_bug.cgi?id=486974) Also it's possible for _cairo_ft_font_face_create to pull out a zombie font_face from the unscaled_font, which would crash _cairo_ft_font_face_scaled_font_create, as that expects non-null font_face->unscaled (if !font-face->pattern).
Diffstat (limited to 'src')
-rw-r--r--src/cairo-ft-font.c38
1 files changed, 30 insertions, 8 deletions
diff --git a/src/cairo-ft-font.c b/src/cairo-ft-font.c
index 1e2a18ee..f9ff0b10 100644
--- a/src/cairo-ft-font.c
+++ b/src/cairo-ft-font.c
@@ -543,8 +543,10 @@ _cairo_ft_unscaled_font_destroy (void *abstract_font)
/* See comments in _ft_font_face_destroy about the "zombie" state
* for a _ft_font_face.
*/
- if (unscaled->faces && !unscaled->faces->unscaled)
+ if (unscaled->faces && unscaled->faces->unscaled == NULL) {
+ assert (unscaled->faces->next == NULL);
cairo_font_face_destroy (&unscaled->faces->base);
+ }
} else {
_font_map_release_face_lock_held (font_map, unscaled);
}
@@ -2233,9 +2235,10 @@ _cairo_ft_font_face_destroy (void *abstract_face)
if (font_face == NULL)
return;
- /* When destroying the face created by cairo_ft_font_face_create_for_ft_face,
+ /* When destroying a face created by cairo_ft_font_face_create_for_ft_face,
* we have a special "zombie" state for the face when the unscaled font
- * is still alive but there are no public references to the font face.
+ * is still alive but there are no other references to a font face with
+ * the same FT_Face.
*
* We go from:
*
@@ -2249,6 +2252,8 @@ _cairo_ft_font_face_destroy (void *abstract_face)
if (font_face->unscaled &&
font_face->unscaled->from_face &&
+ font_face->next == NULL &&
+ font_face->unscaled->faces == font_face &&
CAIRO_REFERENCE_COUNT_GET_VALUE (&font_face->unscaled->base.ref_count) > 1)
{
cairo_font_face_reference (&font_face->base);
@@ -2394,12 +2399,21 @@ _cairo_ft_font_face_create (cairo_ft_unscaled_font_t *unscaled,
font_face->ft_options.extra_flags == ft_options->extra_flags &&
cairo_font_options_equal (&font_face->ft_options.base, &ft_options->base))
{
- if (font_face->base.status == CAIRO_STATUS_SUCCESS)
- return cairo_font_face_reference (&font_face->base);
+ if (font_face->base.status) {
+ /* The font_face has been left in an error state, abandon it. */
+ *prev_font_face = font_face->next;
+ break;
+ }
- /* The font_face has been left in an error state, abandon it. */
- *prev_font_face = font_face->next;
- break;
+ if (font_face->unscaled == NULL) {
+ /* Resurrect this "zombie" font_face (from
+ * _cairo_ft_font_face_destroy), switching its unscaled_font
+ * from owner to ownee. */
+ font_face->unscaled = unscaled;
+ _cairo_unscaled_font_reference (&unscaled->base);
+ return &font_face->base;
+ } else
+ return cairo_font_face_reference (&font_face->base);
}
}
@@ -2415,6 +2429,14 @@ _cairo_ft_font_face_create (cairo_ft_unscaled_font_t *unscaled,
font_face->ft_options = *ft_options;
+ if (unscaled->faces && unscaled->faces->unscaled == NULL) {
+ /* This "zombie" font_face (from _cairo_ft_font_face_destroy)
+ * is no longer needed. */
+ assert (unscaled->from_face && unscaled->faces->next == NULL);
+ cairo_font_face_destroy (&unscaled->faces->base);
+ unscaled->faces = NULL;
+ }
+
font_face->next = unscaled->faces;
unscaled->faces = font_face;