diff --git a/Libraries/LibWeb/CSS/Parser/ValueParsing.cpp b/Libraries/LibWeb/CSS/Parser/ValueParsing.cpp index 562dfde9378..599220220a4 100644 --- a/Libraries/LibWeb/CSS/Parser/ValueParsing.cpp +++ b/Libraries/LibWeb/CSS/Parser/ValueParsing.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -1925,8 +1926,19 @@ RefPtr Parser::parse_string_value(TokenStream& RefPtr Parser::parse_image_value(TokenStream& tokens) { - if (auto url = parse_url_function(tokens); url.has_value()) - return ImageStyleValue::create(url.value()); + tokens.mark(); + auto url = parse_url_function(tokens); + if (url.has_value()) { + // If the value is a 'url(..)' parse as image, but if it is just a reference 'url(#xx)', leave it alone, + // so we can parse as URL further on. These URLs are used as references inside SVG documents for masks. + if (!url.value().equals(m_url, URL::ExcludeFragment::Yes)) { + tokens.discard_a_mark(); + return ImageStyleValue::create(url.value()); + } + tokens.restore_a_mark(); + return nullptr; + } + tokens.discard_a_mark(); if (auto linear_gradient = parse_linear_gradient_function(tokens)) return linear_gradient; diff --git a/Libraries/LibWeb/CSS/Properties.json b/Libraries/LibWeb/CSS/Properties.json index 7c1a8a8b3cf..2f167d8879d 100644 --- a/Libraries/LibWeb/CSS/Properties.json +++ b/Libraries/LibWeb/CSS/Properties.json @@ -1958,25 +1958,21 @@ ] }, "mask": { - "animation-type": "none", - "affects-layout": false, - "affects-stacking-context": true, "inherited": false, - "valid-identifiers": [ - "none" - ], - "__comment": "FIXME: This should be a and/or #", - "valid-types": [ - "url" - ], - "initial": "none" + "__comment": "FIXME: add longhands mask-clip, mask-composite, mask-mode, mask-origin, mask-position, mask-repeat, mask-size; also reset mask-border", + "initial": "none", + "longhands": [ + "mask-image" + ] }, "mask-image": { "animation-type": "discrete", "inherited": false, "affects-layout": false, + "affects-stacking-context": true, "valid-types": [ - "image" + "image", + "url" ], "valid-identifiers": [ "none" diff --git a/Libraries/LibWeb/Layout/Node.cpp b/Libraries/LibWeb/Layout/Node.cpp index b37e2f14c92..aece5f6e4a5 100644 --- a/Libraries/LibWeb/Layout/Node.cpp +++ b/Libraries/LibWeb/Layout/Node.cpp @@ -827,7 +827,10 @@ void NodeWithStyle::apply_style(CSS::ComputedProperties const& computed_style) else if (stroke_width.is_percentage()) computed_values.set_stroke_width(CSS::LengthPercentage { stroke_width.as_percentage().percentage() }); - if (auto const& mask_image = computed_style.property(CSS::PropertyID::MaskImage); mask_image.is_abstract_image()) { + auto const& mask_image = computed_style.property(CSS::PropertyID::MaskImage); + if (mask_image.is_url()) { + computed_values.set_mask(mask_image.as_url().url()); + } else if (mask_image.is_abstract_image()) { auto const& abstract_image = mask_image.as_abstract_image(); computed_values.set_mask_image(abstract_image); const_cast(abstract_image).load_any_resources(document()); @@ -835,9 +838,6 @@ void NodeWithStyle::apply_style(CSS::ComputedProperties const& computed_style) computed_values.set_mask_type(computed_style.mask_type()); - if (auto const& mask = computed_style.property(CSS::PropertyID::Mask); mask.is_url()) - computed_values.set_mask(mask.as_url().url()); - auto const& clip_path = computed_style.property(CSS::PropertyID::ClipPath); if (clip_path.is_url()) computed_values.set_clip_path(clip_path.as_url().url()); diff --git a/Libraries/LibWeb/SVG/SVGGraphicsElement.cpp b/Libraries/LibWeb/SVG/SVGGraphicsElement.cpp index 8d9e5d27382..a814961fba7 100644 --- a/Libraries/LibWeb/SVG/SVGGraphicsElement.cpp +++ b/Libraries/LibWeb/SVG/SVGGraphicsElement.cpp @@ -182,8 +182,17 @@ void SVGGraphicsElement::apply_presentational_hints(GC::Refset_property_from_presentational_hint(property.id, style_value.release_nonnull()); + if (property.id == CSS::PropertyID::Mask) { + // Mask is a shorthand property in CSS, but parse_css_value does not take that into account. For now, + // just parse as 'mask-image' as anything else is currently not supported. + // FIXME: properly parse longhand 'mask' property + if (auto style_value = parse_css_value(parsing_context, value, CSS::PropertyID::MaskImage)) { + cascaded_properties->set_property_from_presentational_hint(CSS::PropertyID::MaskImage, style_value.release_nonnull()); + } + } else { + if (auto style_value = parse_css_value(parsing_context, value, property.id)) + cascaded_properties->set_property_from_presentational_hint(property.id, style_value.release_nonnull()); + } break; } }); diff --git a/Tests/LibWeb/Screenshot/expected/css-mask-longhand.html b/Tests/LibWeb/Screenshot/expected/css-mask-longhand.html new file mode 100644 index 00000000000..428df7c0d9e --- /dev/null +++ b/Tests/LibWeb/Screenshot/expected/css-mask-longhand.html @@ -0,0 +1,13 @@ + + +
+ + diff --git a/Tests/LibWeb/Screenshot/input/css-mask-longhand.html b/Tests/LibWeb/Screenshot/input/css-mask-longhand.html new file mode 100644 index 00000000000..67ac2854b25 --- /dev/null +++ b/Tests/LibWeb/Screenshot/input/css-mask-longhand.html @@ -0,0 +1,13 @@ + + +
+ + diff --git a/Tests/LibWeb/Text/expected/css/CSSStyleDeclaration-all-supported-properties-and-default-values.txt b/Tests/LibWeb/Text/expected/css/CSSStyleDeclaration-all-supported-properties-and-default-values.txt index b3eaf490912..afc43a69d0f 100644 --- a/Tests/LibWeb/Text/expected/css/CSSStyleDeclaration-all-supported-properties-and-default-values.txt +++ b/Tests/LibWeb/Text/expected/css/CSSStyleDeclaration-all-supported-properties-and-default-values.txt @@ -1,6 +1,6 @@ All supported properties and their default values exposed from CSSStyleDeclaration from getComputedStyle: 'cssText': '' -'length': '220' +'length': '219' 'parentRule': 'null' 'cssFloat': 'none' 'WebkitAlignContent': 'normal' diff --git a/Tests/LibWeb/Text/expected/css/CSSStyleDeclaration-has-indexed-property-getter.txt b/Tests/LibWeb/Text/expected/css/CSSStyleDeclaration-has-indexed-property-getter.txt index 15df8d37e4e..aeba2e39f4d 100644 --- a/Tests/LibWeb/Text/expected/css/CSSStyleDeclaration-has-indexed-property-getter.txt +++ b/Tests/LibWeb/Text/expected/css/CSSStyleDeclaration-has-indexed-property-getter.txt @@ -156,70 +156,69 @@ All properties associated with getComputedStyle(document.body): "153": "margin-left", "154": "margin-right", "155": "margin-top", - "156": "mask", - "157": "mask-image", - "158": "mask-type", - "159": "max-block-size", - "160": "max-height", - "161": "max-inline-size", - "162": "max-width", - "163": "min-block-size", - "164": "min-height", - "165": "min-inline-size", - "166": "min-width", - "167": "mix-blend-mode", - "168": "object-fit", - "169": "object-position", - "170": "opacity", - "171": "order", - "172": "outline-color", - "173": "outline-offset", - "174": "outline-style", - "175": "outline-width", - "176": "overflow-x", - "177": "overflow-y", - "178": "padding-block-end", - "179": "padding-block-start", - "180": "padding-bottom", - "181": "padding-inline-end", - "182": "padding-inline-start", - "183": "padding-left", - "184": "padding-right", - "185": "padding-top", - "186": "position", - "187": "r", - "188": "right", - "189": "rotate", - "190": "row-gap", - "191": "rx", - "192": "ry", - "193": "scale", - "194": "scrollbar-gutter", - "195": "scrollbar-width", - "196": "stop-color", - "197": "stop-opacity", - "198": "table-layout", - "199": "text-decoration-color", - "200": "text-decoration-style", - "201": "text-decoration-thickness", - "202": "text-overflow", - "203": "top", - "204": "transform", - "205": "transform-box", - "206": "transform-origin", - "207": "transition-delay", - "208": "transition-duration", - "209": "transition-property", - "210": "transition-timing-function", - "211": "translate", - "212": "unicode-bidi", - "213": "user-select", - "214": "vertical-align", - "215": "view-transition-name", - "216": "width", - "217": "x", - "218": "y", - "219": "z-index" + "156": "mask-image", + "157": "mask-type", + "158": "max-block-size", + "159": "max-height", + "160": "max-inline-size", + "161": "max-width", + "162": "min-block-size", + "163": "min-height", + "164": "min-inline-size", + "165": "min-width", + "166": "mix-blend-mode", + "167": "object-fit", + "168": "object-position", + "169": "opacity", + "170": "order", + "171": "outline-color", + "172": "outline-offset", + "173": "outline-style", + "174": "outline-width", + "175": "overflow-x", + "176": "overflow-y", + "177": "padding-block-end", + "178": "padding-block-start", + "179": "padding-bottom", + "180": "padding-inline-end", + "181": "padding-inline-start", + "182": "padding-left", + "183": "padding-right", + "184": "padding-top", + "185": "position", + "186": "r", + "187": "right", + "188": "rotate", + "189": "row-gap", + "190": "rx", + "191": "ry", + "192": "scale", + "193": "scrollbar-gutter", + "194": "scrollbar-width", + "195": "stop-color", + "196": "stop-opacity", + "197": "table-layout", + "198": "text-decoration-color", + "199": "text-decoration-style", + "200": "text-decoration-thickness", + "201": "text-overflow", + "202": "top", + "203": "transform", + "204": "transform-box", + "205": "transform-origin", + "206": "transition-delay", + "207": "transition-duration", + "208": "transition-property", + "209": "transition-timing-function", + "210": "translate", + "211": "unicode-bidi", + "212": "user-select", + "213": "vertical-align", + "214": "view-transition-name", + "215": "width", + "216": "x", + "217": "y", + "218": "z-index" } All properties associated with document.body.style by default: {} diff --git a/Tests/LibWeb/Text/expected/css/getComputedStyle-print-all.txt b/Tests/LibWeb/Text/expected/css/getComputedStyle-print-all.txt index 3efc595cdcc..90a96c09ed2 100644 --- a/Tests/LibWeb/Text/expected/css/getComputedStyle-print-all.txt +++ b/Tests/LibWeb/Text/expected/css/getComputedStyle-print-all.txt @@ -154,7 +154,6 @@ margin-inline-start: 8px margin-left: 8px margin-right: 8px margin-top: 8px -mask: none mask-image: none mask-type: luminance max-block-size: none