diff --git a/Userland/Libraries/LibWeb/CSS/StyleValues/AbstractImageStyleValue.h b/Userland/Libraries/LibWeb/CSS/StyleValues/AbstractImageStyleValue.h index 43abb002c4..e0338a5247 100644 --- a/Userland/Libraries/LibWeb/CSS/StyleValues/AbstractImageStyleValue.h +++ b/Userland/Libraries/LibWeb/CSS/StyleValues/AbstractImageStyleValue.h @@ -37,6 +37,8 @@ public: virtual bool is_paintable() const = 0; virtual void paint(PaintContext& context, DevicePixelRect const& dest_rect, ImageRendering) const = 0; + + virtual Optional color_if_single_pixel_bitmap() const { return {}; } }; // And now, some gradient related things. Maybe these should live somewhere else. diff --git a/Userland/Libraries/LibWeb/CSS/StyleValues/ImageStyleValue.cpp b/Userland/Libraries/LibWeb/CSS/StyleValues/ImageStyleValue.cpp index 3b4368b696..ab7c8f6aa5 100644 --- a/Userland/Libraries/LibWeb/CSS/StyleValues/ImageStyleValue.cpp +++ b/Userland/Libraries/LibWeb/CSS/StyleValues/ImageStyleValue.cpp @@ -146,4 +146,13 @@ JS::GCPtr ImageStyleValue::image_data() const return m_image_request->image_data(); } +Optional ImageStyleValue::color_if_single_pixel_bitmap() const +{ + if (auto const* b = bitmap(m_current_frame_index)) { + if (b->width() == 1 && b->height() == 1) + return b->bitmap().get_pixel(0, 0); + } + return {}; +} + } diff --git a/Userland/Libraries/LibWeb/CSS/StyleValues/ImageStyleValue.h b/Userland/Libraries/LibWeb/CSS/StyleValues/ImageStyleValue.h index 0e4eac86f0..2363330674 100644 --- a/Userland/Libraries/LibWeb/CSS/StyleValues/ImageStyleValue.h +++ b/Userland/Libraries/LibWeb/CSS/StyleValues/ImageStyleValue.h @@ -47,6 +47,8 @@ public: virtual bool is_paintable() const override; void paint(PaintContext& context, DevicePixelRect const& dest_rect, CSS::ImageRendering image_rendering) const override; + virtual Optional color_if_single_pixel_bitmap() const override; + Function on_animate; JS::GCPtr image_data() const; diff --git a/Userland/Libraries/LibWeb/Painting/BackgroundPainting.cpp b/Userland/Libraries/LibWeb/Painting/BackgroundPainting.cpp index 1d97944896..1be5c43df4 100644 --- a/Userland/Libraries/LibWeb/Painting/BackgroundPainting.cpp +++ b/Userland/Libraries/LibWeb/Painting/BackgroundPainting.cpp @@ -355,24 +355,44 @@ void paint_background(PaintContext& context, Layout::NodeWithStyleAndBoxModelMet image.resolve_for_size(layout_node, image_rect.size()); - while (image_y < css_clip_rect.bottom()) { - image_rect.set_y(image_y); + auto for_each_image_device_rect = [&](auto callback) { + while (image_y < css_clip_rect.bottom()) { + image_rect.set_y(image_y); - auto image_x = initial_image_x; - while (image_x < css_clip_rect.right()) { - image_rect.set_x(image_x); - auto image_device_rect = context.rounded_device_rect(image_rect); - if (image_device_rect != last_image_device_rect) - image.paint(context, image_device_rect, image_rendering); - last_image_device_rect = image_device_rect; - if (!repeat_x) + auto image_x = initial_image_x; + while (image_x < css_clip_rect.right()) { + image_rect.set_x(image_x); + auto image_device_rect = context.rounded_device_rect(image_rect); + callback(image_device_rect); + if (!repeat_x) + break; + image_x += x_step; + } + + if (!repeat_y) break; - image_x += x_step; + image_y += y_step; } + }; - if (!repeat_y) - break; - image_y += y_step; + if (auto color = image.color_if_single_pixel_bitmap(); color.has_value()) { + // OPTIMIZATION: If the image is a single pixel, we can just fill the whole area with it. + // However, we must first figure out the real coverage area, taking repeat etc into account. + + // FIXME: This could be written in a far more efficient way. + auto fill_rect = Optional {}; + for_each_image_device_rect([&](auto const& image_device_rect) { + if (!fill_rect.has_value()) { + fill_rect = image_device_rect; + } else { + fill_rect = fill_rect->united(image_device_rect); + } + }); + painter.fill_rect(fill_rect->to_type(), color.value()); + } else { + for_each_image_device_rect([&](auto const& image_device_rect) { + image.paint(context, image_device_rect, image_rendering); + }); } } }