C

Text Rendering and Fonts

Overview

In Qt Quick Ultralite, text is rendered to the screen via the Text and StaticText components. The components have properties for controlling the font family (font.family), size (font.pixelSize), weight (font.weight, font.bold) and italics (font.italic). The specific font settings in a component make up a font configuration. See also QUL_DEFAULT_FONT_FAMILY.

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.

The precomputed data for the static font engine and the font file for the Spark font engine are stored in the asset data segment. For more details on asset data handling, see the board-specific documentation. Spark has a mode to load the font file synchronously, for example, from an external flash. In the synchronous mode only the currently needed bits are loaded into RAM. This mode is not supported yet. For details on the cache priming data memory handling read the cache priming section.
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 textNeed to pre-register used glyphs with font.unicodeCoverage, which 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 only the graymap8 mode. FreeType rasterizer does support bitmap mode, but this mode has not been exposed yet via the public APIs.Spark's rasterizer supports the following formats: bitmap, graymap2, graymap4, graymap6, graymap8. Qt for MCUs currently supports only graymap8.
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.

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).

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.

The font.family property

The family name is case insensitive and may include a foundry name. For example, "Helvetica [Cronyx]". If the family is available from more than one foundry and the foundry isn't specified, an arbitrary foundry is chosen. If the family isn't available, a family is set using the font matching algorithm.

Precomputed data

To support assigning text between items with different font settings, 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.

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

Embedding glyphs

The Qt Quick Ultralite compiler takes care of embedding 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 on Text items. This is necessary in scenarios where the strings are dynamically created and not known at compile time.

Example:

Text {
    font.family: "DejaVu Sans"
    font.unicodeCoverage: [Font.UnicodeBlock_Kannada, "ᜠᜡ\u1722", [0x600, 0x61F]]
    text: CppSingleton.retrieveText()
}

In the example above, the glyphs for many extra unicode codepoints are prerendered for the font configuration used by the Text item. This information is compiled into the application binary. The codepoints in the "Kannada" Unicode block, the codepoint range 0x600 to 0x61F (inclusive), and the individual characters ᜠ, ᜡ, and U+1722 will be included.

Only a single glyph is generated per codepoint, even if the codepoint is contained in several ranges, blocks, or strings.

Setting the font.unicodeCoverage property affects all Text blocks that use the same font configuration.

The full list of available block names is:

