From 7089681f6811a0f81270a665f1ba1849c54d7a01 Mon Sep 17 00:00:00 2001 From: Sam Atkins Date: Mon, 15 Nov 2021 17:05:06 +0000 Subject: [PATCH] LibWeb: Manually tile background images This reimplements image tiling instead of using `Painter::blit_tiled()`, so that we will be able to handle CSS's more complicated repetition rules. (Like `background-repeat: space`) Otherwise this does the same as before. :^) --- .../LibWeb/Painting/BackgroundPainting.cpp | 50 +++++++++++++++---- 1 file changed, 41 insertions(+), 9 deletions(-) diff --git a/Userland/Libraries/LibWeb/Painting/BackgroundPainting.cpp b/Userland/Libraries/LibWeb/Painting/BackgroundPainting.cpp index b67bf39bfb..1708274a1b 100644 --- a/Userland/Libraries/LibWeb/Painting/BackgroundPainting.cpp +++ b/Userland/Libraries/LibWeb/Painting/BackgroundPainting.cpp @@ -56,43 +56,75 @@ void paint_background(PaintContext& context, Layout::NodeWithStyleAndBoxModelMet painter.save(); painter.add_clip_rect(clip_rect); - auto painting_rect = border_rect; - // FIXME: Attachment // FIXME: Size - int scaled_width = image.width(); - int scaled_height = image.height(); + Gfx::IntRect image_rect { border_rect.x(), border_rect.y(), image.width(), image.height() }; // FIXME: Origin // FIXME: Position // Repetition + bool repeat_x = false; + bool repeat_y = false; + float x_step = 0; + float y_step = 0; + switch (layer.repeat_x) { case CSS::Repeat::Round: case CSS::Repeat::Space: // FIXME: Support 'round' and 'space'. Fall through to 'repeat' since that most closely resembles these. case CSS::Repeat::Repeat: - // The background rect is already sized to align with 'repeat'. + x_step = image_rect.width(); + repeat_x = true; break; case CSS::Repeat::NoRepeat: - painting_rect.set_width(min(painting_rect.width(), scaled_width)); + repeat_x = false; break; } + // Move image_rect to the left-most tile position that is still visible + if (repeat_x && image_rect.x() > clip_rect.x()) { + auto x_delta = floorf(x_step * ceilf((image_rect.x() - clip_rect.x()) / x_step)); + image_rect.set_x(image_rect.x() - x_delta); + } switch (layer.repeat_y) { case CSS::Repeat::Round: case CSS::Repeat::Space: // FIXME: Support 'round' and 'space'. Fall through to 'repeat' since that most closely resembles these. case CSS::Repeat::Repeat: - // The background rect is already sized to align with 'repeat'. + y_step = image_rect.height(); + repeat_y = true; break; case CSS::Repeat::NoRepeat: - painting_rect.set_height(min(painting_rect.height(), scaled_height)); + repeat_y = false; break; } + // Move image_rect to the top-most tile position that is still visible + if (repeat_y && image_rect.y() > clip_rect.y()) { + auto y_delta = floorf(y_step * ceilf((image_rect.y() - clip_rect.y()) / y_step)); + image_rect.set_y(image_rect.y() - y_delta); + } // FIXME: Handle rounded corners - painter.blit_tiled(painting_rect, image, image.rect()); + float initial_image_x = image_rect.x(); + float image_y = image_rect.y(); + while (image_y < clip_rect.bottom()) { + image_rect.set_y(roundf(image_y)); + + float image_x = initial_image_x; + while (image_x < clip_rect.right()) { + image_rect.set_x(roundf(image_x)); + painter.draw_scaled_bitmap(image_rect, image, image.rect(), 1.0f, Gfx::Painter::ScalingMode::BilinearBlend); + if (!repeat_x) + break; + image_x += x_step; + } + + if (!repeat_y) + break; + image_y += y_step; + } + painter.restore(); } }