Jelajahi Sumber

LibWeb: Support animations in embedded SVG images

Tim Ledbetter 11 bulan lalu
induk
melakukan
a95905f93f

+ 36 - 1
Userland/Libraries/LibWeb/SVG/SVGImageElement.cpp

@@ -5,12 +5,14 @@
  */
 
 #include "SVGImageElement.h"
+#include <LibCore/Timer.h>
 #include <LibJS/Heap/Heap.h>
 #include <LibWeb/Bindings/SVGImageElementPrototype.h>
 #include <LibWeb/DOM/DocumentObserver.h>
 #include <LibWeb/HTML/PotentialCORSRequest.h>
 #include <LibWeb/HTML/SharedResourceRequest.h>
 #include <LibWeb/Layout/SVGImageBox.h>
+#include <LibWeb/Painting/Paintable.h>
 #include <LibWeb/SVG/SVGDecodedImageData.h>
 
 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<Gfx::ImmutableBitmap> 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();
+}
+
 }

+ 5 - 0
Userland/Libraries/LibWeb/SVG/SVGImageElement.h

@@ -49,12 +49,17 @@ protected:
 
 private:
     virtual JS::GCPtr<Layout::Node> create_layout_node(NonnullRefPtr<CSS::StyleProperties>) override;
+    void animate();
 
     JS::GCPtr<SVG::SVGAnimatedLength> m_x;
     JS::GCPtr<SVG::SVGAnimatedLength> m_y;
     JS::GCPtr<SVG::SVGAnimatedLength> m_width;
     JS::GCPtr<SVG::SVGAnimatedLength> m_height;
 
+    RefPtr<Core::Timer> m_animation_timer;
+    size_t m_current_frame_index { 0 };
+    size_t m_loops_completed { 0 };
+
     URL::URL m_href;
 
     JS::GCPtr<HTML::SharedResourceRequest> m_resource_request;