{"id":50557193,"url":"https://github.com/wieslawsoltes/protext","last_synced_at":"2026-06-04T08:02:10.722Z","repository":{"id":355566817,"uuid":"1228598853","full_name":"wieslawsoltes/ProText","owner":"wieslawsoltes","description":"High-performance text controls for Avalonia, powered by PretextSharp and Skia.","archived":false,"fork":false,"pushed_at":"2026-05-11T19:32:30.000Z","size":346,"stargazers_count":1,"open_issues_count":0,"forks_count":1,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-11T19:45:30.225Z","etag":null,"topics":["avalonia","controls","pretext","textblock","textbox"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/wieslawsoltes.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2026-05-04T07:23:28.000Z","updated_at":"2026-05-04T20:55:54.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/wieslawsoltes/ProText","commit_stats":null,"previous_names":["wieslawsoltes/protext"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/wieslawsoltes/ProText","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wieslawsoltes%2FProText","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wieslawsoltes%2FProText/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wieslawsoltes%2FProText/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wieslawsoltes%2FProText/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/wieslawsoltes","download_url":"https://codeload.github.com/wieslawsoltes/ProText/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wieslawsoltes%2FProText/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33895175,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-04T02:00:06.755Z","response_time":64,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["avalonia","controls","pretext","textblock","textbox"],"created_at":"2026-06-04T08:02:09.565Z","updated_at":"2026-06-04T08:02:10.703Z","avatar_url":"https://github.com/wieslawsoltes.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# ProText\n\nHigh-performance Avalonia 12 text controls powered by PretextSharp.\n\nProText is a focused text rendering toolkit for Avalonia applications that need fast measurement, predictable caching, rich inline display, editable text presentation, and TextBox-like input surfaces without routing text rendering through Avalonia `TextBlock` fallbacks.\n\nThe repository, library project, package id, assembly name, and CLR namespace are now `ProText` because the scope covers display, presenter, and editable text controls.\n\nThe controls are mapped into Avalonia's XML namespace through assembly-level `XmlnsDefinition` metadata, so they can be used directly in normal Avalonia XAML once the package or project reference is present.\n\n## Packages\n\n| Package | Version | Downloads | Purpose |\n| --- | --- | --- | --- |\n| [ProText](https://www.nuget.org/packages/ProText/) | [![NuGet](https://img.shields.io/nuget/v/ProText.svg)](https://www.nuget.org/packages/ProText/) | [![Downloads](https://img.shields.io/nuget/dt/ProText.svg)](https://www.nuget.org/packages/ProText/) | ProText control library with `ProTextBlock`, `ProTextPresenter`, `ProTextBox`, Fluent theme resources, XML documentation, README metadata, and symbol packages. |\n\nInstall the package with:\n\n```bash\ndotnet add package ProText\n```\n\nOr reference it directly from a project file:\n\n```xml\n\u003cPackageReference Include=\"ProText\" Version=\"0.1.0\" /\u003e\n```\n\nFor local development inside this repository, reference the project directly:\n\n```xml\n\u003cProjectReference Include=\"../../src/ProText/ProText.csproj\" /\u003e\n```\n\nPackage metadata:\n\n- Package id: `ProText`\n- Package title: `ProText`\n- Description: `High-performance Avalonia 12 text controls powered by PretextSharp.`\n- License: `MIT`\n- Repository: `https://github.com/wieslawsoltes/ProText`\n- Dependencies: Avalonia, Avalonia Skia rendering support, Pretext, and Pretext Skia rendering support\n- Artifacts: `.nupkg`, `.snupkg`, XML documentation, and the root [README.md](README.md)\n\nOnly [src/ProText/ProText.csproj](src/ProText/ProText.csproj) is packable. Samples, tests, and benchmark projects are explicitly marked as non-packable.\n\n## Controls\n\n### `ProTextBlock`\n\n`ProTextBlock` is a high-performance display control intended for TextBlock-like scenarios: labels, dense rows, document fragments, diagnostics, search results, preview text, telemetry panels, and other text-heavy read-only UI.\n\nIt mirrors the public text-related `TextBlock` surface where practical, including:\n\n- `Text` and `Inlines`\n- `Background`, `Padding`, and `Foreground`\n- `FontFamily`, `FontSize`, `FontStyle`, `FontWeight`, `FontStretch`, and `FontFeatures`\n- `TextAlignment`, `TextWrapping`, `TextTrimming`, `TextDecorations`, `LetterSpacing`, `LineHeight`, `LineSpacing`, `MaxLines`, and `BaselineOffset`\n- attached property helpers for TextBlock-compatible layout properties\n- ProText-specific properties such as `UseGlobalCache`, `UsePretextRendering`, `PretextWhiteSpace`, `PretextWordBreak`, and `PretextLineHeightMultiplier`\n\nPlain text and supported inline content are prepared through PretextSharp, measured through the shared ProText layout layer, and rendered through Skia custom drawing.\n\n### `ProTextPresenter`\n\n`ProTextPresenter` is the reusable presenter layer for custom editable or selectable text controls. It uses the same rich content preparation, layout snapshots, cache identity, font fallback, and Skia renderer as `ProTextBlock`, while exposing presenter-style caret, selection, preedit, password, measurement, and hit-test APIs.\n\nNotable features include:\n\n- `Text` and display-oriented `Inlines`\n- `PreeditText` and `PreeditTextCursorPosition` for IME composition display\n- `CaretIndex`, `SelectionStart`, `SelectionEnd`, `ShowSelectionHighlight`, `SelectionBrush`, `SelectionForegroundBrush`, `CaretBrush`, and `CaretBlinkInterval`\n- `PasswordChar` and `RevealPassword`\n- `ShowCaret()`, `HideCaret()`, `MoveCaretToTextPosition(int)`, `MoveCaretToPoint(Point)`, `MoveCaretHorizontal(LogicalDirection)`, and `MoveCaretVertical(LogicalDirection)`\n- `GetNextCharacterHit(LogicalDirection)`, `GetCharacterIndex(Point)`, `GetCaretBounds(int)`, `GetLineCount()`, `GetLineBounds(int)`, and `MeasureText(double)`\n- `CaretBoundsChanged` event\n\nUse `ProTextPresenter` when building a custom editor, search box, command surface, code-like text host, or any control that needs text presentation primitives but owns its own editing behavior.\n\n### `ProTextBox`\n\n`ProTextBox` is a lightweight TextBox-like control that hosts `ProTextPresenter` in its template. It is designed for ProText-backed editable text scenarios where you want a ready-to-use control rather than building a presenter host yourself.\n\nIt provides a focused TextBox-style API:\n\n- two-way `Text`\n- `AcceptsReturn`, `AcceptsTab`, and `NewLine`\n- `IsReadOnly`, `MaxLength`, `MinLines`, `MaxLines`, `IsUndoEnabled`, `UndoLimit`, `CanUndo`, `CanRedo`, `Undo()`, and `Redo()`\n- `CaretIndex`, `SelectionStart`, `SelectionEnd`, `SelectedText`, `SelectAll()`, and `ClearSelection()`\n- mouse drag selection, shift-click extension, double-click word selection, triple-click line selection, and keyboard word/line navigation\n- clipboard-oriented state such as `CanCut`, `CanCopy`, and `CanPaste`\n- text and clipboard routed events such as `TextChanging`, `TextChanged`, `CopyingToClipboard`, `CuttingToClipboard`, and `PastingFromClipboard`\n- `PasswordChar`, `RevealPassword`, placeholder/watermark text aliases, floating placeholder/watermark aliases, and placeholder/watermark foreground aliases\n- `InnerLeftContent` and `InnerRightContent`\n- `TextAlignment`, `TextWrapping`, `TextDecorations`, `LineHeight`, content alignment, selection brushes, caret brush, and caret blink interval\n- `GetLineCount()` and `ScrollToLine(int)` backed by `ProTextPresenter` layout data\n- `UseGlobalCache`, `UsePretextRendering`, and `PretextLineHeightMultiplier`\n\nAvalonia's built-in `TextBox` expects Avalonia's own `TextPresenter` template part, so `ProTextPresenter` is not a drop-in replacement for the built-in `TextBox` template. `ProTextBox` exists as the ProText-backed editable host.\n\n## Rendering Model\n\nProText keeps text on the Pretext-powered path from preparation through rendering:\n\n- plain text is prepared and segmented through PretextSharp\n- rich inline text is flattened into immutable ProText value data, then prepared through Pretext rich inline APIs\n- layout snapshots are local to each control and keyed by width\n- global prepared-content cache keys exclude viewport width so prepared text can be reused across controls\n- layout and render fingerprints are tracked separately\n- render operations snapshot brushes, decorations, and selection styles into immutable value data\n- Skia drawing is performed through Avalonia custom draw operations using `ISkiaSharpApiLeaseFeature`\n\nSupported inline text content includes `Run`, `Span`, `Bold`, `Italic`, `Underline`, and `LineBreak`. `InlineUIContainer` is skipped because it is visual content rather than text content; ProText does not create an internal Avalonia fallback visual for it.\n\nForeground brushes support solid colors and gradient brushes where practical. Multilingual text remains on the Pretext path and uses the ProText Skia font resolver for font fallback.\n\n## Cache And Diagnostics\n\nGlobal prepared-text caching is enabled by default and can be disabled per control with `UseGlobalCache=\"False\"`.\n\n`ProTextCache` exposes process-wide cache controls:\n\n- `MaxEntryCount` bounds the shared prepared-text and rich-inline cache\n- `Clear()` clears ProText and PretextSharp internal layout caches\n- `GetSnapshot()` returns `Count`, `MaxEntryCount`, `Hits`, and `Misses` for diagnostics, sample UI, and benchmarks\n\n## Quick Start\n\nReference the package or project, then use the controls from the standard Avalonia XAML namespace.\n\n```xml\n\u003cWindow xmlns=\"https://github.com/avaloniaui\"\n        xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n        x:Class=\"MyApp.MainWindow\"\u003e\n    \u003cProTextBlock Text=\"High-volume text rendered through PretextSharp\"\n                  TextWrapping=\"Wrap\"\n                  TextTrimming=\"CharacterEllipsis\"\n                  UseGlobalCache=\"True\" /\u003e\n\u003c/Window\u003e\n```\n\n### Display Text\n\n```xml\n\u003cProTextBlock Text=\"High-volume text rendered through PretextSharp\"\n              TextWrapping=\"Wrap\"\n              TextTrimming=\"CharacterEllipsis\"\n              UseGlobalCache=\"True\" /\u003e\n```\n\n### Rich Inline Text\n\n```xml\n\u003cProTextBlock TextWrapping=\"Wrap\"\n              xmlns:docs=\"clr-namespace:Avalonia.Controls.Documents;assembly=Avalonia.Controls\"\u003e\n    \u003cdocs:Run Text=\"Inline content: \" /\u003e\n    \u003cdocs:Bold\u003ebold\u003c/docs:Bold\u003e\n    \u003cdocs:Run Text=\", \" /\u003e\n    \u003cdocs:Italic\u003eitalic\u003c/docs:Italic\u003e\n    \u003cdocs:Run Text=\", and \" /\u003e\n    \u003cdocs:Underline\u003eunderlined\u003c/docs:Underline\u003e\n\u003c/ProTextBlock\u003e\n```\n\n### Presenter Surface\n\n```xml\n\u003cProTextPresenter Text=\"Selectable text presented through ProText\"\n                  TextWrapping=\"Wrap\"\n                  CaretIndex=\"24\"\n                  SelectionStart=\"9\"\n                  SelectionEnd=\"16\"\n                  SelectionBrush=\"#663B82F6\"\n                  SelectionForegroundBrush=\"#FFFFFF\" /\u003e\n```\n\n### Editable TextBox-Like Control\n\n```xml\n\u003cProTextBox Text=\"Editable text presented through ProTextPresenter\"\n            TextWrapping=\"Wrap\"\n            PlaceholderText=\"Search\"\n            SelectionStart=\"9\"\n            SelectionEnd=\"22\" /\u003e\n```\n\nTo use the Fluent `ProTextBox` theme, merge the ProText theme after Avalonia's Fluent theme:\n\n```xml\n\u003cApplication.Resources\u003e\n    \u003cResourceDictionary\u003e\n        \u003cResourceDictionary.MergedDictionaries\u003e\n            \u003cResourceInclude Source=\"avares://ProText/Themes/Fluent.axaml\" /\u003e\n        \u003c/ResourceDictionary.MergedDictionaries\u003e\n    \u003c/ResourceDictionary\u003e\n\u003c/Application.Resources\u003e\n```\n\n## Sample App\n\nThe sample project demonstrates the current control set and comparison scenarios:\n\n- Avalonia `TextBlock` beside `ProTextBlock`\n- equivalent inline text rendered by Avalonia and ProText\n- `ProTextPresenter` selection, caret, password, preedit, and rich-inline presentation\n- Avalonia `TextBox` beside `ProTextBox`\n- dense scrolling text content with cache diagnostics\n- zoomable, pannable canvas tabs with 1000 absolute-positioned Avalonia `TextBox` controls and 1000 absolute-positioned `ProTextBox` controls\n\nRun it with:\n\n```bash\ndotnet run --project samples/ProText.Sample/ProText.Sample.csproj\n```\n\n## Performance Snapshot\n\nResults below were generated on 2026-05-04 with BenchmarkDotNet `0.15.8` on Apple M3 Pro, macOS Tahoe `26.4.1`, .NET SDK `10.0.201`, and .NET runtime `10.0.5`. `ProText.Benchmarks` and `ProText.InlineBenchmarks` use BenchmarkDotNet's default job; `ProText.PresenterBenchmarks` and `ProText.TextBoxBenchmarks` use `ShortRun` as configured in the benchmark projects.\n\nCommands used for the documented run:\n\n```bash\ndotnet run -c Release --project benchmarks/ProText.Benchmarks/ProText.Benchmarks.csproj -- --filter \"*\"\ndotnet run -c Release --project benchmarks/ProText.InlineBenchmarks/ProText.InlineBenchmarks.csproj -- --filter \"*\"\ndotnet run -c Release --project benchmarks/ProText.PresenterBenchmarks/ProText.PresenterBenchmarks.csproj -- --filter \"*\"\ndotnet run -c Release --project benchmarks/ProText.TextBoxBenchmarks/ProText.TextBoxBenchmarks.csproj -- --filter \"*\"\n```\n\n### TextBlock Layout And Cache\n\n| Method | Width | Mean | Ratio | Allocated | Alloc Ratio |\n| --- | ---: | ---: | ---: | ---: | ---: |\n| AvaloniaTextBlockMeasure | 160 | 757,121.0 ns | 1.000 | 229,608 B | 1.000 |\n| ProTextBlockGlobalCacheMeasure | 160 | 3,720.3 ns | 0.005 | 49,312 B | 0.215 |\n| ProTextBlockLocalCacheMeasure | 160 | 3,723.5 ns | 0.005 | 49,312 B | 0.215 |\n| AvaloniaRichTextBlockMeasure | 160 | 51,570.5 ns | 0.068 | 22,328 B | 0.097 |\n| ProTextBlockRichMeasure | 160 | 4,796.9 ns | 0.006 | 32,327 B | 0.141 |\n| PretextColdPrepare | 160 | 480,168.2 ns | 0.634 | 1,295,812 B | 5.644 |\n| PretextMeasureLineStats | 160 | 950.9 ns | 0.001 | 88 B | 0.000 |\n| AvaloniaTextBlockMeasure | 320 | 676,603.0 ns | 1.000 | 157,456 B | 1.000 |\n| ProTextBlockGlobalCacheMeasure | 320 | 3,782.3 ns | 0.006 | 49,312 B | 0.313 |\n| ProTextBlockLocalCacheMeasure | 320 | 3,791.4 ns | 0.006 | 49,312 B | 0.313 |\n| AvaloniaRichTextBlockMeasure | 320 | 45,619.8 ns | 0.067 | 15,840 B | 0.101 |\n| ProTextBlockRichMeasure | 320 | 4,775.3 ns | 0.007 | 32,327 B | 0.205 |\n| PretextColdPrepare | 320 | 478,321.7 ns | 0.707 | 1,295,812 B | 8.230 |\n| PretextMeasureLineStats | 320 | 851.7 ns | 0.001 | 88 B | 0.001 |\n| AvaloniaTextBlockMeasure | 640 | 637,930.0 ns | 1.000 | 115,864 B | 1.000 |\n| ProTextBlockGlobalCacheMeasure | 640 | 3,782.7 ns | 0.006 | 49,312 B | 0.426 |\n| ProTextBlockLocalCacheMeasure | 640 | 3,801.7 ns | 0.006 | 49,312 B | 0.426 |\n| AvaloniaRichTextBlockMeasure | 640 | 44,579.6 ns | 0.070 | 14,496 B | 0.125 |\n| ProTextBlockRichMeasure | 640 | 4,734.0 ns | 0.007 | 32,327 B | 0.279 |\n| PretextColdPrepare | 640 | 473,190.0 ns | 0.742 | 1,295,812 B | 11.184 |\n| PretextMeasureLineStats | 640 | 1,024.3 ns | 0.002 | 88 B | 0.001 |\n\n### TextBlock Headless Render\n\n| Method | Mean | Ratio | Allocated | Alloc Ratio |\n| --- | ---: | ---: | ---: | ---: |\n| AvaloniaTextBlockFrame | 62.52 us | 1.00 | 655 B | 1.00 |\n| ProTextBlockFrame | 62.77 us | 1.00 | 656 B | 1.00 |\n\n### Inline Layout\n\n| Method | Width | Mean | Ratio | Allocated | Alloc Ratio |\n| --- | ---: | ---: | ---: | ---: | ---: |\n| AvaloniaTextBlockInlineMeasure | 180 | 466,180.91 ns | 1.000 | 177,808 B | 1.00 |\n| ProTextBlockInlineMeasure | 180 | 57,538.85 ns | 0.123 | 295,863 B | 1.66 |\n| ProTextPresenterInlineMeasure | 180 | 79.03 ns | 0.000 | - | 0.00 |\n| AvaloniaTextBlockInlineMeasure | 360 | 438,062.62 ns | 1.000 | 148,632 B | 1.00 |\n| ProTextBlockInlineMeasure | 360 | 58,334.96 ns | 0.133 | 295,863 B | 1.99 |\n| ProTextPresenterInlineMeasure | 360 | 78.16 ns | 0.000 | - | 0.00 |\n| AvaloniaTextBlockInlineMeasure | 720 | 426,446.30 ns | 1.000 | 143,296 B | 1.00 |\n| ProTextBlockInlineMeasure | 720 | 57,865.73 ns | 0.136 | 295,863 B | 2.06 |\n| ProTextPresenterInlineMeasure | 720 | 80.31 ns | 0.000 | - | 0.00 |\n\n### Presenter Operations\n\n| Method | Width | Mean | Ratio | Allocated |\n| --- | ---: | ---: | ---: | ---: |\n| PresenterMeasure | 240 | 81.80 ns | 1.00 | - |\n| PresenterCaretBounds | 240 | 314.18 ns | 3.84 | 128 B |\n| PresenterHitTest | 240 | 4,723.75 ns | 57.75 | 1,912 B |\n| EmptyWindowFrame | 240 | 50,813.18 ns | 621.17 | 606 B |\n| PresenterPlainFrame | 240 | 340,712.50 ns | 4,165.10 | 7,012 B |\n| PresenterSelectedFrame | 240 | 343,965.24 ns | 4,204.86 | 7,026 B |\n| PresenterMeasure | 480 | 80.45 ns | 1.00 | - |\n| PresenterCaretBounds | 480 | 320.81 ns | 3.99 | 128 B |\n| PresenterHitTest | 480 | 8,654.58 ns | 107.58 | 3,456 B |\n| EmptyWindowFrame | 480 | 50,954.18 ns | 633.37 | 606 B |\n| PresenterPlainFrame | 480 | 339,838.00 ns | 4,224.26 | 7,010 B |\n| PresenterSelectedFrame | 480 | 341,366.86 ns | 4,243.27 | 7,010 B |\n| PresenterMeasure | 960 | 80.63 ns | 1.00 | - |\n| PresenterCaretBounds | 960 | 4,709.12 ns | 58.40 | 1,128 B |\n| PresenterHitTest | 960 | 17,238.17 ns | 213.78 | 6,800 B |\n| EmptyWindowFrame | 960 | 50,832.60 ns | 630.42 | 606 B |\n| PresenterPlainFrame | 960 | 350,925.74 ns | 4,352.12 | 7,000 B |\n| PresenterSelectedFrame | 960 | 340,326.70 ns | 4,220.67 | 7,012 B |\n\n### TextBox Layout\n\nThe TextBox benchmark suite applies Avalonia's Fluent TextBox theme and the ProText Fluent theme before measuring. Setup validates that Avalonia `TextPresenter` and ProText `ProTextPresenter` are present in the visual tree. Layout benchmarks alternate width constraints to avoid cached no-op timings.\n\n| Method | Width | Mean | Ratio | Allocated | Alloc Ratio |\n| --- | ---: | ---: | ---: | ---: | ---: |\n| AvaloniaTextBoxMeasure | 220 | 1,291.90 us | 1.00 | 285.70 KB | 1.00 |\n| ProTextBoxMeasure | 220 | 46.83 us | 0.04 | 174.84 KB | 0.61 |\n| AvaloniaTextBoxSelectedMeasure | 220 | 1,316.04 us | 1.02 | 285.70 KB | 1.00 |\n| ProTextBoxSelectedMeasure | 220 | 46.56 us | 0.04 | 174.84 KB | 0.61 |\n| AvaloniaTextBoxMeasure | 440 | 1,238.14 us | 1.00 | 215.05 KB | 1.00 |\n| ProTextBoxMeasure | 440 | 37.33 us | 0.03 | 121.86 KB | 0.57 |\n| AvaloniaTextBoxSelectedMeasure | 440 | 1,218.57 us | 0.98 | 215.05 KB | 1.00 |\n| ProTextBoxSelectedMeasure | 440 | 37.46 us | 0.03 | 121.86 KB | 0.57 |\n| AvaloniaTextBoxMeasure | 880 | 1,169.68 us | 1.00 | 185.08 KB | 1.00 |\n| ProTextBoxMeasure | 880 | 32.94 us | 0.03 | 99.11 KB | 0.54 |\n| AvaloniaTextBoxSelectedMeasure | 880 | 1,171.24 us | 1.00 | 185.08 KB | 1.00 |\n| ProTextBoxSelectedMeasure | 880 | 32.52 us | 0.03 | 99.11 KB | 0.54 |\n\n### TextBox Headless Render\n\nFrame benchmarks use one explicit headless render tick plus `GetLastRenderedFrame()` rather than `CaptureRenderedFrame()`'s stabilization loop.\n\n| Method | Mean | Ratio | Allocated | Alloc Ratio |\n| --- | ---: | ---: | ---: | ---: |\n| EmptyWindowFrame | 44.59 us | 0.10 | 533 B | 0.05 |\n| AvaloniaTextBoxCaptureOnly | 161.11 us | 0.35 | 1,068 B | 0.11 |\n| ProTextBoxCaptureOnly | 128.78 us | 0.28 | 908 B | 0.09 |\n| AvaloniaTextBoxFrame | 460.62 us | 1.00 | 9,993 B | 1.00 |\n| ProTextBoxFrame | 488.39 us | 1.06 | 7,123 B | 0.71 |\n| DirectProTextPresenterFrame | 460.73 us | 1.00 | 7,392 B | 0.74 |\n\n## Project Layout\n\n- `src/ProText` - ProText control library, themes, shared layout, cache, and Skia renderer\n- `samples/ProText.Sample` - desktop comparison and stress sample app\n- `tests/ProText.Tests` - unit tests and Avalonia headless rendering tests\n- `benchmarks/ProText.Benchmarks` - TextBlock, layout, cache, and render benchmarks\n- `benchmarks/ProText.InlineBenchmarks` - rich-inline layout benchmarks\n- `benchmarks/ProText.PresenterBenchmarks` - presenter measurement, hit-test, caret, selection, and render benchmarks\n- `benchmarks/ProText.TextBoxBenchmarks` - Avalonia TextBox versus ProTextBox benchmarks\n- `plan` - technical specification and implementation plan\n\n## Verification\n\n```bash\ndotnet build ProText.slnx\ndotnet test tests/ProText.Tests/ProText.Tests.csproj\ndotnet run -c Release --project benchmarks/ProText.Benchmarks/ProText.Benchmarks.csproj -- --list flat\ndotnet run -c Release --project benchmarks/ProText.InlineBenchmarks/ProText.InlineBenchmarks.csproj -- --list flat\ndotnet run -c Release --project benchmarks/ProText.PresenterBenchmarks/ProText.PresenterBenchmarks.csproj -- --list flat\ndotnet run -c Release --project benchmarks/ProText.TextBoxBenchmarks/ProText.TextBoxBenchmarks.csproj -- --list flat\n```\n\n## Design Principles\n\n- Keep text measurement, layout, and rendering on the Pretext path.\n- Keep prepared-text caching global by default, bounded, and diagnosable.\n- Keep viewport-width-dependent layout snapshots local to each control.\n- Snapshot mutable Avalonia brushes and text decorations before rendering.\n- Share inline flattening, layout, selection, and render-style code between display and editable controls.\n- Avoid internal Avalonia `TextBlock` fallbacks inside ProText controls.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwieslawsoltes%2Fprotext","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwieslawsoltes%2Fprotext","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwieslawsoltes%2Fprotext/lists"}