michael@0: From 0238fe2cafea2e1ed19bb222117bd73ee6898d4d Mon Sep 17 00:00:00 2001 michael@0: From: Karl Tomlinson michael@0: Date: Thu, 14 May 2009 10:46:29 +0000 michael@0: Subject: [ft] Resolve mutual referencing problems with zombie faces michael@0: michael@0: Bug 21706 -- zombie ft_font_face / ft_unscaled_font mutual michael@0: referencing problems michael@0: [http://bugs.freedesktop.org/show_bug.cgi?id=21706] michael@0: michael@0: There can be more than one zombie font_face belonging to an unscaled_font, michael@0: but only the first is destroyed. This leaks the client's FT_Face michael@0: (and associated font data) as release of the FT_Face depends on release michael@0: of the font_face. michael@0: michael@0: (The reason why Firefox ends up with two different font_faces for one michael@0: unscaled_font is that load_flags for faces with artificial oblique have michael@0: FT_LOAD_NO_BITMAP set. michael@0: https://bugzilla.mozilla.org/show_bug.cgi?id=486974) michael@0: michael@0: Also it's possible for _cairo_ft_font_face_create to pull out a zombie michael@0: font_face from the unscaled_font, which would crash michael@0: _cairo_ft_font_face_scaled_font_create, as that expects non-null michael@0: font_face->unscaled (if !font-face->pattern). michael@0: --- michael@0: diff --git a/AUTHORS b/AUTHORS michael@0: index 289fecb..8c06174 100644 michael@0: --- a/AUTHORS michael@0: +++ b/AUTHORS michael@0: @@ -86,7 +86,7 @@ Travis Spencer XCB backend fix michael@0: Bill Spitzak Build fix to find Xrender.h without xrender.pc michael@0: Zhe Su Add support for fontconfig's embeddedbitmap option michael@0: Owen Taylor Font rewrite, documentation, win32 backend michael@0: -Karl Tomlinson michael@0: +Karl Tomlinson Optimisation and obscure bug fixes (mozilla) michael@0: Alp Toker Fix several code/comment typos michael@0: Malcolm Tredinnick Documentation fixes michael@0: David Turner Optimize gradient calculations michael@0: diff --git a/src/cairo-ft-font.c b/src/cairo-ft-font.c michael@0: index 1e2a18e..f9ff0b1 100644 michael@0: --- a/src/cairo-ft-font.c michael@0: +++ b/src/cairo-ft-font.c michael@0: @@ -543,8 +543,10 @@ _cairo_ft_unscaled_font_destroy (void *abstract_font) michael@0: /* See comments in _ft_font_face_destroy about the "zombie" state michael@0: * for a _ft_font_face. michael@0: */ michael@0: - if (unscaled->faces && !unscaled->faces->unscaled) michael@0: + if (unscaled->faces && unscaled->faces->unscaled == NULL) { michael@0: + assert (unscaled->faces->next == NULL); michael@0: cairo_font_face_destroy (&unscaled->faces->base); michael@0: + } michael@0: } else { michael@0: _font_map_release_face_lock_held (font_map, unscaled); michael@0: } michael@0: @@ -2233,9 +2235,10 @@ _cairo_ft_font_face_destroy (void *abstract_face) michael@0: if (font_face == NULL) michael@0: return; michael@0: michael@0: - /* When destroying the face created by cairo_ft_font_face_create_for_ft_face, michael@0: + /* When destroying a face created by cairo_ft_font_face_create_for_ft_face, michael@0: * we have a special "zombie" state for the face when the unscaled font michael@0: - * is still alive but there are no public references to the font face. michael@0: + * is still alive but there are no other references to a font face with michael@0: + * the same FT_Face. michael@0: * michael@0: * We go from: michael@0: * michael@0: @@ -2249,6 +2252,8 @@ _cairo_ft_font_face_destroy (void *abstract_face) michael@0: michael@0: if (font_face->unscaled && michael@0: font_face->unscaled->from_face && michael@0: + font_face->next == NULL && michael@0: + font_face->unscaled->faces == font_face && michael@0: CAIRO_REFERENCE_COUNT_GET_VALUE (&font_face->unscaled->base.ref_count) > 1) michael@0: { michael@0: cairo_font_face_reference (&font_face->base); michael@0: @@ -2394,12 +2399,21 @@ _cairo_ft_font_face_create (cairo_ft_unscaled_font_t *unscaled, michael@0: font_face->ft_options.extra_flags == ft_options->extra_flags && michael@0: cairo_font_options_equal (&font_face->ft_options.base, &ft_options->base)) michael@0: { michael@0: - if (font_face->base.status == CAIRO_STATUS_SUCCESS) michael@0: - return cairo_font_face_reference (&font_face->base); michael@0: + if (font_face->base.status) { michael@0: + /* The font_face has been left in an error state, abandon it. */ michael@0: + *prev_font_face = font_face->next; michael@0: + break; michael@0: + } michael@0: michael@0: - /* The font_face has been left in an error state, abandon it. */ michael@0: - *prev_font_face = font_face->next; michael@0: - break; michael@0: + if (font_face->unscaled == NULL) { michael@0: + /* Resurrect this "zombie" font_face (from michael@0: + * _cairo_ft_font_face_destroy), switching its unscaled_font michael@0: + * from owner to ownee. */ michael@0: + font_face->unscaled = unscaled; michael@0: + _cairo_unscaled_font_reference (&unscaled->base); michael@0: + return &font_face->base; michael@0: + } else michael@0: + return cairo_font_face_reference (&font_face->base); michael@0: } michael@0: } michael@0: michael@0: @@ -2415,6 +2429,14 @@ _cairo_ft_font_face_create (cairo_ft_unscaled_font_t *unscaled, michael@0: michael@0: font_face->ft_options = *ft_options; michael@0: michael@0: + if (unscaled->faces && unscaled->faces->unscaled == NULL) { michael@0: + /* This "zombie" font_face (from _cairo_ft_font_face_destroy) michael@0: + * is no longer needed. */ michael@0: + assert (unscaled->from_face && unscaled->faces->next == NULL); michael@0: + cairo_font_face_destroy (&unscaled->faces->base); michael@0: + unscaled->faces = NULL; michael@0: + } michael@0: + michael@0: font_face->next = unscaled->faces; michael@0: unscaled->faces = font_face; michael@0: michael@0: -- michael@0: cgit v0.8.2