mirror of
https://github.com/RGBCube/serenity
synced 2025-07-27 15:57:35 +00:00
LibWeb: Handle degenerate radial gradients
This commit is contained in:
parent
476acae04f
commit
65acfe6c60
2 changed files with 35 additions and 6 deletions
|
@ -2086,7 +2086,7 @@ Gfx::FloatSize RadialGradientStyleValue::resolve_size(Layout::Node const& node,
|
|||
};
|
||||
|
||||
// https://w3c.github.io/csswg-drafts/css-images/#radial-gradient-syntax
|
||||
return m_size.visit(
|
||||
auto resolved_size = m_size.visit(
|
||||
[&](Extent extent) {
|
||||
switch (extent) {
|
||||
case Extent::ClosestSide:
|
||||
|
@ -2117,6 +2117,35 @@ Gfx::FloatSize RadialGradientStyleValue::resolve_size(Layout::Node const& node,
|
|||
auto radius_b = ellipse_size.radius_b.resolved(node, CSS::Length::make_px(size.height())).to_px(node);
|
||||
return Gfx::FloatSize { radius_a, radius_b };
|
||||
});
|
||||
|
||||
// Handle degenerate cases
|
||||
// https://w3c.github.io/csswg-drafts/css-images/#degenerate-radials
|
||||
|
||||
constexpr auto arbitrary_small_number = 1e-10;
|
||||
constexpr auto arbitrary_large_number = 1e10;
|
||||
|
||||
// If the ending shape is a circle with zero radius:
|
||||
if (m_ending_shape == EndingShape::Circle && resolved_size.is_empty()) {
|
||||
// Render as if the ending shape was a circle whose radius was an arbitrary very small number greater than zero.
|
||||
// This will make the gradient continue to look like a circle.
|
||||
return Gfx::FloatSize { arbitrary_small_number, arbitrary_small_number };
|
||||
}
|
||||
// If the ending shape has zero width (regardless of the height):
|
||||
if (resolved_size.width() <= 0) {
|
||||
// Render as if the ending shape was an ellipse whose height was an arbitrary very large number
|
||||
// and whose width was an arbitrary very small number greater than zero.
|
||||
// This will make the gradient look similar to a horizontal linear gradient that is mirrored across the center of the ellipse.
|
||||
// It also means that all color-stop positions specified with a percentage resolve to 0px.
|
||||
return Gfx::FloatSize { arbitrary_small_number, arbitrary_large_number };
|
||||
}
|
||||
// Otherwise, if the ending shape has zero height:
|
||||
if (resolved_size.height() <= 0) {
|
||||
// Render as if the ending shape was an ellipse whose width was an arbitrary very large number and whose height
|
||||
// was an arbitrary very small number greater than zero. This will make the gradient look like a solid-color image equal
|
||||
// to the color of the last color-stop, or equal to the average color of the gradient if it’s repeating.
|
||||
return Gfx::FloatSize { arbitrary_large_number, arbitrary_small_number };
|
||||
}
|
||||
return resolved_size;
|
||||
}
|
||||
|
||||
void RadialGradientStyleValue::resolve_for_size(Layout::Node const& node, Gfx::FloatSize const& paint_size) const
|
||||
|
|
|
@ -220,19 +220,19 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
Gfx::Color get_color(int index) const
|
||||
Gfx::Color get_color(uint64_t index) const
|
||||
{
|
||||
return m_gradient_line_colors[clamp(index, 0, m_gradient_line_colors.size() - 1)];
|
||||
}
|
||||
|
||||
Gfx::Color sample_color(float loc) const
|
||||
{
|
||||
auto repeat_wrap_if_required = [&](int loc) {
|
||||
auto repeat_wrap_if_required = [&](uint64_t loc) {
|
||||
if (m_repeating)
|
||||
return (loc + m_start_offset) % static_cast<int>(m_gradient_line_colors.size());
|
||||
return (loc + m_start_offset) % m_gradient_line_colors.size();
|
||||
return loc;
|
||||
};
|
||||
auto int_loc = static_cast<int>(floor(loc));
|
||||
auto int_loc = static_cast<uint64_t>(floor(loc));
|
||||
auto blend = loc - int_loc;
|
||||
auto color = get_color(repeat_wrap_if_required(int_loc));
|
||||
// Blend between the two neighbouring colors (this fixes some nasty aliasing issues at small angles)
|
||||
|
@ -314,7 +314,7 @@ void paint_radial_gradient(PaintContext& context, Gfx::IntRect const& gradient_r
|
|||
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();
|
||||
return AK::sqrt(gradient_x * gradient_x + gradient_y * gradient_y) * max_visible_gradient;
|
||||
});
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue