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:
parent
d1b06af307
commit
476acae04f
4 changed files with 57 additions and 3 deletions
|
@ -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
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue