mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-11-10 13:32:23 +00:00
Pathfinder effects, compound shapes, Expand Appearance and pattern expansion now pass the document to the effects they evaluate, so a painted piece that names a swatch or pattern takes part as drawn instead of being refused. A path with a painted effect takes part in Pathfinder and compound shapes as its pieces, each with its own paint, inside the path's opacity and blend mode. The renderer's kept effect art and live evaluations now count the document's swatch and pattern names for objects with a plug-in effect, so deleting or restoring a swatch a piece names redraws the object.
65 lines
3.1 KiB
Rust
65 lines
3.1 KiB
Rust
//! Live objects (blends, envelopes, gradient meshes, repeats) evaluated alike for the renderer and
|
|
//! every exporter, with what the pure evaluation in [`vectorcraft_doc::live`] can't do itself
|
|
//! ([`Hooks`]): type inside an envelope distorts as its glyph outlines, run by run
|
|
//! ([`outline_text`]); symbol instances as their symbol's art; with Distort Appearance strokes and
|
|
//! geometry effects bend with the art ([`bake_appearance`]); with Distort Pattern Fills the pattern
|
|
//! tiles do.
|
|
|
|
use std::sync::Arc;
|
|
|
|
use vectorcraft_doc::live::{self, Hooks, Outliner};
|
|
use vectorcraft_doc::{Document, Node, NodeKind};
|
|
use vectorcraft_geom::{Affine, Rect};
|
|
|
|
use crate::{bake_appearance, outline_text};
|
|
|
|
/// The text outliner live evaluation uses: type as its glyph outlines, one path per run in the
|
|
/// run's paint ([`outline_text`]).
|
|
pub fn text_outliner() -> Outliner<'static> {
|
|
Some(&outline_text)
|
|
}
|
|
|
|
/// Type outlined, or a symbol instance as its symbol's art (from `doc`) placed by the instance,
|
|
/// through the symbol's 9-slice guides when it has them ([`Document::place_symbol_art`], `None`
|
|
/// past its object limit). As an [`OutlineHook`](crate::OutlineHook), it gives compound shapes and
|
|
/// Pathfinder operations the symbol instances among their members.
|
|
pub fn outline_object(doc: Option<&Document>, n: &Node) -> Option<Node> {
|
|
match &n.kind {
|
|
NodeKind::SymbolInstance { symbol, xf } => {
|
|
let doc = doc?;
|
|
let sym = doc.symbols.iter().find(|s| s.name == *symbol)?;
|
|
let art = vectorcraft_doc::symbol_overrides::dynamic_art(&sym.art, n);
|
|
let art = doc.place_symbol_art(symbol, &art, *xf)?;
|
|
Some(Node::group(n.id, vec![Arc::new(art)]))
|
|
}
|
|
_ => outline_text(n),
|
|
}
|
|
}
|
|
|
|
/// Run `f` with the hooks live evaluation needs; symbols and patterns come from `doc` (without a
|
|
/// document, symbol instances and pattern tiles stay as they are).
|
|
fn with_hooks<R>(doc: Option<&Document>, f: impl FnOnce(Hooks) -> R) -> R {
|
|
// Envelopes map type from its glyphs here too, without an engine session.
|
|
vectorcraft_text::register_envelope_ink();
|
|
let outline = |n: &Node| outline_object(doc, n);
|
|
let tiles = |name: &str, xf: Affine, region: Rect| Some(doc?.pattern(name)?.instances_in(xf, region));
|
|
let appearance = |n: &Node| bake_appearance(doc, n);
|
|
f(Hooks { outline: Some(&outline), appearance: Some(&appearance), pattern: Some(&tiles), symbols: doc })
|
|
}
|
|
|
|
/// One level of evaluation of live object `n` ([`live::expand_live_hooks`]).
|
|
pub fn expand_live(doc: Option<&Document>, n: &Node) -> Vec<Node> {
|
|
with_hooks(doc, |h| live::expand_live_hooks(n, h))
|
|
}
|
|
|
|
/// Live object `n` evaluated into a plain group ([`live::expanded_group_hooks`]): Expand.
|
|
pub fn expanded_live_group(doc: Option<&Document>, n: &Node) -> Node {
|
|
with_hooks(doc, |h| live::expanded_group_hooks(n, h))
|
|
}
|
|
|
|
/// `n` with every live object in it replaced by its evaluated art ([`live::expand_deep_hooks`]):
|
|
/// what the exporters write for live objects.
|
|
pub fn expand_live_deep(doc: Option<&Document>, n: &Node) -> Node {
|
|
with_hooks(doc, |h| live::expand_deep_hooks(n, h))
|
|
}
|