LibWeb: Parse and store filter property

This shares its implementation with `backdrop-filter`.
This commit is contained in:
Jelle Raaijmakers 2024-10-25 11:00:22 +02:00 committed by Andreas Kling
commit 29974de852
Notes: github-actions[bot] 2024-10-26 09:28:54 +00:00
14 changed files with 104 additions and 75 deletions

View file

@ -104,6 +104,7 @@ counter-set: none
cx: 0px cx: 0px
cy: 0px cy: 0px
display: block display: block
filter: none
flex-basis: auto flex-basis: auto
flex-direction: row flex-direction: row
flex-grow: 0 flex-grow: 0
@ -120,7 +121,7 @@ grid-row-start: auto
grid-template-areas: none grid-template-areas: none
grid-template-columns: auto grid-template-columns: auto
grid-template-rows: auto grid-template-rows: auto
height: 2074px height: 2091px
inline-size: auto inline-size: auto
inset-block-end: auto inset-block-end: auto
inset-block-start: auto inset-block-start: auto

View file

@ -11,12 +11,12 @@
#include <AK/Optional.h> #include <AK/Optional.h>
#include <LibGfx/FontCascadeList.h> #include <LibGfx/FontCascadeList.h>
#include <LibGfx/ScalingMode.h> #include <LibGfx/ScalingMode.h>
#include <LibWeb/CSS/BackdropFilter.h>
#include <LibWeb/CSS/CalculatedOr.h> #include <LibWeb/CSS/CalculatedOr.h>
#include <LibWeb/CSS/Clip.h> #include <LibWeb/CSS/Clip.h>
#include <LibWeb/CSS/ColumnCount.h> #include <LibWeb/CSS/ColumnCount.h>
#include <LibWeb/CSS/CountersSet.h> #include <LibWeb/CSS/CountersSet.h>
#include <LibWeb/CSS/Display.h> #include <LibWeb/CSS/Display.h>
#include <LibWeb/CSS/Filter.h>
#include <LibWeb/CSS/GridTrackPlacement.h> #include <LibWeb/CSS/GridTrackPlacement.h>
#include <LibWeb/CSS/GridTrackSize.h> #include <LibWeb/CSS/GridTrackSize.h>
#include <LibWeb/CSS/LengthBox.h> #include <LibWeb/CSS/LengthBox.h>
@ -55,7 +55,7 @@ struct QuotesData {
Vector<Array<FlyString, 2>> strings {}; Vector<Array<FlyString, 2>> strings {};
}; };
struct ResolvedBackdropFilter { struct ResolvedFilter {
struct Blur { struct Blur {
float radius; float radius;
}; };
@ -64,19 +64,19 @@ struct ResolvedBackdropFilter {
double offset_x; double offset_x;
double offset_y; double offset_y;
double radius; double radius;
Color color; Gfx::Color color;
}; };
struct HueRotate { struct HueRotate {
float angle_degrees; float angle_degrees;
}; };
struct ColorOperation { struct Color {
Filter::Color::Operation operation; FilterOperation::Color::Type type;
float amount; float amount;
}; };
using FilterFunction = Variant<Blur, DropShadow, HueRotate, ColorOperation>; using FilterFunction = Variant<Blur, DropShadow, HueRotate, Color>;
bool is_none() const { return filters.size() == 0; } bool is_none() const { return filters.size() == 0; }
@ -121,7 +121,8 @@ public:
static CSS::Display display() { return CSS::Display { CSS::DisplayOutside::Inline, CSS::DisplayInside::Flow }; } static CSS::Display display() { return CSS::Display { CSS::DisplayOutside::Inline, CSS::DisplayInside::Flow }; }
static Color color() { return Color::Black; } static Color color() { return Color::Black; }
static Color stop_color() { return Color::Black; } static Color stop_color() { return Color::Black; }
static CSS::ResolvedBackdropFilter backdrop_filter() { return ResolvedBackdropFilter { .filters = {} }; } static CSS::ResolvedFilter backdrop_filter() { return ResolvedFilter { .filters = {} }; }
static CSS::ResolvedFilter filter() { return ResolvedFilter { .filters = {} }; }
static Color background_color() { return Color::Transparent; } static Color background_color() { return Color::Transparent; }
static CSS::ListStyleType list_style_type() { return CSS::ListStyleType::Disc; } static CSS::ListStyleType list_style_type() { return CSS::ListStyleType::Disc; }
static CSS::ListStylePosition list_style_position() { return CSS::ListStylePosition::Outside; } static CSS::ListStylePosition list_style_position() { return CSS::ListStylePosition::Outside; }
@ -409,7 +410,8 @@ public:
CSS::JustifyContent justify_content() const { return m_noninherited.justify_content; } CSS::JustifyContent justify_content() const { return m_noninherited.justify_content; }
CSS::JustifySelf justify_self() const { return m_noninherited.justify_self; } CSS::JustifySelf justify_self() const { return m_noninherited.justify_self; }
CSS::JustifyItems justify_items() const { return m_noninherited.justify_items; } CSS::JustifyItems justify_items() const { return m_noninherited.justify_items; }
CSS::ResolvedBackdropFilter const& backdrop_filter() const { return m_noninherited.backdrop_filter; } CSS::ResolvedFilter const& backdrop_filter() const { return m_noninherited.backdrop_filter; }
CSS::ResolvedFilter const& filter() const { return m_noninherited.filter; }
Vector<ShadowData> const& box_shadow() const { return m_noninherited.box_shadow; } Vector<ShadowData> const& box_shadow() const { return m_noninherited.box_shadow; }
CSS::BoxSizing box_sizing() const { return m_noninherited.box_sizing; } CSS::BoxSizing box_sizing() const { return m_noninherited.box_sizing; }
CSS::Size const& width() const { return m_noninherited.width; } CSS::Size const& width() const { return m_noninherited.width; }
@ -601,7 +603,8 @@ protected:
CSS::LengthBox inset { InitialValues::inset() }; CSS::LengthBox inset { InitialValues::inset() };
CSS::LengthBox margin { InitialValues::margin() }; CSS::LengthBox margin { InitialValues::margin() };
CSS::LengthBox padding { InitialValues::padding() }; CSS::LengthBox padding { InitialValues::padding() };
CSS::ResolvedBackdropFilter backdrop_filter { InitialValues::backdrop_filter() }; CSS::ResolvedFilter backdrop_filter { InitialValues::backdrop_filter() };
CSS::ResolvedFilter filter { InitialValues::filter() };
BorderData border_left; BorderData border_left;
BorderData border_top; BorderData border_top;
BorderData border_right; BorderData border_right;
@ -746,7 +749,8 @@ public:
void set_list_style_type(CSS::ListStyleType value) { m_inherited.list_style_type = value; } 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_list_style_position(CSS::ListStylePosition value) { m_inherited.list_style_position = value; }
void set_display(CSS::Display value) { m_noninherited.display = value; } void set_display(CSS::Display value) { m_noninherited.display = value; }
void set_backdrop_filter(CSS::ResolvedBackdropFilter backdrop_filter) { m_noninherited.backdrop_filter = move(backdrop_filter); } void set_backdrop_filter(CSS::ResolvedFilter backdrop_filter) { m_noninherited.backdrop_filter = move(backdrop_filter); }
void set_filter(CSS::ResolvedFilter filter) { m_noninherited.filter = move(filter); }
void set_border_bottom_left_radius(CSS::BorderRadiusData value) { m_noninherited.border_bottom_left_radius = move(value); } 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_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); } void set_border_top_left_radius(CSS::BorderRadiusData value) { m_noninherited.border_top_left_radius = move(value); }

