mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 20:07:35 +00:00
LibWeb: Make HTML::DecodedImageData to be GC-allocated
This change fixes GC-leak caused by following mutual dependency: - SVGDecodedImageData owns JS::Handle for Page. - SVGDecodedImageData is owned by visited objects. by making everything inherited from HTML::DecodedImageData and ListOfAvailableImages to be GC-allocated. Generally, if visited object has a handle, very likely we leak everything visited from object in a handle.
This commit is contained in:
parent
57a04c536c
commit
41a3c19cfe
18 changed files with 100 additions and 54 deletions
|
@ -132,7 +132,7 @@ void ImageStyleValue::paint(PaintContext& context, DevicePixelRect const& dest_r
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RefPtr<HTML::DecodedImageData const> ImageStyleValue::image_data() const
|
JS::GCPtr<HTML::DecodedImageData> ImageStyleValue::image_data() const
|
||||||
{
|
{
|
||||||
if (!m_image_request)
|
if (!m_image_request)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
|
@ -48,7 +48,7 @@ public:
|
||||||
|
|
||||||
Function<void()> on_animate;
|
Function<void()> on_animate;
|
||||||
|
|
||||||
RefPtr<HTML::DecodedImageData const> image_data() const;
|
JS::GCPtr<HTML::DecodedImageData> image_data() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ImageStyleValue(AK::URL const&);
|
ImageStyleValue(AK::URL const&);
|
||||||
|
|
|
@ -347,7 +347,7 @@ void Document::initialize(JS::Realm& realm)
|
||||||
|
|
||||||
m_selection = heap().allocate<Selection::Selection>(realm, realm, *this);
|
m_selection = heap().allocate<Selection::Selection>(realm, realm, *this);
|
||||||
|
|
||||||
m_list_of_available_images = make<HTML::ListOfAvailableImages>();
|
m_list_of_available_images = heap().allocate<HTML::ListOfAvailableImages>(realm);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Document::visit_edges(Cell::Visitor& visitor)
|
void Document::visit_edges(Cell::Visitor& visitor)
|
||||||
|
@ -413,6 +413,8 @@ void Document::visit_edges(Cell::Visitor& visitor)
|
||||||
|
|
||||||
for (auto& timeline : m_associated_animation_timelines)
|
for (auto& timeline : m_associated_animation_timelines)
|
||||||
visitor.visit(timeline);
|
visitor.visit(timeline);
|
||||||
|
|
||||||
|
visitor.visit(m_list_of_available_images);
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://w3c.github.io/selection-api/#dom-document-getselection
|
// https://w3c.github.io/selection-api/#dom-document-getselection
|
||||||
|
|
|
@ -728,7 +728,7 @@ private:
|
||||||
JS::GCPtr<HTML::HTMLBaseElement const> m_first_base_element_with_href_in_tree_order;
|
JS::GCPtr<HTML::HTMLBaseElement const> m_first_base_element_with_href_in_tree_order;
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/images.html#list-of-available-images
|
// https://html.spec.whatwg.org/multipage/images.html#list-of-available-images
|
||||||
OwnPtr<HTML::ListOfAvailableImages> m_list_of_available_images;
|
JS::GCPtr<HTML::ListOfAvailableImages> m_list_of_available_images;
|
||||||
|
|
||||||
JS::GCPtr<CSS::VisualViewport> m_visual_viewport;
|
JS::GCPtr<CSS::VisualViewport> m_visual_viewport;
|
||||||
|
|
||||||
|
|
|
@ -5,13 +5,17 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <LibGfx/Bitmap.h>
|
#include <LibGfx/Bitmap.h>
|
||||||
|
#include <LibJS/Heap/Heap.h>
|
||||||
|
#include <LibJS/Runtime/Realm.h>
|
||||||
#include <LibWeb/HTML/AnimatedBitmapDecodedImageData.h>
|
#include <LibWeb/HTML/AnimatedBitmapDecodedImageData.h>
|
||||||
|
|
||||||
namespace Web::HTML {
|
namespace Web::HTML {
|
||||||
|
|
||||||
ErrorOr<NonnullRefPtr<AnimatedBitmapDecodedImageData>> AnimatedBitmapDecodedImageData::create(Vector<Frame>&& frames, size_t loop_count, bool animated)
|
JS_DEFINE_ALLOCATOR(AnimatedBitmapDecodedImageData);
|
||||||
|
|
||||||
|
ErrorOr<JS::NonnullGCPtr<AnimatedBitmapDecodedImageData>> AnimatedBitmapDecodedImageData::create(JS::Realm& realm, Vector<Frame>&& frames, size_t loop_count, bool animated)
|
||||||
{
|
{
|
||||||
return adopt_nonnull_ref_or_enomem(new (nothrow) AnimatedBitmapDecodedImageData(move(frames), loop_count, animated));
|
return realm.heap().allocate<AnimatedBitmapDecodedImageData>(realm, move(frames), loop_count, animated);
|
||||||
}
|
}
|
||||||
|
|
||||||
AnimatedBitmapDecodedImageData::AnimatedBitmapDecodedImageData(Vector<Frame>&& frames, size_t loop_count, bool animated)
|
AnimatedBitmapDecodedImageData::AnimatedBitmapDecodedImageData(Vector<Frame>&& frames, size_t loop_count, bool animated)
|
||||||
|
|
|
@ -12,13 +12,16 @@
|
||||||
namespace Web::HTML {
|
namespace Web::HTML {
|
||||||
|
|
||||||
class AnimatedBitmapDecodedImageData final : public DecodedImageData {
|
class AnimatedBitmapDecodedImageData final : public DecodedImageData {
|
||||||
|
JS_CELL(AnimatedBitmapDecodedImageData, Cell);
|
||||||
|
JS_DECLARE_ALLOCATOR(AnimatedBitmapDecodedImageData);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
struct Frame {
|
struct Frame {
|
||||||
RefPtr<Gfx::ImmutableBitmap> bitmap;
|
RefPtr<Gfx::ImmutableBitmap> bitmap;
|
||||||
int duration { 0 };
|
int duration { 0 };
|
||||||
};
|
};
|
||||||
|
|
||||||
static ErrorOr<NonnullRefPtr<AnimatedBitmapDecodedImageData>> create(Vector<Frame>&&, size_t loop_count, bool animated);
|
static ErrorOr<JS::NonnullGCPtr<AnimatedBitmapDecodedImageData>> create(JS::Realm&, Vector<Frame>&&, size_t loop_count, bool animated);
|
||||||
virtual ~AnimatedBitmapDecodedImageData() override;
|
virtual ~AnimatedBitmapDecodedImageData() override;
|
||||||
|
|
||||||
virtual RefPtr<Gfx::ImmutableBitmap> bitmap(size_t frame_index, Gfx::IntSize = {}) const override;
|
virtual RefPtr<Gfx::ImmutableBitmap> bitmap(size_t frame_index, Gfx::IntSize = {}) const override;
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
namespace Web::HTML {
|
namespace Web::HTML {
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/images.html#img-req-data
|
// https://html.spec.whatwg.org/multipage/images.html#img-req-data
|
||||||
class DecodedImageData : public RefCounted<DecodedImageData> {
|
class DecodedImageData : public JS::Cell {
|
||||||
public:
|
public:
|
||||||
virtual ~DecodedImageData();
|
virtual ~DecodedImageData();
|
||||||
|
|
||||||
|
|
|
@ -715,7 +715,7 @@ void HTMLImageElement::react_to_changes_in_the_environment()
|
||||||
|
|
||||||
// FIXME: 13. End the synchronous section, continuing the remaining steps in parallel.
|
// FIXME: 13. End the synchronous section, continuing the remaining steps in parallel.
|
||||||
|
|
||||||
auto step_15 = [this](String const& selected_source, JS::NonnullGCPtr<ImageRequest> image_request, ListOfAvailableImages::Key const& key, NonnullRefPtr<DecodedImageData> const& image_data) {
|
auto step_15 = [this](String const& selected_source, JS::NonnullGCPtr<ImageRequest> image_request, ListOfAvailableImages::Key const& key, JS::NonnullGCPtr<DecodedImageData> image_data) {
|
||||||
// 15. Queue an element task on the DOM manipulation task source given the img element and the following steps:
|
// 15. Queue an element task on the DOM manipulation task source given the img element and the following steps:
|
||||||
queue_an_element_task(HTML::Task::Source::DOMManipulation, [this, selected_source, image_request, key, image_data] {
|
queue_an_element_task(HTML::Task::Source::DOMManipulation, [this, selected_source, image_request, key, image_data] {
|
||||||
// 1. FIXME: If the img element has experienced relevant mutations since this algorithm started, then let pending request be null and abort these steps.
|
// 1. FIXME: If the img element has experienced relevant mutations since this algorithm started, then let pending request be null and abort these steps.
|
||||||
|
@ -789,7 +789,7 @@ void HTMLImageElement::react_to_changes_in_the_environment()
|
||||||
VERIFY(image_request->shared_image_request());
|
VERIFY(image_request->shared_image_request());
|
||||||
auto image_data = image_request->shared_image_request()->image_data();
|
auto image_data = image_request->shared_image_request()->image_data();
|
||||||
image_request->set_image_data(image_data);
|
image_request->set_image_data(image_data);
|
||||||
step_15(selected_source, image_request, key, NonnullRefPtr(*image_data));
|
step_15(selected_source, image_request, key, *image_data);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
[this]() {
|
[this]() {
|
||||||
|
|
|
@ -354,7 +354,7 @@ i32 HTMLObjectElement::default_tab_index_value() const
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
RefPtr<DecodedImageData const> HTMLObjectElement::image_data() const
|
JS::GCPtr<DecodedImageData> HTMLObjectElement::image_data() const
|
||||||
{
|
{
|
||||||
if (!m_image_request)
|
if (!m_image_request)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
|
@ -81,7 +81,7 @@ private:
|
||||||
|
|
||||||
Representation m_representation { Representation::Unknown };
|
Representation m_representation { Representation::Unknown };
|
||||||
|
|
||||||
RefPtr<DecodedImageData const> image_data() const;
|
JS::GCPtr<DecodedImageData> image_data() const;
|
||||||
|
|
||||||
JS::GCPtr<SharedImageRequest> m_image_request;
|
JS::GCPtr<SharedImageRequest> m_image_request;
|
||||||
};
|
};
|
||||||
|
|
|
@ -41,6 +41,7 @@ void ImageRequest::visit_edges(JS::Cell::Visitor& visitor)
|
||||||
Base::visit_edges(visitor);
|
Base::visit_edges(visitor);
|
||||||
visitor.visit(m_shared_image_request);
|
visitor.visit(m_shared_image_request);
|
||||||
visitor.visit(m_page);
|
visitor.visit(m_page);
|
||||||
|
visitor.visit(m_image_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/images.html#img-available
|
// https://html.spec.whatwg.org/multipage/images.html#img-available
|
||||||
|
@ -92,14 +93,14 @@ void abort_the_image_request(JS::Realm&, ImageRequest* image_request)
|
||||||
// AD-HOC: We simply don't do this, since our SharedImageRequest may be used by someone else.
|
// AD-HOC: We simply don't do this, since our SharedImageRequest may be used by someone else.
|
||||||
}
|
}
|
||||||
|
|
||||||
RefPtr<DecodedImageData const> ImageRequest::image_data() const
|
JS::GCPtr<DecodedImageData> ImageRequest::image_data() const
|
||||||
{
|
{
|
||||||
return m_image_data;
|
return m_image_data;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImageRequest::set_image_data(RefPtr<DecodedImageData const> data)
|
void ImageRequest::set_image_data(JS::GCPtr<DecodedImageData> data)
|
||||||
{
|
{
|
||||||
m_image_data = move(data);
|
m_image_data = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/images.html#prepare-an-image-for-presentation
|
// https://html.spec.whatwg.org/multipage/images.html#prepare-an-image-for-presentation
|
||||||
|
|
|
@ -43,8 +43,8 @@ public:
|
||||||
AK::URL const& current_url() const;
|
AK::URL const& current_url() const;
|
||||||
void set_current_url(JS::Realm&, AK::URL);
|
void set_current_url(JS::Realm&, AK::URL);
|
||||||
|
|
||||||
[[nodiscard]] RefPtr<DecodedImageData const> image_data() const;
|
[[nodiscard]] JS::GCPtr<DecodedImageData> image_data() const;
|
||||||
void set_image_data(RefPtr<DecodedImageData const>);
|
void set_image_data(JS::GCPtr<DecodedImageData>);
|
||||||
|
|
||||||
[[nodiscard]] float current_pixel_density() const { return m_current_pixel_density; }
|
[[nodiscard]] float current_pixel_density() const { return m_current_pixel_density; }
|
||||||
void set_current_pixel_density(float density) { m_current_pixel_density = density; }
|
void set_current_pixel_density(float density) { m_current_pixel_density = density; }
|
||||||
|
@ -76,7 +76,7 @@ private:
|
||||||
AK::URL m_current_url;
|
AK::URL m_current_url;
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/images.html#img-req-data
|
// https://html.spec.whatwg.org/multipage/images.html#img-req-data
|
||||||
RefPtr<DecodedImageData const> m_image_data;
|
JS::GCPtr<DecodedImageData> m_image_data;
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/images.html#current-pixel-density
|
// https://html.spec.whatwg.org/multipage/images.html#current-pixel-density
|
||||||
// Each image request has a current pixel density, which must initially be 1.
|
// Each image request has a current pixel density, which must initially be 1.
|
||||||
|
|
|
@ -9,6 +9,9 @@
|
||||||
|
|
||||||
namespace Web::HTML {
|
namespace Web::HTML {
|
||||||
|
|
||||||
|
JS_DEFINE_ALLOCATOR(ListOfAvailableImages);
|
||||||
|
JS_DEFINE_ALLOCATOR(ListOfAvailableImages::Entry);
|
||||||
|
|
||||||
ListOfAvailableImages::ListOfAvailableImages() = default;
|
ListOfAvailableImages::ListOfAvailableImages() = default;
|
||||||
ListOfAvailableImages::~ListOfAvailableImages() = default;
|
ListOfAvailableImages::~ListOfAvailableImages() = default;
|
||||||
|
|
||||||
|
@ -30,23 +33,30 @@ u32 ListOfAvailableImages::Key::hash() const
|
||||||
return cached_hash.value();
|
return cached_hash.value();
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorOr<NonnullRefPtr<ListOfAvailableImages::Entry>> ListOfAvailableImages::Entry::create(NonnullRefPtr<DecodedImageData> image_data, bool ignore_higher_layer_caching)
|
JS::NonnullGCPtr<ListOfAvailableImages::Entry> ListOfAvailableImages::Entry::create(JS::VM& vm, JS::NonnullGCPtr<DecodedImageData> image_data, bool ignore_higher_layer_caching)
|
||||||
{
|
{
|
||||||
return adopt_nonnull_ref_or_enomem(new (nothrow) Entry(move(image_data), ignore_higher_layer_caching));
|
return vm.heap().allocate_without_realm<Entry>(image_data, ignore_higher_layer_caching);
|
||||||
}
|
}
|
||||||
|
|
||||||
ListOfAvailableImages::Entry::Entry(NonnullRefPtr<DecodedImageData> data, bool ignore_higher_layer_caching)
|
void ListOfAvailableImages::visit_edges(JS::Cell::Visitor& visitor)
|
||||||
|
{
|
||||||
|
Base::visit_edges(visitor);
|
||||||
|
for (auto& it : m_images)
|
||||||
|
visitor.visit(it.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
ListOfAvailableImages::Entry::Entry(JS::NonnullGCPtr<DecodedImageData> data, bool ignore_higher_layer_caching)
|
||||||
: ignore_higher_layer_caching(ignore_higher_layer_caching)
|
: ignore_higher_layer_caching(ignore_higher_layer_caching)
|
||||||
, image_data(move(data))
|
, image_data(data)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
ListOfAvailableImages::Entry::~Entry() = default;
|
ListOfAvailableImages::Entry::~Entry() = default;
|
||||||
|
|
||||||
ErrorOr<void> ListOfAvailableImages::add(Key const& key, NonnullRefPtr<DecodedImageData> image_data, bool ignore_higher_layer_caching)
|
ErrorOr<void> ListOfAvailableImages::add(Key const& key, JS::NonnullGCPtr<DecodedImageData> image_data, bool ignore_higher_layer_caching)
|
||||||
{
|
{
|
||||||
auto entry = TRY(Entry::create(move(image_data), ignore_higher_layer_caching));
|
auto entry = Entry::create(vm(), image_data, ignore_higher_layer_caching);
|
||||||
TRY(m_images.try_set(key, move(entry)));
|
TRY(m_images.try_set(key, entry));
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,7 +65,7 @@ void ListOfAvailableImages::remove(Key const& key)
|
||||||
m_images.remove(key);
|
m_images.remove(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
RefPtr<ListOfAvailableImages::Entry> ListOfAvailableImages::get(Key const& key) const
|
JS::GCPtr<ListOfAvailableImages::Entry> ListOfAvailableImages::get(Key const& key) const
|
||||||
{
|
{
|
||||||
auto it = m_images.find(key);
|
auto it = m_images.find(key);
|
||||||
if (it == m_images.end())
|
if (it == m_images.end())
|
||||||
|
|
|
@ -16,7 +16,10 @@
|
||||||
namespace Web::HTML {
|
namespace Web::HTML {
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/images.html#list-of-available-images
|
// https://html.spec.whatwg.org/multipage/images.html#list-of-available-images
|
||||||
class ListOfAvailableImages {
|
class ListOfAvailableImages : public JS::Cell {
|
||||||
|
JS_CELL(ListOfAvailableImages, Cell);
|
||||||
|
JS_DECLARE_ALLOCATOR(ListOfAvailableImages);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
struct Key {
|
struct Key {
|
||||||
AK::URL url;
|
AK::URL url;
|
||||||
|
@ -30,26 +33,32 @@ public:
|
||||||
mutable Optional<u32> cached_hash;
|
mutable Optional<u32> cached_hash;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Entry final : public RefCounted<Entry> {
|
struct Entry final : public JS::Cell {
|
||||||
static ErrorOr<NonnullRefPtr<Entry>> create(NonnullRefPtr<DecodedImageData>, bool ignore_higher_layer_caching);
|
JS_CELL(Entry, Cell);
|
||||||
|
JS_DECLARE_ALLOCATOR(Entry);
|
||||||
|
|
||||||
|
public:
|
||||||
|
static JS::NonnullGCPtr<Entry> create(JS::VM&, JS::NonnullGCPtr<DecodedImageData>, bool ignore_higher_layer_caching);
|
||||||
~Entry();
|
~Entry();
|
||||||
|
|
||||||
bool ignore_higher_layer_caching { false };
|
bool ignore_higher_layer_caching { false };
|
||||||
NonnullRefPtr<DecodedImageData> image_data;
|
JS::NonnullGCPtr<DecodedImageData> image_data;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Entry(NonnullRefPtr<DecodedImageData>, bool ignore_higher_layer_caching);
|
Entry(JS::NonnullGCPtr<DecodedImageData>, bool ignore_higher_layer_caching);
|
||||||
};
|
};
|
||||||
|
|
||||||
ListOfAvailableImages();
|
ListOfAvailableImages();
|
||||||
~ListOfAvailableImages();
|
~ListOfAvailableImages();
|
||||||
|
|
||||||
ErrorOr<void> add(Key const&, NonnullRefPtr<DecodedImageData>, bool ignore_higher_layer_caching);
|
ErrorOr<void> add(Key const&, JS::NonnullGCPtr<DecodedImageData>, bool ignore_higher_layer_caching);
|
||||||
void remove(Key const&);
|
void remove(Key const&);
|
||||||
[[nodiscard]] RefPtr<Entry> get(Key const&) const;
|
[[nodiscard]] JS::GCPtr<Entry> get(Key const&) const;
|
||||||
|
|
||||||
|
void visit_edges(JS::Cell::Visitor& visitor) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
HashMap<Key, NonnullRefPtr<Entry>> m_images;
|
HashMap<Key, JS::NonnullGCPtr<Entry>> m_images;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,9 +56,10 @@ void SharedImageRequest::visit_edges(JS::Cell::Visitor& visitor)
|
||||||
visitor.visit(callback.on_finish);
|
visitor.visit(callback.on_finish);
|
||||||
visitor.visit(callback.on_fail);
|
visitor.visit(callback.on_fail);
|
||||||
}
|
}
|
||||||
|
visitor.visit(m_image_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
RefPtr<DecodedImageData const> SharedImageRequest::image_data() const
|
JS::GCPtr<DecodedImageData> SharedImageRequest::image_data() const
|
||||||
{
|
{
|
||||||
return m_image_data;
|
return m_image_data;
|
||||||
}
|
}
|
||||||
|
@ -137,7 +138,7 @@ void SharedImageRequest::handle_successful_fetch(AK::URL const& url_string, Stri
|
||||||
|
|
||||||
bool const is_svg_image = mime_type == "image/svg+xml"sv || url_string.basename().ends_with(".svg"sv);
|
bool const is_svg_image = mime_type == "image/svg+xml"sv || url_string.basename().ends_with(".svg"sv);
|
||||||
|
|
||||||
RefPtr<DecodedImageData> image_data;
|
JS::GCPtr<DecodedImageData> image_data;
|
||||||
|
|
||||||
auto handle_failed_decode = [&] {
|
auto handle_failed_decode = [&] {
|
||||||
m_state = State::Failed;
|
m_state = State::Failed;
|
||||||
|
@ -148,7 +149,7 @@ void SharedImageRequest::handle_successful_fetch(AK::URL const& url_string, Stri
|
||||||
};
|
};
|
||||||
|
|
||||||
if (is_svg_image) {
|
if (is_svg_image) {
|
||||||
auto result = SVG::SVGDecodedImageData::create(m_page, url_string, data);
|
auto result = SVG::SVGDecodedImageData::create(m_document->realm(), m_page, url_string, data);
|
||||||
if (result.is_error())
|
if (result.is_error())
|
||||||
return handle_failed_decode();
|
return handle_failed_decode();
|
||||||
|
|
||||||
|
@ -165,10 +166,10 @@ void SharedImageRequest::handle_successful_fetch(AK::URL const& url_string, Stri
|
||||||
.duration = static_cast<int>(frame.duration),
|
.duration = static_cast<int>(frame.duration),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
image_data = AnimatedBitmapDecodedImageData::create(move(frames), result.value().loop_count, result.value().is_animated).release_value_but_fixme_should_propagate_errors();
|
image_data = AnimatedBitmapDecodedImageData::create(m_document->realm(), move(frames), result.value().loop_count, result.value().is_animated).release_value_but_fixme_should_propagate_errors();
|
||||||
}
|
}
|
||||||
|
|
||||||
m_image_data = move(image_data);
|
m_image_data = image_data;
|
||||||
|
|
||||||
m_state = State::Finished;
|
m_state = State::Finished;
|
||||||
|
|
||||||
|
|
|
@ -28,7 +28,7 @@ public:
|
||||||
|
|
||||||
AK::URL const& url() const { return m_url; }
|
AK::URL const& url() const { return m_url; }
|
||||||
|
|
||||||
[[nodiscard]] RefPtr<DecodedImageData const> image_data() const;
|
[[nodiscard]] JS::GCPtr<DecodedImageData> image_data() const;
|
||||||
|
|
||||||
[[nodiscard]] JS::GCPtr<Fetch::Infrastructure::FetchController> fetch_controller();
|
[[nodiscard]] JS::GCPtr<Fetch::Infrastructure::FetchController> fetch_controller();
|
||||||
void set_fetch_controller(JS::GCPtr<Fetch::Infrastructure::FetchController>);
|
void set_fetch_controller(JS::GCPtr<Fetch::Infrastructure::FetchController>);
|
||||||
|
@ -66,7 +66,7 @@ private:
|
||||||
Vector<Callbacks> m_callbacks;
|
Vector<Callbacks> m_callbacks;
|
||||||
|
|
||||||
AK::URL m_url;
|
AK::URL m_url;
|
||||||
RefPtr<DecodedImageData const> m_image_data;
|
JS::GCPtr<DecodedImageData> m_image_data;
|
||||||
JS::GCPtr<Fetch::Infrastructure::FetchController> m_fetch_controller;
|
JS::GCPtr<Fetch::Infrastructure::FetchController> m_fetch_controller;
|
||||||
|
|
||||||
JS::GCPtr<DOM::Document> m_document;
|
JS::GCPtr<DOM::Document> m_document;
|
||||||
|
|
|
@ -23,6 +23,8 @@
|
||||||
|
|
||||||
namespace Web::SVG {
|
namespace Web::SVG {
|
||||||
|
|
||||||
|
JS_DEFINE_ALLOCATOR(SVGDecodedImageData);
|
||||||
|
|
||||||
class SVGDecodedImageData::SVGPageClient final : public PageClient {
|
class SVGDecodedImageData::SVGPageClient final : public PageClient {
|
||||||
JS_CELL(SVGDecodedImageData::SVGPageClient, PageClient);
|
JS_CELL(SVGDecodedImageData::SVGPageClient, PageClient);
|
||||||
|
|
||||||
|
@ -54,7 +56,7 @@ private:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
ErrorOr<NonnullRefPtr<SVGDecodedImageData>> SVGDecodedImageData::create(Page& host_page, AK::URL const& url, ByteBuffer data)
|
ErrorOr<JS::NonnullGCPtr<SVGDecodedImageData>> SVGDecodedImageData::create(JS::Realm& realm, JS::NonnullGCPtr<Page> host_page, AK::URL const& url, ByteBuffer data)
|
||||||
{
|
{
|
||||||
auto page_client = SVGPageClient::create(Bindings::main_thread_vm(), host_page);
|
auto page_client = SVGPageClient::create(Bindings::main_thread_vm(), host_page);
|
||||||
auto page = Page::create(Bindings::main_thread_vm(), *page_client);
|
auto page = Page::create(Bindings::main_thread_vm(), *page_client);
|
||||||
|
@ -98,19 +100,28 @@ ErrorOr<NonnullRefPtr<SVGDecodedImageData>> SVGDecodedImageData::create(Page& ho
|
||||||
|
|
||||||
MUST(document->append_child(*svg_root));
|
MUST(document->append_child(*svg_root));
|
||||||
|
|
||||||
return adopt_nonnull_ref_or_enomem(new (nothrow) SVGDecodedImageData(page, move(page_client), move(document), move(svg_root)));
|
return realm.heap().allocate<SVGDecodedImageData>(realm, page, page_client, document, *svg_root);
|
||||||
}
|
}
|
||||||
|
|
||||||
SVGDecodedImageData::SVGDecodedImageData(JS::NonnullGCPtr<Page> page, JS::Handle<SVGPageClient> page_client, JS::Handle<DOM::Document> document, JS::Handle<SVG::SVGSVGElement> root_element)
|
SVGDecodedImageData::SVGDecodedImageData(JS::NonnullGCPtr<Page> page, JS::NonnullGCPtr<SVGPageClient> page_client, JS::NonnullGCPtr<DOM::Document> document, JS::NonnullGCPtr<SVG::SVGSVGElement> root_element)
|
||||||
: m_page(move(page))
|
: m_page(page)
|
||||||
, m_page_client(move(page_client))
|
, m_page_client(page_client)
|
||||||
, m_document(move(document))
|
, m_document(document)
|
||||||
, m_root_element(move(root_element))
|
, m_root_element(root_element)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
SVGDecodedImageData::~SVGDecodedImageData() = default;
|
SVGDecodedImageData::~SVGDecodedImageData() = default;
|
||||||
|
|
||||||
|
void SVGDecodedImageData::visit_edges(Cell::Visitor& visitor)
|
||||||
|
{
|
||||||
|
Base::visit_edges(visitor);
|
||||||
|
visitor.visit(m_page);
|
||||||
|
visitor.visit(m_document);
|
||||||
|
visitor.visit(m_page_client);
|
||||||
|
visitor.visit(m_root_element);
|
||||||
|
}
|
||||||
|
|
||||||
RefPtr<Gfx::Bitmap> SVGDecodedImageData::render(Gfx::IntSize size) const
|
RefPtr<Gfx::Bitmap> SVGDecodedImageData::render(Gfx::IntSize size) const
|
||||||
{
|
{
|
||||||
auto bitmap = Gfx::Bitmap::create(Gfx::BitmapFormat::BGRA8888, size).release_value_but_fixme_should_propagate_errors();
|
auto bitmap = Gfx::Bitmap::create(Gfx::BitmapFormat::BGRA8888, size).release_value_but_fixme_should_propagate_errors();
|
||||||
|
|
|
@ -12,8 +12,11 @@
|
||||||
namespace Web::SVG {
|
namespace Web::SVG {
|
||||||
|
|
||||||
class SVGDecodedImageData final : public HTML::DecodedImageData {
|
class SVGDecodedImageData final : public HTML::DecodedImageData {
|
||||||
|
JS_CELL(SVGDecodedImageData, Cell);
|
||||||
|
JS_DECLARE_ALLOCATOR(SVGDecodedImageData);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static ErrorOr<NonnullRefPtr<SVGDecodedImageData>> create(Page&, AK::URL const&, ByteBuffer encoded_svg);
|
static ErrorOr<JS::NonnullGCPtr<SVGDecodedImageData>> create(JS::Realm&, JS::NonnullGCPtr<Page>, AK::URL const&, ByteBuffer encoded_svg);
|
||||||
virtual ~SVGDecodedImageData() override;
|
virtual ~SVGDecodedImageData() override;
|
||||||
|
|
||||||
virtual RefPtr<Gfx::ImmutableBitmap> bitmap(size_t frame_index, Gfx::IntSize) const override;
|
virtual RefPtr<Gfx::ImmutableBitmap> bitmap(size_t frame_index, Gfx::IntSize) const override;
|
||||||
|
@ -30,18 +33,20 @@ public:
|
||||||
|
|
||||||
DOM::Document const& svg_document() const { return *m_document; }
|
DOM::Document const& svg_document() const { return *m_document; }
|
||||||
|
|
||||||
|
virtual void visit_edges(Cell::Visitor& visitor) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
class SVGPageClient;
|
class SVGPageClient;
|
||||||
SVGDecodedImageData(JS::NonnullGCPtr<Page>, JS::Handle<SVGPageClient>, JS::Handle<DOM::Document>, JS::Handle<SVG::SVGSVGElement>);
|
SVGDecodedImageData(JS::NonnullGCPtr<Page>, JS::NonnullGCPtr<SVGPageClient>, JS::NonnullGCPtr<DOM::Document>, JS::NonnullGCPtr<SVG::SVGSVGElement>);
|
||||||
|
|
||||||
RefPtr<Gfx::Bitmap> render(Gfx::IntSize) const;
|
RefPtr<Gfx::Bitmap> render(Gfx::IntSize) const;
|
||||||
mutable RefPtr<Gfx::ImmutableBitmap> m_immutable_bitmap;
|
mutable RefPtr<Gfx::ImmutableBitmap> m_immutable_bitmap;
|
||||||
|
|
||||||
JS::Handle<Page> m_page;
|
JS::NonnullGCPtr<Page> m_page;
|
||||||
JS::Handle<SVGPageClient> m_page_client;
|
JS::NonnullGCPtr<SVGPageClient> m_page_client;
|
||||||
|
|
||||||
JS::Handle<DOM::Document> m_document;
|
JS::NonnullGCPtr<DOM::Document> m_document;
|
||||||
JS::Handle<SVG::SVGSVGElement> m_root_element;
|
JS::NonnullGCPtr<SVG::SVGSVGElement> m_root_element;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue