diff --git a/Userland/Libraries/LibWeb/CSS/ComputedValues.h b/Userland/Libraries/LibWeb/CSS/ComputedValues.h index 21ec32f74a..c274ce49f6 100644 --- a/Userland/Libraries/LibWeb/CSS/ComputedValues.h +++ b/Userland/Libraries/LibWeb/CSS/ComputedValues.h @@ -47,6 +47,34 @@ struct QuotesData { Vector> strings {}; }; +struct ResolvedBackdropFilter { + struct Blur { + float radius; + }; + + struct DropShadow { + double offset_x; + double offset_y; + double radius; + Color color; + }; + + struct HueRotate { + float angle_degrees; + }; + + struct ColorOperation { + Filter::Color::Operation operation; + float amount; + }; + + using FilterFunction = Variant; + + bool is_none() const { return filters.size() == 0; } + + Vector filters; +}; + class InitialValues { public: static AspectRatio aspect_ratio() { return AspectRatio { true, {} }; } @@ -71,7 +99,7 @@ public: static CSS::Display display() { return CSS::Display { CSS::DisplayOutside::Inline, CSS::DisplayInside::Flow }; } static Color color() { return Color::Black; } static Color stop_color() { return Color::Black; } - static CSS::BackdropFilter backdrop_filter() { return BackdropFilter::make_none(); } + static CSS::ResolvedBackdropFilter backdrop_filter() { return ResolvedBackdropFilter { .filters = {} }; } static Color background_color() { return Color::Transparent; } static CSS::ListStyleType list_style_type() { return CSS::ListStyleType::Disc; } static CSS::ListStylePosition list_style_position() { return CSS::ListStylePosition::Outside; } @@ -302,7 +330,7 @@ public: CSS::JustifyContent justify_content() const { return m_noninherited.justify_content; } CSS::JustifySelf justify_self() const { return m_noninherited.justify_self; } CSS::JustifyItems justify_items() const { return m_noninherited.justify_items; } - CSS::BackdropFilter const& backdrop_filter() const { return m_noninherited.backdrop_filter; } + CSS::ResolvedBackdropFilter const& backdrop_filter() const { return m_noninherited.backdrop_filter; } Vector const& box_shadow() const { return m_noninherited.box_shadow; } CSS::BoxSizing box_sizing() const { return m_noninherited.box_sizing; } CSS::Size const& width() const { return m_noninherited.width; } @@ -452,7 +480,7 @@ protected: CSS::LengthBox inset { InitialValues::inset() }; CSS::LengthBox margin { InitialValues::margin() }; CSS::LengthBox padding { InitialValues::padding() }; - CSS::BackdropFilter backdrop_filter { InitialValues::backdrop_filter() }; + CSS::ResolvedBackdropFilter backdrop_filter { InitialValues::backdrop_filter() }; BorderData border_left; BorderData border_top; BorderData border_right; @@ -565,7 +593,7 @@ public: void set_list_style_type(CSS::ListStyleType value) { m_inherited.list_style_type = value; } void set_list_style_position(CSS::ListStylePosition value) { m_inherited.list_style_position = value; } void set_display(CSS::Display value) { m_noninherited.display = value; } - void set_backdrop_filter(CSS::BackdropFilter backdrop_filter) { m_noninherited.backdrop_filter = move(backdrop_filter); } + void set_backdrop_filter(CSS::ResolvedBackdropFilter backdrop_filter) { m_noninherited.backdrop_filter = move(backdrop_filter); } void set_border_bottom_left_radius(CSS::BorderRadiusData value) { m_noninherited.border_bottom_left_radius = move(value); } void set_border_bottom_right_radius(CSS::BorderRadiusData value) { m_noninherited.border_bottom_right_radius = move(value); } void set_border_top_left_radius(CSS::BorderRadiusData value) { m_noninherited.border_top_left_radius = move(value); } diff --git a/Userland/Libraries/LibWeb/CSS/StyleValues/FilterValueListStyleValue.cpp b/Userland/Libraries/LibWeb/CSS/StyleValues/FilterValueListStyleValue.cpp index b877129cc8..9c5b8d42e3 100644 --- a/Userland/Libraries/LibWeb/CSS/StyleValues/FilterValueListStyleValue.cpp +++ b/Userland/Libraries/LibWeb/CSS/StyleValues/FilterValueListStyleValue.cpp @@ -23,18 +23,6 @@ float Filter::Blur::resolved_radius(Layout::Node const& node) const return sigma * 2; } -Filter::DropShadow::Resolved Filter::DropShadow::resolved(Layout::Node const& node) const -{ - // The default value for omitted values is missing length values set to 0 - // and the missing used color is taken from the color property. - return Resolved { - offset_x.to_px(node).to_double(), - offset_y.to_px(node).to_double(), - radius.has_value() ? radius->to_px(node).to_double() : 0.0, - color.has_value() ? *color : node.computed_values().color() - }; -} - float Filter::HueRotate::angle_degrees() const { // Default value when omitted is 0deg. diff --git a/Userland/Libraries/LibWeb/CSS/StyleValues/FilterValueListStyleValue.h b/Userland/Libraries/LibWeb/CSS/StyleValues/FilterValueListStyleValue.h index 8d65b2e699..8d7e96a6ca 100644 --- a/Userland/Libraries/LibWeb/CSS/StyleValues/FilterValueListStyleValue.h +++ b/Userland/Libraries/LibWeb/CSS/StyleValues/FilterValueListStyleValue.h @@ -29,13 +29,6 @@ struct DropShadow { Length offset_y; Optional radius {}; Optional color {}; - struct Resolved { - double offset_x; - double offset_y; - double radius; - Color color; - }; - Resolved resolved(Layout::Node const&) const; bool operator==(DropShadow const&) const = default; }; diff --git a/Userland/Libraries/LibWeb/Layout/Node.cpp b/Userland/Libraries/LibWeb/Layout/Node.cpp index aff4b62ea6..0b5de0ea3e 100644 --- a/Userland/Libraries/LibWeb/Layout/Node.cpp +++ b/Userland/Libraries/LibWeb/Layout/Node.cpp @@ -537,7 +537,35 @@ void NodeWithStyle::apply_style(const CSS::StyleProperties& computed_style) computed_values.set_flex_shrink(computed_style.flex_shrink()); computed_values.set_order(computed_style.order()); computed_values.set_clip(computed_style.clip()); - computed_values.set_backdrop_filter(computed_style.backdrop_filter()); + + if (computed_style.backdrop_filter().has_filters()) { + CSS::ResolvedBackdropFilter resolved_backdrop_filter; + for (auto& filter : computed_style.backdrop_filter().filters()) { + filter.visit( + [&](CSS::Filter::Blur const& blur) { + resolved_backdrop_filter.filters.append(CSS::ResolvedBackdropFilter::Blur { + .radius = blur.resolved_radius(*this) }); + }, + [&](CSS::Filter::DropShadow const& drop_shadow) { + // The default value for omitted values is missing length values set to 0 + // and the missing used color is taken from the color property. + resolved_backdrop_filter.filters.append(CSS::ResolvedBackdropFilter::DropShadow { + .offset_x = drop_shadow.offset_x.to_px(*this).to_double(), + .offset_y = drop_shadow.offset_y.to_px(*this).to_double(), + .radius = drop_shadow.radius.has_value() ? drop_shadow.radius->to_px(*this).to_double() : 0.0, + .color = drop_shadow.color.has_value() ? *drop_shadow.color : this->computed_values().color() }); + }, + [&](CSS::Filter::Color const& color_operation) { + resolved_backdrop_filter.filters.append(CSS::ResolvedBackdropFilter::ColorOperation { + .operation = color_operation.operation, + .amount = color_operation.resolved_amount() }); + }, + [&](CSS::Filter::HueRotate const& hue_rotate) { + resolved_backdrop_filter.filters.append(CSS::ResolvedBackdropFilter::HueRotate { .angle_degrees = hue_rotate.angle_degrees() }); + }); + } + computed_values.set_backdrop_filter(resolved_backdrop_filter); + } auto justify_content = computed_style.justify_content(); if (justify_content.has_value()) diff --git a/Userland/Libraries/LibWeb/Painting/FilterPainting.cpp b/Userland/Libraries/LibWeb/Painting/FilterPainting.cpp index 4b568fdb68..07912b5f47 100644 --- a/Userland/Libraries/LibWeb/Painting/FilterPainting.cpp +++ b/Userland/Libraries/LibWeb/Painting/FilterPainting.cpp @@ -19,7 +19,7 @@ namespace Web::Painting { -void apply_filter_list(Gfx::Bitmap& target_bitmap, Layout::Node const& node, ReadonlySpan filter_list) +void apply_filter_list(Gfx::Bitmap& target_bitmap, ReadonlySpan filter_list) { auto apply_color_filter = [&](Gfx::ColorFilter const& filter) { const_cast(filter).apply(target_bitmap, target_bitmap.rect(), target_bitmap, target_bitmap.rect()); @@ -27,14 +27,14 @@ void apply_filter_list(Gfx::Bitmap& target_bitmap, Layout::Node const& node, Rea for (auto& filter_function : filter_list) { // See: https://drafts.fxtf.org/filter-effects-1/#supported-filter-functions filter_function.visit( - [&](CSS::Filter::Blur const& blur) { + [&](CSS::ResolvedBackdropFilter::Blur const& blur_filter) { // Applies a Gaussian blur to the input image. // The passed parameter defines the value of the standard deviation to the Gaussian function. Gfx::StackBlurFilter filter { target_bitmap }; - filter.process_rgba(blur.resolved_radius(node), Color::Transparent); + filter.process_rgba(blur_filter.radius, Color::Transparent); }, - [&](CSS::Filter::Color const& color) { - auto amount = color.resolved_amount(); + [&](CSS::ResolvedBackdropFilter::ColorOperation const& color) { + auto amount = color.amount; auto amount_clamped = clamp(amount, 0.0f, 1.0f); switch (color.operation) { case CSS::Filter::Color::Operation::Grayscale: { @@ -86,19 +86,19 @@ void apply_filter_list(Gfx::Bitmap& target_bitmap, Layout::Node const& node, Rea break; } }, - [&](CSS::Filter::HueRotate const& hue_rotate) { + [&](CSS::ResolvedBackdropFilter::HueRotate const& hue_rotate) { // Applies a hue rotation on the input image. // The passed parameter defines the number of degrees around the color circle the input samples will be adjusted. // A value of 0deg leaves the input unchanged. Implementations must not normalize this value in order to allow animations beyond 360deg. - apply_color_filter(Gfx::HueRotateFilter { hue_rotate.angle_degrees() }); + apply_color_filter(Gfx::HueRotateFilter { hue_rotate.angle_degrees }); }, - [&](CSS::Filter::DropShadow const&) { + [&](CSS::ResolvedBackdropFilter::DropShadow const&) { dbgln("TODO: Implement drop-shadow() filter function!"); }); } } -void apply_backdrop_filter(PaintContext& context, Layout::Node const& node, CSSPixelRect const& backdrop_rect, BorderRadiiData const& border_radii_data, CSS::BackdropFilter const& backdrop_filter) +void apply_backdrop_filter(PaintContext& context, CSSPixelRect const& backdrop_rect, BorderRadiiData const& border_radii_data, CSS::ResolvedBackdropFilter const& backdrop_filter) { // This performs the backdrop filter operation: https://drafts.fxtf.org/filter-effects-2/#backdrop-filter-operation @@ -121,7 +121,7 @@ void apply_backdrop_filter(PaintContext& context, Layout::Node const& node, CSSP } auto backdrop_bitmap = maybe_backdrop_bitmap.release_value(); // 2. Apply the backdrop-filter’s filter operations to the entire contents of T'. - apply_filter_list(*backdrop_bitmap, node, backdrop_filter.filters()); + apply_filter_list(*backdrop_bitmap, backdrop_filter.filters); // FIXME: 3. If element B has any transforms (between B and the Backdrop Root), apply the inverse of those transforms to the contents of T’. diff --git a/Userland/Libraries/LibWeb/Painting/FilterPainting.h b/Userland/Libraries/LibWeb/Painting/FilterPainting.h index 71867f14de..4f5e4b2865 100644 --- a/Userland/Libraries/LibWeb/Painting/FilterPainting.h +++ b/Userland/Libraries/LibWeb/Painting/FilterPainting.h @@ -12,8 +12,8 @@ namespace Web::Painting { -void apply_filter_list(Gfx::Bitmap& target_bitmap, Layout::Node const& node, ReadonlySpan filter_list); +void apply_filter_list(Gfx::Bitmap& target_bitmap, ReadonlySpan filter_list); -void apply_backdrop_filter(PaintContext&, Layout::Node const&, CSSPixelRect const&, BorderRadiiData const&, CSS::BackdropFilter const&); +void apply_backdrop_filter(PaintContext&, CSSPixelRect const&, BorderRadiiData const&, CSS::ResolvedBackdropFilter const&); } diff --git a/Userland/Libraries/LibWeb/Painting/PaintableBox.cpp b/Userland/Libraries/LibWeb/Painting/PaintableBox.cpp index a5925deb31..f5017692c4 100644 --- a/Userland/Libraries/LibWeb/Painting/PaintableBox.cpp +++ b/Userland/Libraries/LibWeb/Painting/PaintableBox.cpp @@ -325,7 +325,7 @@ void PaintableBox::paint_backdrop_filter(PaintContext& context) const { auto& backdrop_filter = computed_values().backdrop_filter(); if (!backdrop_filter.is_none()) - apply_backdrop_filter(context, layout_node(), absolute_border_box_rect(), normalized_border_radii_data(), backdrop_filter); + apply_backdrop_filter(context, absolute_border_box_rect(), normalized_border_radii_data(), backdrop_filter); } void PaintableBox::paint_background(PaintContext& context) const