From 345909c009679f5edf10cefca78089b4d1fe7eba Mon Sep 17 00:00:00 2001 From: Nico Weber Date: Fri, 22 Jan 2021 18:56:01 -0500 Subject: [PATCH] WindowServer: Don't crash on wallpapers smaller than the desktop with fill mode 'simple' blit() calls draw_scaled_bitmap() behind the scenes in scaled contexts, and that doesn't like src_rect to be outside of the source bitmap's bounds. Implicitly clip with the source rect, like the non-scaled codepath already does. Fixes #5017 even more. --- Userland/Demos/LibGfxScaleDemo/main.cpp | 2 ++ Userland/Libraries/LibGfx/Painter.cpp | 10 +++++----- Userland/Services/WindowServer/Compositor.cpp | 2 +- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/Userland/Demos/LibGfxScaleDemo/main.cpp b/Userland/Demos/LibGfxScaleDemo/main.cpp index ac11a2fa15..7352420d31 100644 --- a/Userland/Demos/LibGfxScaleDemo/main.cpp +++ b/Userland/Demos/LibGfxScaleDemo/main.cpp @@ -104,6 +104,8 @@ void Canvas::draw(Gfx::Painter& painter) painter.draw_scaled_bitmap({ 202, 39, 80, 40 }, *buggie, Gfx::IntRect { 2, 30, 62, 20 }); painter.draw_tiled_bitmap({ 25, 60, WIDTH - 50, 40 }, *buggie); + + painter.blit({ 25, 101 }, *buggie, { 2, 30, 3 * buggie->width(), 20 }); } int main(int argc, char** argv) diff --git a/Userland/Libraries/LibGfx/Painter.cpp b/Userland/Libraries/LibGfx/Painter.cpp index bab4937eca..5368154933 100644 --- a/Userland/Libraries/LibGfx/Painter.cpp +++ b/Userland/Libraries/LibGfx/Painter.cpp @@ -660,11 +660,11 @@ void Painter::blit_offset(const IntPoint& a_position, const Gfx::Bitmap& source, void Painter::blit_with_alpha(const IntPoint& position, const Gfx::Bitmap& source, const IntRect& a_src_rect) { + auto safe_src_rect = a_src_rect.intersected(source.rect()); if (scale() != source.scale()) - return draw_scaled_bitmap({ position, a_src_rect.size() }, source, a_src_rect); + return draw_scaled_bitmap({ position, safe_src_rect.size() }, source, safe_src_rect); ASSERT(source.has_alpha_channel()); - IntRect safe_src_rect = a_src_rect.intersected(source.rect()); auto dst_rect = IntRect(position, safe_src_rect.size()).translated(translation()); auto clipped_rect = dst_rect.intersected(clip_rect()); @@ -709,13 +709,13 @@ void Painter::blit(const IntPoint& position, const Gfx::Bitmap& source, const In return blit_with_opacity(position, source, a_src_rect, opacity); if (source.has_alpha_channel()) return blit_with_alpha(position, source, a_src_rect); + + auto safe_src_rect = a_src_rect.intersected(source.rect()); if (scale() != source.scale()) - return draw_scaled_bitmap({ position, a_src_rect.size() }, source, a_src_rect, opacity); + return draw_scaled_bitmap({ position, safe_src_rect.size() }, source, safe_src_rect, opacity); // If we get here, the Painter might have a scale factor, but the source bitmap has the same scale factor. // We need to transform from logical to physical coordinates, but we can just copy pixels without resampling. - auto safe_src_rect = a_src_rect.intersected(source.rect()); - ASSERT(source.rect().contains(safe_src_rect)); auto dst_rect = IntRect(position, safe_src_rect.size()).translated(translation()); auto clipped_rect = dst_rect.intersected(clip_rect()); if (clipped_rect.is_empty()) diff --git a/Userland/Services/WindowServer/Compositor.cpp b/Userland/Services/WindowServer/Compositor.cpp index 9d2d025e02..38156ac218 100644 --- a/Userland/Services/WindowServer/Compositor.cpp +++ b/Userland/Services/WindowServer/Compositor.cpp @@ -246,7 +246,7 @@ void Compositor::compose() auto temp_painter = *m_temp_painter; auto paint_wallpaper = [&](Gfx::Painter& painter, const Gfx::IntRect& rect) { - // FIXME: If the wallpaper is opaque, no need to fill with color! + // FIXME: If the wallpaper is opaque and covers the whole rect, no need to fill with color! painter.fill_rect(rect, background_color); if (m_wallpaper) { if (m_wallpaper_mode == WallpaperMode::Simple) {