summaryrefslogtreecommitdiff
path: root/Userland
diff options
context:
space:
mode:
authorMacDue <macdue@dueutil.tech>2022-08-22 21:37:53 +0100
committerAndreas Kling <kling@serenityos.org>2022-08-23 01:02:49 +0200
commit3a1f8d714a0afa03eadcbc6bb6cd35941383f1e2 (patch)
treed28ab472280e3e21956bb7d6e1c01a19f8c6d868 /Userland
parentec3d8a7a1837cb6b8667d7e03514821cc74ed27e (diff)
downloadserenity-3a1f8d714a0afa03eadcbc6bb6cd35941383f1e2.zip
LibWeb: Parse double-position `linear-gradient()` color stops
The only accepted syntax for these seems to be <color> <length percentage> <length percentage>, no other order. But that's just gathered from looking at other browsers as though these are supported by all major browsers, they don't appear in the W3C spec.
Diffstat (limited to 'Userland')
-rw-r--r--Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp26
-rw-r--r--Userland/Libraries/LibWeb/CSS/StyleValue.cpp7
-rw-r--r--Userland/Libraries/LibWeb/CSS/StyleValue.h3
-rw-r--r--Userland/Libraries/LibWeb/Painting/GradientPainting.cpp16
4 files changed, 30 insertions, 22 deletions
diff --git a/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp b/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp
index 9bd1354946..da1ec16fc0 100644
--- a/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp
+++ b/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp
@@ -2509,15 +2509,16 @@ RefPtr<StyleValue> Parser::parse_linear_gradient_function(ComponentValue const&
auto& token = tokens.next_token();
Gfx::Color color;
- Optional<LengthPercentage> length;
+ Optional<LengthPercentage> position;
+ Optional<LengthPercentage> second_position;
auto dimension = parse_dimension(token);
if (dimension.has_value() && dimension->is_length_percentage()) {
// [<length-percentage> <color>] or [<length-percentage>]
- length = dimension->length_percentage();
+ position = dimension->length_percentage();
tokens.skip_whitespace();
// <length-percentage>
if (!tokens.has_next_token() || tokens.peek_token().is(Token::Type::Comma)) {
- element.transition_hint = GradientColorHint { *length };
+ element.transition_hint = GradientColorHint { *position };
return ElementType::ColorHint;
}
// <length-percentage> <color>
@@ -2532,16 +2533,21 @@ RefPtr<StyleValue> Parser::parse_linear_gradient_function(ComponentValue const&
return ElementType::Garbage;
color = *maybe_color;
tokens.skip_whitespace();
- if (tokens.has_next_token() && !tokens.peek_token().is(Token::Type::Comma)) {
- auto token = tokens.next_token();
- auto dimension = parse_dimension(token);
- if (!dimension.has_value() || !dimension->is_length_percentage())
- return ElementType::Garbage;
- length = dimension->length_percentage();
+ // Allow up to [<color> <length-percentage> <length-percentage>] (double-position color stops)
+ // Note: Double-position color stops only appear to be valid in this order.
+ for (auto stop_position : Array { &position, &second_position }) {
+ if (tokens.has_next_token() && !tokens.peek_token().is(Token::Type::Comma)) {
+ auto token = tokens.next_token();
+ auto dimension = parse_dimension(token);
+ if (!dimension.has_value() || !dimension->is_length_percentage())
+ return ElementType::Garbage;
+ *stop_position = dimension->length_percentage();
+ tokens.skip_whitespace();
+ }
}
}
- element.color_stop = GradientColorStop { color, length };
+ element.color_stop = GradientColorStop { color, position, second_position };
return ElementType::ColorStop;
};
diff --git a/Userland/Libraries/LibWeb/CSS/StyleValue.cpp b/Userland/Libraries/LibWeb/CSS/StyleValue.cpp
index daa59d3920..4e8f892c45 100644
--- a/Userland/Libraries/LibWeb/CSS/StyleValue.cpp
+++ b/Userland/Libraries/LibWeb/CSS/StyleValue.cpp
@@ -1512,8 +1512,9 @@ String LinearGradientStyleValue::to_string() const
}
serialize_a_srgb_value(builder, element.color_stop.color);
- if (element.color_stop.length.has_value()) {
- builder.appendff(" {}"sv, element.color_stop.length->to_string());
+ for (auto position : Array { &element.color_stop.position, &element.color_stop.second_position }) {
+ if (position->has_value())
+ builder.appendff(" {}"sv, (*position)->to_string());
}
first = false;
}
@@ -1537,7 +1538,7 @@ static bool operator==(GradientColorHint a, GradientColorHint b)
static bool operator==(GradientColorStop a, GradientColorStop b)
{
- return a.color == b.color && a.length == b.length;
+ return a.color == b.color && a.position == b.position && a.second_position == b.second_position;
}
static bool operator==(ColorStopListElement a, ColorStopListElement b)
diff --git a/Userland/Libraries/LibWeb/CSS/StyleValue.h b/Userland/Libraries/LibWeb/CSS/StyleValue.h
index 89ed09e583..38a0e0f3b6 100644
--- a/Userland/Libraries/LibWeb/CSS/StyleValue.h
+++ b/Userland/Libraries/LibWeb/CSS/StyleValue.h
@@ -74,7 +74,8 @@ enum class SideOrCorner {
struct GradientColorStop {
Color color;
- Optional<LengthPercentage> length;
+ Optional<LengthPercentage> position;
+ Optional<LengthPercentage> second_position = {};
};
struct GradientColorHint {
diff --git a/Userland/Libraries/LibWeb/Painting/GradientPainting.cpp b/Userland/Libraries/LibWeb/Painting/GradientPainting.cpp
index 3d1fcdc3fa..7cdb49bd72 100644
--- a/Userland/Libraries/LibWeb/Painting/GradientPainting.cpp
+++ b/Userland/Libraries/LibWeb/Painting/GradientPainting.cpp
@@ -49,13 +49,13 @@ LinearGradientData resolve_linear_gradient_data(Layout::Node const& node, Gfx::F
// 1. If the first color stop does not have a position, set its position to 0%.
auto& first_stop = color_stop_list.first().color_stop;
- resolved_color_stops.first().position = first_stop.length.has_value()
- ? first_stop.length->resolved(node, gradient_length).to_px(node)
+ resolved_color_stops.first().position = first_stop.position.has_value()
+ ? first_stop.position->resolved(node, gradient_length).to_px(node)
: 0;
// If the last color stop does not have a position, set its position to 100%
auto& last_stop = color_stop_list.last().color_stop;
- resolved_color_stops.last().position = last_stop.length.has_value()
- ? last_stop.length->resolved(node, gradient_length).to_px(node)
+ resolved_color_stops.last().position = last_stop.position.has_value()
+ ? last_stop.position->resolved(node, gradient_length).to_px(node)
: gradient_length_px;
// 2. If a color stop or transition hint has a position that is less than the
@@ -71,8 +71,8 @@ LinearGradientData resolve_linear_gradient_data(Layout::Node const& node, Gfx::F
resolved_color_stops[i].transition_hint = value;
max_previous_color_stop_or_hint = value;
}
- if (stop.color_stop.length.has_value()) {
- float value = stop.color_stop.length->resolved(node, gradient_length).to_px(node);
+ if (stop.color_stop.position.has_value()) {
+ float value = stop.color_stop.position->resolved(node, gradient_length).to_px(node);
value = max(value, max_previous_color_stop_or_hint);
resolved_color_stops[i].position = value;
max_previous_color_stop_or_hint = value;
@@ -86,7 +86,7 @@ LinearGradientData resolve_linear_gradient_data(Layout::Node const& node, Gfx::F
size_t i = 1;
auto find_run_end = [&] {
auto color_stop_has_position = [](auto& color_stop) {
- return color_stop.transition_hint.has_value() || color_stop.color_stop.length.has_value();
+ return color_stop.transition_hint.has_value() || color_stop.color_stop.position.has_value();
};
while (i < color_stop_list.size() - 1 && !color_stop_has_position(color_stop_list[i])) {
i++;
@@ -95,7 +95,7 @@ LinearGradientData resolve_linear_gradient_data(Layout::Node const& node, Gfx::F
};
while (i < color_stop_list.size() - 1) {
auto& stop = color_stop_list[i];
- if (!stop.color_stop.length.has_value()) {
+ if (!stop.color_stop.position.has_value()) {
auto run_start = i - 1;
auto start_position = resolved_color_stops[i++].transition_hint.value_or(resolved_color_stops[run_start].position);
auto run_end = find_run_end();