From c8ffd82cb75fe3b5daa07329ab07ffceb43bd11b Mon Sep 17 00:00:00 2001 From: Sam Atkins Date: Fri, 24 Mar 2023 16:17:50 +0000 Subject: [PATCH] LibWeb: Split LinearGradientStyleValue out of StyleValue.{h,cpp} --- Userland/Libraries/LibWeb/CMakeLists.txt | 1 + .../Libraries/LibWeb/CSS/Parser/Parser.cpp | 1 + Userland/Libraries/LibWeb/CSS/StyleValue.cpp | 105 +------------ Userland/Libraries/LibWeb/CSS/StyleValue.h | 68 --------- .../StyleValues/LinearGradientStyleValue.cpp | 140 ++++++++++++++++++ .../StyleValues/LinearGradientStyleValue.h | 85 +++++++++++ .../LibWeb/Painting/GradientPainting.cpp | 1 + 7 files changed, 229 insertions(+), 172 deletions(-) create mode 100644 Userland/Libraries/LibWeb/CSS/StyleValues/LinearGradientStyleValue.cpp create mode 100644 Userland/Libraries/LibWeb/CSS/StyleValues/LinearGradientStyleValue.h diff --git a/Userland/Libraries/LibWeb/CMakeLists.txt b/Userland/Libraries/LibWeb/CMakeLists.txt index 59b8b5636c..6d8fa041dc 100644 --- a/Userland/Libraries/LibWeb/CMakeLists.txt +++ b/Userland/Libraries/LibWeb/CMakeLists.txt @@ -85,6 +85,7 @@ set(SOURCES CSS/StyleValues/GridTrackSizeStyleValue.cpp CSS/StyleValues/IdentifierStyleValue.cpp CSS/StyleValues/ImageStyleValue.cpp + CSS/StyleValues/LinearGradientStyleValue.cpp CSS/Supports.cpp CSS/SyntaxHighlighter/SyntaxHighlighter.cpp CSS/Time.cpp diff --git a/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp b/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp index b199374562..ffed6fb725 100644 --- a/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp +++ b/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp @@ -51,6 +51,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 a2adfccbf3..806cb84b8e 100644 --- a/Userland/Libraries/LibWeb/CSS/StyleValue.cpp +++ b/Userland/Libraries/LibWeb/CSS/StyleValue.cpp @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -1055,110 +1056,6 @@ static ErrorOr serialize_color_stop_list(StringBuilder& builder, auto cons return {}; } -ErrorOr LinearGradientStyleValue::to_string() const -{ - StringBuilder builder; - auto side_or_corner_to_string = [](SideOrCorner value) { - switch (value) { - case SideOrCorner::Top: - return "top"sv; - case SideOrCorner::Bottom: - return "bottom"sv; - case SideOrCorner::Left: - return "left"sv; - case SideOrCorner::Right: - return "right"sv; - case SideOrCorner::TopLeft: - return "top left"sv; - case SideOrCorner::TopRight: - return "top right"sv; - case SideOrCorner::BottomLeft: - return "bottom left"sv; - case SideOrCorner::BottomRight: - return "bottom right"sv; - default: - VERIFY_NOT_REACHED(); - } - }; - - if (m_properties.gradient_type == GradientType::WebKit) - TRY(builder.try_append("-webkit-"sv)); - if (is_repeating()) - TRY(builder.try_append("repeating-"sv)); - TRY(builder.try_append("linear-gradient("sv)); - TRY(m_properties.direction.visit( - [&](SideOrCorner side_or_corner) -> ErrorOr { - return builder.try_appendff("{}{}, "sv, m_properties.gradient_type == GradientType::Standard ? "to "sv : ""sv, side_or_corner_to_string(side_or_corner)); - }, - [&](Angle const& angle) -> ErrorOr { - return builder.try_appendff("{}, "sv, TRY(angle.to_string())); - })); - - TRY(serialize_color_stop_list(builder, m_properties.color_stop_list)); - TRY(builder.try_append(")"sv)); - return builder.to_string(); -} - -bool LinearGradientStyleValue::equals(StyleValue const& other_) const -{ - if (type() != other_.type()) - return false; - auto& other = other_.as_linear_gradient(); - return m_properties == other.m_properties; -} - -float LinearGradientStyleValue::angle_degrees(CSSPixelSize gradient_size) const -{ - auto corner_angle_degrees = [&] { - return static_cast(atan2(gradient_size.height().value(), gradient_size.width().value())) * 180 / AK::Pi; - }; - return m_properties.direction.visit( - [&](SideOrCorner side_or_corner) { - auto angle = [&] { - switch (side_or_corner) { - case SideOrCorner::Top: - return 0.0f; - case SideOrCorner::Bottom: - return 180.0f; - case SideOrCorner::Left: - return 270.0f; - case SideOrCorner::Right: - return 90.0f; - case SideOrCorner::TopRight: - return corner_angle_degrees(); - case SideOrCorner::BottomLeft: - return corner_angle_degrees() + 180.0f; - case SideOrCorner::TopLeft: - return -corner_angle_degrees(); - case SideOrCorner::BottomRight: - return -(corner_angle_degrees() + 180.0f); - default: - VERIFY_NOT_REACHED(); - } - }(); - // Note: For unknowable reasons the angles are opposite on the -webkit- version - if (m_properties.gradient_type == GradientType::WebKit) - return angle + 180.0f; - return angle; - }, - [&](Angle const& angle) { - return angle.to_degrees(); - }); -} - -void LinearGradientStyleValue::resolve_for_size(Layout::Node const& node, CSSPixelSize size) const -{ - if (m_resolved.has_value() && m_resolved->size == size) - return; - m_resolved = ResolvedData { Painting::resolve_linear_gradient_data(node, size, *this), size }; -} - -void LinearGradientStyleValue::paint(PaintContext& context, DevicePixelRect const& dest_rect, CSS::ImageRendering) const -{ - VERIFY(m_resolved.has_value()); - Painting::paint_linear_gradient(context, dest_rect, m_resolved->data); -} - CSSPixelPoint PositionValue::resolved(Layout::Node const& node, CSSPixelRect const& rect) const { // Note: A preset + a none default x/y_relative_to is impossible in the syntax (and makes little sense) diff --git a/Userland/Libraries/LibWeb/CSS/StyleValue.h b/Userland/Libraries/LibWeb/CSS/StyleValue.h index 036473c7e6..1e298416b2 100644 --- a/Userland/Libraries/LibWeb/CSS/StyleValue.h +++ b/Userland/Libraries/LibWeb/CSS/StyleValue.h @@ -63,18 +63,6 @@ enum class FlexBasis { Auto, }; -// Note: The sides must be before the corners in this enum (as this order is used in parsing). -enum class SideOrCorner { - Top, - Bottom, - Left, - Right, - TopLeft, - TopRight, - BottomLeft, - BottomRight -}; - template struct ColorStopListElement { using PositionType = TPosition; @@ -759,62 +747,6 @@ private: mutable Optional m_resolved; }; -class LinearGradientStyleValue final : public AbstractImageStyleValue { -public: - using GradientDirection = Variant; - - enum class GradientType { - Standard, - WebKit - }; - - static ValueComparingNonnullRefPtr create(GradientDirection direction, Vector color_stop_list, GradientType type, GradientRepeating repeating) - { - VERIFY(color_stop_list.size() >= 2); - return adopt_ref(*new LinearGradientStyleValue(direction, move(color_stop_list), type, repeating)); - } - - virtual ErrorOr to_string() const override; - virtual ~LinearGradientStyleValue() override = default; - virtual bool equals(StyleValue const& other) const override; - - Vector const& color_stop_list() const - { - return m_properties.color_stop_list; - } - - bool is_repeating() const { return m_properties.repeating == GradientRepeating::Yes; } - - float angle_degrees(CSSPixelSize gradient_size) const; - - void resolve_for_size(Layout::Node const&, CSSPixelSize) const override; - - bool is_paintable() const override { return true; } - void paint(PaintContext& context, DevicePixelRect const& dest_rect, CSS::ImageRendering image_rendering) const override; - -private: - LinearGradientStyleValue(GradientDirection direction, Vector color_stop_list, GradientType type, GradientRepeating repeating) - : AbstractImageStyleValue(Type::LinearGradient) - , m_properties { .direction = direction, .color_stop_list = move(color_stop_list), .gradient_type = type, .repeating = repeating } - { - } - - struct Properties { - GradientDirection direction; - Vector color_stop_list; - GradientType gradient_type; - GradientRepeating repeating; - bool operator==(Properties const&) const = default; - } m_properties; - - struct ResolvedData { - Painting::LinearGradientData data; - CSSPixelSize size; - }; - - mutable Optional m_resolved; -}; - class InheritStyleValue final : public StyleValueWithDefaultOperators { public: static ValueComparingNonnullRefPtr the() diff --git a/Userland/Libraries/LibWeb/CSS/StyleValues/LinearGradientStyleValue.cpp b/Userland/Libraries/LibWeb/CSS/StyleValues/LinearGradientStyleValue.cpp new file mode 100644 index 0000000000..233378ee52 --- /dev/null +++ b/Userland/Libraries/LibWeb/CSS/StyleValues/LinearGradientStyleValue.cpp @@ -0,0 +1,140 @@ +/* + * 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 "LinearGradientStyleValue.h" +#include + +namespace Web::CSS { + +// FIXME: Temporary until AbstractImageStyleValue.h exists. (And the Serialize.h include above.) +static ErrorOr serialize_color_stop_list(StringBuilder& builder, auto const& color_stop_list) +{ + bool first = true; + for (auto const& element : color_stop_list) { + if (!first) + TRY(builder.try_append(", "sv)); + + if (element.transition_hint.has_value()) + TRY(builder.try_appendff("{}, "sv, TRY(element.transition_hint->value.to_string()))); + + TRY(serialize_a_srgb_value(builder, element.color_stop.color)); + for (auto position : Array { &element.color_stop.position, &element.color_stop.second_position }) { + if (position->has_value()) + TRY(builder.try_appendff(" {}"sv, TRY((*position)->to_string()))); + } + first = false; + } + return {}; +} + +ErrorOr LinearGradientStyleValue::to_string() const +{ + StringBuilder builder; + auto side_or_corner_to_string = [](SideOrCorner value) { + switch (value) { + case SideOrCorner::Top: + return "top"sv; + case SideOrCorner::Bottom: + return "bottom"sv; + case SideOrCorner::Left: + return "left"sv; + case SideOrCorner::Right: + return "right"sv; + case SideOrCorner::TopLeft: + return "top left"sv; + case SideOrCorner::TopRight: + return "top right"sv; + case SideOrCorner::BottomLeft: + return "bottom left"sv; + case SideOrCorner::BottomRight: + return "bottom right"sv; + default: + VERIFY_NOT_REACHED(); + } + }; + + if (m_properties.gradient_type == GradientType::WebKit) + TRY(builder.try_append("-webkit-"sv)); + if (is_repeating()) + TRY(builder.try_append("repeating-"sv)); + TRY(builder.try_append("linear-gradient("sv)); + TRY(m_properties.direction.visit( + [&](SideOrCorner side_or_corner) -> ErrorOr { + return builder.try_appendff("{}{}, "sv, m_properties.gradient_type == GradientType::Standard ? "to "sv : ""sv, side_or_corner_to_string(side_or_corner)); + }, + [&](Angle const& angle) -> ErrorOr { + return builder.try_appendff("{}, "sv, TRY(angle.to_string())); + })); + + TRY(serialize_color_stop_list(builder, m_properties.color_stop_list)); + TRY(builder.try_append(")"sv)); + return builder.to_string(); +} + +bool LinearGradientStyleValue::equals(StyleValue const& other_) const +{ + if (type() != other_.type()) + return false; + auto& other = other_.as_linear_gradient(); + return m_properties == other.m_properties; +} + +float LinearGradientStyleValue::angle_degrees(CSSPixelSize gradient_size) const +{ + auto corner_angle_degrees = [&] { + return static_cast(atan2(gradient_size.height().value(), gradient_size.width().value())) * 180 / AK::Pi; + }; + return m_properties.direction.visit( + [&](SideOrCorner side_or_corner) { + auto angle = [&] { + switch (side_or_corner) { + case SideOrCorner::Top: + return 0.0f; + case SideOrCorner::Bottom: + return 180.0f; + case SideOrCorner::Left: + return 270.0f; + case SideOrCorner::Right: + return 90.0f; + case SideOrCorner::TopRight: + return corner_angle_degrees(); + case SideOrCorner::BottomLeft: + return corner_angle_degrees() + 180.0f; + case SideOrCorner::TopLeft: + return -corner_angle_degrees(); + case SideOrCorner::BottomRight: + return -(corner_angle_degrees() + 180.0f); + default: + VERIFY_NOT_REACHED(); + } + }(); + // Note: For unknowable reasons the angles are opposite on the -webkit- version + if (m_properties.gradient_type == GradientType::WebKit) + return angle + 180.0f; + return angle; + }, + [&](Angle const& angle) { + return angle.to_degrees(); + }); +} + +void LinearGradientStyleValue::resolve_for_size(Layout::Node const& node, CSSPixelSize size) const +{ + if (m_resolved.has_value() && m_resolved->size == size) + return; + m_resolved = ResolvedData { Painting::resolve_linear_gradient_data(node, size, *this), size }; +} + +void LinearGradientStyleValue::paint(PaintContext& context, DevicePixelRect const& dest_rect, CSS::ImageRendering) const +{ + VERIFY(m_resolved.has_value()); + Painting::paint_linear_gradient(context, dest_rect, m_resolved->data); +} + +} diff --git a/Userland/Libraries/LibWeb/CSS/StyleValues/LinearGradientStyleValue.h b/Userland/Libraries/LibWeb/CSS/StyleValues/LinearGradientStyleValue.h new file mode 100644 index 0000000000..c1bc87f718 --- /dev/null +++ b/Userland/Libraries/LibWeb/CSS/StyleValues/LinearGradientStyleValue.h @@ -0,0 +1,85 @@ +/* + * 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 + +namespace Web::CSS { + +// Note: The sides must be before the corners in this enum (as this order is used in parsing). +enum class SideOrCorner { + Top, + Bottom, + Left, + Right, + TopLeft, + TopRight, + BottomLeft, + BottomRight +}; + +class LinearGradientStyleValue final : public AbstractImageStyleValue { +public: + using GradientDirection = Variant; + + enum class GradientType { + Standard, + WebKit + }; + + static ValueComparingNonnullRefPtr create(GradientDirection direction, Vector color_stop_list, GradientType type, GradientRepeating repeating) + { + VERIFY(color_stop_list.size() >= 2); + return adopt_ref(*new LinearGradientStyleValue(direction, move(color_stop_list), type, repeating)); + } + + virtual ErrorOr to_string() const override; + virtual ~LinearGradientStyleValue() override = default; + virtual bool equals(StyleValue const& other) const override; + + Vector const& color_stop_list() const + { + return m_properties.color_stop_list; + } + + bool is_repeating() const { return m_properties.repeating == GradientRepeating::Yes; } + + float angle_degrees(CSSPixelSize gradient_size) const; + + void resolve_for_size(Layout::Node const&, CSSPixelSize) const override; + + bool is_paintable() const override { return true; } + void paint(PaintContext& context, DevicePixelRect const& dest_rect, CSS::ImageRendering image_rendering) const override; + +private: + LinearGradientStyleValue(GradientDirection direction, Vector color_stop_list, GradientType type, GradientRepeating repeating) + : AbstractImageStyleValue(Type::LinearGradient) + , m_properties { .direction = direction, .color_stop_list = move(color_stop_list), .gradient_type = type, .repeating = repeating } + { + } + + struct Properties { + GradientDirection direction; + Vector color_stop_list; + GradientType gradient_type; + GradientRepeating repeating; + bool operator==(Properties const&) const = default; + } m_properties; + + struct ResolvedData { + Painting::LinearGradientData data; + CSSPixelSize size; + }; + + mutable Optional m_resolved; +}; + +} diff --git a/Userland/Libraries/LibWeb/Painting/GradientPainting.cpp b/Userland/Libraries/LibWeb/Painting/GradientPainting.cpp index 904024a2b2..d409c63fb7 100644 --- a/Userland/Libraries/LibWeb/Painting/GradientPainting.cpp +++ b/Userland/Libraries/LibWeb/Painting/GradientPainting.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include namespace Web::Painting {