View file

@ -12,15 +12,15 @@
namespace Web::CSS { namespace Web::CSS {
class BackdropFilter { class Filter {
public: public:
BackdropFilter() = default; Filter() = default;
BackdropFilter(FilterValueListStyleValue const& filter_value_list) Filter(FilterValueListStyleValue const& filter_value_list)
: m_filter_value_list { filter_value_list } {}; : m_filter_value_list { filter_value_list } {};
static inline BackdropFilter make_none() static Filter make_none()
{ {
return BackdropFilter {}; return Filter {};
} }
bool has_filters() const { return m_filter_value_list; } bool has_filters() const { return m_filter_value_list; }

View file

@ -5156,7 +5156,7 @@ RefPtr<CSSStyleValue> Parser::parse_filter_value_list_value(TokenStream<Componen
auto filter_token_to_operation = [&](auto filter) { auto filter_token_to_operation = [&](auto filter) {
VERIFY(to_underlying(filter) < to_underlying(FilterToken::Blur)); VERIFY(to_underlying(filter) < to_underlying(FilterToken::Blur));
return static_cast<Filter::Color::Operation>(filter); return static_cast<FilterOperation::Color::Type>(filter);
}; };
auto parse_number_percentage = [&](auto& token) -> Optional<NumberPercentage> { auto parse_number_percentage = [&](auto& token) -> Optional<NumberPercentage> {
@ -5205,13 +5205,13 @@ RefPtr<CSSStyleValue> Parser::parse_filter_value_list_value(TokenStream<Componen
if (filter_token == FilterToken::Blur) { if (filter_token == FilterToken::Blur) {
// blur( <length>? ) // blur( <length>? )
if (!tokens.has_next_token()) if (!tokens.has_next_token())
return Filter::Blur {}; return FilterOperation::Blur {};
auto blur_radius = parse_length(tokens); auto blur_radius = parse_length(tokens);
tokens.discard_whitespace(); tokens.discard_whitespace();
if (!blur_radius.has_value()) if (!blur_radius.has_value())
return {}; return {};
// FIXME: Support calculated radius // FIXME: Support calculated radius
return if_no_more_tokens_return(Filter::Blur { blur_radius->value() }); return if_no_more_tokens_return(FilterOperation::Blur { blur_radius->value() });
} else if (filter_token == FilterToken::DropShadow) { } else if (filter_token == FilterToken::DropShadow) {
if (!tokens.has_next_token()) if (!tokens.has_next_token())
return {}; return {};
@ -5240,17 +5240,17 @@ RefPtr<CSSStyleValue> Parser::parse_filter_value_list_value(TokenStream<Componen
} }
} }
// FIXME: Support calculated offsets and radius // FIXME: Support calculated offsets and radius
return if_no_more_tokens_return(Filter::DropShadow { x_offset->value(), y_offset->value(), maybe_radius.map([](auto& it) { return it.value(); }), maybe_color->to_color({}) }); return if_no_more_tokens_return(FilterOperation::DropShadow { x_offset->value(), y_offset->value(), maybe_radius.map([](auto& it) { return it.value(); }), maybe_color->to_color({}) });
} else if (filter_token == FilterToken::HueRotate) { } else if (filter_token == FilterToken::HueRotate) {
// hue-rotate( [ <angle> | <zero> ]? ) // hue-rotate( [ <angle> | <zero> ]? )
if (!tokens.has_next_token()) if (!tokens.has_next_token())
return Filter::HueRotate {}; return FilterOperation::HueRotate {};
auto& token = tokens.consume_a_token(); auto& token = tokens.consume_a_token();
if (token.is(Token::Type::Number)) { if (token.is(Token::Type::Number)) {
// hue-rotate(0) // hue-rotate(0)
auto number = token.token().number(); auto number = token.token().number();
if (number.is_integer() && number.integer_value() == 0) if (number.is_integer() && number.integer_value() == 0)
return if_no_more_tokens_return(Filter::HueRotate { Filter::HueRotate::Zero {} }); return if_no_more_tokens_return(FilterOperation::HueRotate { FilterOperation::HueRotate::Zero {} });
return {}; return {};
} }
if (!token.is(Token::Type::Dimension)) if (!token.is(Token::Type::Dimension))
@ -5261,7 +5261,7 @@ RefPtr<CSSStyleValue> Parser::parse_filter_value_list_value(TokenStream<Componen
if (!angle_unit.has_value()) if (!angle_unit.has_value())
return {}; return {};
Angle angle { angle_value, angle_unit.release_value() }; Angle angle { angle_value, angle_unit.release_value() };
return if_no_more_tokens_return(Filter::HueRotate { angle }); return if_no_more_tokens_return(FilterOperation::HueRotate { angle });
} else { } else {
// Simple filters: // Simple filters:
// brightness( <number-percentage>? ) // brightness( <number-percentage>? )
@ -5272,11 +5272,11 @@ RefPtr<CSSStyleValue> Parser::parse_filter_value_list_value(TokenStream<Componen
// sepia( <number-percentage>? ) // sepia( <number-percentage>? )
// saturate( <number-percentage>? ) // saturate( <number-percentage>? )
if (!tokens.has_next_token()) if (!tokens.has_next_token())
return Filter::Color { filter_token_to_operation(filter_token) }; return FilterOperation::Color { filter_token_to_operation(filter_token) };
auto amount = parse_number_percentage(tokens.consume_a_token()); auto amount = parse_number_percentage(tokens.consume_a_token());
if (!amount.has_value()) if (!amount.has_value())
return {}; return {};
return if_no_more_tokens_return(Filter::Color { filter_token_to_operation(filter_token), *amount }); return if_no_more_tokens_return(FilterOperation::Color { filter_token_to_operation(filter_token), *amount });
} }
}; };
@ -7860,6 +7860,7 @@ Parser::ParseErrorOr<NonnullRefPtr<CSSStyleValue>> Parser::parse_css_value(Prope
return parsed_value.release_nonnull(); return parsed_value.release_nonnull();
return ParseError::SyntaxError; return ParseError::SyntaxError;
case PropertyID::BackdropFilter: case PropertyID::BackdropFilter:
case PropertyID::Filter:
if (auto parsed_value = parse_filter_value_list_value(tokens); parsed_value && !tokens.has_next_token()) if (auto parsed_value = parse_filter_value_list_value(tokens); parsed_value && !tokens.has_next_token())
return parsed_value.release_nonnull(); return parsed_value.release_nonnull();
return ParseError::SyntaxError; return ParseError::SyntaxError;

View file

@ -1065,6 +1065,16 @@
"fill-rule" "fill-rule"
] ]
}, },
"filter": {
"affects-layout": false,
"animation-type": "custom",
"inherited": false,
"initial": "none",
"__comment": "FIXME: List `filter-value-list` as a valid-type once it's generically supported.",
"valid-identifiers": [
"none"
]
},
"flex": { "flex": {
"inherited": false, "inherited": false,
"initial": "0 1 auto", "initial": "0 1 auto",

View file

@ -613,12 +613,20 @@ Optional<CSS::Appearance> StyleProperties::appearance() const
return appearance; return appearance;
} }
CSS::BackdropFilter StyleProperties::backdrop_filter() const CSS::Filter StyleProperties::backdrop_filter() const
{ {
auto value = property(CSS::PropertyID::BackdropFilter); auto value = property(CSS::PropertyID::BackdropFilter);
if (value->is_filter_value_list()) if (value->is_filter_value_list())
return BackdropFilter(value->as_filter_value_list()); return Filter(value->as_filter_value_list());
return BackdropFilter::make_none(); return Filter::make_none();
}
CSS::Filter StyleProperties::filter() const
{
auto value = property(CSS::PropertyID::Filter);
if (value->is_filter_value_list())
return Filter(value->as_filter_value_list());
return Filter::make_none();
} }
Optional<CSS::Positioning> StyleProperties::position() const Optional<CSS::Positioning> StyleProperties::position() const

View file

@ -137,7 +137,8 @@ public:
Optional<CSS::AlignItems> align_items() const; Optional<CSS::AlignItems> align_items() const;
Optional<CSS::AlignSelf> align_self() const; Optional<CSS::AlignSelf> align_self() const;
Optional<CSS::Appearance> appearance() const; Optional<CSS::Appearance> appearance() const;
CSS::BackdropFilter backdrop_filter() const; CSS::Filter backdrop_filter() const;
CSS::Filter filter() const;
float opacity() const; float opacity() const;
Optional<CSS::Visibility> visibility() const; Optional<CSS::Visibility> visibility() const;
Optional<CSS::ImageRendering> image_rendering() const; Optional<CSS::ImageRendering> image_rendering() const;

View file

@ -13,7 +13,7 @@
namespace Web::CSS { namespace Web::CSS {
float Filter::Blur::resolved_radius(Layout::Node const& node) const float FilterOperation::Blur::resolved_radius(Layout::Node const& node) const
{ {
// Default value when omitted is 0px. // Default value when omitted is 0px.
auto sigma = 0; auto sigma = 0;
@ -23,7 +23,7 @@ float Filter::Blur::resolved_radius(Layout::Node const& node) const
return sigma * 2; return sigma * 2;
} }
float Filter::HueRotate::angle_degrees() const float FilterOperation::HueRotate::angle_degrees() const
{ {
// Default value when omitted is 0deg. // Default value when omitted is 0deg.
if (!angle.has_value()) if (!angle.has_value())
@ -31,7 +31,7 @@ float Filter::HueRotate::angle_degrees() const
return angle->visit([&](Angle const& a) { return a.to_degrees(); }, [&](auto) { return 0.0; }); return angle->visit([&](Angle const& a) { return a.to_degrees(); }, [&](auto) { return 0.0; });
} }
float Filter::Color::resolved_amount() const float FilterOperation::Color::resolved_amount() const
{ {
if (amount.has_value()) { if (amount.has_value()) {
if (amount->is_percentage()) if (amount->is_percentage())
@ -50,12 +50,12 @@ String FilterValueListStyleValue::to_string() const
if (!first) if (!first)
builder.append(' '); builder.append(' ');
filter_function.visit( filter_function.visit(
[&](Filter::Blur const& blur) { [&](FilterOperation::Blur const& blur) {
builder.append("blur("sv); builder.append("blur("sv);
if (blur.radius.has_value()) if (blur.radius.has_value())
builder.append(blur.radius->to_string()); builder.append(blur.radius->to_string());
}, },
[&](Filter::DropShadow const& drop_shadow) { [&](FilterOperation::DropShadow const& drop_shadow) {
builder.appendff("drop-shadow({} {}"sv, builder.appendff("drop-shadow({} {}"sv,
drop_shadow.offset_x, drop_shadow.offset_y); drop_shadow.offset_x, drop_shadow.offset_y);
if (drop_shadow.radius.has_value()) if (drop_shadow.radius.has_value())
@ -65,7 +65,7 @@ String FilterValueListStyleValue::to_string() const
serialize_a_srgb_value(builder, *drop_shadow.color); serialize_a_srgb_value(builder, *drop_shadow.color);
} }
}, },
[&](Filter::HueRotate const& hue_rotate) { [&](FilterOperation::HueRotate const& hue_rotate) {
builder.append("hue-rotate("sv); builder.append("hue-rotate("sv);
if (hue_rotate.angle.has_value()) { if (hue_rotate.angle.has_value()) {
hue_rotate.angle->visit( hue_rotate.angle->visit(
@ -77,23 +77,23 @@ String FilterValueListStyleValue::to_string() const
}); });
} }
}, },
[&](Filter::Color const& color) { [&](FilterOperation::Color const& color) {
builder.appendff("{}(", builder.appendff("{}(",
[&] { [&] {
switch (color.operation) { switch (color.operation) {
case Filter::Color::Operation::Brightness: case FilterOperation::Color::Type::Brightness:
return "brightness"sv; return "brightness"sv;
case Filter::Color::Operation::Contrast: case FilterOperation::Color::Type::Contrast:
return "contrast"sv; return "contrast"sv;
case Filter::Color::Operation::Grayscale: case FilterOperation::Color::Type::Grayscale:
return "grayscale"sv; return "grayscale"sv;
case Filter::Color::Operation::Invert: case FilterOperation::Color::Type::Invert:
return "invert"sv; return "invert"sv;
case Filter::Color::Operation::Opacity: case FilterOperation::Color::Type::Opacity:
return "opacity"sv; return "opacity"sv;
case Filter::Color::Operation::Saturate: case FilterOperation::Color::Type::Saturate:
return "saturate"sv; return "saturate"sv;
case Filter::Color::Operation::Sepia: case FilterOperation::Color::Type::Sepia:
return "sepia"sv; return "sepia"sv;
default: default:
VERIFY_NOT_REACHED(); VERIFY_NOT_REACHED();

View file

@ -16,7 +16,7 @@
namespace Web::CSS { namespace Web::CSS {
namespace Filter { namespace FilterOperation {
struct Blur { struct Blur {
Optional<Length> radius {}; Optional<Length> radius {};
@ -43,7 +43,7 @@ struct HueRotate {
}; };
struct Color { struct Color {
enum class Operation { enum class Type {
Brightness, Brightness,
Contrast, Contrast,
Grayscale, Grayscale,
@ -59,7 +59,7 @@ struct Color {
}; };
using FilterFunction = Variant<Filter::Blur, Filter::DropShadow, Filter::HueRotate, Filter::Color>; using FilterFunction = Variant<FilterOperation::Blur, FilterOperation::DropShadow, FilterOperation::HueRotate, FilterOperation::Color>;
class FilterValueListStyleValue final : public StyleValueWithDefaultOperators<FilterValueListStyleValue> { class FilterValueListStyleValue final : public StyleValueWithDefaultOperators<FilterValueListStyleValue> {
public: public:

View file

@ -512,34 +512,38 @@ void NodeWithStyle::apply_style(const CSS::StyleProperties& computed_style)
computed_values.set_order(computed_style.order()); computed_values.set_order(computed_style.order());
computed_values.set_clip(computed_style.clip()); computed_values.set_clip(computed_style.clip());
if (computed_style.backdrop_filter().has_filters()) { auto resolve_filter = [this](CSS::Filter const& computed_filter) -> CSS::ResolvedFilter {
CSS::ResolvedBackdropFilter resolved_backdrop_filter; CSS::ResolvedFilter resolved_filter;
for (auto& filter : computed_style.backdrop_filter().filters()) { for (auto const& filter : computed_filter.filters()) {
filter.visit( filter.visit(
[&](CSS::Filter::Blur const& blur) { [&](CSS::FilterOperation::Blur const& blur) {
resolved_backdrop_filter.filters.append(CSS::ResolvedBackdropFilter::Blur { resolved_filter.filters.append(CSS::ResolvedFilter::Blur {
.radius = blur.resolved_radius(*this) }); .radius = blur.resolved_radius(*this) });
}, },
[&](CSS::Filter::DropShadow const& drop_shadow) { [&](CSS::FilterOperation::DropShadow const& drop_shadow) {
// The default value for omitted values is missing length values set to 0 // The default value for omitted values is missing length values set to 0
// and the missing used color is taken from the color property. // and the missing used color is taken from the color property.
resolved_backdrop_filter.filters.append(CSS::ResolvedBackdropFilter::DropShadow { resolved_filter.filters.append(CSS::ResolvedFilter::DropShadow {
.offset_x = drop_shadow.offset_x.to_px(*this).to_double(), .offset_x = drop_shadow.offset_x.to_px(*this).to_double(),
.offset_y = drop_shadow.offset_y.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, .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() }); .color = drop_shadow.color.has_value() ? *drop_shadow.color : this->computed_values().color() });
}, },
[&](CSS::Filter::Color const& color_operation) { [&](CSS::FilterOperation::Color const& color_operation) {
resolved_backdrop_filter.filters.append(CSS::ResolvedBackdropFilter::ColorOperation { resolved_filter.filters.append(CSS::ResolvedFilter::Color {
.operation = color_operation.operation, .type = color_operation.operation,
.amount = color_operation.resolved_amount() }); .amount = color_operation.resolved_amount() });
}, },
[&](CSS::Filter::HueRotate const& hue_rotate) { [&](CSS::FilterOperation::HueRotate const& hue_rotate) {
resolved_backdrop_filter.filters.append(CSS::ResolvedBackdropFilter::HueRotate { .angle_degrees = hue_rotate.angle_degrees() }); resolved_filter.filters.append(CSS::ResolvedFilter::HueRotate { .angle_degrees = hue_rotate.angle_degrees() });
}); });
} }
computed_values.set_backdrop_filter(resolved_backdrop_filter); return resolved_filter;
} };
if (computed_style.backdrop_filter().has_filters())
computed_values.set_backdrop_filter(resolve_filter(computed_style.backdrop_filter()));
if (computed_style.filter().has_filters())
computed_values.set_filter(resolve_filter(computed_style.filter()));
auto justify_content = computed_style.justify_content(); auto justify_content = computed_style.justify_content();
if (justify_content.has_value()) if (justify_content.has_value())

View file

@ -285,7 +285,7 @@ struct DrawLine {
struct ApplyBackdropFilter { struct ApplyBackdropFilter {
Gfx::IntRect backdrop_region; Gfx::IntRect backdrop_region;
BorderRadiiData border_radii_data; BorderRadiiData border_radii_data;
CSS::ResolvedBackdropFilter backdrop_filter; CSS::ResolvedFilter backdrop_filter;
[[nodiscard]] Gfx::IntRect bounding_rect() const { return backdrop_region; } [[nodiscard]] Gfx::IntRect bounding_rect() const { return backdrop_region; }

View file

@ -964,18 +964,18 @@ void DisplayListPlayerSkia::apply_backdrop_filter(ApplyBackdropFilter const& com
for (auto const& filter_function : command.backdrop_filter.filters) { for (auto const& filter_function : command.backdrop_filter.filters) {
// See: https://drafts.fxtf.org/filter-effects-1/#supported-filter-functions // See: https://drafts.fxtf.org/filter-effects-1/#supported-filter-functions
filter_function.visit( filter_function.visit(
[&](CSS::ResolvedBackdropFilter::Blur const& blur_filter) { [&](CSS::ResolvedFilter::Blur const& blur_filter) {
auto blur_image_filter = SkImageFilters::Blur(blur_filter.radius, blur_filter.radius, nullptr); auto blur_image_filter = SkImageFilters::Blur(blur_filter.radius, blur_filter.radius, nullptr);
canvas.saveLayer(SkCanvas::SaveLayerRec(nullptr, nullptr, blur_image_filter.get(), 0)); canvas.saveLayer(SkCanvas::SaveLayerRec(nullptr, nullptr, blur_image_filter.get(), 0));
canvas.restore(); canvas.restore();
}, },
[&](CSS::ResolvedBackdropFilter::ColorOperation const& color) { [&](CSS::ResolvedFilter::Color const& color) {
auto amount = clamp(color.amount, 0.0f, 1.0f); auto amount = clamp(color.amount, 0.0f, 1.0f);
// Matrices are taken from https://drafts.fxtf.org/filter-effects-1/#FilterPrimitiveRepresentation // Matrices are taken from https://drafts.fxtf.org/filter-effects-1/#FilterPrimitiveRepresentation
sk_sp<SkColorFilter> color_filter; sk_sp<SkColorFilter> color_filter;
switch (color.operation) { switch (color.type) {
case CSS::Filter::Color::Operation::Grayscale: { case CSS::FilterOperation::Color::Type::Grayscale: {
float matrix[20] = { float matrix[20] = {
0.2126f + 0.7874f * (1 - amount), 0.7152f - 0.7152f * (1 - amount), 0.0722f - 0.0722f * (1 - amount), 0, 0, 0.2126f + 0.7874f * (1 - amount), 0.7152f - 0.7152f * (1 - amount), 0.0722f - 0.0722f * (1 - amount), 0, 0,
0.2126f - 0.2126f * (1 - amount), 0.7152f + 0.2848f * (1 - amount), 0.0722f - 0.0722f * (1 - amount), 0, 0, 0.2126f - 0.2126f * (1 - amount), 0.7152f + 0.2848f * (1 - amount), 0.0722f - 0.0722f * (1 - amount), 0, 0,
@ -985,7 +985,7 @@ void DisplayListPlayerSkia::apply_backdrop_filter(ApplyBackdropFilter const& com
color_filter = SkColorFilters::Matrix(matrix); color_filter = SkColorFilters::Matrix(matrix);
break; break;
} }
case CSS::Filter::Color::Operation::Brightness: { case CSS::FilterOperation::Color::Type::Brightness: {
float matrix[20] = { float matrix[20] = {
amount, 0, 0, 0, 0, amount, 0, 0, 0, 0,
0, amount, 0, 0, 0, 0, amount, 0, 0, 0,
@ -995,7 +995,7 @@ void DisplayListPlayerSkia::apply_backdrop_filter(ApplyBackdropFilter const& com
color_filter = SkColorFilters::Matrix(matrix); color_filter = SkColorFilters::Matrix(matrix);
break; break;
} }
case CSS::Filter::Color::Operation::Contrast: { case CSS::FilterOperation::Color::Type::Contrast: {
float intercept = -(0.5f * amount) + 0.5f; float intercept = -(0.5f * amount) + 0.5f;
float matrix[20] = { float matrix[20] = {
amount, 0, 0, 0, intercept, amount, 0, 0, 0, intercept,
@ -1006,7 +1006,7 @@ void DisplayListPlayerSkia::apply_backdrop_filter(ApplyBackdropFilter const& com
color_filter = SkColorFilters::Matrix(matrix); color_filter = SkColorFilters::Matrix(matrix);
break; break;
} }
case CSS::Filter::Color::Operation::Invert: { case CSS::FilterOperation::Color::Type::Invert: {
float matrix[20] = { float matrix[20] = {
1 - 2 * amount, 0, 0, 0, amount, 1 - 2 * amount, 0, 0, 0, amount,
0, 1 - 2 * amount, 0, 0, amount, 0, 1 - 2 * amount, 0, 0, amount,
@ -1016,7 +1016,7 @@ void DisplayListPlayerSkia::apply_backdrop_filter(ApplyBackdropFilter const& com
color_filter = SkColorFilters::Matrix(matrix); color_filter = SkColorFilters::Matrix(matrix);
break; break;
} }
case CSS::Filter::Color::Operation::Opacity: { case CSS::FilterOperation::Color::Type::Opacity: {
float matrix[20] = { float matrix[20] = {
1, 0, 0, 0, 0, 1, 0, 0, 0, 0,
0, 1, 0, 0, 0, 0, 1, 0, 0, 0,
@ -1026,7 +1026,7 @@ void DisplayListPlayerSkia::apply_backdrop_filter(ApplyBackdropFilter const& com
color_filter = SkColorFilters::Matrix(matrix); color_filter = SkColorFilters::Matrix(matrix);
break; break;
} }
case CSS::Filter::Color::Operation::Sepia: { case CSS::FilterOperation::Color::Type::Sepia: {
float matrix[20] = { float matrix[20] = {
0.393f + 0.607f * (1 - amount), 0.769f - 0.769f * (1 - amount), 0.189f - 0.189f * (1 - amount), 0, 0, 0.393f + 0.607f * (1 - amount), 0.769f - 0.769f * (1 - amount), 0.189f - 0.189f * (1 - amount), 0, 0,
0.349f - 0.349f * (1 - amount), 0.686f + 0.314f * (1 - amount), 0.168f - 0.168f * (1 - amount), 0, 0, 0.349f - 0.349f * (1 - amount), 0.686f + 0.314f * (1 - amount), 0.168f - 0.168f * (1 - amount), 0, 0,
@ -1036,7 +1036,7 @@ void DisplayListPlayerSkia::apply_backdrop_filter(ApplyBackdropFilter const& com
color_filter = SkColorFilters::Matrix(matrix); color_filter = SkColorFilters::Matrix(matrix);
break; break;
} }
case CSS::Filter::Color::Operation::Saturate: { case CSS::FilterOperation::Color::Type::Saturate: {
float matrix[20] = { float matrix[20] = {
0.213f + 0.787f * amount, 0.715f - 0.715f * amount, 0.072f - 0.072f * amount, 0, 0, 0.213f + 0.787f * amount, 0.715f - 0.715f * amount, 0.072f - 0.072f * amount, 0, 0,
0.213f - 0.213f * amount, 0.715f + 0.285f * amount, 0.072f - 0.072f * amount, 0, 0, 0.213f - 0.213f * amount, 0.715f + 0.285f * amount, 0.072f - 0.072f * amount, 0, 0,
@ -1054,7 +1054,7 @@ void DisplayListPlayerSkia::apply_backdrop_filter(ApplyBackdropFilter const& com
canvas.saveLayer(SkCanvas::SaveLayerRec(nullptr, nullptr, image_filter.get(), 0)); canvas.saveLayer(SkCanvas::SaveLayerRec(nullptr, nullptr, image_filter.get(), 0));
canvas.restore(); canvas.restore();
}, },
[&](CSS::ResolvedBackdropFilter::HueRotate const& hue_rotate) { [&](CSS::ResolvedFilter::HueRotate const& hue_rotate) {
float radians = AK::to_radians(hue_rotate.angle_degrees); float radians = AK::to_radians(hue_rotate.angle_degrees);
auto cosA = cos(radians); auto cosA = cos(radians);
@ -1082,7 +1082,7 @@ void DisplayListPlayerSkia::apply_backdrop_filter(ApplyBackdropFilter const& com
canvas.saveLayer(SkCanvas::SaveLayerRec(nullptr, nullptr, image_filter.get(), 0)); canvas.saveLayer(SkCanvas::SaveLayerRec(nullptr, nullptr, image_filter.get(), 0));
canvas.restore(); canvas.restore();
}, },
[&](CSS::ResolvedBackdropFilter::DropShadow const&) { [&](CSS::ResolvedFilter::DropShadow const&) {
dbgln("TODO: Implement drop-shadow() filter function!"); dbgln("TODO: Implement drop-shadow() filter function!");
}); });
} }

View file

@ -299,7 +299,7 @@ void DisplayListRecorder::pop_stacking_context()
append(PopStackingContext {}); append(PopStackingContext {});
} }
void DisplayListRecorder::apply_backdrop_filter(Gfx::IntRect const& backdrop_region, BorderRadiiData const& border_radii_data, CSS::ResolvedBackdropFilter const& backdrop_filter) void DisplayListRecorder::apply_backdrop_filter(Gfx::IntRect const& backdrop_region, BorderRadiiData const& border_radii_data, CSS::ResolvedFilter const& backdrop_filter)
{ {
if (backdrop_region.is_empty()) if (backdrop_region.is_empty())
return; return;

View file

@ -124,7 +124,7 @@ public:
void add_rounded_rect_clip(CornerRadii corner_radii, Gfx::IntRect border_rect, CornerClip corner_clip); void add_rounded_rect_clip(CornerRadii corner_radii, Gfx::IntRect border_rect, CornerClip corner_clip);
void add_mask(RefPtr<DisplayList> display_list, Gfx::IntRect rect); void add_mask(RefPtr<DisplayList> display_list, Gfx::IntRect rect);
void apply_backdrop_filter(Gfx::IntRect const& backdrop_region, BorderRadiiData const& border_radii_data, CSS::ResolvedBackdropFilter const& backdrop_filter); void apply_backdrop_filter(Gfx::IntRect const& backdrop_region, BorderRadiiData const& border_radii_data, CSS::ResolvedFilter const& backdrop_filter);
void paint_outer_box_shadow_params(PaintBoxShadowParams params); void paint_outer_box_shadow_params(PaintBoxShadowParams params);
void paint_inner_box_shadow_params(PaintBoxShadowParams params); void paint_inner_box_shadow_params(PaintBoxShadowParams params);