Skip to content

Fix browser DXF interactions and add cross-platform font rendering#26

Open
wieslawsoltes wants to merge 12 commits into
mainfrom
agent/browser-font-manager-dxf-fixes
Open

Fix browser DXF interactions and add cross-platform font rendering#26
wieslawsoltes wants to merge 12 commits into
mainfrom
agent/browser-font-manager-dxf-fixes

Conversation

@wieslawsoltes

Copy link
Copy Markdown
Owner

Summary

This change fixes the browser DXF viewer regressions, restores reliable browser file selection, and replaces the previous platform-dependent text setup with a shared high-performance font, shaping, layout, and rendering pipeline.

It also bundles the official Inter 4.1 family and targeted Noto fallbacks, removes font-dependent UI chrome glyphs, and adds an interactive Inter specimen page that exercises the supported static, variable, and OpenType behavior in the sample gallery.

DXF interaction and browser platform fixes

  • Fix initial zoom-to-fit by fitting after the control has a valid arranged viewport instead of mutating layout state from OnRender.
  • Preserve the point under the cursor while zooming by keeping the DXF camera transform in control-local screen space.
  • Compose retained static-DXF camera transforms with the active visual placement transform immediately before rendering.
  • Carry static-DXF placement through onscreen, offscreen, and extension-pipeline render paths.
  • Add a regression test proving a static DXF buffer honors nested visual placement.
  • Replace the browser file picker's base64 bridge with a direct staged-byte copy into WebAssembly memory.
  • Prefer showOpenFilePicker when available and retain a cancellation-safe hidden-input fallback for browsers or origins where the native picker API is unavailable.
  • Handle picker cancellation, focus restoration, activation failures, and staged-buffer cleanup without leaving an unresolved managed task.

Cross-platform font management

  • Add one process-wide, platform-neutral FontManager used by ProGPU text, WinUI controls, and the SkiaSharp compatibility surface.
  • Align family enumeration, style matching, typeface matching, character fallback, BCP-47-aware fallback preference, and lazy face loading across desktop and browser hosts.
  • Extend system-font metadata with weight, width, and slant information so family matching selects real faces rather than synthesizing every style.
  • Register browser and sample defaults through the shared manager instead of probing operating-system font paths directly.
  • Preserve lazy system-font discovery and character-map inspection so startup does not eagerly parse every installed or bundled face.
  • Update SKFontManager, SKFontStyleSet, and SKTypeface to use the same catalog and matching rules.

Bundled font families

  • Add separately packable ProGPU.Fonts.Inter and ProGPU.Fonts.Noto projects.
  • Bundle all 36 official Inter 4.1 and Inter Display static faces plus the two official Inter variable fonts, unchanged from the upstream release.
  • Bundle official Noto Sans CJK JP and Noto Sans Symbols 2 faces as lazy fallbacks for browser-safe script and symbol coverage.
  • Keep font source, version, license, and hash coverage in the repository.
  • Remove the former Roboto package dependency and avoid Fonts.Avalonia.SourceHanSansJP.Lite entirely.

OpenType shaping and variable fonts

  • Add cached SFNT layout-table access and a managed OpenType shaping engine for GSUB and GPOS.
  • Support Inter's documented substitution, positioning, language, contextual, mark, alternate, numeric, fraction, stylistic-set, character-variant, and slashed-zero features.
  • Support integer alternate selection for features such as aalt and all Inter character-variant tags, including cv14.
  • Implement variable-font axes and runtime instancing through fvar, avar, gvar, HVAR, MVAR, GDEF variation stores, and variable GPOS adjustments.
  • Apply variable deltas to simple and composite outlines, advances, metrics, and positioned glyphs.
  • Make variable instances immutable and canonically comparable so retained caches remain bounded when an evicted instance is recreated.
  • Integrate shaping options into retained render commands, text-layout cache keys, TextVisual, TextLayout, rich text, and fallback runs.
  • Preserve shaped glyph indices through layout and compositor compilation to avoid repeating character-map lookups in render hot paths.

