The user needs to notify cairo when they have deleted the underlying resource so that cairo can drop all associated caches and handles. When creating an ft_font_face() from an FT_Face we key on (long)FT_Face, and so it is possible for a new FT_Face to have the same key if the original face is destroyed and Cairo remains blissfully unaware.
Just to clarify for anyone reading this: I ran into this problem using a [cairomm] workflow similar to this: // Do a bunch of sequential draws for (int i=0; i<numDraws; ++i) { // Make a new surface+context Cairo::RefPtr<Cairo::ImageSurface> surface = Cairo::ImageSurface::create( ... ); Cairo::RefPtr<Cairo::Context> context = Cairo::Context::create(surface); // Make a new FT face FT_Face *ftFace = FT_Open_Face( "/path/to/ttf" ... ); // Draw a bunch of different text using the same FT face for (j=0; j<numText; ++j) { Cairo::RefPtr<Cairo::FontFace> cFace = Cairo::FtFontFace::create(ftFace, FT_LOAD_NO_HINTING); // set misc attributes, such as size, colour, etc. // Draw some text context.set_font_face(cFace); context.show_glyphs( ... ); } // Finish with the Cairo entities surface->write_to_png( ... ); surface->finish(); context.clear(); // Discard surface.clear(); // Discard // Discard the (one) FT face we allocated FT_Done_Face(ftFace); } This workflow fails to render the text if the pointer address of the FT_Face matches that of one used (and freed) during a previous iteration. As alluded to by Chris, the crux of the problem seems to be Cairo using a single static cache of FT_Face objects, without accounting for the possibility that the face has been freed, then another one allocated with the same pointer address. [ Maybe the cache should be on the Surface/Context, rather than global, and thus cleaned up with each Surface/Context? Just a thought ... ]
The root of the problem is that FT_Face() is not ref-counted. Maybe someone can fix that... It's been proposed upstream already.
In this particular case, yes, it would eliminate the problem if FT_Face was refcounted. However, the other objects that cairo implements such as cairo_t and cairo_surface_t, do provide a cairo_*_finish() function so that the user can dispose of any internal references to the object prior to destroying the underlying resource. I feel we should be consistent in our API and implement finish() for all objects, which would not only provide a means to workaround FT_Face, but also similar issues that may arise with other font backends - such as user fonts.
Agreed that cairo_font_face_finish() is useful and should be there. What about cairo_scaled_font_finish()? It would simply release the font-face associated with the scaled font.
What happens if cairo_font_face_finish() is called before cairo_surface_finish() on a font that a PS/PDF surface is holding?
(In reply to comment #5) > What happens if cairo_font_face_finish() is called before > cairo_surface_finish() on a font that a PS/PDF surface is holding? The surface goes into an error state? That works automatically already...
-- GitLab Migration Automatic Message -- This bug has been migrated to freedesktop.org's GitLab instance and has been closed from further activity. You can subscribe and participate further through the new bug through this link to our GitLab instance: https://gitlab.freedesktop.org/cairo/cairo/issues/246.
Use of freedesktop.org services, including Bugzilla, is subject to our Code of Conduct. How we collect and use information is described in our Privacy Policy.