IDecodingTask.cpp 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  2. /* This Source Code Form is subject to the terms of the Mozilla Public
  3. * License, v. 2.0. If a copy of the MPL was not distributed with this
  4. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  5. #include "IDecodingTask.h"
  6. #include "gfxPrefs.h"
  7. #include "nsThreadUtils.h"
  8. #include "Decoder.h"
  9. #include "DecodePool.h"
  10. #include "RasterImage.h"
  11. #include "SurfaceCache.h"
  12. namespace mozilla {
  13. using gfx::IntRect;
  14. namespace image {
  15. ///////////////////////////////////////////////////////////////////////////////
  16. // Helpers for sending notifications to the image associated with a decoder.
  17. ///////////////////////////////////////////////////////////////////////////////
  18. /* static */ void
  19. IDecodingTask::NotifyProgress(NotNull<RasterImage*> aImage,
  20. NotNull<Decoder*> aDecoder)
  21. {
  22. MOZ_ASSERT(aDecoder->HasProgress() && !aDecoder->IsMetadataDecode());
  23. // Capture the decoder's state. If we need to notify asynchronously, it's
  24. // important that we don't wait until the lambda actually runs to capture the
  25. // state that we're going to notify. That would both introduce data races on
  26. // the decoder's state and cause inconsistencies between the NotifyProgress()
  27. // calls we make off-main-thread and the notifications that RasterImage
  28. // actually receives, which would cause bugs.
  29. Progress progress = aDecoder->TakeProgress();
  30. IntRect invalidRect = aDecoder->TakeInvalidRect();
  31. Maybe<uint32_t> frameCount = aDecoder->TakeCompleteFrameCount();
  32. DecoderFlags decoderFlags = aDecoder->GetDecoderFlags();
  33. SurfaceFlags surfaceFlags = aDecoder->GetSurfaceFlags();
  34. // Synchronously notify if we can.
  35. if (NS_IsMainThread() && !(decoderFlags & DecoderFlags::ASYNC_NOTIFY)) {
  36. aImage->NotifyProgress(progress, invalidRect, frameCount,
  37. decoderFlags, surfaceFlags);
  38. return;
  39. }
  40. // We're forced to notify asynchronously.
  41. NotNull<RefPtr<RasterImage>> image = aImage;
  42. NS_DispatchToMainThread(NS_NewRunnableFunction([=]() -> void {
  43. image->NotifyProgress(progress, invalidRect, frameCount,
  44. decoderFlags, surfaceFlags);
  45. }));
  46. }
  47. /* static */ void
  48. IDecodingTask::NotifyDecodeComplete(NotNull<RasterImage*> aImage,
  49. NotNull<Decoder*> aDecoder)
  50. {
  51. MOZ_ASSERT(aDecoder->HasError() || !aDecoder->InFrame(),
  52. "Decode complete in the middle of a frame?");
  53. // Capture the decoder's state.
  54. DecoderFinalStatus finalStatus = aDecoder->FinalStatus();
  55. ImageMetadata metadata = aDecoder->GetImageMetadata();
  56. DecoderTelemetry telemetry = aDecoder->Telemetry();
  57. Progress progress = aDecoder->TakeProgress();
  58. IntRect invalidRect = aDecoder->TakeInvalidRect();
  59. Maybe<uint32_t> frameCount = aDecoder->TakeCompleteFrameCount();
  60. DecoderFlags decoderFlags = aDecoder->GetDecoderFlags();
  61. SurfaceFlags surfaceFlags = aDecoder->GetSurfaceFlags();
  62. // Synchronously notify if we can.
  63. if (NS_IsMainThread() && !(decoderFlags & DecoderFlags::ASYNC_NOTIFY)) {
  64. aImage->NotifyDecodeComplete(finalStatus, metadata, telemetry, progress,
  65. invalidRect, frameCount, decoderFlags,
  66. surfaceFlags);
  67. return;
  68. }
  69. // We're forced to notify asynchronously.
  70. NotNull<RefPtr<RasterImage>> image = aImage;
  71. NS_DispatchToMainThread(NS_NewRunnableFunction([=]() -> void {
  72. image->NotifyDecodeComplete(finalStatus, metadata, telemetry, progress,
  73. invalidRect, frameCount, decoderFlags,
  74. surfaceFlags);
  75. }));
  76. }
  77. ///////////////////////////////////////////////////////////////////////////////
  78. // IDecodingTask implementation.
  79. ///////////////////////////////////////////////////////////////////////////////
  80. void
  81. IDecodingTask::Resume()
  82. {
  83. DecodePool::Singleton()->AsyncRun(this);
  84. }
  85. ///////////////////////////////////////////////////////////////////////////////
  86. // MetadataDecodingTask implementation.
  87. ///////////////////////////////////////////////////////////////////////////////
  88. MetadataDecodingTask::MetadataDecodingTask(NotNull<Decoder*> aDecoder)
  89. : mMutex("mozilla::image::MetadataDecodingTask")
  90. , mDecoder(aDecoder)
  91. {
  92. MOZ_ASSERT(mDecoder->IsMetadataDecode(),
  93. "Use DecodingTask for non-metadata decodes");
  94. }
  95. void
  96. MetadataDecodingTask::Run()
  97. {
  98. MutexAutoLock lock(mMutex);
  99. LexerResult result = mDecoder->Decode(WrapNotNull(this));
  100. if (result.is<TerminalState>()) {
  101. NotifyDecodeComplete(mDecoder->GetImage(), mDecoder);
  102. return; // We're done.
  103. }
  104. if (result == LexerResult(Yield::NEED_MORE_DATA)) {
  105. // We can't make any more progress right now. We also don't want to report
  106. // any progress, because it's important that metadata decode results are
  107. // delivered atomically. The decoder itself will ensure that we get
  108. // reenqueued when more data is available; just return for now.
  109. return;
  110. }
  111. MOZ_ASSERT_UNREACHABLE("Metadata decode yielded for an unexpected reason");
  112. }
  113. ///////////////////////////////////////////////////////////////////////////////
  114. // AnonymousDecodingTask implementation.
  115. ///////////////////////////////////////////////////////////////////////////////
  116. AnonymousDecodingTask::AnonymousDecodingTask(NotNull<Decoder*> aDecoder,
  117. bool aResumable)
  118. : mDecoder(aDecoder)
  119. , mResumable(aResumable)
  120. { }
  121. void
  122. AnonymousDecodingTask::Run()
  123. {
  124. while (true) {
  125. LexerResult result = mDecoder->Decode(WrapNotNull(this));
  126. if (result.is<TerminalState>()) {
  127. return; // We're done.
  128. }
  129. if (result == LexerResult(Yield::NEED_MORE_DATA)) {
  130. // We can't make any more progress right now. Let the caller decide how to
  131. // handle it.
  132. return;
  133. }
  134. // Right now we don't do anything special for other kinds of yields, so just
  135. // keep working.
  136. MOZ_ASSERT(result.is<Yield>());
  137. }
  138. }
  139. void
  140. AnonymousDecodingTask::Resume()
  141. {
  142. // Anonymous decoders normally get all their data at once. We have some situations
  143. // where they don't. If explicitly requested, resuming should be supported.
  144. if (mResumable) {
  145. RefPtr<AnonymousDecodingTask> self(this);
  146. NS_DispatchToMainThread(NS_NewRunnableFunction([self]() -> void { self->Run(); }));
  147. }
  148. }
  149. } // namespace image
  150. } // namespace mozilla