diff --git a/moli-renderer-v8/src/native_bridge/element/styles/declaration/values.rs b/moli-renderer-v8/src/native_bridge/element/styles/declaration/values.rs index 051cf05566..8d50fd4b02 100644 --- a/moli-renderer-v8/src/native_bridge/element/styles/declaration/values.rs +++ b/moli-renderer-v8/src/native_bridge/element/styles/declaration/values.rs @@ -2394,6 +2394,9 @@ fn computed_style_property_value_after_style_update( if property == "font-variant" { return computed_font_variant_shorthand_value(runtime, handle, resolution); } + if property == "mask" { + return computed_mask_shorthand_value(runtime, handle, resolution); + } if property == "border" { return computed_border_shorthand_value(runtime, handle, context); } @@ -2662,6 +2665,36 @@ fn computed_font_variant_shorthand_value( serialize_font_variant_shorthand_values(&values).unwrap_or_default() } +fn computed_mask_shorthand_value( + runtime: &JsContextHost, + handle: DomHandle, + resolution: StyleResolutionContext<'_>, +) -> String { + const LONGHANDS: [&str; 9] = [ + "mask-mode", + "mask-repeat", + "mask-clip", + "mask-origin", + "mask-composite", + "mask-position-x", + "mask-position-y", + "mask-size", + "mask-image", + ]; + + let mut block = moli_css_parse::CssDeclarationBlock::default(); + for property in LONGHANDS { + let value = resolution.computed_property(runtime, handle, property); + if value.is_empty() + || block.set_property(property, &value, false) + == moli_css_parse::CssSetResult::ParseError + { + return String::new(); + } + } + block.property_value("mask").unwrap_or_default() +} + fn computed_webkit_text_stroke_shorthand_value( runtime: &JsContextHost, handle: DomHandle, diff --git a/moli-renderer-v8/src/script_vm/tests/dom_xhr/computed_style.rs b/moli-renderer-v8/src/script_vm/tests/dom_xhr/computed_style.rs index 5d52d5f077..53df860ce1 100644 --- a/moli-renderer-v8/src/script_vm/tests/dom_xhr/computed_style.rs +++ b/moli-renderer-v8/src/script_vm/tests/dom_xhr/computed_style.rs @@ -12410,6 +12410,80 @@ fn svg_generic_presentation_attributes_apply_to_every_svg_element() { ); } +#[test] +fn computed_mask_serializes_from_computed_longhands() { + let mut vm = new_parsed_test_vm( + "https://svg-mask-computed-shorthand.test/path/page.html", + r#" + + + + + + + "#, + ); + + let result = vm + .eval( + r#" +(() => { + const namespace = 'http://www.w3.org/2000/svg'; + const svg = document.getElementById('svg'); + const value = element => getComputedStyle(element).getPropertyValue('mask'); + const dynamic = document.createElementNS(namespace, 'unknown'); + svg.append(dynamic); + const values = [ + CSS.supports('mask', 'url(#supported)'), + value(dynamic), + value(document.getElementById('stylesheet')), + value(document.getElementById('attribute')), + value(document.getElementById('layered')), + value(document.getElementById('cascade')), + ]; + + dynamic.setAttribute('mask', 'url(#dynamic-mask)'); + values.push(value(dynamic)); + dynamic.removeAttribute('mask'); + values.push(value(dynamic)); + + dynamic.style.mask = + 'url(#inline-mask) center / contain no-repeat content-box exclude luminance'; + values.push(value(dynamic)); + dynamic.style.mask = 'none'; + dynamic.style.maskImage = 'url(#longhand-mask)'; + dynamic.style.maskMode = 'luminance'; + values.push(value(dynamic)); + + return values.join('|'); +})() +"#, + ) + .expect("computed mask shorthand should evaluate"); + + assert_eq!( + result, + concat!( + "true|none|", + "url(\"https://svg-mask-computed-shorthand.test/path/page.html#stylesheet-mask\")|", + "url(\"https://svg-mask-computed-shorthand.test/path/page.html#attribute-mask\")|", + "url(\"https://svg-mask-computed-shorthand.test/path/page.html#layered-mask\") ", + "50% 50% / contain no-repeat content-box exclude luminance|", + "url(\"https://svg-mask-computed-shorthand.test/path/page.html#rule-mask\")|", + "url(\"https://svg-mask-computed-shorthand.test/path/page.html#dynamic-mask\")|none|", + "url(\"https://svg-mask-computed-shorthand.test/path/page.html#inline-mask\") ", + "50% 50% / contain no-repeat content-box exclude luminance|", + "url(\"https://svg-mask-computed-shorthand.test/path/page.html#longhand-mask\") luminance", + ) + ); +} + #[test] fn svg_special_presentation_attributes_follow_element_scopes_and_cascade() { let mut vm = new_parsed_test_vm(