/* * Copyright (c) 2026, Andreas Kling * * SPDX-License-Identifier: BSD-2-Clause */ #pragma once #include #include #include #include #include #include namespace Web::HTML { class AnimatedDecodedImageData final : public DecodedImageData { GC_CELL(AnimatedDecodedImageData, DecodedImageData); GC_DECLARE_ALLOCATOR(AnimatedDecodedImageData); public: static constexpr bool OVERRIDES_FINALIZE = true; static GC::Ref create( JS::Realm&, i64 session_id, u32 frame_count, u32 loop_count, Gfx::IntSize, Gfx::ColorSpace, Vector durations, Vector> initial_bitmaps); virtual ~AnimatedDecodedImageData() override; virtual void finalize() override; virtual RefPtr bitmap(size_t frame_index, Gfx::IntSize = {}) const override; virtual int frame_duration(size_t frame_index) const override; virtual size_t frame_count() const override { return m_frame_count; } virtual size_t loop_count() const override { return m_loop_count; } virtual bool is_animated() const override { return true; } virtual Optional intrinsic_width() const override; virtual Optional intrinsic_height() const override; virtual Optional intrinsic_aspect_ratio() const override; virtual Optional frame_rect(size_t frame_index) const override; virtual void paint(DisplayListRecordingContext&, size_t frame_index, Gfx::IntRect dst_rect, Gfx::IntRect clip_rect, Gfx::ScalingMode) const override; virtual size_t notify_frame_advanced(size_t caller_frame_index) 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; RefPtr bitmap; u64 generation { 0 }; }; AnimatedDecodedImageData( i64 session_id, u32 frame_count, u32 loop_count, Gfx::IntSize, Gfx::ColorSpace, Vector durations); 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 RefPtr m_last_displayed_bitmap; 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_highest_requested_frame { 0 }; }; }