Text Rendering and Fonts


In Qt Quick Ultralite, text is rendered to the screen using the Text and StaticText items. These items have a font property for controlling the selected font configuration. Read the font type documentation to learn about available APIs and font engine-specific details.

Qt for MCUs offering by default includes the static font engine and optionally the Monotype Spark font engine.

The advantage of Spark is its low memory requirements, especially when an application depends on a wide range of characters (for example, CJK characters). This can be a natural requirement for internationalized applications. Moreover, an application developer need not do anything special to support dynamic text with Spark. Spark enables text scaling support at run-time, without compromising on performance and text quality.

On the other hand, the static font engine's advantage is its simplicity. It operates on a static precomputed data, with very fast lookup operations. It does not have any font processing overhead at run-time, because fonts are processed while building the application. The static font engine does not have any run-time rasterization support, thus it has its limitations.

In general, we recommend you to start with the default engine and upgrade to Monotype Spark as your product matures and exceeds the default engine's capabilities or the memory resources of the hardware. Installing and enabling the Spark font engine requires minimal effort, so you can switch to it at any point during the application development.

The following table highlights the key differences between the two font engines, enabling you to choose the appropriate one:

FeatureStatic font engineMonotype Spark font engineNotes
Font rasterizationBuild-time by fontcompiler, using FreeType.Run-time by Monotype Spark.
Memory requirementsUses a traditional approach on MCUs, which is rasterizing all used characters ahead of time. The downside is that it can become a lot of bytes with internationalized applications. The only memory requirement that comes from using the static font engine is to have sufficient space for the precomputed data of rasterized glyphs and font metrics. The static font engine's implementation is a thin API around this data (~120 lines of code).The Monotype Spark library is linked to the application. The library size is estimated to be ~75 kB with the default configuration, but it may vary depending on the target device and system configuration. Note that the Spark library features can be configured to reduce its size. The engine requires a font file to be bundled with an application.

Additional RAM is required by run-time data, see QUL_MONOTYPE_SPARK_HEAP_SIZE for more information. If caching is enabled, additional RAM is required.

Caching systemNot needed, because all data is precomputed.Caching improves performance dramatically if enabled, and sufficient memory has been allocated for the cache. Cache memory is used to store glyphs, advance widths, and Unicode-glyph id mappings (CMAP). The cache content can optionally be prepared ahead of time with the cache priming feature.
Dynamic textThe glyphs must be pre-registered using the font.unicodeCoverage property. This increases the precomputed data size.No special handling required from an application developer if the font file contains the glyphs information.Dynamic text in this document refers to a text that is not known at compile time. This, for example, can be text fetched from a network, read from a file, or user input. Strings defined in C++ code also count as dynamic strings in Qt for MCUs.
Font formats.ttf, .ttc, .pfa, .pfb, .otfTrueType fonts, CCC compressed fonts and Fontmaps.
Font hintingUses FreeType's hint processing capabilities.Spark utilizes two different hinting methods – spark hinting and auto hinting, which are optimized for the limited resources on micro-controller platforms. TrueType's hinting instructions are not supported to conserve runtime memory.Font hinting is a step that is applied during the glyph rasterization process. Hints are instructions that can control how the font renderer assigns pixel values. Hints are commonly used to preserve certain typeface consistencies, such as glyph stem, weights, and heights. Hints can be encoded into a font or applied dynamically during font processing.
Glyph compressionCurrently not implemented.Supports run-length encoding on glyph data, but this feature is not integrated yet.
Glyph render modesQt for MCUs currently utilizes bitmap and graymap8 modes only. The render mode can be configured for each font using the font.quality property.Spark's rasterizer supports the following formats: bitmap, graymap2, graymap4, graymap6, graymap8. Qt for MCUs currently supports only bitmap and graymap8.The values of font.quality are mapped to bitmap for Font.QualityVeryLow, and to graymap8 for Font.QualityVeryHigh. These values are the same for both font engines.
Complex text layoutsSupported by the StaticText type, using the HarfBuzz library. Text layout is performed at application build-time.Monotype's support for this is not integrated yet.Although Complex text layout (CTL) is not the font engine's responsibility, text layout systems usually are tightly coupled with font engines. Complex text layout includes topics such as bi-directional text and context-sensitive languages (for example, Arabic script). Many scripts do not require CTL.

Font properties


