[Development] Platform specific font matching in QPA

jiang.jiang at nokia.com jiang.jiang at nokia.com
Tue Mar 20 17:18:50 CET 2012


Hi folks,

Today I want to bring up the topic on font matching in QPA. In my opinion it's broken for certain very useful cases and beyond simple fix.

The first case is what Thiago brought up here [1]. Matching for aliases like "serif" and "monospace" is a commonly used feature in both desktop applications and WebKit. It allows us to specify an abstract font family name and have it configured in a platform specific format (fontconfig config file for instance). This is how things used to work in other toolkits and Qt 4.

The second one is when I tried to implement a separated Han script font matching in QUnicodeTables. As we know, Chinese, Japanese and Korean share a lot of code points in Unicode, without language tagging (lang="ja" in HTML), by simply checking the code points of a string, there is no way we can tell which font should be used. Should we use a Chinese font or Japanese font for the same "δΈ­" character? Such logic can only be found in a platform specific config file. It does not only happen to CJK fonts, whenever you have more than one fonts for the same script, how do we want to prioritize them will be platform dependent logic.

However, in QPA we can't do that. The current font matching logic in QPA works like this:

In the beginning, QFontDatabase will call populateFontDatabase() in a QPlatformFontDatabase and it will list all the fonts on the platform and use QPlatformFontDatabase::registerFont() to add these fonts into an internal structure defined in QFontDatabase. An important parameter of this registerFont() call is a void *handle. It's a unique representation of the font being added on the platform. For QFontconfigDatabase we use a combination of font path and index as the handle.

When QFontDatbase is asked to load a font request in a given script, it will go through all the fonts registered in its internal structure, evaluating the match() function to calculate a score for each font, the one with the lowest score gets selected.

After we find out the selected font, QPlatformFontDatabase::fontEngine() function will be called with the handle stored for that font, and QPlatformFontDatabase can just load the font with this handle.

In summary, QPlatformFontDatabase has no way to control the font matching order at all, all the font matching logic is fixed in QtGui. You can't simply write a QPA platform plugin to override this. As shown above, such logic is simply not flexible enough to handle a lot of use cases.

How is it handled in Qt 4.8 (non-QPA)? You may wonder. In Qt 4 each platform has its own QFontDatabase implementation in qfontdatabase_x11.cpp, qfontdatabase_mac.cpp, etc. In X11 for instance, QFont request (in QFontDef format) will be converted to a fontconfig query pattern (FcPattern *), fontconfig will do the match and return the matched font to us. Then we will create a QFontEngine (QFontEngineMultiX11 to be specific) out of it. So the platform specific font matching rules are perfectly executed. In Qt 5/QPA we lost that ability.

What's my proposal to fix it then? It's actually quite simple (no API change at all!), QFontDatabase will first try to get the matched QFontEngine by calling QPlatformFontDatabase::fontEngine() directly, with handle = 0, in that case the QPlatformFontDatabase::fontEngine() function will do a match in platform specific way, with the QFontDef and script given. If it fails to find a font or don't want to support this, simply return 0 and QFontDatabase will work just like how it's working now.

The WIP fix is here: http://codereview.qt-project.org/20590

- Jiang

[1] http://lists.qt-project.org/pipermail/development/2012-March/002736.html


More information about the Development mailing list