LibGfx+Everywhere: Make DisjointRectSet work for non-int Rects

For convenience, `DisjointIntRectSet` is an alias for
`DisjointRectSet<int>`, and is used everywhere for now.
This commit is contained in:
Sam Atkins 2022-10-26 15:04:16 +01:00 committed by Andreas Kling
parent f52413a70e
commit ff0a2b1a60
Notes: sideshowbarker 2024-07-17 05:03:26 +09:00
13 changed files with 67 additions and 59 deletions

View file

@ -127,7 +127,7 @@ void ImageEditor::paint_event(GUI::PaintEvent& event)
painter.add_clip_rect(frame_inner_rect());
{
Gfx::DisjointRectSet background_rects;
Gfx::DisjointIntRectSet background_rects;
background_rects.add(frame_inner_rect());
background_rects.shatter(content_rect());
for (auto& rect : background_rects.rects())

View file

@ -1,5 +1,6 @@
/*
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
* Copyright (c) 2022, Sam Atkins <atkinssj@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
@ -12,6 +13,7 @@
namespace Gfx {
template<typename T>
class DisjointRectSet {
public:
DisjointRectSet(DisjointRectSet const&) = delete;
@ -20,7 +22,7 @@ public:
DisjointRectSet() = default;
~DisjointRectSet() = default;
DisjointRectSet(IntRect const& rect)
DisjointRectSet(Rect<T> const& rect)
{
m_rects.append(rect);
}
@ -35,17 +37,17 @@ public:
return rects;
}
void move_by(int dx, int dy)
void move_by(T dx, T dy)
{
for (auto& r : m_rects)
r.translate_by(dx, dy);
}
void move_by(IntPoint const& delta)
void move_by(Point<T> const& delta)
{
move_by(delta.x(), delta.y());
}
void add(IntRect const& rect)
void add(Rect<T> const& rect)
{
if (add_no_shatter(rect) && m_rects.size() > 1)
shatter();
@ -74,7 +76,7 @@ public:
}
}
DisjointRectSet shatter(IntRect const& hammer) const
DisjointRectSet shatter(Rect<T> const& hammer) const
{
if (hammer.is_empty())
return clone();
@ -107,7 +109,7 @@ public:
return shards;
}
bool contains(IntRect const& rect) const
bool contains(Rect<T> const& rect) const
{
if (is_empty() || rect.is_empty())
return false;
@ -123,7 +125,7 @@ public:
return false;
}
bool intersects(IntRect const& rect) const
bool intersects(Rect<T> const& rect) const
{
for (auto& r : m_rects) {
if (r.intersects(rect))
@ -145,7 +147,7 @@ public:
return false;
}
DisjointRectSet intersected(IntRect const& rect) const
DisjointRectSet intersected(Rect<T> const& rect) const
{
DisjointRectSet intersected_rects;
intersected_rects.m_rects.ensure_capacity(m_rects.capacity());
@ -178,7 +180,7 @@ public:
}
template<typename Function>
IterationDecision for_each_intersected(IntRect const& rect, Function f) const
IterationDecision for_each_intersected(Rect<T> const& rect, Function f) const
{
if (is_empty() || rect.is_empty())
return IterationDecision::Continue;
@ -224,22 +226,22 @@ public:
void clear() { m_rects.clear(); }
void clear_with_capacity() { m_rects.clear_with_capacity(); }
Vector<IntRect, 32> const& rects() const { return m_rects; }
Vector<IntRect, 32> take_rects() { return move(m_rects); }
Vector<Rect<T>, 32> const& rects() const { return m_rects; }
Vector<Rect<T>, 32> take_rects() { return move(m_rects); }
void translate_by(int dx, int dy)
void translate_by(T dx, T dy)
{
for (auto& rect : m_rects)
rect.translate_by(dx, dy);
}
void translate_by(Gfx::IntPoint const& delta)
void translate_by(Point<T> const& delta)
{
for (auto& rect : m_rects)
rect.translate_by(delta);
}
private:
bool add_no_shatter(IntRect const& new_rect)
bool add_no_shatter(Rect<T> const& new_rect)
{
if (new_rect.is_empty())
return false;
@ -254,7 +256,7 @@ private:
void shatter()
{
Vector<IntRect, 32> output;
Vector<Rect<T>, 32> output;
output.ensure_capacity(m_rects.size());
bool pass_had_intersections = false;
do {
@ -284,7 +286,7 @@ private:
} while (pass_had_intersections);
}
Vector<IntRect, 32> m_rects;
Vector<Rect<T>, 32> m_rects;
};
}

View file

@ -11,7 +11,10 @@ namespace Gfx {
class Bitmap;
class CharacterBitmap;
class Color;
template<typename T>
class DisjointRectSet;
class Emoji;
class Font;
class GlyphBitmap;
@ -44,6 +47,9 @@ class Rect;
template<typename T>
class Quad;
using DisjointIntRectSet = DisjointRectSet<int>;
using DisjointFloatRectSet = DisjointRectSet<float>;
using IntLine = Line<int>;
using FloatLine = Line<float>;

View file

@ -39,7 +39,7 @@ void paint_box_shadow(PaintContext& context, Gfx::IntRect const& content_rect, B
continue;
auto fill_rect_masked = [](auto& painter, auto fill_rect, auto mask_rect, auto color) {
Gfx::DisjointRectSet rect_set;
Gfx::DisjointIntRectSet rect_set;
rect_set.add(fill_rect);
auto shattered = rect_set.shatter(mask_rect);
for (auto& rect : shattered.rects())

View file

@ -45,7 +45,7 @@ void Animation::was_removed(Badge<Compositor>)
m_was_removed = true;
}
bool Animation::update(Badge<Compositor>, Gfx::Painter& painter, Screen& screen, Gfx::DisjointRectSet& flush_rects)
bool Animation::update(Badge<Compositor>, Gfx::Painter& painter, Screen& screen, Gfx::DisjointIntRectSet& flush_rects)
{
int elapsed_ms = m_timer.elapsed();
float progress = min((float)elapsed_ms / (float)m_duration, 1.0f);

View file

@ -33,9 +33,9 @@ public:
void set_duration(int duration_in_ms);
int duration() const { return m_duration; }
bool update(Badge<Compositor>, Gfx::Painter&, Screen&, Gfx::DisjointRectSet& flush_rects);
bool update(Badge<Compositor>, Gfx::Painter&, Screen&, Gfx::DisjointIntRectSet& flush_rects);
Function<void(float progress, Gfx::Painter&, Screen&, Gfx::DisjointRectSet& flush_rects)> on_update;
Function<void(float progress, Gfx::Painter&, Screen&, Gfx::DisjointIntRectSet& flush_rects)> on_update;
Function<void()> on_stop;
private:

View file

@ -746,7 +746,7 @@ void Compositor::invalidate_screen(Gfx::IntRect const& screen_rect)
start_compose_async_timer();
}
void Compositor::invalidate_screen(Gfx::DisjointRectSet const& rects)
void Compositor::invalidate_screen(Gfx::DisjointIntRectSet const& rects)
{
m_dirty_screen_rects.add(rects.intersected(Screen::bounding_rect()));
@ -1210,7 +1210,7 @@ void Compositor::recompute_occlusions()
m_opaque_wallpaper_rects.clear();
}
if (!fullscreen_window || (fullscreen_window && !fullscreen_window->is_opaque())) {
Gfx::DisjointRectSet remaining_visible_screen_rects;
Gfx::DisjointIntRectSet remaining_visible_screen_rects;
remaining_visible_screen_rects.add_many(Screen::rects());
bool have_transparent = false;
wm.for_each_visible_window_from_front_to_back([&](Window& w) {
@ -1264,8 +1264,8 @@ void Compositor::recompute_occlusions()
auto render_rect_on_screen = w.frame().render_rect().translated(transition_offset);
auto visible_window_rects = remaining_visible_screen_rects.intersected(w.rect().translated(transition_offset));
Gfx::DisjointRectSet opaque_covering;
Gfx::DisjointRectSet transparent_covering;
Gfx::DisjointIntRectSet opaque_covering;
Gfx::DisjointIntRectSet transparent_covering;
bool found_this_window = false;
wm.for_each_visible_window_from_back_to_front([&](Window& w2) {
if (!found_this_window) {
@ -1412,7 +1412,7 @@ void Compositor::recompute_occlusions()
}
// Figure out the affected transparency rects underneath. First figure out if any transparency is visible at all
Gfx::DisjointRectSet transparent_underneath;
Gfx::DisjointIntRectSet transparent_underneath;
wm.for_each_visible_window_from_back_to_front([&](Window& w2) {
if (&w == &w2)
return IterationDecision::Break;
@ -1517,7 +1517,7 @@ void Compositor::unregister_animation(Badge<Animation>, Animation& animation)
VERIFY(was_removed);
}
void Compositor::update_animations(Screen& screen, Gfx::DisjointRectSet& flush_rects)
void Compositor::update_animations(Screen& screen, Gfx::DisjointIntRectSet& flush_rects)
{
auto& painter = *screen.compositor_screen_data().m_back_painter;
// Iterating over the animations using remove_all_matching we can iterate
@ -1697,7 +1697,7 @@ void Compositor::switch_to_window_stack(WindowStack& new_window_stack, bool show
VERIFY(!m_window_stack_transition_animation);
m_window_stack_transition_animation = Animation::create();
m_window_stack_transition_animation->set_duration(250);
m_window_stack_transition_animation->on_update = [this, delta_x, delta_y](float progress, Gfx::Painter&, Screen&, Gfx::DisjointRectSet&) {
m_window_stack_transition_animation->on_update = [this, delta_x, delta_y](float progress, Gfx::Painter&, Screen&, Gfx::DisjointIntRectSet&) {
VERIFY(m_transitioning_to_window_stack);
VERIFY(m_current_window_stack);

View file

@ -52,9 +52,9 @@ struct CompositorScreenData {
bool m_cursor_back_is_valid { false };
bool m_have_flush_rects { false };
Gfx::DisjointRectSet m_flush_rects;
Gfx::DisjointRectSet m_flush_transparent_rects;
Gfx::DisjointRectSet m_flush_special_rects;
Gfx::DisjointIntRectSet m_flush_rects;
Gfx::DisjointIntRectSet m_flush_transparent_rects;
Gfx::DisjointIntRectSet m_flush_special_rects;
Gfx::Painter& overlay_painter() { return *m_temp_painter; }
@ -68,7 +68,7 @@ struct CompositorScreenData {
template<typename F>
IterationDecision for_each_intersected_flushing_rect(Gfx::IntRect const& intersecting_rect, F f)
{
auto iterate_flush_rects = [&](Gfx::DisjointRectSet const& flush_rects) {
auto iterate_flush_rects = [&](Gfx::DisjointIntRectSet const& flush_rects) {
for (auto& rect : flush_rects.rects()) {
auto intersection = intersecting_rect.intersected(rect);
if (intersection.is_empty())
@ -101,7 +101,7 @@ public:
void invalidate_window();
void invalidate_screen();
void invalidate_screen(Gfx::IntRect const&);
void invalidate_screen(Gfx::DisjointRectSet const&);
void invalidate_screen(Gfx::DisjointIntRectSet const&);
void screen_resolution_changed();
@ -209,7 +209,7 @@ private:
void change_cursor(Cursor const*);
void flush(Screen&);
Gfx::IntPoint window_transition_offset(Window&);
void update_animations(Screen&, Gfx::DisjointRectSet& flush_rects);
void update_animations(Screen&, Gfx::DisjointIntRectSet& flush_rects);
void create_window_stack_switch_overlay(WindowStack&);
void remove_window_stack_switch_overlays();
void stop_window_stack_switch_overlay_timer();
@ -227,10 +227,10 @@ private:
bool m_overlay_rects_changed { false };
IntrusiveList<&Overlay::m_list_node> m_overlay_list;
Gfx::DisjointRectSet m_overlay_rects;
Gfx::DisjointRectSet m_dirty_screen_rects;
Gfx::DisjointRectSet m_opaque_wallpaper_rects;
Gfx::DisjointRectSet m_transparent_wallpaper_rects;
Gfx::DisjointIntRectSet m_overlay_rects;
Gfx::DisjointIntRectSet m_dirty_screen_rects;
Gfx::DisjointIntRectSet m_opaque_wallpaper_rects;
Gfx::DisjointIntRectSet m_transparent_wallpaper_rects;
WallpaperMode m_wallpaper_mode { WallpaperMode::Unchecked };
RefPtr<Gfx::Bitmap> m_wallpaper;

View file

@ -469,7 +469,7 @@ void Screen::constrain_pending_flush_rects()
if (flush_rects.pending_flush_rects.is_empty())
return;
Gfx::IntRect screen_rect({}, rect().size());
Gfx::DisjointRectSet rects;
Gfx::DisjointIntRectSet rects;
for (auto& fb_rect : flush_rects.pending_flush_rects) {
Gfx::IntRect rect { (int)fb_rect.x, (int)fb_rect.y, (int)fb_rect.width, (int)fb_rect.height };
auto intersected_rect = rect.intersected(screen_rect);

View file

@ -322,7 +322,7 @@ void Window::start_minimize_animation()
}
m_animation = Animation::create();
m_animation->set_duration(150);
m_animation->on_update = [this](float progress, Gfx::Painter& painter, Screen& screen, Gfx::DisjointRectSet& flush_rects) {
m_animation->on_update = [this](float progress, Gfx::Painter& painter, Screen& screen, Gfx::DisjointIntRectSet& flush_rects) {
Gfx::PainterStateSaver saver(painter);
painter.set_draw_op(Gfx::Painter::DrawOp::Invert);
@ -350,7 +350,7 @@ void Window::start_launch_animation(Gfx::IntRect const& launch_origin_rect)
m_animation = Animation::create();
m_animation->set_duration(150);
m_animation->on_update = [this, launch_origin_rect](float progress, Gfx::Painter& painter, Screen& screen, Gfx::DisjointRectSet& flush_rects) {
m_animation->on_update = [this, launch_origin_rect](float progress, Gfx::Painter& painter, Screen& screen, Gfx::DisjointIntRectSet& flush_rects) {
Gfx::PainterStateSaver saver(painter);
painter.set_draw_op(Gfx::Painter::DrawOp::Invert);

View file

@ -227,7 +227,7 @@ public:
void prepare_dirty_rects();
void clear_dirty_rects();
Gfx::DisjointRectSet& dirty_rects() { return m_dirty_rects; }
Gfx::DisjointIntRectSet& dirty_rects() { return m_dirty_rects; }
// Only used by WindowType::Applet. Perhaps it could be a Window subclass? I don't know.
void set_rect_in_applet_area(Gfx::IntRect const& rect) { m_rect_in_applet_area = rect; }
@ -290,7 +290,7 @@ public:
void remove_cursor_override() { m_cursor_override = nullptr; }
void request_update(Gfx::IntRect const&, bool ignore_occlusion = false);
Gfx::DisjointRectSet take_pending_paint_rects() { return move(m_pending_paint_rects); }
Gfx::DisjointIntRectSet take_pending_paint_rects() { return move(m_pending_paint_rects); }
void start_minimize_animation();
@ -335,9 +335,9 @@ public:
return true;
}
Gfx::DisjointRectSet& opaque_rects() { return m_opaque_rects; }
Gfx::DisjointRectSet& transparency_rects() { return m_transparency_rects; }
Gfx::DisjointRectSet& transparency_wallpaper_rects() { return m_transparency_wallpaper_rects; }
Gfx::DisjointIntRectSet& opaque_rects() { return m_opaque_rects; }
Gfx::DisjointIntRectSet& transparency_rects() { return m_transparency_rects; }
Gfx::DisjointIntRectSet& transparency_wallpaper_rects() { return m_transparency_wallpaper_rects; }
// The affected transparency rects are the rectangles of other windows (above or below)
// that also need to be marked dirty whenever a window's dirty rect in a transparency
// area needs to be rendered
@ -401,11 +401,11 @@ private:
Gfx::IntRect m_saved_nonfullscreen_rect;
Gfx::IntRect m_taskbar_rect;
Vector<Screen*, default_screen_count> m_screens;
Gfx::DisjointRectSet m_dirty_rects;
Gfx::DisjointRectSet m_opaque_rects;
Gfx::DisjointRectSet m_transparency_rects;
Gfx::DisjointRectSet m_transparency_wallpaper_rects;
HashMap<Window*, Gfx::DisjointRectSet> m_affected_transparency_rects;
Gfx::DisjointIntRectSet m_dirty_rects;
Gfx::DisjointIntRectSet m_opaque_rects;
Gfx::DisjointIntRectSet m_transparency_rects;
Gfx::DisjointIntRectSet m_transparency_wallpaper_rects;
HashMap<Window*, Gfx::DisjointIntRectSet> m_affected_transparency_rects;
WindowType m_type { WindowType::Normal };
WindowMode m_mode { WindowMode::Modeless };
bool m_automatic_cursor_tracking_enabled { false };
@ -448,7 +448,7 @@ private:
RefPtr<Cursor> m_cursor;
RefPtr<Cursor> m_cursor_override;
WindowFrame m_frame;
Gfx::DisjointRectSet m_pending_paint_rects;
Gfx::DisjointIntRectSet m_pending_paint_rects;
Gfx::IntRect m_rect_in_applet_area;
RefPtr<Menu> m_window_menu;
MenuItem* m_window_menu_minimize_item { nullptr };

View file

@ -595,7 +595,7 @@ Gfx::IntRect WindowFrame::unconstrained_render_rect() const
return inflated_for_shadow(rect());
}
Gfx::DisjointRectSet WindowFrame::opaque_render_rects() const
Gfx::DisjointIntRectSet WindowFrame::opaque_render_rects() const
{
auto border_radius = WindowManager::the().palette().window_border_radius();
if (has_alpha_channel() || border_radius > 0) {
@ -605,17 +605,17 @@ Gfx::DisjointRectSet WindowFrame::opaque_render_rects() const
}
if (m_window.is_opaque())
return constrained_render_rect_to_screen(rect());
Gfx::DisjointRectSet opaque_rects;
Gfx::DisjointIntRectSet opaque_rects;
opaque_rects.add_many(constrained_render_rect_to_screen(rect()).shatter(m_window.rect()));
return opaque_rects;
}
Gfx::DisjointRectSet WindowFrame::transparent_render_rects() const
Gfx::DisjointIntRectSet WindowFrame::transparent_render_rects() const
{
auto border_radius = WindowManager::the().palette().window_border_radius();
if (has_alpha_channel() || border_radius > 0) {
if (m_window.is_opaque()) {
Gfx::DisjointRectSet transparent_rects;
Gfx::DisjointIntRectSet transparent_rects;
transparent_rects.add_many(render_rect().shatter(m_window.rect()));
return transparent_rects;
}
@ -623,7 +623,7 @@ Gfx::DisjointRectSet WindowFrame::transparent_render_rects() const
}
auto total_render_rect = render_rect();
Gfx::DisjointRectSet transparent_rects;
Gfx::DisjointIntRectSet transparent_rects;
if (has_shadow())
transparent_rects.add_many(total_render_rect.shatter(rect()));
if (!m_window.is_opaque())

View file

@ -56,8 +56,8 @@ public:
Gfx::IntRect rect() const;
Gfx::IntRect render_rect() const;
Gfx::IntRect unconstrained_render_rect() const;
Gfx::DisjointRectSet opaque_render_rects() const;
Gfx::DisjointRectSet transparent_render_rects() const;
Gfx::DisjointIntRectSet opaque_render_rects() const;
Gfx::DisjointIntRectSet transparent_render_rects() const;
void paint(Screen&, Gfx::Painter&, Gfx::IntRect const&);
void render(Screen&, Gfx::Painter&);