LCOV - code coverage report
Current view: top level - image - RasterImage.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 404 771 52.4 %
Date: 2017-07-14 16:53:18 Functions: 48 81 59.3 %
Legend: Lines: hit not hit

          Line data    Source code
       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             : 
       6             : // Must #include ImageLogging.h before any IPDL-generated files or other files
       7             : // that #include prlog.h
       8             : #include "ImageLogging.h"
       9             : 
      10             : #include "RasterImage.h"
      11             : 
      12             : #include "gfxPlatform.h"
      13             : #include "nsComponentManagerUtils.h"
      14             : #include "nsError.h"
      15             : #include "Decoder.h"
      16             : #include "prenv.h"
      17             : #include "prsystem.h"
      18             : #include "IDecodingTask.h"
      19             : #include "ImageContainer.h"
      20             : #include "ImageRegion.h"
      21             : #include "Layers.h"
      22             : #include "LookupResult.h"
      23             : #include "nsIConsoleService.h"
      24             : #include "nsIInputStream.h"
      25             : #include "nsIScriptError.h"
      26             : #include "nsISupportsPrimitives.h"
      27             : #include "nsPresContext.h"
      28             : #include "SourceBuffer.h"
      29             : #include "SurfaceCache.h"
      30             : #include "FrameAnimator.h"
      31             : 
      32             : #include "gfxContext.h"
      33             : 
      34             : #include "mozilla/gfx/2D.h"
      35             : #include "mozilla/DebugOnly.h"
      36             : #include "mozilla/Likely.h"
      37             : #include "mozilla/RefPtr.h"
      38             : #include "mozilla/Move.h"
      39             : #include "mozilla/MemoryReporting.h"
      40             : #include "mozilla/Services.h"
      41             : #include <stdint.h>
      42             : #include "mozilla/Telemetry.h"
      43             : #include "mozilla/TimeStamp.h"
      44             : #include "mozilla/Tuple.h"
      45             : #include "mozilla/ClearOnShutdown.h"
      46             : #include "mozilla/gfx/Scale.h"
      47             : 
      48             : #include "GeckoProfiler.h"
      49             : #include "gfx2DGlue.h"
      50             : #include "gfxPrefs.h"
      51             : #include <algorithm>
      52             : 
      53             : namespace mozilla {
      54             : 
      55             : using namespace gfx;
      56             : using namespace layers;
      57             : 
      58             : namespace image {
      59             : 
      60             : using std::ceil;
      61             : using std::min;
      62             : 
      63             : #ifndef DEBUG
      64             : NS_IMPL_ISUPPORTS(RasterImage, imgIContainer, nsIProperties)
      65             : #else
      66        5143 : NS_IMPL_ISUPPORTS(RasterImage, imgIContainer, nsIProperties,
      67             :                   imgIContainerDebug)
      68             : #endif
      69             : 
      70             : //******************************************************************************
      71          20 : RasterImage::RasterImage(ImageURL* aURI /* = nullptr */) :
      72             :   ImageResource(aURI), // invoke superclass's constructor
      73             :   mSize(0,0),
      74             :   mLockCount(0),
      75             :   mDecodeCount(0),
      76          20 :   mImageProducerID(ImageContainer::AllocateProducerID()),
      77             :   mLastFrameID(0),
      78             :   mLastImageContainerDrawResult(DrawResult::NOT_READY),
      79             : #ifdef DEBUG
      80             :   mFramesNotified(0),
      81             : #endif
      82          40 :   mSourceBuffer(WrapNotNull(new SourceBuffer())),
      83             :   mHasSize(false),
      84             :   mTransient(false),
      85             :   mSyncLoad(false),
      86             :   mDiscardable(false),
      87             :   mSomeSourceData(false),
      88             :   mAllSourceData(false),
      89             :   mHasBeenDecoded(false),
      90             :   mPendingAnimation(false),
      91             :   mAnimationFinished(false),
      92          80 :   mWantFullDecode(false)
      93             : {
      94          20 : }
      95             : 
      96             : //******************************************************************************
      97           3 : RasterImage::~RasterImage()
      98             : {
      99             :   // Make sure our SourceBuffer is marked as complete. This will ensure that any
     100             :   // outstanding decoders terminate.
     101           1 :   if (!mSourceBuffer->IsComplete()) {
     102           0 :     mSourceBuffer->Complete(NS_ERROR_ABORT);
     103             :   }
     104             : 
     105             :   // Release all frames from the surface cache.
     106           1 :   SurfaceCache::RemoveImage(ImageKey(this));
     107             : 
     108             :   // Record Telemetry.
     109           1 :   Telemetry::Accumulate(Telemetry::IMAGE_DECODE_COUNT, mDecodeCount);
     110           1 :   if (mAnimationState) {
     111           0 :     Telemetry::Accumulate(Telemetry::IMAGE_ANIMATED_DECODE_COUNT, mDecodeCount);
     112             :   }
     113           3 : }
     114             : 
     115             : nsresult
     116          20 : RasterImage::Init(const char* aMimeType,
     117             :                   uint32_t aFlags)
     118             : {
     119             :   // We don't support re-initialization
     120          20 :   if (mInitialized) {
     121           0 :     return NS_ERROR_ILLEGAL_VALUE;
     122             :   }
     123             : 
     124             :   // Not sure an error can happen before init, but be safe
     125          20 :   if (mError) {
     126           0 :     return NS_ERROR_FAILURE;
     127             :   }
     128             : 
     129             :   // We want to avoid redecodes for transient images.
     130          20 :   MOZ_ASSERT_IF(aFlags & INIT_FLAG_TRANSIENT,
     131             :                 !(aFlags & INIT_FLAG_DISCARDABLE));
     132             : 
     133             :   // Store initialization data
     134          20 :   mDiscardable = !!(aFlags & INIT_FLAG_DISCARDABLE);
     135          20 :   mWantFullDecode = !!(aFlags & INIT_FLAG_DECODE_IMMEDIATELY);
     136          20 :   mTransient = !!(aFlags & INIT_FLAG_TRANSIENT);
     137          20 :   mSyncLoad = !!(aFlags & INIT_FLAG_SYNC_LOAD);
     138             : 
     139             :   // Use the MIME type to select a decoder type, and make sure there *is* a
     140             :   // decoder for this MIME type.
     141          20 :   NS_ENSURE_ARG_POINTER(aMimeType);
     142          20 :   mDecoderType = DecoderFactory::GetDecoderType(aMimeType);
     143          20 :   if (mDecoderType == DecoderType::UNKNOWN) {
     144           1 :     return NS_ERROR_FAILURE;
     145             :   }
     146             : 
     147             :   // Lock this image's surfaces in the SurfaceCache if we're not discardable.
     148          19 :   if (!mDiscardable) {
     149          19 :     mLockCount++;
     150          19 :     SurfaceCache::LockImage(ImageKey(this));
     151             :   }
     152             : 
     153             :   // Mark us as initialized
     154          19 :   mInitialized = true;
     155             : 
     156          19 :   return NS_OK;
     157             : }
     158             : 
     159             : //******************************************************************************
     160             : NS_IMETHODIMP_(void)
     161          15 : RasterImage::RequestRefresh(const TimeStamp& aTime)
     162             : {
     163          15 :   if (HadRecentRefresh(aTime)) {
     164           6 :     return;
     165             :   }
     166             : 
     167          14 :   EvaluateAnimation();
     168             : 
     169          14 :   if (!mAnimating) {
     170           4 :     return;
     171             :   }
     172             : 
     173          10 :   RefreshResult res;
     174          10 :   if (mAnimationState) {
     175          10 :     MOZ_ASSERT(mFrameAnimator);
     176          10 :     res = mFrameAnimator->RequestRefresh(*mAnimationState, aTime, mAnimationFinished);
     177             :   }
     178             : 
     179          10 :   if (res.mFrameAdvanced) {
     180             :     // Notify listeners that our frame has actually changed, but do this only
     181             :     // once for all frames that we've now passed (if AdvanceFrame() was called
     182             :     // more than once).
     183             :     #ifdef DEBUG
     184           8 :       mFramesNotified++;
     185             :     #endif
     186             : 
     187           8 :     NotifyProgress(NoProgress, res.mDirtyRect);
     188             :   }
     189             : 
     190          10 :   if (res.mAnimationFinished) {
     191           0 :     mAnimationFinished = true;
     192           0 :     EvaluateAnimation();
     193             :   }
     194             : }
     195             : 
     196             : //******************************************************************************
     197             : NS_IMETHODIMP
     198         219 : RasterImage::GetWidth(int32_t* aWidth)
     199             : {
     200         219 :   NS_ENSURE_ARG_POINTER(aWidth);
     201             : 
     202         219 :   if (mError) {
     203           0 :     *aWidth = 0;
     204           0 :     return NS_ERROR_FAILURE;
     205             :   }
     206             : 
     207         219 :   *aWidth = mSize.width;
     208         219 :   return NS_OK;
     209             : }
     210             : 
     211             : //******************************************************************************
     212             : NS_IMETHODIMP
     213         219 : RasterImage::GetHeight(int32_t* aHeight)
     214             : {
     215         219 :   NS_ENSURE_ARG_POINTER(aHeight);
     216             : 
     217         219 :   if (mError) {
     218           0 :     *aHeight = 0;
     219           0 :     return NS_ERROR_FAILURE;
     220             :   }
     221             : 
     222         219 :   *aHeight = mSize.height;
     223         219 :   return NS_OK;
     224             : }
     225             : 
     226             : //******************************************************************************
     227             : nsresult
     228           0 : RasterImage::GetNativeSizes(nsTArray<IntSize>& aNativeSizes) const
     229             : {
     230           0 :   if (mError) {
     231           0 :     return NS_ERROR_FAILURE;
     232             :   }
     233             : 
     234           0 :   if (mNativeSizes.IsEmpty()) {
     235           0 :     aNativeSizes.Clear();
     236           0 :     aNativeSizes.AppendElement(mSize);
     237             :   } else {
     238           0 :     aNativeSizes = mNativeSizes;
     239             :   }
     240             : 
     241           0 :   return NS_OK;
     242             : }
     243             : 
     244             : //******************************************************************************
     245             : NS_IMETHODIMP
     246           0 : RasterImage::GetIntrinsicSize(nsSize* aSize)
     247             : {
     248           0 :   if (mError) {
     249           0 :     return NS_ERROR_FAILURE;
     250             :   }
     251             : 
     252           0 :   *aSize = nsSize(nsPresContext::CSSPixelsToAppUnits(mSize.width),
     253             :                   nsPresContext::CSSPixelsToAppUnits(mSize.height));
     254           0 :   return NS_OK;
     255             : }
     256             : 
     257             : //******************************************************************************
     258             : NS_IMETHODIMP
     259         179 : RasterImage::GetIntrinsicRatio(nsSize* aRatio)
     260             : {
     261         179 :   if (mError) {
     262           0 :     return NS_ERROR_FAILURE;
     263             :   }
     264             : 
     265         179 :   *aRatio = nsSize(mSize.width, mSize.height);
     266         179 :   return NS_OK;
     267             : }
     268             : 
     269             : NS_IMETHODIMP_(Orientation)
     270           0 : RasterImage::GetOrientation()
     271             : {
     272           0 :   return mOrientation;
     273             : }
     274             : 
     275             : //******************************************************************************
     276             : NS_IMETHODIMP
     277          72 : RasterImage::GetType(uint16_t* aType)
     278             : {
     279          72 :   NS_ENSURE_ARG_POINTER(aType);
     280             : 
     281          72 :   *aType = imgIContainer::TYPE_RASTER;
     282          72 :   return NS_OK;
     283             : }
     284             : 
     285             : LookupResult
     286          60 : RasterImage::LookupFrameInternal(const IntSize& aSize,
     287             :                                  uint32_t aFlags,
     288             :                                  PlaybackType aPlaybackType)
     289             : {
     290          60 :   if (mAnimationState && aPlaybackType == PlaybackType::eAnimated) {
     291          13 :     MOZ_ASSERT(mFrameAnimator);
     292          13 :     MOZ_ASSERT(ToSurfaceFlags(aFlags) == DefaultSurfaceFlags(),
     293             :                "Can't composite frames with non-default surface flags");
     294          13 :     return mFrameAnimator->GetCompositedFrame(*mAnimationState);
     295             :   }
     296             : 
     297          47 :   SurfaceFlags surfaceFlags = ToSurfaceFlags(aFlags);
     298             : 
     299             :   // We don't want any substitution for sync decodes, and substitution would be
     300             :   // illegal when high quality downscaling is disabled, so we use
     301             :   // SurfaceCache::Lookup in this case.
     302          47 :   if ((aFlags & FLAG_SYNC_DECODE) || !(aFlags & FLAG_HIGH_QUALITY_SCALING)) {
     303             :     return SurfaceCache::Lookup(ImageKey(this),
     304          46 :                                 RasterSurfaceKey(aSize,
     305             :                                                  surfaceFlags,
     306          23 :                                                  PlaybackType::eStatic));
     307             :   }
     308             : 
     309             :   // We'll return the best match we can find to the requested frame.
     310             :   return SurfaceCache::LookupBestMatch(ImageKey(this),
     311          48 :                                        RasterSurfaceKey(aSize,
     312             :                                                         surfaceFlags,
     313          24 :                                                         PlaybackType::eStatic));
     314             : }
     315             : 
     316             : DrawableSurface
     317          57 : RasterImage::LookupFrame(const IntSize& aSize,
     318             :                          uint32_t aFlags,
     319             :                          PlaybackType aPlaybackType)
     320             : {
     321          57 :   MOZ_ASSERT(NS_IsMainThread());
     322             : 
     323             :   // If we're opaque, we don't need to care about premultiplied alpha, because
     324             :   // that can only matter for frames with transparency.
     325          57 :   if (IsOpaque()) {
     326           0 :     aFlags &= ~FLAG_DECODE_NO_PREMULTIPLY_ALPHA;
     327             :   }
     328             : 
     329          57 :   IntSize requestedSize = CanDownscaleDuringDecode(aSize, aFlags)
     330          57 :                         ? aSize : mSize;
     331          57 :   if (requestedSize.IsEmpty()) {
     332           0 :     return DrawableSurface();  // Can't decode to a surface of zero size.
     333             :   }
     334             : 
     335             :   LookupResult result =
     336         114 :     LookupFrameInternal(requestedSize, aFlags, aPlaybackType);
     337             : 
     338          57 :   if (!result && !mHasSize) {
     339             :     // We can't request a decode without knowing our intrinsic size. Give up.
     340           0 :     return DrawableSurface();
     341             :   }
     342             : 
     343         157 :   if (result.Type() == MatchType::NOT_FOUND ||
     344         114 :       result.Type() == MatchType::SUBSTITUTE_BECAUSE_NOT_FOUND ||
     345          43 :       ((aFlags & FLAG_SYNC_DECODE) && !result)) {
     346             :     // We don't have a copy of this frame, and there's no decoder working on
     347             :     // one. (Or we're sync decoding and the existing decoder hasn't even started
     348             :     // yet.) Trigger decoding so it'll be available next time.
     349          14 :     MOZ_ASSERT(aPlaybackType != PlaybackType::eAnimated ||
     350             :                gfxPrefs::ImageMemAnimatedDiscardable() ||
     351             :                !mAnimationState || mAnimationState->KnownFrameCount() < 1,
     352             :                "Animated frames should be locked");
     353             : 
     354          14 :     bool ranSync = Decode(requestedSize, aFlags, aPlaybackType);
     355             : 
     356             :     // If we can or did sync decode, we should already have the frame.
     357          14 :     if (ranSync || (aFlags & FLAG_SYNC_DECODE)) {
     358           3 :       result = LookupFrameInternal(requestedSize, aFlags, aPlaybackType);
     359             :     }
     360             :   }
     361             : 
     362          57 :   if (!result) {
     363             :     // We still weren't able to get a frame. Give up.
     364          11 :     return DrawableSurface();
     365             :   }
     366             : 
     367          46 :   if (result.Surface()->GetCompositingFailed()) {
     368           0 :     return DrawableSurface();
     369             :   }
     370             : 
     371          46 :   MOZ_ASSERT(!result.Surface()->GetIsPaletted(),
     372             :              "Should not have a paletted frame");
     373             : 
     374             :   // Sync decoding guarantees that we got the frame, but if it's owned by an
     375             :   // async decoder that's currently running, the contents of the frame may not
     376             :   // be available yet. Make sure we get everything.
     377          46 :   if (mAllSourceData && (aFlags & FLAG_SYNC_DECODE)) {
     378           0 :     result.Surface()->WaitUntilFinished();
     379             :   }
     380             : 
     381             :   // If we could have done some decoding in this function we need to check if
     382             :   // that decoding encountered an error and hence aborted the surface. We want
     383             :   // to avoid calling IsAborted if we weren't passed any sync decode flag because
     384             :   // IsAborted acquires the monitor for the imgFrame.
     385          70 :   if (aFlags & (FLAG_SYNC_DECODE | FLAG_SYNC_DECODE_IF_FAST) &&
     386          24 :     result.Surface()->IsAborted()) {
     387           0 :     return DrawableSurface();
     388             :   }
     389             : 
     390          46 :   return Move(result.Surface());
     391             : }
     392             : 
     393             : bool
     394         157 : RasterImage::IsOpaque()
     395             : {
     396         157 :   if (mError) {
     397           0 :     return false;
     398             :   }
     399             : 
     400         157 :   Progress progress = mProgressTracker->GetProgress();
     401             : 
     402             :   // If we haven't yet finished decoding, the safe answer is "not opaque".
     403         157 :   if (!(progress & FLAG_DECODE_COMPLETE)) {
     404          40 :     return false;
     405             :   }
     406             : 
     407             :   // Other, we're opaque if FLAG_HAS_TRANSPARENCY is not set.
     408         117 :   return !(progress & FLAG_HAS_TRANSPARENCY);
     409             : }
     410             : 
     411             : NS_IMETHODIMP_(bool)
     412          86 : RasterImage::WillDrawOpaqueNow()
     413             : {
     414          86 :   if (!IsOpaque()) {
     415          86 :     return false;
     416             :   }
     417             : 
     418           0 :   if (mAnimationState) {
     419           0 :     if (!gfxPrefs::ImageMemAnimatedDiscardable()) {
     420             :       // We never discard frames of animated images.
     421           0 :       return true;
     422             :     } else {
     423           0 :       if (mAnimationState->GetCompositedFrameInvalid()) {
     424             :         // We're not going to draw anything at all.
     425           0 :         return false;
     426             :       }
     427             :     }
     428             :   }
     429             : 
     430             :   // If we are not locked our decoded data could get discard at any time (ie
     431             :   // between the call to this function and when we are asked to draw), so we
     432             :   // have to return false if we are unlocked.
     433           0 :   if (mLockCount == 0) {
     434           0 :     return false;
     435             :   }
     436             : 
     437             :   LookupResult result =
     438             :     SurfaceCache::LookupBestMatch(ImageKey(this),
     439           0 :                                   RasterSurfaceKey(mSize,
     440             :                                                    DefaultSurfaceFlags(),
     441           0 :                                                    PlaybackType::eStatic));
     442           0 :   MatchType matchType = result.Type();
     443           0 :   if (matchType == MatchType::NOT_FOUND || matchType == MatchType::PENDING ||
     444           0 :       !result.Surface()->IsFinished()) {
     445           0 :     return false;
     446             :   }
     447             : 
     448           0 :   return true;
     449             : }
     450             : 
     451             : void
     452           0 : RasterImage::OnSurfaceDiscarded(const SurfaceKey& aSurfaceKey)
     453             : {
     454           0 :   MOZ_ASSERT(mProgressTracker);
     455             : 
     456             :   bool animatedFramesDiscarded =
     457           0 :     mAnimationState && aSurfaceKey.Playback() == PlaybackType::eAnimated;
     458             : 
     459           0 :   RefPtr<RasterImage> image = this;
     460           0 :   NS_DispatchToMainThread(NS_NewRunnableFunction(
     461             :                             "RasterImage::OnSurfaceDiscarded",
     462           0 :                             [=]() -> void {
     463           0 :     image->OnSurfaceDiscardedInternal(animatedFramesDiscarded);
     464           0 :   }));
     465           0 : }
     466             : 
     467             : void
     468           0 : RasterImage::OnSurfaceDiscardedInternal(bool aAnimatedFramesDiscarded)
     469             : {
     470           0 :   MOZ_ASSERT(NS_IsMainThread());
     471             : 
     472           0 :   if (aAnimatedFramesDiscarded && mAnimationState) {
     473           0 :     MOZ_ASSERT(gfxPrefs::ImageMemAnimatedDiscardable());
     474           0 :     mImageContainer = nullptr;
     475             :     gfx::IntRect rect =
     476           0 :       mAnimationState->UpdateState(mAnimationFinished, this, mSize);
     477           0 :     NotifyProgress(NoProgress, rect);
     478             :   }
     479             : 
     480           0 :   if (mProgressTracker) {
     481           0 :     mProgressTracker->OnDiscard();
     482             :   }
     483           0 : }
     484             : 
     485             : //******************************************************************************
     486             : NS_IMETHODIMP
     487           4 : RasterImage::GetAnimated(bool* aAnimated)
     488             : {
     489           4 :   if (mError) {
     490           0 :     return NS_ERROR_FAILURE;
     491             :   }
     492             : 
     493           4 :   NS_ENSURE_ARG_POINTER(aAnimated);
     494             : 
     495             :   // If we have an AnimationState, we can know for sure.
     496           4 :   if (mAnimationState) {
     497           4 :     *aAnimated = true;
     498           4 :     return NS_OK;
     499             :   }
     500             : 
     501             :   // Otherwise, we need to have been decoded to know for sure, since if we were
     502             :   // decoded at least once mAnimationState would have been created for animated
     503             :   // images. This is true even though we check for animation during the
     504             :   // metadata decode, because we may still discover animation only during the
     505             :   // full decode for corrupt images.
     506           0 :   if (!mHasBeenDecoded) {
     507           0 :     return NS_ERROR_NOT_AVAILABLE;
     508             :   }
     509             : 
     510             :   // We know for sure
     511           0 :   *aAnimated = false;
     512             : 
     513           0 :   return NS_OK;
     514             : }
     515             : 
     516             : //******************************************************************************
     517             : NS_IMETHODIMP_(int32_t)
     518           4 : RasterImage::GetFirstFrameDelay()
     519             : {
     520           4 :   if (mError) {
     521           0 :     return -1;
     522             :   }
     523             : 
     524           4 :   bool animated = false;
     525           4 :   if (NS_FAILED(GetAnimated(&animated)) || !animated) {
     526           0 :     return -1;
     527             :   }
     528             : 
     529           4 :   MOZ_ASSERT(mAnimationState, "Animated images should have an AnimationState");
     530           4 :   return mAnimationState->FirstFrameTimeout().AsEncodedValueDeprecated();
     531             : }
     532             : 
     533             : NS_IMETHODIMP_(already_AddRefed<SourceSurface>)
     534           0 : RasterImage::GetFrame(uint32_t aWhichFrame,
     535             :                       uint32_t aFlags)
     536             : {
     537           0 :   return GetFrameAtSize(mSize, aWhichFrame, aFlags);
     538             : }
     539             : 
     540             : NS_IMETHODIMP_(already_AddRefed<SourceSurface>)
     541           0 : RasterImage::GetFrameAtSize(const IntSize& aSize,
     542             :                             uint32_t aWhichFrame,
     543             :                             uint32_t aFlags)
     544             : {
     545             :   RefPtr<SourceSurface> surf =
     546           0 :     GetFrameInternal(aSize, aWhichFrame, aFlags).second().forget();
     547             :   // If we are here, it suggests the image is embedded in a canvas or some
     548             :   // other path besides layers, and we won't need the file handle.
     549           0 :   MarkSurfaceShared(surf);
     550           0 :   return surf.forget();
     551             : }
     552             : 
     553             : Pair<DrawResult, RefPtr<SourceSurface>>
     554           0 : RasterImage::GetFrameInternal(const IntSize& aSize,
     555             :                               uint32_t aWhichFrame,
     556             :                               uint32_t aFlags)
     557             : {
     558           0 :   MOZ_ASSERT(aWhichFrame <= FRAME_MAX_VALUE);
     559             : 
     560           0 :   if (aSize.IsEmpty()) {
     561           0 :     return MakePair(DrawResult::BAD_ARGS, RefPtr<SourceSurface>());
     562             :   }
     563             : 
     564           0 :   if (aWhichFrame > FRAME_MAX_VALUE) {
     565           0 :     return MakePair(DrawResult::BAD_ARGS, RefPtr<SourceSurface>());
     566             :   }
     567             : 
     568           0 :   if (mError) {
     569           0 :     return MakePair(DrawResult::BAD_IMAGE, RefPtr<SourceSurface>());
     570             :   }
     571             : 
     572             :   // Get the frame. If it's not there, it's probably the caller's fault for
     573             :   // not waiting for the data to be loaded from the network or not passing
     574             :   // FLAG_SYNC_DECODE.
     575             :   DrawableSurface surface =
     576           0 :     LookupFrame(aSize, aFlags, ToPlaybackType(aWhichFrame));
     577           0 :   if (!surface) {
     578             :     // The OS threw this frame away and we couldn't redecode it.
     579           0 :     return MakePair(DrawResult::TEMPORARY_ERROR, RefPtr<SourceSurface>());
     580             :   }
     581             : 
     582           0 :   RefPtr<SourceSurface> sourceSurface = surface->GetSourceSurface();
     583             : 
     584           0 :   if (!surface->IsFinished()) {
     585           0 :     return MakePair(DrawResult::INCOMPLETE, Move(sourceSurface));
     586             :   }
     587             : 
     588           0 :   return MakePair(DrawResult::SUCCESS, Move(sourceSurface));
     589             : }
     590             : 
     591             : Pair<DrawResult, RefPtr<layers::Image>>
     592           0 : RasterImage::GetCurrentImage(ImageContainer* aContainer, uint32_t aFlags)
     593             : {
     594           0 :   MOZ_ASSERT(NS_IsMainThread());
     595           0 :   MOZ_ASSERT(aContainer);
     596             : 
     597             :   DrawResult drawResult;
     598           0 :   RefPtr<SourceSurface> surface;
     599           0 :   Tie(drawResult, surface) =
     600           0 :     GetFrameInternal(mSize, FRAME_CURRENT, aFlags | FLAG_ASYNC_NOTIFY);
     601           0 :   if (!surface) {
     602             :     // The OS threw out some or all of our buffer. We'll need to wait for the
     603             :     // redecode (which was automatically triggered by GetFrame) to complete.
     604           0 :     return MakePair(drawResult, RefPtr<layers::Image>());
     605             :   }
     606             : 
     607           0 :   RefPtr<layers::Image> image = new layers::SourceSurfaceImage(surface);
     608           0 :   return MakePair(drawResult, Move(image));
     609             : }
     610             : 
     611             : NS_IMETHODIMP_(bool)
     612          14 : RasterImage::IsImageContainerAvailable(LayerManager* aManager, uint32_t aFlags)
     613             : {
     614          14 :   int32_t maxTextureSize = aManager->GetMaxTextureSize();
     615          25 :   if (!mHasSize ||
     616          22 :       mSize.width > maxTextureSize ||
     617          11 :       mSize.height > maxTextureSize) {
     618           3 :     return false;
     619             :   }
     620             : 
     621          11 :   return true;
     622             : }
     623             : 
     624             : NS_IMETHODIMP_(already_AddRefed<ImageContainer>)
     625           0 : RasterImage::GetImageContainer(LayerManager* aManager, uint32_t aFlags)
     626             : {
     627           0 :   MOZ_ASSERT(NS_IsMainThread());
     628           0 :   MOZ_ASSERT(aManager);
     629           0 :   MOZ_ASSERT((aFlags & ~(FLAG_SYNC_DECODE |
     630             :                          FLAG_SYNC_DECODE_IF_FAST |
     631             :                          FLAG_ASYNC_NOTIFY))
     632             :                == FLAG_NONE,
     633             :              "Unsupported flag passed to GetImageContainer");
     634             : 
     635           0 :   int32_t maxTextureSize = aManager->GetMaxTextureSize();
     636           0 :   if (!mHasSize ||
     637           0 :       mSize.width > maxTextureSize ||
     638           0 :       mSize.height > maxTextureSize) {
     639           0 :     return nullptr;
     640             :   }
     641             : 
     642           0 :   if (mAnimationConsumers == 0) {
     643           0 :     SendOnUnlockedDraw(aFlags);
     644             :   }
     645             : 
     646           0 :   RefPtr<layers::ImageContainer> container = mImageContainer.get();
     647             : 
     648             :   bool mustRedecode =
     649           0 :     (aFlags & (FLAG_SYNC_DECODE | FLAG_SYNC_DECODE_IF_FAST)) &&
     650           0 :     mLastImageContainerDrawResult != DrawResult::SUCCESS &&
     651           0 :     mLastImageContainerDrawResult != DrawResult::BAD_IMAGE;
     652             : 
     653           0 :   if (container && !mustRedecode) {
     654           0 :     return container.forget();
     655             :   }
     656             : 
     657             :   // We need a new ImageContainer, so create one.
     658           0 :   container = LayerManager::CreateImageContainer();
     659             : 
     660             :   DrawResult drawResult;
     661           0 :   RefPtr<layers::Image> image;
     662           0 :   Tie(drawResult, image) = GetCurrentImage(container, aFlags);
     663           0 :   if (!image) {
     664           0 :     return nullptr;
     665             :   }
     666             : 
     667             :   // |image| holds a reference to a SourceSurface which in turn holds a lock on
     668             :   // the current frame's data buffer, ensuring that it doesn't get freed as
     669             :   // long as the layer system keeps this ImageContainer alive.
     670           0 :   AutoTArray<ImageContainer::NonOwningImage, 1> imageList;
     671           0 :   imageList.AppendElement(ImageContainer::NonOwningImage(image, TimeStamp(),
     672           0 :                                                          mLastFrameID++,
     673           0 :                                                          mImageProducerID));
     674           0 :   container->SetCurrentImagesInTransaction(imageList);
     675             : 
     676           0 :   mLastImageContainerDrawResult = drawResult;
     677           0 :   mImageContainer = container;
     678             : 
     679           0 :   return container.forget();
     680             : }
     681             : 
     682             : void
     683          22 : RasterImage::UpdateImageContainer()
     684             : {
     685          22 :   MOZ_ASSERT(NS_IsMainThread());
     686             : 
     687          22 :   RefPtr<layers::ImageContainer> container = mImageContainer.get();
     688          22 :   if (!container) {
     689          22 :     return;
     690             :   }
     691             : 
     692             :   DrawResult drawResult;
     693           0 :   RefPtr<layers::Image> image;
     694           0 :   Tie(drawResult, image) = GetCurrentImage(container, FLAG_NONE);
     695           0 :   if (!image) {
     696           0 :     return;
     697             :   }
     698             : 
     699           0 :   mLastImageContainerDrawResult = drawResult;
     700           0 :   AutoTArray<ImageContainer::NonOwningImage, 1> imageList;
     701           0 :   imageList.AppendElement(ImageContainer::NonOwningImage(image, TimeStamp(),
     702           0 :                                                          mLastFrameID++,
     703           0 :                                                          mImageProducerID));
     704           0 :   container->SetCurrentImages(imageList);
     705             : }
     706             : 
     707             : size_t
     708          19 : RasterImage::SizeOfSourceWithComputedFallback(MallocSizeOf aMallocSizeOf) const
     709             : {
     710          19 :   return mSourceBuffer->SizeOfIncludingThisWithComputedFallback(aMallocSizeOf);
     711             : }
     712             : 
     713             : void
     714           0 : RasterImage::CollectSizeOfSurfaces(nsTArray<SurfaceMemoryCounter>& aCounters,
     715             :                                    MallocSizeOf aMallocSizeOf) const
     716             : {
     717           0 :   SurfaceCache::CollectSizeOfSurfaces(ImageKey(this), aCounters, aMallocSizeOf);
     718           0 :   if (mFrameAnimator) {
     719           0 :     mFrameAnimator->CollectSizeOfCompositingSurfaces(aCounters, aMallocSizeOf);
     720             :   }
     721           0 : }
     722             : 
     723             : bool
     724          33 : RasterImage::SetMetadata(const ImageMetadata& aMetadata,
     725             :                          bool aFromMetadataDecode)
     726             : {
     727          33 :   MOZ_ASSERT(NS_IsMainThread());
     728             : 
     729          33 :   if (mError) {
     730           0 :     return true;
     731             :   }
     732             : 
     733          33 :   if (aMetadata.HasSize()) {
     734          33 :     IntSize size = aMetadata.GetSize();
     735          33 :     if (size.width < 0 || size.height < 0) {
     736           0 :       NS_WARNING("Image has negative intrinsic size");
     737           0 :       DoError();
     738           0 :       return true;
     739             :     }
     740             : 
     741          33 :     MOZ_ASSERT(aMetadata.HasOrientation());
     742          33 :     Orientation orientation = aMetadata.GetOrientation();
     743             : 
     744             :     // If we already have a size, check the new size against the old one.
     745          33 :     if (mHasSize && (size != mSize || orientation != mOrientation)) {
     746             :       NS_WARNING("Image changed size or orientation on redecode! "
     747           0 :                  "This should not happen!");
     748           0 :       DoError();
     749           0 :       return true;
     750             :     }
     751             : 
     752             :     // Set the size and flag that we have it.
     753          33 :     mSize = size;
     754          33 :     mOrientation = orientation;
     755          33 :     mNativeSizes = aMetadata.GetNativeSizes();
     756          33 :     mHasSize = true;
     757             :   }
     758             : 
     759          33 :   if (mHasSize && aMetadata.HasAnimation() && !mAnimationState) {
     760             :     // We're becoming animated, so initialize animation stuff.
     761           2 :     mAnimationState.emplace(mAnimationMode);
     762           2 :     mFrameAnimator = MakeUnique<FrameAnimator>(this, mSize);
     763             : 
     764           2 :     if (!gfxPrefs::ImageMemAnimatedDiscardable()) {
     765             :       // We don't support discarding animated images (See bug 414259).
     766             :       // Lock the image and throw away the key.
     767           0 :       LockImage();
     768             :     }
     769             : 
     770           2 :     if (!aFromMetadataDecode) {
     771             :       // The metadata decode reported that this image isn't animated, but we
     772             :       // discovered that it actually was during the full decode. This is a
     773             :       // rare failure that only occurs for corrupt images. To recover, we need
     774             :       // to discard all existing surfaces and redecode.
     775           0 :       return false;
     776             :     }
     777             :   }
     778             : 
     779          33 :   if (mAnimationState) {
     780           4 :     mAnimationState->SetLoopCount(aMetadata.GetLoopCount());
     781           4 :     mAnimationState->SetFirstFrameTimeout(aMetadata.GetFirstFrameTimeout());
     782             : 
     783           4 :     if (aMetadata.HasLoopLength()) {
     784           2 :       mAnimationState->SetLoopLength(aMetadata.GetLoopLength());
     785             :     }
     786           4 :     if (aMetadata.HasFirstFrameRefreshArea()) {
     787             :       mAnimationState
     788           2 :         ->SetFirstFrameRefreshArea(aMetadata.GetFirstFrameRefreshArea());
     789             :     }
     790             :   }
     791             : 
     792          33 :   if (aMetadata.HasHotspot()) {
     793           0 :     IntPoint hotspot = aMetadata.GetHotspot();
     794             : 
     795             :     nsCOMPtr<nsISupportsPRUint32> intwrapx =
     796           0 :       do_CreateInstance(NS_SUPPORTS_PRUINT32_CONTRACTID);
     797             :     nsCOMPtr<nsISupportsPRUint32> intwrapy =
     798           0 :       do_CreateInstance(NS_SUPPORTS_PRUINT32_CONTRACTID);
     799           0 :     intwrapx->SetData(hotspot.x);
     800           0 :     intwrapy->SetData(hotspot.y);
     801             : 
     802           0 :     Set("hotspotX", intwrapx);
     803           0 :     Set("hotspotY", intwrapy);
     804             :   }
     805             : 
     806          33 :   return true;
     807             : }
     808             : 
     809             : NS_IMETHODIMP
     810          19 : RasterImage::SetAnimationMode(uint16_t aAnimationMode)
     811             : {
     812          19 :   if (mAnimationState) {
     813           2 :     mAnimationState->SetAnimationMode(aAnimationMode);
     814             :   }
     815          19 :   return SetAnimationModeInternal(aAnimationMode);
     816             : }
     817             : 
     818             : //******************************************************************************
     819             : 
     820             : nsresult
     821           2 : RasterImage::StartAnimation()
     822             : {
     823           2 :   if (mError) {
     824           0 :     return NS_ERROR_FAILURE;
     825             :   }
     826             : 
     827           2 :   MOZ_ASSERT(ShouldAnimate(), "Should not animate!");
     828             : 
     829             :   // If we're not ready to animate, then set mPendingAnimation, which will cause
     830             :   // us to start animating if and when we do become ready.
     831           2 :   mPendingAnimation = !mAnimationState || mAnimationState->KnownFrameCount() < 1;
     832           2 :   if (mPendingAnimation) {
     833           0 :     return NS_OK;
     834             :   }
     835             : 
     836             :   // Don't bother to animate if we're displaying the first frame forever.
     837          10 :   if (mAnimationState->GetCurrentAnimationFrameIndex() == 0 &&
     838          10 :       mAnimationState->FirstFrameTimeout() == FrameTimeout::Forever()) {
     839           0 :     mAnimationFinished = true;
     840           0 :     return NS_ERROR_ABORT;
     841             :   }
     842             : 
     843             :   // We need to set the time that this initial frame was first displayed, as
     844             :   // this is used in AdvanceFrame().
     845           2 :   mAnimationState->InitAnimationFrameTimeIfNecessary();
     846             : 
     847           2 :   return NS_OK;
     848             : }
     849             : 
     850             : //******************************************************************************
     851             : nsresult
     852           0 : RasterImage::StopAnimation()
     853             : {
     854           0 :   MOZ_ASSERT(mAnimating, "Should be animating!");
     855             : 
     856           0 :   nsresult rv = NS_OK;
     857           0 :   if (mError) {
     858           0 :     rv = NS_ERROR_FAILURE;
     859             :   } else {
     860           0 :     mAnimationState->SetAnimationFrameTime(TimeStamp());
     861             :   }
     862             : 
     863           0 :   mAnimating = false;
     864           0 :   return rv;
     865             : }
     866             : 
     867             : //******************************************************************************
     868             : NS_IMETHODIMP
     869           0 : RasterImage::ResetAnimation()
     870             : {
     871           0 :   if (mError) {
     872           0 :     return NS_ERROR_FAILURE;
     873             :     }
     874             : 
     875           0 :   mPendingAnimation = false;
     876             : 
     877           0 :   if (mAnimationMode == kDontAnimMode || !mAnimationState ||
     878           0 :       mAnimationState->GetCurrentAnimationFrameIndex() == 0) {
     879           0 :     return NS_OK;
     880             :   }
     881             : 
     882           0 :   mAnimationFinished = false;
     883             : 
     884           0 :   if (mAnimating) {
     885           0 :     StopAnimation();
     886             :   }
     887             : 
     888           0 :   MOZ_ASSERT(mAnimationState, "Should have AnimationState");
     889           0 :   mAnimationState->ResetAnimation();
     890             : 
     891           0 :   NotifyProgress(NoProgress, mAnimationState->FirstFrameRefreshArea());
     892             : 
     893             :   // Start the animation again. It may not have been running before, if
     894             :   // mAnimationFinished was true before entering this function.
     895           0 :   EvaluateAnimation();
     896             : 
     897           0 :   return NS_OK;
     898             : }
     899             : 
     900             : //******************************************************************************
     901             : NS_IMETHODIMP_(void)
     902           2 : RasterImage::SetAnimationStartTime(const TimeStamp& aTime)
     903             : {
     904           2 :   if (mError || mAnimationMode == kDontAnimMode || mAnimating || !mAnimationState) {
     905           0 :     return;
     906             :   }
     907             : 
     908           2 :   mAnimationState->SetAnimationFrameTime(aTime);
     909             : }
     910             : 
     911             : NS_IMETHODIMP_(float)
     912           0 : RasterImage::GetFrameIndex(uint32_t aWhichFrame)
     913             : {
     914           0 :   MOZ_ASSERT(aWhichFrame <= FRAME_MAX_VALUE, "Invalid argument");
     915           0 :   return (aWhichFrame == FRAME_FIRST || !mAnimationState)
     916           0 :          ? 0.0f
     917           0 :          : mAnimationState->GetCurrentAnimationFrameIndex();
     918             : }
     919             : 
     920             : NS_IMETHODIMP_(IntRect)
     921           0 : RasterImage::GetImageSpaceInvalidationRect(const IntRect& aRect)
     922             : {
     923           0 :   return aRect;
     924             : }
     925             : 
     926             : nsresult
     927          20 : RasterImage::OnImageDataComplete(nsIRequest*, nsISupports*, nsresult aStatus,
     928             :                                  bool aLastPart)
     929             : {
     930          20 :   MOZ_ASSERT(NS_IsMainThread());
     931             : 
     932             :   // Record that we have all the data we're going to get now.
     933          20 :   mAllSourceData = true;
     934             : 
     935             :   // Let decoders know that there won't be any more data coming.
     936          20 :   mSourceBuffer->Complete(aStatus);
     937             : 
     938             :   // Allow a synchronous metadata decode if mSyncLoad was set, or if we're
     939             :   // running on a single thread (in which case waiting for the async metadata
     940             :   // decoder could delay this image's load event quite a bit), or if this image
     941             :   // is transient.
     942          40 :   bool canSyncDecodeMetadata = mSyncLoad || mTransient ||
     943          40 :                                DecodePool::NumberOfCores() < 2;
     944             : 
     945          20 :   if (canSyncDecodeMetadata && !mHasSize) {
     946             :     // We're loading this image synchronously, so it needs to be usable after
     947             :     // this call returns.  Since we haven't gotten our size yet, we need to do a
     948             :     // synchronous metadata decode here.
     949           0 :     DecodeMetadata(FLAG_SYNC_DECODE);
     950             :   }
     951             : 
     952             :   // Determine our final status, giving precedence to Necko failure codes. We
     953             :   // check after running the metadata decode in case it triggered an error.
     954          20 :   nsresult finalStatus = mError ? NS_ERROR_FAILURE : NS_OK;
     955          20 :   if (NS_FAILED(aStatus)) {
     956           1 :     finalStatus = aStatus;
     957             :   }
     958             : 
     959             :   // If loading failed, report an error.
     960          20 :   if (NS_FAILED(finalStatus)) {
     961           1 :     DoError();
     962             :   }
     963             : 
     964          20 :   Progress loadProgress = LoadCompleteProgress(aLastPart, mError, finalStatus);
     965             : 
     966          20 :   if (!mHasSize && !mError) {
     967             :     // We don't have our size yet, so we'll fire the load event in SetSize().
     968          19 :     MOZ_ASSERT(!canSyncDecodeMetadata,
     969             :                "Firing load async after metadata sync decode?");
     970          19 :     NotifyProgress(FLAG_ONLOAD_BLOCKED);
     971          19 :     mLoadProgress = Some(loadProgress);
     972          19 :     return finalStatus;
     973             :   }
     974             : 
     975           1 :   NotifyForLoadEvent(loadProgress);
     976             : 
     977           1 :   return finalStatus;
     978             : }
     979             : 
     980             : void
     981          20 : RasterImage::NotifyForLoadEvent(Progress aProgress)
     982             : {
     983          20 :   MOZ_ASSERT(mHasSize || mError, "Need to know size before firing load event");
     984          20 :   MOZ_ASSERT(!mHasSize ||
     985             :              (mProgressTracker->GetProgress() & FLAG_SIZE_AVAILABLE),
     986             :              "Should have notified that the size is available if we have it");
     987             : 
     988             :   // If we encountered an error, make sure we notify for that as well.
     989          20 :   if (mError) {
     990           1 :     aProgress |= FLAG_HAS_ERROR;
     991             :   }
     992             : 
     993             :   // Notify our listeners, which will fire this image's load event.
     994          20 :   NotifyProgress(aProgress);
     995          20 : }
     996             : 
     997             : nsresult
     998          19 : RasterImage::OnImageDataAvailable(nsIRequest*,
     999             :                                   nsISupports*,
    1000             :                                   nsIInputStream* aInputStream,
    1001             :                                   uint64_t,
    1002             :                                   uint32_t aCount)
    1003             : {
    1004          19 :   nsresult rv = mSourceBuffer->AppendFromInputStream(aInputStream, aCount);
    1005          19 :   if (NS_SUCCEEDED(rv) && !mSomeSourceData) {
    1006          19 :     mSomeSourceData = true;
    1007          19 :     if (!mSyncLoad) {
    1008             :       // Create an async metadata decoder and verify we succeed in doing so.
    1009          19 :       rv = DecodeMetadata(DECODE_FLAGS_DEFAULT);
    1010             :     }
    1011             :   }
    1012             : 
    1013          19 :   if (NS_FAILED(rv)) {
    1014           0 :     DoError();
    1015             :   }
    1016          19 :   return rv;
    1017             : }
    1018             : 
    1019             : nsresult
    1020          19 : RasterImage::SetSourceSizeHint(uint32_t aSizeHint)
    1021             : {
    1022          19 :   return mSourceBuffer->ExpectLength(aSizeHint);
    1023             : }
    1024             : 
    1025             : /********* Methods to implement lazy allocation of nsIProperties object *******/
    1026             : NS_IMETHODIMP
    1027           0 : RasterImage::Get(const char* prop, const nsIID& iid, void** result)
    1028             : {
    1029           0 :   if (!mProperties) {
    1030           0 :     return NS_ERROR_FAILURE;
    1031             :   }
    1032           0 :   return mProperties->Get(prop, iid, result);
    1033             : }
    1034             : 
    1035             : NS_IMETHODIMP
    1036           0 : RasterImage::Set(const char* prop, nsISupports* value)
    1037             : {
    1038           0 :   if (!mProperties) {
    1039           0 :     mProperties = do_CreateInstance("@mozilla.org/properties;1");
    1040             :   }
    1041           0 :   if (!mProperties) {
    1042           0 :     return NS_ERROR_OUT_OF_MEMORY;
    1043             :   }
    1044           0 :   return mProperties->Set(prop, value);
    1045             : }
    1046             : 
    1047             : NS_IMETHODIMP
    1048           0 : RasterImage::Has(const char* prop, bool* _retval)
    1049             : {
    1050           0 :   NS_ENSURE_ARG_POINTER(_retval);
    1051           0 :   if (!mProperties) {
    1052           0 :     *_retval = false;
    1053           0 :     return NS_OK;
    1054             :   }
    1055           0 :   return mProperties->Has(prop, _retval);
    1056             : }
    1057             : 
    1058             : NS_IMETHODIMP
    1059           0 : RasterImage::Undefine(const char* prop)
    1060             : {
    1061           0 :   if (!mProperties) {
    1062           0 :     return NS_ERROR_FAILURE;
    1063             :   }
    1064           0 :   return mProperties->Undefine(prop);
    1065             : }
    1066             : 
    1067             : NS_IMETHODIMP
    1068           0 : RasterImage::GetKeys(uint32_t* count, char*** keys)
    1069             : {
    1070           0 :   if (!mProperties) {
    1071           0 :     *count = 0;
    1072           0 :     *keys = nullptr;
    1073           0 :     return NS_OK;
    1074             :   }
    1075           0 :   return mProperties->GetKeys(count, keys);
    1076             : }
    1077             : 
    1078             : void
    1079           0 : RasterImage::Discard()
    1080             : {
    1081           0 :   MOZ_ASSERT(NS_IsMainThread());
    1082           0 :   MOZ_ASSERT(CanDiscard(), "Asked to discard but can't");
    1083           0 :   MOZ_ASSERT(!mAnimationState || gfxPrefs::ImageMemAnimatedDiscardable(),
    1084             :     "Asked to discard for animated image");
    1085             : 
    1086             :   // Delete all the decoded frames.
    1087           0 :   SurfaceCache::RemoveImage(ImageKey(this));
    1088             : 
    1089           0 :   if (mAnimationState) {
    1090           0 :     mImageContainer = nullptr;
    1091             :     gfx::IntRect rect =
    1092           0 :       mAnimationState->UpdateState(mAnimationFinished, this, mSize);
    1093           0 :     NotifyProgress(NoProgress, rect);
    1094             :   }
    1095             : 
    1096             :   // Notify that we discarded.
    1097           0 :   if (mProgressTracker) {
    1098           0 :     mProgressTracker->OnDiscard();
    1099             :   }
    1100           0 : }
    1101             : 
    1102             : bool
    1103           0 : RasterImage::CanDiscard() {
    1104           0 :   return mAllSourceData &&
    1105             :          // Can discard animated images if the pref is set
    1106           0 :          (!mAnimationState || gfxPrefs::ImageMemAnimatedDiscardable());
    1107             : }
    1108             : 
    1109             : NS_IMETHODIMP
    1110          14 : RasterImage::StartDecoding(uint32_t aFlags)
    1111             : {
    1112          14 :   if (mError) {
    1113           1 :     return NS_ERROR_FAILURE;
    1114             :   }
    1115             : 
    1116          13 :   if (!mHasSize) {
    1117          11 :     mWantFullDecode = true;
    1118          11 :     return NS_OK;
    1119             :   }
    1120             : 
    1121           2 :   uint32_t flags = (aFlags & FLAG_ASYNC_NOTIFY) | FLAG_SYNC_DECODE_IF_FAST;
    1122           2 :   return RequestDecodeForSize(mSize, flags);
    1123             : }
    1124             : 
    1125             : bool
    1126           9 : RasterImage::StartDecodingWithResult(uint32_t aFlags)
    1127             : {
    1128           9 :   if (mError) {
    1129           0 :     return false;
    1130             :   }
    1131             : 
    1132           9 :   if (!mHasSize) {
    1133           0 :     mWantFullDecode = true;
    1134           0 :     return false;
    1135             :   }
    1136             : 
    1137           9 :   uint32_t flags = (aFlags & FLAG_ASYNC_NOTIFY) | FLAG_SYNC_DECODE_IF_FAST;
    1138          18 :   DrawableSurface surface = RequestDecodeForSizeInternal(mSize, flags);
    1139           9 :   return surface && surface->IsFinished();
    1140             : }
    1141             : 
    1142             : NS_IMETHODIMP
    1143          13 : RasterImage::RequestDecodeForSize(const IntSize& aSize, uint32_t aFlags)
    1144             : {
    1145          13 :   MOZ_ASSERT(NS_IsMainThread());
    1146             : 
    1147          13 :   if (mError) {
    1148           0 :     return NS_ERROR_FAILURE;
    1149             :   }
    1150             : 
    1151          13 :   RequestDecodeForSizeInternal(aSize, aFlags);
    1152             : 
    1153          13 :   return NS_OK;
    1154             : }
    1155             : 
    1156             : DrawableSurface
    1157          22 : RasterImage::RequestDecodeForSizeInternal(const IntSize& aSize, uint32_t aFlags)
    1158             : {
    1159          22 :   MOZ_ASSERT(NS_IsMainThread());
    1160             : 
    1161          22 :   if (mError) {
    1162           0 :     return DrawableSurface();
    1163             :   }
    1164             : 
    1165          22 :   if (!mHasSize) {
    1166           0 :     mWantFullDecode = true;
    1167           0 :     return DrawableSurface();
    1168             :   }
    1169             : 
    1170             :   // Decide whether to sync decode images we can decode quickly. Here we are
    1171             :   // explicitly trading off flashing for responsiveness in the case that we're
    1172             :   // redecoding an image (see bug 845147).
    1173             :   bool shouldSyncDecodeIfFast =
    1174          22 :     !mHasBeenDecoded && (aFlags & FLAG_SYNC_DECODE_IF_FAST);
    1175             : 
    1176             :   uint32_t flags = shouldSyncDecodeIfFast
    1177          22 :                  ? aFlags
    1178          22 :                  : aFlags & ~FLAG_SYNC_DECODE_IF_FAST;
    1179             : 
    1180             :   // Perform a frame lookup, which will implicitly start decoding if needed.
    1181             :   return LookupFrame(aSize, flags, mAnimationState ? PlaybackType::eAnimated
    1182          22 :                                                    : PlaybackType::eStatic);
    1183             : }
    1184             : 
    1185             : static bool
    1186          33 : LaunchDecodingTask(IDecodingTask* aTask,
    1187             :                    RasterImage* aImage,
    1188             :                    uint32_t aFlags,
    1189             :                    bool aHaveSourceData)
    1190             : {
    1191          33 :   if (aHaveSourceData) {
    1192          25 :     nsCString uri(aImage->GetURIString());
    1193             : 
    1194             :     // If we have all the data, we can sync decode if requested.
    1195          14 :     if (aFlags & imgIContainer::FLAG_SYNC_DECODE) {
    1196           0 :       DecodePool::Singleton()->SyncRunIfPossible(aTask, uri);
    1197           0 :       return true;
    1198             :     }
    1199             : 
    1200          14 :     if (aFlags & imgIContainer::FLAG_SYNC_DECODE_IF_FAST) {
    1201           3 :       return DecodePool::Singleton()->SyncRunIfPreferred(aTask, uri);
    1202             :     }
    1203             :   }
    1204             : 
    1205             :   // Perform an async decode. We also take this path if we don't have all the
    1206             :   // source data yet, since sync decoding is impossible in that situation.
    1207          30 :   DecodePool::Singleton()->AsyncRun(aTask);
    1208          30 :   return false;
    1209             : }
    1210             : 
    1211             : bool
    1212          14 : RasterImage::Decode(const IntSize& aSize,
    1213             :                     uint32_t aFlags,
    1214             :                     PlaybackType aPlaybackType)
    1215             : {
    1216          14 :   MOZ_ASSERT(NS_IsMainThread());
    1217             : 
    1218          14 :   if (mError) {
    1219           0 :     return false;
    1220             :   }
    1221             : 
    1222             :   // If we don't have a size yet, we can't do any other decoding.
    1223          14 :   if (!mHasSize) {
    1224           0 :     mWantFullDecode = true;
    1225           0 :     return false;
    1226             :   }
    1227             : 
    1228             :   // We're about to decode again, which may mean that some of the previous sizes
    1229             :   // we've decoded at aren't useful anymore. We can allow them to expire from
    1230             :   // the cache by unlocking them here. When the decode finishes, it will send an
    1231             :   // invalidation that will cause all instances of this image to redraw. If this
    1232             :   // image is locked, any surfaces that are still useful will become locked
    1233             :   // again when LookupFrame touches them, and the remainder will eventually
    1234             :   // expire.
    1235          14 :   SurfaceCache::UnlockEntries(ImageKey(this));
    1236             : 
    1237             :   // Determine which flags we need to decode this image with.
    1238          14 :   DecoderFlags decoderFlags = DefaultDecoderFlags();
    1239          14 :   if (aFlags & FLAG_ASYNC_NOTIFY) {
    1240           3 :     decoderFlags |= DecoderFlags::ASYNC_NOTIFY;
    1241             :   }
    1242          14 :   if (mTransient) {
    1243           0 :     decoderFlags |= DecoderFlags::IMAGE_IS_TRANSIENT;
    1244             :   }
    1245          14 :   if (mHasBeenDecoded) {
    1246           0 :     decoderFlags |= DecoderFlags::IS_REDECODE;
    1247             :   }
    1248             : 
    1249          14 :   SurfaceFlags surfaceFlags = ToSurfaceFlags(aFlags);
    1250          14 :   if (IsOpaque()) {
    1251             :     // If there's no transparency, it doesn't matter whether we premultiply
    1252             :     // alpha or not.
    1253           0 :     surfaceFlags &= ~SurfaceFlags::NO_PREMULTIPLY_ALPHA;
    1254             :   }
    1255             : 
    1256             :   // Create a decoder.
    1257          28 :   RefPtr<IDecodingTask> task;
    1258          14 :   if (mAnimationState && aPlaybackType == PlaybackType::eAnimated) {
    1259           4 :     task = DecoderFactory::CreateAnimationDecoder(mDecoderType, WrapNotNull(this),
    1260             :                                                   mSourceBuffer, mSize,
    1261           2 :                                                   decoderFlags, surfaceFlags);
    1262             :     // We pass false for aAllowInvalidation because we may be asked to use
    1263             :     // async notifications. Any potential invalidation here will be sent when
    1264             :     // RequestRefresh is called, or NotifyDecodeComplete.
    1265             : #ifdef DEBUG
    1266             :     gfx::IntRect rect =
    1267             : #endif
    1268           2 :       mAnimationState->UpdateState(mAnimationFinished, this, mSize, false);
    1269           2 :     MOZ_ASSERT(rect.IsEmpty());
    1270             :   } else {
    1271          24 :     task = DecoderFactory::CreateDecoder(mDecoderType, WrapNotNull(this),
    1272             :                                          mSourceBuffer, mSize, aSize,
    1273          12 :                                          decoderFlags, surfaceFlags);
    1274             :   }
    1275             : 
    1276             :   // Make sure DecoderFactory was able to create a decoder successfully.
    1277          14 :   if (!task) {
    1278           0 :     return false;
    1279             :   }
    1280             : 
    1281          14 :   mDecodeCount++;
    1282             : 
    1283             :   // We're ready to decode; start the decoder.
    1284          14 :   return LaunchDecodingTask(task, this, aFlags, mAllSourceData);
    1285             : }
    1286             : 
    1287             : NS_IMETHODIMP
    1288          19 : RasterImage::DecodeMetadata(uint32_t aFlags)
    1289             : {
    1290          19 :   if (mError) {
    1291           0 :     return NS_ERROR_FAILURE;
    1292             :   }
    1293             : 
    1294          19 :   MOZ_ASSERT(!mHasSize, "Should not do unnecessary metadata decodes");
    1295             : 
    1296             :   // Create a decoder.
    1297             :   RefPtr<IDecodingTask> task =
    1298          38 :     DecoderFactory::CreateMetadataDecoder(mDecoderType, WrapNotNull(this),
    1299          38 :                                           mSourceBuffer);
    1300             : 
    1301             :   // Make sure DecoderFactory was able to create a decoder successfully.
    1302          19 :   if (!task) {
    1303           0 :     return NS_ERROR_FAILURE;
    1304             :   }
    1305             : 
    1306             :   // We're ready to decode; start the decoder.
    1307          19 :   LaunchDecodingTask(task, this, aFlags, mAllSourceData);
    1308          19 :   return NS_OK;
    1309             : }
    1310             : 
    1311             : void
    1312           0 : RasterImage::RecoverFromInvalidFrames(const IntSize& aSize, uint32_t aFlags)
    1313             : {
    1314           0 :   if (!mHasSize) {
    1315           0 :     return;
    1316             :   }
    1317             : 
    1318           0 :   NS_WARNING("A RasterImage's frames became invalid. Attempting to recover...");
    1319             : 
    1320             :   // Discard all existing frames, since they're probably all now invalid.
    1321           0 :   SurfaceCache::RemoveImage(ImageKey(this));
    1322             : 
    1323             :   // Relock the image if it's supposed to be locked.
    1324           0 :   if (mLockCount > 0) {
    1325           0 :     SurfaceCache::LockImage(ImageKey(this));
    1326             :   }
    1327             : 
    1328             :   // Animated images require some special handling, because we normally require
    1329             :   // that they never be discarded.
    1330           0 :   if (mAnimationState) {
    1331           0 :     Decode(mSize, aFlags | FLAG_SYNC_DECODE, PlaybackType::eAnimated);
    1332           0 :     ResetAnimation();
    1333           0 :     return;
    1334             :   }
    1335             : 
    1336             :   // For non-animated images, it's fine to recover using an async decode.
    1337           0 :   Decode(aSize, aFlags, PlaybackType::eStatic);
    1338             : }
    1339             : 
    1340             : static bool
    1341          92 : HaveSkia()
    1342             : {
    1343             : #ifdef MOZ_ENABLE_SKIA
    1344          92 :   return true;
    1345             : #else
    1346             :   return false;
    1347             : #endif
    1348             : }
    1349             : 
    1350             : bool
    1351          92 : RasterImage::CanDownscaleDuringDecode(const IntSize& aSize, uint32_t aFlags)
    1352             : {
    1353             :   // Check basic requirements: downscale-during-decode is enabled, Skia is
    1354             :   // available, this image isn't transient, we have all the source data and know
    1355             :   // our size, and the flags allow us to do it.
    1356         368 :   if (!mHasSize || mTransient || !HaveSkia() ||
    1357         276 :       !gfxPrefs::ImageDownscaleDuringDecodeEnabled() ||
    1358          92 :       !(aFlags & imgIContainer::FLAG_HIGH_QUALITY_SCALING)) {
    1359          22 :     return false;
    1360             :   }
    1361             : 
    1362             :   // We don't downscale animated images during decode.
    1363          70 :   if (mAnimationState) {
    1364          22 :     return false;
    1365             :   }
    1366             : 
    1367             :   // Never upscale.
    1368          48 :   if (aSize.width >= mSize.width || aSize.height >= mSize.height) {
    1369          48 :     return false;
    1370             :   }
    1371             : 
    1372             :   // Zero or negative width or height is unacceptable.
    1373           0 :   if (aSize.width < 1 || aSize.height < 1) {
    1374           0 :     return false;
    1375             :   }
    1376             : 
    1377             :   // There's no point in scaling if we can't store the result.
    1378           0 :   if (!SurfaceCache::CanHold(aSize)) {
    1379           0 :     return false;
    1380             :   }
    1381             : 
    1382           0 :   return true;
    1383             : }
    1384             : 
    1385             : DrawResult
    1386          35 : RasterImage::DrawInternal(DrawableSurface&& aSurface,
    1387             :                           gfxContext* aContext,
    1388             :                           const IntSize& aSize,
    1389             :                           const ImageRegion& aRegion,
    1390             :                           SamplingFilter aSamplingFilter,
    1391             :                           uint32_t aFlags,
    1392             :                           float aOpacity)
    1393             : {
    1394          70 :   gfxContextMatrixAutoSaveRestore saveMatrix(aContext);
    1395          35 :   ImageRegion region(aRegion);
    1396          35 :   bool frameIsFinished = aSurface->IsFinished();
    1397             : 
    1398             : #ifdef DEBUG
    1399             :   // Record the image drawing for startup performance testing.
    1400          35 :   if (NS_IsMainThread()) {
    1401          70 :     nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
    1402          35 :     NS_WARNING_ASSERTION(obs, "Can't get an observer service handle");
    1403          35 :     if (obs) {
    1404          70 :       nsCOMPtr<nsIURI> imageURI = mURI->ToIURI();
    1405          70 :       nsAutoCString spec;
    1406          35 :       imageURI->GetSpec(spec);
    1407          35 :       obs->NotifyObservers(nullptr, "image-drawing", NS_ConvertUTF8toUTF16(spec).get());
    1408             :     }
    1409             :   }
    1410             : #endif
    1411             : 
    1412             :   // By now we may have a frame with the requested size. If not, we need to
    1413             :   // adjust the drawing parameters accordingly.
    1414          35 :   IntSize finalSize = aSurface->GetImageSize();
    1415          35 :   bool couldRedecodeForBetterFrame = false;
    1416          35 :   if (finalSize != aSize) {
    1417           0 :     gfx::Size scale(double(aSize.width) / finalSize.width,
    1418           0 :                     double(aSize.height) / finalSize.height);
    1419           0 :     aContext->Multiply(gfxMatrix::Scaling(scale.width, scale.height));
    1420           0 :     region.Scale(1.0 / scale.width, 1.0 / scale.height);
    1421             : 
    1422           0 :     couldRedecodeForBetterFrame = CanDownscaleDuringDecode(aSize, aFlags);
    1423             :   }
    1424             : 
    1425          35 :   if (!aSurface->Draw(aContext, region, aSamplingFilter, aFlags, aOpacity)) {
    1426           0 :     RecoverFromInvalidFrames(aSize, aFlags);
    1427           0 :     return DrawResult::TEMPORARY_ERROR;
    1428             :   }
    1429          35 :   if (!frameIsFinished) {
    1430           0 :     return DrawResult::INCOMPLETE;
    1431             :   }
    1432          35 :   if (couldRedecodeForBetterFrame) {
    1433           0 :     return DrawResult::WRONG_SIZE;
    1434             :   }
    1435          35 :   return DrawResult::SUCCESS;
    1436             : }
    1437             : 
    1438             : //******************************************************************************
    1439             : NS_IMETHODIMP_(DrawResult)
    1440          35 : RasterImage::Draw(gfxContext* aContext,
    1441             :                   const IntSize& aSize,
    1442             :                   const ImageRegion& aRegion,
    1443             :                   uint32_t aWhichFrame,
    1444             :                   SamplingFilter aSamplingFilter,
    1445             :                   const Maybe<SVGImageContext>& /*aSVGContext - ignored*/,
    1446             :                   uint32_t aFlags,
    1447             :                   float aOpacity)
    1448             : {
    1449          35 :   if (aWhichFrame > FRAME_MAX_VALUE) {
    1450           0 :     return DrawResult::BAD_ARGS;
    1451             :   }
    1452             : 
    1453          35 :   if (mError) {
    1454           0 :     return DrawResult::BAD_IMAGE;
    1455             :   }
    1456             : 
    1457             :   // Illegal -- you can't draw with non-default decode flags.
    1458             :   // (Disabling colorspace conversion might make sense to allow, but
    1459             :   // we don't currently.)
    1460          35 :   if (ToSurfaceFlags(aFlags) != DefaultSurfaceFlags()) {
    1461           0 :     return DrawResult::BAD_ARGS;
    1462             :   }
    1463             : 
    1464          35 :   if (!aContext) {
    1465           0 :     return DrawResult::BAD_ARGS;
    1466             :   }
    1467             : 
    1468          35 :   if (mAnimationConsumers == 0) {
    1469           0 :     SendOnUnlockedDraw(aFlags);
    1470             :   }
    1471             : 
    1472             : 
    1473             :   // If we're not using SamplingFilter::GOOD, we shouldn't high-quality scale or
    1474             :   // downscale during decode.
    1475             :   uint32_t flags = aSamplingFilter == SamplingFilter::GOOD
    1476          35 :                  ? aFlags
    1477          35 :                  : aFlags & ~FLAG_HIGH_QUALITY_SCALING;
    1478             : 
    1479             :   DrawableSurface surface =
    1480          70 :     LookupFrame(aSize, flags, ToPlaybackType(aWhichFrame));
    1481          35 :   if (!surface) {
    1482             :     // Getting the frame (above) touches the image and kicks off decoding.
    1483           0 :     if (mDrawStartTime.IsNull()) {
    1484           0 :       mDrawStartTime = TimeStamp::Now();
    1485             :     }
    1486           0 :     return DrawResult::NOT_READY;
    1487             :   }
    1488             : 
    1489          35 :   bool shouldRecordTelemetry = !mDrawStartTime.IsNull() &&
    1490          35 :                                surface->IsFinished();
    1491             : 
    1492          35 :   auto result = DrawInternal(Move(surface), aContext, aSize,
    1493          35 :                              aRegion, aSamplingFilter, flags, aOpacity);
    1494             : 
    1495          35 :   if (shouldRecordTelemetry) {
    1496           0 :       TimeDuration drawLatency = TimeStamp::Now() - mDrawStartTime;
    1497           0 :       Telemetry::Accumulate(Telemetry::IMAGE_DECODE_ON_DRAW_LATENCY,
    1498           0 :                             int32_t(drawLatency.ToMicroseconds()));
    1499           0 :       if (mAnimationState) {
    1500           0 :         Telemetry::Accumulate(Telemetry::IMAGE_ANIMATED_DECODE_ON_DRAW_LATENCY,
    1501           0 :                               int32_t(drawLatency.ToMicroseconds()));
    1502             : 
    1503             :       }
    1504           0 :       mDrawStartTime = TimeStamp();
    1505             :   }
    1506             : 
    1507          35 :   return result;
    1508             : }
    1509             : 
    1510             : //******************************************************************************
    1511             : 
    1512             : NS_IMETHODIMP
    1513          56 : RasterImage::LockImage()
    1514             : {
    1515          56 :   MOZ_ASSERT(NS_IsMainThread(),
    1516             :              "Main thread to encourage serialization with UnlockImage");
    1517          56 :   if (mError) {
    1518           1 :     return NS_ERROR_FAILURE;
    1519             :   }
    1520             : 
    1521             :   // Increment the lock count
    1522          55 :   mLockCount++;
    1523             : 
    1524             :   // Lock this image's surfaces in the SurfaceCache.
    1525          55 :   if (mLockCount == 1) {
    1526           0 :     SurfaceCache::LockImage(ImageKey(this));
    1527             :   }
    1528             : 
    1529          55 :   return NS_OK;
    1530             : }
    1531             : 
    1532             : //******************************************************************************
    1533             : 
    1534             : NS_IMETHODIMP
    1535          33 : RasterImage::UnlockImage()
    1536             : {
    1537          33 :   MOZ_ASSERT(NS_IsMainThread(),
    1538             :              "Main thread to encourage serialization with LockImage");
    1539          33 :   if (mError) {
    1540           1 :     return NS_ERROR_FAILURE;
    1541             :   }
    1542             : 
    1543             :   // It's an error to call this function if the lock count is 0
    1544          32 :   MOZ_ASSERT(mLockCount > 0,
    1545             :              "Calling UnlockImage with mLockCount == 0!");
    1546          32 :   if (mLockCount == 0) {
    1547           0 :     return NS_ERROR_ABORT;
    1548             :   }
    1549             : 
    1550             :   // Decrement our lock count
    1551          32 :   mLockCount--;
    1552             : 
    1553             :   // Unlock this image's surfaces in the SurfaceCache.
    1554          32 :   if (mLockCount == 0 ) {
    1555           0 :     SurfaceCache::UnlockImage(ImageKey(this));
    1556             :   }
    1557             : 
    1558          32 :   return NS_OK;
    1559             : }
    1560             : 
    1561             : //******************************************************************************
    1562             : 
    1563             : NS_IMETHODIMP
    1564           0 : RasterImage::RequestDiscard()
    1565             : {
    1566           0 :   if (mDiscardable &&      // Enabled at creation time...
    1567           0 :       mLockCount == 0 &&   // ...not temporarily disabled...
    1568           0 :       CanDiscard()) {
    1569           0 :     Discard();
    1570             :   }
    1571             : 
    1572           0 :   return NS_OK;
    1573             : }
    1574             : 
    1575             : // Indempotent error flagging routine. If a decoder is open, shuts it down.
    1576             : void
    1577           1 : RasterImage::DoError()
    1578             : {
    1579             :   // If we've flagged an error before, we have nothing to do
    1580           1 :   if (mError) {
    1581           1 :     return;
    1582             :   }
    1583             : 
    1584             :   // We can't safely handle errors off-main-thread, so dispatch a worker to
    1585             :   // do it.
    1586           0 :   if (!NS_IsMainThread()) {
    1587           0 :     HandleErrorWorker::DispatchIfNeeded(this);
    1588           0 :     return;
    1589             :   }
    1590             : 
    1591             :   // Put the container in an error state.
    1592           0 :   mError = true;
    1593             : 
    1594             :   // Stop animation and release our FrameAnimator.
    1595           0 :   if (mAnimating) {
    1596           0 :     StopAnimation();
    1597             :   }
    1598           0 :   mAnimationState = Nothing();
    1599           0 :   mFrameAnimator = nullptr;
    1600             : 
    1601             :   // Release all locks.
    1602           0 :   mLockCount = 0;
    1603           0 :   SurfaceCache::UnlockImage(ImageKey(this));
    1604             : 
    1605             :   // Release all frames from the surface cache.
    1606           0 :   SurfaceCache::RemoveImage(ImageKey(this));
    1607             : 
    1608             :   // Invalidate to get rid of any partially-drawn image content.
    1609           0 :   NotifyProgress(NoProgress, IntRect(0, 0, mSize.width, mSize.height));
    1610             : 
    1611           0 :   MOZ_LOG(gImgLog, LogLevel::Error,
    1612             :           ("RasterImage: [this=%p] Error detected for image\n", this));
    1613             : }
    1614             : 
    1615             : /* static */ void
    1616           0 : RasterImage::HandleErrorWorker::DispatchIfNeeded(RasterImage* aImage)
    1617             : {
    1618           0 :   RefPtr<HandleErrorWorker> worker = new HandleErrorWorker(aImage);
    1619           0 :   NS_DispatchToMainThread(worker);
    1620           0 : }
    1621             : 
    1622           0 : RasterImage::HandleErrorWorker::HandleErrorWorker(RasterImage* aImage)
    1623             :   : Runnable("image::RasterImage::HandleErrorWorker")
    1624           0 :   , mImage(aImage)
    1625             : {
    1626           0 :   MOZ_ASSERT(mImage, "Should have image");
    1627           0 : }
    1628             : 
    1629             : NS_IMETHODIMP
    1630           0 : RasterImage::HandleErrorWorker::Run()
    1631             : {
    1632           0 :   mImage->DoError();
    1633             : 
    1634           0 :   return NS_OK;
    1635             : }
    1636             : 
    1637             : bool
    1638          16 : RasterImage::ShouldAnimate()
    1639             : {
    1640          32 :   return ImageResource::ShouldAnimate() &&
    1641          32 :          mAnimationState &&
    1642          44 :          mAnimationState->KnownFrameCount() >= 1 &&
    1643          28 :          !mAnimationFinished;
    1644             : }
    1645             : 
    1646             : #ifdef DEBUG
    1647             : NS_IMETHODIMP
    1648           0 : RasterImage::GetFramesNotified(uint32_t* aFramesNotified)
    1649             : {
    1650           0 :   NS_ENSURE_ARG_POINTER(aFramesNotified);
    1651             : 
    1652           0 :   *aFramesNotified = mFramesNotified;
    1653             : 
    1654           0 :   return NS_OK;
    1655             : }
    1656             : #endif
    1657             : 
    1658             : void
    1659         133 : RasterImage::NotifyProgress(Progress aProgress,
    1660             :                             const IntRect& aInvalidRect /* = IntRect() */,
    1661             :                             const Maybe<uint32_t>& aFrameCount /* = Nothing() */,
    1662             :                             DecoderFlags aDecoderFlags
    1663             :                               /* = DefaultDecoderFlags() */,
    1664             :                             SurfaceFlags aSurfaceFlags
    1665             :                               /* = DefaultSurfaceFlags() */)
    1666             : {
    1667         133 :   MOZ_ASSERT(NS_IsMainThread());
    1668             : 
    1669             :   // Ensure that we stay alive long enough to finish notifying.
    1670         266 :   RefPtr<RasterImage> image = this;
    1671             : 
    1672         133 :   const bool wasDefaultFlags = aSurfaceFlags == DefaultSurfaceFlags();
    1673             : 
    1674         133 :   if (!aInvalidRect.IsEmpty() && wasDefaultFlags) {
    1675             :     // Update our image container since we're invalidating.
    1676          22 :     UpdateImageContainer();
    1677             :   }
    1678             : 
    1679         133 :   if (!(aDecoderFlags & DecoderFlags::FIRST_FRAME_ONLY)) {
    1680             :     // We may have decoded new animation frames; update our animation state.
    1681         121 :     MOZ_ASSERT_IF(aFrameCount && *aFrameCount > 1, mAnimationState || mError);
    1682         121 :     if (mAnimationState && aFrameCount) {
    1683          36 :       mAnimationState->UpdateKnownFrameCount(*aFrameCount);
    1684             :     }
    1685             : 
    1686             :     // If we should start animating right now, do so.
    1687         294 :     if (mAnimationState && aFrameCount == Some(1u) &&
    1688         244 :         mPendingAnimation && ShouldAnimate()) {
    1689           0 :       StartAnimation();
    1690             :     }
    1691             :   }
    1692             : 
    1693             :   // Tell the observers what happened.
    1694         133 :   image->mProgressTracker->SyncNotifyProgress(aProgress, aInvalidRect);
    1695         133 : }
    1696             : 
    1697             : void
    1698          33 : RasterImage::NotifyDecodeComplete(const DecoderFinalStatus& aStatus,
    1699             :                                   const ImageMetadata& aMetadata,
    1700             :                                   const DecoderTelemetry& aTelemetry,
    1701             :                                   Progress aProgress,
    1702             :                                   const IntRect& aInvalidRect,
    1703             :                                   const Maybe<uint32_t>& aFrameCount,
    1704             :                                   DecoderFlags aDecoderFlags,
    1705             :                                   SurfaceFlags aSurfaceFlags)
    1706             : {
    1707          33 :   MOZ_ASSERT(NS_IsMainThread());
    1708             : 
    1709             :   // If the decoder detected an error, log it to the error console.
    1710          33 :   if (aStatus.mShouldReportError) {
    1711           0 :     ReportDecoderError();
    1712             :   }
    1713             : 
    1714             :   // Record all the metadata the decoder gathered about this image.
    1715          33 :   bool metadataOK = SetMetadata(aMetadata, aStatus.mWasMetadataDecode);
    1716          33 :   if (!metadataOK) {
    1717             :     // This indicates a serious error that requires us to discard all existing
    1718             :     // surfaces and redecode to recover. We'll drop the results from this
    1719             :     // decoder on the floor, since they aren't valid.
    1720           0 :     RecoverFromInvalidFrames(mSize,
    1721           0 :                              FromSurfaceFlags(aSurfaceFlags));
    1722           0 :     return;
    1723             :   }
    1724             : 
    1725          33 :   MOZ_ASSERT(mError || mHasSize || !aMetadata.HasSize(),
    1726             :              "SetMetadata should've gotten a size");
    1727             : 
    1728          33 :   if (!aStatus.mWasMetadataDecode && aStatus.mFinished) {
    1729             :     // Flag that we've been decoded before.
    1730          14 :     mHasBeenDecoded = true;
    1731             :   }
    1732             : 
    1733             :   // Send out any final notifications.
    1734             :   NotifyProgress(aProgress, aInvalidRect, aFrameCount,
    1735          33 :                  aDecoderFlags, aSurfaceFlags);
    1736             : 
    1737         120 :   if (!(aDecoderFlags & DecoderFlags::FIRST_FRAME_ONLY) &&
    1738         101 :       mHasBeenDecoded && mAnimationState) {
    1739             :     // We've finished a full decode of all animation frames and our AnimationState
    1740             :     // has been notified about them all, so let it know not to expect anymore.
    1741           2 :     mAnimationState->NotifyDecodeComplete();
    1742           2 :     gfx::IntRect rect = mAnimationState->UpdateState(mAnimationFinished, this, mSize);
    1743           2 :     if (!rect.IsEmpty()) {
    1744           0 :       NotifyProgress(NoProgress, rect);
    1745             :     }
    1746             :   }
    1747             : 
    1748             :   // Do some telemetry if this isn't a metadata decode.
    1749          33 :   if (!aStatus.mWasMetadataDecode) {
    1750          14 :     if (aTelemetry.mChunkCount) {
    1751          14 :       Telemetry::Accumulate(Telemetry::IMAGE_DECODE_CHUNKS, aTelemetry.mChunkCount);
    1752             :     }
    1753             : 
    1754          14 :     if (aStatus.mFinished) {
    1755          14 :       Telemetry::Accumulate(Telemetry::IMAGE_DECODE_TIME,
    1756          28 :                             int32_t(aTelemetry.mDecodeTime.ToMicroseconds()));
    1757             : 
    1758          14 :       if (mAnimationState) {
    1759           2 :         Telemetry::Accumulate(Telemetry::IMAGE_ANIMATED_DECODE_TIME,
    1760           4 :                               int32_t(aTelemetry.mDecodeTime.ToMicroseconds()));
    1761             :       }
    1762             : 
    1763          14 :       if (aTelemetry.mSpeedHistogram) {
    1764          14 :         Telemetry::Accumulate(*aTelemetry.mSpeedHistogram, aTelemetry.Speed());
    1765             :       }
    1766             :     }
    1767             :   }
    1768             : 
    1769             :   // Only act on errors if we have no usable frames from the decoder.
    1770          33 :   if (aStatus.mHadError &&
    1771           0 :       (!mAnimationState || mAnimationState->KnownFrameCount() == 0)) {
    1772           0 :     DoError();
    1773          33 :   } else if (aStatus.mWasMetadataDecode && !mHasSize) {
    1774           0 :     DoError();
    1775             :   }
    1776             : 
    1777             :   // XXX(aosmond): Can we get this far without mFinished == true?
    1778          33 :   if (aStatus.mFinished && aStatus.mWasMetadataDecode) {
    1779             :     // If we were waiting to fire the load event, go ahead and fire it now.
    1780          19 :     if (mLoadProgress) {
    1781          19 :       NotifyForLoadEvent(*mLoadProgress);
    1782          19 :       mLoadProgress = Nothing();
    1783          19 :       NotifyProgress(FLAG_ONLOAD_UNBLOCKED);
    1784             :     }
    1785             : 
    1786             :     // If we were a metadata decode and a full decode was requested, do it.
    1787          19 :     if (mWantFullDecode) {
    1788          11 :       mWantFullDecode = false;
    1789          11 :       RequestDecodeForSize(mSize, DECODE_FLAGS_DEFAULT);
    1790             :     }
    1791             :   }
    1792             : }
    1793             : 
    1794             : void
    1795           0 : RasterImage::ReportDecoderError()
    1796             : {
    1797             :   nsCOMPtr<nsIConsoleService> consoleService =
    1798           0 :     do_GetService(NS_CONSOLESERVICE_CONTRACTID);
    1799             :   nsCOMPtr<nsIScriptError> errorObject =
    1800           0 :     do_CreateInstance(NS_SCRIPTERROR_CONTRACTID);
    1801             : 
    1802           0 :   if (consoleService && errorObject) {
    1803           0 :     nsAutoString msg(NS_LITERAL_STRING("Image corrupt or truncated."));
    1804           0 :     nsAutoString src;
    1805           0 :     if (GetURI()) {
    1806           0 :       nsCString uri;
    1807           0 :       if (GetURI()->GetSpecTruncatedTo1k(uri) == ImageURL::TruncatedTo1k) {
    1808           0 :         msg += NS_LITERAL_STRING(" URI in this note truncated due to length.");
    1809             :       }
    1810           0 :       src = NS_ConvertUTF8toUTF16(uri);
    1811             :     }
    1812           0 :     if (NS_SUCCEEDED(errorObject->InitWithWindowID(
    1813             :                        msg,
    1814             :                        src,
    1815             :                        EmptyString(), 0, 0, nsIScriptError::errorFlag,
    1816             :                        "Image", InnerWindowID()
    1817             :                      ))) {
    1818           0 :       consoleService->LogMessage(errorObject);
    1819             :     }
    1820             :   }
    1821           0 : }
    1822             : 
    1823             : already_AddRefed<imgIContainer>
    1824           0 : RasterImage::Unwrap()
    1825             : {
    1826           0 :   nsCOMPtr<imgIContainer> self(this);
    1827           0 :   return self.forget();
    1828             : }
    1829             : 
    1830             : void
    1831          14 : RasterImage::PropagateUseCounters(nsIDocument*)
    1832             : {
    1833             :   // No use counters.
    1834          14 : }
    1835             : 
    1836             : IntSize
    1837          35 : RasterImage::OptimalImageSizeForDest(const gfxSize& aDest, uint32_t aWhichFrame,
    1838             :                                      SamplingFilter aSamplingFilter, uint32_t aFlags)
    1839             : {
    1840          35 :   MOZ_ASSERT(aDest.width >= 0 || ceil(aDest.width) <= INT32_MAX ||
    1841             :              aDest.height >= 0 || ceil(aDest.height) <= INT32_MAX,
    1842             :              "Unexpected destination size");
    1843             : 
    1844          35 :   if (mSize.IsEmpty() || aDest.IsEmpty()) {
    1845           0 :     return IntSize(0, 0);
    1846             :   }
    1847             : 
    1848          35 :   IntSize destSize = IntSize::Ceil(aDest.width, aDest.height);
    1849             : 
    1850          70 :   if (aSamplingFilter == SamplingFilter::GOOD &&
    1851          35 :       CanDownscaleDuringDecode(destSize, aFlags)) {
    1852           0 :     return destSize;
    1853             :   }
    1854             : 
    1855             :   // We can't scale to this size. Use our intrinsic size for now.
    1856          35 :   return mSize;
    1857             : }
    1858             : 
    1859             : } // namespace image
    1860             : } // namespace mozilla

Generated by: LCOV version 1.13