mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2026-06-18 07:43:37 +00:00
DecodedImageData::paint() used to take both a destination and a clip rectangle even though most callers passed the same value. SVG image painting used that API to wrap every nested SVG display list in save/add-clip/restore, which put an unbounded command in front of the bounded nested-list command and made offscreen SVG image content harder to cull. Move clipping to ImagePaintable, where the object-fit destination can be compared with the replaced element box. CSS image and marker painting continue to draw into their destination rect, while repeated background images keep their explicit tile clip. The scaled decoded image display-list command now stores only its destination rect and uses that as its bounds; playback still clips decoded images to that rect so bitmap rendering stays unchanged.
80 lines
2.4 KiB
C++
80 lines
2.4 KiB
C++
/*
|
|
* Copyright (c) 2023, Andreas Kling <andreas@ladybird.org>
|
|
*
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
*/
|
|
|
|
#include <LibGC/Heap.h>
|
|
#include <LibGfx/Bitmap.h>
|
|
#include <LibJS/Runtime/ExternalMemory.h>
|
|
#include <LibJS/Runtime/Realm.h>
|
|
#include <LibWeb/HTML/BitmapDecodedImageData.h>
|
|
#include <LibWeb/Painting/DisplayListRecorder.h>
|
|
#include <LibWeb/Painting/DisplayListRecordingContext.h>
|
|
|
|
namespace Web::HTML {
|
|
|
|
GC_DEFINE_ALLOCATOR(BitmapDecodedImageData);
|
|
|
|
ErrorOr<GC::Ref<BitmapDecodedImageData>> BitmapDecodedImageData::create(JS::Realm& realm, Vector<Frame>&& frames, size_t loop_count, bool animated)
|
|
{
|
|
return realm.create<BitmapDecodedImageData>(move(frames), loop_count, animated);
|
|
}
|
|
|
|
BitmapDecodedImageData::BitmapDecodedImageData(Vector<Frame>&& frames, size_t loop_count, bool animated)
|
|
: m_frames(move(frames))
|
|
, m_loop_count(loop_count)
|
|
, m_animated(animated)
|
|
{
|
|
}
|
|
|
|
BitmapDecodedImageData::~BitmapDecodedImageData() = default;
|
|
|
|
size_t BitmapDecodedImageData::external_memory_size() const
|
|
{
|
|
size_t size = JS::vector_external_memory_size(m_frames);
|
|
for (auto const& frame : m_frames)
|
|
size = JS::saturating_add_external_memory_size(size, frame.frame.bitmap().data_size());
|
|
return size;
|
|
}
|
|
|
|
Optional<Gfx::DecodedImageFrame> BitmapDecodedImageData::frame(size_t frame_index, Gfx::IntSize) const
|
|
{
|
|
if (frame_index >= m_frames.size())
|
|
return {};
|
|
return m_frames[frame_index].frame;
|
|
}
|
|
|
|
int BitmapDecodedImageData::frame_duration(size_t frame_index) const
|
|
{
|
|
if (frame_index >= m_frames.size())
|
|
return 0;
|
|
return m_frames[frame_index].duration;
|
|
}
|
|
|
|
Optional<CSSPixels> BitmapDecodedImageData::intrinsic_width() const
|
|
{
|
|
return m_frames.first().frame.width();
|
|
}
|
|
|
|
Optional<CSSPixels> BitmapDecodedImageData::intrinsic_height() const
|
|
{
|
|
return m_frames.first().frame.height();
|
|
}
|
|
|
|
Optional<CSSPixelFraction> BitmapDecodedImageData::intrinsic_aspect_ratio() const
|
|
{
|
|
return CSSPixels(m_frames.first().frame.width()) / CSSPixels(m_frames.first().frame.height());
|
|
}
|
|
|
|
Optional<Gfx::IntRect> BitmapDecodedImageData::frame_rect(size_t frame_index) const
|
|
{
|
|
return m_frames[frame_index].frame.rect();
|
|
}
|
|
|
|
void BitmapDecodedImageData::paint(DisplayListRecordingContext& context, size_t frame_index, Gfx::IntRect dst_rect, Gfx::ScalingMode scaling_mode) const
|
|
{
|
|
context.display_list_recorder().draw_scaled_decoded_image_frame(dst_rect, m_frames[frame_index].frame, scaling_mode);
|
|
}
|
|
|
|
}
|