diff --git a/Userland/Libraries/LibWeb/Painting/StackingContext.cpp b/Userland/Libraries/LibWeb/Painting/StackingContext.cpp index 0d8f0364f8..445c7c1821 100644 --- a/Userland/Libraries/LibWeb/Painting/StackingContext.cpp +++ b/Userland/Libraries/LibWeb/Painting/StackingContext.cpp @@ -293,25 +293,40 @@ void StackingContext::paint(PaintContext& context) const auto affine_transform = affine_transform_matrix(); if (opacity < 1.0f || !affine_transform.is_identity()) { - auto bitmap_or_error = Gfx::Bitmap::try_create(Gfx::BitmapFormat::BGRA8888, context.painter().target()->size()); + auto transform_origin = this->transform_origin(); + auto source_rect = paintable().absolute_paint_rect().translated(-transform_origin); + auto transformed_destination_rect = affine_transform.map(source_rect).translated(transform_origin); + auto destination_rect = transformed_destination_rect.to_rounded(); + + // FIXME: We should find a way to scale the paintable, rather than paint into a separate bitmap, + // then scale it. This snippet now copies the background at the destination, then scales it down/up + // to the size of the source (which could add some artefacts, though just scaling the bitmap already does that). + // We need to copy the background at the destination because a bunch of our rendering effects now rely on + // being able to sample the painter (see border radii, shadows, filters, etc). + auto try_get_scaled_destination_bitmap = [&]() -> ErrorOr> { + auto bitmap = TRY(context.painter().get_region_bitmap(destination_rect, Gfx::BitmapFormat::BGRA8888, destination_rect)); + if (source_rect.size() != transformed_destination_rect.size()) { + bitmap = TRY(bitmap->scaled( + static_cast(source_rect.width()) / transformed_destination_rect.width(), + static_cast(source_rect.height()) / transformed_destination_rect.height())); + } + return bitmap; + }; + + auto bitmap_or_error = try_get_scaled_destination_bitmap(); if (bitmap_or_error.is_error()) return; auto bitmap = bitmap_or_error.release_value_but_fixme_should_propagate_errors(); Gfx::Painter painter(bitmap); + painter.translate(-paintable().absolute_paint_rect().location().to_rounded()); auto paint_context = context.clone(painter); paint_internal(paint_context); - auto transform_origin = this->transform_origin(); - auto source_rect = paintable().absolute_border_box_rect().translated(-transform_origin); - - auto transformed_destination_rect = affine_transform.map(source_rect).translated(transform_origin); - source_rect.translate_by(transform_origin); - // NOTE: If the destination and source rects are the same size, we round the source rect to ensure that it's pixel-aligned. if (transformed_destination_rect.size() == source_rect.size()) - context.painter().draw_scaled_bitmap(transformed_destination_rect.to_rounded(), *bitmap, source_rect.to_rounded(), opacity); + context.painter().draw_scaled_bitmap(destination_rect, *bitmap, bitmap->rect(), opacity); else - context.painter().draw_scaled_bitmap(transformed_destination_rect.to_rounded(), *bitmap, source_rect, opacity, Gfx::Painter::ScalingMode::BilinearBlend); + context.painter().draw_scaled_bitmap(destination_rect, *bitmap, bitmap->rect(), opacity, Gfx::Painter::ScalingMode::BilinearBlend); } else { paint_internal(context); }