/src/serenity/Userland/Libraries/LibWeb/CSS/StyleValues/LinearGradientStyleValue.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> |
3 | | * Copyright (c) 2021, Tobias Christiansen <tobyase@serenityos.org> |
4 | | * Copyright (c) 2021-2023, Sam Atkins <atkinssj@serenityos.org> |
5 | | * Copyright (c) 2022-2023, MacDue <macdue@dueutil.tech> |
6 | | * |
7 | | * SPDX-License-Identifier: BSD-2-Clause |
8 | | */ |
9 | | |
10 | | #include "LinearGradientStyleValue.h" |
11 | | |
12 | | namespace Web::CSS { |
13 | | |
14 | | String LinearGradientStyleValue::to_string() const |
15 | 0 | { |
16 | 0 | StringBuilder builder; |
17 | 0 | auto side_or_corner_to_string = [](SideOrCorner value) { |
18 | 0 | switch (value) { |
19 | 0 | case SideOrCorner::Top: |
20 | 0 | return "top"sv; |
21 | 0 | case SideOrCorner::Bottom: |
22 | 0 | return "bottom"sv; |
23 | 0 | case SideOrCorner::Left: |
24 | 0 | return "left"sv; |
25 | 0 | case SideOrCorner::Right: |
26 | 0 | return "right"sv; |
27 | 0 | case SideOrCorner::TopLeft: |
28 | 0 | return "top left"sv; |
29 | 0 | case SideOrCorner::TopRight: |
30 | 0 | return "top right"sv; |
31 | 0 | case SideOrCorner::BottomLeft: |
32 | 0 | return "bottom left"sv; |
33 | 0 | case SideOrCorner::BottomRight: |
34 | 0 | return "bottom right"sv; |
35 | 0 | default: |
36 | 0 | VERIFY_NOT_REACHED(); |
37 | 0 | } |
38 | 0 | }; |
39 | |
|
40 | 0 | if (m_properties.gradient_type == GradientType::WebKit) |
41 | 0 | builder.append("-webkit-"sv); |
42 | 0 | if (is_repeating()) |
43 | 0 | builder.append("repeating-"sv); |
44 | 0 | builder.append("linear-gradient("sv); |
45 | 0 | m_properties.direction.visit( |
46 | 0 | [&](SideOrCorner side_or_corner) { |
47 | 0 | return builder.appendff("{}{}, "sv, m_properties.gradient_type == GradientType::Standard ? "to "sv : ""sv, side_or_corner_to_string(side_or_corner)); |
48 | 0 | }, |
49 | 0 | [&](Angle const& angle) { |
50 | 0 | return builder.appendff("{}, "sv, angle.to_string()); |
51 | 0 | }); |
52 | |
|
53 | 0 | serialize_color_stop_list(builder, m_properties.color_stop_list); |
54 | 0 | builder.append(")"sv); |
55 | 0 | return MUST(builder.to_string()); |
56 | 0 | } |
57 | | |
58 | | bool LinearGradientStyleValue::equals(CSSStyleValue const& other_) const |
59 | 0 | { |
60 | 0 | if (type() != other_.type()) |
61 | 0 | return false; |
62 | 0 | auto& other = other_.as_linear_gradient(); |
63 | 0 | return m_properties == other.m_properties; |
64 | 0 | } |
65 | | |
66 | | float LinearGradientStyleValue::angle_degrees(CSSPixelSize gradient_size) const |
67 | 0 | { |
68 | 0 | auto corner_angle_degrees = [&] { |
69 | 0 | return AK::to_degrees(atan2(gradient_size.height().to_double(), gradient_size.width().to_double())); |
70 | 0 | }; |
71 | 0 | return m_properties.direction.visit( |
72 | 0 | [&](SideOrCorner side_or_corner) { |
73 | 0 | auto angle = [&] { |
74 | 0 | switch (side_or_corner) { |
75 | 0 | case SideOrCorner::Top: |
76 | 0 | return 0.0; |
77 | 0 | case SideOrCorner::Bottom: |
78 | 0 | return 180.0; |
79 | 0 | case SideOrCorner::Left: |
80 | 0 | return 270.0; |
81 | 0 | case SideOrCorner::Right: |
82 | 0 | return 90.0; |
83 | 0 | case SideOrCorner::TopRight: |
84 | 0 | return corner_angle_degrees(); |
85 | 0 | case SideOrCorner::BottomLeft: |
86 | 0 | return corner_angle_degrees() + 180.0; |
87 | 0 | case SideOrCorner::TopLeft: |
88 | 0 | return -corner_angle_degrees(); |
89 | 0 | case SideOrCorner::BottomRight: |
90 | 0 | return -(corner_angle_degrees() + 180.0); |
91 | 0 | default: |
92 | 0 | VERIFY_NOT_REACHED(); |
93 | 0 | } |
94 | 0 | }(); |
95 | | // Note: For unknowable reasons the angles are opposite on the -webkit- version |
96 | 0 | if (m_properties.gradient_type == GradientType::WebKit) |
97 | 0 | return angle + 180.0; |
98 | 0 | return angle; |
99 | 0 | }, |
100 | 0 | [&](Angle const& angle) { |
101 | 0 | return angle.to_degrees(); |
102 | 0 | }); |
103 | 0 | } |
104 | | |
105 | | void LinearGradientStyleValue::resolve_for_size(Layout::NodeWithStyleAndBoxModelMetrics const& node, CSSPixelSize size) const |
106 | 0 | { |
107 | 0 | if (m_resolved.has_value() && m_resolved->size == size) |
108 | 0 | return; |
109 | 0 | m_resolved = ResolvedData { Painting::resolve_linear_gradient_data(node, size, *this), size }; |
110 | 0 | } |
111 | | |
112 | | void LinearGradientStyleValue::paint(PaintContext& context, DevicePixelRect const& dest_rect, CSS::ImageRendering, Vector<Gfx::Path> const& clip_paths) const |
113 | 0 | { |
114 | 0 | VERIFY(m_resolved.has_value()); |
115 | 0 | context.display_list_recorder().fill_rect_with_linear_gradient(dest_rect.to_type<int>(), m_resolved->data, clip_paths); |
116 | 0 | } |
117 | | |
118 | | } |