Universal text preparation and line layout for any SkiaSharp-based UI, with grapheme-aware wrapping, locale-aware segmentation, bidi support, and streaming line walking.
The core Pretext package targets netstandard2.0, net461, net6.0, net8.0, and net10.0. The Pretext.Uno companion package and sample app remain net10.0-desktop.
PretextSharp is a .NET/C# port of the original pretext project by Cheng Lou.
Documentation site: wieslawsoltes.github.io/PretextSharp
Key documentation:
- Getting Started Overview
- Quickstart: Prepare and Layout
- Choosing an API
- Prepared Text Lifecycle
- Public Types and Operations
- Rich Inline API
- Pretext.Uno Helpers
- Prepare text once and reuse the result across repeated layout passes with
PrepareandPrepareWithSegments. - Compute fast aggregate metrics with
Layout, or materialize full line data withLayoutWithLines. - Stream line geometry incrementally with
LayoutNextLine,LayoutNextLineRange, andWalkLineRangesfor custom layout engines. - Re-materialize text lazily with
MaterializeLineRangeafter cheap geometry-only probing. - Measure widest-line geometry without allocating text via
MeasureLineStatsandMeasureNaturalWidth. - Handle ordinary spaces, preserved spaces, tabs, hard breaks, non-breaking spaces, zero-width breaks, and soft hyphens.
- Support
WordBreakMode.KeepAllfor CJK-focused no-space wrapping behavior. - Build rich inline flows with
PrepareRichInline,WalkRichInlineLineRanges, andMaterializeRichInlineLineRange. - Support multilingual text with locale-aware segmentation on desktop targets and bidi-aware segment levels.
- Depend only on
SkiaSharpin the core library so the package can be used outside Uno as well. - Ship with a published
Pretext.Unocompanion library for reusable Uno host controls and obstacle-aware flow helpers. - Ship with deterministic parity tests and a Uno sample app that demonstrates bubbles, masonry, editorial, justification, rich-inline, and virtualized markdown chat layouts.
| API | Purpose |
|---|---|
Prepare |
Prepare text for repeated layout when you only need aggregate metrics. |
PrepareWithSegments |
Prepare text and expose segments, widths, break metadata, and segment levels. |
Layout |
Return line count and total height for a given width and line height. |
LayoutWithLines |
Return materialized line text and line widths. |
LayoutNextLine |
Stream the next line from a given cursor for custom layout flows. |
LayoutNextLineRange |
Stream geometry-only line ranges without materializing text. |
MaterializeLineRange |
Turn a LayoutLineRange back into a materialized LayoutLine. |
WalkLineRanges |
Iterate line geometry without allocating full line text. |
MeasureLineStats |
Return line count plus widest line width for a prepared block. |
MeasureNaturalWidth |
Return the widest unwrapped line width for prepared text. |
PrepareRichInline |
Prepare multi-item inline flow with collapsed boundary whitespace and atomic items. |
WalkRichInlineLineRanges |
Stream rich-inline line ranges without materializing fragment text. |
MaterializeRichInlineLineRange |
Materialize one streamed rich-inline line when you actually need fragment text. |
MeasureRichInlineStats |
Measure rich-inline line count and max line width. |
ProfilePrepare |
Measure preparation cost for profiling and diagnostics. |
SetLocale |
Override locale-sensitive segmentation behavior when needed. |
ClearCache |
Reset cached font state and prepared segment text caches. |
| Need | Start with |
|---|---|
| Line count and total height only | Prepare + Layout |
| Actual line text and widths | PrepareWithSegments + LayoutWithLines |
| One line at a time in a custom loop | PrepareWithSegments + LayoutNextLine |
| Geometry only, fewer allocations | PrepareWithSegments + WalkLineRanges |
| Rich inline fragments with atomic chips or badges | PrepareRichInline + WalkRichInlineLineRanges |
| Preparation cost diagnostics | ProfilePrepare |
Install from NuGet:
dotnet add package PretextSupported target frameworks for the core package:
netstandard2.0net461net6.0net8.0net10.0
Then prepare and lay out text:
using Pretext;
const string text = "Hello soft\u00ADwrapped world";
const string font = "16px Inter";
const double lineHeight = 20;
var prepared = PretextLayout.PrepareWithSegments(text, font);
var metrics = PretextLayout.Layout(prepared, maxWidth: 160, lineHeight);
var lines = PretextLayout.LayoutWithLines(prepared, maxWidth: 160, lineHeight);
Console.WriteLine(metrics.LineCount);
Console.WriteLine(metrics.Height);
foreach (var line in lines.Lines)
{
Console.WriteLine($"{line.Text} ({line.Width})");
}If the prepared text is empty after normalization, Layout returns new LayoutResult(0, 0). If a container in your UI must still reserve one visual row, clamp with Math.Max(1, metrics.LineCount) in the caller instead of expecting Pretext to synthesize a blank line.
The core package exposes the Pretext namespace and is not tied to Uno. Use it anywhere you use SkiaSharp.
The font argument is a CSS-like subset such as 16px Inter, italic 16px Georgia, or 700 18px "IBM Plex Sans". Line height is supplied separately to layout calls.
Use WhiteSpaceMode.PreWrap when your layout needs preserved spaces, tabs, or hard breaks:
var prepared = PretextLayout.PrepareWithSegments(
"foo\tbar\nbaz",
"16px Inter",
new PrepareOptions(WhiteSpaceMode.PreWrap));Use WordBreakMode.KeepAll when CJK-heavy text should avoid ordinary intra-run breaks:
var prepared = PretextLayout.PrepareWithSegments(
"日本語foo-bar",
"16px Inter",
new PrepareOptions(WordBreak: WordBreakMode.KeepAll));Use the rich-inline helper when paragraph text and atomic inline boxes must share one flow:
var flow = PretextLayout.PrepareRichInline(
[
new RichInlineItem("Ship ", "16px Inter"),
new RichInlineItem("@maya", "700 12px Inter", RichInlineBreakMode.Never, extraWidth: 18),
new RichInlineItem("'s note wraps cleanly.", "16px Inter"),
]);
PretextLayout.WalkRichInlineLineRanges(flow, 180, line =>
{
var materialized = PretextLayout.MaterializeRichInlineLineRange(flow, line);
Console.WriteLine(string.Join("", materialized.Fragments.Select(f => f.Text)));
});Install the Uno companion package when you want the reusable Uno-specific helpers on top of the core engine:
dotnet add package Pretext.UnoIt brings the Pretext core package transitively and exposes:
Pretext.PretextLayoutPretext.Uno.Controls.StretchScrollHostPretext.Uno.Controls.UiRenderSchedulerPretext.Uno.Layout.PreparedTextMetricsPretext.Uno.Layout.ColumnFlowLayoutPretext.Uno.Layout.ObstacleLayoutHelper
The sample app lives in samples/PretextSamples and demonstrates the library in visually different layouts. It uses Uno Platform, exercises the core Pretext APIs together with the Pretext.Uno companion helpers, and keeps only sample-specific UI/theme code in the sample tree.
- Overview
- Accordion
- Bubbles
- Masonry
- Rich Text
- Markdown Chat
- Dynamic Layout
- Editorial Engine
- Justification Comparison
- Variable ASCII
Run it with:
dotnet run --project samples/PretextSamples/PretextSamples.csproj -f net10.0-desktop- .NET 10 SDK for building this repository
- Uno.Sdk 6.5.x for the sample app only
dotnet build PretextSamples.slnx
dotnet test tests/Pretext.Uno.Tests/Pretext.Uno.Tests.csproj
dotnet pack src/Pretext/Pretext.csproj -c Release
dotnet pack src/Pretext.Uno/Pretext.Uno.csproj -c ReleaseThe repository includes:
ci.ymlfor multi-platform build, test, docs validation, and preview package generationdocs.ymlfor GitHub Pages deploymentrelease.ymlfor tag-driven packing, optional NuGet publication, and GitHub release creation- a Lunet docs site in
site/
The docs cover:
- installation and namespace/package selection
- font strings, measurement, and prepared-text lifecycle
- whitespace and break behavior, locale-aware segmentation, and bidi
- practical Uno and generic SkiaSharp integration patterns
- full reference coverage for the public core API and
Pretext.Unohelpers
src/
Pretext/
Pretext.Uno/
tests/
Pretext.Uno.Tests/
samples/
PretextSamples/
site/
The core Pretext implementation in this repository is ported from the original pretext project by Cheng Lou. This repository adapts that work to .NET, SkiaSharp, packaging, tests, samples, and companion Uno helpers.
MIT. See LICENSE.