Calling QFontDatabase::addApplicationFont() on Symbian fails.
A list or requirements that need to be met by the underlaying OS font support. Some of these requirements are due to Qt's internal font handling and the others are dictated by Qt's public application font API.
|#||Requirement||Why it is needed|
|1||Application font files must be loadable from any directory which the application has read access to. That could for example be the private application folder, a temporary folder or any (read-only) public folder.||Cross platform Qt applications are written in a way to access deployed resources (such as .ttf files). These resources are usually directly used with Qt Api (for example adding the font file as application font).|
|2||Application fonts need to be addable from data buffers.|
|3||Font data of the added Application font such as typeface name, weight, etc. needs to be accessible||The font needs to be properly registered with all relevant details in Qt's font database|
|4||Font tables of the added Application font need to be accessible.||Needed for all kinds of text related operations in Qt, e.g. text shaping or mapping between UTF-16 and Glyph ID|
|5||Rasterized glyphs of the added Application font need to be accessible.||Needed for displaying/rendering the font|
|6a||The added Application font should only be visible and usable by the (running) application which added it.||When other applications enumerate all avalable fonts, only System fonts and own application fonts must be enumerated. Since an application font may be removed any time, an application must never use an application font which was added by another application.|
|6b||If 6a is not possible, an added font should at least be flagged as an added font.||Other applications which enumerate all avalable fonts could detect and skip application fonts added by other applications. Qt would not list those fonts in the font database.|
|7||An application must be allowed to add and remove an application at any time without fearing to influence other running applications.||An application font only concerns the application that adds it. The application cannot be disallowed to remove an application font, only because another application may be illegally accessing it.|
The obvious way to implement Application Fonts for Qt on Symbian would be to use CWsScreenDevice::AddFile() as backend function. This has also already been proposed in the comments below.
- # 3: CFbsFont::GetFaceAttrib() returns the needed metadata.
- # 4: From Symbian^3/v2 on, there will be a font table API (see
QTBUG-15515for details). That means that Application fonts will only be implemented for Symbian^3/v2 and higher, unless I use the ugly CFontStore hack to access font tables of added fonts.
- # 5: CFont::GetCharacterData returns rasterized glyphs and glyph metrics.
- # 1: As the documentation of CWsScreenDevice::AddFile() mentions, the font file to add must be in a public folder and not in the application's private folder. The reason behind it is that the font server (fbserv.exe) does not have the AllFiles capability, thus cannot open a file from everywhere.
- Font files which are deployed with the application could be transparently installed into e.g. :\resources\qt-appfonts\0XUID, qmake would take care of that. And the font loading mechanism in QFontDatabase::addApplicationFont() would automatically use that public location to load a font.
- Font files which are to be added by QFontDatabase::addApplicationFont() but do not reside in a public folder (see Question 1, below) are temporarily copied to a public place at runtime, so that fbserv.exe can access them (see Question 2, below).
- # 2: There is no Symbian Api to add a font from a data buffer
- Qt could save the font to a temporary file to a (semi) public place and then call CWsScreenDevice::AddFile()
- # 6a, # 6b: CWsScreenDevice::AddFile() adds all font files to a system wide font store (in the font server), and these added fonts are visible and usable by all other processes. There is even no API to find out if a font has been added by a(nother) process (or is there? see Question 3, below).
- Qt could go through all :\resource\fonts folders and so get the typeface names of present system font files (either by loading the fonts into a font store or directly parsing the font files for the type face name). With that information, Qt could rule these type faces out from being possibly added by a(nother) process. This is slow, of course. And removes again all the benefit which we gain through the new Font table API in Symbian^3/v2 (that Api was added in order not to have to load font files from the file system in order to access font tables).
- Since the font will in most cases be copied to a temporary location, anyway, Qt could mark the font data by patching the written file. The typeface name, or even some obscure, unused OS/2 table field could be used as marker. So, while populating the font database, (another instance of) Qt can check if there is such marker and filter the font out. That would of course only work for font files that have been added via Qt API.
- # 7: There is no warning that a process is removing a font it added. So, other processes which (unfortunately) may use that font, suddenly have an invalid font, leading to crashes, and I believe even bad accesses in the fbserv.exe which will reboot the phone.
- Qt could acquire a CFont for each atomic access it performs. If a font is suddenly removed, Qt would still get a valid CFont in the next atomic access. I am afraid that this will kill the performance, though. Qt is currently acquiring a CFont the first time it is needed and only releasing it at the destruction of the application.
I thought that using a CFontStore instance instead of the the troubled CWsScreenDevice::AddFile() would be the best option. That would theoretically meet all the requirements which are not met by
the CWsScreenDevice::AddFile() way plus it would also work on Symbian versions below Symbian^3/v2. However, I was not able to access reasterized glyphs from a CFontStore (requirement #5), which is a show stopper for this approach. Please see the attached fontstoretest.zip to see what I tried. I still hope that there is a way to use a CFontStore, but I need suggestions from somebody who understands the involved Symbian classes (see Question 4, below).
Solution 3: Dedicated font server for Qt on Symbian (see
This won't happen before Qt 4.8, if it happens at all. So, I just mentioned it here for comlpeteness.
There are a lot of open questions which I need to find answers for in order to implement this feature either partially or completely. My Symbian background is not strong enough to immediately find the best solutions. I know that Symbian offers very specific API, but it is not always obvious to find. So, if you have the Symbian-foo but do not hate Qt , please have a look at the following questions and ideally drop a few answers as comments, below.
- Is there a Symbian API to find that out if a file resides in a protected folder, and may not be readable by all processes?
- Are there "process specific" temporary forlders in Symbian where the owner process can write into and all other processes can read from? Basically a safe way to exchange files between processes without fearing sabotage.
- Is there some (perhaps hidden) API which reveals that a certain font is not a system font but had been added by a process via CWsScreenDevice::AddFile()?
- Is it possible to instantiate a CFontStore, load a font file with it and call GetCharacterData() to get glyph metrics and rasterized glyph data?