1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-31 18:58:12 +00:00

LibWeb: Share decoded images at the Resource level :^)

This patch adds ImageResource as a subclass of Resource. This new class
also keeps a Gfx::ImageDecoder so that we can share decoded bitmaps
between all clients of an image resource inside LibWeb.

With this, we now share both encoded and decoded data for images. :^)

I had to change how the purgeable-volatile flag is updated to keep the
volatile-images-outside-the-visible-viewport optimization working.
HTMLImageElement now inherits from ImageResourceClient (a subclass of
ResourceClient with additional image-specific stuff) and informs its
ImageResource about whether it's inside the viewport or outside.

This is pretty awesome! :^)
This commit is contained in:
Andreas Kling 2020-06-02 20:27:26 +02:00
parent 1c6e4e04a8
commit d4ddb0013c
14 changed files with 200 additions and 30 deletions

View file

@ -56,7 +56,7 @@ void HTMLImageElement::load_image(const String& src)
{
LoadRequest request;
request.set_url(document().complete_url(src));
set_resource(ResourceLoader::the().load_resource(request));
set_resource(ResourceLoader::the().load_resource(Resource::Type::Image, request));
}
void HTMLImageElement::resource_did_load()
@ -70,7 +70,8 @@ void HTMLImageElement::resource_did_load()
dbg() << "HTMLImageElement: Resource did load, encoded data looks tasty: " << this->src();
m_image_decoder = Gfx::ImageDecoder::create(resource()->encoded_data());
ASSERT(!m_image_decoder);
m_image_decoder = resource()->ensure_decoder();
if (m_image_decoder->is_animated() && m_image_decoder->frame_count() > 1) {
const auto& first_frame = m_image_decoder->frame(0);
@ -91,6 +92,11 @@ void HTMLImageElement::resource_did_fail()
dispatch_event(Event::create("error"));
}
void HTMLImageElement::resource_did_replace_decoder()
{
m_image_decoder = resource()->ensure_decoder();
}
void HTMLImageElement::animate()
{
if (!layout_node()) {
@ -161,19 +167,17 @@ const Gfx::Bitmap* HTMLImageElement::bitmap() const
return m_image_decoder->bitmap();
}
void HTMLImageElement::set_volatile(Badge<LayoutDocument>, bool v)
void HTMLImageElement::set_visible_in_viewport(Badge<LayoutDocument>, bool visible_in_viewport)
{
if (!m_image_decoder)
if (m_visible_in_viewport == visible_in_viewport)
return;
if (v) {
m_image_decoder->set_volatile();
return;
}
bool has_image = m_image_decoder->set_nonvolatile();
if (has_image)
return;
ASSERT(resource());
m_image_decoder = Gfx::ImageDecoder::create(resource()->encoded_data());
m_visible_in_viewport = visible_in_viewport;
// FIXME: Don't update volatility every time. If we're here, we're probably scanning through
// the whole document, updating "is visible in viewport" flags, and this could lead
// to the same bitmap being marked volatile back and forth unnecessarily.
if (resource())
resource()->update_volatility();
}
}

View file

@ -30,7 +30,7 @@
#include <LibCore/Forward.h>
#include <LibGfx/Forward.h>
#include <LibWeb/DOM/HTMLElement.h>
#include <LibWeb/Loader/Resource.h>
#include <LibWeb/Loader/ImageResource.h>
namespace Web {
@ -38,7 +38,7 @@ class LayoutDocument;
class HTMLImageElement final
: public HTMLElement
, public ResourceClient {
, public ImageResourceClient {
public:
using WrapperType = Bindings::HTMLImageElementWrapper;
@ -55,11 +55,14 @@ public:
const Gfx::Bitmap* bitmap() const;
const Gfx::ImageDecoder* image_decoder() const { return m_image_decoder; }
void set_volatile(Badge<LayoutDocument>, bool);
void set_visible_in_viewport(Badge<LayoutDocument>, bool);
private:
// ^ImageResource
virtual void resource_did_load() override;
virtual void resource_did_fail() override;
virtual void resource_did_replace_decoder() override;
virtual bool is_visible_in_viewport() const override { return m_visible_in_viewport; }
void load_image(const String& src);
@ -72,6 +75,8 @@ private:
size_t m_current_frame_index { 0 };
size_t m_loops_completed { 0 };
NonnullRefPtr<Core::Timer> m_timer;
bool m_visible_in_viewport { false };
};
template<>

View file

@ -76,7 +76,7 @@ void HTMLLinkElement::load_stylesheet(const URL& url)
{
LoadRequest request;
request.set_url(url);
set_resource(ResourceLoader::the().load_resource(request));
set_resource(ResourceLoader::the().load_resource(Resource::Type::Generic, request));
}
}