#pragma once
#include "ImageFrame.h"
#include <wtf/Forward.h>
#include <wtf/Optional.h>
#include <wtf/SynchronizedFixedQueue.h>
#include <wtf/WorkQueue.h>
namespace WebCore {
class GraphicsContext;
class Image;
class ImageDecoder;
class URL;
class ImageFrameCache : public ThreadSafeRefCounted<ImageFrameCache> {
friend class ImageSource;
public:
static Ref<ImageFrameCache> create(Image* image)
{
return adoptRef(*new ImageFrameCache(image));
}
static Ref<ImageFrameCache> create(NativeImagePtr&& nativeImage)
{
return adoptRef(*new ImageFrameCache(WTFMove(nativeImage)));
}
~ImageFrameCache();
void setDecoder(ImageDecoder*);
ImageDecoder* decoder() const;
unsigned decodedSize() const { return m_decodedSize; }
void destroyAllDecodedData() { destroyDecodedData(frameCount(), frameCount()); }
void destroyAllDecodedDataExcludeFrame(size_t excludeFrame) { destroyDecodedData(frameCount(), excludeFrame); }
void destroyDecodedDataBeforeFrame(size_t beforeFrame) { destroyDecodedData(beforeFrame, beforeFrame); }
void destroyIncompleteDecodedData();
void growFrames();
void clearMetadata();
void clearImage() { m_image = nullptr; }
URL sourceURL() const;
void startAsyncDecodingQueue();
void requestFrameAsyncDecodingAtIndex(size_t, SubsamplingLevel, const std::optional<IntSize>&);
void stopAsyncDecodingQueue();
bool hasAsyncDecodingQueue() const { return m_decodingQueue; }
bool isAsyncDecodingQueueIdle() const;
EncodedDataStatus encodedDataStatus();
bool isSizeAvailable() { return encodedDataStatus() >= EncodedDataStatus::SizeAvailable; }
size_t frameCount();
RepetitionCount repetitionCount();
String uti();
String filenameExtension();
std::optional<IntPoint> hotSpot();
IntSize size();
IntSize sizeRespectingOrientation();
Color singlePixelSolidColor();
bool frameIsBeingDecodedAndIsCompatibleWithOptionsAtIndex(size_t, const DecodingOptions&);
DecodingStatus frameDecodingStatusAtIndex(size_t);
bool frameHasAlphaAtIndex(size_t);
bool frameHasImageAtIndex(size_t);
bool frameHasFullSizeNativeImageAtIndex(size_t, const std::optional<SubsamplingLevel>&);
bool frameHasDecodedNativeImageCompatibleWithOptionsAtIndex(size_t, const std::optional<SubsamplingLevel>&, const DecodingOptions&);
SubsamplingLevel frameSubsamplingLevelAtIndex(size_t);
IntSize frameSizeAtIndex(size_t, SubsamplingLevel = SubsamplingLevel::Default);
unsigned frameBytesAtIndex(size_t, SubsamplingLevel = SubsamplingLevel::Default);
float frameDurationAtIndex(size_t);
ImageOrientation frameOrientationAtIndex(size_t);
NativeImagePtr frameImageAtIndex(size_t);
NativeImagePtr frameImageAtIndexCacheIfNeeded(size_t, SubsamplingLevel);
private:
ImageFrameCache(Image*);
ImageFrameCache(NativeImagePtr&&);
template<typename T, T (ImageDecoder::*functor)() const>
T metadata(const T& defaultValue, std::optional<T>* cachedValue = nullptr);
template<typename T, typename... Args>
T frameMetadataAtIndex(size_t, T (ImageFrame::*functor)(Args...) const, Args&&...);
template<typename T, typename... Args>
T frameMetadataAtIndexCacheIfNeeded(size_t, T (ImageFrame::*functor)() const, std::optional<T>* cachedValue, Args&&...);
bool isDecoderAvailable() const { return m_decoder; }
void destroyDecodedData(size_t frameCount, size_t excludeFrame);
void decodedSizeChanged(long long decodedSize);
void didDecodeProperties(unsigned decodedPropertiesSize);
void decodedSizeIncreased(unsigned decodedSize);
void decodedSizeDecreased(unsigned decodedSize);
void decodedSizeReset(unsigned decodedSize);
void setNativeImage(NativeImagePtr&&);
void cacheMetadataAtIndex(size_t, SubsamplingLevel, DecodingStatus = DecodingStatus::Invalid);
void cacheNativeImageAtIndex(NativeImagePtr&&, size_t, SubsamplingLevel, const DecodingOptions&, DecodingStatus = DecodingStatus::Invalid);
void cacheNativeImageAtIndexAsync(NativeImagePtr&&, size_t, SubsamplingLevel, const DecodingOptions&, DecodingStatus);
Ref<WorkQueue> decodingQueue();
const ImageFrame& frameAtIndexCacheIfNeeded(size_t, ImageFrame::Caching, const std::optional<SubsamplingLevel>& = { });
Image* m_image { nullptr };
RefPtr<ImageDecoder> m_decoder;
unsigned m_decodedSize { 0 };
unsigned m_decodedPropertiesSize { 0 };
Vector<ImageFrame, 1> m_frames;
struct ImageFrameRequest {
size_t index;
SubsamplingLevel subsamplingLevel;
DecodingOptions decodingOptions;
DecodingStatus decodingStatus;
bool operator==(const ImageFrameRequest& other) const
{
return index == other.index && subsamplingLevel == other.subsamplingLevel && decodingOptions == other.decodingOptions && decodingStatus == other.decodingStatus;
}
};
static const int BufferSize = 8;
using FrameRequestQueue = SynchronizedFixedQueue<ImageFrameRequest, BufferSize>;
using FrameCommitQueue = Deque<ImageFrameRequest, BufferSize>;
FrameRequestQueue m_frameRequestQueue;
FrameCommitQueue m_frameCommitQueue;
RefPtr<WorkQueue> m_decodingQueue;
std::optional<EncodedDataStatus> m_encodedDataStatus;
std::optional<size_t> m_frameCount;
std::optional<RepetitionCount> m_repetitionCount;
std::optional<String> m_uti;
std::optional<String> m_filenameExtension;
std::optional<std::optional<IntPoint>> m_hotSpot;
std::optional<IntSize> m_size;
std::optional<IntSize> m_sizeRespectingOrientation;
std::optional<Color> m_singlePixelSolidColor;
};
}