From ed921b66f530d6326f52296efa5a4acfd58b8cce Mon Sep 17 00:00:00 2001 From: Aliaksandr Kalenik Date: Tue, 4 Nov 2025 21:51:40 +0100 Subject: [PATCH] LibGfx+LibWeb: Delete unused Line class and Rect methods --- Libraries/LibGfx/Forward.h | 6 - Libraries/LibGfx/ImageFormats/PNGWriter.cpp | 1 + .../LibGfx/ImageFormats/TinyVGLoader.cpp | 11 +- Libraries/LibGfx/Line.h | 199 ---------- Libraries/LibGfx/Rect.h | 352 ------------------ Libraries/LibWeb/Painting/ScrollFrame.h | 1 + Libraries/LibWeb/PixelUnits.h | 2 - Tests/LibGfx/TestRect.cpp | 29 -- 8 files changed, 4 insertions(+), 597 deletions(-) delete mode 100644 Libraries/LibGfx/Line.h diff --git a/Libraries/LibGfx/Forward.h b/Libraries/LibGfx/Forward.h index 9afdd1a8cd..f30f57ac75 100644 --- a/Libraries/LibGfx/Forward.h +++ b/Libraries/LibGfx/Forward.h @@ -19,9 +19,6 @@ class GlyphRun; class ImageDecoder; struct FontPixelMetrics; -template -class Line; - class Painter; class PaintingSurface; class Palette; @@ -46,9 +43,6 @@ class Rect; template class Quad; -using IntLine = Line; -using FloatLine = Line; - using IntRect = Rect; using FloatRect = Rect; diff --git a/Libraries/LibGfx/ImageFormats/PNGWriter.cpp b/Libraries/LibGfx/ImageFormats/PNGWriter.cpp index c55fc4d4d2..8ebf39d5c8 100644 --- a/Libraries/LibGfx/ImageFormats/PNGWriter.cpp +++ b/Libraries/LibGfx/ImageFormats/PNGWriter.cpp @@ -4,6 +4,7 @@ * SPDX-License-Identifier: BSD-2-Clause */ +#include #include #include #include diff --git a/Libraries/LibGfx/ImageFormats/TinyVGLoader.cpp b/Libraries/LibGfx/ImageFormats/TinyVGLoader.cpp index 59fa109c97..a975e2521b 100644 --- a/Libraries/LibGfx/ImageFormats/TinyVGLoader.cpp +++ b/Libraries/LibGfx/ImageFormats/TinyVGLoader.cpp @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include @@ -249,11 +248,6 @@ public: return FloatRect { TRY(read_unit()), TRY(read_unit()), TRY(read_unit()), TRY(read_unit()) }; } - ErrorOr read_line() - { - return FloatLine { TRY(read_point()), TRY(read_point()) }; - } - ErrorOr read_path(u32 segment_count) { Path path; @@ -414,9 +408,8 @@ ErrorOr> TinyVGDecodedImageData::decode(St auto header = TRY(reader.read_draw_command_header(style_type)); Path path; for (u32 i = 0; i < header.count; i++) { - auto line = TRY(reader.read_line()); - path.move_to(line.a()); - path.line_to(line.b()); + path.move_to(TRY(reader.read_point())); + path.line_to(TRY(reader.read_point())); } TRY(draw_commands.try_append(DrawCommand { move(path), {}, move(header.line_style), header.line_width })); break; diff --git a/Libraries/LibGfx/Line.h b/Libraries/LibGfx/Line.h deleted file mode 100644 index 5d42899e51..0000000000 --- a/Libraries/LibGfx/Line.h +++ /dev/null @@ -1,199 +0,0 @@ -/* - * Copyright (c) 2021, the SerenityOS developers. - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include -#include -#include -#include -#include - -namespace Gfx { - -template -class Line { -public: - Line() = default; - - Line(Point a, Point b) - : m_a(a) - , m_b(b) - { - } - - template - Line(U a, U b) - : m_a(a) - , m_b(b) - { - } - - template - explicit Line(Line const& other) - : m_a(other.a()) - , m_b(other.b()) - { - } - - bool intersects(Line const& other) const - { - return intersected(other).has_value(); - } - - Optional> intersected(Line const& other) const - { - auto cross_product = [](Point const& p1, Point const& p2) { - return p1.x() * p2.y() - p1.y() * p2.x(); - }; - auto r = m_b - m_a; - auto s = other.m_b - other.m_a; - auto delta_a = other.m_a - m_a; - auto num = cross_product(delta_a, r); - auto denom = cross_product(r, s); - if (denom == 0) { - if (num == 0) { - // Lines are collinear, check if line ends are touching - if (m_a == other.m_a || m_a == other.m_b) - return m_a; - if (m_b == other.m_a || m_b == other.m_b) - return m_b; - // Check if they're overlapping - if (!(m_b.x() - m_a.x() < 0 && m_b.x() - other.m_a.x() < 0 && other.m_b.x() - m_a.x() && other.m_b.x() - other.m_a.x())) { - // Overlapping - // TODO find center point? - } - if (!(m_b.y() - m_a.y() < 0 && m_b.y() - other.m_a.y() < 0 && other.m_b.y() - m_a.y() && other.m_b.y() - other.m_a.y())) { - // Overlapping - // TODO find center point? - } - return {}; - } else { - // Lines are parallel and not intersecting - return {}; - } - } - auto u = static_cast(num) / static_cast(denom); - if (u < 0.0f || u > 1.0f) { - // Lines are not parallel and don't intersect - return {}; - } - auto t = static_cast(cross_product(delta_a, s)) / static_cast(denom); - if (t < 0.0f || t > 1.0f) { - // Lines are not parallel and don't intersect - return {}; - } - // TODO: round if we're dealing with int - return Point { m_a.x() + static_cast(t * r.x()), m_a.y() + static_cast(t * r.y()) }; - } - - float length() const - { - return m_a.distance_from(m_b); - } - - Point closest_to(Point const& point) const - { - if (m_a == m_b) - return m_a; - auto delta_a = point.x() - m_a.x(); - auto delta_b = point.y() - m_a.y(); - auto delta_c = m_b.x() - m_a.x(); - auto delta_d = m_b.y() - m_a.y(); - auto len_sq = delta_c * delta_c + delta_d * delta_d; - float param = -1.0; - if (len_sq != 0) - param = static_cast(delta_a * delta_c + delta_b * delta_d) / static_cast(len_sq); - if (param < 0) - return m_a; - if (param > 1) - return m_b; - // TODO: round if we're dealing with int - return { static_cast(m_a.x() + param * delta_c), static_cast(m_a.y() + param * delta_d) }; - } - - Line shortest_line_to(Point const& point) const - { - return { closest_to(point), point }; - } - - float distance_to(Point const& point) const - { - return shortest_line_to(point).length(); - } - - Point const& a() const { return m_a; } - Point const& b() const { return m_b; } - - Line rotated(float radians) - { - Gfx::AffineTransform rotation_transform; - rotation_transform.rotate_radians(radians); - - Line line = *this; - line.set_a(line.a().transformed(rotation_transform)); - line.set_b(line.b().transformed(rotation_transform)); - return line; - } - - void set_a(Point const& a) { m_a = a; } - void set_b(Point const& b) { m_b = b; } - - Line scaled(T sx, T sy) const - { - Line line = *this; - line.set_a(line.a().scaled(sx, sy)); - line.set_b(line.b().scaled(sx, sy)); - return line; - } - - Line translated(Point const& delta) const - { - Line line = *this; - line.set_a(line.a().translated(delta)); - line.set_b(line.b().translated(delta)); - return line; - } - - template - requires(!IsSame) - [[nodiscard]] ALWAYS_INLINE constexpr Line to_type() const - { - return Line(*this); - } - - ByteString to_byte_string() const; - -private: - Point m_a; - Point m_b; -}; - -template<> -inline ByteString IntLine::to_byte_string() const -{ - return ByteString::formatted("[{},{} -> {},{}]", m_a.x(), m_a.y(), m_b.x(), m_b.y()); -} - -template<> -inline ByteString FloatLine::to_byte_string() const -{ - return ByteString::formatted("[{},{} -> {},{}]", m_a.x(), m_a.y(), m_b.x(), m_b.y()); -} - -} - -namespace AK { - -template -struct Formatter> : Formatter { - ErrorOr format(FormatBuilder& builder, Gfx::Line const& value) - { - return Formatter::format(builder, "[{},{} -> {},{}]"sv, value.a().x(), value.a().y(), value.b().x(), value.b().y()); - } -}; - -} diff --git a/Libraries/LibGfx/Rect.h b/Libraries/LibGfx/Rect.h index 25231df807..628362c0b1 100644 --- a/Libraries/LibGfx/Rect.h +++ b/Libraries/LibGfx/Rect.h @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include @@ -411,65 +410,6 @@ public: return false; } - template - IterationDecision for_each_intersected(Container const& others, Function f) const - { - if (is_empty()) - return IterationDecision::Continue; - for (auto const& other : others) { - auto intersected_rect = intersected(other); - if (!intersected_rect.is_empty()) { - IterationDecision decision = f(intersected_rect); - if (decision != IterationDecision::Continue) - return decision; - } - } - return IterationDecision::Continue; - } - - [[nodiscard]] Vector, 4> shatter(Rect const& hammer) const - { - Vector, 4> pieces; - if (!intersects(hammer)) { - pieces.unchecked_append(*this); - return pieces; - } - Rect top_shard { - x(), - y(), - width(), - hammer.y() - y(), - }; - Rect bottom_shard { - x(), - hammer.bottom(), - width(), - bottom() - hammer.bottom(), - }; - Rect left_shard { - x(), - max(hammer.y(), y()), - hammer.x() - x(), - min(hammer.bottom(), bottom()) - max(hammer.y(), y()), - }; - Rect right_shard { - hammer.right(), - max(hammer.y(), y()), - right() - hammer.right(), - min(hammer.bottom(), bottom()) - max(hammer.y(), y()), - }; - if (!top_shard.is_empty()) - pieces.unchecked_append(top_shard); - if (!bottom_shard.is_empty()) - pieces.unchecked_append(bottom_shard); - if (!left_shard.is_empty()) - pieces.unchecked_append(left_shard); - if (!right_shard.is_empty()) - pieces.unchecked_append(right_shard); - - return pieces; - } - template [[nodiscard]] bool operator==(Rect const& other) const { @@ -526,30 +466,6 @@ public: return intersection(*this, other); } - [[nodiscard]] Vector, 2> intersected(Line const& line) const - { - if (is_empty()) - return {}; - Vector, 2> points; - if (auto point = line.intersected({ top_left(), top_right() }); point.has_value()) - points.append({ point.value().x(), y() }); - if (auto point = line.intersected({ bottom_left(), bottom_right() }); point.has_value()) { - points.append({ point.value().x(), bottom() - 1 }); - if (points.size() == 2) - return points; - } - if (height() > 2) { - if (auto point = line.intersected({ { x(), y() + 1 }, { x(), bottom() - 2 } }); point.has_value()) { - points.append({ x(), point.value().y() }); - if (points.size() == 2) - return points; - } - if (auto point = line.intersected({ { right() - 1, y() + 1 }, { right() - 1, bottom() - 2 } }); point.has_value()) - points.append({ right() - 1, point.value().y() }); - } - return points; - } - template [[nodiscard]] Gfx::Rect interpolated_to(Gfx::Rect const& to, float factor) const { @@ -568,274 +484,6 @@ public: return { interpolated_left, interpolated_top, interpolated_right - interpolated_left, interpolated_bottom - interpolated_top }; } - [[nodiscard]] float center_point_distance_to(Rect const& other) const - { - return Line { center(), other.center() }.length(); - } - - [[nodiscard]] Vector, 2> closest_outside_center_points(Rect const& other) const - { - if (intersects(other)) - return {}; - Line centers_line { center(), other.center() }; - auto points_this = intersected(centers_line); - VERIFY(points_this.size() == 1); - auto points_other = other.intersected(centers_line); - VERIFY(points_other.size() == 1); - return { points_this[0], points_other[0] }; - } - - [[nodiscard]] float outside_center_point_distance_to(Rect const& other) const - { - auto points = closest_outside_center_points(other); - if (points.is_empty()) - return 0.f; - return Line { points[0], points[0] }.length(); - } - - [[nodiscard]] Rect constrained_to(Rect const& constrain_rect) const - { - if (constrain_rect.contains(*this)) - return *this; - T move_x = 0, move_y = 0; - if (right() > constrain_rect.right()) - move_x = constrain_rect.right() - right(); - if (bottom() > constrain_rect.bottom()) - move_y = constrain_rect.bottom() - bottom(); - if (x() < constrain_rect.x()) - move_x = constrain_rect.x() - x(); - if (y() < constrain_rect.y()) - move_y = constrain_rect.y() - y(); - auto rect = *this; - if (move_x != 0 || move_y != 0) - rect.translate_by(move_x, move_y); - return rect; - } - - [[nodiscard]] Point closest_to(Point const& point) const - { - if (is_empty()) - return {}; - Optional> closest_point; - float closest_distance = 0.0; - auto check_distance = [&](Line const& line) { - auto point_on_line = line.closest_to(point); - auto distance = Line { point_on_line, point }.length(); - if (!closest_point.has_value() || distance < closest_distance) { - closest_point = point_on_line; - closest_distance = distance; - } - }; - - check_distance({ top_left(), top_right().moved_left(1) }); - check_distance({ bottom_left().moved_up(1), bottom_right().translated(-1) }); - if (height() > 2) { - check_distance({ { x(), y() + 1 }, { x(), bottom() - 2 } }); - check_distance({ { right() - 1, y() + 1 }, { right() - 1, bottom() - 2 } }); - } - VERIFY(closest_point.has_value()); - VERIFY(side(closest_point.value()) != Side::None); - return closest_point.value(); - } - - class RelativeLocation { - friend class Rect; - - RelativeLocation(Rect const& base_rect, Rect const& other_rect) - { - if (base_rect.is_empty() || other_rect.is_empty()) - return; - auto parts = base_rect.shatter(other_rect); - for (auto& part : parts) { - if (part.x() < other_rect.x()) { - if (part.y() < other_rect.y()) - m_top_left = true; - if ((part.y() >= other_rect.y() && part.y() < other_rect.bottom() - 1) || (part.y() < other_rect.bottom() && part.bottom() - 1 > other_rect.y())) - m_left = true; - if (part.y() >= other_rect.bottom() - 1 || part.bottom() - 1 > other_rect.y()) - m_bottom_left = true; - } - if (part.x() >= other_rect.x() || part.right() - 1 > other_rect.x()) { - if (part.y() < other_rect.y()) - m_top = true; - if (part.y() >= other_rect.bottom() - 1 || part.bottom() > other_rect.bottom()) - m_bottom = true; - } - if (part.x() >= other_rect.right() - 1 || part.right() > other_rect.right()) { - if (part.y() < other_rect.y()) - m_top_right = true; - if ((part.y() >= other_rect.y() && part.y() < other_rect.bottom() - 1) || (part.y() < other_rect.bottom() && part.bottom() - 1 > other_rect.y())) - m_right = true; - if (part.y() >= other_rect.bottom() - 1 || part.bottom() - 1 > other_rect.y()) - m_bottom_right = true; - } - } - } - - public: - RelativeLocation() = default; - - bool top_left() const { return m_top_left; } - bool top() const { return m_top; } - bool top_right() const { return m_top_right; } - bool left() const { return m_left; } - bool right() const { return m_right; } - bool bottom_left() const { return m_bottom_left; } - bool bottom() const { return m_bottom; } - bool bottom_right() const { return m_bottom_right; } - bool anywhere_above() const { return m_top_left || m_top || m_top_right; } - bool anywhere_below() const { return m_bottom_left || m_bottom || m_bottom_right; } - bool anywhere_left() const { return m_top_left || m_left || m_bottom_left; } - bool anywhere_right() const { return m_top_right || m_right || m_bottom_right; } - - private: - bool m_top_left : 1 { false }; - bool m_top : 1 { false }; - bool m_top_right : 1 { false }; - bool m_left : 1 { false }; - bool m_right : 1 { false }; - bool m_bottom_left : 1 { false }; - bool m_bottom : 1 { false }; - bool m_bottom_right : 1 { false }; - }; - [[nodiscard]] RelativeLocation relative_location_to(Rect const& other) const - { - return RelativeLocation(*this, other); - } - - enum class Side { - None = 0, - Left, - Top, - Right, - Bottom - }; - [[nodiscard]] Side side(Point const& point) const - { - if (is_empty()) - return Side::None; - if (point.y() == y() || point.y() == bottom() - 1) - return (point.x() >= x() && point.x() < right()) ? (point.y() == y() ? Side::Top : Side::Bottom) : Side::None; - if (point.x() == x() || point.x() == right() - 1) - return (point.y() > y() && point.y() < bottom()) ? (point.x() == x() ? Side::Left : Side::Right) : Side::None; - return Side::None; - } - - [[nodiscard]] Rect rect_on_side(Side side, Rect const& other) const - { - switch (side) { - case Side::None: - break; - case Side::Left: - // Return the area in other that is to the left of this rect - if (other.x() < x()) { - if (other.right() > x()) - return { other.location(), { x() - other.x(), other.height() } }; - else - return other; - } - break; - case Side::Top: - // Return the area in other that is above this rect - if (other.y() < y()) { - if (other.bottom() > y()) - return { other.location(), { other.width(), y() - other.y() } }; - else - return other; - } - break; - case Side::Right: - // Return the area in other that is to the right of this rect - if (other.right() > x()) { - if (other.x() < right()) - return { { right(), other.y() }, { other.width() - (right() - 1 - other.x()), other.height() } }; - else - return other; - } - break; - case Side::Bottom: - // Return the area in other that is below this rect - if (other.bottom() > y()) { - if (other.y() < bottom()) - return { { other.x(), bottom() }, { other.width(), other.height() - (bottom() - 1 - other.y()) } }; - else - return other; - } - break; - } - return {}; - } - - template - static bool disperse(Container& rects) - { - auto has_intersecting = [&]() { - for (auto& rect : rects) { - for (auto& other_rect : rects) { - if (&rect == &other_rect) - continue; - if (rect.intersects(other_rect)) - return true; - } - } - return false; - }; - - if (!has_intersecting()) - return false; - - auto calc_delta = [&](Rect const& rect) -> Point { - auto rect_center = rect.center(); - Point center_sum; - for (auto& other_rect : rects) { - if (&other_rect == &rect) - continue; - if (rect.intersects(other_rect)) - center_sum += rect_center - other_rect.center(); - } - double m = sqrt((double)center_sum.x() * (double)center_sum.x() + (double)center_sum.y() * (double)center_sum.y()); - if (m != 0.0) - return { (double)center_sum.x() / m + 0.5, (double)center_sum.y() / m + 0.5 }; - return {}; - }; - - Vector, 8> deltas; - do { - bool changes = false; - - deltas.clear_with_capacity(); - for (auto& rect : rects) { - auto delta = calc_delta(rect); - if (!delta.is_zero()) - changes = true; - deltas.append(delta); - } - - // TODO: If we have no changes we would loop infinitely! - // Figure out some way to resolve this. Maybe randomly moving an intersecting rect? - VERIFY(changes); - - size_t i = 0; - for (auto& rect : rects) - rect.translate_by(deltas[i++]); - - } while (has_intersecting()); - return true; - } - - [[nodiscard]] bool is_adjacent(Rect const& other) const - { - if (is_empty() || other.is_empty()) - return false; - if (intersects(other)) - return false; - if (other.right() == x() || other.x() == right()) - return max(top(), other.top()) < min(bottom(), other.bottom()); - if (other.bottom() == y() || other.y() == bottom()) - return max(left(), other.left()) < min(right(), other.right()); - return false; - } - [[nodiscard]] static Rect centered_at(Point const& point, Size const& size) { return { { point.x() - size.width() / 2, point.y() - size.height() / 2 }, size }; diff --git a/Libraries/LibWeb/Painting/ScrollFrame.h b/Libraries/LibWeb/Painting/ScrollFrame.h index a5604cd8da..16cc502d35 100644 --- a/Libraries/LibWeb/Painting/ScrollFrame.h +++ b/Libraries/LibWeb/Painting/ScrollFrame.h @@ -6,6 +6,7 @@ #pragma once +#include #include #include #include diff --git a/Libraries/LibWeb/PixelUnits.h b/Libraries/LibWeb/PixelUnits.h index d99e8155f6..5812547030 100644 --- a/Libraries/LibWeb/PixelUnits.h +++ b/Libraries/LibWeb/PixelUnits.h @@ -415,12 +415,10 @@ constexpr CSSPixelFraction operator/(CSSPixels left, T right) { return left / CS inline float operator/(CSSPixels left, float right) { return left.to_float() / right; } inline double operator/(CSSPixels left, double right) { return left.to_double() / right; } -using CSSPixelLine = Gfx::Line; using CSSPixelPoint = Gfx::Point; using CSSPixelRect = Gfx::Rect; using CSSPixelSize = Gfx::Size; -using DevicePixelLine = Gfx::Line; using DevicePixelPoint = Gfx::Point; using DevicePixelRect = Gfx::Rect; using DevicePixelSize = Gfx::Size; diff --git a/Tests/LibGfx/TestRect.cpp b/Tests/LibGfx/TestRect.cpp index 123725bdce..b760a267f5 100644 --- a/Tests/LibGfx/TestRect.cpp +++ b/Tests/LibGfx/TestRect.cpp @@ -28,35 +28,6 @@ TEST_CASE(rect_contains_vertically) EXPECT(!rect.contains_vertically(100.f)); } -TEST_CASE(rect_shatter) -{ - Gfx::IntRect glass_plate = { 0, 0, 100, 100 }; - Gfx::IntRect hammer = { 30, 40, 40, 10 }; - - auto shards = glass_plate.shatter(hammer); - EXPECT(!shards.is_empty()); - - int total_shard_area = 0; - for (auto shard : shards) { - EXPECT(glass_plate.contains(shard)); - EXPECT(!hammer.intersects(shard)); - total_shard_area += shard.size().area(); - } - - EXPECT_EQ(glass_plate.size().area() - hammer.size().area(), total_shard_area); -} - -TEST_CASE(rect_closest_to) -{ - Gfx::IntRect const screen_rect = { 0, 0, 960, 540 }; - Gfx::Point p = { 460, 592 }; // point is below the rect - Gfx::Point closest = screen_rect.closest_to(p); - EXPECT_EQ(screen_rect.side(closest), Gfx::IntRect::Side::Bottom); - p = { 960, 0 }; // point exactly on top right corner - closest = screen_rect.closest_to(p); - EXPECT_EQ(screen_rect.side(closest), Gfx::IntRect::Side::Top); -} - TEST_CASE(rect_unite) { Gfx::IntRect rect_a { 10, 10, 100, 100 };