/* * Copyright (c) 2026, Andreas Kling * * SPDX-License-Identifier: BSD-2-Clause */ #pragma once #include #include #include #include #include #include #include #include namespace Web::HTML { class AnimatedBitmapDecodedImageData final : public AnimatedDecodedImageData { GC_CELL(AnimatedBitmapDecodedImageData, AnimatedDecodedImageData); GC_DECLARE_ALLOCATOR(AnimatedBitmapDecodedImageData); friend class Web::Internals::Internals; public: static constexpr bool OVERRIDES_FINALIZE = true; static GC::Ref create( JS::Realm&, DOM::Document&, i64 session_id, u32 frame_count, u32 loop_count, Gfx::IntSize, Gfx::ColorSpace, Vector durations, Vector> initial_bitmaps); virtual ~AnimatedBitmapDecodedImageData() override; virtual void finalize() override; virtual void visit_edges(Cell::Visitor&) override; virtual Optional default_frame(Gfx::IntSize = {}) const override; virtual Optional current_frame(Gfx::IntSize = {}) const override; virtual Optional intrinsic_width() const override; virtual Optional intrinsic_height() const override; virtual Optional intrinsic_aspect_ratio() const override; virtual void paint(DisplayListRecordingContext&, Gfx::IntRect dst_rect, CSS::ImageRendering) const override; void receive_frames(Vector>, u32 start_frame_index); i64 session_id() const { return m_session_id; } static void deliver_frames_for_session(i64 session_id, Vector>); static void install_frame_delivery_callback(); private: static HashMap>& session_registry(); static constexpr u32 BUFFER_POOL_SIZE = 8; static constexpr u32 REQUEST_BATCH_SIZE = 4; struct BufferSlot { Optional frame_index; Optional frame; u64 generation { 0 }; }; AnimatedBitmapDecodedImageData( i64 session_id, u32 frame_count, u32 loop_count, Gfx::IntSize, Gfx::ColorSpace, Vector durations, GC::Ref, GC::Ref); virtual size_t external_memory_size() const override; virtual void reset_animation() override; virtual void start_animation() override; virtual void stop_animation() override; void advance_animation(); bool animation_has_completed() const; int frame_duration(size_t frame_index) const; Optional frame(size_t frame_index, Gfx::IntSize = {}) const; BufferSlot const* find_slot(u32 frame_index) const; BufferSlot& evict_oldest_slot(); void maybe_request_more_frames(size_t current_frame_index); i64 m_session_id; u32 m_frame_count; u32 m_loop_count; Gfx::IntSize m_size; Gfx::ColorSpace m_color_space; Vector m_durations; Array m_buffer_slots; mutable Optional m_last_displayed_frame; u64 m_write_generation { 0 }; bool m_request_in_flight { false }; u32 m_current_frame_index { 0 }; u32 m_last_requested_start_frame { 0 }; u32 m_loops_completed { 0 }; GC::Ref m_animation_timer; }; }