Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 5 additions & 4 deletions crates/shift-bridge/docs/DOCS.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,11 @@ crates/shift-bridge/
2. JS calls a mutation such as `closeContour(layerId, contourId)`.
3. `Bridge` parses boundary strings and asks `FontWorkspace` to run the edit against that layer.
4. The bridge returns a `shift-wire` change DTO and bumps the live version.
5. `saveWorkspace()` / `saveWorkspaceAs(path)` update the `.shift` source package target and record the persisted version.
6. `inspectPackage(path)` and `inspectPackageDraft(storePath)` expose source/package identity for the utility process without choosing a recovery policy.
7. `closeWorkspace()` drops the live Rust workspace handle before the utility process deletes a clean or discarded SQLite document.
8. `exportWorkspace(request)` creates a `FontSaveSnapshot` and exports asynchronously through `shift-backends`.
5. Read-only glyph snapshots ask `shift-font` for native interpolation and use `shift-wire` only to adapt its regions and deltas into renderer DTOs.
6. `saveWorkspace()` / `saveWorkspaceAs(path)` update the `.shift` source package target and record the persisted version.
7. `inspectPackage(path)` and `inspectPackageDraft(storePath)` expose source/package identity for the utility process without choosing a recovery policy.
8. `closeWorkspace()` drops the live Rust workspace handle before the utility process deletes a clean or discarded SQLite document.
9. `exportWorkspace(request)` creates a `FontSaveSnapshot` and exports asynchronously through `shift-backends`.

## Type Boundary

Expand Down
9 changes: 0 additions & 9 deletions crates/shift-bridge/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -393,15 +393,6 @@ export interface NapiGlyphLayerSnapshot {
state: NapiGlyphState
}

export interface NapiGlyphMaster {
sourceId: SourceId
sourceName: string
isDefaultSource: boolean
location: NapiLocation
structure: NapiGlyphStructure
values: Float64Array
}

export interface NapiGlyphRecord {
id: GlyphId
name: GlyphName
Expand Down
22 changes: 5 additions & 17 deletions crates/shift-bridge/src/bridge.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use shift_wire::{
NapiGlyphSnapshot, NapiGlyphSnapshotRequest, NapiLayerReplaced, NapiLocation,
NapiNamedInstance, NapiPointSeed, NapiSource,
},
interpolation::{build_glyph_variation_data, build_masters, GlyphVariationBuild},
interpolation::glyph_variation_data,
Axis, AxisMapping, FontMetadata, FontMetrics, GlyphChangedEntities, GlyphLayerSnapshot,
GlyphRecord, GlyphSnapshot, GlyphSnapshotRequest, GlyphState, GlyphStructure, NamedInstance,
Source,
Expand Down Expand Up @@ -547,9 +547,10 @@ impl Bridge {
continue;
};

let variation_data = self
.variation_build_for_glyph(glyph)?
.and_then(|(_, build)| build.variation_data);
let variation_data = font
.glyph_interpolation(&glyph_id)?
.map(|interpolation| glyph_variation_data(&interpolation, font.axes()))
.transpose()?;

let layers = glyph
.layers()
Expand Down Expand Up @@ -640,19 +641,6 @@ impl Bridge {
Ok(FontSaveSnapshot::new(self.font()?.clone(), None))
}

fn variation_build_for_glyph(
&self,
glyph: &Glyph,
) -> BridgeResult<Option<(usize, GlyphVariationBuild)>> {
let font = self.font()?;

Ok(build_masters(font, glyph).map(|masters| {
let master_count = masters.len();
let build = build_glyph_variation_data(&masters, font.axes());
(master_count, build)
}))
}

fn workspace(&self) -> BridgeResult<&FontWorkspace> {
self
.workspace
Expand Down
13 changes: 13 additions & 0 deletions crates/shift-font/docs/DOCS.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ crates/shift-font/src/
changes.rs -- replace-grade semantic change records
layer_edit.rs -- glyph-layer geometry mutations
variation.rs -- external-to-design mapping evaluation
interpolation.rs -- source compatibility, glyph values, variation models
projection.rs -- location-bound resolved glyph views
composite.rs -- recursive component flattening
```

## Key Types
Expand All @@ -30,6 +33,9 @@ crates/shift-font/src/
- `Source` is an editable designspace position with a name and location.
- `Glyph` is a glyph concept identified by `GlyphId`.
- `GlyphLayer` is authored editable data for one glyph at one source.
- `GlyphInterpolation` is a reusable model built from one glyph's compatible authored source layers. Its default-source template owns topology; its regions and deltas own native interpolation semantics.
- `FontProjection` is a read-only, location-bound view that reuses resolved component layers across one or many glyph requests.
- `ResolvedGlyph` is derived, flattened geometry plus x advance. An existing blank glyph resolves to an empty contour list; a missing glyph resolves to `None`.
- `Contour` and `Point` describe outline geometry inside a glyph layer.

## Identity
Expand All @@ -48,12 +54,19 @@ Stable IDs are identity. Names and Unicode values are editable metadata.
- Own font authoring data structures such as `Font`, `Glyph`, `GlyphLayer`, `Contour`, `Point`, `Source`, and `Axis`.
- Keep object-level mutation behavior near the objects it mutates.
- Provide model-native helpers for layer editing, component resolution, variation behavior, axis mapping evaluation, and geometry-derived behavior.
- Own canonical glyph interpolation value ordering, source compatibility, variation-model construction, interpolation evaluation, and location-bound glyph resolution.
- Stay independent of TypeScript, NAPI, and bridge DTOs.

`Font::glyph_interpolation(glyph_id)` builds a reusable model from compatible master-source layers. The default source defines structural topology. Incompatible non-default layers and nonviable models do not become transport errors; callers receive `None` and may use their documented authored-layer fallback.

`Font::projection(location)` expects an internal authoring location. Apply external axis mappings before creating the projection. Resolution prefers an exact authored layer, then compatible interpolation, then the default or preferred authored layer. Component branches resolve at the same location and are flattened into each `ResolvedGlyph`.

## Boundaries

`shift-font` should not expose TypeScript-facing wire contracts. Those belong in `shift-wire`.

`shift-wire` may translate native interpolation regions and deltas into transport DTOs, but it must not rebuild source samples, define topology compatibility, or evaluate variation models.

`shift-font` should not perform SQLite persistence. Durable working-store reads and writes belong in `shift-store`.

`shift-font` should not own Electron, NAPI, or editor state. The TypeScript editor owns UI interaction, selection, hover, camera, tools, and command history.
Expand Down
22 changes: 22 additions & 0 deletions crates/shift-font/src/composite.rs
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,28 @@ pub fn flatten_component_contours_for_layer(
.collect()
}

/// Resolves root and component contours for one derived glyph layer.
///
/// Root points receive fresh identities because the result is read-only
/// derived geometry. Components use the supplied provider and skip cyclic
/// branches without dropping other contours.
pub fn resolved_contours_for_layer(
provider: &impl GlyphLayerProvider,
layer: &GlyphLayer,
root_glyph_id: &GlyphId,
) -> Vec<ResolvedContour> {
let mut contours = layer
.contours_iter()
.map(|contour| transform_contour_points(contour, Transform::identity()))
.collect::<Vec<_>>();
contours.extend(flatten_component_contours_for_layer(
provider,
layer,
root_glyph_id,
));
contours
}

/// Resolves root-level component instances with provenance data.
///
/// Each returned instance corresponds to a direct component of `layer` and
Expand Down
Loading
Loading