UnicodeBlock_BasicLatin, UnicodeBlock_Latin1Supplement, UnicodeBlock_LatinExtendedA, UnicodeBlock_LatinExtendedB,
    UnicodeBlock_IPAExtensions, UnicodeBlock_SpacingModifierLetters, UnicodeBlock_CombiningDiacriticalMarks,
    UnicodeBlock_GreekandCoptic, UnicodeBlock_Cyrillic, UnicodeBlock_CyrillicSupplement, UnicodeBlock_Armenian,
    UnicodeBlock_Hebrew, UnicodeBlock_Arabic, UnicodeBlock_Syriac, UnicodeBlock_ArabicSupplement, UnicodeBlock_Thaana,
    UnicodeBlock_NKo, UnicodeBlock_Samaritan, UnicodeBlock_Mandaic, UnicodeBlock_SyriacSupplement,
    UnicodeBlock_ArabicExtendedA, UnicodeBlock_Devanagari, UnicodeBlock_Bengali, UnicodeBlock_Gurmukhi,
    UnicodeBlock_Gujarati, UnicodeBlock_Oriya, UnicodeBlock_Tamil, UnicodeBlock_Telugu, UnicodeBlock_Kannada,
    UnicodeBlock_Malayalam, UnicodeBlock_Sinhala, UnicodeBlock_Thai, UnicodeBlock_Lao, UnicodeBlock_Tibetan,
    UnicodeBlock_Myanmar, UnicodeBlock_Georgian, UnicodeBlock_HangulJamo, UnicodeBlock_Ethiopic,
    UnicodeBlock_EthiopicSupplement, UnicodeBlock_Cherokee, UnicodeBlock_UnifiedCanadianAboriginalSyllabics,
    UnicodeBlock_Ogham, UnicodeBlock_Runic, UnicodeBlock_Tagalog, UnicodeBlock_Hanunoo, UnicodeBlock_Buhid,
    UnicodeBlock_Tagbanwa, UnicodeBlock_Khmer, UnicodeBlock_Mongolian,
    UnicodeBlock_UnifiedCanadianAboriginalSyllabicsExtended, UnicodeBlock_Limbu, UnicodeBlock_TaiLe,
    UnicodeBlock_NewTaiLue, UnicodeBlock_KhmerSymbols, UnicodeBlock_Buginese, UnicodeBlock_TaiTham,
    UnicodeBlock_CombiningDiacriticalMarksExtended, UnicodeBlock_Balinese, UnicodeBlock_Sundanese, UnicodeBlock_Batak,
    UnicodeBlock_Lepcha, UnicodeBlock_OlChiki, UnicodeBlock_CyrillicExtendedC, UnicodeBlock_GeorgianExtended,
    UnicodeBlock_SundaneseSupplement, UnicodeBlock_VedicExtensions, UnicodeBlock_PhoneticExtensions,
    UnicodeBlock_PhoneticExtensionsSupplement, UnicodeBlock_CombiningDiacriticalMarksSupplement,
    UnicodeBlock_LatinExtendedAdditional, UnicodeBlock_GreekExtended, UnicodeBlock_GeneralPunctuation,
    UnicodeBlock_SuperscriptsandSubscripts, UnicodeBlock_CurrencySymbols,
    UnicodeBlock_CombiningDiacriticalMarksforSymbols, UnicodeBlock_LetterlikeSymbols, UnicodeBlock_NumberForms,
    UnicodeBlock_Arrows, UnicodeBlock_MathematicalOperators, UnicodeBlock_MiscellaneousTechnical,
    UnicodeBlock_ControlPictures, UnicodeBlock_OpticalCharacterRecognition, UnicodeBlock_EnclosedAlphanumerics,
    UnicodeBlock_BoxDrawing, UnicodeBlock_BlockElements, UnicodeBlock_GeometricShapes,
    UnicodeBlock_MiscellaneousSymbols, UnicodeBlock_Dingbats, UnicodeBlock_MiscellaneousMathematicalSymbolsA,
    UnicodeBlock_SupplementalArrowsA, UnicodeBlock_BraillePatterns, UnicodeBlock_SupplementalArrowsB,
    UnicodeBlock_MiscellaneousMathematicalSymbolsB, UnicodeBlock_SupplementalMathematicalOperators,
    UnicodeBlock_MiscellaneousSymbolsandArrows, UnicodeBlock_Glagolitic, UnicodeBlock_LatinExtendedC,
    UnicodeBlock_Coptic, UnicodeBlock_GeorgianSupplement, UnicodeBlock_Tifinagh, UnicodeBlock_EthiopicExtended,
    UnicodeBlock_CyrillicExtendedA, UnicodeBlock_SupplementalPunctuation, UnicodeBlock_CJKRadicalsSupplement,
    UnicodeBlock_KangxiRadicals, UnicodeBlock_IdeographicDescriptionCharacters, UnicodeBlock_CJKSymbolsandPunctuation,
    UnicodeBlock_Hiragana, UnicodeBlock_Katakana, UnicodeBlock_Bopomofo, UnicodeBlock_HangulCompatibilityJamo,
    UnicodeBlock_Kanbun, UnicodeBlock_BopomofoExtended, UnicodeBlock_CJKStrokes,
    UnicodeBlock_KatakanaPhoneticExtensions, UnicodeBlock_EnclosedCJKLettersandMonths, UnicodeBlock_CJKCompatibility,
    UnicodeBlock_CJKUnifiedIdeographsExtensionA, UnicodeBlock_YijingHexagramSymbols, UnicodeBlock_CJKUnifiedIdeographs,
    UnicodeBlock_YiSyllables, UnicodeBlock_YiRadicals, UnicodeBlock_Lisu, UnicodeBlock_Vai,
    UnicodeBlock_CyrillicExtendedB, UnicodeBlock_Bamum, UnicodeBlock_ModifierToneLetters, UnicodeBlock_LatinExtendedD,
    UnicodeBlock_SylotiNagri, UnicodeBlock_CommonIndicNumberForms, UnicodeBlock_Phagspa, UnicodeBlock_Saurashtra,
    UnicodeBlock_DevanagariExtended, UnicodeBlock_KayahLi, UnicodeBlock_Rejang, UnicodeBlock_HangulJamoExtendedA,
    UnicodeBlock_Javanese, UnicodeBlock_MyanmarExtendedB, UnicodeBlock_Cham, UnicodeBlock_MyanmarExtendedA,
    UnicodeBlock_TaiViet, UnicodeBlock_MeeteiMayekExtensions, UnicodeBlock_EthiopicExtendedA,
    UnicodeBlock_LatinExtendedE, UnicodeBlock_CherokeeSupplement, UnicodeBlock_MeeteiMayek,
    UnicodeBlock_HangulSyllables, UnicodeBlock_HangulJamoExtendedB, UnicodeBlock_HighSurrogates,
    UnicodeBlock_HighPrivateUseSurrogates, UnicodeBlock_LowSurrogates, UnicodeBlock_PrivateUseArea,
    UnicodeBlock_CJKCompatibilityIdeographs, UnicodeBlock_AlphabeticPresentationForms,
    UnicodeBlock_ArabicPresentationFormsA, UnicodeBlock_VariationSelectors, UnicodeBlock_VerticalForms,
    UnicodeBlock_CombiningHalfMarks, UnicodeBlock_CJKCompatibilityForms, UnicodeBlock_SmallFormVariants,
    UnicodeBlock_ArabicPresentationFormsB, UnicodeBlock_HalfwidthandFullwidthForms, UnicodeBlock_Specials,
    UnicodeBlock_LinearBSyllabary, UnicodeBlock_LinearBIdeograms, UnicodeBlock_AegeanNumbers,
    UnicodeBlock_AncientGreekNumbers, UnicodeBlock_AncientSymbols, UnicodeBlock_PhaistosDisc, UnicodeBlock_Lycian,
    UnicodeBlock_Carian, UnicodeBlock_CopticEpactNumbers, UnicodeBlock_OldItalic, UnicodeBlock_Gothic,
    UnicodeBlock_OldPermic, UnicodeBlock_Ugaritic, UnicodeBlock_OldPersian, UnicodeBlock_Deseret, UnicodeBlock_Shavian,
    UnicodeBlock_Osmanya, UnicodeBlock_Osage, UnicodeBlock_Elbasan, UnicodeBlock_CaucasianAlbanian,
    UnicodeBlock_LinearA, UnicodeBlock_CypriotSyllabary, UnicodeBlock_ImperialAramaic, UnicodeBlock_Palmyrene,
    UnicodeBlock_Nabataean, UnicodeBlock_Hatran, UnicodeBlock_Phoenician, UnicodeBlock_Lydian,
    UnicodeBlock_MeroiticHieroglyphs, UnicodeBlock_MeroiticCursive, UnicodeBlock_Kharoshthi,
    UnicodeBlock_OldSouthArabian, UnicodeBlock_OldNorthArabian, UnicodeBlock_Manichaean, UnicodeBlock_Avestan,
    UnicodeBlock_InscriptionalParthian, UnicodeBlock_InscriptionalPahlavi, UnicodeBlock_PsalterPahlavi,
    UnicodeBlock_OldTurkic, UnicodeBlock_OldHungarian, UnicodeBlock_HanifiRohingya, UnicodeBlock_RumiNumeralSymbols,
    UnicodeBlock_OldSogdian, UnicodeBlock_Sogdian, UnicodeBlock_Elymaic, UnicodeBlock_Brahmi, UnicodeBlock_Kaithi,
    UnicodeBlock_SoraSompeng, UnicodeBlock_Chakma, UnicodeBlock_Mahajani, UnicodeBlock_Sharada,
    UnicodeBlock_SinhalaArchaicNumbers, UnicodeBlock_Khojki, UnicodeBlock_Multani, UnicodeBlock_Khudawadi,
    UnicodeBlock_Grantha, UnicodeBlock_Newa, UnicodeBlock_Tirhuta, UnicodeBlock_Siddham, UnicodeBlock_Modi,
    UnicodeBlock_MongolianSupplement, UnicodeBlock_Takri, UnicodeBlock_Ahom, UnicodeBlock_Dogra,
    UnicodeBlock_WarangCiti, UnicodeBlock_Nandinagari, UnicodeBlock_ZanabazarSquare, UnicodeBlock_Soyombo,
    UnicodeBlock_PauCinHau, UnicodeBlock_Bhaiksuki, UnicodeBlock_Marchen, UnicodeBlock_MasaramGondi,
    UnicodeBlock_GunjalaGondi, UnicodeBlock_Makasar, UnicodeBlock_TamilSupplement, UnicodeBlock_Cuneiform,
    UnicodeBlock_CuneiformNumbersandPunctuation, UnicodeBlock_EarlyDynasticCuneiform, UnicodeBlock_EgyptianHieroglyphs,
    UnicodeBlock_EgyptianHieroglyphFormatControls, UnicodeBlock_AnatolianHieroglyphs, UnicodeBlock_BamumSupplement,
    UnicodeBlock_Mro, UnicodeBlock_BassaVah, UnicodeBlock_PahawhHmong, UnicodeBlock_Medefaidrin, UnicodeBlock_Miao,
    UnicodeBlock_IdeographicSymbolsandPunctuation, UnicodeBlock_Tangut, UnicodeBlock_TangutComponents,
    UnicodeBlock_KanaSupplement, UnicodeBlock_KanaExtendedA, UnicodeBlock_SmallKanaExtension, UnicodeBlock_Nushu,
    UnicodeBlock_Duployan, UnicodeBlock_ShorthandFormatControls, UnicodeBlock_ByzantineMusicalSymbols,
    UnicodeBlock_MusicalSymbols, UnicodeBlock_AncientGreekMusicalNotation, UnicodeBlock_MayanNumerals,
    UnicodeBlock_TaiXuanJingSymbols, UnicodeBlock_CountingRodNumerals, UnicodeBlock_MathematicalAlphanumericSymbols,
    UnicodeBlock_SuttonSignWriting, UnicodeBlock_GlagoliticSupplement, UnicodeBlock_NyiakengPuachueHmong,
    UnicodeBlock_Wancho, UnicodeBlock_MendeKikakui, UnicodeBlock_Adlam, UnicodeBlock_IndicSiyaqNumbers,
    UnicodeBlock_OttomanSiyaqNumbers, UnicodeBlock_ArabicMathematicalAlphabeticSymbols, UnicodeBlock_MahjongTiles,
    UnicodeBlock_DominoTiles, UnicodeBlock_PlayingCards, UnicodeBlock_EnclosedAlphanumericSupplement,
    UnicodeBlock_EnclosedIdeographicSupplement, UnicodeBlock_MiscellaneousSymbolsandPictographs, UnicodeBlock_Emoticons,
    UnicodeBlock_OrnamentalDingbats, UnicodeBlock_TransportandMapSymbols, UnicodeBlock_AlchemicalSymbols,
    UnicodeBlock_GeometricShapesExtended, UnicodeBlock_SupplementalArrowsC,
    UnicodeBlock_SupplementalSymbolsandPictographs, UnicodeBlock_ChessSymbols,
    UnicodeBlock_SymbolsandPictographsExtendedA, UnicodeBlock_CJKUnifiedIdeographsExtensionB,
    UnicodeBlock_CJKUnifiedIdeographsExtensionC, UnicodeBlock_CJKUnifiedIdeographsExtensionD,
    UnicodeBlock_CJKUnifiedIdeographsExtensionE, UnicodeBlock_CJKUnifiedIdeographsExtensionF,
    UnicodeBlock_CJKCompatibilityIdeographsSupplement, UnicodeBlock_Tags, UnicodeBlock_VariationSelectorsSupplement,
    UnicodeBlock_SupplementaryPrivateUseAreaA, UnicodeBlock_SupplementaryPrivateUseAreaB,

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 sample code above cannot render glyphs correctly unless font.unicodeCoverage 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.

