Skip to content

Commit e10333a

Browse files
Merge pull request #1 from wieslawsoltes/feat/upstream-pretext-sync
feat: port upstream keep-all word breaking and rich-inline helpers
2 parents b9f352b + cf3c9b8 commit e10333a

38 files changed

Lines changed: 6097 additions & 1328 deletions

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ BenchmarkDotNet.Artifacts/
6565
project.lock.json
6666
project.fragment.lock.json
6767
artifacts/
68+
plan/
6869

6970
# Tye
7071
.tye/

Directory.Packages.props

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
See https://aka.platform.uno/using-uno-sdk#implicit-packages for more information regarding the Implicit Packages.
77
-->
88
<ItemGroup>
9+
<PackageVersion Include="Markdig" Version="0.43.0" />
910
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.11.1" />
1011
<PackageVersion Include="Microsoft.SourceLink.GitHub" Version="8.0.0" />
1112
<PackageVersion Include="SkiaSharp" Version="3.119.1" />

README.md

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ Key documentation:
2121
- [Choosing an API](https://wieslawsoltes.github.io/PretextSharp/articles/getting-started/choosing-an-api/)
2222
- [Prepared Text Lifecycle](https://wieslawsoltes.github.io/PretextSharp/articles/concepts/prepared-text-lifecycle/)
2323
- [Public Types and Operations](https://wieslawsoltes.github.io/PretextSharp/articles/reference/public-types-and-operations/)
24+
- [Rich Inline API](https://wieslawsoltes.github.io/PretextSharp/articles/reference/rich-inline-api/)
2425
- [Pretext.Uno Helpers](https://wieslawsoltes.github.io/PretextSharp/articles/reference/pretext-uno-helpers/)
2526

2627
## NuGet Packages
@@ -34,12 +35,16 @@ Key documentation:
3435

3536
- Prepare text once and reuse the result across repeated layout passes with `Prepare` and `PrepareWithSegments`.
3637
- Compute fast aggregate metrics with `Layout`, or materialize full line data with `LayoutWithLines`.
37-
- Stream line geometry incrementally with `LayoutNextLine` and `WalkLineRanges` for custom layout engines.
38+
- Stream line geometry incrementally with `LayoutNextLine`, `LayoutNextLineRange`, and `WalkLineRanges` for custom layout engines.
39+
- Re-materialize text lazily with `MaterializeLineRange` after cheap geometry-only probing.
40+
- Measure widest-line geometry without allocating text via `MeasureLineStats` and `MeasureNaturalWidth`.
3841
- Handle ordinary spaces, preserved spaces, tabs, hard breaks, non-breaking spaces, zero-width breaks, and soft hyphens.
42+
- Support `WordBreakMode.KeepAll` for CJK-focused no-space wrapping behavior.
43+
- Build rich inline flows with `PrepareRichInline`, `WalkRichInlineLineRanges`, and `MaterializeRichInlineLineRange`.
3944
- Support multilingual text with locale-aware segmentation on desktop targets and bidi-aware segment levels.
4045
- Depend only on `SkiaSharp` in the core library so the package can be used outside Uno as well.
4146
- Ship with a published `Pretext.Uno` companion library for reusable Uno host controls and obstacle-aware flow helpers.
42-
- Ship with deterministic parity tests and a Uno sample app that demonstrates bubbles, masonry, editorial, and justification layouts.
47+
- Ship with deterministic parity tests and a Uno sample app that demonstrates bubbles, masonry, editorial, justification, rich-inline, and virtualized markdown chat layouts.
4348

4449
## Core API
4550

@@ -50,7 +55,15 @@ Key documentation:
5055
| `Layout` | Return line count and total height for a given width and line height. |
5156
| `LayoutWithLines` | Return materialized line text and line widths. |
5257
| `LayoutNextLine` | Stream the next line from a given cursor for custom layout flows. |
58+
| `LayoutNextLineRange` | Stream geometry-only line ranges without materializing text. |
59+
| `MaterializeLineRange` | Turn a `LayoutLineRange` back into a materialized `LayoutLine`. |
5360
| `WalkLineRanges` | Iterate line geometry without allocating full line text. |
61+
| `MeasureLineStats` | Return line count plus widest line width for a prepared block. |
62+
| `MeasureNaturalWidth` | Return the widest unwrapped line width for prepared text. |
63+
| `PrepareRichInline` | Prepare multi-item inline flow with collapsed boundary whitespace and atomic items. |
64+
| `WalkRichInlineLineRanges` | Stream rich-inline line ranges without materializing fragment text. |
65+
| `MaterializeRichInlineLineRange` | Materialize one streamed rich-inline line when you actually need fragment text. |
66+
| `MeasureRichInlineStats` | Measure rich-inline line count and max line width. |
5467
| `ProfilePrepare` | Measure preparation cost for profiling and diagnostics. |
5568
| `SetLocale` | Override locale-sensitive segmentation behavior when needed. |
5669
| `ClearCache` | Reset cached font state and prepared segment text caches. |
@@ -63,6 +76,7 @@ Key documentation:
6376
| Actual line text and widths | `PrepareWithSegments` + `LayoutWithLines` |
6477
| One line at a time in a custom loop | `PrepareWithSegments` + `LayoutNextLine` |
6578
| Geometry only, fewer allocations | `PrepareWithSegments` + `WalkLineRanges` |
79+
| Rich inline fragments with atomic chips or badges | `PrepareRichInline` + `WalkRichInlineLineRanges` |
6680
| Preparation cost diagnostics | `ProfilePrepare` |
6781

6882
## Quick Start
@@ -95,6 +109,8 @@ foreach (var line in lines.Lines)
95109
}
96110
```
97111

112+
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.
113+
98114
The core package exposes the `Pretext` namespace and is not tied to Uno. Use it anywhere you use SkiaSharp.
99115

100116
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.
@@ -108,6 +124,32 @@ var prepared = PretextLayout.PrepareWithSegments(
108124
new PrepareOptions(WhiteSpaceMode.PreWrap));
109125
```
110126

127+
Use `WordBreakMode.KeepAll` when CJK-heavy text should avoid ordinary intra-run breaks:
128+
129+
```csharp
130+
var prepared = PretextLayout.PrepareWithSegments(
131+
"日本語foo-bar",
132+
"16px Inter",
133+
new PrepareOptions(WordBreak: WordBreakMode.KeepAll));
134+
```
135+
136+
Use the rich-inline helper when paragraph text and atomic inline boxes must share one flow:
137+
138+
```csharp
139+
var flow = PretextLayout.PrepareRichInline(
140+
[
141+
new RichInlineItem("Ship ", "16px Inter"),
142+
new RichInlineItem("@maya", "700 12px Inter", RichInlineBreakMode.Never, extraWidth: 18),
143+
new RichInlineItem("'s note wraps cleanly.", "16px Inter"),
144+
]);
145+
146+
PretextLayout.WalkRichInlineLineRanges(flow, 180, line =>
147+
{
148+
var materialized = PretextLayout.MaterializeRichInlineLineRange(flow, line);
149+
Console.WriteLine(string.Join("", materialized.Fragments.Select(f => f.Text)));
150+
});
151+
```
152+
111153
## Uno Companion
112154

113155
Install the Uno companion package when you want the reusable Uno-specific helpers on top of the core engine:
@@ -134,6 +176,7 @@ The sample app lives in `samples/PretextSamples` and demonstrates the library in
134176
- Bubbles
135177
- Masonry
136178
- Rich Text
179+
- Markdown Chat
137180
- Dynamic Layout
138181
- Editorial Engine
139182
- Justification Comparison

samples/PretextSamples/Assets/shower_thoughts.json

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

samples/PretextSamples/MainPage.xaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
<NavigationViewItem Content="Bubbles" Tag="bubbles" Icon="Comment" />
1818
<NavigationViewItem Content="Masonry" Tag="masonry" Icon="Library" />
1919
<NavigationViewItem Content="Rich Text" Tag="rich" Icon="Document" />
20+
<NavigationViewItem Content="Markdown Chat" Tag="markdown-chat" Icon="Comment" />
2021
<NavigationViewItem Content="Dynamic Layout" Tag="dynamic" Icon="Pictures" />
2122
<NavigationViewItem Content="Editorial Engine" Tag="editorial" Icon="Play" />
2223
<NavigationViewItem Content="Justification Comparison" Tag="justification" Icon="Document" />

samples/PretextSamples/MainPage.xaml.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ public sealed partial class MainPage : Page
1212
["bubbles"] = static () => new BubblesSampleView(),
1313
["masonry"] = static () => new MasonrySampleView(),
1414
["rich"] = static () => new RichNoteSampleView(),
15+
["markdown-chat"] = static () => new MarkdownChatSampleView(),
1516
["dynamic"] = static () => new DynamicLayoutSampleView(),
1617
["editorial"] = static () => new EditorialEngineSampleView(),
1718
["justification"] = static () => new JustificationComparisonSampleView(),

samples/PretextSamples/PretextSamples.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
<Project Sdk="Uno.Sdk">
22
<ItemGroup>
3+
<PackageReference Include="Markdig" />
34
<ProjectReference Include="..\..\src\Pretext.Uno\Pretext.Uno.csproj" />
45
<PackageReference Include="Tmds.DBus.Protocol" />
56
</ItemGroup>

0 commit comments

Comments
 (0)