Native-looking text in QML 2

One of the comments in Morten's blog post about desktop components in QML 2 was that the text looks out of place on Windows. This is because QML 2 uses a custom rendering mechanism called "distance fields" for the text which allows hardware accelerated drawing of transformable text. Yoann blogged about this a year back.

This is what the distance field text looks like in the desktop components:

Qt 5 desktop components rendered with distance field text

While distance field text is perfect for UI components for which you want smooth animated movement, rotations and zooms, it will look different from the text rendered by native applications on Windows. This is especially true because the distance field text renderer does not apply grid-fitting hints to the glyphs, whereas this is the standard on Windows. Note that on e.g. Mac OS X, the standard is to draw the text without applying grid-fitting, so the distance field text will not look as out-of-place on this platform.

Grid-fitting means that the shapes of the glyphs are modified for the current font size and device resolution in order to make them look sharper. This is done by moving control points around e.g. to avoid features of the glyph being positioned between two pixels, which would cause the anti-aliasing to fill both those pixels, partially blending the font color with the current background in order to give the visual impression that the glyph touches half of each pixel. A sharper image can be made if the feature fills exactly one full pixel instead. The mechanism is especially effective for low pixel densities and small font sizes.

The downside of grid-fitting, in addition to certain typographical consequences, is that the text and its layout becomes unzoomable. This is because the modifications to the glyphs happen based on the target size of the glyph on screen. When you scale it, the shapes of the glyphs will change, making the shapes wobble, and the metrics of the text will also change, requiring a relayout of the text. If you zoom on a web page, for instance, the paragraph you wanted to see up close might have moved around significantly by the time you get to a text size you can comfortably read, and then you will have to pan around to find it again.

When using distance fields, we will render the glyphs without grid-fitting to make them scalable. An additional convenience of this is that we only have to cache the shape of each glyph once, whereas grid-fitted glyphs have to be cached per size. This saves some memory and also makes effects like animated zooms a lot faster, since the glyphs can be redrawn at every zoom level using the same distance field cache.

Here's what the previous screen shot looks like if you scale the push button by a factor of two:

Distance field rendered text with zoomed button

But while the distance fields have many advantages, they don't cover the need to have applications that look like they belong together with other Windows applications. For an application using desktop components, you can imagine this being a more important goal than having smoothly transformable text items. On a desktop machine running Windows, the memory cost of a glyph cache might not be the primary concern either. I've been meaning to fix this for a while. The code for drawing text through the system back-end instead of the distance field renderer has been in the scene graph since the text nodes were originally written, but so far there has not been any convenient way for developers to choose it over the default. With change 6a16f63df4a51edee03556f841d34aad573870f2 to Qt Declarative, this option has now been added. On any text component in QML, you can now set the renderType property to NativeRendering in order to use the system back-end to rasterize the glyphs instead of Qt. This will apply to any platform, although it will have the largest effect on Windows or on Linux when hinting is turned on in the system settings.

Text {
text: "Some text"
renderType: Text.NativeRendering

I've added the branch qt5-nativetext to the desktop components repository where the effect can be tested. The components in this branch will use the distance field renderer by default, but by setting the DESKTOPCOMPONENTS_USE_NATIVE_TEXT environment variable to "1", you will be able to see the difference. Running qmlscene on Gallery.qml with this environment variable set yields the following result:

QML 2 widgets with native-looking text

So the appearance is crisper and the text fits in on the platform, but scaling the text does not give the nice results we had before, and will instead look pixelated. See the following screen shot for comparison:

The effect of zooming native-looking text

So the choice is yours. If you're targeting Windows and you want your application to look like a standard, native Windows application, you can use the renderType property to achieve this. If you want the lean, flexible and transformable text of Qt, leave the property unaltered.

Blog Topics: