diff options
author | MacDue <macdue@dueutil.tech> | 2022-08-22 21:37:53 +0100 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2022-08-23 01:02:49 +0200 |
commit | 3a1f8d714a0afa03eadcbc6bb6cd35941383f1e2 (patch) | |
tree | d28ab472280e3e21956bb7d6e1c01a19f8c6d868 | |
parent | ec3d8a7a1837cb6b8667d7e03514821cc74ed27e (diff) | |
download | serenity-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.
-rw-r--r-- | Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp | 26 | ||||
-rw-r--r-- | Userland/Libraries/LibWeb/CSS/StyleValue.cpp | 7 | ||||
-rw-r--r-- | Userland/Libraries/LibWeb/CSS/StyleValue.h | 3 | ||||
-rw-r--r-- | Userland/Libraries/LibWeb/Painting/GradientPainting.cpp | 16 |
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(); |