Text and icon rendering quality

  • Route missing glyphs through the shared fallback manager in plain text and rich-text layout.
  • Resolve real bold, italic, and family faces for inline formatting and measure with the selected face's metrics.
  • Replace font-dependent control chrome characters with retained vector strokes for combo arrows, calendar navigation, date-picker icons, sort indicators, tab close buttons, tree expanders, navigation fallbacks, and viewport maximize/restore controls.
  • Invalidate retained navigation-item chrome when pane state changes so cached compact visuals are not replayed in the expanded pane.
  • Remove unsupported emoji decoration from sample actions while keeping actual typography and Unicode samples focused on verified font coverage.

Inter specimen page

  • Add an Inter Typeface page to the browser and desktop sample navigation.
  • Showcase the Inter text and display families, all static weights and italics, continuous wght and opsz axes, language-sensitive forms, ligatures, kerning, fractions, numeric styles, alternates, stylistic sets, character variants, and slashed zero.
  • Provide interactive controls backed by retained text commands and dedicated theme resources for light, dark, Fluent, and macOS theme families.

Performance and quality safeguards

  • Keep bundled-face registration lazy; static and fallback faces are parsed once on first demand.
  • Cache parsed OpenType tables, feature plans, variable data, and immutable variable instances outside per-frame paths.
  • Include shaping options in retained layout identity without forcing unrelated scene invalidation.
  • Keep DXF camera changes in the existing uniform update path and preserve compiled static geometry.
  • Use retained vector icon commands rather than per-frame glyph lookup or outline conversion.
  • Preserve the existing physical-pixel, DPI, subpixel positioning, glyph-atlas, and retained-scene rendering policies.

Validation

  • dotnet test src/ProGPU.Tests/ProGPU.Tests.csproj -c Release --no-restore --nologo
    • Passed: 1,892
    • Failed: 0
    • Skipped: 0
  • Published the browser sample in Release WebAssembly AOT mode:
    • dotnet publish src/ProGPU.Samples.Browser/ProGPU.Samples.Browser.csproj -c Release -o artifacts/browser-aot
  • Served the AOT output locally and exercised the sample gallery in a real browser at http://127.0.0.1:8081/.
  • Verified DXF initial fit, pan, cursor-centered wheel zoom, nested placement, and local file selection.
  • Verified the Inter specimen, control glyphs, fallback text, and representative sample pages with no browser console errors or warnings.
  • Compared representative variable outlines, metrics, features, and positioning against upstream font metadata and reference OpenType tooling.

Notes

  • The AOT publish succeeds with the repository's existing trim-analysis warnings for dynamic third-party/framework surfaces.
  • netDxf.netstandard remains in the documented mixed interpreter/AOT mode because of the existing .NET 10 Mono AOT compiler limitation; DXF rendering itself continues through the normal WebGPU path.

@wieslawsoltes
wieslawsoltes marked this pull request as ready for review July 17, 2026 17:00

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a06d0c9b57

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

? cmd.Rect.Width
: 10000f;
var key = (cmd.Text, font, cmd.FontSize, maxWidth, TextAlignment.Left);
var key = (cmd.Text, font, cmd.FontSize, maxWidth, TextAlignment.Left, cmd.TextShapingOptions);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Use value identity for shaping options cache keys

When callers create an equivalent TextShapingOptions instance on each render (for example via TextShapingOptions.WithFeatures(...) in OnRender), this tuple compares the options object by reference because TextShapingOptions has no value equality. The same text/font/features then misses _layoutCache every frame and leaves a new TextLayout behind, so retained text with stable shaping settings can grow the compositor cache unbounded instead of reusing the layout.

Useful? React with 👍 / 👎.

Comment on lines +250 to +252
if (typeface.IsVariableFont)
{
return ApplyStyleVariations(typeface, style) ?? typeface;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Fall back to family matching for variable slant changes

When the current face is a variable font that does not have an ital/slnt axis but its family has a separate italic variable face (the bundled Inter Variable family is registered this way), this branch returns the original upright face after applying only the available axes and never searches the family for the italic face. Calls such as SKFontManager.MatchTypeface or rich text style resolution that request italic from the upright variable face therefore get synthetic skew instead of the registered true italic variable face.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant