diff --git a/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp b/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp index 9155305b1cf..8b676e5a1ee 100644 --- a/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp +++ b/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp @@ -2360,11 +2360,17 @@ Optional Parser::parse_url_function(ComponentValue const& component_val RefPtr Parser::parse_linear_gradient_function(ComponentValue const& component_value) { + using GradientType = LinearGradientStyleValue::GradientType; + if (!component_value.is_function()) return {}; auto function_name = component_value.function().name(); - if (!function_name.is_one_of_ignoring_case("linear-gradient"sv, "-webkit-linear-gradient"sv)) + + GradientType gradient_type { GradientType::Standard }; + if (function_name.equals_ignoring_case("-webkit-linear-gradient"sv)) + gradient_type = GradientType::WebKit; + else if (!function_name.equals_ignoring_case("linear-gradient"sv)) return {}; // linear-gradient() = linear-gradient([ | to ]?, ) @@ -2376,7 +2382,29 @@ RefPtr Parser::parse_linear_gradient_function(ComponentValue const& return {}; bool has_direction_param = true; - LinearGradientStyleValue::GradientDirection gradient_direction = SideOrCorner::Bottom; + LinearGradientStyleValue::GradientDirection gradient_direction = gradient_type == GradientType::Standard + ? SideOrCorner::Bottom + : SideOrCorner::Top; + + auto to_side = [](StringView value) -> Optional { + if (value.equals_ignoring_case("top"sv)) + return SideOrCorner::Top; + if (value.equals_ignoring_case("bottom"sv)) + return SideOrCorner::Bottom; + if (value.equals_ignoring_case("left"sv)) + return SideOrCorner::Left; + if (value.equals_ignoring_case("right"sv)) + return SideOrCorner::Right; + return {}; + }; + + auto is_to_side_or_corner = [&](auto const& token) { + if (!token.is(Token::Type::Ident)) + return false; + if (gradient_type == GradientType::WebKit) + return to_side(token.token().ident()).has_value(); + return token.token().ident().equals_ignoring_case("to"sv); + }; auto& first_param = tokens.peek_token(); if (first_param.is(Token::Type::Dimension)) { @@ -2390,31 +2418,24 @@ RefPtr Parser::parse_linear_gradient_function(ComponentValue const& return {}; gradient_direction = Angle { angle_value, angle_type.release_value() }; - } else if (first_param.is(Token::Type::Ident) && first_param.token().ident().equals_ignoring_case("to"sv)) { + } else if (is_to_side_or_corner(first_param)) { // = [left | right] || [top | bottom] - tokens.next_token(); - tokens.skip_whitespace(); - auto to_side = [](StringView value) -> Optional { - if (value.equals_ignoring_case("top"sv)) - return SideOrCorner::Top; - if (value.equals_ignoring_case("bottom"sv)) - return SideOrCorner::Bottom; - if (value.equals_ignoring_case("left"sv)) - return SideOrCorner::Left; - if (value.equals_ignoring_case("right"sv)) - return SideOrCorner::Right; - return {}; - }; + // Note: -webkit-linear-gradient does not include to the "to" prefix on the side or corner + if (gradient_type == GradientType::Standard) { + tokens.next_token(); + tokens.skip_whitespace(); - if (!tokens.has_next_token()) - return {}; + if (!tokens.has_next_token()) + return {}; + } // [left | right] || [top | bottom] - auto& second_param = tokens.next_token(); - if (!second_param.is(Token::Type::Ident)) + auto& first_side = tokens.next_token(); + if (!first_side.is(Token::Type::Ident)) return {}; - auto side_a = to_side(second_param.token().ident()); + + auto side_a = to_side(first_side.token().ident()); tokens.skip_whitespace(); Optional side_b; if (tokens.has_next_token() && tokens.peek_token().is(Token::Type::Ident)) @@ -2536,7 +2557,7 @@ RefPtr Parser::parse_linear_gradient_function(ComponentValue const& color_stops.append(list_element); } - return LinearGradientStyleValue::create(gradient_direction, move(color_stops)); + return LinearGradientStyleValue::create(gradient_direction, move(color_stops), gradient_type); } RefPtr Parser::convert_to_rule(NonnullRefPtr rule) diff --git a/Userland/Libraries/LibWeb/CSS/StyleValue.cpp b/Userland/Libraries/LibWeb/CSS/StyleValue.cpp index 520c699ab7f..234b947bc4e 100644 --- a/Userland/Libraries/LibWeb/CSS/StyleValue.cpp +++ b/Userland/Libraries/LibWeb/CSS/StyleValue.cpp @@ -1431,10 +1431,12 @@ String LinearGradientStyleValue::to_string() const } }; + if (m_gradient_type == GradientType::WebKit) + builder.append("-webkit-"sv); builder.append("linear-gradient("sv); m_direction.visit( [&](SideOrCorner side_or_corner) { - builder.appendff("to {}, "sv, side_or_corner_to_string(side_or_corner)); + builder.appendff("{}{}, "sv, m_gradient_type == GradientType::Standard ? "to "sv : ""sv, side_or_corner_to_string(side_or_corner)); }, [&](Angle const& angle) { builder.appendff("{}, "sv, angle.to_string()); @@ -1506,26 +1508,32 @@ float LinearGradientStyleValue::angle_degrees(Gfx::FloatRect const& gradient_rec }; return m_direction.visit( [&](SideOrCorner side_or_corner) { - 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(); - } + 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_gradient_type == GradientType::WebKit) + return angle + 180.0f; + return angle; }, [&](Angle const& angle) { return angle.to_degrees(); diff --git a/Userland/Libraries/LibWeb/CSS/StyleValue.h b/Userland/Libraries/LibWeb/CSS/StyleValue.h index 3bfccc5eec7..b28a579a1a2 100644 --- a/Userland/Libraries/LibWeb/CSS/StyleValue.h +++ b/Userland/Libraries/LibWeb/CSS/StyleValue.h @@ -933,10 +933,15 @@ class LinearGradientStyleValue final : public StyleValue { public: using GradientDirection = Variant; - static NonnullRefPtr create(GradientDirection direction, Vector color_stop_list) + enum class GradientType { + Standard, + WebKit + }; + + static NonnullRefPtr create(GradientDirection direction, Vector color_stop_list, GradientType type) { VERIFY(color_stop_list.size() >= 2); - return adopt_ref(*new LinearGradientStyleValue(direction, move(color_stop_list))); + return adopt_ref(*new LinearGradientStyleValue(direction, move(color_stop_list), type)); } virtual String to_string() const override; @@ -951,15 +956,17 @@ public: float angle_degrees(Gfx::FloatRect const& gradient_rect) const; private: - LinearGradientStyleValue(GradientDirection direction, Vector color_stop_list) + LinearGradientStyleValue(GradientDirection direction, Vector color_stop_list, GradientType type) : StyleValue(Type::LinearGradient) , m_direction(direction) , m_color_stop_list(move(color_stop_list)) + , m_gradient_type(type) { } GradientDirection m_direction; Vector m_color_stop_list; + GradientType m_gradient_type; }; class InheritStyleValue final : public StyleValue {