mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-30 16:22:00 +00:00
a2e11d2db7
Differential Revision: https://phabricator.services.mozilla.com/D226498
593 lines
19 KiB
C++
593 lines
19 KiB
C++
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
#include "mozilla/image/ImageUtils.h"
|
|
#include "DecodePool.h"
|
|
#include "Decoder.h"
|
|
#include "DecoderFactory.h"
|
|
#include "IDecodingTask.h"
|
|
#include "mozilla/AppShutdown.h"
|
|
#include "mozilla/DebugOnly.h"
|
|
#include "mozilla/gfx/2D.h"
|
|
#include "mozilla/Logging.h"
|
|
#include "nsNetUtil.h"
|
|
#include "nsStreamUtils.h"
|
|
|
|
namespace mozilla::image {
|
|
|
|
static LazyLogModule sLog("ImageUtils");
|
|
|
|
AnonymousDecoder::AnonymousDecoder() = default;
|
|
|
|
AnonymousDecoder::~AnonymousDecoder() = default;
|
|
|
|
class AnonymousDecoderTask : public IDecodingTask {
|
|
public:
|
|
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(AnonymousDecoderTask, final)
|
|
|
|
AnonymousDecoderTask(RefPtr<Decoder>&& aDecoder,
|
|
ThreadSafeWeakPtr<AnonymousDecoder>&& aOwner)
|
|
: mDecoder(std::move(aDecoder)), mOwner(std::move(aOwner)) {}
|
|
|
|
bool ShouldPreferSyncRun() const final { return false; }
|
|
|
|
TaskPriority Priority() const final { return TaskPriority::eLow; }
|
|
|
|
bool IsValid() const {
|
|
return !AppShutdown::IsInOrBeyond(ShutdownPhase::XPCOMShutdownFinal) &&
|
|
!mOwner.IsDead();
|
|
}
|
|
|
|
bool MaybeStart() {
|
|
if (!IsValid()) {
|
|
return false;
|
|
}
|
|
|
|
MOZ_LOG(sLog, LogLevel::Debug,
|
|
("[%p] AnonymousDecoderTask::Start -- queue", this));
|
|
DecodePool::Singleton()->AsyncRun(this);
|
|
return true;
|
|
}
|
|
|
|
void Resume() final {
|
|
if (!IsValid()) {
|
|
return;
|
|
}
|
|
|
|
MOZ_LOG(sLog, LogLevel::Debug,
|
|
("[%p] AnonymousDecoderTask::Resume -- queue", this));
|
|
DecodePool::Singleton()->AsyncRun(this);
|
|
}
|
|
|
|
void Run() final {
|
|
bool resume = true;
|
|
while (!mOwner.IsDead() && resume) {
|
|
LexerResult result = mDecoder->Decode(WrapNotNull(this));
|
|
if (result == LexerResult(Yield::NEED_MORE_DATA)) {
|
|
MOZ_LOG(sLog, LogLevel::Debug,
|
|
("[%p] AnonymousDecoderTask::Run -- need more data", this));
|
|
MOZ_ASSERT(result == LexerResult(Yield::NEED_MORE_DATA));
|
|
OnNeedMoreData();
|
|
return;
|
|
}
|
|
|
|
// Check if we have a new frame to process.
|
|
RefPtr<imgFrame> frame = mDecoder->GetCurrentFrame();
|
|
if (frame) {
|
|
RefPtr<gfx::SourceSurface> surface = frame->GetSourceSurface();
|
|
if (surface) {
|
|
MOZ_LOG(sLog, LogLevel::Debug,
|
|
("[%p] AnonymousDecoderTask::Run -- new frame %p", this,
|
|
frame.get()));
|
|
resume = OnFrameAvailable(std::move(frame), std::move(surface));
|
|
} else {
|
|
MOZ_ASSERT_UNREACHABLE("No surface from frame?");
|
|
}
|
|
}
|
|
|
|
if (result.is<TerminalState>()) {
|
|
MOZ_LOG(sLog, LogLevel::Debug,
|
|
("[%p] AnonymousDecoderTask::Run -- complete", this));
|
|
OnComplete(result == LexerResult(TerminalState::SUCCESS));
|
|
break;
|
|
}
|
|
|
|
MOZ_ASSERT(result == LexerResult(Yield::OUTPUT_AVAILABLE));
|
|
}
|
|
}
|
|
|
|
protected:
|
|
virtual ~AnonymousDecoderTask() = default;
|
|
|
|
virtual void OnNeedMoreData() {}
|
|
|
|
// Returns true if the caller should continue decoding more frames if
|
|
// possible.
|
|
virtual bool OnFrameAvailable(RefPtr<imgFrame>&& aFrame,
|
|
RefPtr<gfx::SourceSurface>&& aSurface) {
|
|
MOZ_ASSERT_UNREACHABLE("Unhandled frame!");
|
|
return true;
|
|
}
|
|
|
|
virtual void OnComplete(bool aSuccess) = 0;
|
|
|
|
RefPtr<Decoder> mDecoder;
|
|
ThreadSafeWeakPtr<AnonymousDecoder> mOwner;
|
|
};
|
|
|
|
class AnonymousMetadataDecoderTask final : public AnonymousDecoderTask {
|
|
public:
|
|
AnonymousMetadataDecoderTask(RefPtr<Decoder>&& aDecoder,
|
|
ThreadSafeWeakPtr<AnonymousDecoder>&& aOwner)
|
|
: AnonymousDecoderTask(std::move(aDecoder), std::move(aOwner)) {}
|
|
|
|
protected:
|
|
void OnComplete(bool aSuccess) override {
|
|
RefPtr<AnonymousDecoder> owner(mOwner);
|
|
if (!owner) {
|
|
return;
|
|
}
|
|
|
|
if (!aSuccess) {
|
|
owner->OnMetadata(nullptr);
|
|
return;
|
|
}
|
|
|
|
const auto& mdIn = mDecoder->GetImageMetadata();
|
|
owner->OnMetadata(&mdIn);
|
|
}
|
|
};
|
|
|
|
class AnonymousFrameCountDecoderTask final : public AnonymousDecoderTask {
|
|
public:
|
|
AnonymousFrameCountDecoderTask(RefPtr<Decoder>&& aDecoder,
|
|
ThreadSafeWeakPtr<AnonymousDecoder>&& aOwner)
|
|
: AnonymousDecoderTask(std::move(aDecoder), std::move(aOwner)) {}
|
|
|
|
protected:
|
|
void UpdateFrameCount(bool aComplete) {
|
|
RefPtr<AnonymousDecoder> owner(mOwner);
|
|
if (!owner) {
|
|
return;
|
|
}
|
|
|
|
const auto& mdIn = mDecoder->GetImageMetadata();
|
|
uint32_t frameCount = mdIn.HasFrameCount() ? mdIn.GetFrameCount() : 0;
|
|
owner->OnFrameCount(frameCount, aComplete);
|
|
}
|
|
|
|
void OnNeedMoreData() override { UpdateFrameCount(/* aComplete */ false); }
|
|
|
|
void OnComplete(bool aSuccess) override {
|
|
UpdateFrameCount(/* aComplete */ true);
|
|
}
|
|
};
|
|
|
|
class AnonymousFramesDecoderTask final : public AnonymousDecoderTask {
|
|
public:
|
|
AnonymousFramesDecoderTask(RefPtr<Decoder>&& aDecoder,
|
|
ThreadSafeWeakPtr<AnonymousDecoder>&& aOwner)
|
|
: AnonymousDecoderTask(std::move(aDecoder), std::move(aOwner)) {}
|
|
|
|
void SetOutputSize(const OrientedIntSize& aSize) {
|
|
if (mDecoder) {
|
|
mDecoder->SetOutputSize(aSize);
|
|
}
|
|
}
|
|
|
|
protected:
|
|
bool OnFrameAvailable(RefPtr<imgFrame>&& aFrame,
|
|
RefPtr<gfx::SourceSurface>&& aSurface) override {
|
|
RefPtr<AnonymousDecoder> owner(mOwner);
|
|
if (!owner) {
|
|
return false;
|
|
}
|
|
|
|
return owner->OnFrameAvailable(std::move(aFrame), std::move(aSurface));
|
|
}
|
|
|
|
void OnComplete(bool aSuccess) override {
|
|
RefPtr<AnonymousDecoder> owner(mOwner);
|
|
if (!owner) {
|
|
return;
|
|
}
|
|
|
|
owner->OnFramesComplete();
|
|
}
|
|
};
|
|
|
|
class AnonymousDecoderImpl final : public AnonymousDecoder {
|
|
public:
|
|
explicit AnonymousDecoderImpl(const Maybe<gfx::IntSize>& aOutputSize)
|
|
: mMutex("mozilla::image::AnonymousDecoderImpl::mMutex"),
|
|
mOutputSize(aOutputSize) {}
|
|
|
|
~AnonymousDecoderImpl() override { Destroy(); }
|
|
|
|
#ifdef MOZ_REFCOUNTED_LEAK_CHECKING
|
|
const char* typeName() const override {
|
|
return "mozilla::image::AnonymousDecoderImpl";
|
|
}
|
|
|
|
size_t typeSize() const override { return sizeof(*this); }
|
|
#endif
|
|
|
|
bool Initialize(RefPtr<Decoder>&& aDecoder) override {
|
|
MutexAutoLock lock(mMutex);
|
|
|
|
if (NS_WARN_IF(!aDecoder)) {
|
|
MOZ_LOG(sLog, LogLevel::Error,
|
|
("[%p] AnonymousDecoderImpl::Initialize -- bad decoder", this));
|
|
return false;
|
|
}
|
|
|
|
RefPtr<Decoder> metadataDecoder =
|
|
DecoderFactory::CloneAnonymousMetadataDecoder(aDecoder);
|
|
if (NS_WARN_IF(!metadataDecoder)) {
|
|
MOZ_LOG(sLog, LogLevel::Error,
|
|
("[%p] AnonymousDecoderImpl::Initialize -- failed clone metadata "
|
|
"decoder",
|
|
this));
|
|
return false;
|
|
}
|
|
|
|
DecoderFlags flags =
|
|
aDecoder->GetDecoderFlags() | DecoderFlags::COUNT_FRAMES;
|
|
RefPtr<Decoder> frameCountDecoder =
|
|
DecoderFactory::CloneAnonymousMetadataDecoder(aDecoder, Some(flags));
|
|
if (NS_WARN_IF(!frameCountDecoder)) {
|
|
MOZ_LOG(sLog, LogLevel::Error,
|
|
("[%p] AnonymousDecoderImpl::Initialize -- failed clone frame "
|
|
"count decoder",
|
|
this));
|
|
return false;
|
|
}
|
|
|
|
mMetadataTask = new AnonymousMetadataDecoderTask(
|
|
std::move(metadataDecoder), ThreadSafeWeakPtr<AnonymousDecoder>(this));
|
|
mFrameCountTask = new AnonymousFrameCountDecoderTask(
|
|
std::move(frameCountDecoder),
|
|
ThreadSafeWeakPtr<AnonymousDecoder>(this));
|
|
mFramesTask = new AnonymousFramesDecoderTask(
|
|
std::move(aDecoder), ThreadSafeWeakPtr<AnonymousDecoder>(this));
|
|
|
|
MOZ_LOG(sLog, LogLevel::Debug,
|
|
("[%p] AnonymousDecoderImpl::Initialize -- success", this));
|
|
return true;
|
|
}
|
|
|
|
void Destroy() override {
|
|
MutexAutoLock lock(mMutex);
|
|
DestroyLocked(NS_ERROR_ABORT);
|
|
}
|
|
|
|
void DestroyLocked(nsresult aResult) MOZ_REQUIRES(mMutex) {
|
|
MOZ_LOG(sLog, LogLevel::Debug,
|
|
("[%p] AnonymousDecoderImpl::Destroy", this));
|
|
|
|
mFramesToDecode = 0;
|
|
mMetadataTask = nullptr;
|
|
mFrameCountTask = nullptr;
|
|
mFramesTask = nullptr;
|
|
mPendingFramesResult.mFrames.Clear();
|
|
mPendingFramesResult.mFinished = true;
|
|
mMetadataPromise.RejectIfExists(aResult, __func__);
|
|
mFrameCountPromise.RejectIfExists(aResult, __func__);
|
|
mFramesPromise.RejectIfExists(aResult, __func__);
|
|
}
|
|
|
|
void OnMetadata(const ImageMetadata* aMetadata) override {
|
|
MutexAutoLock lock(mMutex);
|
|
|
|
// We must have already gotten destroyed before metadata decoding finished.
|
|
if (!mMetadataTask) {
|
|
return;
|
|
}
|
|
|
|
if (!aMetadata) {
|
|
MOZ_LOG(sLog, LogLevel::Error,
|
|
("[%p] AnonymousDecoderImpl::OnMetadata -- failed", this));
|
|
DestroyLocked(NS_ERROR_FAILURE);
|
|
return;
|
|
}
|
|
|
|
const auto size = aMetadata->GetSize();
|
|
mMetadataResult.mWidth = size.width;
|
|
mMetadataResult.mHeight = size.height;
|
|
mMetadataResult.mRepetitions = aMetadata->GetLoopCount();
|
|
mMetadataResult.mAnimated = aMetadata->HasAnimation();
|
|
|
|
MOZ_LOG(sLog, LogLevel::Debug,
|
|
("[%p] AnonymousDecoderImpl::OnMetadata -- %dx%d, repetitions %d, "
|
|
"animated %d",
|
|
this, size.width, size.height, mMetadataResult.mRepetitions,
|
|
mMetadataResult.mAnimated));
|
|
|
|
if (mOutputSize && !mMetadataResult.mAnimated && mFramesTask) {
|
|
if (mOutputSize->width <= size.width &&
|
|
mOutputSize->height <= size.height) {
|
|
MOZ_LOG(
|
|
sLog, LogLevel::Debug,
|
|
("[%p] AnonymousDecoderImpl::OnMetadata -- use output size %dx%d",
|
|
this, mOutputSize->width, mOutputSize->height));
|
|
mFramesTask->SetOutputSize(
|
|
OrientedIntSize::FromUnknownSize(*mOutputSize));
|
|
} else {
|
|
MOZ_LOG(sLog, LogLevel::Debug,
|
|
("[%p] AnonymousDecoderImpl::OnMetadata -- cannot use output "
|
|
"size %dx%d, exceeds metadata size",
|
|
this, mOutputSize->width, mOutputSize->height));
|
|
}
|
|
}
|
|
|
|
if (!mMetadataResult.mAnimated) {
|
|
mMetadataResult.mFrameCount = 1;
|
|
mMetadataResult.mFrameCountComplete = true;
|
|
mMetadataTask = nullptr;
|
|
mFrameCountTask = nullptr;
|
|
} else if (mFrameCountTask && !mFrameCountTaskRunning) {
|
|
MOZ_LOG(
|
|
sLog, LogLevel::Debug,
|
|
("[%p] AnonymousDecoderImpl::OnMetadata -- start frame count task",
|
|
this));
|
|
mFrameCountTaskRunning = mFrameCountTask->MaybeStart();
|
|
return;
|
|
}
|
|
|
|
mMetadataPromise.Resolve(mMetadataResult, __func__);
|
|
|
|
if (mFramesTask && mFramesToDecode > 0 && !mFramesTaskRunning) {
|
|
MOZ_LOG(sLog, LogLevel::Debug,
|
|
("[%p] AnonymousDecoderImpl::OnMetadata -- start frames task, "
|
|
"want %zu",
|
|
this, mFramesToDecode));
|
|
mFramesTaskRunning = mFramesTask->MaybeStart();
|
|
}
|
|
}
|
|
|
|
void OnFrameCount(uint32_t aFrameCount, bool aComplete) override {
|
|
MutexAutoLock lock(mMutex);
|
|
|
|
// We must have already gotten destroyed before frame count decoding
|
|
// finished.
|
|
if (!mFrameCountTask) {
|
|
return;
|
|
}
|
|
|
|
MOZ_LOG(sLog, LogLevel::Debug,
|
|
("[%p] AnonymousDecoderImpl::OnFrameCount -- frameCount %u, "
|
|
"complete %d",
|
|
this, aFrameCount, aComplete));
|
|
|
|
bool resolve = aComplete;
|
|
if (mFrameCount < aFrameCount) {
|
|
mFrameCount = aFrameCount;
|
|
resolve = true;
|
|
}
|
|
|
|
// If metadata completing is waiting on an updated frame count, resolve it.
|
|
mMetadataResult.mFrameCount = mFrameCount;
|
|
mMetadataResult.mFrameCountComplete = aComplete;
|
|
mMetadataPromise.ResolveIfExists(mMetadataResult, __func__);
|
|
|
|
if (mMetadataTask) {
|
|
mMetadataTask = nullptr;
|
|
if (mFramesTask && mFramesToDecode > 0 && !mFramesTaskRunning) {
|
|
MOZ_LOG(
|
|
sLog, LogLevel::Debug,
|
|
("[%p] AnonymousDecoderImpl::OnFrameCount -- start frames task, "
|
|
"want %zu",
|
|
this, mFramesToDecode));
|
|
mFramesTaskRunning = mFramesTask->MaybeStart();
|
|
}
|
|
}
|
|
|
|
if (resolve) {
|
|
mFrameCountPromise.ResolveIfExists(
|
|
DecodeFrameCountResult{aFrameCount, aComplete}, __func__);
|
|
}
|
|
|
|
if (aComplete) {
|
|
mFrameCountTask = nullptr;
|
|
}
|
|
}
|
|
|
|
bool OnFrameAvailable(RefPtr<imgFrame>&& aFrame,
|
|
RefPtr<gfx::SourceSurface>&& aSurface) override {
|
|
MutexAutoLock lock(mMutex);
|
|
|
|
MOZ_DIAGNOSTIC_ASSERT(mFramesTaskRunning);
|
|
|
|
// We must have already gotten destroyed before frame decoding finished.
|
|
if (!mFramesTask) {
|
|
mFramesTaskRunning = false;
|
|
return false;
|
|
}
|
|
|
|
// Filter duplicate frames.
|
|
if (mLastFrame == aFrame) {
|
|
return true;
|
|
}
|
|
|
|
mPendingFramesResult.mFrames.AppendElement(
|
|
DecodedFrame{std::move(aSurface), mMetadataResult.mAnimated
|
|
? aFrame->GetTimeout()
|
|
: FrameTimeout::Forever()});
|
|
mLastFrame = std::move(aFrame);
|
|
|
|
MOZ_LOG(sLog, LogLevel::Debug,
|
|
("[%p] AnonymousDecoderImpl::OnFrameAvailable -- want %zu, got %zu",
|
|
this, mFramesToDecode, mPendingFramesResult.mFrames.Length()));
|
|
|
|
// Check if we have satisfied the number of requested frames.
|
|
if (mFramesToDecode > mPendingFramesResult.mFrames.Length()) {
|
|
return true;
|
|
}
|
|
|
|
mFramesToDecode = 0;
|
|
if (!mFramesPromise.IsEmpty()) {
|
|
mFramesPromise.Resolve(std::move(mPendingFramesResult), __func__);
|
|
}
|
|
mFramesTaskRunning = false;
|
|
return false;
|
|
}
|
|
|
|
void OnFramesComplete() override {
|
|
MutexAutoLock lock(mMutex);
|
|
|
|
// We must have already gotten destroyed before frame decoding finished.
|
|
if (!mFramesTask) {
|
|
return;
|
|
}
|
|
|
|
MOZ_LOG(
|
|
sLog, LogLevel::Debug,
|
|
("[%p] AnonymousDecoderImpl::OnFramesComplete -- wanted %zu, got %zu",
|
|
this, mFramesToDecode, mPendingFramesResult.mFrames.Length()));
|
|
|
|
mFramesToDecode = 0;
|
|
mPendingFramesResult.mFinished = true;
|
|
if (!mFramesPromise.IsEmpty()) {
|
|
mFramesPromise.Resolve(std::move(mPendingFramesResult), __func__);
|
|
}
|
|
mLastFrame = nullptr;
|
|
mFramesTask = nullptr;
|
|
}
|
|
|
|
RefPtr<DecodeMetadataPromise> DecodeMetadata() override {
|
|
MutexAutoLock lock(mMutex);
|
|
|
|
if (!mMetadataTask) {
|
|
MOZ_LOG(sLog, LogLevel::Debug,
|
|
("[%p] AnonymousDecoderImpl::DecodeMetadata -- already complete",
|
|
this));
|
|
if (mMetadataResult.mWidth > 0 && mMetadataResult.mHeight > 0) {
|
|
return DecodeMetadataPromise::CreateAndResolve(mMetadataResult,
|
|
__func__);
|
|
}
|
|
return DecodeMetadataPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
|
|
}
|
|
|
|
if (!mMetadataTaskRunning) {
|
|
MOZ_LOG(sLog, LogLevel::Debug,
|
|
("[%p] AnonymousDecoderImpl::DecodeMetadata -- queue", this));
|
|
mMetadataTaskRunning = mMetadataTask->MaybeStart();
|
|
}
|
|
|
|
return mMetadataPromise.Ensure(__func__);
|
|
}
|
|
|
|
RefPtr<DecodeFrameCountPromise> DecodeFrameCount(
|
|
uint32_t aKnownFrameCount) override {
|
|
MutexAutoLock lock(mMutex);
|
|
|
|
MOZ_ASSERT(mFrameCountPromise.IsEmpty());
|
|
|
|
// If we have finished, or we have an updated frame count, return right
|
|
// away. This may drive the frame decoder for the application as the data
|
|
// comes in from the network.
|
|
if (!mFrameCountTask || aKnownFrameCount < mFrameCount) {
|
|
MOZ_LOG(sLog, LogLevel::Debug,
|
|
("[%p] AnonymousDecoderImpl::DecodeFrameCount -- known %u, "
|
|
"detected %u, complete %d",
|
|
this, aKnownFrameCount, mFrameCount, !mFrameCountTask));
|
|
return DecodeFrameCountPromise::CreateAndResolve(
|
|
DecodeFrameCountResult{mFrameCount,
|
|
/* mFinished */ !mFrameCountTask},
|
|
__func__);
|
|
}
|
|
|
|
// mFrameCountTask is launching when metadata decoding is finished.
|
|
MOZ_LOG(sLog, LogLevel::Debug,
|
|
("[%p] AnonymousDecoderImpl::DecodeFrameCount -- waiting, known "
|
|
"%u, detected %u",
|
|
this, aKnownFrameCount, mFrameCount));
|
|
return mFrameCountPromise.Ensure(__func__);
|
|
}
|
|
|
|
RefPtr<DecodeFramesPromise> DecodeFrames(size_t aCount) override {
|
|
MutexAutoLock lock(mMutex);
|
|
|
|
// If we cleared our task reference, then we know we finished decoding.
|
|
if (!mFramesTask) {
|
|
mPendingFramesResult.mFinished = true;
|
|
return DecodeFramesPromise::CreateAndResolve(
|
|
std::move(mPendingFramesResult), __func__);
|
|
}
|
|
|
|
// If we are not waiting on any frames, then we know we paused decoding.
|
|
// If we still are metadata decoding, we need to wait.
|
|
if (mFramesToDecode == 0 && !mMetadataTask && !mFramesTaskRunning) {
|
|
MOZ_LOG(sLog, LogLevel::Debug,
|
|
("[%p] AnonymousDecoderImpl::DecodeFrames -- queue", this));
|
|
mFramesTaskRunning = mFramesTask->MaybeStart();
|
|
}
|
|
|
|
mFramesToDecode = std::max(mFramesToDecode, aCount);
|
|
return mFramesPromise.Ensure(__func__);
|
|
}
|
|
|
|
void CancelDecodeFrames() override {
|
|
MutexAutoLock lock(mMutex);
|
|
MOZ_LOG(sLog, LogLevel::Debug,
|
|
("[%p] AnonymousDecoderImpl::CancelDecodeFrames", this));
|
|
mFramesToDecode = 0;
|
|
mFramesPromise.RejectIfExists(NS_ERROR_ABORT, __func__);
|
|
}
|
|
|
|
private:
|
|
Mutex mMutex;
|
|
MozPromiseHolder<DecodeMetadataPromise> mMetadataPromise
|
|
MOZ_GUARDED_BY(mMutex);
|
|
MozPromiseHolder<DecodeFrameCountPromise> mFrameCountPromise
|
|
MOZ_GUARDED_BY(mMutex);
|
|
MozPromiseHolder<DecodeFramesPromise> mFramesPromise MOZ_GUARDED_BY(mMutex);
|
|
RefPtr<AnonymousFramesDecoderTask> mFramesTask MOZ_GUARDED_BY(mMutex);
|
|
RefPtr<AnonymousMetadataDecoderTask> mMetadataTask MOZ_GUARDED_BY(mMutex);
|
|
RefPtr<AnonymousFrameCountDecoderTask> mFrameCountTask MOZ_GUARDED_BY(mMutex);
|
|
RefPtr<imgFrame> mLastFrame MOZ_GUARDED_BY(mMutex);
|
|
DecodeMetadataResult mMetadataResult MOZ_GUARDED_BY(mMutex);
|
|
DecodeFramesResult mPendingFramesResult MOZ_GUARDED_BY(mMutex);
|
|
Maybe<gfx::IntSize> mOutputSize MOZ_GUARDED_BY(mMutex);
|
|
size_t mFramesToDecode MOZ_GUARDED_BY(mMutex) = 1;
|
|
uint32_t mFrameCount MOZ_GUARDED_BY(mMutex) = 0;
|
|
bool mMetadataTaskRunning MOZ_GUARDED_BY(mMutex) = false;
|
|
bool mFrameCountTaskRunning MOZ_GUARDED_BY(mMutex) = false;
|
|
bool mFramesTaskRunning MOZ_GUARDED_BY(mMutex) = false;
|
|
};
|
|
|
|
/* static */ already_AddRefed<AnonymousDecoder> ImageUtils::CreateDecoder(
|
|
SourceBuffer* aSourceBuffer, DecoderType aType,
|
|
const Maybe<gfx::IntSize>& aOutputSize, SurfaceFlags aSurfaceFlags) {
|
|
if (NS_WARN_IF(!aSourceBuffer)) {
|
|
return nullptr;
|
|
}
|
|
|
|
if (NS_WARN_IF(aType == DecoderType::UNKNOWN)) {
|
|
return nullptr;
|
|
}
|
|
|
|
RefPtr<Decoder> decoder = DecoderFactory::CreateAnonymousDecoder(
|
|
aType, WrapNotNull(aSourceBuffer), Nothing(),
|
|
DecoderFlags::IMAGE_IS_TRANSIENT, aSurfaceFlags);
|
|
if (NS_WARN_IF(!decoder)) {
|
|
return nullptr;
|
|
}
|
|
|
|
auto anonymousDecoder = MakeRefPtr<AnonymousDecoderImpl>(aOutputSize);
|
|
if (NS_WARN_IF(!anonymousDecoder->Initialize(std::move(decoder)))) {
|
|
return nullptr;
|
|
}
|
|
|
|
return anonymousDecoder.forget();
|
|
}
|
|
|
|
/* static */ DecoderType ImageUtils::GetDecoderType(
|
|
const nsACString& aMimeType) {
|
|
return DecoderFactory::GetDecoderType(aMimeType.Data());
|
|
}
|
|
|
|
} // namespace mozilla::image
|