Skip to content

Add first-class component glyph views - #158

Merged
kostyafarber merged 2 commits into
mainfrom
feature/component-glyph-shape
Jul 20, 2026
Merged

Add first-class component glyph views#158
kostyafarber merged 2 commits into
mainfrom
feature/component-glyph-shape

Conversation

@kostyafarber

Copy link
Copy Markdown
Collaborator

What changed

  • Replace the separate recursive GlyphOutline / render-model path with a first-class GlyphView containing ComponentGlyph and GlyphContour occurrences.
  • Make rendering, previews, text layout, bounds, xAdvance, and sidebearings consume the same composed glyph view.
  • Keep editing presentation root-owned: component contours render and measure correctly but do not expose parent-glyph point handles.
  • Add Rust-owned GlyphComponents relationships with stable component paths, parent/child ancestry, anchor attachments, authored order, and cycle pruning.
  • Resolve each component glyph independently at the root location using exact master → interpolation → deterministic master fallback → explicit error.
  • Exclude layer-only/background sources from component projection.
  • Support sparse one-axis interpolation when compatible component masters bracket a missing default layer.
  • Hard-delete the provisional outline/shape/provider abstractions and regenerate bridge types.

Why

Sidebearings were derived from the root glyph's direct geometry. A pure component glyph has no direct contours, so its root bounds were null even though a separate recursive outline path rendered it correctly. This split also required TypeScript to repeat component traversal semantics owned by Rust.

The new model keeps composition, interpolation, and editability orthogonal. Source contour coordinates are shared once per base glyph at the view location; each placement adds only a transform/provenance occurrence wrapper. ComponentGlyph.contours and the flattened GlyphView.contours reference the same occurrence objects.

Impact

Pure and mixed component glyphs now provide composed bounds and sidebearings in the editor sidebar, previews, and text layout. Rust and the renderer share one component occurrence model, including repeated/nested placements and anchor attachment identity.

Validation

  • cargo test -p shift-font -p shift-wire — 171 font tests and 6 wire tests passed
  • cargo clippy -p shift-font -p shift-wire -p shift-bridge --all-targets
  • pnpm lint:check
  • pnpm typecheck
  • Focused desktop suite — 89 tests passed, including real Homenaje Aacute composed bounds and 20/20 sidebearings
  • Pre-commit full suite — 502 tests passed; two unrelated Electron main-process suites could not collect because the secondary worktree lacks a valid Electron binary

const sourcePosition = Mat.applyToPoint(explicit, source);
const targetPosition = Mat.applyToPoint(targetComponent.#localTransformCell.value, target);
const attachmentOffset = Mat.Translate(
targetPosition.x - sourcePosition.x,

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

use Vec

Comment thread apps/desktop/src/renderer/src/lib/model/ComponentGlyph.ts
Comment thread crates/shift-font/src/composite.rs Outdated
) -> CoreResult<Transform> {
let parent_layer = layers
.get(&component_glyph.parent_glyph_id())
.ok_or_else(|| CoreError::GlyphNotFound(component_glyph.parent_glyph_id()))?;

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

we are doing this ok_or_else a lot

Comment thread crates/shift-font/src/interpolation.rs Outdated
}
}

fn interpolation_template<'a>(font: &Font, glyph: &'a crate::Glyph) -> Option<&'a GlyphLayer> {

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

template is a bad name

locationCell: Signal<AxisLocation>,
view: GlyphView,
) {
this.#definitionCell = definitionCell;

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

perhaps some inline comments might help to understand whats going on here

@kostyafarber
kostyafarber marked this pull request as ready for review July 20, 2026 07:22
@kostyafarber
kostyafarber merged commit a925357 into main Jul 20, 2026
11 of 12 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant