Effects: Drop Shadow has Darkness, the object's own colors with black added

The reference app's Drop Shadow has a Color and a Darkness, the
percentage of black added to the object's own colors. Drop Shadow had
only a Color, so every shadow was one color. Choosing one or the other,
and the defaults, are VectorCraft's own.

Drop Shadow now takes `shade` ("color" or "darkness", default "color")
and `darkness` (%, default 100). Its dialog and the Appearance panel's
inline editor show Color and Darkness as radio buttons. With Darkness
d, a CMYK document keeps the object's cyan, magenta and yellow and
raises its black from K to K + d × (1 − K), and an RGB document
multiplies each channel by 1 − d, so in RGB 0% gives the object's
color and 100% gives black. A shadow saved without these keys draws as
before. SVG export writes a Darkness shadow with feComponentTransfer
and SVG import reads it back; CSS export leaves it out.

Docs: docs/target-app-parity.md.
This commit is contained in:
dotCooCoo
2026-10-16 02:25:58 +07:00
committed by bflatastic
parent b5a0fee1ea
commit 720ce5ed73
29 changed files with 497 additions and 51 deletions
+2 -2
View File
@@ -308,8 +308,8 @@ pub fn effect_catalog() -> Vec<EffectInfo> {
"stylize.dropShadow",
"Drop Shadow…",
STYLIZE,
"{mode: blend mode (\"multiply\"), opacity: % (75), x: pt (7), y: pt (7), blur: pt (5), color: \"#rrggbb\" (\"#000000\")}",
json!({"mode": "multiply", "opacity": 75.0, "x": 7.0, "y": 7.0, "blur": 5.0, "color": "#000000"}),
"{mode: blend mode (\"multiply\"), opacity: % (75), x: pt (7), y: pt (7), blur: pt (5), shade: \"color\"|\"darkness\" (\"color\"), color: \"#rrggbb\" (\"#000000\"), darkness: % (100)} (shade \"darkness\": the shadow is the object's own colors with `darkness` percent of black added instead of `color`: in a CMYK document their cyan, magenta and yellow stay and their black K becomes K + darkness × (1 − K); in an RGB document each channel is multiplied by 1 − darkness)",
json!({"mode": "multiply", "opacity": 75.0, "x": 7.0, "y": 7.0, "blur": 5.0, "shade": "color", "color": "#000000", "darkness": 100.0}),
),
r(
"stylize.innerGlow",
+6
View File
@@ -21,6 +21,9 @@ pub enum RasterFx {
dy: f64,
blur: f64,
color: Color,
/// Darkness (0..1): the shadow is the object's own colors with this share of black added
/// instead of `color`; `None` when it is `color`.
darkness: Option<f32>,
},
OuterGlow {
mode: BlendMode,
@@ -111,6 +114,9 @@ pub fn raster_effects(effects: &[Effect]) -> Vec<RasterFx> {
dy: num(&p, "y", 7.0).clamp(-1e4, 1e4),
blur,
color: color_param(&p, Color::BLACK),
darkness: text(&p, "shade", "color")
.eq_ignore_ascii_case("darkness")
.then(|| (num(&p, "darkness", 100.0) / 100.0).clamp(0.0, 1.0) as f32),
},
"stylize.outerGlow" => RasterFx::OuterGlow {
mode: blend_mode(text(&p, "mode", "screen")),
+16 -1
View File
@@ -565,11 +565,12 @@ fn raster_effects_parse_and_outset() {
let r = raster_effects(&list);
assert_eq!(r.len(), 5);
match &r[0] {
RasterFx::DropShadow { mode, opacity, dx, dy, blur, color } => {
RasterFx::DropShadow { mode, opacity, dx, dy, blur, color, darkness } => {
assert_eq!(*mode, vectorcraft_doc::color::BlendMode::Multiply);
assert!(close(*opacity as f64, 0.5, 1e-6));
assert_eq!((*dx, *dy, *blur), (10.0, -4.0, 6.0));
assert_eq!(color.to_rgb(), [1.0, 0.0, 0.0]);
assert_eq!(*darkness, None);
}
other => panic!("{other:?}"),
}
@@ -578,6 +579,20 @@ fn raster_effects_parse_and_outset() {
assert_eq!(outset(&[], vectorcraft_geom::Rect::ZERO), 0.0);
}
#[test]
fn drop_shadow_darkness_replaces_its_color_when_chosen() {
let darkness = |params: Value| match raster_effects(&[fx("stylize.dropShadow", params)]).as_slice() {
[RasterFx::DropShadow { darkness, .. }] => *darkness,
other => panic!("{other:?}"),
};
assert_eq!(darkness(json!({"shade": "darkness", "darkness": 60})), Some(0.6));
assert_eq!(darkness(json!({"shade": "darkness"})), Some(1.0));
assert_eq!(darkness(json!({"shade": "darkness", "darkness": 250})), Some(1.0));
// Color is the default: a Darkness value alone leaves the shadow its color.
assert_eq!(darkness(json!({"darkness": 60})), None);
assert_eq!(darkness(json!({})), None);
}
#[test]
fn blend_mode_names() {
use vectorcraft_doc::color::BlendMode;