Starting with version 1.7, it is possible to define bindings on font subproperties with the Spark font engine.

Text {
    text: "Hello world from Qt"
    font.italic: italicSwitch.checked
    font.pixelSize: pixelSizeSlider.value

See font bindings example for more details on how binding evaluation map to a font class name in a fontmap file.

Both font engines permit bindings on the font property. For example:

Text {
    id: conf1
    font.pixelSize: 30
Text {
    id: conf2
    font.pixelSize: 100
Text {
    // Binding on font property.
    font: someCondition ? conf1.font : conf2.font
    text: "some text"

This allows runtime font changes with the static engine, albeit without the fine-grained control on font subproperty bindings that is possible with the Spark engine.


The memory usage can be optimized by sharing a font configuration (Text.font) where texts use the same style (see also Qt.font()).

Text {
    // Sharing the font configuration with other Text element through a binding.
    font: myText.font
    text: "some text"

Constant font configurations are automatically shared in the emitted C++ code.


The font basic type in Qt Quick Ultralite is a constant value, so assigning to font subproperties is not supported.

// error: Assigning to properties of 'font' is not supported, use bindings
onClicked: myText.font.italic = false

As suggested by the error message, one can use a binding to achieve the same results.

property bool isItalic: true

Text {
    text: "hello world"
    font.italic: isItalic

MouseArea {
    anchors.fill: parent
    onClicked: isItalic = false

Static font engine

The font file processing happens at application build-time and is done by the fontcompiler. The fontcompiler tool relies on the FreeType-based font engine from Qt. The output from the fontcompiler is the precomputed data of rasterized glyphs and font metrics. Nothing gets added or removed from this data at run-time - the set of available glyphs is decided at build-time. All operations on this data are O(1) or O(log n). This font engine supports constant font configurations only.

Font search directory

The font engine uses the QUL_FONTS_DIR CMake target property to find the fonts used by the application, and extract the necessary font data.

Precomputed data

To support assigning text between items with different font settings, by default fontcompiler rasterizes all used characters in all used font configurations in the application. Exceptions to this are font.unicodeCoverage and StaticText, which register characters only for the used font configuration.

In addition, fontcompiler by default includes small set of commonly used glyphs, for example, digits.

To reduce the memory footprint this behavior can be disabled using QUL_AUTO_GENERATE_GLYPHS. In such case only characters that where explicitly defined in font.unicodeCoverage will be rasterized.

The precomputed data is a shared source of data for anything that needs to render a text, this includes Text and StaticText.

See QUL_GLYPHS_COPY_TO_RAM for more information about configuring the run-time storage of this data.

Embedding glyphs

Depending on the QUL_AUTO_GENERATE_GLYPHS setting, the fontcompiler can embed the glyphs for all characters that are used in any QML string literal and all font configurations into the resulting binary. The character selection can be extended by using the font.unicodeCoverage property. This is necessary in scenarios where the strings are dynamically created and not known at compile time.

If QUL_AUTO_GENERATE_GLYPHS is set to OFF only glyphs defined using font.unicodeCoverage will be embedded. By careful application design this technique can lead to significant footprint reduction.

Setting the font.unicodeCoverage property affects all QML items that use the same font configuration.

Rendering dynamic strings in QML

Strings from C++ models

C++ models can produce dynamic strings that are not known at compile time. Consider the following example:

// MyModel.h
struct MyModelData
    std::string stringField;

inline bool operator==(const MyModelData &lhs, const MyModelData &rhs)
    return lhs.stringField == rhs.stringField;

struct MyModel : public Qul::ListModel<MyModelData>
    int count() const override { return 10; };
    MyModelData data(int index) const override
        std::string data;
        for (int i = 0; i <= index; ++i) {
            data += 'a' + i;
        return {data};
// MyView.qml
Item {
    ListView {
        anchors.fill: parent
        model: MyModel { }
        delegate: Text {
            height: 20
            text: model.stringField

The fontcompiler cannot generate glyphs for such model data, as it cannot predict what glyphs are needed. This results in glyphs missing when rendering QML content.

To tell fontcompiler what character ranges can be produced by the model and which glyphs must be generated, use the font.unicodeCoverage property for font used by the delegate.

Item {
    ListView {
        anchors.fill: parent
        model: MyModel { }
        delegate: Text {
            height: 20
            font.unicodeCoverage: [Font.UnicodeBlock_BasicLatin] // << define character set
            text: model.stringField

Strings from C++ functions

The C++ functions that return strings follows the same rules as the C++ models. Consider the following example:

// MyObject.h
struct MyObject : public Qul::Object
    std::string getDynamicString() const
        std::string data;
        for (int i = 0; i < 26; ++i) {
            data += 'A' + i;
        return data;
// MyView.qml
Item {
    MyObject { id: myObject }
    Text {
        text: myObject.getDynamicString()

The earlier example code cannot render glyphs correctly unless the font.unicodeCoverage property is set for the Text item that uses a dynamic string:

Item {
    MyObject { id: myobject }
    Text {
        text: myobject.getDynamicString()
        font.unicodeCoverage: [Font.UnicodeBlock_BasicLatin] // << define character set

Monotype Spark font engine

Monotype’s Spark font engine is a scalable font rendering subsystem based on the industry standard TrueType font standard. It is designed for resource constrained environments such as automotive displays, medical devices, white goods, wearable devices, television set-top boxes, portable media players, and control panels. It brings the benefits of scalable type and high-quality multilingual font display to the embedded environment.

High performance architecture optimized for both space efficiency and speed. Spark meets stringent size requirements for many applications and devices, including those that support East Asian languages, requiring thousands of characters. Combined with Monotype's tuned fonts, the Monotype Spark solution lets you to take advantage of scalable font in situations where previously it may not have been possible, due to memory restrictions, complexity, or platform costs.

The scaling and hinting of TrueType outlines involves a large number of arithmetic operations. Fixed point math is used to improve performance on low-end devices that do not have a dedicated floating point processor. Spark also supports floating point math in case the device has a dedicated floating point unit. For optimal results, you need to get your fonts finely tuned for floating point calculations.

Glyph rasterization can be optimized for target screen depth and rotation, among other features. Monotype offers various techniques that can be applied to a font file to reduce memory requirements and optimize processing speed. Some of the techinques are described in the following sections.

The Monotype Spark library is highly configurable. For optimal performance and memory usage, read the Spark documentation, which includes a thorough performance guide.

Contact Qt sales in order to discuss your application and font requirements.

The Monotype Spark product's page can be visited here.

How to install

When installing Qt for MCUs, select the Monotype Spark™ Support checkbox for your development targets. You can also use the Maintenance Tool from your <QT_INSTALL_PATH> to install the Monotype component at a later stage in your project.

The Qt for MCUs evaluation packages contain everything you need to build an application that uses the Monotype Spark font engine. After purchasing a commercial license along with the Monotype's Spark add-on license, you get full access to the engineering package.

The optimized Monotype's font files for the micro-controller targets, are installed to <QT_INSTALL_PATH>\QtMCUs\<VERSION>\src\3rdparty\monotype\fonts\.

How to enable

By default, Qt Quick Ultralite applications use the static font engine. To select the Monotype Spark font engine, set QUL_MONOTYPE_SPARK_FONT_FILE target property to a font file path. See font formats for the list of supported formats. Setting this CMake variable causes your application to be linked with the Monotype library.

                        QUL_MONOTYPE_SPARK_FONT_FILE "${CMAKE_CURRENT_SOURCE_DIR}/fonts/SampleFontmap.fmp")

See QUL_FONT_FILES_COPY_TO_RAM for more information about configuring the run-time storage of the application's font files.

Font formats

TrueType fonts

Any TrueType font is supported, but note that TrueType hinting instructions are ignored. See spark hinting and auto hinting sections.


The Fontmap is a concept that allows combining multiple font files into a single Fontmap file. Only TTF files can be used in Fontmap components. In addition, Fontmap offers font selection based on the Unicode range, Unicode Script, and font class. In a Fontmap, Unicode Script entry is called language.

As part of the Monotype package, the Fontmap editor tool is installed to <QT_INSTALL_PATH>\QtMCUs\<VERSION>\bin\. Fontmap editor is a Windows application that can be used to create and/or modify Fontmap files. The application has also been tested to work with Wine. The documentation for the tool and the Fontmap guide is installed to <QT_INSTALL_PATH>\QtMCUs\<VERSION>\docs\monotype\FontmapEditor\.

Note: Currently, the selected font is independent of the Unicode Script.

CCC compressed fonts

CCC font is a Monotype font format that uses a lossless compression algorithm called CCC, to compress large size font tables. With little overhead to decompress, it makes a good compromise between compression ratio and resources. All TTF fonts can be converted to CCC.

Note: CCC compressed fonts currently are not yet supported as Fontmap components.

Engine configuration

The font engine can be configured through the following CMake target properties:


Disables preallocation of the cache buffer of Monotype Spark font engine


Enable cache priming for the Monotype Spark font engine


Set maximum cache size for the Monotype Spark font engine


Disables preallocation of the heap buffer of Monotype Spark font engine


Set maximum heap size for the Monotype Spark font engine


Use vector outlines for text rendering with the Monotype Spark font engine

Optimal values for heap size and cache size require careful testing and tuning.

Spark can also work with heap and cache memory that has been allocated externally.

Font class mapping

Note: This section is applicable only if using a Fontmap font file.

One of the components that affect font selection from a Fontmap file is the font class name. See Fontmap's documentation, to know how font selection works. The supported font class naming format is "<font.family> <font.weight> <font.italic>", where:

  • font.family - If not set, uses value from QUL_DEFAULT_FONT_FAMILY target property. If set, uses the provided string as is.
  • font.weight - Maps enums to strings, for example, Font.ExtraLight becomes "Extralight". An exception to this is, Font.Normal, which maps to an empty string.
  • font.bold - Is a synonym for font.weight: Font.Bold
  • font.italic - If set, maps to "Italic", otherwise maps to an empty string.

Mapping examples

See font bindings example.

Porting an existing application

Lets assume that we have a qml application, which uses sans-serif font family as in the following example:

Text {
    font.family: "sans-serif"

To design your Fontmap for the above example, you need to map a font file (TTF) to the sans-serif font class name. This is a straightforward process with the FontmapEditor GUI tool. If you do not wish to modify your qml sources, but would like to use a different font file than SansSerif.ttf, nothing prevents you from mapping sans-serif to FrutigerOTS_S12-29g.ttf in the Fontmap file. Or you can change all occurrences of sans-serif in your source code with, for example, FrutigerOTS. And then in the FontmapEditor map FrutigerOTS to FrutigerOTS_S12-29g.ttf.

Font hinting

Spark hinting

Spark hinting instructions are designed for very low memory requirements and for enhanced performance. Note that Spark does not process conventional TrueType hints if they are present in the font. Besides new hinting instructions, Spark applies other unique hinting techniques to significantly reduce the font size. Spark hints may be optionally compressed to reduce memory usage further.

Auto hinting

Auto-hinting is built into the Spark font engine because TrueType font hinting is not supported to conserve runtime memory. In the event that the system font does not contain Spark hints, Spark deploys auto-hinting. Auto-hinting alone, does not yield the same high quality as the auto-hinting with Spark hints combination, especially at smaller text sizes.


On rendering a glyph for the first time, Spark creates the glyph and stores it in the cache. After that, if you try to render that glyph again, it is fetched directly from the cache without having to re-create it, improving the performance. Along with the glyph cache, Spark also supports CMAP and Advance cache. It enables faster retrieval of glyph ID and glyph advance compared to parsing of the “CMAP” and “HMTX” table of a TrueType font, respectively. When the cache is full, Spark removes the least used entries from the cache.

Among other cache configuration, Spark lets you configure the cache entries that are never removed and size threshold of glyphs that should not be added into the cache. Some of these capabilites are not yet available with Qt for MCUs.

See QUL_MONOTYPE_SPARK_CACHE_SIZE documentation for more information.

Cache priming

It is sometimes useful to prepopulate the cache in order to improve the performance further. This improves the application startup time significantly, especially if it contains a lot of text.

Use the font.unicodeCoverage property to select characters to include in the cache priming data during application build-time. When the font engine is accessed for the first time at an application run-time, the cache priming data is copied from a flash memory into the Spark's cache memory.

See QUL_MONOTYPE_SPARK_CACHE_PRIMING documentation for more information.

StaticText considerations

Text that is displayed using the StaticText type is always rasterized and laid out at application build-time. It does not rely on calling any of the font engine APIs at run-time. If cache priming detects common glyphs with those stored for StaticText purposes, it will optimize by fetching those glyphs from StaticText data when populating the Spark cache at the run-time. This optimization enables to save on the required flash memory space.

See QUL_GLYPHS_COPY_TO_RAM for more information about configuring the run-time storage of StaticText glyphs.

Available under certain Qt licenses.
Find out more.