diff --git a/Userland/Libraries/LibGfx/Point.h b/Userland/Libraries/LibGfx/Point.h index 545752c9d5..51062877f4 100644 --- a/Userland/Libraries/LibGfx/Point.h +++ b/Userland/Libraries/LibGfx/Point.h @@ -42,8 +42,8 @@ public: { } - [[nodiscard]] ALWAYS_INLINE T x() const { return m_x; } - [[nodiscard]] ALWAYS_INLINE T y() const { return m_y; } + [[nodiscard]] constexpr ALWAYS_INLINE T x() const { return m_x; } + [[nodiscard]] constexpr ALWAYS_INLINE T y() const { return m_y; } ALWAYS_INLINE void set_x(T x) { m_x = x; } ALWAYS_INLINE void set_y(T y) { m_y = y; } diff --git a/Userland/Libraries/LibWeb/CSS/StyleValues/RadialGradientStyleValue.cpp b/Userland/Libraries/LibWeb/CSS/StyleValues/RadialGradientStyleValue.cpp index dd71ca2d77..7982913c76 100644 --- a/Userland/Libraries/LibWeb/CSS/StyleValues/RadialGradientStyleValue.cpp +++ b/Userland/Libraries/LibWeb/CSS/StyleValues/RadialGradientStyleValue.cpp @@ -55,72 +55,72 @@ String RadialGradientStyleValue::to_string() const return MUST(builder.to_string()); } -Gfx::FloatSize RadialGradientStyleValue::resolve_size(Layout::Node const& node, Gfx::FloatPoint center, Gfx::FloatRect const& size) const +CSSPixelSize RadialGradientStyleValue::resolve_size(Layout::Node const& node, CSSPixelPoint center, CSSPixelRect const& size) const { auto const side_shape = [&](auto distance_function) { - auto const distance_from = [&](float v, float a, float b, auto distance_function) { - return distance_function(fabs(a - v), fabs(b - v)); + auto const distance_from = [&](CSSPixels v, CSSPixels a, CSSPixels b, auto distance_function) { + return distance_function(abs(a - v), abs(b - v)); }; auto x_dist = distance_from(center.x(), size.left(), size.right(), distance_function); auto y_dist = distance_from(center.y(), size.top(), size.bottom(), distance_function); if (m_properties.ending_shape == EndingShape::Circle) { auto dist = distance_function(x_dist, y_dist); - return Gfx::FloatSize { dist, dist }; + return CSSPixelSize { dist, dist }; } else { - return Gfx::FloatSize { x_dist, y_dist }; + return CSSPixelSize { x_dist, y_dist }; } }; auto const closest_side_shape = [&] { - return side_shape(AK::min); + return side_shape(AK::min); }; auto const farthest_side_shape = [&] { - return side_shape(AK::max); + return side_shape(AK::max); }; - auto const corner_distance = [&](auto distance_compare, Gfx::FloatPoint& corner) { - auto top_left_distance = size.top_left().distance_from(center); - auto top_right_distance = size.top_right().distance_from(center); - auto bottom_right_distance = size.bottom_right().distance_from(center); - auto bottom_left_distance = size.bottom_left().distance_from(center); - auto distance = top_left_distance; + auto const corner_distance = [&](auto distance_compare, CSSPixelPoint& corner) { + auto top_left_distance_squared = square_distance_between(size.top_left(), center); + auto top_right_distance_squared = square_distance_between(size.top_right(), center); + auto bottom_right_distance_squared = square_distance_between(size.bottom_right(), center); + auto bottom_left_distance_squared = square_distance_between(size.bottom_left(), center); + auto distance_squared = top_left_distance_squared; corner = size.top_left(); - if (distance_compare(top_right_distance, distance)) { + if (distance_compare(top_right_distance_squared, distance_squared)) { corner = size.top_right(); - distance = top_right_distance; + distance_squared = top_right_distance_squared; } - if (distance_compare(bottom_right_distance, distance)) { + if (distance_compare(bottom_right_distance_squared, distance_squared)) { corner = size.bottom_right(); - distance = bottom_right_distance; + distance_squared = bottom_right_distance_squared; } - if (distance_compare(bottom_left_distance, distance)) { + if (distance_compare(bottom_left_distance_squared, distance_squared)) { corner = size.bottom_left(); - distance = bottom_left_distance; + distance_squared = bottom_left_distance_squared; } - return distance; + return sqrt(distance_squared); }; - auto const closest_corner_distance = [&](Gfx::FloatPoint& corner) { - return corner_distance([](float a, float b) { return a < b; }, corner); + auto const closest_corner_distance = [&](CSSPixelPoint& corner) { + return corner_distance([](CSSPixels a, CSSPixels b) { return a < b; }, corner); }; - auto const farthest_corner_distance = [&](Gfx::FloatPoint& corner) { - return corner_distance([](float a, float b) { return a > b; }, corner); + auto const farthest_corner_distance = [&](CSSPixelPoint& corner) { + return corner_distance([](CSSPixels a, CSSPixels b) { return a > b; }, corner); }; auto const corner_shape = [&](auto corner_distance, auto get_shape) { - Gfx::FloatPoint corner {}; + CSSPixelPoint corner {}; auto distance = corner_distance(corner); if (m_properties.ending_shape == EndingShape::Ellipse) { auto shape = get_shape(); auto aspect_ratio = shape.width() / shape.height(); auto p = corner - center; - auto radius_a = AK::sqrt(p.y() * p.y() * aspect_ratio * aspect_ratio + p.x() * p.x()); + auto radius_a = sqrt(p.y() * p.y() * aspect_ratio * aspect_ratio + p.x() * p.x()); auto radius_b = radius_a / aspect_ratio; - return Gfx::FloatSize { radius_a, radius_b }; + return CSSPixelSize { radius_a, radius_b }; } - return Gfx::FloatSize { distance, distance }; + return CSSPixelSize { distance, distance }; }; // https://w3c.github.io/csswg-drafts/css-images/#radial-gradient-syntax @@ -148,25 +148,25 @@ Gfx::FloatSize RadialGradientStyleValue::resolve_size(Layout::Node const& node, }, [&](CircleSize const& circle_size) { auto radius = circle_size.radius.to_px(node); - return Gfx::FloatSize { radius.to_float(), radius.to_float() }; + return CSSPixelSize { radius, radius }; }, [&](EllipseSize const& ellipse_size) { - auto radius_a = ellipse_size.radius_a.resolved(node, CSSPixels::nearest_value_for(size.width())).to_px(node); - auto radius_b = ellipse_size.radius_b.resolved(node, CSSPixels::nearest_value_for(size.height())).to_px(node); - return Gfx::FloatSize { radius_a.to_float(), radius_b.to_float() }; + auto radius_a = ellipse_size.radius_a.resolved(node, size.width()).to_px(node); + auto radius_b = ellipse_size.radius_b.resolved(node, size.height()).to_px(node); + return CSSPixelSize { 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; + constexpr auto arbitrary_small_number = CSSPixels::smallest_positive_value(); + constexpr auto arbitrary_large_number = CSSPixels::max(); // If the ending shape is a circle with zero radius: if (m_properties.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 }; + return CSSPixelSize { arbitrary_small_number, arbitrary_small_number }; } // If the ending shape has zero width (regardless of the height): if (resolved_size.width() <= 0) { @@ -174,14 +174,14 @@ Gfx::FloatSize RadialGradientStyleValue::resolve_size(Layout::Node const& node, // 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 }; + return CSSPixelSize { 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 CSSPixelSize { arbitrary_large_number, arbitrary_small_number }; } return resolved_size; } @@ -189,12 +189,12 @@ Gfx::FloatSize RadialGradientStyleValue::resolve_size(Layout::Node const& node, void RadialGradientStyleValue::resolve_for_size(Layout::NodeWithStyleAndBoxModelMetrics const& node, CSSPixelSize paint_size) const { CSSPixelRect gradient_box { { 0, 0 }, paint_size }; - auto center = m_properties.position.resolved(node, gradient_box).to_type(); - auto gradient_size = resolve_size(node, center, gradient_box.to_type()); + auto center = m_properties.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.to_type(), *this), + Painting::resolve_radial_gradient_data(node, gradient_size, *this), gradient_size, center, }; @@ -212,8 +212,8 @@ void RadialGradientStyleValue::paint(PaintContext& context, DevicePixelRect cons { VERIFY(m_resolved.has_value()); Painting::paint_radial_gradient(context, dest_rect, m_resolved->data, - context.rounded_device_point(m_resolved->center.to_type()), - context.rounded_device_size(m_resolved->gradient_size.to_type())); + context.rounded_device_point(m_resolved->center), + context.rounded_device_size(m_resolved->gradient_size)); } } diff --git a/Userland/Libraries/LibWeb/CSS/StyleValues/RadialGradientStyleValue.h b/Userland/Libraries/LibWeb/CSS/StyleValues/RadialGradientStyleValue.h index 3308f81971..f33e6ca701 100644 --- a/Userland/Libraries/LibWeb/CSS/StyleValues/RadialGradientStyleValue.h +++ b/Userland/Libraries/LibWeb/CSS/StyleValues/RadialGradientStyleValue.h @@ -65,7 +65,7 @@ public: void resolve_for_size(Layout::NodeWithStyleAndBoxModelMetrics const&, CSSPixelSize) const override; - Gfx::FloatSize resolve_size(Layout::Node const&, Gfx::FloatPoint, Gfx::FloatRect const&) const; + CSSPixelSize resolve_size(Layout::Node const&, CSSPixelPoint, CSSPixelRect const&) const; bool is_repeating() const { return m_properties.repeating == GradientRepeating::Yes; } @@ -89,8 +89,8 @@ private: struct ResolvedData { Painting::RadialGradientData data; - Gfx::FloatSize gradient_size; - Gfx::FloatPoint center; + CSSPixelSize gradient_size; + CSSPixelPoint center; }; mutable Optional m_resolved; diff --git a/Userland/Libraries/LibWeb/PixelUnits.h b/Userland/Libraries/LibWeb/PixelUnits.h index e8ce2b439d..2ccdeacd44 100644 --- a/Userland/Libraries/LibWeb/PixelUnits.h +++ b/Userland/Libraries/LibWeb/PixelUnits.h @@ -405,7 +405,7 @@ using DevicePixelSize = Gfx::Size; } -inline Web::CSSPixels abs(Web::CSSPixels const& value) +constexpr Web::CSSPixels abs(Web::CSSPixels const& value) { return value.abs(); } @@ -430,11 +430,23 @@ constexpr Web::CSSPixels round(Web::CSSPixels const& value) return ceil(value - Web::CSSPixels::from_raw(Web::CSSPixels::fixed_point_denominator >> 1 /* 0.5 */)); } +inline Web::CSSPixels sqrt(Web::CSSPixels const& value) +{ + return Web::CSSPixels::nearest_value_for(AK::sqrt(value.to_float())); +} + constexpr Web::DevicePixels abs(Web::DevicePixels const& value) { return AK::abs(value.value()); } +constexpr Web::CSSPixels square_distance_between(Web::CSSPixelPoint const& a, Web::CSSPixelPoint const& b) +{ + auto delta_x = abs(a.x() - b.x()); + auto delta_y = abs(a.y() - b.y()); + return delta_x * delta_x + delta_y * delta_y; +} + template<> template<> [[nodiscard]] ALWAYS_INLINE Web::CSSPixelRect Web::CSSPixelRect::to_rounded() const