Previously animation ownership was a messy split between `AnimatedBitmapDecodedImageData` and the consumers (i.e. `ImageStyleValueResource`, `HTMLImageElement`, and `SVGImageElement`) with `AnimatedBitmapDecodedImageData` owning the frames and a current frame index, and the consumers owning the rest of the state (e.g. loop count, timers to drive the animation forward, their own current index). This had a couple of main issues: - While `AnimatedDecodedImageData` partially synchronized animations by dropping unexpected advancement notifications, this didn't apply to other animation state which meant, for instance, that a later started consumer could drive the animation of an earlier one past the max loop count (albeit without invalidating the earlier consumer). - Multiple consumers didn't share frame timings, meaning animations could be up to a full frame out of sync visually. - Animations were paused depending on whether there were any consumers, this is different to the behavior in other browsers (where they continue regardless of whether there are any consumers). - It was an overgeneralization of how animations need to work - only `AnimatedBitmapDecodedImageData` works with an indexed frame model, with animated SVGs (although not yet implemented) relying on their internal event loop to be driven forward. Given the above the new approach implemented in this commit is: - The API for `DecodedImageData` is animation system agnostic, only exposing `default_frame`, `current_frame`, and `restart_animation` methods not reliant on providing a specific frame index. - `AnimatedBitmapDecodedImageData` owns its own timer, loop count, etc. The animation starts when the first consumer registers and ends when the document is hidden or becomes inactive (or completes in the case of finite animations). - Consumers are invalidated by `AnimatedBitmapDecodedImageData` when required. Tests have been added for: - Animations being paused when the document becomes inactive and restarted when it becomes active again. - Frame timings being synchronized across consumers. - Restarts triggered by `HTMLImageElement` applying to all consumers. - Processing ending once a non-infinite animation plays to completion. The tests to ensure animations are cancelled when consumers are removed (e.g. `animated-background-image-timer-stops-when-hidden.html`) have been updated to assert the inverse since animation state is now per resource not per consumer.
107 lines
3.4 KiB
C++
107 lines
3.4 KiB
C++
/*
|
|
* Copyright (c) 2020, Andreas Kling <andreas@ladybird.org>
|
|
*
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include <LibCore/Forward.h>
|
|
#include <LibGfx/Forward.h>
|
|
#include <LibWeb/HTML/NavigableContainer.h>
|
|
#include <LibWeb/Layout/ImageProvider.h>
|
|
|
|
namespace Web::HTML {
|
|
|
|
class HTMLObjectElement final
|
|
: public NavigableContainer
|
|
, public Layout::ImageProvider {
|
|
WEB_PLATFORM_OBJECT(HTMLObjectElement, NavigableContainer)
|
|
GC_DECLARE_ALLOCATOR(HTMLObjectElement);
|
|
|
|
enum class Representation {
|
|
Unknown,
|
|
Image,
|
|
ContentNavigable,
|
|
Children,
|
|
};
|
|
|
|
public:
|
|
virtual ~HTMLObjectElement() override;
|
|
|
|
virtual void form_associated_element_attribute_changed(FlyString const& name, Optional<String> const& old_value, Optional<String> const& value, Optional<FlyString> const& namespace_) override;
|
|
virtual void form_associated_element_was_removed(DOM::Node*) override;
|
|
|
|
String data() const;
|
|
void set_data(String const& data);
|
|
|
|
String type() const { return get_attribute_value(HTML::AttributeNames::type); }
|
|
|
|
// ^FormAssociatedElement
|
|
virtual bool is_form_associated_element() const override { return true; }
|
|
|
|
// ^FormAssociatedElement
|
|
// https://html.spec.whatwg.org/multipage/forms.html#category-listed
|
|
virtual bool is_listed() const override { return true; }
|
|
|
|
// ^EventTarget
|
|
virtual bool is_focusable() const override
|
|
{
|
|
return meets_focusable_area_rendering_requirements();
|
|
}
|
|
|
|
virtual void visit_edges(Cell::Visitor&) override;
|
|
virtual void adopted_from(DOM::Document&) override;
|
|
|
|
private:
|
|
HTMLObjectElement(DOM::Document&, DOM::QualifiedName);
|
|
|
|
virtual bool is_html_object_element() const override { return true; }
|
|
|
|
virtual void initialize(JS::Realm&) override;
|
|
|
|
virtual bool is_presentational_hint(FlyString const&) const override;
|
|
virtual void apply_presentational_hints(Vector<CSS::StyleProperty>&) const override;
|
|
|
|
virtual RefPtr<Layout::Node> create_layout_node(CSS::ComputedProperties const&) override;
|
|
virtual void adjust_computed_style(CSS::ComputedProperties&) override;
|
|
|
|
bool has_ancestor_media_element_or_object_element_not_showing_fallback_content() const;
|
|
|
|
void queue_element_task_to_run_object_representation_steps();
|
|
void run_object_representation_handler_steps(Fetch::Infrastructure::Response const&, MimeSniff::MimeType const&, ReadonlyBytes);
|
|
void run_object_representation_completed_steps(Representation);
|
|
void run_object_representation_fallback_steps();
|
|
|
|
void load_image();
|
|
void update_layout_and_child_objects(Representation);
|
|
|
|
void resource_did_load(Fetch::Infrastructure::Response const&, ReadonlyBytes);
|
|
void resource_did_fail();
|
|
|
|
// ^DOM::Element
|
|
virtual i32 default_tab_index_value() const override;
|
|
|
|
// ^Layout::ImageProvider
|
|
virtual GC::Ptr<DecodedImageData> decoded_image_data() const override { return image_data(); }
|
|
|
|
GC::Ptr<DecodedImageData> image_data() const;
|
|
|
|
Representation m_representation { Representation::Unknown };
|
|
|
|
GC::Ptr<SharedResourceRequest> m_resource_request;
|
|
|
|
GC::Ptr<DOM::DocumentObserver> m_document_observer;
|
|
|
|
Vector<DOM::DocumentLoadEventDelayer> m_document_load_event_delayer_for_object_representation_task;
|
|
Vector<DOM::DocumentLoadEventDelayer> m_document_load_event_delayer_for_resource_load;
|
|
};
|
|
|
|
}
|
|
|
|
namespace Web::DOM {
|
|
|
|
template<>
|
|
inline bool Node::fast_is<HTML::HTMLObjectElement>() const { return is_html_object_element(); }
|
|
|
|
}
|