Text

Purpose

Text selects font data, validates/decodes text, shapes Unicode runs and prepares drawable glyphs. Font loading, shaping, rasterization and graphics upload are different stages with different ownership and execution requirements.

Interface

Types below are in CE::Text unless another namespace is shown.

Types and operations

API and purpose

FontService, Font
Configure named families and a default through Context::fonts(), retain a resolved font, and choose/restore named group members by stable references. Configure fonts once; choose and save a font.

FontSelection, FontCollection
Select ordered fallback fonts and retain immutable font-byte snapshots. Font selection; font discovery.

ShapedText, LayoutOptions
Run layout_text() and inspect shaped lines, glyphs and source mapping. Shaping, direction and width.

Rendering::Prepared, Rendering::Generation
Prepare CPU glyph geometry, upload retained resources and resolve text draw packets. Preparation and submission; text task.

Rendering::Updater, Rendering::Request
Own asynchronous preparation/upload/adoption for changing text while retaining the last success. Retained updates and failures.

FontRasterizer, FontRasterGlyph
Obtain shared CPU font metrics, raster pixels and kerning for toolkit adapters. UI font responsibilities; rasterizer declarations.

Legacy::Font
Use the separate legacy ASCII/bitmap compatibility path. Legacy bitmap fonts.

Sources, direction and raster values

Type

Choices and details

FontConfiguration, FontFamily

Named family sources, selection groups, the application default and common fallback references. Catalogue configuration.

FontStyle, FontFace

Requested numeric weight/italic state and borrowed retained face bytes/index/style for adapters. Retained handles and style.

FontSource

File, system family or string source selection; make discovery policy explicit. Font sources and fallback.

ParagraphDirection

Automatic, LeftToRight, RightToLeft paragraph direction. Shaping and bidi direction.

SourceRange, GlyphId

Distinguish source byte/scalar ranges from font-qualified glyph indices. Encoding and source indices.

FontSizing, FontBitmapFormat

Raster sizing in Pixels/Characters; output Alpha/PremultipliedRGBA pixel storage. Raster size/format declarations; toolkit alpha conventions.

Usage

For a fixed label, retain a font, lay out the string, prepare CPU glyph data and upload one immutable generation. Resolve that generation during frame preparation. For changing text, Rendering::Updater manages replacement work while the last successful generation remains visible.

        ---
config:
  theme: base
  themeVariables:
    fontFamily: system-ui, sans-serif
    fontSize: 14px
  flowchart:
    htmlLabels: true
    curve: linear
    nodeSpacing: 22
    rankSpacing: 38
    padding: 12
---
flowchart LR
    accTitle: Text · simple static label
    accDescr: Local names omit Text::; ambiguous nested namespaces remain qualified. Arrows point toward dependencies. Application roles are rounded; named API operations have rounded corners. Dashed arrows mark optional choices.
    k0(["Application<br/>init_platform()"]):::app
    k1["FontService"]:::focal
    k2["Font"]:::focal
    k3("layout_text()"):::focal
    k4["ShapedText"]:::focal
    k5("Text::Rendering::<br/>prepare()"):::focal
    k6["Text::Rendering::<br/>Prepared"]:::focal
    k7("Text::Rendering::<br/>upload()"):::focal
    k8["Rendering::Resources::<br/>Provider"]:::neighbor
    k9["Text::Rendering::<br/>Generation"]:::focal
    k0 --> k1
    k1 --> k2
    k3 --> k2
    k3 --> k4
    k5 --> k4
    k5 --> k6
    k7 --> k6
    k7 --> k8
    k7 --> k9
    classDef focal fill:#e7f3ef,stroke:#387d6b,color:#153d33,stroke-width:1.2px
    classDef neighbor fill:#f0f3f8,stroke:#8c9bb1,color:#35445b,stroke-width:1px
    classDef app fill:#fff2df,stroke:#c09452,color:#674515,stroke-dasharray:5 3
    classDef system fill:#eaf0fc,stroke:#617fab,color:#263f69,stroke-width:1.2px
    linkStyle default stroke:#7e8fa7,stroke-width:1.2px

    

Local names omit Text:: where unambiguous. Explore this diagram and its other views →

The arrows show dependencies, including the owned result types used by each operation; the stage order is layout, prepare, upload, then draw resolution. See the updater diagram for asynchronous replacement and the engine dependency map for the font and resource relationships.

Choose the text path

Reader task

Start with

Work the application owns

Static world label or HUD message

layout_text(), Rendering::prepare() and Rendering::upload()

Select the font and layout options; retain and submit the complete generation. Explicit stages.

Score, dialogue or other changing text

Text::Rendering::Updater

Construct on platform, request content and call update() on its serialized simulation owner; inspect failure() and explicitly retry() an unchanged failed request. Update task.

Editable widget/document text

GUI toolkit session

