mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-01-07 19:57:45 +03:00
LibWeb: Allow any valid <color>
in CSS gradients
We now keep the color value as a StyleValue up until we go to paint the gradient, which makes `currentColor` work, along with any other color values that can't be immediately converted into a `Gfx::Color` while parsing.
This commit is contained in:
parent
2971ae59d8
commit
631a988a57
Notes:
sideshowbarker
2024-07-17 04:57:23 +09:00
Author: https://github.com/AtkinsSJ Commit: https://github.com/SerenityOS/serenity/commit/631a988a57 Pull-request: https://github.com/SerenityOS/serenity/pull/20595
10
Tests/LibWeb/Ref/css-gradient-currentcolor-ref.html
Normal file
10
Tests/LibWeb/Ref/css-gradient-currentcolor-ref.html
Normal file
@ -0,0 +1,10 @@
|
||||
<html>
|
||||
<style>
|
||||
div {
|
||||
width: 200px;
|
||||
height: 200px;
|
||||
background: linear-gradient(green, white);
|
||||
}
|
||||
</style>
|
||||
<div></div>
|
||||
</html>
|
11
Tests/LibWeb/Ref/css-gradient-currentcolor.html
Normal file
11
Tests/LibWeb/Ref/css-gradient-currentcolor.html
Normal file
@ -0,0 +1,11 @@
|
||||
<html>
|
||||
<style>
|
||||
div {
|
||||
color: green;
|
||||
width: 200px;
|
||||
height: 200px;
|
||||
background: linear-gradient(currentColor, white);
|
||||
}
|
||||
</style>
|
||||
<div></div>
|
||||
</html>
|
@ -1,5 +1,6 @@
|
||||
{
|
||||
"square-flex.html": "square-ref.html",
|
||||
"separate-borders-inline-table.html": "separate-borders-ref.html",
|
||||
"opacity-stacking.html": "opacity-stacking-ref.html"
|
||||
"opacity-stacking.html": "opacity-stacking-ref.html",
|
||||
"css-gradient-currentcolor.html": "css-gradient-currentcolor-ref.html"
|
||||
}
|
||||
|
@ -2419,7 +2419,7 @@ static Optional<Vector<TElement>> parse_color_stop_list(auto& tokens, auto is_po
|
||||
return ElementType::Garbage;
|
||||
auto const& token = tokens.next_token();
|
||||
|
||||
Gfx::Color color;
|
||||
RefPtr<StyleValue> color;
|
||||
Optional<typename TElement::PositionType> position;
|
||||
Optional<typename TElement::PositionType> second_position;
|
||||
auto dimension = parse_dimension(token);
|
||||
@ -2434,15 +2434,15 @@ static Optional<Vector<TElement>> parse_color_stop_list(auto& tokens, auto is_po
|
||||
}
|
||||
// <T-percentage> <color>
|
||||
auto maybe_color = parse_color(tokens.next_token());
|
||||
if (!maybe_color.has_value())
|
||||
if (maybe_color.is_error())
|
||||
return ElementType::Garbage;
|
||||
color = *maybe_color;
|
||||
color = maybe_color.release_value();
|
||||
} else {
|
||||
// [<color> <T-percentage>?]
|
||||
auto maybe_color = parse_color(token);
|
||||
if (!maybe_color.has_value())
|
||||
if (maybe_color.is_error())
|
||||
return ElementType::Garbage;
|
||||
color = *maybe_color;
|
||||
color = maybe_color.release_value();
|
||||
tokens.skip_whitespace();
|
||||
// Allow up to [<color> <T-percentage> <T-percentage>] (double-position color stops)
|
||||
// Note: Double-position color stops only appear to be valid in this order.
|
||||
@ -2503,7 +2503,7 @@ Optional<Vector<LinearColorStopListElement>> Parser::parse_linear_color_stop_lis
|
||||
tokens,
|
||||
[](Dimension& dimension) { return dimension.is_length_percentage(); },
|
||||
[](Dimension& dimension) { return dimension.length_percentage(); },
|
||||
[&](auto& token) { return parse_color(token); },
|
||||
[&](auto& token) { return parse_color_value(token); },
|
||||
[&](auto& token) { return parse_dimension(token); });
|
||||
}
|
||||
|
||||
@ -2515,7 +2515,7 @@ Optional<Vector<AngularColorStopListElement>> Parser::parse_angular_color_stop_l
|
||||
tokens,
|
||||
[](Dimension& dimension) { return dimension.is_angle_percentage(); },
|
||||
[](Dimension& dimension) { return dimension.angle_percentage(); },
|
||||
[&](auto& token) { return parse_color(token); },
|
||||
[&](auto& token) { return parse_color_value(token); },
|
||||
[&](auto& token) { return parse_dimension(token); });
|
||||
}
|
||||
|
||||
|
@ -24,7 +24,7 @@ public:
|
||||
virtual Optional<CSSPixels> natural_height() const { return {}; }
|
||||
|
||||
virtual void load_any_resources(DOM::Document&) {};
|
||||
virtual void resolve_for_size(Layout::Node const&, CSSPixelSize) const {};
|
||||
virtual void resolve_for_size(Layout::NodeWithStyleAndBoxModelMetrics const&, CSSPixelSize) const {};
|
||||
|
||||
virtual bool is_paintable() const = 0;
|
||||
virtual void paint(PaintContext& context, DevicePixelRect const& dest_rect, ImageRendering) const = 0;
|
||||
@ -47,7 +47,7 @@ struct ColorStopListElement {
|
||||
|
||||
Optional<ColorHint> transition_hint;
|
||||
struct ColorStop {
|
||||
Color color;
|
||||
RefPtr<StyleValue> color;
|
||||
Optional<TPosition> position;
|
||||
Optional<TPosition> second_position = {};
|
||||
inline bool operator==(ColorStop const&) const = default;
|
||||
@ -69,7 +69,7 @@ static ErrorOr<void> serialize_color_stop_list(StringBuilder& builder, auto cons
|
||||
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));
|
||||
TRY(builder.try_append(TRY(element.color_stop.color->to_string())));
|
||||
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())));
|
||||
|
@ -8,6 +8,7 @@
|
||||
*/
|
||||
|
||||
#include "ConicGradientStyleValue.h"
|
||||
#include <LibWeb/Layout/Node.h>
|
||||
|
||||
namespace Web::CSS {
|
||||
|
||||
@ -34,7 +35,7 @@ ErrorOr<String> ConicGradientStyleValue::to_string() const
|
||||
return builder.to_string();
|
||||
}
|
||||
|
||||
void ConicGradientStyleValue::resolve_for_size(Layout::Node const& node, CSSPixelSize size) const
|
||||
void ConicGradientStyleValue::resolve_for_size(Layout::NodeWithStyleAndBoxModelMetrics const& node, CSSPixelSize size) const
|
||||
{
|
||||
if (!m_resolved.has_value())
|
||||
m_resolved = ResolvedData { Painting::resolve_conic_gradient_data(node, *this), {} };
|
||||
|
@ -39,7 +39,7 @@ public:
|
||||
|
||||
bool is_paintable() const override { return true; }
|
||||
|
||||
void resolve_for_size(Layout::Node const&, CSSPixelSize) const override;
|
||||
void resolve_for_size(Layout::NodeWithStyleAndBoxModelMetrics const&, CSSPixelSize) const override;
|
||||
|
||||
virtual ~ConicGradientStyleValue() override = default;
|
||||
|
||||
|
@ -102,7 +102,7 @@ float LinearGradientStyleValue::angle_degrees(CSSPixelSize gradient_size) const
|
||||
});
|
||||
}
|
||||
|
||||
void LinearGradientStyleValue::resolve_for_size(Layout::Node const& node, CSSPixelSize size) const
|
||||
void LinearGradientStyleValue::resolve_for_size(Layout::NodeWithStyleAndBoxModelMetrics const& node, CSSPixelSize size) const
|
||||
{
|
||||
if (m_resolved.has_value() && m_resolved->size == size)
|
||||
return;
|
||||
|
@ -57,7 +57,7 @@ public:
|
||||
|
||||
float angle_degrees(CSSPixelSize gradient_size) const;
|
||||
|
||||
void resolve_for_size(Layout::Node const&, CSSPixelSize) const override;
|
||||
void resolve_for_size(Layout::NodeWithStyleAndBoxModelMetrics 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;
|
||||
|
@ -8,6 +8,7 @@
|
||||
*/
|
||||
|
||||
#include "RadialGradientStyleValue.h"
|
||||
#include <LibWeb/Layout/Node.h>
|
||||
|
||||
namespace Web::CSS {
|
||||
|
||||
@ -184,7 +185,7 @@ Gfx::FloatSize RadialGradientStyleValue::resolve_size(Layout::Node const& node,
|
||||
return resolved_size;
|
||||
}
|
||||
|
||||
void RadialGradientStyleValue::resolve_for_size(Layout::Node const& node, CSSPixelSize paint_size) const
|
||||
void RadialGradientStyleValue::resolve_for_size(Layout::NodeWithStyleAndBoxModelMetrics const& node, CSSPixelSize paint_size) const
|
||||
{
|
||||
CSSPixelRect gradient_box { { 0, 0 }, paint_size };
|
||||
auto center = m_properties.position.resolved(node, gradient_box).to_type<float>();
|
||||
|
@ -63,7 +63,7 @@ public:
|
||||
|
||||
bool is_paintable() const override { return true; }
|
||||
|
||||
void resolve_for_size(Layout::Node const&, CSSPixelSize) const override;
|
||||
void resolve_for_size(Layout::NodeWithStyleAndBoxModelMetrics const&, CSSPixelSize) const override;
|
||||
|
||||
Gfx::FloatSize resolve_size(Layout::Node const&, Gfx::FloatPoint, Gfx::FloatRect const&) const;
|
||||
|
||||
|
@ -10,11 +10,12 @@
|
||||
#include <LibWeb/CSS/StyleValues/ConicGradientStyleValue.h>
|
||||
#include <LibWeb/CSS/StyleValues/LinearGradientStyleValue.h>
|
||||
#include <LibWeb/CSS/StyleValues/RadialGradientStyleValue.h>
|
||||
#include <LibWeb/Layout/Node.h>
|
||||
#include <LibWeb/Painting/GradientPainting.h>
|
||||
|
||||
namespace Web::Painting {
|
||||
|
||||
static ColorStopData resolve_color_stop_positions(auto const& color_stop_list, auto resolve_position_to_float, bool repeating)
|
||||
static ColorStopData resolve_color_stop_positions(Layout::NodeWithStyleAndBoxModelMetrics const& node, auto const& color_stop_list, auto resolve_position_to_float, bool repeating)
|
||||
{
|
||||
VERIFY(color_stop_list.size() >= 2);
|
||||
ColorStopList resolved_color_stops;
|
||||
@ -29,7 +30,7 @@ static ColorStopData resolve_color_stop_positions(auto const& color_stop_list, a
|
||||
|
||||
resolved_color_stops.ensure_capacity(expanded_size);
|
||||
for (auto& stop : color_stop_list) {
|
||||
auto resolved_stop = Gfx::ColorStop { .color = stop.color_stop.color };
|
||||
auto resolved_stop = Gfx::ColorStop { .color = stop.color_stop.color->to_color(node) };
|
||||
for (int i = 0; i < color_stop_length(stop); i++)
|
||||
resolved_color_stops.append(resolved_stop);
|
||||
}
|
||||
@ -109,13 +110,13 @@ static ColorStopData resolve_color_stop_positions(auto const& color_stop_list, a
|
||||
return { resolved_color_stops, repeat_length };
|
||||
}
|
||||
|
||||
LinearGradientData resolve_linear_gradient_data(Layout::Node const& node, CSSPixelSize gradient_size, CSS::LinearGradientStyleValue const& linear_gradient)
|
||||
LinearGradientData resolve_linear_gradient_data(Layout::NodeWithStyleAndBoxModelMetrics const& node, CSSPixelSize gradient_size, CSS::LinearGradientStyleValue const& linear_gradient)
|
||||
{
|
||||
auto gradient_angle = linear_gradient.angle_degrees(gradient_size);
|
||||
auto gradient_length_px = Gfx::calculate_gradient_length(gradient_size.to_type<float>(), gradient_angle);
|
||||
|
||||
auto resolved_color_stops = resolve_color_stop_positions(
|
||||
linear_gradient.color_stop_list(), [&](auto const& length_percentage) {
|
||||
node, linear_gradient.color_stop_list(), [&](auto const& length_percentage) {
|
||||
return length_percentage.to_px(node, gradient_length_px).to_float() / static_cast<float>(gradient_length_px);
|
||||
},
|
||||
linear_gradient.is_repeating());
|
||||
@ -123,22 +124,22 @@ LinearGradientData resolve_linear_gradient_data(Layout::Node const& node, CSSPix
|
||||
return { gradient_angle, resolved_color_stops };
|
||||
}
|
||||
|
||||
ConicGradientData resolve_conic_gradient_data(Layout::Node const& node, CSS::ConicGradientStyleValue const& conic_gradient)
|
||||
ConicGradientData resolve_conic_gradient_data(Layout::NodeWithStyleAndBoxModelMetrics const& node, CSS::ConicGradientStyleValue const& conic_gradient)
|
||||
{
|
||||
CSS::Angle one_turn(360.0f, CSS::Angle::Type::Deg);
|
||||
auto resolved_color_stops = resolve_color_stop_positions(
|
||||
conic_gradient.color_stop_list(), [&](auto const& angle_percentage) {
|
||||
node, conic_gradient.color_stop_list(), [&](auto const& angle_percentage) {
|
||||
return angle_percentage.resolved(node, one_turn).to_degrees() / one_turn.to_degrees();
|
||||
},
|
||||
conic_gradient.is_repeating());
|
||||
return { conic_gradient.angle_degrees(), resolved_color_stops };
|
||||
}
|
||||
|
||||
RadialGradientData resolve_radial_gradient_data(Layout::Node const& node, CSSPixelSize gradient_size, CSS::RadialGradientStyleValue const& radial_gradient)
|
||||
RadialGradientData resolve_radial_gradient_data(Layout::NodeWithStyleAndBoxModelMetrics const& node, CSSPixelSize gradient_size, CSS::RadialGradientStyleValue const& radial_gradient)
|
||||
{
|
||||
// Start center, goes right to ending point, where the gradient line intersects the ending shape
|
||||
auto resolved_color_stops = resolve_color_stop_positions(
|
||||
radial_gradient.color_stop_list(), [&](auto const& length_percentage) {
|
||||
node, radial_gradient.color_stop_list(), [&](auto const& length_percentage) {
|
||||
return (length_percentage.to_px(node, gradient_size.width()) / gradient_size.width()).to_float();
|
||||
},
|
||||
radial_gradient.is_repeating());
|
||||
|
@ -36,9 +36,9 @@ struct RadialGradientData {
|
||||
ColorStopData color_stops;
|
||||
};
|
||||
|
||||
LinearGradientData resolve_linear_gradient_data(Layout::Node const&, CSSPixelSize, CSS::LinearGradientStyleValue const&);
|
||||
ConicGradientData resolve_conic_gradient_data(Layout::Node const&, CSS::ConicGradientStyleValue const&);
|
||||
RadialGradientData resolve_radial_gradient_data(Layout::Node const&, CSSPixelSize, CSS::RadialGradientStyleValue const&);
|
||||
LinearGradientData resolve_linear_gradient_data(Layout::NodeWithStyleAndBoxModelMetrics const&, CSSPixelSize, CSS::LinearGradientStyleValue const&);
|
||||
ConicGradientData resolve_conic_gradient_data(Layout::NodeWithStyleAndBoxModelMetrics const&, CSS::ConicGradientStyleValue const&);
|
||||
RadialGradientData resolve_radial_gradient_data(Layout::NodeWithStyleAndBoxModelMetrics const&, CSSPixelSize, CSS::RadialGradientStyleValue const&);
|
||||
|
||||
void paint_linear_gradient(PaintContext&, DevicePixelRect const&, LinearGradientData const&);
|
||||
void paint_conic_gradient(PaintContext&, DevicePixelRect const&, ConicGradientData const&, DevicePixelPoint position);
|
||||
|
Loading…
Reference in New Issue
Block a user