Report compound-path paint and a non-normal blend in document summaries.

document.inspect skipped fill and stroke on compound paths because they are containers, and it never wrote the blend mode.
This commit is contained in:
Vikram Bhaskaran
2026-10-12 23:41:01 +11:00
parent 885a6e38cd
commit 1b79120568
2 changed files with 28 additions and 1 deletions
+6 -1
View File
@@ -1,6 +1,7 @@
//! Agent-friendly document summaries and view-models for panels.
use serde_json::{Value, json};
use vectorcraft_color::BlendMode;
use vectorcraft_doc::{ArrowAlign, Document, LineCap, LineJoin, Node, NodeKind, StrokeAlign, StrokeLayer, WidthProfile};
use crate::Session;
@@ -40,6 +41,9 @@ pub fn node_summary_opts(n: &Node, opts: SummaryOpts) -> Value {
if n.opacity < 1.0 {
v["opacity"] = json!(n.opacity);
}
if n.blend != BlendMode::Normal {
v["blend"] = json!(n.blend.label());
}
// The angle of its rotated bounding box (counter-clockwise degrees).
if n.bbox_angle != 0.0 {
v["rotation"] = json!(n.bbox_angle);
@@ -58,7 +62,8 @@ pub fn node_summary_opts(n: &Node, opts: SummaryOpts) -> Value {
v["objectStroke"] = json!(n.appearance.stroke_paint().label());
v["objectStrokeWidth"] = json!(n.appearance.stroke_width());
}
} else if !n.is_container() {
} else if !n.is_container() || matches!(n.kind, NodeKind::Compound { .. }) {
// A compound path is a container, but its fill and stroke live on it, not on its members.
v["fill"] = json!(n.appearance.fill_paint().label());
v["stroke"] = json!(n.appearance.stroke_paint().label());
v["strokeWidth"] = json!(n.appearance.stroke_width());
+22
View File
@@ -1520,6 +1520,28 @@ fn inspect_lists_everything() {
/// `document.node {summary: true}` answers the `document.inspect` shape for one node:
/// the same fields the full-tree summary carries, without serializing the whole tree.
#[test]
/// A compound path reports the paint that lives on it, and any node reports a blend other than Normal.
#[test]
fn inspect_reports_compound_paint_and_blend() {
let mut s = session();
let a = rect(&mut s, 0.0, 0.0, 40.0, 40.0);
let b = rect(&mut s, 10.0, 10.0, 10.0, 10.0);
s.execute("select.set", &json!({"ids": [a.0, b.0]})).unwrap();
let c = s.execute("object.compoundPath.make", &json!({})).unwrap()["id"].as_u64().unwrap();
s.execute("object.setProps", &json!({"id": c, "blend": "Multiply"})).unwrap();
let v = s.execute("document.inspect", &json!({})).unwrap();
let node = &v["layers"][0]["children"][0];
assert_eq!(node["id"], c);
assert_eq!(node["kind"], "Compound Path");
assert!(node["fill"].as_str().is_some_and(|f| f != "None"), "compound paint: {node}");
assert!(node.get("stroke").is_some() && node.get("strokeWidth").is_some(), "{node}");
assert_eq!(node["blend"], "Multiply");
let plain = rect(&mut s, 80.0, 0.0, 10.0, 10.0);
let v = s.execute("document.inspect", &json!({})).unwrap();
let plain = v["layers"][0]["children"].as_array().unwrap().iter().find(|n| n["id"] == plain.0).unwrap();
assert!(plain.get("blend").is_none(), "Normal is omitted: {plain}");
}
fn document_node_summary_matches_inspect() {
let mut s = session();
let id = rect(&mut s, 0.0, 0.0, 10.0, 10.0).0;