diff --git a/Userland/Libraries/LibWeb/CSS/StyleValue.cpp b/Userland/Libraries/LibWeb/CSS/StyleValue.cpp index 5e3ed8d9aa..6be6795082 100644 --- a/Userland/Libraries/LibWeb/CSS/StyleValue.cpp +++ b/Userland/Libraries/LibWeb/CSS/StyleValue.cpp @@ -16,6 +16,7 @@ #include #include #include +#include namespace Web::CSS { @@ -1650,9 +1651,6 @@ ImageStyleValue::ImageStyleValue(AK::URL const& url) void ImageStyleValue::load_any_resources(DOM::Document& document) { - if (m_bitmap) - return; - if (resource()) return; @@ -1665,10 +1663,41 @@ void ImageStyleValue::resource_did_load() { if (!m_document) return; - m_bitmap = resource()->bitmap(); // FIXME: Do less than a full repaint if possible? if (m_document && m_document->browsing_context()) m_document->browsing_context()->set_needs_display(); + + if (resource()->is_animated() && resource()->frame_count() > 1) { + m_timer = Platform::Timer::create(); + m_timer->set_interval(resource()->frame_duration(0)); + m_timer->on_timeout = [this] { animate(); }; + m_timer->start(); + } +} + +void ImageStyleValue::animate() +{ + m_current_frame_index = (m_current_frame_index + 1) % resource()->frame_count(); + auto current_frame_duration = resource()->frame_duration(m_current_frame_index); + + if (current_frame_duration != m_timer->interval()) + m_timer->restart(current_frame_duration); + + if (m_current_frame_index == resource()->frame_count() - 1) { + ++m_loops_completed; + if (m_loops_completed > 0 && m_loops_completed == resource()->loop_count()) + m_timer->stop(); + } + + if (on_animate) + on_animate(); +} + +Gfx::Bitmap const* ImageStyleValue::bitmap(size_t frame_index) const +{ + if (!resource()) + return nullptr; + return resource()->bitmap(frame_index); } String ImageStyleValue::to_string() const @@ -1685,22 +1714,22 @@ bool ImageStyleValue::equals(StyleValue const& other) const Optional ImageStyleValue::natural_width() const { - if (m_bitmap) - return m_bitmap->width(); + if (resource()) + return bitmap(0)->width(); return {}; } Optional ImageStyleValue::natural_height() const { - if (m_bitmap) - return m_bitmap->height(); + if (resource()) + return bitmap(0)->height(); return {}; } void ImageStyleValue::paint(PaintContext& context, Gfx::IntRect const& dest_rect, CSS::ImageRendering image_rendering) const { - if (m_bitmap) - context.painter().draw_scaled_bitmap(dest_rect, *m_bitmap, m_bitmap->rect(), 1.0f, to_gfx_scaling_mode(image_rendering)); + if (resource()) + context.painter().draw_scaled_bitmap(dest_rect, *bitmap(m_current_frame_index), bitmap(0)->rect(), 1.0f, to_gfx_scaling_mode(image_rendering)); } static void serialize_color_stop_list(StringBuilder& builder, auto const& color_stop_list) diff --git a/Userland/Libraries/LibWeb/CSS/StyleValue.h b/Userland/Libraries/LibWeb/CSS/StyleValue.h index f0b0bbbb6d..0f5aaae9b4 100644 --- a/Userland/Libraries/LibWeb/CSS/StyleValue.h +++ b/Userland/Libraries/LibWeb/CSS/StyleValue.h @@ -1171,23 +1171,29 @@ public: virtual void load_any_resources(DOM::Document&) override; - Gfx::Bitmap const* bitmap() const { return m_bitmap; } - Optional natural_width() const override; Optional natural_height() const override; - bool is_paintable() const override { return !m_bitmap.is_null(); } + bool is_paintable() const override { return bitmap(0) != nullptr; } void paint(PaintContext& context, Gfx::IntRect const& dest_rect, CSS::ImageRendering image_rendering) const override; + Function on_animate; + private: ImageStyleValue(AK::URL const&); // ^ResourceClient virtual void resource_did_load() override; + void animate(); + Gfx::Bitmap const* bitmap(size_t index) const; + AK::URL m_url; WeakPtr m_document; - RefPtr m_bitmap; + + size_t m_current_frame_index { 0 }; + size_t m_loops_completed { 0 }; + RefPtr m_timer; }; enum class GradientRepeating { diff --git a/Userland/Libraries/LibWeb/HTML/HTMLBodyElement.cpp b/Userland/Libraries/LibWeb/HTML/HTMLBodyElement.cpp index 85aa75e484..e3e3586704 100644 --- a/Userland/Libraries/LibWeb/HTML/HTMLBodyElement.cpp +++ b/Userland/Libraries/LibWeb/HTML/HTMLBodyElement.cpp @@ -55,6 +55,11 @@ void HTMLBodyElement::parse_attribute(FlyString const& name, String const& value document().set_visited_link_color(color.value()); } else if (name.equals_ignoring_case("background"sv)) { m_background_style_value = CSS::ImageStyleValue::create(document().parse_url(value)); + m_background_style_value->on_animate = [this] { + if (layout_node()) { + layout_node()->set_needs_display(); + } + }; } #undef __ENUMERATE