set_target_properties(my_app
                      PROPERTIES
                        QUL_MONOTYPE_SPARK_FONT_FILE "${CMAKE_CURRENT_SOURCE_DIR}/fonts/SampleFontmap.fmp")

Font formats

The value of QUL_DEFAULT_FONT_FAMILY CMake target property is ignored by all but the Fontmap format. Thus, if not using a Fontmap font, variable does not need to be set.

When not using a Fontmap file, only the font.pixelSize font configuration property is respected.

TrueType fonts

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

Fontmaps

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 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:

QUL_MONOTYPE_SPARK_CACHE_PRIMING

Enable cache priming for the Monotype Spark font engine

QUL_MONOTYPE_SPARK_CACHE_SIZE

Set maximum cache size for the Monotype Spark font engine

QUL_MONOTYPE_SPARK_HEAP_SIZE

Set maximum heap size for 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. Qt for MCUs does not provide a public API yet to use this feature.

Font class mapping

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

As mentioned earlier, certain Qt Quick Ultralite items have properties for configuring fonts. One of the components that affect font selection in a Fontmap file is a font class name. See Fontmap's documentation, to know how font selection works. With the Monotype Spark font engine, font configurations from QML files are mapped by the fontcompiler to Fontmap's font class names. 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

The fontcompiler tool for the following example will expect to find "DejaVu Sans Mono" font class name in the provided Fontmap file.

Text {
    font.family: "DejaVu Sans Mono"
}

If we assume that QUL_DEFAULT_FONT_FAMILY="My Font". The fontcompiler tool will expect to find "My Font ExtraLight" font class name in the provided Fontmap file.

Text {
    font.weight: Font.ExtraLight
}

Porting an existing application

If you already have a qml application, which for example uses sans-serif font family as in the following example:

Text {
    font.family: "sans-serif"
}

The fontcompiler tool maps that to a "sans-serif" font class name. To design your Fontmap for the above example, you need to map a font file 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.

Caching

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 font.unicodeCoverage 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.

Note: The font.unicodeCoverage property has a different meaning when used with the Spark engine compared to the static font engine.

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.

Available under certain Qt licenses.
Find out more.