diff --git a/image/IDecodingTask.h b/image/IDecodingTask.h index 380e680950cf..f5e67545c8d4 100644 --- a/image/IDecodingTask.h +++ b/image/IDecodingTask.h @@ -88,7 +88,7 @@ class MetadataDecodingTask final : public IDecodingTask { * An IDecodingTask implementation for anonymous decoders - that is, decoders * with no associated Image object. */ -class AnonymousDecodingTask final : public IDecodingTask { +class AnonymousDecodingTask : public IDecodingTask { public: NS_INLINE_DECL_THREADSAFE_REFCOUNTING(AnonymousDecodingTask, override) @@ -101,7 +101,7 @@ class AnonymousDecodingTask final : public IDecodingTask { void Resume() override; - private: + protected: virtual ~AnonymousDecodingTask() {} NotNull> mDecoder; diff --git a/image/test/gtest/TestDecoders.cpp b/image/test/gtest/TestDecoders.cpp index f043b011d033..4b1f6cf2b6cc 100644 --- a/image/test/gtest/TestDecoders.cpp +++ b/image/test/gtest/TestDecoders.cpp @@ -5,6 +5,7 @@ #include "gtest/gtest.h" #include "Common.h" +#include "mozilla/Monitor.h" #include "AnimationSurfaceProvider.h" #include "DecodePool.h" #include "Decoder.h" @@ -122,6 +123,67 @@ static void CheckDecoderBadBuffer(const ImageTestCase& aTestCase) { }); } +/** + * AnonymousDecodingTask but with a monitor so we can wait for it to finish + * safely. + */ +class MonitorAnonymousDecodingTask final : public AnonymousDecodingTask { + public: + explicit MonitorAnonymousDecodingTask(NotNull aDecoder, + bool aResumable); + + void Run() override; + + void WaitUntilFinished(); + + private: + virtual ~MonitorAnonymousDecodingTask() = default; + + Monitor mMonitor MOZ_UNANNOTATED; +}; + +MonitorAnonymousDecodingTask::MonitorAnonymousDecodingTask( + NotNull aDecoder, bool aResumable) + : AnonymousDecodingTask(aDecoder, aResumable), + mMonitor("MonitorAnonymousDecodingTask") {} + +void MonitorAnonymousDecodingTask::Run() { + MonitorAutoLock lock(mMonitor); + + while (true) { + LexerResult result = mDecoder->Decode(WrapNotNull(this)); + + if (result.is()) { + mMonitor.NotifyAll(); + return; // We're done. + } + + if (result == LexerResult(Yield::NEED_MORE_DATA)) { + // We can't make any more progress right now. Let the caller decide how to + // handle it. + mMonitor.NotifyAll(); + return; + } + + // Right now we don't do anything special for other kinds of yields, so just + // keep working. + MOZ_ASSERT(result.is()); + } +} + +void MonitorAnonymousDecodingTask::WaitUntilFinished() { + MonitorAutoLock lock(mMonitor); + + while (true) { + if (mDecoder->GetDecodeDone()) { + return; + } + + // Not done yet, so we'll have to wait. + mMonitor.Wait(); + } +} + template void WithSingleChunkDecode(const ImageTestCase& aTestCase, const Maybe& aOutputSize, @@ -150,15 +212,13 @@ void WithSingleChunkDecode(const ImageTestCase& aTestCase, decoderType, sourceBuffer, aOutputSize, decoderFlags, aTestCase.mSurfaceFlags); ASSERT_TRUE(decoder != nullptr); - RefPtr task = - new AnonymousDecodingTask(WrapNotNull(decoder), /* aResumable */ false); + RefPtr task = new MonitorAnonymousDecodingTask( + WrapNotNull(decoder), /* aResumable */ false); if (aUseDecodePool) { DecodePool::Singleton()->AsyncRun(task.get()); - while (!decoder->GetDecodeDone()) { - task->Resume(); - } + task->WaitUntilFinished(); } else { // Run the full decoder synchronously on the main thread. task->Run(); } diff --git a/image/test/gtest/moz.build b/image/test/gtest/moz.build index 2501e98f60d2..9ab29ceb2e66 100644 --- a/image/test/gtest/moz.build +++ b/image/test/gtest/moz.build @@ -12,6 +12,7 @@ UNIFIED_SOURCES = [ "TestAnimationFrameBuffer.cpp", "TestBlendAnimationFilter.cpp", "TestCopyOnWrite.cpp", + "TestDecoders.cpp", "TestDecodersPerf.cpp", "TestDecodeToSurface.cpp", "TestDeinterlacingFilter.cpp", @@ -28,12 +29,6 @@ UNIFIED_SOURCES = [ "TestSwizzleFilter.cpp", ] -# Bug 1894284 - Fails under TSAN -if not CONFIG["MOZ_TSAN"]: - UNIFIED_SOURCES += [ - "TestDecoders.cpp", - ] - TEST_HARNESS_FILES.gtest += [ "animated-with-extra-image-sub-blocks.gif", "blend.avif",