Author native toolkit UI and route input/focus. Shared Engine fonts do not replace toolkit layout/editing behavior.

Existing ASCII/bitmap content

Text::Legacy

Follow the separate legacy font contract; do not infer Unicode shaping from this compatibility path.

Uses

Consumer

Dependency

Integration boundary

Font selection and layout

Text::FontService, retained Text::FontCollection and file/system-font discovery

Configure the catalogue before consumers. Layout retains the selected font-byte snapshot rather than borrowing the source string or reopening font files.

Text::Rendering::upload()

Rendering::Resources::Provider from Resources

Upload complete glyph pages/geometry on graphics and retain a compatible default or explicit material.

Text::Rendering::Updater

Workers::Group and Runtime::PlatformDispatcher::Submission

Uses a Context-tracked CPU group and saved platform endpoint. Jobs own requests and borrow neither updater nor game.

Glyph draw resolution

Rendering DrawStyle2D, pass values and retained resource bindings

Convert an uploaded generation to packets without repeating layout, rasterization or upload.

The explicit layout/prepare path does not schedule jobs. Updater supplies scheduling and nonblocking adoption through the worker group and platform endpoint above.

Used by

Consumer

Text value/service

Responsibility

Application labels, dialogue and HUDs

Text::Rendering::Generation

Retain the current complete result and submit it from frame preparation. Old frames may retain older generations.

Runtime Context

Text::FontService

Own the configured catalogue and default font; retained font handles can outlive that service.

GUI TGUI/RmlUi adapters

Text::Font and Text::FontRasterizer

Import retained font bytes/metrics while keeping native toolkit layout, mutable atlas and editing state on the UI owner.

Inspect layout before uploading

Text::ShapedText exposes lines, positioned glyphs and source mapping, so CPU layout can be inspected without a graphics provider. Local positions are Y-up pixels; pixel_height is the font em size. A glyph ID belongs to its retained font collection. Source UTF-8 byte ranges, Unicode scalar ranges and shaping clusters answer different indexing questions; use the encoding and source-index guide before mapping selection or hit-test state back to an application string.

Contracts

The context owns its font catalogue; an unconfigured catalogue supplies the embedded default. Named families and random selection groups use stable application references. Font handles retain CPU snapshots independently of the catalogue and Context. Configure before consumers: publishing another catalogue does not rebind an existing handle or widget. Lookup does not inspect changed source files.

Random selection runs only when requested. Restoring a saved reference reuses it while it is available and remains in the named group; otherwise it selects a replacement, then uses the application default or embedded fallback if no group candidate is available. The application persists the returned reference and owns shared object identity; runtime handles and font bytes are not save data.

Layout positions use local Y-up pixels; pixel_height is the font em size. Glyph IDs are qualified by their retained font collection. Shaping clusters and UTF-8 byte/scalar ranges are not interchangeable character indices. Layout retains the font-byte snapshot used for later preparation, not a borrowed input string or mutable native face.

Fallback and wrapping operate on the documented Unicode boundaries. Replacing text produces another layout/uploaded generation; it must not mutate a generation already retained by a frame. Upload retains a compatible default material; explicit custom materials must match the generation’s geometry.

FontRasterizer::load() copies font bytes; its copies share synchronized native face state. Returned metrics/glyph pixels own their values and can survive the rasterizer. This CPU service neither borrows a graphics provider nor makes a toolkit’s mutable atlas thread-safe.

Lifecycle

Load selected fonts at a loading boundary, lay out text and prepare its CPU representation. Upload after graphics initialization and retain the generation in the game/HUD. Replace it when content changes, allowing published frames to retain older generations. Settle upload requests and release game handles before backend shutdown. Retained font bytes and native graphics lifetime are separate.

Execution

Font selection/layout/preparation are CPU stages; upload follows graphics affinity. Use owned request data across dispatch boundaries and consume completed futures without blocking simulation. Record positions and immutable generation handles during frame preparation.

Integration

For a static label, run the explicit CPU preparation and upload stages on the platform upload owner after graphics initialization. The configured default needs no application font plumbing:

auto font = engine_.fonts().default_font();
auto layout = CE::Text::layout_text(font, "Score: 0", {.pixel_height = 24});
auto prepared = CE::Text::Rendering::prepare(std::move(layout));
auto score = CE::Text::Rendering::upload(std::move(prepared), engine_.resources());

Retain score and resolve it using its retained material in frame preparation. For a score or other changing label, use Rendering::Updater to manage these stages without adding worker futures or upload/adoption bookkeeping to the game. It keeps the last successful generation while a replacement is pending or fails.

Limits and further reading

Text rendering is not a full editor/IME service. Do not infer arbitrary toolkit font compatibility or complete script acceptance from a basic label example. Read Unicode layout, encoding and source indices, font discovery, legacy fonts, layout declarations, shared rasterization operations and text rendering declarations.