diff --git a/Servers/WindowServer/WSCompositor.cpp b/Servers/WindowServer/WSCompositor.cpp index f1ff205d29..3184300f2e 100644 --- a/Servers/WindowServer/WSCompositor.cpp +++ b/Servers/WindowServer/WSCompositor.cpp @@ -104,10 +104,10 @@ void WSCompositor::compose() } else if (m_wallpaper_mode == WallpaperMode::Tile) { m_back_painter->blit_tiled(dirty_rect.location(), *m_wallpaper, dirty_rect); } else { - // FIXME: Does not work: offset rect creates trails. - m_back_painter->draw_scaled_bitmap(dirty_rect, *m_wallpaper, - { dirty_rect.location(), - m_wallpaper->size() }); + float hscale = (float)m_wallpaper->size().width() / (float)ws.size().width(); + float vscale = (float)m_wallpaper->size().height() / (float)ws.size().height(); + + m_back_painter->blit_scaled(dirty_rect.location(), *m_wallpaper, dirty_rect, hscale, vscale); } } } diff --git a/SharedGraphics/Painter.cpp b/SharedGraphics/Painter.cpp index 97c58b59a5..c1c85c6deb 100644 --- a/SharedGraphics/Painter.cpp +++ b/SharedGraphics/Painter.cpp @@ -204,6 +204,36 @@ void Painter::draw_bitmap(const Point& p, const GlyphBitmap& bitmap, Color color } } +void Painter::blit_scaled(const Point& position, const GraphicsBitmap& source, const Rect& src_rect, float hscale, float vscale) +{ + auto dst_rect = Rect(position, src_rect.size()).translated(translation()); + auto clipped_rect = dst_rect.intersected(clip_rect()); + if (clipped_rect.is_empty()) + return; + const int first_row = (clipped_rect.top() - dst_rect.top()); + const int last_row = (clipped_rect.bottom() - dst_rect.top()); + const int first_column = (clipped_rect.left() - dst_rect.left()); + RGBA32* dst = m_target->scanline(clipped_rect.y()) + clipped_rect.x(); + const size_t dst_skip = m_target->pitch() / sizeof(RGBA32); + + int x_start = first_column + src_rect.left(); + for (int row = first_row; row <= last_row; ++row) { + int sr = (row + src_rect.top()) * vscale; + if (sr >= source.size().height() || sr < 0) { + dst += dst_skip; + continue; + } + const RGBA32* sl = source.scanline(sr); + for (int x = x_start; x < clipped_rect.width() + x_start; ++x) { + int sx = x * hscale; + if (sx < source.size().width() && sx >= 0) + dst[x - x_start] = sl[sx]; + } + dst += dst_skip; + } + return; +} + void Painter::blit_with_opacity(const Point& position, const GraphicsBitmap& source, const Rect& src_rect, float opacity) { ASSERT(!m_target->has_alpha_channel()); diff --git a/SharedGraphics/Painter.h b/SharedGraphics/Painter.h index de0125a4c6..66d4904115 100644 --- a/SharedGraphics/Painter.h +++ b/SharedGraphics/Painter.h @@ -29,7 +29,7 @@ public: void blit_dimmed(const Point&, const GraphicsBitmap&, const Rect& src_rect); void blit_tiled(const Point&, const GraphicsBitmap&, const Rect& src_rect); void blit_offset(const Point&, const GraphicsBitmap&, const Rect& src_rect, const Point&); - void blit_scaled(const Point&, const GraphicsBitmap&, const Rect& src_rect, const Size&); + void blit_scaled(const Point&, const GraphicsBitmap&, const Rect&, float, float); void draw_text(const Rect&, const StringView&, const Font&, TextAlignment = TextAlignment::TopLeft, Color = Color::Black, TextElision = TextElision::None); void draw_text(const Rect&, const StringView&, TextAlignment = TextAlignment::TopLeft, Color = Color::Black, TextElision = TextElision::None); void draw_glyph(const Point&, char, Color);