LibWeb/SVG: Add FEFloodElement

This commit is contained in:
Lucien Fiorini 2025-07-06 21:48:55 +02:00 committed by Sam Atkins
commit d3684a36b0
Notes: github-actions[bot] 2025-07-09 17:08:44 +00:00
22 changed files with 189 additions and 18 deletions

View file

@ -823,6 +823,7 @@ set(SOURCES
SVG/SVGDescElement.cpp SVG/SVGDescElement.cpp
SVG/SVGElement.cpp SVG/SVGElement.cpp
SVG/SVGEllipseElement.cpp SVG/SVGEllipseElement.cpp
SVG/SVGFEFloodElement.cpp
SVG/SVGFilterElement.cpp SVG/SVGFilterElement.cpp
SVG/SVGForeignObjectElement.cpp SVG/SVGForeignObjectElement.cpp
SVG/SVGGElement.cpp SVG/SVGGElement.cpp

View file

@ -443,6 +443,22 @@ ClipRule ComputedProperties::clip_rule() const
return keyword_to_fill_rule(value.to_keyword()).release_value(); 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 FlexDirection ComputedProperties::flex_direction() const
{ {
auto const& value = property(PropertyID::FlexDirection); auto const& value = property(PropertyID::FlexDirection);

View file

@ -194,6 +194,8 @@ public:
float stroke_opacity() const; float stroke_opacity() const;
FillRule fill_rule() const; FillRule fill_rule() const;
ClipRule clip_rule() const; ClipRule clip_rule() const;
Color flood_color(Layout::NodeWithStyle const&) const;
float flood_opacity() const;
Gfx::FontCascadeList const& computed_font_list() const Gfx::FontCascadeList const& computed_font_list() const
{ {

View file

@ -152,6 +152,8 @@ public:
static float fill_opacity() { return 1.0f; } static float fill_opacity() { return 1.0f; }
static CSS::FillRule fill_rule() { return CSS::FillRule::Nonzero; } static CSS::FillRule fill_rule() { return CSS::FillRule::Nonzero; }
static CSS::ClipRule clip_rule() { return CSS::ClipRule::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::LengthPercentage stroke_dashoffset() { return CSS::Length::make_px(0); }
static CSS::StrokeLinecap stroke_linecap() { return CSS::StrokeLinecap::Butt; } static CSS::StrokeLinecap stroke_linecap() { return CSS::StrokeLinecap::Butt; }
static CSS::StrokeLinejoin stroke_linejoin() { return CSS::StrokeLinejoin::Miter; } static CSS::StrokeLinejoin stroke_linejoin() { return CSS::StrokeLinejoin::Miter; }
@ -554,6 +556,8 @@ public:
CSS::MaskType mask_type() const { return m_noninherited.mask_type; } CSS::MaskType mask_type() const { return m_noninherited.mask_type; }
Optional<ClipPathReference> const& clip_path() const { return m_noninherited.clip_path; } Optional<ClipPathReference> const& clip_path() const { return m_noninherited.clip_path; }
CSS::ClipRule clip_rule() const { return m_inherited.clip_rule; } 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& cx() const { return m_noninherited.cx; }
LengthPercentage const& cy() const { return m_noninherited.cy; } LengthPercentage const& cy() const { return m_noninherited.cy; }
@ -796,6 +800,9 @@ protected:
Vector<CounterData, 0> counter_increment; Vector<CounterData, 0> counter_increment;
Vector<CounterData, 0> counter_reset; Vector<CounterData, 0> counter_reset;
Vector<CounterData, 0> counter_set; Vector<CounterData, 0> counter_set;
Color flood_color { InitialValues::flood_color() };
float flood_opacity { InitialValues::flood_opacity() };
} m_noninherited; } m_noninherited;
}; };
@ -982,6 +989,8 @@ public:
void set_mask_image(CSS::AbstractImageStyleValue const& value) { m_noninherited.mask_image = value; } 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_path(ClipPathReference value) { m_noninherited.clip_path = move(value); }
void set_clip_rule(CSS::ClipRule value) { m_inherited.clip_rule = 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_cx(LengthPercentage cx) { m_noninherited.cx = move(cx); }
void set_cy(LengthPercentage cy) { m_noninherited.cy = move(cy); } void set_cy(LengthPercentage cy) { m_noninherited.cy = move(cy); }

View file

@ -1537,6 +1537,24 @@
"float" "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": { "font": {
"inherited": true, "inherited": true,
"initial": "normal medium serif", "initial": "normal medium serif",

View file

@ -91,6 +91,7 @@
#include <LibWeb/SVG/SVGDefsElement.h> #include <LibWeb/SVG/SVGDefsElement.h>
#include <LibWeb/SVG/SVGDescElement.h> #include <LibWeb/SVG/SVGDescElement.h>
#include <LibWeb/SVG/SVGEllipseElement.h> #include <LibWeb/SVG/SVGEllipseElement.h>
#include <LibWeb/SVG/SVGFEFloodElement.h>
#include <LibWeb/SVG/SVGFilterElement.h> #include <LibWeb/SVG/SVGFilterElement.h>
#include <LibWeb/SVG/SVGForeignObjectElement.h> #include <LibWeb/SVG/SVGForeignObjectElement.h>
#include <LibWeb/SVG/SVGGElement.h> #include <LibWeb/SVG/SVGGElement.h>
@ -461,6 +462,8 @@ static GC::Ref<SVG::SVGElement> create_svg_element(JS::Realm& realm, Document& d
return realm.create<SVG::SVGDescElement>(document, move(qualified_name)); return realm.create<SVG::SVGDescElement>(document, move(qualified_name));
if (local_name == SVG::TagNames::ellipse) if (local_name == SVG::TagNames::ellipse)
return realm.create<SVG::SVGEllipseElement>(document, move(qualified_name)); return realm.create<SVG::SVGEllipseElement>(document, move(qualified_name));
if (local_name == SVG::TagNames::feFlood)
return realm.create<SVG::SVGFEFloodElement>(document, move(qualified_name));
if (local_name == SVG::TagNames::filter) if (local_name == SVG::TagNames::filter)
return realm.create<SVG::SVGFilterElement>(document, move(qualified_name)); return realm.create<SVG::SVGFilterElement>(document, move(qualified_name));
if (local_name.equals_ignoring_ascii_case(SVG::TagNames::foreignObject)) if (local_name.equals_ignoring_ascii_case(SVG::TagNames::foreignObject))

View file

@ -967,6 +967,7 @@ class SVGDefsElement;
class SVGDescElement; class SVGDescElement;
class SVGElement; class SVGElement;
class SVGEllipseElement; class SVGEllipseElement;
class SVGFEFloodElement;
class SVGFilterElement; class SVGFilterElement;
class SVGForeignObjectElement; class SVGForeignObjectElement;
class SVGGeometryElement; class SVGGeometryElement;

View file

@ -61,6 +61,9 @@ static ReadonlySpan<NamedPropertyID> attribute_style_properties()
NamedPropertyID(CSS::PropertyID::Display), NamedPropertyID(CSS::PropertyID::Display),
NamedPropertyID(CSS::PropertyID::FillOpacity), NamedPropertyID(CSS::PropertyID::FillOpacity),
NamedPropertyID(CSS::PropertyID::FillRule), NamedPropertyID(CSS::PropertyID::FillRule),
NamedPropertyID(CSS::PropertyID::Filter),
NamedPropertyID(CSS::PropertyID::FloodColor),
NamedPropertyID(CSS::PropertyID::FloodOpacity),
NamedPropertyID(CSS::PropertyID::FontFamily), NamedPropertyID(CSS::PropertyID::FontFamily),
NamedPropertyID(CSS::PropertyID::FontSize), NamedPropertyID(CSS::PropertyID::FontSize),
NamedPropertyID(CSS::PropertyID::FontStyle), NamedPropertyID(CSS::PropertyID::FontStyle),

View file

@ -29,6 +29,8 @@ public:
bool should_include_in_accessibility_tree() const; bool should_include_in_accessibility_tree() const;
virtual Optional<ARIA::Role> default_role() const override; virtual Optional<ARIA::Role> default_role() const override;
GC::Ref<SVGAnimatedLength> svg_animated_length_for_property(CSS::PropertyID) const;
virtual bool is_presentational_hint(FlyString const&) const override; virtual bool is_presentational_hint(FlyString const&) const override;
virtual void apply_presentational_hints(GC::Ref<CSS::CascadedProperties>) const override; virtual void apply_presentational_hints(GC::Ref<CSS::CascadedProperties>) const override;
@ -47,8 +49,6 @@ protected:
void update_use_elements_that_reference_this(); void update_use_elements_that_reference_this();
void remove_from_use_element_that_reference_this(); void remove_from_use_element_that_reference_this();
GC::Ref<SVGAnimatedLength> svg_animated_length_for_property(CSS::PropertyID) const;
private: private:
// ^HTML::GlobalEventHandlers // ^HTML::GlobalEventHandlers
virtual GC::Ptr<DOM::EventTarget> global_event_handlers_to_event_target(FlyString const&) override { return *this; } virtual GC::Ptr<DOM::EventTarget> global_event_handlers_to_event_target(FlyString const&) override { return *this; }

View file

@ -0,0 +1,54 @@
/*
* Copyright (c) 2025, Lucien Fiorini <lucienfiorini@gmail.com>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <LibWeb/Bindings/SVGFEFloodElementPrototype.h>
#include <LibWeb/CSS/ComputedProperties.h>
#include <LibWeb/CSS/Parser/Parser.h>
#include <LibWeb/Layout/Node.h>
#include <LibWeb/Layout/SVGGraphicsBox.h>
#include <LibWeb/SVG/SVGFEFloodElement.h>
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<Layout::Node> SVGFEFloodElement::create_layout_node(GC::Ref<CSS::ComputedProperties> style)
{
return heap().allocate<Layout::SVGBox>(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();
}
}

View file

@ -0,0 +1,36 @@
/*
* Copyright (c) 2025, Lucien Fiorini <lucienfiorini@gmail.com>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <LibWeb/SVG/SVGAnimatedLength.h>
#include <LibWeb/SVG/SVGElement.h>
#include <LibWeb/SVG/SVGFilterPrimitiveStandardAttributes.h>
namespace Web::SVG {
class SVGFEFloodElement final
: public SVGElement
, public SVGFilterPrimitiveStandardAttributes<SVGFEFloodElement> {
WEB_PLATFORM_OBJECT(SVGFEFloodElement, SVGElement);
GC_DECLARE_ALLOCATOR(SVGFEFloodElement);
public:
virtual ~SVGFEFloodElement() override = default;
virtual GC::Ptr<Layout::Node> create_layout_node(GC::Ref<CSS::ComputedProperties>) 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;
};
}

View file

@ -0,0 +1,8 @@
#import <SVG/SVGFilterPrimitiveStandardAttributes.idl>
// https://www.w3.org/TR/filter-effects-1/#InterfaceSVGFEFloodElement
[Exposed=Window]
interface SVGFEFloodElement : SVGElement {
};
SVGFEFloodElement includes SVGFilterPrimitiveStandardAttributes;

View file

@ -17,6 +17,7 @@ namespace Web::SVG::TagNames {
__ENUMERATE_SVG_TAG(defs) \ __ENUMERATE_SVG_TAG(defs) \
__ENUMERATE_SVG_TAG(desc) \ __ENUMERATE_SVG_TAG(desc) \
__ENUMERATE_SVG_TAG(ellipse) \ __ENUMERATE_SVG_TAG(ellipse) \
__ENUMERATE_SVG_TAG(feFlood) \
__ENUMERATE_SVG_TAG(filter) \ __ENUMERATE_SVG_TAG(filter) \
__ENUMERATE_SVG_TAG(foreignObject) \ __ENUMERATE_SVG_TAG(foreignObject) \
__ENUMERATE_SVG_TAG(g) \ __ENUMERATE_SVG_TAG(g) \

View file

@ -340,6 +340,7 @@ libweb_js_bindings(SVG/SVGGraphicsElement)
libweb_js_bindings(SVG/SVGImageElement) libweb_js_bindings(SVG/SVGImageElement)
libweb_js_bindings(SVG/SVGCircleElement) libweb_js_bindings(SVG/SVGCircleElement)
libweb_js_bindings(SVG/SVGEllipseElement) libweb_js_bindings(SVG/SVGEllipseElement)
libweb_js_bindings(SVG/SVGFEFloodElement)
libweb_js_bindings(SVG/SVGFilterElement) libweb_js_bindings(SVG/SVGFilterElement)
libweb_js_bindings(SVG/SVGForeignObjectElement) libweb_js_bindings(SVG/SVGForeignObjectElement)
libweb_js_bindings(SVG/SVGLength) libweb_js_bindings(SVG/SVGLength)

View file

@ -338,6 +338,7 @@ SVGDefsElement
SVGDescElement SVGDescElement
SVGElement SVGElement
SVGEllipseElement SVGEllipseElement
SVGFEFloodElement
SVGFilterElement SVGFilterElement
SVGForeignObjectElement SVGForeignObjectElement
SVGGElement SVGGElement

View file

@ -155,6 +155,8 @@ All properties associated with getComputedStyle(document.body):
"flex-shrink", "flex-shrink",
"flex-wrap", "flex-wrap",
"float", "float",
"flood-color",
"flood-opacity",
"grid-auto-columns", "grid-auto-columns",
"grid-auto-flow", "grid-auto-flow",
"grid-auto-rows", "grid-auto-rows",

View file

@ -385,6 +385,10 @@ All supported properties and their default values exposed from CSSStylePropertie
'flexWrap': 'nowrap' 'flexWrap': 'nowrap'
'flex-wrap': 'nowrap' 'flex-wrap': 'nowrap'
'float': 'none' 'float': 'none'
'floodColor': 'rgb(0, 0, 0)'
'flood-color': 'rgb(0, 0, 0)'
'floodOpacity': '1'
'flood-opacity': '1'
'font': '16px serif' 'font': '16px serif'
'fontFamily': 'serif' 'fontFamily': 'serif'
'font-family': 'serif' 'font-family': 'serif'

View file

@ -153,6 +153,8 @@ flex-grow: 0
flex-shrink: 1 flex-shrink: 1
flex-wrap: nowrap flex-wrap: nowrap
float: none float: none
flood-color: rgb(0, 0, 0)
flood-opacity: 1
grid-auto-columns: auto grid-auto-columns: auto
grid-auto-flow: row grid-auto-flow: row
grid-auto-rows: auto grid-auto-rows: auto
@ -163,7 +165,7 @@ grid-row-start: auto
grid-template-areas: none grid-template-areas: none
grid-template-columns: none grid-template-columns: none
grid-template-rows: none grid-template-rows: none
height: 2475px height: 2505px
inline-size: 784px inline-size: 784px
inset-block-end: auto inset-block-end: auto
inset-block-start: auto inset-block-start: auto

View file

@ -1,9 +1,9 @@
Harness status: OK Harness status: OK
Found 245 tests Found 248 tests
239 Pass 241 Pass
6 Fail 7 Fail
Pass accent-color Pass accent-color
Pass border-collapse Pass border-collapse
Pass border-spacing Pass border-spacing
@ -147,12 +147,15 @@ Pass counter-set
Pass cx Pass cx
Pass cy Pass cy
Pass display Pass display
Fail filter
Pass flex-basis Pass flex-basis
Pass flex-direction Pass flex-direction
Pass flex-grow Pass flex-grow
Pass flex-shrink Pass flex-shrink
Pass flex-wrap Pass flex-wrap
Pass float Pass float
Pass flood-color
Pass flood-opacity
Pass grid-auto-columns Pass grid-auto-columns
Pass grid-auto-flow Pass grid-auto-flow
Pass grid-auto-rows Pass grid-auto-rows

View file

@ -1,9 +1,9 @@
Harness status: OK Harness status: OK
Found 43 tests Found 45 tests
39 Pass 42 Pass
4 Fail 3 Fail
Pass clip-path presentation attribute supported on an irrelevant element Pass clip-path presentation attribute supported on an irrelevant element
Pass clip-rule 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 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 presentation attribute supported on an irrelevant element
Pass fill-opacity 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 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-family presentation attribute supported on an irrelevant element
Pass font-size 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 Fail font-stretch presentation attribute supported on an irrelevant element

View file

@ -1,9 +1,9 @@
Harness status: OK Harness status: OK
Found 53 tests Found 55 tests
48 Pass 51 Pass
5 Fail 4 Fail
Pass clip-path presentation attribute supported on a relevant element Pass clip-path presentation attribute supported on a relevant element
Pass clip-rule 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 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 presentation attribute supported on a relevant element
Pass fill-opacity 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 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-family presentation attribute supported on a relevant element
Pass font-size 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 Fail font-stretch presentation attribute supported on a relevant element

View file

@ -1,9 +1,9 @@
Harness status: OK Harness status: OK
Found 43 tests Found 45 tests
39 Pass 42 Pass
4 Fail 3 Fail
Pass clip-path presentation attribute supported on an unknown SVG element Pass clip-path presentation attribute supported on an unknown SVG element
Pass clip-rule 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 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 presentation attribute supported on an unknown SVG element
Pass fill-opacity 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 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-family presentation attribute supported on an unknown SVG element
Pass font-size 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 Fail font-stretch presentation attribute supported on an unknown SVG element