From a95905f93f5621daa86f838ed5b7138bc6e095e1 Mon Sep 17 00:00:00 2001 From: Tim Ledbetter Date: Thu, 29 Aug 2024 21:41:22 +0100 Subject: [PATCH] LibWeb: Support animations in embedded SVG images --- .../Libraries/LibWeb/SVG/SVGImageElement.cpp | 37 ++++++++++++++++++- .../Libraries/LibWeb/SVG/SVGImageElement.h | 5 +++ 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/Userland/Libraries/LibWeb/SVG/SVGImageElement.cpp b/Userland/Libraries/LibWeb/SVG/SVGImageElement.cpp index 8da7ff9b961..d28875ebf0c 100644 --- a/Userland/Libraries/LibWeb/SVG/SVGImageElement.cpp +++ b/Userland/Libraries/LibWeb/SVG/SVGImageElement.cpp @@ -5,12 +5,14 @@ */ #include "SVGImageElement.h" +#include #include #include #include #include #include #include +#include #include namespace Web::SVG { @@ -18,6 +20,8 @@ namespace Web::SVG { SVGImageElement::SVGImageElement(DOM::Document& document, DOM::QualifiedName qualified_name) : SVGGraphicsElement(document, move(qualified_name)) { + m_animation_timer = Core::Timer::try_create().release_value_but_fixme_should_propagate_errors(); + m_animation_timer->on_timeout = [this] { animate(); }; } void SVGImageElement::initialize(JS::Realm& realm) @@ -156,6 +160,12 @@ void SVGImageElement::fetch_the_document(URL::URL const& url) m_resource_request->add_callbacks( [this] { m_load_event_delayer.clear(); + auto image_data = m_resource_request->image_data(); + if (image_data->is_animated() && image_data->frame_count() > 1) { + m_current_frame_index = 0; + m_animation_timer->set_interval(image_data->frame_duration(0)); + m_animation_timer->start(); + } }, [this] { m_load_event_delayer.clear(); @@ -210,8 +220,33 @@ RefPtr SVGImageElement::current_image_bitmap(Gfx::IntSize if (!m_resource_request) return {}; if (auto data = m_resource_request->image_data()) - return data->bitmap(0, size); + return data->bitmap(m_current_frame_index, size); return {}; } +void SVGImageElement::animate() +{ + auto image_data = m_resource_request->image_data(); + if (!image_data) { + return; + } + + m_current_frame_index = (m_current_frame_index + 1) % image_data->frame_count(); + auto current_frame_duration = image_data->frame_duration(m_current_frame_index); + + if (current_frame_duration != m_animation_timer->interval()) { + m_animation_timer->restart(current_frame_duration); + } + + if (m_current_frame_index == image_data->frame_count() - 1) { + ++m_loops_completed; + if (m_loops_completed > 0 && m_loops_completed == image_data->loop_count()) { + m_animation_timer->stop(); + } + } + + if (paintable()) + paintable()->set_needs_display(); +} + } diff --git a/Userland/Libraries/LibWeb/SVG/SVGImageElement.h b/Userland/Libraries/LibWeb/SVG/SVGImageElement.h index 76aa073a571..1ad742e1fe2 100644 --- a/Userland/Libraries/LibWeb/SVG/SVGImageElement.h +++ b/Userland/Libraries/LibWeb/SVG/SVGImageElement.h @@ -49,12 +49,17 @@ protected: private: virtual JS::GCPtr create_layout_node(NonnullRefPtr) override; + void animate(); JS::GCPtr m_x; JS::GCPtr m_y; JS::GCPtr m_width; JS::GCPtr m_height; + RefPtr m_animation_timer; + size_t m_current_frame_index { 0 }; + size_t m_loops_completed { 0 }; + URL::URL m_href; JS::GCPtr m_resource_request;