From 89ed8e59f94e5c2be227510eda17a3d6e13f63f2 Mon Sep 17 00:00:00 2001 From: Sam Atkins Date: Thu, 23 Mar 2023 21:26:03 +0000 Subject: [PATCH] LibWeb: Split FilterValueListStyleValue out of StyleValue.{h,cpp} --- Userland/Libraries/LibWeb/CMakeLists.txt | 1 + .../Libraries/LibWeb/CSS/BackdropFilter.h | 1 + .../Libraries/LibWeb/CSS/Parser/Parser.cpp | 1 + .../Libraries/LibWeb/CSS/StyleComputer.cpp | 1 + Userland/Libraries/LibWeb/CSS/StyleValue.cpp | 112 +-------------- Userland/Libraries/LibWeb/CSS/StyleValue.h | 80 ----------- .../StyleValues/FilterValueListStyleValue.cpp | 127 ++++++++++++++++++ .../StyleValues/FilterValueListStyleValue.h | 100 ++++++++++++++ 8 files changed, 232 insertions(+), 191 deletions(-) create mode 100644 Userland/Libraries/LibWeb/CSS/StyleValues/FilterValueListStyleValue.cpp create mode 100644 Userland/Libraries/LibWeb/CSS/StyleValues/FilterValueListStyleValue.h diff --git a/Userland/Libraries/LibWeb/CMakeLists.txt b/Userland/Libraries/LibWeb/CMakeLists.txt index 1d35524eb9..450c8b59ac 100644 --- a/Userland/Libraries/LibWeb/CMakeLists.txt +++ b/Userland/Libraries/LibWeb/CMakeLists.txt @@ -73,6 +73,7 @@ set(SOURCES CSS/StyleValues/BorderStyleValue.cpp CSS/StyleValues/ColorStyleValue.cpp CSS/StyleValues/ContentStyleValue.cpp + CSS/StyleValues/FilterValueListStyleValue.cpp CSS/Supports.cpp CSS/SyntaxHighlighter/SyntaxHighlighter.cpp CSS/Time.cpp diff --git a/Userland/Libraries/LibWeb/CSS/BackdropFilter.h b/Userland/Libraries/LibWeb/CSS/BackdropFilter.h index bdceb36ee1..5dd1e5be8d 100644 --- a/Userland/Libraries/LibWeb/CSS/BackdropFilter.h +++ b/Userland/Libraries/LibWeb/CSS/BackdropFilter.h @@ -8,6 +8,7 @@ #include #include +#include namespace Web::CSS { diff --git a/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp b/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp index 84b48ed75b..1a2883164a 100644 --- a/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp +++ b/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include diff --git a/Userland/Libraries/LibWeb/CSS/StyleComputer.cpp b/Userland/Libraries/LibWeb/CSS/StyleComputer.cpp index c04837ee15..61d8a4b754 100644 --- a/Userland/Libraries/LibWeb/CSS/StyleComputer.cpp +++ b/Userland/Libraries/LibWeb/CSS/StyleComputer.cpp @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include diff --git a/Userland/Libraries/LibWeb/CSS/StyleValue.cpp b/Userland/Libraries/LibWeb/CSS/StyleValue.cpp index 0e9bca9cb5..f13b0db3a2 100644 --- a/Userland/Libraries/LibWeb/CSS/StyleValue.cpp +++ b/Userland/Libraries/LibWeb/CSS/StyleValue.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -1022,117 +1023,6 @@ CalculatedStyleValue::CalculationResult CalculatedStyleValue::CalcNumberSumPartW return value->resolve(layout_node, percentage_basis); } -float Filter::Blur::resolved_radius(Layout::Node const& node) const -{ - // Default value when omitted is 0px. - auto sigma = 0; - if (radius.has_value()) - sigma = radius->resolved(node).to_px(node).value(); - // Note: The radius/sigma of the blur needs to be doubled for LibGfx's blur functions. - 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.resolved(node).to_px(node).value(), - offset_y.resolved(node).to_px(node).value(), - radius.has_value() ? radius->resolved(node).to_px(node).value() : 0.0f, - color.has_value() ? *color : node.computed_values().color() - }; -} - -float Filter::HueRotate::angle_degrees() const -{ - // Default value when omitted is 0deg. - if (!angle.has_value()) - return 0.0f; - return angle->visit([&](Angle const& angle) { return angle.to_degrees(); }, [&](auto) { return 0.0f; }); -} - -float Filter::Color::resolved_amount() const -{ - if (amount.has_value()) { - if (amount->is_percentage()) - return amount->percentage().as_fraction(); - return amount->number().value(); - } - // All color filters (brightness, sepia, etc) have a default amount of 1. - return 1.0f; -} - -ErrorOr FilterValueListStyleValue::to_string() const -{ - StringBuilder builder {}; - bool first = true; - for (auto& filter_function : filter_value_list()) { - if (!first) - TRY(builder.try_append(' ')); - TRY(filter_function.visit( - [&](Filter::Blur const& blur) -> ErrorOr { - TRY(builder.try_append("blur("sv)); - if (blur.radius.has_value()) - TRY(builder.try_append(TRY(blur.radius->to_string()))); - return {}; - }, - [&](Filter::DropShadow const& drop_shadow) -> ErrorOr { - TRY(builder.try_appendff("drop-shadow({} {}"sv, - drop_shadow.offset_x, drop_shadow.offset_y)); - if (drop_shadow.radius.has_value()) - TRY(builder.try_appendff(" {}", TRY(drop_shadow.radius->to_string()))); - if (drop_shadow.color.has_value()) { - TRY(builder.try_append(' ')); - TRY(serialize_a_srgb_value(builder, *drop_shadow.color)); - } - return {}; - }, - [&](Filter::HueRotate const& hue_rotate) -> ErrorOr { - TRY(builder.try_append("hue-rotate("sv)); - if (hue_rotate.angle.has_value()) { - TRY(hue_rotate.angle->visit( - [&](Angle const& angle) -> ErrorOr { - return builder.try_append(TRY(angle.to_string())); - }, - [&](auto&) -> ErrorOr { - return builder.try_append('0'); - })); - } - return {}; - }, - [&](Filter::Color const& color) -> ErrorOr { - TRY(builder.try_appendff("{}(", - [&] { - switch (color.operation) { - case Filter::Color::Operation::Brightness: - return "brightness"sv; - case Filter::Color::Operation::Contrast: - return "contrast"sv; - case Filter::Color::Operation::Grayscale: - return "grayscale"sv; - case Filter::Color::Operation::Invert: - return "invert"sv; - case Filter::Color::Operation::Opacity: - return "opacity"sv; - case Filter::Color::Operation::Saturate: - return "saturate"sv; - case Filter::Color::Operation::Sepia: - return "sepia"sv; - default: - VERIFY_NOT_REACHED(); - } - }())); - if (color.amount.has_value()) - TRY(builder.try_append(TRY(color.amount->to_string()))); - return {}; - })); - TRY(builder.try_append(')')); - first = false; - } - return builder.to_string(); -} - ErrorOr FlexStyleValue::to_string() const { return String::formatted("{} {} {}", TRY(m_properties.grow->to_string()), TRY(m_properties.shrink->to_string()), TRY(m_properties.basis->to_string())); diff --git a/Userland/Libraries/LibWeb/CSS/StyleValue.h b/Userland/Libraries/LibWeb/CSS/StyleValue.h index 0719cc91a5..1a40817745 100644 --- a/Userland/Libraries/LibWeb/CSS/StyleValue.h +++ b/Userland/Libraries/LibWeb/CSS/StyleValue.h @@ -145,58 +145,6 @@ struct EdgeRect { bool operator==(EdgeRect const&) const = default; }; -namespace Filter { - -struct Blur { - Optional radius {}; - float resolved_radius(Layout::Node const&) const; - bool operator==(Blur const&) const = default; -}; - -struct DropShadow { - Length offset_x; - Length offset_y; - Optional radius {}; - Optional color {}; - struct Resolved { - float offset_x; - float offset_y; - float radius; - Color color; - }; - Resolved resolved(Layout::Node const&) const; - bool operator==(DropShadow const&) const = default; -}; - -struct HueRotate { - struct Zero { - bool operator==(Zero const&) const = default; - }; - using AngleOrZero = Variant; - Optional angle {}; - float angle_degrees() const; - bool operator==(HueRotate const&) const = default; -}; - -struct Color { - enum class Operation { - Brightness, - Contrast, - Grayscale, - Invert, - Opacity, - Saturate, - Sepia - } operation; - Optional amount {}; - float resolved_amount() const; - bool operator==(Color const&) const = default; -}; - -}; - -using FilterFunction = Variant; - // FIXME: Find a better place for this helper. inline Gfx::Painter::ScalingMode to_gfx_scaling_mode(CSS::ImageRendering css_value) { @@ -713,34 +661,6 @@ private: NonnullOwnPtr m_expression; }; -class FilterValueListStyleValue final : public StyleValueWithDefaultOperators { -public: - static ValueComparingNonnullRefPtr create( - Vector filter_value_list) - { - VERIFY(filter_value_list.size() >= 1); - return adopt_ref(*new FilterValueListStyleValue(move(filter_value_list))); - } - - Vector const& filter_value_list() const { return m_filter_value_list; } - - virtual ErrorOr to_string() const override; - - virtual ~FilterValueListStyleValue() override = default; - - bool properties_equal(FilterValueListStyleValue const& other) const { return m_filter_value_list == other.m_filter_value_list; }; - -private: - FilterValueListStyleValue(Vector filter_value_list) - : StyleValueWithDefaultOperators(Type::FilterValueList) - , m_filter_value_list(move(filter_value_list)) - { - } - - // FIXME: No support for SVG filters yet - Vector m_filter_value_list; -}; - class FlexStyleValue final : public StyleValueWithDefaultOperators { public: static ValueComparingNonnullRefPtr create( diff --git a/Userland/Libraries/LibWeb/CSS/StyleValues/FilterValueListStyleValue.cpp b/Userland/Libraries/LibWeb/CSS/StyleValues/FilterValueListStyleValue.cpp new file mode 100644 index 0000000000..a106fd1001 --- /dev/null +++ b/Userland/Libraries/LibWeb/CSS/StyleValues/FilterValueListStyleValue.cpp @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2018-2020, Andreas Kling + * Copyright (c) 2021, Tobias Christiansen + * Copyright (c) 2021-2023, Sam Atkins + * Copyright (c) 2022-2023, MacDue + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include "FilterValueListStyleValue.h" +#include +#include + +namespace Web::CSS { + +float Filter::Blur::resolved_radius(Layout::Node const& node) const +{ + // Default value when omitted is 0px. + auto sigma = 0; + if (radius.has_value()) + sigma = radius->resolved(node).to_px(node).value(); + // Note: The radius/sigma of the blur needs to be doubled for LibGfx's blur functions. + 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.resolved(node).to_px(node).value(), + offset_y.resolved(node).to_px(node).value(), + radius.has_value() ? radius->resolved(node).to_px(node).value() : 0.0f, + color.has_value() ? *color : node.computed_values().color() + }; +} + +float Filter::HueRotate::angle_degrees() const +{ + // Default value when omitted is 0deg. + if (!angle.has_value()) + return 0.0f; + return angle->visit([&](Angle const& a) { return a.to_degrees(); }, [&](auto) { return 0.0f; }); +} + +float Filter::Color::resolved_amount() const +{ + if (amount.has_value()) { + if (amount->is_percentage()) + return amount->percentage().as_fraction(); + return amount->number().value(); + } + // All color filters (brightness, sepia, etc) have a default amount of 1. + return 1.0f; +} + +ErrorOr FilterValueListStyleValue::to_string() const +{ + StringBuilder builder {}; + bool first = true; + for (auto& filter_function : filter_value_list()) { + if (!first) + TRY(builder.try_append(' ')); + TRY(filter_function.visit( + [&](Filter::Blur const& blur) -> ErrorOr { + TRY(builder.try_append("blur("sv)); + if (blur.radius.has_value()) + TRY(builder.try_append(TRY(blur.radius->to_string()))); + return {}; + }, + [&](Filter::DropShadow const& drop_shadow) -> ErrorOr { + TRY(builder.try_appendff("drop-shadow({} {}"sv, + drop_shadow.offset_x, drop_shadow.offset_y)); + if (drop_shadow.radius.has_value()) + TRY(builder.try_appendff(" {}", TRY(drop_shadow.radius->to_string()))); + if (drop_shadow.color.has_value()) { + TRY(builder.try_append(' ')); + TRY(serialize_a_srgb_value(builder, *drop_shadow.color)); + } + return {}; + }, + [&](Filter::HueRotate const& hue_rotate) -> ErrorOr { + TRY(builder.try_append("hue-rotate("sv)); + if (hue_rotate.angle.has_value()) { + TRY(hue_rotate.angle->visit( + [&](Angle const& angle) -> ErrorOr { + return builder.try_append(TRY(angle.to_string())); + }, + [&](auto&) -> ErrorOr { + return builder.try_append('0'); + })); + } + return {}; + }, + [&](Filter::Color const& color) -> ErrorOr { + TRY(builder.try_appendff("{}(", + [&] { + switch (color.operation) { + case Filter::Color::Operation::Brightness: + return "brightness"sv; + case Filter::Color::Operation::Contrast: + return "contrast"sv; + case Filter::Color::Operation::Grayscale: + return "grayscale"sv; + case Filter::Color::Operation::Invert: + return "invert"sv; + case Filter::Color::Operation::Opacity: + return "opacity"sv; + case Filter::Color::Operation::Saturate: + return "saturate"sv; + case Filter::Color::Operation::Sepia: + return "sepia"sv; + default: + VERIFY_NOT_REACHED(); + } + }())); + if (color.amount.has_value()) + TRY(builder.try_append(TRY(color.amount->to_string()))); + return {}; + })); + TRY(builder.try_append(')')); + first = false; + } + return builder.to_string(); +} + +} diff --git a/Userland/Libraries/LibWeb/CSS/StyleValues/FilterValueListStyleValue.h b/Userland/Libraries/LibWeb/CSS/StyleValues/FilterValueListStyleValue.h new file mode 100644 index 0000000000..2275d04dcc --- /dev/null +++ b/Userland/Libraries/LibWeb/CSS/StyleValues/FilterValueListStyleValue.h @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2018-2020, Andreas Kling + * Copyright (c) 2021, Tobias Christiansen + * Copyright (c) 2021-2023, Sam Atkins + * Copyright (c) 2022-2023, MacDue + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include +#include +#include +#include + +namespace Web::CSS { + +namespace Filter { + +struct Blur { + Optional radius {}; + float resolved_radius(Layout::Node const&) const; + bool operator==(Blur const&) const = default; +}; + +struct DropShadow { + Length offset_x; + Length offset_y; + Optional radius {}; + Optional color {}; + struct Resolved { + float offset_x; + float offset_y; + float radius; + Color color; + }; + Resolved resolved(Layout::Node const&) const; + bool operator==(DropShadow const&) const = default; +}; + +struct HueRotate { + struct Zero { + bool operator==(Zero const&) const = default; + }; + using AngleOrZero = Variant; + Optional angle {}; + float angle_degrees() const; + bool operator==(HueRotate const&) const = default; +}; + +struct Color { + enum class Operation { + Brightness, + Contrast, + Grayscale, + Invert, + Opacity, + Saturate, + Sepia + } operation; + Optional amount {}; + float resolved_amount() const; + bool operator==(Color const&) const = default; +}; + +}; + +using FilterFunction = Variant; + +class FilterValueListStyleValue final : public StyleValueWithDefaultOperators { +public: + static ValueComparingNonnullRefPtr create( + Vector filter_value_list) + { + VERIFY(filter_value_list.size() >= 1); + return adopt_ref(*new FilterValueListStyleValue(move(filter_value_list))); + } + + Vector const& filter_value_list() const { return m_filter_value_list; } + + virtual ErrorOr to_string() const override; + + virtual ~FilterValueListStyleValue() override = default; + + bool properties_equal(FilterValueListStyleValue const& other) const { return m_filter_value_list == other.m_filter_value_list; }; + +private: + FilterValueListStyleValue(Vector filter_value_list) + : StyleValueWithDefaultOperators(Type::FilterValueList) + , m_filter_value_list(move(filter_value_list)) + { + } + + // FIXME: No support for SVG filters yet + Vector m_filter_value_list; +}; + +}