diff --git a/Libraries/LibWeb/CMakeLists.txt b/Libraries/LibWeb/CMakeLists.txt index c91dac76459..220fc75fb62 100644 --- a/Libraries/LibWeb/CMakeLists.txt +++ b/Libraries/LibWeb/CMakeLists.txt @@ -823,6 +823,7 @@ set(SOURCES SVG/SVGDescElement.cpp SVG/SVGElement.cpp SVG/SVGEllipseElement.cpp + SVG/SVGFEFloodElement.cpp SVG/SVGFilterElement.cpp SVG/SVGForeignObjectElement.cpp SVG/SVGGElement.cpp diff --git a/Libraries/LibWeb/CSS/ComputedProperties.cpp b/Libraries/LibWeb/CSS/ComputedProperties.cpp index e257cee4020..49988d84c1a 100644 --- a/Libraries/LibWeb/CSS/ComputedProperties.cpp +++ b/Libraries/LibWeb/CSS/ComputedProperties.cpp @@ -443,6 +443,22 @@ ClipRule ComputedProperties::clip_rule() const return keyword_to_fill_rule(value.to_keyword()).release_value(); } +Color ComputedProperties::flood_color(Layout::NodeWithStyle const& node) const +{ + auto const& value = property(PropertyID::FloodColor); + if (value.has_color()) { + return value.to_color(node, { .length_resolution_context = Length::ResolutionContext::for_layout_node(node) }); + } + + return InitialValues::flood_color(); +} + +float ComputedProperties::flood_opacity() const +{ + auto const& value = property(PropertyID::FloodOpacity); + return resolve_opacity_value(value); +} + FlexDirection ComputedProperties::flex_direction() const { auto const& value = property(PropertyID::FlexDirection); diff --git a/Libraries/LibWeb/CSS/ComputedProperties.h b/Libraries/LibWeb/CSS/ComputedProperties.h index 745dc11e698..690b5897c39 100644 --- a/Libraries/LibWeb/CSS/ComputedProperties.h +++ b/Libraries/LibWeb/CSS/ComputedProperties.h @@ -194,6 +194,8 @@ public: float stroke_opacity() const; FillRule fill_rule() const; ClipRule clip_rule() const; + Color flood_color(Layout::NodeWithStyle const&) const; + float flood_opacity() const; Gfx::FontCascadeList const& computed_font_list() const { diff --git a/Libraries/LibWeb/CSS/ComputedValues.h b/Libraries/LibWeb/CSS/ComputedValues.h index 5aebfe85060..af628577859 100644 --- a/Libraries/LibWeb/CSS/ComputedValues.h +++ b/Libraries/LibWeb/CSS/ComputedValues.h @@ -152,6 +152,8 @@ public: static float fill_opacity() { return 1.0f; } static CSS::FillRule fill_rule() { return CSS::FillRule::Nonzero; } static CSS::ClipRule clip_rule() { return CSS::ClipRule::Nonzero; } + static Color flood_color() { return Color::Black; } + static float flood_opacity() { return 1.0f; } static CSS::LengthPercentage stroke_dashoffset() { return CSS::Length::make_px(0); } static CSS::StrokeLinecap stroke_linecap() { return CSS::StrokeLinecap::Butt; } static CSS::StrokeLinejoin stroke_linejoin() { return CSS::StrokeLinejoin::Miter; } @@ -554,6 +556,8 @@ public: CSS::MaskType mask_type() const { return m_noninherited.mask_type; } Optional const& clip_path() const { return m_noninherited.clip_path; } CSS::ClipRule clip_rule() const { return m_inherited.clip_rule; } + Color flood_color() const { return m_noninherited.flood_color; } + float flood_opacity() const { return m_noninherited.flood_opacity; } LengthPercentage const& cx() const { return m_noninherited.cx; } LengthPercentage const& cy() const { return m_noninherited.cy; } @@ -796,6 +800,9 @@ protected: Vector counter_increment; Vector counter_reset; Vector counter_set; + + Color flood_color { InitialValues::flood_color() }; + float flood_opacity { InitialValues::flood_opacity() }; } m_noninherited; }; @@ -982,6 +989,8 @@ public: void set_mask_image(CSS::AbstractImageStyleValue const& value) { m_noninherited.mask_image = value; } void set_clip_path(ClipPathReference value) { m_noninherited.clip_path = move(value); } void set_clip_rule(CSS::ClipRule value) { m_inherited.clip_rule = value; } + void set_flood_color(Color value) { m_noninherited.flood_color = value; } + void set_flood_opacity(float value) { m_noninherited.flood_opacity = value; } void set_cx(LengthPercentage cx) { m_noninherited.cx = move(cx); } void set_cy(LengthPercentage cy) { m_noninherited.cy = move(cy); } diff --git a/Libraries/LibWeb/CSS/Properties.json b/Libraries/LibWeb/CSS/Properties.json index f1d20a04394..7eb1d531b22 100644 --- a/Libraries/LibWeb/CSS/Properties.json +++ b/Libraries/LibWeb/CSS/Properties.json @@ -1537,6 +1537,24 @@ "float" ] }, + "flood-color": { + "affects-layout": false, + "animation-type": "by-computed-value", + "inherited": false, + "initial": "black", + "valid-types": [ + "color" + ] + }, + "flood-opacity": { + "affects-layout": false, + "animation-type": "by-computed-value", + "inherited": false, + "initial": "1", + "valid-types": [ + "number [0,1]" + ] + }, "font": { "inherited": true, "initial": "normal medium serif", diff --git a/Libraries/LibWeb/DOM/ElementFactory.cpp b/Libraries/LibWeb/DOM/ElementFactory.cpp index 1d2fb19ba7b..60e596c836a 100644 --- a/Libraries/LibWeb/DOM/ElementFactory.cpp +++ b/Libraries/LibWeb/DOM/ElementFactory.cpp @@ -91,6 +91,7 @@ #include #include #include +#include #include #include #include @@ -461,6 +462,8 @@ static GC::Ref create_svg_element(JS::Realm& realm, Document& d return realm.create(document, move(qualified_name)); if (local_name == SVG::TagNames::ellipse) return realm.create(document, move(qualified_name)); + if (local_name == SVG::TagNames::feFlood) + return realm.create(document, move(qualified_name)); if (local_name == SVG::TagNames::filter) return realm.create(document, move(qualified_name)); if (local_name.equals_ignoring_ascii_case(SVG::TagNames::foreignObject)) diff --git a/Libraries/LibWeb/Forward.h b/Libraries/LibWeb/Forward.h index 486292f5c60..b2054179f4f 100644 --- a/Libraries/LibWeb/Forward.h +++ b/Libraries/LibWeb/Forward.h @@ -967,6 +967,7 @@ class SVGDefsElement; class SVGDescElement; class SVGElement; class SVGEllipseElement; +class SVGFEFloodElement; class SVGFilterElement; class SVGForeignObjectElement; class SVGGeometryElement; diff --git a/Libraries/LibWeb/SVG/SVGElement.cpp b/Libraries/LibWeb/SVG/SVGElement.cpp index b5b7b1224d5..ccc0744d02e 100644 --- a/Libraries/LibWeb/SVG/SVGElement.cpp +++ b/Libraries/LibWeb/SVG/SVGElement.cpp @@ -61,6 +61,9 @@ static ReadonlySpan attribute_style_properties() NamedPropertyID(CSS::PropertyID::Display), NamedPropertyID(CSS::PropertyID::FillOpacity), NamedPropertyID(CSS::PropertyID::FillRule), + NamedPropertyID(CSS::PropertyID::Filter), + NamedPropertyID(CSS::PropertyID::FloodColor), + NamedPropertyID(CSS::PropertyID::FloodOpacity), NamedPropertyID(CSS::PropertyID::FontFamily), NamedPropertyID(CSS::PropertyID::FontSize), NamedPropertyID(CSS::PropertyID::FontStyle), diff --git a/Libraries/LibWeb/SVG/SVGElement.h b/Libraries/LibWeb/SVG/SVGElement.h index b016517f337..54e98980894 100644 --- a/Libraries/LibWeb/SVG/SVGElement.h +++ b/Libraries/LibWeb/SVG/SVGElement.h @@ -29,6 +29,8 @@ public: bool should_include_in_accessibility_tree() const; virtual Optional default_role() const override; + GC::Ref svg_animated_length_for_property(CSS::PropertyID) const; + virtual bool is_presentational_hint(FlyString const&) const override; virtual void apply_presentational_hints(GC::Ref) const override; @@ -47,8 +49,6 @@ protected: void update_use_elements_that_reference_this(); void remove_from_use_element_that_reference_this(); - GC::Ref svg_animated_length_for_property(CSS::PropertyID) const; - private: // ^HTML::GlobalEventHandlers virtual GC::Ptr global_event_handlers_to_event_target(FlyString const&) override { return *this; } diff --git a/Libraries/LibWeb/SVG/SVGFEFloodElement.cpp b/Libraries/LibWeb/SVG/SVGFEFloodElement.cpp new file mode 100644 index 00000000000..14a24340660 --- /dev/null +++ b/Libraries/LibWeb/SVG/SVGFEFloodElement.cpp @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2025, Lucien Fiorini + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include +#include +#include +#include +#include + +namespace Web::SVG { + +GC_DEFINE_ALLOCATOR(SVGFEFloodElement); + +SVGFEFloodElement::SVGFEFloodElement(DOM::Document& document, DOM::QualifiedName qualified_name) + : SVGElement(document, qualified_name) +{ +} + +void SVGFEFloodElement::initialize(JS::Realm& realm) +{ + Base::initialize(realm); + WEB_SET_PROTOTYPE_FOR_INTERFACE(SVGFEFloodElement); +} + +void SVGFEFloodElement::visit_edges(Cell::Visitor& visitor) +{ + Base::visit_edges(visitor); + SVGFilterPrimitiveStandardAttributes::visit_edges(visitor); +} + +GC::Ptr SVGFEFloodElement::create_layout_node(GC::Ref style) +{ + return heap().allocate(document(), *this, move(style)); +} + +// https://www.w3.org/TR/filter-effects-1/#FloodColorProperty +Gfx::Color SVGFEFloodElement::flood_color() const +{ + // FIXME: Find a way to get the Gfx::Color of the flood_color property + // without having a layout node. + return Color::Black; +} + +// https://www.w3.org/TR/filter-effects-1/#FloodOpacityProperty +float SVGFEFloodElement::flood_opacity() const +{ + return computed_properties()->flood_opacity(); +} + +} diff --git a/Libraries/LibWeb/SVG/SVGFEFloodElement.h b/Libraries/LibWeb/SVG/SVGFEFloodElement.h new file mode 100644 index 00000000000..0f7f4302435 --- /dev/null +++ b/Libraries/LibWeb/SVG/SVGFEFloodElement.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2025, Lucien Fiorini + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include +#include + +namespace Web::SVG { + +class SVGFEFloodElement final + : public SVGElement + , public SVGFilterPrimitiveStandardAttributes { + WEB_PLATFORM_OBJECT(SVGFEFloodElement, SVGElement); + GC_DECLARE_ALLOCATOR(SVGFEFloodElement); + +public: + virtual ~SVGFEFloodElement() override = default; + + virtual GC::Ptr create_layout_node(GC::Ref) override; + + Gfx::Color flood_color() const; + float flood_opacity() const; + +private: + SVGFEFloodElement(DOM::Document&, DOM::QualifiedName); + + virtual void initialize(JS::Realm&) override; + virtual void visit_edges(Cell::Visitor&) override; +}; + +} diff --git a/Libraries/LibWeb/SVG/SVGFEFloodElement.idl b/Libraries/LibWeb/SVG/SVGFEFloodElement.idl new file mode 100644 index 00000000000..9436e8dcdfc --- /dev/null +++ b/Libraries/LibWeb/SVG/SVGFEFloodElement.idl @@ -0,0 +1,8 @@ +#import + +// https://www.w3.org/TR/filter-effects-1/#InterfaceSVGFEFloodElement +[Exposed=Window] +interface SVGFEFloodElement : SVGElement { +}; + +SVGFEFloodElement includes SVGFilterPrimitiveStandardAttributes; diff --git a/Libraries/LibWeb/SVG/TagNames.h b/Libraries/LibWeb/SVG/TagNames.h index 6472daa8009..bc44181ed5e 100644 --- a/Libraries/LibWeb/SVG/TagNames.h +++ b/Libraries/LibWeb/SVG/TagNames.h @@ -17,6 +17,7 @@ namespace Web::SVG::TagNames { __ENUMERATE_SVG_TAG(defs) \ __ENUMERATE_SVG_TAG(desc) \ __ENUMERATE_SVG_TAG(ellipse) \ + __ENUMERATE_SVG_TAG(feFlood) \ __ENUMERATE_SVG_TAG(filter) \ __ENUMERATE_SVG_TAG(foreignObject) \ __ENUMERATE_SVG_TAG(g) \ diff --git a/Libraries/LibWeb/idl_files.cmake b/Libraries/LibWeb/idl_files.cmake index 6a4146065d3..b8f7d3c848b 100644 --- a/Libraries/LibWeb/idl_files.cmake +++ b/Libraries/LibWeb/idl_files.cmake @@ -340,6 +340,7 @@ libweb_js_bindings(SVG/SVGGraphicsElement) libweb_js_bindings(SVG/SVGImageElement) libweb_js_bindings(SVG/SVGCircleElement) libweb_js_bindings(SVG/SVGEllipseElement) +libweb_js_bindings(SVG/SVGFEFloodElement) libweb_js_bindings(SVG/SVGFilterElement) libweb_js_bindings(SVG/SVGForeignObjectElement) libweb_js_bindings(SVG/SVGLength) diff --git a/Tests/LibWeb/Text/expected/all-window-properties.txt b/Tests/LibWeb/Text/expected/all-window-properties.txt index b686224203c..9c9164485eb 100644 --- a/Tests/LibWeb/Text/expected/all-window-properties.txt +++ b/Tests/LibWeb/Text/expected/all-window-properties.txt @@ -338,6 +338,7 @@ SVGDefsElement SVGDescElement SVGElement SVGEllipseElement +SVGFEFloodElement SVGFilterElement SVGForeignObjectElement SVGGElement 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 307d5ba5028..dfae658b5c9 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 @@ -155,6 +155,8 @@ All properties associated with getComputedStyle(document.body): "flex-shrink", "flex-wrap", "float", + "flood-color", + "flood-opacity", "grid-auto-columns", "grid-auto-flow", "grid-auto-rows", diff --git a/Tests/LibWeb/Text/expected/css/CSSStyleProperties-all-supported-properties-and-default-values.txt b/Tests/LibWeb/Text/expected/css/CSSStyleProperties-all-supported-properties-and-default-values.txt index e5756fc1604..af1baf2698e 100644 --- a/Tests/LibWeb/Text/expected/css/CSSStyleProperties-all-supported-properties-and-default-values.txt +++ b/Tests/LibWeb/Text/expected/css/CSSStyleProperties-all-supported-properties-and-default-values.txt @@ -385,6 +385,10 @@ All supported properties and their default values exposed from CSSStylePropertie 'flexWrap': 'nowrap' 'flex-wrap': 'nowrap' 'float': 'none' +'floodColor': 'rgb(0, 0, 0)' +'flood-color': 'rgb(0, 0, 0)' +'floodOpacity': '1' +'flood-opacity': '1' 'font': '16px serif' 'fontFamily': 'serif' 'font-family': 'serif' diff --git a/Tests/LibWeb/Text/expected/css/getComputedStyle-print-all.txt b/Tests/LibWeb/Text/expected/css/getComputedStyle-print-all.txt index 1930d185d7b..b1302f767a5 100644 --- a/Tests/LibWeb/Text/expected/css/getComputedStyle-print-all.txt +++ b/Tests/LibWeb/Text/expected/css/getComputedStyle-print-all.txt @@ -153,6 +153,8 @@ flex-grow: 0 flex-shrink: 1 flex-wrap: nowrap float: none +flood-color: rgb(0, 0, 0) +flood-opacity: 1 grid-auto-columns: auto grid-auto-flow: row grid-auto-rows: auto @@ -163,7 +165,7 @@ grid-row-start: auto grid-template-areas: none grid-template-columns: none grid-template-rows: none -height: 2475px +height: 2505px inline-size: 784px inset-block-end: auto inset-block-start: auto diff --git a/Tests/LibWeb/Text/expected/wpt-import/css/css-cascade/all-prop-revert-layer.txt b/Tests/LibWeb/Text/expected/wpt-import/css/css-cascade/all-prop-revert-layer.txt index 6cd6a3c0a49..a3452c78b74 100644 --- a/Tests/LibWeb/Text/expected/wpt-import/css/css-cascade/all-prop-revert-layer.txt +++ b/Tests/LibWeb/Text/expected/wpt-import/css/css-cascade/all-prop-revert-layer.txt @@ -1,9 +1,9 @@ Harness status: OK -Found 245 tests +Found 248 tests -239 Pass -6 Fail +241 Pass +7 Fail Pass accent-color Pass border-collapse Pass border-spacing @@ -147,12 +147,15 @@ Pass counter-set Pass cx Pass cy Pass display +Fail filter Pass flex-basis Pass flex-direction Pass flex-grow Pass flex-shrink Pass flex-wrap Pass float +Pass flood-color +Pass flood-opacity Pass grid-auto-columns Pass grid-auto-flow Pass grid-auto-rows diff --git a/Tests/LibWeb/Text/expected/wpt-import/svg/styling/presentation-attributes-irrelevant.txt b/Tests/LibWeb/Text/expected/wpt-import/svg/styling/presentation-attributes-irrelevant.txt index f7e15d9b133..7dc65880b26 100644 --- a/Tests/LibWeb/Text/expected/wpt-import/svg/styling/presentation-attributes-irrelevant.txt +++ b/Tests/LibWeb/Text/expected/wpt-import/svg/styling/presentation-attributes-irrelevant.txt @@ -1,9 +1,9 @@ Harness status: OK -Found 43 tests +Found 45 tests -39 Pass -4 Fail +42 Pass +3 Fail Pass clip-path presentation attribute supported on an irrelevant element Pass clip-rule presentation attribute supported on an irrelevant element Pass color presentation attribute supported on an irrelevant element @@ -13,7 +13,9 @@ Pass display presentation attribute supported on an irrelevant element Pass fill presentation attribute supported on an irrelevant element Pass fill-opacity presentation attribute supported on an irrelevant element Pass fill-rule presentation attribute supported on an irrelevant element -Fail filter presentation attribute supported on an irrelevant element +Pass filter presentation attribute supported on an irrelevant element +Pass flood-color presentation attribute supported on an irrelevant element +Pass flood-opacity presentation attribute supported on an irrelevant element Pass font-family presentation attribute supported on an irrelevant element Pass font-size presentation attribute supported on an irrelevant element Fail font-stretch presentation attribute supported on an irrelevant element diff --git a/Tests/LibWeb/Text/expected/wpt-import/svg/styling/presentation-attributes-relevant.txt b/Tests/LibWeb/Text/expected/wpt-import/svg/styling/presentation-attributes-relevant.txt index 1737cbbb440..fddc6f55837 100644 --- a/Tests/LibWeb/Text/expected/wpt-import/svg/styling/presentation-attributes-relevant.txt +++ b/Tests/LibWeb/Text/expected/wpt-import/svg/styling/presentation-attributes-relevant.txt @@ -1,9 +1,9 @@ Harness status: OK -Found 53 tests +Found 55 tests -48 Pass -5 Fail +51 Pass +4 Fail Pass clip-path presentation attribute supported on a relevant element Pass clip-rule presentation attribute supported on a relevant element Pass color presentation attribute supported on a relevant element @@ -15,7 +15,9 @@ Pass display presentation attribute supported on a relevant element Pass fill presentation attribute supported on a relevant element Pass fill-opacity presentation attribute supported on a relevant element Pass fill-rule presentation attribute supported on a relevant element -Fail filter presentation attribute supported on a relevant element +Pass filter presentation attribute supported on a relevant element +Pass flood-color presentation attribute supported on a relevant element +Pass flood-opacity presentation attribute supported on a relevant element Pass font-family presentation attribute supported on a relevant element Pass font-size presentation attribute supported on a relevant element Fail font-stretch presentation attribute supported on a relevant element diff --git a/Tests/LibWeb/Text/expected/wpt-import/svg/styling/presentation-attributes-unknown.txt b/Tests/LibWeb/Text/expected/wpt-import/svg/styling/presentation-attributes-unknown.txt index f460234d5a0..69d33a73197 100644 --- a/Tests/LibWeb/Text/expected/wpt-import/svg/styling/presentation-attributes-unknown.txt +++ b/Tests/LibWeb/Text/expected/wpt-import/svg/styling/presentation-attributes-unknown.txt @@ -1,9 +1,9 @@ Harness status: OK -Found 43 tests +Found 45 tests -39 Pass -4 Fail +42 Pass +3 Fail Pass clip-path presentation attribute supported on an unknown SVG element Pass clip-rule presentation attribute supported on an unknown SVG element Pass color presentation attribute supported on an unknown SVG element @@ -13,7 +13,9 @@ Pass display presentation attribute supported on an unknown SVG element Pass fill presentation attribute supported on an unknown SVG element Pass fill-opacity presentation attribute supported on an unknown SVG element Pass fill-rule presentation attribute supported on an unknown SVG element -Fail filter presentation attribute supported on an unknown SVG element +Pass filter presentation attribute supported on an unknown SVG element +Pass flood-color presentation attribute supported on an unknown SVG element +Pass flood-opacity presentation attribute supported on an unknown SVG element Pass font-family presentation attribute supported on an unknown SVG element Pass font-size presentation attribute supported on an unknown SVG element Fail font-stretch presentation attribute supported on an unknown SVG element