1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-15 02:24:58 +00:00
serenity/Userland/Libraries/LibWeb/Loader/ImageResource.cpp
Timothy Flynn 90829fe880 LibWeb: Allow HTMLObjectElement to convert a Resource to ImageResource
HTMLObjectElement, when implemented according to the spec, does not know
the resource type specified by the 'data' attribute until after it has
actually loaded (i.e. it may be an image, XML document, etc.). Currently
we always use ImageLoader within HTMLObjectElement to load the object,
but will need to use ResourceLoader instead to generically load data.

However, ImageLoader / ImageResource have image-specific functionality
that HTMLObjectElement still needs if the resource turns out to be an
image. This patch will allow (only) HTMLObjectElement to convert the
generic Resource to an ImageResource as needed.
2022-03-23 13:44:51 +01:00

110 lines
2.8 KiB
C++

/*
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <LibGfx/Bitmap.h>
#include <LibWeb/ImageDecoding.h>
#include <LibWeb/Loader/ImageResource.h>
namespace Web {
NonnullRefPtr<ImageResource> ImageResource::convert_from_resource(Resource& resource)
{
return adopt_ref(*new ImageResource(resource));
}
ImageResource::ImageResource(const LoadRequest& request)
: Resource(Type::Image, request)
{
}
ImageResource::ImageResource(Resource& resource)
: Resource(Type::Image, resource)
{
}
ImageResource::~ImageResource() = default;
int ImageResource::frame_duration(size_t frame_index) const
{
decode_if_needed();
if (frame_index >= m_decoded_frames.size())
return 0;
return m_decoded_frames[frame_index].duration;
}
void ImageResource::decode_if_needed() const
{
if (!has_encoded_data())
return;
if (m_has_attempted_decode)
return;
if (!m_decoded_frames.is_empty())
return;
NonnullRefPtr decoder = image_decoder_client();
auto image = decoder->decode_image(encoded_data());
if (image.has_value()) {
m_loop_count = image.value().loop_count;
m_animated = image.value().is_animated;
m_decoded_frames.resize(image.value().frames.size());
for (size_t i = 0; i < m_decoded_frames.size(); ++i) {
auto& frame = m_decoded_frames[i];
frame.bitmap = image.value().frames[i].bitmap;
frame.duration = image.value().frames[i].duration;
}
}
m_has_attempted_decode = true;
}
const Gfx::Bitmap* ImageResource::bitmap(size_t frame_index) const
{
decode_if_needed();
if (frame_index >= m_decoded_frames.size())
return nullptr;
return m_decoded_frames[frame_index].bitmap;
}
void ImageResource::update_volatility()
{
bool visible_in_viewport = false;
for_each_client([&](auto& client) {
if (static_cast<const ImageResourceClient&>(client).is_visible_in_viewport())
visible_in_viewport = true;
});
if (!visible_in_viewport) {
for (auto& frame : m_decoded_frames) {
if (frame.bitmap)
frame.bitmap->set_volatile();
}
return;
}
bool still_has_decoded_image = true;
for (auto& frame : m_decoded_frames) {
if (!frame.bitmap) {
still_has_decoded_image = false;
} else {
bool was_purged = false;
bool bitmap_has_memory = frame.bitmap->set_nonvolatile(was_purged);
if (!bitmap_has_memory || was_purged)
still_has_decoded_image = false;
}
}
if (still_has_decoded_image)
return;
m_decoded_frames.clear();
m_has_attempted_decode = false;
}
ImageResourceClient::~ImageResourceClient() = default;
}