1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-26 02:17:34 +00:00

LibWeb: Paint radial-gradient()s

This almost looks too easy now :^), but it's just another way to sample
the gradient line.
This commit is contained in:
MacDue 2022-11-13 00:33:42 +00:00 committed by Sam Atkins
parent d1b06af307
commit 476acae04f
4 changed files with 57 additions and 3 deletions

View file

@ -2119,8 +2119,18 @@ Gfx::FloatSize RadialGradientStyleValue::resolve_size(Layout::Node const& node,
}); });
} }
void RadialGradientStyleValue::resolve_for_size(Layout::Node const&, Gfx::FloatSize const&) const void RadialGradientStyleValue::resolve_for_size(Layout::Node const& node, Gfx::FloatSize const& paint_size) const
{ {
Gfx::FloatRect gradient_box { { 0, 0 }, paint_size };
auto center = m_position.resolved(node, gradient_box);
auto gradient_size = resolve_size(node, center, gradient_box);
if (m_resolved.has_value() && m_resolved->gradient_size == gradient_size)
return;
m_resolved = ResolvedData {
Painting::resolve_radial_gradient_data(node, gradient_size, *this),
gradient_size,
center,
};
} }
bool RadialGradientStyleValue::equals(StyleValue const& other) const bool RadialGradientStyleValue::equals(StyleValue const& other) const
@ -2134,8 +2144,10 @@ bool RadialGradientStyleValue::equals(StyleValue const& other) const
&& m_color_stop_list == other_gradient.m_color_stop_list); && m_color_stop_list == other_gradient.m_color_stop_list);
} }
void RadialGradientStyleValue::paint(PaintContext&, Gfx::IntRect const&, CSS::ImageRendering) const void RadialGradientStyleValue::paint(PaintContext& context, Gfx::IntRect const& dest_rect, CSS::ImageRendering) const
{ {
VERIFY(m_resolved.has_value());
Painting::paint_radial_gradient(context, dest_rect, m_resolved->data, m_resolved->center.to_rounded<int>(), m_resolved->gradient_size);
} }
String ConicGradientStyleValue::to_string() const String ConicGradientStyleValue::to_string() const

View file

@ -1271,6 +1271,14 @@ private:
Size m_size; Size m_size;
PositionValue m_position; PositionValue m_position;
Vector<LinearColorStopListElement> m_color_stop_list; Vector<LinearColorStopListElement> m_color_stop_list;
struct ResolvedData {
Painting::RadialGradientData data;
Gfx::FloatSize gradient_size;
Gfx::FloatPoint center;
};
mutable Optional<ResolvedData> m_resolved;
}; };
class ConicGradientStyleValue final : public AbstractImageStyleValue { class ConicGradientStyleValue final : public AbstractImageStyleValue {

View file

@ -155,6 +155,18 @@ ConicGradientData resolve_conic_gradient_data(Layout::Node const& node, CSS::Con
return { conic_gradient.angle_degrees(), resolved_color_stops }; return { conic_gradient.angle_degrees(), resolved_color_stops };
} }
RadialGradientData resolve_radial_gradient_data(Layout::Node const& node, Gfx::FloatSize const& gradient_size, CSS::RadialGradientStyleValue const& radial_gradient)
{
// Start center, goes right to ending point, where the gradient line intersects the ending shape
auto gradient_length = CSS::Length::make_px(gradient_size.width());
auto resolved_color_stops = resolve_color_stop_positions(
radial_gradient.color_stop_list(), [&](auto const& length_percentage) {
return length_percentage.resolved(node, gradient_length).to_px(node) / gradient_size.width();
},
false);
return { resolved_color_stops };
}
static float color_stop_step(ColorStop const& previous_stop, ColorStop const& next_stop, float position) static float color_stop_step(ColorStop const& previous_stop, ColorStop const& next_stop, float position)
{ {
if (position < previous_stop.position) if (position < previous_stop.position)
@ -229,7 +241,7 @@ public:
return color; return color;
} }
void paint_into_rect(Gfx::Painter& painter, Gfx::IntRect const& rect, auto location_transform) ALWAYS_INLINE void paint_into_rect(Gfx::Painter& painter, Gfx::IntRect const& rect, auto location_transform)
{ {
for (int y = 0; y < rect.height(); y++) { for (int y = 0; y < rect.height(); y++) {
for (int x = 0; x < rect.width(); x++) { for (int x = 0; x < rect.width(); x++) {
@ -290,4 +302,20 @@ void paint_conic_gradient(PaintContext& context, Gfx::IntRect const& gradient_re
}); });
} }
void paint_radial_gradient(PaintContext& context, Gfx::IntRect const& gradient_rect, RadialGradientData const& data, Gfx::IntPoint center, Gfx::FloatSize const& size)
{
// A conservative guesstimate on how many colors we need to generate:
auto max_dimension = max(gradient_rect.width(), gradient_rect.height());
int max_visible_gradient = max(max_dimension / 2, min(size.width(), max_dimension));
GradientLine gradient_line(max_visible_gradient, data.color_stops);
auto center_point = Gfx::FloatPoint { center }.translated(0.5, 0.5);
gradient_line.paint_into_rect(context.painter(), gradient_rect, [&](int x, int y) {
// FIXME: See if there's a more efficient calculation we do there :^)
auto point = (Gfx::FloatPoint { x, y } - center_point);
auto gradient_x = point.x() / size.width();
auto gradient_y = point.y() / size.height();
return AK::sqrt(gradient_x * gradient_x + gradient_y * gradient_y) * size.width();
});
}
} }

View file

@ -37,10 +37,16 @@ struct ConicGradientData {
ColorStopData color_stops; ColorStopData color_stops;
}; };
struct RadialGradientData {
ColorStopData color_stops;
};
LinearGradientData resolve_linear_gradient_data(Layout::Node const&, Gfx::FloatSize const&, CSS::LinearGradientStyleValue const&); LinearGradientData resolve_linear_gradient_data(Layout::Node const&, Gfx::FloatSize const&, CSS::LinearGradientStyleValue const&);
ConicGradientData resolve_conic_gradient_data(Layout::Node const&, CSS::ConicGradientStyleValue const&); ConicGradientData resolve_conic_gradient_data(Layout::Node const&, CSS::ConicGradientStyleValue const&);
RadialGradientData resolve_radial_gradient_data(Layout::Node const&, Gfx::FloatSize const&, CSS::RadialGradientStyleValue const&);
void paint_linear_gradient(PaintContext&, Gfx::IntRect const&, LinearGradientData const&); void paint_linear_gradient(PaintContext&, Gfx::IntRect const&, LinearGradientData const&);
void paint_conic_gradient(PaintContext&, Gfx::IntRect const&, ConicGradientData const&, Gfx::IntPoint position); void paint_conic_gradient(PaintContext&, Gfx::IntRect const&, ConicGradientData const&, Gfx::IntPoint position);
void paint_radial_gradient(PaintContext&, Gfx::IntRect const&, RadialGradientData const&, Gfx::IntPoint position, Gfx::FloatSize const& size);
} }