mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-11-15 04:49:52 +00:00
After Reset Bounding Box on a turned symbol instance, Break Link to Symbol and Object > Expand gave the art a box turned with the instance's transform again. The art's boxes now turn with the instance's own box, so they stand square when the instance's box did, and the angles the art has inside the symbol are kept relative to it. The group that an instance's opacity, blending mode or opacity mask adds around the art takes the instance's box angle instead of standing square to the page. A reflected instance can hold a box 180 degrees from the box its transform gives in one step; the art now takes the instance's box there too, the same rectangle with its handles where the instance had them. Compound shapes and Pathfinder receive an instance's art through the same rule. The clip groups and clip paths that 9-slice guides make for gradient and pattern art take the angle of the cell that places them, and the outer group keeps the object's angle turned by the instance, instead of standing square to the page. This also changes the result for an instance that was never reset: a 20 degree sliced instance gave clip groups at 0 degrees and now gives them at 20. Docs: params text, docs/mcp.md, docs/target-app-parity.md.
74 lines
3.7 KiB
Rust
74 lines
3.7 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`]), except type's strokes, which paint
|
|
//! along its bent outlines at their own weight ([`bake_type_appearance`], #6644); 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, bake_type_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. The group around the art takes
|
|
/// the instance's box angle, and the art's boxes turn with it, as Break Link turns them.
|
|
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 mut art = doc.place_symbol_art(symbol, &art, *xf)?;
|
|
let turn = vectorcraft_doc::orient::placed_turn(n.bbox_angle, *xf);
|
|
if turn != 0.0 {
|
|
art.turn_boxes(turn);
|
|
}
|
|
let mut out = Node::group(n.id, vec![Arc::new(art)]);
|
|
out.bbox_angle = n.bbox_angle;
|
|
Some(out)
|
|
}
|
|
_ => 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);
|
|
let type_appearance = |n: &Node| bake_type_appearance(doc, n);
|
|
f(Hooks { outline: Some(&outline), appearance: Some(&appearance), type_appearance: Some(&type_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))
|
|
}
|