mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-11-11 20:01:43 +00:00
85 lines
4.3 KiB
Rust
85 lines
4.3 KiB
Rust
use super::bounds::drawn_bounds;
|
|
use super::{Affine, AppearanceItem, Effect, Frame, Node, NodeKind, RasterFx, Rect, SymbolBoxes, Vec2, effects};
|
|
|
|
fn visible(effects: &[Effect]) -> bool {
|
|
effects.iter().any(|e| e.visible)
|
|
}
|
|
|
|
/// Does this node need the effects path (a path or compound path with visible effects)?
|
|
pub(crate) fn has_fx(n: &Node) -> bool {
|
|
if !matches!(n.kind, NodeKind::Path { guide: false, .. } | NodeKind::Compound { .. }) {
|
|
return false;
|
|
}
|
|
visible(&n.appearance.effects)
|
|
|| n.appearance.items.iter().any(|i| match i {
|
|
AppearanceItem::Fill(f) => visible(&f.effects),
|
|
AppearanceItem::Stroke(s) => visible(&s.effects),
|
|
})
|
|
}
|
|
|
|
/// Does `n` carry visible object-level effects that only apply through its art (type, images,
|
|
/// symbol instances, live objects; Crop Marks and colour adjustments on anything), is it type with
|
|
/// a geometry effect on a fill or stroke of its own or an image with a fill or stroke of its own
|
|
/// that paints a shape ([`effects::has_item_geometry`]), is it a path whose Transform effect copies
|
|
/// it with a gradient or changes its fills and strokes ([`effects::has_transform_art`]), or is it a
|
|
/// group or layer with an appearance of its own (see [`Renderer::draw_object_fx`])?
|
|
pub(crate) fn has_object_fx(n: &Node) -> bool {
|
|
(effects::needs_outline(n) && (visible(&n.appearance.effects) || n.projection().is_some()))
|
|
|| effects::has_item_geometry(n)
|
|
|| effects::has_transform_art(n)
|
|
|| effects::has_container_appearance(n)
|
|
|| effects::has_crop_marks(n)
|
|
|| effects::addons::halftone::has_halftone(n)
|
|
|| effects::has_adjustment(n)
|
|
|| effects::has_revolve(n)
|
|
|| effects::has_solid(n)
|
|
}
|
|
|
|
/// Is `n` a group or layer (whose evaluated art keeps its knockout setting)?
|
|
pub(super) fn is_container(n: &Node) -> bool {
|
|
matches!(n.kind, NodeKind::Group { .. } | NodeKind::Layer { .. })
|
|
}
|
|
|
|
/// Can the art [`Renderer::fx_art`] makes for `n` be made from live objects it evaluates? It can
|
|
/// when `n` is a live object, and when `n` is a group or layer without a Pathfinder effect that
|
|
/// holds live objects and whose geometry effects reshape them or whose own fills and strokes paint
|
|
/// their evaluated outlines ([`effects::evaluate_container`]).
|
|
pub(super) fn evaluates_live(n: &Node) -> bool {
|
|
use vectorcraft_doc::live::{is_live, subtree_has_live};
|
|
let to_members = effects::has_geometry(&n.appearance.effects) || n.appearance.items.iter().any(effects::paints);
|
|
is_live(n) || (is_container(n) && to_members && !effects::has_pathfinder(n) && subtree_has_live(n))
|
|
}
|
|
|
|
/// Can the art [`Renderer::fx_art`] makes for `n` change while `n` stays the same, other than
|
|
/// through live objects it evaluates? It can when `n` holds type (laid out in the fonts installed),
|
|
/// a symbol instance (made from its symbol's art), an object with a 3D effect or a color
|
|
/// adjustment (shaded or recolored through the color settings), one with Vector Halftone (its
|
|
/// dots sampled from everything it draws), or one with a live-effect plug-in that paints its pieces
|
|
/// (drawn only while the swatches and patterns they name are in the document), in it or in the
|
|
/// opacity masks of the objects in it.
|
|
pub(super) fn reads_outside(n: &Node) -> bool {
|
|
let mut reads = false;
|
|
n.walk(&mut |c| {
|
|
reads |= matches!(c.kind, NodeKind::Text(_) | NodeKind::SymbolInstance { .. })
|
|
|| effects::has_revolve(c)
|
|
|| effects::has_solid(c)
|
|
|| effects::has_adjustment(c)
|
|
|| effects::addons::halftone::has_halftone(c)
|
|
|| effects::has_painted_plugin_effect(c)
|
|
|| c.extras().mask.as_ref().is_some_and(|m| reads_outside(&m.art))
|
|
});
|
|
reads
|
|
}
|
|
|
|
/// The [`Content::bounds`] of `n` under raster effects `rfx`: its [`drawn_bounds`] when `rfx`
|
|
/// holds a Rasterize.
|
|
pub(super) fn rasterize_bounds(symbols: &SymbolBoxes, n: &Node, rfx: &[RasterFx]) -> Option<Rect> {
|
|
rfx.iter().any(|fx| matches!(fx, RasterFx::Rasterize(_))).then(|| drawn_bounds(symbols, n)).flatten()
|
|
}
|
|
|
|
/// `f` with the content moved by (`dx`, `dy`) document units (a shadow's offset).
|
|
pub(super) fn shifted<'a>(f: &Frame<'a>, dx: f64, dy: f64) -> Frame<'a> {
|
|
let moved = Affine::translate((dx, dy));
|
|
Frame { view: f.view * moved, visible: f.visible - Vec2::new(dx, dy), output: f.output * moved, ..*f }
|
|
}
|