From 3d24c663d2ec3630a86ee7ad1d9a11437223dda6 Mon Sep 17 00:00:00 2001 From: Taha-Mahmoodi <85902429+Taha-Mahmoodi@users.noreply.github.com> Date: Fri, 23 Oct 2026 01:22:42 +0430 Subject: [PATCH] Fix #3233: dimensions are redrawn in the colour mode after Document Color Mode and on open Follow-up to #3702 (CodeRabbit): dimensions are only redrawn when their recipe changes. Document Color Mode converted their art through the colour profile, so black became a four-ink C67 M67 Y67 K100 again, and CMYK files saved before #3702 kept RGB dimension art. dimension::refresh now also redraws when the document's colour mode changes. dimension::conform, run when a document is opened or reverted (Session::add_document, replace_document), redraws a dimension whose art has colours in the wrong model; one that can't be redrawn keeps its art. dimension_colours_follow_the_document_colour_model covers RGB to CMYK and back, and a CMYK document with RGB dimension art being opened. Without the change it finds C0.67 M0.67 Y0.67 K1 after Document Color Mode. --- crates/engine/src/cmd/dimension.rs | 34 +++++++++++++++++++++++++++++- crates/engine/src/lib.rs | 2 ++ crates/engine/tests/dimensions.rs | 15 +++++++++++++ 3 files changed, 50 insertions(+), 1 deletion(-) diff --git a/crates/engine/src/cmd/dimension.rs b/crates/engine/src/cmd/dimension.rs index cb8a68f67..62b268d50 100644 --- a/crates/engine/src/cmd/dimension.rs +++ b/crates/engine/src/cmd/dimension.rs @@ -227,13 +227,45 @@ pub(crate) fn refresh(before: &Document, doc: &mut Document) -> Result<()> { next.moved = None; } } - if next != old || before.node(id).and_then(|n| n.extras().dimension.as_deref()).is_some_and(|d| d != &next) { + // A new document colour mode (Document Color Mode) redraws every dimension in it. + if next != old + || before.color_mode != doc.color_mode + || before.node(id).and_then(|n| n.extras().dimension.as_deref()).is_some_and(|d| d != &next) + { replace(doc, id, next)?; } } Ok(()) } +/// Redraw the dimensions of an opened document whose art isn't in its colour mode: files saved +/// before dimensions followed the colour mode have RGB dimensions in CMYK documents. A dimension +/// that can't be redrawn keeps the art it has. +pub(crate) fn conform(doc: &mut Document) { + if !doc.dimensions { + return; + } + let mode = doc.color_mode; + let off_mode = |c: &Color| match mode { + ColorMode::Rgb => matches!(c, Color::Cmyk { .. }), + ColorMode::Cmyk => matches!(c, Color::Rgb { .. }), + }; + let mut stale = Vec::new(); + doc.walk(|n| { + if let Some(d) = &n.extras().dimension { + let mut off = false; + n.walk(&mut |c| off |= [c.appearance.fill_paint(), c.appearance.stroke_paint()].iter().filter_map(|p| p.color()).any(|c| off_mode(&c))); + if off { + stale.push((n.id, (**d).clone())); + } + } + }); + for (id, d) in stale { + // An error leaves this dimension as it was; the others are still redrawn. + let _ = replace(doc, id, d); + } +} + /// Option colour `c` as a paint in the document's colour model: in a CMYK document black is K /// only (a rich four-ink black would print a black dimension in every plate) and other colours /// convert through the active colour settings. diff --git a/crates/engine/src/lib.rs b/crates/engine/src/lib.rs index bcd8f58a3..69fb0dd0b 100644 --- a/crates/engine/src/lib.rs +++ b/crates/engine/src/lib.rs @@ -1587,6 +1587,7 @@ impl Session { Self::refresh_text_bounds(&mut doc); // Guides from files saved before guides had layers go on a layer. doc.adopt_guides(); + cmd::dimension::conform(&mut doc); self.reset_tool_for_doc_switch(); let mut st = DocState::new(doc, path); st.history.limit = self.prefs.history_states as usize; @@ -1604,6 +1605,7 @@ impl Session { doc.limit_depth(); Self::refresh_text_bounds(&mut doc); doc.adopt_guides(); + cmd::dimension::conform(&mut doc); if self.active == Some(index) { // Pending tool work (typing, a drag) belongs to the content being thrown away. self.reset_tool_for_doc_switch(); diff --git a/crates/engine/tests/dimensions.rs b/crates/engine/tests/dimensions.rs index 733b132b2..2c99eec0b 100644 --- a/crates/engine/tests/dimensions.rs +++ b/crates/engine/tests/dimensions.rs @@ -505,4 +505,19 @@ fn dimension_colours_follow_the_document_colour_model() { let line = edge(&mut s); let id = dim(&mut s, line); assert!(colours(&s, id).iter().all(|c| *c == vectorcraft_color::Color::rgb8(0, 0, 0))); + // Document Color Mode redraws dimensions in the new mode: K-only black in CMYK, RGB black back + // in RGB (not a profile conversion of the old art). + let k = vectorcraft_color::Color::cmyk(0.0, 0.0, 0.0, 1.0); + run(&mut s, "file.documentColorMode", json!({"mode":"cmyk"})); + let after = colours(&s, id); + assert!(!after.is_empty() && after.iter().all(|c| *c == k), "{after:?}"); + run(&mut s, "file.documentColorMode", json!({"mode":"rgb"})); + assert!(colours(&s, id).iter().all(|c| *c == vectorcraft_color::Color::rgb8(0, 0, 0)), "{:?}", colours(&s, id)); + // A CMYK file saved with RGB dimension art (before dimensions followed the colour mode) opens + // with its dimensions redrawn in CMYK. + let mut old = (*s.doc().unwrap().doc).clone(); + old.color_mode = vectorcraft_doc::ColorMode::Cmyk; + s.add_document(old, None); + let opened = colours(&s, id); + assert!(!opened.is_empty() && opened.iter().all(|c| *c == k), "{opened:?}"); }