GNOME Bugzilla – Bug 647969
CoreText backend needs proper font fallback/coverage support
Last modified: 2012-06-06 07:12:36 UTC
The big part that is still missing in the CoreText backend is support for font fallbacks, see bug 611943 and bug 608929 for related discussion. Currently the main problem is that we do not have access to the font cascading lists on OS X with CoreText in the same detail as we have with fontconfig on Linux. Secondly, when using CoreText to try to find a close match to a given font description, CoreText appears to do really strict matching and falls back to the default, Lucida Grande, quickly. See bug 611943 comment 4 for a detailed overview of where I got stuck. I do have most code to get this done in place on a local branch, it is still a mess because the important pieces are missing. In the near future, I hope to pick up things from this local branch and the above mentioned comment, so to be continued.
*** Bug 655297 has been marked as a duplicate of this bug. ***
I've found out that the system cascade list on OS X is not accessible: http://lists.apple.com/archives/coretext-dev/2011/Jun/msg00007.html An earlier approach to replicate PangoFcFonset by using CTFontDescriptor instead of a FcPattern did not really work out, see the opening comment above and bug 611943 comment 4. My current plan is to see if it's possible to employ CTFontCreateForString() within the Pango CoreText backend. I am working on this at the moment. To be continued.
Created attachment 197866 [details] Overview of cascading in CoreText and Pango The attached image shows the "flow" of the two font systems at an abstract level. In CoreText, cascading happens when you typeset a string with a given font into a CTLine. This results into a set of runs which are drawn to the screen. Each CTRun can contain a different font than the one specified when creating the CTLine due to the cascading. This font must be used to render the run. In the Pango "basic CoreText" engine the shape function will determine which glyphs to render from the given font. To implement this, we use CTLine. However, if CTLine produces a CTRun with a different font, we have no way of changing the font at this point, since Pango expects a series of glyphs for the given font, which was already cascaded. So, Pango really wants to do its own cascading and thus we need a cascade list. As said in comment 2, the system cascade list is not publicly accessible on Mac OS X. My plan with CTFontCreateForString() was to use this function in a get_font() method of PangoFontset to create "lazy-loading" fontsets, but Pango does not work in that way. Options I can come up with: Hacky solution: Create PangoFontsets consistent of 1 font with always perfect coverage. Get CoreText to do the cascading when rendering fonts in the PangoRenderer. In essense, we circumvent the Pango font cascading here. I don't think this is a very good solution since it will likely bring up all kinds of different problems, for example when doing text measurements / dealing with font metrics. Proper solution: Build our own font cascade list. How can this be achieved? Ideas (including bad ones) in non-particular order: 1) Create a string with glyphs from all kinds of languages (using e.g. pango_language_get_sample_string()) and use CTFontForString() to retrieve fonts. 2) Compute our own cascade list by going over all fonts available on the system. 3) Can we perhaps misuse CTLine to create a cascade list / fontset? 4) Misuse the hidden symbol to get access to the system cascade list (CTFontCopyDefaultCascadeList()). 4a) If the system cascade list appears hardcoded and similar on different systems, consider copying this list and hardcode it into the Pango CoreText backend. 5) Figure out where on the system CoreText stores cascade lists and use these. 6) Look what LibreOffice is doing on Mac. A brief investigation reveals that LibreOffice is still using ATSUI. They appear to enable font fallbacks in ATSUI by supplying a list consisting out of most system fonts.
I am currently trying to get font fallbacks working by using option 4). This provides me with a cascade list that will at least work. Cascading seems to work fine already, however, it appears that there are a bunch of rendering issues so the results are not presented on the screen correctly. I am working on fixing these rendering issues. When font fallbacks are working this way, we need to decide what to do with the cascade list since it is very probably not desirable to depend on a hidden function (though if it appears to be available on 10.5, 10.6 and 10.7, why not?).
Created attachment 198995 [details] [review] Patch to implement support for font fallbacks in core text backend Here's what I have so far. On my Snow Leopard and Lion machines it seems to be working nicely. A lot of the code has been cleaned up/refactored by introducing PangoCoreTextFontsetKey and PangoCoreTextFontKey. Because of this, the backend code also looks similar to that of the fontconfig backend. A point of discussion is the usage of CTFontCopyDefaultCascadeList(). The patch is using this function and it is working just fine for me. However, we have to decide whether we want to rely on a public, non-exposed, symbol in the CoreText library. Alternatives have been lined out in an earlier comment, the ones I deem most feasible are hardcoding a cascade list and creating a cascade list consisting out of all/most of the fonts found on the system. Also it might be good to walk through the functions in the backend again and remove those which are not used (anymore). Other issues are: - Rendering Georgian text sometimes misses some glyphs, I think this is due to the font, not the code ... - Hebrew punctuation might not be rendered correctly, but I have not much clue how to fix it, since I don't know the script. Issues that existed already before this patch and I intend to fix in the near future: - Pango spits out a "expected RTL" warning (e.g. when rendering Arabic). This is probably a simple fix in the basic core text module. - Support for detecting small caps fonts. I think I have a solution lying around somewhere that I need to implement.
Note to self: With this patch applied gtk+/tests/testoffscreen crashes. Need to debug this.
Created attachment 200835 [details] [review] [Update Nov 6, 2011] Patch to implement support for font fallbacks in core text backend This is an updated patch which fixes the crash mentioned in comment 6. The crash was fixed by falling back to "Sans" if the requested font family could not be loaded. Whereas in the FontConfig backend FontConfig will take care of this, we have to do this manually/explicitly in the CoreText backend.
Created attachment 201356 [details] [review] [Update Nov 13, 2011] Patch to implement support for font fallbacks in core text backend This is an updated patch based on the top of today's Pango master (commit cce4c9f84350bb53371323ab96ccf9245e014f75). The patch has been updated to work with the fixed traits value handling found in master.
This patch causes Banshee on OS X to crash on startup. see: https://bugzilla.gnome.org/show_bug.cgi?id=665752
*** Bug 665752 has been marked as a duplicate of this bug. ***
(In reply to comment #9) > This patch causes Banshee on OS X to crash on startup. > > see: https://bugzilla.gnome.org/show_bug.cgi?id=665752 My initial impression is that the final fallback, to load the font "Sans" fails, resulting in pango_core_text_fontset_new() to return NULL and the subsequent call to pango_core_text_fontset_get_key() to fail. I need to reproduce this, so I can debug the final font fallback. Loading "Sans" should usually *always* work otherwise you are in big trouble like exposed here...
Created attachment 203357 [details] [review] Patch that fixes major slowdown This patch applies on top of Kris' latest patch and fixes a major slowdown caused by it: Getting the coverage from the font is quite expensive, this patch simply caches the coverage in the core text font.
Created attachment 203657 [details] [review] Updated patch with coverage caching and font cache fix This is Kris' patch, with two fixes merged into it: - pango_core_text_font_key_equal() was broken and never considered fonts equal, so we were adding fonts over fonts to the hash. - cache the PangoCoverage in PangoCoreTextFont because it's cached nowhere else, and creating it on the fly was a major performance problem.
Font fallback support (including the fixes from comment 13) was merged into master today; resolving this bug as FIXED. (In reply to comment #11) > (In reply to comment #9) > > This patch causes Banshee on OS X to crash on startup. > > > > see: https://bugzilla.gnome.org/show_bug.cgi?id=665752 I would very much encourage to try Banshee with Pango from master, since some things have been fixed that might have fixed this too (e.g. you could have been bitten by the font_key_equal() bug).
Created attachment 206381 [details] banshee log Yeah, sorry Banshee still crashes on Pango master
Created attachment 206383 [details] correct banshee log how embarrassing, and now the correct log
Thanks for checking. It could be the case that this is due to memory corruption, I experienced similar traces yesterday after reworking the shaping engine. Will double check tonight.
(In reply to comment #16) > Created an attachment (id=206383) [details] > correct banshee log > > how embarrassing, and now the correct log I haven't seen these traces in my debugging sessions. The memory corruption that I experienced with the shaping engine has now been fixed (patch is in master), though this was most likely being caused by a patch which never made it to the git repository. Could you check if pango master as of today fares any better? Or does the crash still exist with that?
Created attachment 211216 [details] latest banshee git compiled against pango 1.30.0 crash log
Created attachment 211217 [details] gdb backtrace
Created attachment 211219 [details] gdb session
Though i am not the original banshee crash reporter, I can confirm this problem exists in released pango 1.30.0 upon banshee startup. From my gdb analysis I found that the problem lies in pangocoretext-fontmap.c in line 1265: fontset = pango_core_text_fontset_new (&key, tmp_desc); which returns NULL after evaluating "if (!find_best_match (font_family, description, &best_description, &best_face)) ". I've attached a log of my gdb session which is hopefully helpful as I am not an expert in pango or mac os font handling. Note that i tried to print some usefull variables within the gdb log at the very end.
Reopening based on Timo's logs. I reproduced the crash on startup of Banshee with 1.30.0 as well.
Timo, thanks for the very detailed gdb traces. The session posted in comment 21 seems to contain some hints for me: (gdb) print *desc $1 = {family_name = 0x583ea00 "Lucida Grande", style = PANGO_STYLE_NORMAL, variant = PANGO_VARIANT_SMALL_CAPS, weight = PANGO_WEIGHT_BOLD, stretch = PANGO_STRETCH_NORMAL, gravity = PANGO_GRAVITY_SOUTH, mask = 127, static_family = 1, size_is_absolute = 0, size = 12288} It looks like loading a small caps font failed. A quick grep through a Banshee tarball turns out that SourceView.cs is indeed trying to render a small caps font. The small caps code paths have not been properly tested, so I will construct a small testcase for this. I am quite confident this should allow me to trigger the problem so I can properly fix it.
Fixed in master commit f5135453d26e68f9f2fbe8f0ddb01e437df41384 Author: Kristian Rietveld <kris@loopnest.org> Date: Mon Jun 4 20:27:01 2012 +0200 Bug 673497 - corefont fallback not always working The fallback failed when a "small caps" font was requested. This commit improves the fallback support. When the first fallback, trying Sans with the same style fails, we reset the variant, weight and stretch to default values and try again. With Sans we should always be able to adhere to the requested style. Last but not least, output a sensible error message if all fallbacks fail instead of simply crashing on a NULL pointer somewhere.
Created attachment 215650 [details] gdb session log with pango 1.30.1 I've just tested against pango 1.30.1 with the included fix, and indeed mono (pango) does not crash but give the error message "Pango-ERROR **: Could not load fallback font, bailing out.". So it seems there is still something wrong. I've attached again a gdb session with some prints, using pango 1.30.1. Hope this can be of help.
When I try to load a bold small-caps font, I get the same warning (simple:3649): Pango-WARNING **: couldn't load font "Lucida Grande Bold Small-Caps Not-Rotated 12", modified variant/weight/stretch as fallback, expect ugly output. however, after this, the program continues without warnings and renders with a fallback font. In your trace however, a bunch of warnings pop up: (Banshee:27538): GLib-GObject-CRITICAL **: g_object_ref: assertion `G_IS_OBJECT (object)' failed (Banshee:27538): GLib-GObject-CRITICAL **: g_object_get_qdata: assertion `G_IS_OBJECT (object)' failed (Banshee:27538): GLib-GObject-CRITICAL **: g_object_set_qdata_full: assertion `G_IS_OBJECT (object)' failed Can you break on these (break on g_log) and see what is causing these? Also this seems troublesome: (Banshee:27538): Pango-WARNING **: failed to choose a font, expect ugly output. engine-type='PangoRenderCoreText', script='latin' Does any test program work at all? If you built your own GTK+, try one of the tests in gtk+/tests.
Created attachment 215680 [details] output of 'testprint' gtk test program I'll try to get to the warnings with a gdb session tomorrow. I always rebuild gtk+ (2.24.10) when rebuilding pango, and with pango 1.31.1 most test seem to run, but I could manage to reproduce the error with the "testprint" test. When running testprint it fails the same way, log is attached.
Aha, testprint is failing for me as well, and I see why. It is my fault! Thanks again for the hint; writing up a patch now.
Pushed to master: commit 70a85d441d973883af4afb57599bc570eeea4c83 Author: Kristian Rietveld <kris@loopnest.org> Date: Tue Jun 5 22:34:59 2012 +0200 coretext: don't insert item in the hash if it originated from the hash Oversight in my fallback fix, this resulted in things being wrongly destroyed due to unrefs. Oops. a day after a release unfortunately. Hope this fixes your problems for real now.
just applied your latest patch and now the testprint as well as banshee works fine - bug is fixed! Thank you a lot, Kristian, for your work!
Timo: thanks for your time to produce the gdb sessions, without these we wouldn't have been able to fix it so quickly.