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
_______________________________________________
Development mailing list
[email protected]
http://lists.qt-project.org/mailman/listinfo/development

Reply via email to