Skip to content

ui::testing::HeadlessTextMeasurer

Header: winui/testing/HeadlessUI.hpp.

Derives from ui::TextMeasurer.

Deterministic, platform-independent text metrics. They don't match the real text renderer's metrics, but they make layout reproducible in tests and on any OS.

Every code point advances by font_size * AdvanceRatio (nudged by weight, plus character spacing); a line is font_size * LineRatio tall unless the style sets a line height. The semantic goldens are laid out with it. HeadlessUI owns one; construct your own to measure or lay out a bare element in a test.

Example:

const ui::testing::HeadlessTextMeasurer measurer;
ui::TextStyle style;
style.font_size = 20.0f;
const ui::Size one = measurer.measure("abcd", style);
REQUIRE(one.width == 4 * 20.0f * ui::testing::HeadlessTextMeasurer::AdvanceRatio);

ui::ButtonControl button{"OK"};
const ui::Size desired = button.measure(ui::Size{200, ui::Unbounded}, measurer, ui::Theme::default_light());

AdvanceRatio

static float AdvanceRatio = 0.55f

The advance width per em, a rough monospace stand-in for a proportional UI font.

LineRatio

static float LineRatio = 1.35f

Line height per em, used when TextStyle::line_height is unset.

BaselineRatio

static float BaselineRatio = 0.8f

The baseline's depth into a line, as a share of the line height.

weight_advance_factor

static float weight_advance_factor(FontWeight w)

A weight-dependent nudge on top of AdvanceRatio. Lighter weights sit slightly narrower and heavier ones slightly wider, so a semantic golden orders weights correctly.

measure

TextMetrics measure(std::string_view text, const TextStyle& style) const override

One line of text: code points times the advance, by one line height. \n is not treated as a break here; measure_wrapped() handles it.

measure_wrapped

TextMetrics measure_wrapped(std::string_view text, const TextStyle& style, float max_width) const override

The run broken into lines no wider than max_width per style.wrapping: the widest line's width and the height of all lines together. A width of 0 or less, an infinite one (ui::Unbounded), or a NoWrap style, is measure(). The default ignores wrapping altogether; both shipped measurers override it.