mirror of
https://github.com/RGBCube/serenity
synced 2025-07-24 17:07:35 +00:00
LibWeb: Paint 1x1 backgrounds as color fill instead of tiling bitmap
This yields a huge speedup on pages that use this weird but not-entirely-uncommon technique.
This commit is contained in:
parent
e8f04be3ae
commit
6eeda29642
4 changed files with 47 additions and 14 deletions
|
@ -37,6 +37,8 @@ public:
|
||||||
|
|
||||||
virtual bool is_paintable() const = 0;
|
virtual bool is_paintable() const = 0;
|
||||||
virtual void paint(PaintContext& context, DevicePixelRect const& dest_rect, ImageRendering) const = 0;
|
virtual void paint(PaintContext& context, DevicePixelRect const& dest_rect, ImageRendering) const = 0;
|
||||||
|
|
||||||
|
virtual Optional<Gfx::Color> color_if_single_pixel_bitmap() const { return {}; }
|
||||||
};
|
};
|
||||||
|
|
||||||
// And now, some gradient related things. Maybe these should live somewhere else.
|
// And now, some gradient related things. Maybe these should live somewhere else.
|
||||||
|
|
|
@ -146,4 +146,13 @@ JS::GCPtr<HTML::DecodedImageData> ImageStyleValue::image_data() const
|
||||||
return m_image_request->image_data();
|
return m_image_request->image_data();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Optional<Gfx::Color> 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 {};
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,6 +47,8 @@ public:
|
||||||
virtual bool is_paintable() const override;
|
virtual bool is_paintable() const override;
|
||||||
void paint(PaintContext& context, DevicePixelRect const& dest_rect, CSS::ImageRendering image_rendering) const override;
|
void paint(PaintContext& context, DevicePixelRect const& dest_rect, CSS::ImageRendering image_rendering) const override;
|
||||||
|
|
||||||
|
virtual Optional<Gfx::Color> color_if_single_pixel_bitmap() const override;
|
||||||
|
|
||||||
Function<void()> on_animate;
|
Function<void()> on_animate;
|
||||||
|
|
||||||
JS::GCPtr<HTML::DecodedImageData> image_data() const;
|
JS::GCPtr<HTML::DecodedImageData> image_data() const;
|
||||||
|
|
|
@ -355,24 +355,44 @@ void paint_background(PaintContext& context, Layout::NodeWithStyleAndBoxModelMet
|
||||||
|
|
||||||
image.resolve_for_size(layout_node, image_rect.size());
|
image.resolve_for_size(layout_node, image_rect.size());
|
||||||
|
|
||||||
while (image_y < css_clip_rect.bottom()) {
|
auto for_each_image_device_rect = [&](auto callback) {
|
||||||
image_rect.set_y(image_y);
|
while (image_y < css_clip_rect.bottom()) {
|
||||||
|
image_rect.set_y(image_y);
|
||||||
|
|
||||||
auto image_x = initial_image_x;
|
auto image_x = initial_image_x;
|
||||||
while (image_x < css_clip_rect.right()) {
|
while (image_x < css_clip_rect.right()) {
|
||||||
image_rect.set_x(image_x);
|
image_rect.set_x(image_x);
|
||||||
auto image_device_rect = context.rounded_device_rect(image_rect);
|
auto image_device_rect = context.rounded_device_rect(image_rect);
|
||||||
if (image_device_rect != last_image_device_rect)
|
callback(image_device_rect);
|
||||||
image.paint(context, image_device_rect, image_rendering);
|
if (!repeat_x)
|
||||||
last_image_device_rect = image_device_rect;
|
break;
|
||||||
if (!repeat_x)
|
image_x += x_step;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!repeat_y)
|
||||||
break;
|
break;
|
||||||
image_x += x_step;
|
image_y += y_step;
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
if (!repeat_y)
|
if (auto color = image.color_if_single_pixel_bitmap(); color.has_value()) {
|
||||||
break;
|
// OPTIMIZATION: If the image is a single pixel, we can just fill the whole area with it.
|
||||||
image_y += y_step;
|
// 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<DevicePixelRect> {};
|
||||||
|
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<int>(), color.value());
|
||||||
|
} else {
|
||||||
|
for_each_image_device_rect([&](auto const& image_device_rect) {
|
||||||
|
image.paint(context, image_device_rect, image_rendering);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue