Decoder.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517
  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 "Decoder.h"
  6. #include "mozilla/gfx/2D.h"
  7. #include "DecodePool.h"
  8. #include "GeckoProfiler.h"
  9. #include "IDecodingTask.h"
  10. #include "ISurfaceProvider.h"
  11. #include "nsProxyRelease.h"
  12. #include "nsServiceManagerUtils.h"
  13. #include "nsComponentManagerUtils.h"
  14. #include "mozilla/Telemetry.h"
  15. using mozilla::gfx::IntSize;
  16. using mozilla::gfx::SurfaceFormat;
  17. namespace mozilla {
  18. namespace image {
  19. class MOZ_STACK_CLASS AutoRecordDecoderTelemetry final
  20. {
  21. public:
  22. explicit AutoRecordDecoderTelemetry(Decoder* aDecoder)
  23. : mDecoder(aDecoder)
  24. {
  25. MOZ_ASSERT(mDecoder);
  26. // Begin recording telemetry data.
  27. mStartTime = TimeStamp::Now();
  28. }
  29. ~AutoRecordDecoderTelemetry()
  30. {
  31. // Finish telemetry.
  32. mDecoder->mDecodeTime += (TimeStamp::Now() - mStartTime);
  33. }
  34. private:
  35. Decoder* mDecoder;
  36. TimeStamp mStartTime;
  37. };
  38. Decoder::Decoder(RasterImage* aImage)
  39. : mImageData(nullptr)
  40. , mImageDataLength(0)
  41. , mColormap(nullptr)
  42. , mColormapSize(0)
  43. , mImage(aImage)
  44. , mProgress(NoProgress)
  45. , mFrameCount(0)
  46. , mLoopLength(FrameTimeout::Zero())
  47. , mDecoderFlags(DefaultDecoderFlags())
  48. , mSurfaceFlags(DefaultSurfaceFlags())
  49. , mInitialized(false)
  50. , mMetadataDecode(false)
  51. , mHaveExplicitOutputSize(false)
  52. , mInFrame(false)
  53. , mFinishedNewFrame(false)
  54. , mReachedTerminalState(false)
  55. , mDecodeDone(false)
  56. , mError(false)
  57. , mShouldReportError(false)
  58. { }
  59. Decoder::~Decoder()
  60. {
  61. MOZ_ASSERT(mProgress == NoProgress || !mImage,
  62. "Destroying Decoder without taking all its progress changes");
  63. MOZ_ASSERT(mInvalidRect.IsEmpty() || !mImage,
  64. "Destroying Decoder without taking all its invalidations");
  65. mInitialized = false;
  66. if (mImage && !NS_IsMainThread()) {
  67. // Dispatch mImage to main thread to prevent it from being destructed by the
  68. // decode thread.
  69. NS_ReleaseOnMainThread(mImage.forget());
  70. }
  71. }
  72. /*
  73. * Common implementation of the decoder interface.
  74. */
  75. nsresult
  76. Decoder::Init()
  77. {
  78. // No re-initializing
  79. MOZ_ASSERT(!mInitialized, "Can't re-initialize a decoder!");
  80. // All decoders must have a SourceBufferIterator.
  81. MOZ_ASSERT(mIterator);
  82. // Metadata decoders must not set an output size.
  83. MOZ_ASSERT_IF(mMetadataDecode, !mHaveExplicitOutputSize);
  84. // All decoders must be anonymous except for metadata decoders.
  85. // XXX(seth): Soon that exception will be removed.
  86. MOZ_ASSERT_IF(mImage, IsMetadataDecode());
  87. // Implementation-specific initialization.
  88. nsresult rv = InitInternal();
  89. mInitialized = true;
  90. return rv;
  91. }
  92. LexerResult
  93. Decoder::Decode(IResumable* aOnResume /* = nullptr */)
  94. {
  95. MOZ_ASSERT(mInitialized, "Should be initialized here");
  96. MOZ_ASSERT(mIterator, "Should have a SourceBufferIterator");
  97. // If we're already done, don't attempt to keep decoding.
  98. if (GetDecodeDone()) {
  99. return LexerResult(HasError() ? TerminalState::FAILURE
  100. : TerminalState::SUCCESS);
  101. }
  102. LexerResult lexerResult(TerminalState::FAILURE);
  103. {
  104. PROFILER_LABEL("ImageDecoder", "Decode", js::ProfileEntry::Category::GRAPHICS);
  105. AutoRecordDecoderTelemetry telemetry(this);
  106. lexerResult = DoDecode(*mIterator, aOnResume);
  107. };
  108. if (lexerResult.is<Yield>()) {
  109. // We either need more data to continue (in which case either @aOnResume or
  110. // the caller will reschedule us to run again later), or the decoder is
  111. // yielding to allow the caller access to some intermediate output.
  112. return lexerResult;
  113. }
  114. // We reached a terminal state; we're now done decoding.
  115. MOZ_ASSERT(lexerResult.is<TerminalState>());
  116. mReachedTerminalState = true;
  117. // If decoding failed, record that fact.
  118. if (lexerResult.as<TerminalState>() == TerminalState::FAILURE) {
  119. PostError();
  120. }
  121. // Perform final cleanup.
  122. CompleteDecode();
  123. return LexerResult(HasError() ? TerminalState::FAILURE
  124. : TerminalState::SUCCESS);
  125. }
  126. LexerResult
  127. Decoder::TerminateFailure()
  128. {
  129. PostError();
  130. // Perform final cleanup if need be.
  131. if (!mReachedTerminalState) {
  132. mReachedTerminalState = true;
  133. CompleteDecode();
  134. }
  135. return LexerResult(TerminalState::FAILURE);
  136. }
  137. bool
  138. Decoder::ShouldSyncDecode(size_t aByteLimit)
  139. {
  140. MOZ_ASSERT(aByteLimit > 0);
  141. MOZ_ASSERT(mIterator, "Should have a SourceBufferIterator");
  142. return mIterator->RemainingBytesIsNoMoreThan(aByteLimit);
  143. }
  144. void
  145. Decoder::CompleteDecode()
  146. {
  147. // Implementation-specific finalization.
  148. nsresult rv = BeforeFinishInternal();
  149. if (NS_FAILED(rv)) {
  150. PostError();
  151. }
  152. rv = HasError() ? FinishWithErrorInternal()
  153. : FinishInternal();
  154. if (NS_FAILED(rv)) {
  155. PostError();
  156. }
  157. if (IsMetadataDecode()) {
  158. // If this was a metadata decode and we never got a size, the decode failed.
  159. if (!HasSize()) {
  160. PostError();
  161. }
  162. return;
  163. }
  164. // If the implementation left us mid-frame, finish that up. Note that it may
  165. // have left us transparent.
  166. if (mInFrame) {
  167. PostHasTransparency();
  168. PostFrameStop();
  169. }
  170. // If PostDecodeDone() has not been called, we may need to send teardown
  171. // notifications if it is unrecoverable.
  172. if (!mDecodeDone) {
  173. // We should always report an error to the console in this case.
  174. mShouldReportError = true;
  175. if (GetCompleteFrameCount() > 0) {
  176. // We're usable if we have at least one complete frame, so do exactly
  177. // what we should have when the decoder completed.
  178. PostHasTransparency();
  179. PostDecodeDone();
  180. } else {
  181. // We're not usable. Record some final progress indicating the error.
  182. mProgress |= FLAG_DECODE_COMPLETE | FLAG_HAS_ERROR;
  183. }
  184. }
  185. if (mDecodeDone) {
  186. MOZ_ASSERT(HasError() || mCurrentFrame, "Should have an error or a frame");
  187. // If this image wasn't animated and isn't a transient image, mark its frame
  188. // as optimizable. We don't support optimizing animated images and
  189. // optimizing transient images isn't worth it.
  190. if (!HasAnimation() &&
  191. !(mDecoderFlags & DecoderFlags::IMAGE_IS_TRANSIENT) &&
  192. mCurrentFrame) {
  193. mCurrentFrame->SetOptimizable();
  194. }
  195. }
  196. }
  197. void
  198. Decoder::SetOutputSize(const gfx::IntSize& aSize)
  199. {
  200. mOutputSize = Some(aSize);
  201. mHaveExplicitOutputSize = true;
  202. }
  203. Maybe<gfx::IntSize>
  204. Decoder::ExplicitOutputSize() const
  205. {
  206. MOZ_ASSERT_IF(mHaveExplicitOutputSize, mOutputSize);
  207. return mHaveExplicitOutputSize ? mOutputSize : Nothing();
  208. }
  209. Maybe<uint32_t>
  210. Decoder::TakeCompleteFrameCount()
  211. {
  212. const bool finishedNewFrame = mFinishedNewFrame;
  213. mFinishedNewFrame = false;
  214. return finishedNewFrame ? Some(GetCompleteFrameCount()) : Nothing();
  215. }
  216. DecoderFinalStatus
  217. Decoder::FinalStatus() const
  218. {
  219. return DecoderFinalStatus(IsMetadataDecode(),
  220. GetDecodeDone(),
  221. HasError(),
  222. ShouldReportError());
  223. }
  224. DecoderTelemetry
  225. Decoder::Telemetry() const
  226. {
  227. MOZ_ASSERT(mIterator);
  228. return DecoderTelemetry(SpeedHistogram(),
  229. mIterator->ByteCount(),
  230. mIterator->ChunkCount(),
  231. mDecodeTime);
  232. }
  233. nsresult
  234. Decoder::AllocateFrame(const gfx::IntSize& aOutputSize,
  235. const gfx::IntRect& aFrameRect,
  236. gfx::SurfaceFormat aFormat,
  237. uint8_t aPaletteDepth,
  238. const Maybe<AnimationParams>& aAnimParams)
  239. {
  240. mCurrentFrame = AllocateFrameInternal(aOutputSize, aFrameRect, aFormat,
  241. aPaletteDepth, aAnimParams,
  242. mCurrentFrame.get());
  243. if (mCurrentFrame) {
  244. // Gather the raw pointers the decoders will use.
  245. mCurrentFrame->GetImageData(&mImageData, &mImageDataLength);
  246. mCurrentFrame->GetPaletteData(&mColormap, &mColormapSize);
  247. // We should now be on |aFrameNum|. (Note that we're comparing the frame
  248. // number, which is zero-based, with the frame count, which is one-based.)
  249. MOZ_ASSERT_IF(aAnimParams, aAnimParams->mFrameNum + 1 == mFrameCount);
  250. // If we're past the first frame, PostIsAnimated() should've been called.
  251. MOZ_ASSERT_IF(mFrameCount > 1, HasAnimation());
  252. // Update our state to reflect the new frame.
  253. MOZ_ASSERT(!mInFrame, "Starting new frame but not done with old one!");
  254. mInFrame = true;
  255. }
  256. return mCurrentFrame ? NS_OK : NS_ERROR_FAILURE;
  257. }
  258. RawAccessFrameRef
  259. Decoder::AllocateFrameInternal(const gfx::IntSize& aOutputSize,
  260. const gfx::IntRect& aFrameRect,
  261. SurfaceFormat aFormat,
  262. uint8_t aPaletteDepth,
  263. const Maybe<AnimationParams>& aAnimParams,
  264. imgFrame* aPreviousFrame)
  265. {
  266. if (HasError()) {
  267. return RawAccessFrameRef();
  268. }
  269. uint32_t frameNum = aAnimParams ? aAnimParams->mFrameNum : 0;
  270. if (frameNum != mFrameCount) {
  271. MOZ_ASSERT_UNREACHABLE("Allocating frames out of order");
  272. return RawAccessFrameRef();
  273. }
  274. if (aOutputSize.width <= 0 || aOutputSize.height <= 0 ||
  275. aFrameRect.width <= 0 || aFrameRect.height <= 0) {
  276. NS_WARNING("Trying to add frame with zero or negative size");
  277. return RawAccessFrameRef();
  278. }
  279. NotNull<RefPtr<imgFrame>> frame = WrapNotNull(new imgFrame());
  280. bool nonPremult = bool(mSurfaceFlags & SurfaceFlags::NO_PREMULTIPLY_ALPHA);
  281. if (NS_FAILED(frame->InitForDecoder(aOutputSize, aFrameRect, aFormat,
  282. aPaletteDepth, nonPremult,
  283. aAnimParams))) {
  284. NS_WARNING("imgFrame::Init should succeed");
  285. return RawAccessFrameRef();
  286. }
  287. RawAccessFrameRef ref = frame->RawAccessRef();
  288. if (!ref) {
  289. frame->Abort();
  290. return RawAccessFrameRef();
  291. }
  292. if (frameNum == 1) {
  293. MOZ_ASSERT(aPreviousFrame, "Must provide a previous frame when animated");
  294. aPreviousFrame->SetRawAccessOnly();
  295. // If we dispose of the first frame by clearing it, then the first frame's
  296. // refresh area is all of itself.
  297. // RESTORE_PREVIOUS is invalid (assumed to be DISPOSE_CLEAR).
  298. DisposalMethod prevDisposal = aPreviousFrame->GetDisposalMethod();
  299. if (prevDisposal == DisposalMethod::CLEAR ||
  300. prevDisposal == DisposalMethod::CLEAR_ALL ||
  301. prevDisposal == DisposalMethod::RESTORE_PREVIOUS) {
  302. mFirstFrameRefreshArea = aPreviousFrame->GetRect();
  303. }
  304. }
  305. if (frameNum > 0) {
  306. ref->SetRawAccessOnly();
  307. // Some GIFs are huge but only have a small area that they animate. We only
  308. // need to refresh that small area when frame 0 comes around again.
  309. mFirstFrameRefreshArea.UnionRect(mFirstFrameRefreshArea, frame->GetRect());
  310. }
  311. mFrameCount++;
  312. return ref;
  313. }
  314. /*
  315. * Hook stubs. Override these as necessary in decoder implementations.
  316. */
  317. nsresult Decoder::InitInternal() { return NS_OK; }
  318. nsresult Decoder::BeforeFinishInternal() { return NS_OK; }
  319. nsresult Decoder::FinishInternal() { return NS_OK; }
  320. nsresult Decoder::FinishWithErrorInternal() { return NS_OK; }
  321. /*
  322. * Progress Notifications
  323. */
  324. void
  325. Decoder::PostSize(int32_t aWidth,
  326. int32_t aHeight,
  327. Orientation aOrientation /* = Orientation()*/)
  328. {
  329. // Validate.
  330. MOZ_ASSERT(aWidth >= 0, "Width can't be negative!");
  331. MOZ_ASSERT(aHeight >= 0, "Height can't be negative!");
  332. // Set our intrinsic size.
  333. mImageMetadata.SetSize(aWidth, aHeight, aOrientation);
  334. // Set our output size if it's not already set.
  335. if (!mOutputSize) {
  336. mOutputSize = Some(IntSize(aWidth, aHeight));
  337. }
  338. MOZ_ASSERT(mOutputSize->width <= aWidth && mOutputSize->height <= aHeight,
  339. "Output size will result in upscaling");
  340. // Create a downscaler if we need to downscale. This is used by legacy
  341. // decoders that haven't been converted to use SurfacePipe yet.
  342. // XXX(seth): Obviously, we'll remove this once all decoders use SurfacePipe.
  343. if (mOutputSize->width < aWidth || mOutputSize->height < aHeight) {
  344. mDownscaler.emplace(*mOutputSize);
  345. }
  346. // Record this notification.
  347. mProgress |= FLAG_SIZE_AVAILABLE;
  348. }
  349. void
  350. Decoder::PostHasTransparency()
  351. {
  352. mProgress |= FLAG_HAS_TRANSPARENCY;
  353. }
  354. void
  355. Decoder::PostIsAnimated(FrameTimeout aFirstFrameTimeout)
  356. {
  357. mProgress |= FLAG_IS_ANIMATED;
  358. mImageMetadata.SetHasAnimation();
  359. mImageMetadata.SetFirstFrameTimeout(aFirstFrameTimeout);
  360. }
  361. void
  362. Decoder::PostFrameStop(Opacity aFrameOpacity)
  363. {
  364. // We should be mid-frame
  365. MOZ_ASSERT(!IsMetadataDecode(), "Stopping frame during metadata decode");
  366. MOZ_ASSERT(mInFrame, "Stopping frame when we didn't start one");
  367. MOZ_ASSERT(mCurrentFrame, "Stopping frame when we don't have one");
  368. // Update our state.
  369. mInFrame = false;
  370. mFinishedNewFrame = true;
  371. mCurrentFrame->Finish(aFrameOpacity);
  372. mProgress |= FLAG_FRAME_COMPLETE;
  373. mLoopLength += mCurrentFrame->GetTimeout();
  374. // If we're not sending partial invalidations, then we send an invalidation
  375. // here when the first frame is complete.
  376. if (!ShouldSendPartialInvalidations() && mFrameCount == 1) {
  377. mInvalidRect.UnionRect(mInvalidRect,
  378. IntRect(IntPoint(), Size()));
  379. }
  380. }
  381. void
  382. Decoder::PostInvalidation(const gfx::IntRect& aRect,
  383. const Maybe<gfx::IntRect>& aRectAtOutputSize
  384. /* = Nothing() */)
  385. {
  386. // We should be mid-frame
  387. MOZ_ASSERT(mInFrame, "Can't invalidate when not mid-frame!");
  388. MOZ_ASSERT(mCurrentFrame, "Can't invalidate when not mid-frame!");
  389. // Record this invalidation, unless we're not sending partial invalidations
  390. // or we're past the first frame.
  391. if (ShouldSendPartialInvalidations() && mFrameCount == 1) {
  392. mInvalidRect.UnionRect(mInvalidRect, aRect);
  393. mCurrentFrame->ImageUpdated(aRectAtOutputSize.valueOr(aRect));
  394. }
  395. }
  396. void
  397. Decoder::PostDecodeDone(int32_t aLoopCount /* = 0 */)
  398. {
  399. MOZ_ASSERT(!IsMetadataDecode(), "Done with decoding in metadata decode");
  400. MOZ_ASSERT(!mInFrame, "Can't be done decoding if we're mid-frame!");
  401. MOZ_ASSERT(!mDecodeDone, "Decode already done!");
  402. mDecodeDone = true;
  403. mImageMetadata.SetLoopCount(aLoopCount);
  404. // Some metadata that we track should take into account every frame in the
  405. // image. If this is a first-frame-only decode, our accumulated loop length
  406. // and first frame refresh area only includes the first frame, so it's not
  407. // correct and we don't record it.
  408. if (!IsFirstFrameDecode()) {
  409. mImageMetadata.SetLoopLength(mLoopLength);
  410. mImageMetadata.SetFirstFrameRefreshArea(mFirstFrameRefreshArea);
  411. }
  412. mProgress |= FLAG_DECODE_COMPLETE;
  413. }
  414. void
  415. Decoder::PostError()
  416. {
  417. mError = true;
  418. if (mInFrame) {
  419. MOZ_ASSERT(mCurrentFrame);
  420. MOZ_ASSERT(mFrameCount > 0);
  421. mCurrentFrame->Abort();
  422. mInFrame = false;
  423. --mFrameCount;
  424. }
  425. }
  426. } // namespace image
  427. } // namespace mozilla