Fix clipping masks, click targets, and bounds when rendering Vector[] and flattened graphic wrappers (#4429)

* Honor clipping masks when rendering Vector[] lists, not just Graphic[] groups

* Keep per-layer click targets when a Vector[] round-trips through a Graphic[] wrapper

* Skip the rebuild and the merged-layers snapshot when flattening a lone anonymous graphic wrapper

* Fix a group's bounds excluding its raster children and stretching to the origin

* Fix SVG clipping masks landing in the wrong space when sibling layers differ in transform
This commit is contained in:
Keavon Chambers
2026-08-11 13:31:48 -07:00
committed by GitHub
parent 8e23d3509b
commit 9a129ecf5c
3 changed files with 434 additions and 281 deletions

View File

@@ -3,7 +3,7 @@ use core_types::list::{AttributeValueDyn, Item, List, ListDyn, NodeIdPath};
use core_types::registry::types::{Angle, SeedValue, SignedInteger};
use core_types::{ATTR_EDITOR_LAYER_PATH, ATTR_EDITOR_MERGED_LAYERS, ATTR_TRANSFORM, AnyHash, BlendMode, CacheHash, CloneVarArgs, Color, Context, Ctx, ExtractAll, OwnedContextImpl};
use glam::{DAffine2, DVec2};
use graphic_types::graphic::{Graphic, IntoGraphicList};
use graphic_types::graphic::{Graphic, IntoGraphicList, is_lone_anonymous_leaf};
use graphic_types::{Artboard, Vector};
use rand::SeedableRng;
use rand::seq::SliceRandom;
@@ -1020,7 +1020,7 @@ pub async fn flatten_vector<T: IntoGraphicList>(_: impl Ctx, #[implementations(L
// TODO: The cleaner fix is to drive each layer's metadata from its own Monitor's captured `(Context, List<Graphic>)`,
// TODO: at which point this attribute (and the equivalents in Boolean Operation, Solidify Stroke, Combine Paths,
// TODO: Morph, Rasterize) become unnecessary.
if !output.is_empty() {
if !output.is_empty() && !is_lone_anonymous_leaf(&graphic_list) {
// Item 0 carries a composed transform inherited from the flattened input, but the merged_layers
// already holds the original transforms; pre-compensate by item 0's inverse so the renderer's
// `upstream_footprint *= item_0_transform` recursion cancels out and leaves the originals intact.