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(