image/src/RasterImage.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     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/. */
     6 // Must #include ImageLogging.h before any IPDL-generated files or other files that #include prlog.h
     7 #include "ImageLogging.h"
     9 #include "RasterImage.h"
    11 #include "base/histogram.h"
    12 #include "gfxPlatform.h"
    13 #include "nsComponentManagerUtils.h"
    14 #include "imgDecoderObserver.h"
    15 #include "nsError.h"
    16 #include "Decoder.h"
    17 #include "nsAutoPtr.h"
    18 #include "prenv.h"
    19 #include "prsystem.h"
    20 #include "ImageContainer.h"
    21 #include "Layers.h"
    22 #include "nsPresContext.h"
    23 #include "nsIThreadPool.h"
    24 #include "nsXPCOMCIDInternal.h"
    25 #include "nsIObserverService.h"
    26 #include "FrameAnimator.h"
    28 #include "nsPNGDecoder.h"
    29 #include "nsGIFDecoder2.h"
    30 #include "nsJPEGDecoder.h"
    31 #include "nsBMPDecoder.h"
    32 #include "nsICODecoder.h"
    33 #include "nsIconDecoder.h"
    35 #include "gfxContext.h"
    37 #include "mozilla/gfx/2D.h"
    38 #include "mozilla/RefPtr.h"
    39 #include "mozilla/MemoryReporting.h"
    40 #include "mozilla/Services.h"
    41 #include "mozilla/Preferences.h"
    42 #include <stdint.h>
    43 #include "mozilla/Telemetry.h"
    44 #include "mozilla/TimeStamp.h"
    45 #include "mozilla/ClearOnShutdown.h"
    46 #include "mozilla/gfx/Scale.h"
    48 #include "GeckoProfiler.h"
    49 #include "gfx2DGlue.h"
    50 #include <algorithm>
    52 #ifdef MOZ_NUWA_PROCESS
    53 #include "ipc/Nuwa.h"
    54 #endif
    56 using namespace mozilla;
    57 using namespace mozilla::gfx;
    58 using namespace mozilla::image;
    59 using namespace mozilla::layers;
    61 // a mask for flags that will affect the decoding
    62 #define DECODE_FLAGS_MASK (imgIContainer::FLAG_DECODE_NO_PREMULTIPLY_ALPHA | imgIContainer::FLAG_DECODE_NO_COLORSPACE_CONVERSION)
    63 #define DECODE_FLAGS_DEFAULT 0
    65 /* Accounting for compressed data */
    66 #if defined(PR_LOGGING)
    67 static PRLogModuleInfo *
    68 GetCompressedImageAccountingLog()
    69 {
    70   static PRLogModuleInfo *sLog;
    71   if (!sLog)
    72     sLog = PR_NewLogModule("CompressedImageAccounting");
    73   return sLog;
    74 }
    75 #else
    76 #define GetCompressedImageAccountingLog()
    77 #endif
    79 // Tweakable progressive decoding parameters.  These are initialized to 0 here
    80 // because otherwise, we have to initialize them in a static initializer, which
    81 // makes us slower to start up.
    82 static uint32_t gDecodeBytesAtATime = 0;
    83 static uint32_t gMaxMSBeforeYield = 0;
    84 static bool gHQDownscaling = false;
    85 // This is interpreted as a floating-point value / 1000
    86 static uint32_t gHQDownscalingMinFactor = 1000;
    87 static bool gMultithreadedDecoding = true;
    88 static int32_t gDecodingThreadLimit = -1;
    89 // The number of pixels in a 5 megapixel decoded image.
    90 // Equivalent to an example 3125x1600 resolution.
    91 static uint32_t gHQUpscalingMaxSize = 20971520;
    93 // The maximum number of times any one RasterImage was decoded.  This is only
    94 // used for statistics.
    95 static int32_t sMaxDecodeCount = 0;
    97 static void
    98 InitPrefCaches()
    99 {
   100   Preferences::AddUintVarCache(&gDecodeBytesAtATime,
   101                                "image.mem.decode_bytes_at_a_time", 200000);
   102   Preferences::AddUintVarCache(&gMaxMSBeforeYield,
   103                                "image.mem.max_ms_before_yield", 400);
   104   Preferences::AddBoolVarCache(&gHQDownscaling,
   105                                "image.high_quality_downscaling.enabled", false);
   106   Preferences::AddUintVarCache(&gHQDownscalingMinFactor,
   107                                "image.high_quality_downscaling.min_factor", 1000);
   108   Preferences::AddBoolVarCache(&gMultithreadedDecoding,
   109                                "image.multithreaded_decoding.enabled", true);
   110   Preferences::AddIntVarCache(&gDecodingThreadLimit,
   111                               "image.multithreaded_decoding.limit", -1);
   112   Preferences::AddUintVarCache(&gHQUpscalingMaxSize,
   113                                "image.high_quality_upscaling.max_size", 20971520);
   114 }
   116 /* We define our own error checking macros here for 2 reasons:
   117  *
   118  * 1) Most of the failures we encounter here will (hopefully) be
   119  * the result of decoding failures (ie, bad data) and not code
   120  * failures. As such, we don't want to clutter up debug consoles
   121  * with spurious messages about NS_ENSURE_SUCCESS failures.
   122  *
   123  * 2) We want to set the internal error flag, shutdown properly,
   124  * and end up in an error state.
   125  *
   126  * So this macro should be called when the desired failure behavior
   127  * is to put the container into an error state and return failure.
   128  * It goes without saying that macro won't compile outside of a
   129  * non-static RasterImage method.
   130  */
   131 #define LOG_CONTAINER_ERROR                      \
   132   PR_BEGIN_MACRO                                 \
   133   PR_LOG (GetImgLog(), PR_LOG_ERROR,             \
   134           ("RasterImage: [this=%p] Error "      \
   135            "detected at line %u for image of "   \
   136            "type %s\n", this, __LINE__,          \
   137            mSourceDataMimeType.get()));          \
   138   PR_END_MACRO
   140 #define CONTAINER_ENSURE_SUCCESS(status)      \
   141   PR_BEGIN_MACRO                              \
   142   nsresult _status = status; /* eval once */  \
   143   if (NS_FAILED(_status)) {                   \
   144     LOG_CONTAINER_ERROR;                      \
   145     DoError();                                \
   146     return _status;                           \
   147   }                                           \
   148  PR_END_MACRO
   150 #define CONTAINER_ENSURE_TRUE(arg, rv)  \
   151   PR_BEGIN_MACRO                        \
   152   if (!(arg)) {                         \
   153     LOG_CONTAINER_ERROR;                \
   154     DoError();                          \
   155     return rv;                          \
   156   }                                     \
   157   PR_END_MACRO
   161 static int num_containers;
   162 static int num_discardable_containers;
   163 static int64_t total_source_bytes;
   164 static int64_t discardable_source_bytes;
   166 /* Are we globally disabling image discarding? */
   167 static bool
   168 DiscardingEnabled()
   169 {
   170   static bool inited;
   171   static bool enabled;
   173   if (!inited) {
   174     inited = true;
   176     enabled = (PR_GetEnv("MOZ_DISABLE_IMAGE_DISCARD") == nullptr);
   177   }
   179   return enabled;
   180 }
   182 class ScaleRequest
   183 {
   184 public:
   185   ScaleRequest(RasterImage* aImage, const gfxSize& aScale, imgFrame* aSrcFrame)
   186     : scale(aScale)
   187     , dstLocked(false)
   188     , done(false)
   189     , stopped(false)
   190   {
   191     MOZ_ASSERT(!aSrcFrame->GetIsPaletted());
   192     MOZ_ASSERT(aScale.width > 0 && aScale.height > 0);
   194     weakImage = aImage->asWeakPtr();
   195     srcRect = aSrcFrame->GetRect();
   197     nsIntRect dstRect = srcRect;
   198     dstRect.ScaleRoundOut(scale.width, scale.height);
   199     dstSize = dstRect.Size();
   200   }
   202   // This can only be called on the main thread.
   203   bool GetSurfaces(imgFrame* srcFrame)
   204   {
   205     MOZ_ASSERT(NS_IsMainThread());
   207     nsRefPtr<RasterImage> image = weakImage.get();
   208     if (!image) {
   209       return false;
   210     }
   212     bool success = false;
   213     if (!dstLocked) {
   214       // We need to hold a lock onto the RasterImage object itself so that
   215       // it (and its associated imgFrames) aren't marked as discardable.
   216       bool imgLocked = NS_SUCCEEDED(image->LockImage());
   217       bool srcLocked = NS_SUCCEEDED(srcFrame->LockImageData());
   218       dstLocked = NS_SUCCEEDED(dstFrame->LockImageData());
   220       nsRefPtr<gfxASurface> dstASurf;
   221       nsRefPtr<gfxASurface> srcASurf;
   222       success = srcLocked && NS_SUCCEEDED(srcFrame->GetSurface(getter_AddRefs(srcASurf)));
   223       success = success && dstLocked && NS_SUCCEEDED(dstFrame->GetSurface(getter_AddRefs(dstASurf)));
   225       success = success && imgLocked && srcLocked && dstLocked && srcASurf && dstASurf;
   227       if (success) {
   228         srcSurface = srcASurf->GetAsImageSurface();
   229         dstSurface = dstASurf->GetAsImageSurface();
   230         srcData = srcSurface->Data();
   231         dstData = dstSurface->Data();
   232         srcStride = srcSurface->Stride();
   233         dstStride = dstSurface->Stride();
   234         srcFormat = mozilla::gfx::ImageFormatToSurfaceFormat(srcFrame->GetFormat());
   235       }
   237       // We have references to the Thebes surfaces, so we don't need to leave
   238       // the source frame (that we don't own) locked. We'll unlock the
   239       // destination frame in ReleaseSurfaces(), below.
   240       if (srcLocked) {
   241         success = NS_SUCCEEDED(srcFrame->UnlockImageData()) && success;
   242       }
   244       success = success && srcSurface && dstSurface;
   245     }
   247     return success;
   248   }
   250   // This can only be called on the main thread.
   251   bool ReleaseSurfaces()
   252   {
   253     MOZ_ASSERT(NS_IsMainThread());
   255     nsRefPtr<RasterImage> image = weakImage.get();
   256     if (!image) {
   257       return false;
   258     }
   260     bool success = false;
   261     if (dstLocked) {
   262       if (DiscardingEnabled())
   263         dstFrame->SetDiscardable();
   264       success = NS_SUCCEEDED(dstFrame->UnlockImageData());
   265       success = success && NS_SUCCEEDED(image->UnlockImage());
   267       dstLocked = false;
   268       srcData = nullptr;
   269       dstData = nullptr;
   270       srcSurface = nullptr;
   271       dstSurface = nullptr;
   272     }
   273     return success;
   274   }
   276   // These values may only be touched on the main thread.
   277   WeakPtr<RasterImage> weakImage;
   278   nsAutoPtr<imgFrame> dstFrame;
   279   nsRefPtr<gfxImageSurface> srcSurface;
   280   nsRefPtr<gfxImageSurface> dstSurface;
   282   // Below are the values that may be touched on the scaling thread.
   283   gfxSize scale;
   284   uint8_t* srcData;
   285   uint8_t* dstData;
   286   nsIntRect srcRect;
   287   gfxIntSize dstSize;
   288   uint32_t srcStride;
   289   uint32_t dstStride;
   290   mozilla::gfx::SurfaceFormat srcFormat;
   291   bool dstLocked;
   292   bool done;
   293   // This boolean is accessed from both threads simultaneously without locking.
   294   // That's safe because stopping a ScaleRequest is strictly an optimization;
   295   // if we're not cache-coherent, at worst we'll do extra work.
   296   bool stopped;
   297 };
   299 class DrawRunner : public nsRunnable
   300 {
   301 public:
   302   DrawRunner(ScaleRequest* request)
   303    : mScaleRequest(request)
   304   {}
   306   NS_IMETHOD Run()
   307   {
   308     // ScaleWorker is finished with this request, so we can unlock the data now.
   309     mScaleRequest->ReleaseSurfaces();
   311     nsRefPtr<RasterImage> image = mScaleRequest->weakImage.get();
   313     if (image) {
   314       RasterImage::ScaleStatus status;
   315       if (mScaleRequest->done) {
   316         status = RasterImage::SCALE_DONE;
   317       } else {
   318         status = RasterImage::SCALE_INVALID;
   319       }
   321       image->ScalingDone(mScaleRequest, status);
   322     }
   324     return NS_OK;
   325   }
   327 private: /* members */
   328   nsAutoPtr<ScaleRequest> mScaleRequest;
   329 };
   331 class ScaleRunner : public nsRunnable
   332 {
   333 public:
   334   ScaleRunner(RasterImage* aImage, const gfxSize& aScale, imgFrame* aSrcFrame)
   335   {
   336     nsAutoPtr<ScaleRequest> request(new ScaleRequest(aImage, aScale, aSrcFrame));
   338     // Destination is unconditionally ARGB32 because that's what the scaler
   339     // outputs.
   340     request->dstFrame = new imgFrame();
   341     nsresult rv = request->dstFrame->Init(0, 0, request->dstSize.width, request->dstSize.height,
   342                                           gfxImageFormat::ARGB32);
   344     if (NS_FAILED(rv) || !request->GetSurfaces(aSrcFrame)) {
   345       return;
   346     }
   348     aImage->ScalingStart(request);
   350     mScaleRequest = request;
   351   }
   353   NS_IMETHOD Run()
   354   {
   355     // An alias just for ease of typing
   356     ScaleRequest* request = mScaleRequest;
   358     if (!request->stopped) {
   359       request->done = mozilla::gfx::Scale(request->srcData, request->srcRect.width, request->srcRect.height, request->srcStride,
   360                                           request->dstData, request->dstSize.width, request->dstSize.height, request->dstStride,
   361                                           request->srcFormat);
   362     } else {
   363       request->done = false;
   364     }
   366     // OK, we've got a new scaled image. Let's get the main thread to unlock and
   367     // redraw it.
   368     nsRefPtr<DrawRunner> runner = new DrawRunner(mScaleRequest.forget());
   369     NS_DispatchToMainThread(runner, NS_DISPATCH_NORMAL);
   371     return NS_OK;
   372   }
   374   bool IsOK() const { return !!mScaleRequest; }
   376 private:
   377   nsAutoPtr<ScaleRequest> mScaleRequest;
   378 };
   380 namespace mozilla {
   381 namespace image {
   383 /* static */ StaticRefPtr<RasterImage::DecodePool> RasterImage::DecodePool::sSingleton;
   384 static nsCOMPtr<nsIThread> sScaleWorkerThread = nullptr;
   386 #ifndef DEBUG
   387 NS_IMPL_ISUPPORTS(RasterImage, imgIContainer, nsIProperties)
   388 #else
   389 NS_IMPL_ISUPPORTS(RasterImage, imgIContainer, nsIProperties,
   390                   imgIContainerDebug)
   391 #endif
   393 //******************************************************************************
   394 RasterImage::RasterImage(imgStatusTracker* aStatusTracker,
   395                          ImageURL* aURI /* = nullptr */) :
   396   ImageResource(aURI), // invoke superclass's constructor
   397   mSize(0,0),
   398   mFrameDecodeFlags(DECODE_FLAGS_DEFAULT),
   399   mMultipartDecodedFrame(nullptr),
   400   mAnim(nullptr),
   401   mLockCount(0),
   402   mDecodeCount(0),
   403   mRequestedSampleSize(0),
   404 #ifdef DEBUG
   405   mFramesNotified(0),
   406 #endif
   407   mDecodingMonitor("RasterImage Decoding Monitor"),
   408   mDecoder(nullptr),
   409   mBytesDecoded(0),
   410   mInDecoder(false),
   411   mStatusDiff(ImageStatusDiff::NoChange()),
   412   mNotifying(false),
   413   mHasSize(false),
   414   mDecodeOnDraw(false),
   415   mMultipart(false),
   416   mDiscardable(false),
   417   mHasSourceData(false),
   418   mDecoded(false),
   419   mHasBeenDecoded(false),
   420   mAnimationFinished(false),
   421   mFinishing(false),
   422   mInUpdateImageContainer(false),
   423   mWantFullDecode(false),
   424   mPendingError(false),
   425   mScaleRequest(nullptr)
   426 {
   427   mStatusTrackerInit = new imgStatusTrackerInit(this, aStatusTracker);
   429   // Set up the discard tracker node.
   430   mDiscardTrackerNode.img = this;
   431   Telemetry::GetHistogramById(Telemetry::IMAGE_DECODE_COUNT)->Add(0);
   433   // Statistics
   434   num_containers++;
   435 }
   437 //******************************************************************************
   438 RasterImage::~RasterImage()
   439 {
   440   // Discardable statistics
   441   if (mDiscardable) {
   442     num_discardable_containers--;
   443     discardable_source_bytes -= mSourceData.Length();
   445     PR_LOG (GetCompressedImageAccountingLog(), PR_LOG_DEBUG,
   446             ("CompressedImageAccounting: destroying RasterImage %p.  "
   447              "Total Containers: %d, Discardable containers: %d, "
   448              "Total source bytes: %lld, Source bytes for discardable containers %lld",
   449              this,
   450              num_containers,
   451              num_discardable_containers,
   452              total_source_bytes,
   453              discardable_source_bytes));
   454   }
   456   if (mDecoder) {
   457     // Kill off our decode request, if it's pending.  (If not, this call is
   458     // harmless.)
   459     ReentrantMonitorAutoEnter lock(mDecodingMonitor);
   460     DecodePool::StopDecoding(this);
   461     mDecoder = nullptr;
   463     // Unlock the last frame (if we have any). Our invariant is that, while we
   464     // have a decoder open, the last frame is always locked.
   465     // This would be done in ShutdownDecoder, but since mDecoder is non-null,
   466     // we didn't call ShutdownDecoder and we need to do it manually.
   467     if (GetNumFrames() > 0) {
   468       imgFrame *curframe = mFrameBlender.RawGetFrame(GetNumFrames() - 1);
   469       curframe->UnlockImageData();
   470     }
   471   }
   473   delete mAnim;
   474   mAnim = nullptr;
   475   delete mMultipartDecodedFrame;
   477   // Total statistics
   478   num_containers--;
   479   total_source_bytes -= mSourceData.Length();
   481   if (NS_IsMainThread()) {
   482     DiscardTracker::Remove(&mDiscardTrackerNode);
   483   }
   484 }
   486 /* static */ void
   487 RasterImage::Initialize()
   488 {
   489   InitPrefCaches();
   491   // Create our singletons now, so we don't have to worry about what thread
   492   // they're created on.
   493   DecodePool::Singleton();
   494 }
   496 nsresult
   497 RasterImage::Init(const char* aMimeType,
   498                   uint32_t aFlags)
   499 {
   500   // We don't support re-initialization
   501   if (mInitialized)
   502     return NS_ERROR_ILLEGAL_VALUE;
   504   // Not sure an error can happen before init, but be safe
   505   if (mError)
   506     return NS_ERROR_FAILURE;
   508   NS_ENSURE_ARG_POINTER(aMimeType);
   510   // We must be non-discardable and non-decode-on-draw for
   511   // multipart channels
   512   NS_ABORT_IF_FALSE(!(aFlags & INIT_FLAG_MULTIPART) ||
   513                     (!(aFlags & INIT_FLAG_DISCARDABLE) &&
   514                      !(aFlags & INIT_FLAG_DECODE_ON_DRAW)),
   515                     "Can't be discardable or decode-on-draw for multipart");
   517   // Store initialization data
   518   mSourceDataMimeType.Assign(aMimeType);
   519   mDiscardable = !!(aFlags & INIT_FLAG_DISCARDABLE);
   520   mDecodeOnDraw = !!(aFlags & INIT_FLAG_DECODE_ON_DRAW);
   521   mMultipart = !!(aFlags & INIT_FLAG_MULTIPART);
   523   // Statistics
   524   if (mDiscardable) {
   525     num_discardable_containers++;
   526     discardable_source_bytes += mSourceData.Length();
   527   }
   529   // Instantiate the decoder
   530   nsresult rv = InitDecoder(/* aDoSizeDecode = */ true);
   531   CONTAINER_ENSURE_SUCCESS(rv);
   533   // If we aren't storing source data, we want to switch from a size decode to
   534   // a full decode as soon as possible.
   535   if (!StoringSourceData()) {
   536     mWantFullDecode = true;
   537   }
   539   // Mark us as initialized
   540   mInitialized = true;
   542   return NS_OK;
   543 }
   545 //******************************************************************************
   546 // [notxpcom] void requestRefresh ([const] in TimeStamp aTime);
   547 NS_IMETHODIMP_(void)
   548 RasterImage::RequestRefresh(const mozilla::TimeStamp& aTime)
   549 {
   550   EvaluateAnimation();
   552   if (!mAnimating) {
   553     return;
   554   }
   556   FrameAnimator::RefreshResult res;
   557   if (mAnim) {
   558     res = mAnim->RequestRefresh(aTime);
   559   }
   561   if (res.frameAdvanced) {
   562     // Notify listeners that our frame has actually changed, but do this only
   563     // once for all frames that we've now passed (if AdvanceFrame() was called
   564     // more than once).
   565     #ifdef DEBUG
   566       mFramesNotified++;
   567     #endif
   569     UpdateImageContainer();
   571     // Explicitly call this on mStatusTracker so we're sure to not interfere
   572     // with the decoding process
   573     if (mStatusTracker)
   574       mStatusTracker->FrameChanged(&res.dirtyRect);
   575   }
   577   if (res.animationFinished) {
   578     mAnimationFinished = true;
   579     EvaluateAnimation();
   580   }
   581 }
   583 //******************************************************************************
   584 /* readonly attribute int32_t width; */
   585 NS_IMETHODIMP
   586 RasterImage::GetWidth(int32_t *aWidth)
   587 {
   588   NS_ENSURE_ARG_POINTER(aWidth);
   590   if (mError) {
   591     *aWidth = 0;
   592     return NS_ERROR_FAILURE;
   593   }
   595   *aWidth = mSize.width;
   596   return NS_OK;
   597 }
   599 //******************************************************************************
   600 /* readonly attribute int32_t height; */
   601 NS_IMETHODIMP
   602 RasterImage::GetHeight(int32_t *aHeight)
   603 {
   604   NS_ENSURE_ARG_POINTER(aHeight);
   606   if (mError) {
   607     *aHeight = 0;
   608     return NS_ERROR_FAILURE;
   609   }
   611   *aHeight = mSize.height;
   612   return NS_OK;
   613 }
   615 //******************************************************************************
   616 /* [noscript] readonly attribute nsSize intrinsicSize; */
   617 NS_IMETHODIMP
   618 RasterImage::GetIntrinsicSize(nsSize* aSize)
   619 {
   620   if (mError)
   621     return NS_ERROR_FAILURE;
   623   *aSize = nsSize(nsPresContext::CSSPixelsToAppUnits(mSize.width),
   624                   nsPresContext::CSSPixelsToAppUnits(mSize.height));
   625   return NS_OK;
   626 }
   628 //******************************************************************************
   629 /* [noscript] readonly attribute nsSize intrinsicRatio; */
   630 NS_IMETHODIMP
   631 RasterImage::GetIntrinsicRatio(nsSize* aRatio)
   632 {
   633   if (mError)
   634     return NS_ERROR_FAILURE;
   636   *aRatio = nsSize(mSize.width, mSize.height);
   637   return NS_OK;
   638 }
   640 NS_IMETHODIMP_(Orientation)
   641 RasterImage::GetOrientation()
   642 {
   643   return mOrientation;
   644 }
   646 //******************************************************************************
   647 /* unsigned short GetType(); */
   648 NS_IMETHODIMP
   649 RasterImage::GetType(uint16_t *aType)
   650 {
   651   NS_ENSURE_ARG_POINTER(aType);
   653   *aType = GetType();
   654   return NS_OK;
   655 }
   657 //******************************************************************************
   658 /* [noscript, notxpcom] uint16_t GetType(); */
   659 NS_IMETHODIMP_(uint16_t)
   660 RasterImage::GetType()
   661 {
   662   return imgIContainer::TYPE_RASTER;
   663 }
   665 imgFrame*
   666 RasterImage::GetImgFrameNoDecode(uint32_t framenum)
   667 {
   668   if (!mAnim) {
   669     NS_ASSERTION(framenum == 0, "Don't ask for a frame > 0 if we're not animated!");
   670     return mFrameBlender.GetFrame(0);
   671   }
   672   return mFrameBlender.GetFrame(framenum);
   673 }
   675 imgFrame*
   676 RasterImage::GetImgFrame(uint32_t framenum)
   677 {
   678   nsresult rv = WantDecodedFrames();
   679   CONTAINER_ENSURE_TRUE(NS_SUCCEEDED(rv), nullptr);
   680   return GetImgFrameNoDecode(framenum);
   681 }
   683 imgFrame*
   684 RasterImage::GetDrawableImgFrame(uint32_t framenum)
   685 {
   686   imgFrame* frame = nullptr;
   688   if (mMultipart && framenum == GetCurrentImgFrameIndex()) {
   689     // In the multipart case we prefer to use mMultipartDecodedFrame, which is
   690     // the most recent one we completely decoded, rather than display the real
   691     // current frame and risk severe tearing.
   692     frame = mMultipartDecodedFrame;
   693   }
   695   if (!frame) {
   696     frame = GetImgFrame(framenum);
   697   }
   699   // We will return a paletted frame if it's not marked as compositing failed
   700   // so we can catch crashes for reasons we haven't investigated.
   701   if (frame && frame->GetCompositingFailed())
   702     return nullptr;
   704   if (frame) {
   705     frame->ApplyDirtToSurfaces();
   706   }
   708   return frame;
   709 }
   711 uint32_t
   712 RasterImage::GetCurrentImgFrameIndex() const
   713 {
   714   if (mAnim)
   715     return mAnim->GetCurrentAnimationFrameIndex();
   717   return 0;
   718 }
   720 imgFrame*
   721 RasterImage::GetCurrentImgFrame()
   722 {
   723   return GetImgFrame(GetCurrentImgFrameIndex());
   724 }
   726 //******************************************************************************
   727 /* [notxpcom] boolean frameIsOpaque(in uint32_t aWhichFrame); */
   728 NS_IMETHODIMP_(bool)
   729 RasterImage::FrameIsOpaque(uint32_t aWhichFrame)
   730 {
   731   if (aWhichFrame > FRAME_MAX_VALUE) {
   732     NS_WARNING("aWhichFrame outside valid range!");
   733     return false;
   734   }
   736   if (mError)
   737     return false;
   739   // See if we can get an image frame.
   740   imgFrame* frame = aWhichFrame == FRAME_FIRST ? GetImgFrameNoDecode(0)
   741                                                : GetImgFrameNoDecode(GetCurrentImgFrameIndex());
   743   // If we don't get a frame, the safe answer is "not opaque".
   744   if (!frame)
   745     return false;
   747   // Other, the frame is transparent if either:
   748   //  1. It needs a background.
   749   //  2. Its size doesn't cover our entire area.
   750   nsIntRect framerect = frame->GetRect();
   751   return !frame->GetNeedsBackground() &&
   752          framerect.IsEqualInterior(nsIntRect(0, 0, mSize.width, mSize.height));
   753 }
   755 nsIntRect
   756 RasterImage::FrameRect(uint32_t aWhichFrame)
   757 {
   758   if (aWhichFrame > FRAME_MAX_VALUE) {
   759     NS_WARNING("aWhichFrame outside valid range!");
   760     return nsIntRect();
   761   }
   763   // Get the requested frame.
   764   imgFrame* frame = aWhichFrame == FRAME_FIRST ? GetImgFrameNoDecode(0)
   765                                                : GetImgFrameNoDecode(GetCurrentImgFrameIndex());
   767   // If we have the frame, use that rectangle.
   768   if (frame) {
   769     return frame->GetRect();
   770   }
   772   // If the frame doesn't exist, we return the empty rectangle. It's not clear
   773   // whether this is appropriate in general, but at the moment the only
   774   // consumer of this method is imgStatusTracker (when it wants to figure out
   775   // dirty rectangles to send out batched observer updates). This should
   776   // probably be revisited when we fix bug 503973.
   777   return nsIntRect();
   778 }
   780 uint32_t
   781 RasterImage::GetCurrentFrameIndex()
   782 {
   783   return GetCurrentImgFrameIndex();
   784 }
   786 uint32_t
   787 RasterImage::GetNumFrames() const
   788 {
   789   return mFrameBlender.GetNumFrames();
   790 }
   792 //******************************************************************************
   793 /* readonly attribute boolean animated; */
   794 NS_IMETHODIMP
   795 RasterImage::GetAnimated(bool *aAnimated)
   796 {
   797   if (mError)
   798     return NS_ERROR_FAILURE;
   800   NS_ENSURE_ARG_POINTER(aAnimated);
   802   // If we have mAnim, we can know for sure
   803   if (mAnim) {
   804     *aAnimated = true;
   805     return NS_OK;
   806   }
   808   // Otherwise, we need to have been decoded to know for sure, since if we were
   809   // decoded at least once mAnim would have been created for animated images
   810   if (!mHasBeenDecoded)
   811     return NS_ERROR_NOT_AVAILABLE;
   813   // We know for sure
   814   *aAnimated = false;
   816   return NS_OK;
   817 }
   819 //******************************************************************************
   820 /* [notxpcom] int32_t getFirstFrameDelay (); */
   821 NS_IMETHODIMP_(int32_t)
   822 RasterImage::GetFirstFrameDelay()
   823 {
   824   if (mError)
   825     return -1;
   827   bool animated = false;
   828   if (NS_FAILED(GetAnimated(&animated)) || !animated)
   829     return -1;
   831   return mFrameBlender.GetTimeoutForFrame(0);
   832 }
   834 nsresult
   835 RasterImage::CopyFrame(uint32_t aWhichFrame,
   836                        uint32_t aFlags,
   837                        gfxImageSurface **_retval)
   838 {
   839   if (aWhichFrame > FRAME_MAX_VALUE)
   840     return NS_ERROR_INVALID_ARG;
   842   if (mError)
   843     return NS_ERROR_FAILURE;
   845   // Disallowed in the API
   846   if (mInDecoder && (aFlags & imgIContainer::FLAG_SYNC_DECODE))
   847     return NS_ERROR_FAILURE;
   849   nsresult rv;
   851   if (!ApplyDecodeFlags(aFlags, aWhichFrame))
   852     return NS_ERROR_NOT_AVAILABLE;
   854   // If requested, synchronously flush any data we have lying around to the decoder
   855   if (aFlags & FLAG_SYNC_DECODE) {
   856     rv = SyncDecode();
   857     CONTAINER_ENSURE_SUCCESS(rv);
   858   }
   860   NS_ENSURE_ARG_POINTER(_retval);
   862   // Get the frame. If it's not there, it's probably the caller's fault for
   863   // not waiting for the data to be loaded from the network or not passing
   864   // FLAG_SYNC_DECODE
   865   uint32_t frameIndex = (aWhichFrame == FRAME_FIRST) ?
   866                         0 : GetCurrentImgFrameIndex();
   867   imgFrame *frame = GetDrawableImgFrame(frameIndex);
   868   if (!frame) {
   869     *_retval = nullptr;
   870     return NS_ERROR_FAILURE;
   871   }
   873   nsRefPtr<gfxPattern> pattern;
   874   frame->GetPattern(getter_AddRefs(pattern));
   875   nsIntRect intframerect = frame->GetRect();
   876   gfxRect framerect(intframerect.x, intframerect.y, intframerect.width, intframerect.height);
   878   // Create a 32-bit image surface of our size, but draw using the frame's
   879   // rect, implicitly padding the frame out to the image's size.
   880   nsRefPtr<gfxImageSurface> imgsurface = new gfxImageSurface(gfxIntSize(mSize.width, mSize.height),
   881                                                              gfxImageFormat::ARGB32);
   882   gfxContext ctx(imgsurface);
   883   ctx.SetOperator(gfxContext::OPERATOR_SOURCE);
   884   ctx.Rectangle(framerect);
   885   ctx.Translate(framerect.TopLeft());
   886   ctx.SetPattern(pattern);
   887   ctx.Fill();
   889   imgsurface.forget(_retval);
   890   return NS_OK;
   891 }
   893 //******************************************************************************
   894 /* [noscript] SourceSurface getFrame(in uint32_t aWhichFrame,
   895  *                                   in uint32_t aFlags); */
   896 NS_IMETHODIMP_(TemporaryRef<SourceSurface>)
   897 RasterImage::GetFrame(uint32_t aWhichFrame,
   898                       uint32_t aFlags)
   899 {
   900   MOZ_ASSERT(aWhichFrame <= FRAME_MAX_VALUE);
   902   if (aWhichFrame > FRAME_MAX_VALUE)
   903     return nullptr;
   905   if (mError)
   906     return nullptr;
   908   // Disallowed in the API
   909   if (mInDecoder && (aFlags & imgIContainer::FLAG_SYNC_DECODE))
   910     return nullptr;
   912   if (!ApplyDecodeFlags(aFlags, aWhichFrame))
   913     return nullptr;
   915   // If the caller requested a synchronous decode, do it
   916   if (aFlags & FLAG_SYNC_DECODE) {
   917     nsresult rv = SyncDecode();
   918     CONTAINER_ENSURE_TRUE(NS_SUCCEEDED(rv), nullptr);
   919   }
   921   // Get the frame. If it's not there, it's probably the caller's fault for
   922   // not waiting for the data to be loaded from the network or not passing
   923   // FLAG_SYNC_DECODE
   924   uint32_t frameIndex = (aWhichFrame == FRAME_FIRST) ?
   925                           0 : GetCurrentImgFrameIndex();
   926   imgFrame *frame = GetDrawableImgFrame(frameIndex);
   927   if (!frame) {
   928     return nullptr;
   929   }
   931   nsRefPtr<gfxASurface> framesurf;
   933   // If this frame covers the entire image, we can just reuse its existing
   934   // surface.
   935   nsIntRect framerect = frame->GetRect();
   936   if (framerect.x == 0 && framerect.y == 0 &&
   937       framerect.width == mSize.width &&
   938       framerect.height == mSize.height) {
   939     frame->GetSurface(getter_AddRefs(framesurf));
   940     if (!framesurf && !frame->IsSinglePixel()) {
   941       // No reason to be optimized away here - the OS threw out the data
   942       if (!(aFlags & FLAG_SYNC_DECODE))
   943         return nullptr;
   945       // Unconditionally call ForceDiscard() here because GetSurface can only
   946       // return null when we can forcibly discard and redecode. There are two
   947       // other cases where GetSurface() can return null - when it is a single
   948       // pixel image, which we check before getting here, or when this is an
   949       // indexed image, in which case we shouldn't be in this function at all.
   950       // The only remaining possibility is that SetDiscardable() was called on
   951       // this imgFrame, which implies the image can be redecoded.
   952       ForceDiscard();
   953       return GetFrame(aWhichFrame, aFlags);
   954     }
   955   }
   957   // The image doesn't have a surface because it's been optimized away. Create
   958   // one.
   959   if (!framesurf) {
   960     nsRefPtr<gfxImageSurface> imgsurf;
   961     CopyFrame(aWhichFrame, aFlags, getter_AddRefs(imgsurf));
   962     framesurf = imgsurf;
   963   }
   965   RefPtr<SourceSurface> result;
   967   // As far as Moz2D is concerned, SourceSurface contains premultiplied alpha.
   968   // If we're abusing it to contain non-premultiplied alpha then we want to
   969   // avoid having Moz2D do any conversions on it (like copy to another
   970   // surface). Hence why we try to wrap framesurf's data here for
   971   // FLAG_DECODE_NO_PREMULTIPLY_ALPHA.
   972   if ((aFlags & FLAG_WANT_DATA_SURFACE) != 0 ||
   973       (aFlags & FLAG_DECODE_NO_PREMULTIPLY_ALPHA) != 0) {
   974     result = gfxPlatform::GetPlatform()->GetWrappedDataSourceSurface(framesurf);
   975   }
   976   if (!result) {
   977     result = gfxPlatform::GetPlatform()->GetSourceSurfaceForSurface(nullptr,
   978                                                                     framesurf);
   979   }
   980   return result.forget();
   981 }
   983 already_AddRefed<layers::Image>
   984 RasterImage::GetCurrentImage()
   985 {
   986   if (!mDecoded) {
   987     // We can't call StartDecoding because that can synchronously notify
   988     // which can cause DOM modification
   989     RequestDecodeCore(ASYNCHRONOUS);
   990     return nullptr;
   991   }
   993   RefPtr<SourceSurface> surface = GetFrame(FRAME_CURRENT, FLAG_NONE);
   994   if (!surface) {
   995     // The OS threw out some or all of our buffer. Start decoding again.
   996     // GetFrame will only return null in the case that the image was
   997     // discarded. We already checked that the image is decoded, so other
   998     // error paths are not possible.
   999     ForceDiscard();
  1000     RequestDecodeCore(ASYNCHRONOUS);
  1001     return nullptr;
  1004   if (!mImageContainer) {
  1005     mImageContainer = LayerManager::CreateImageContainer();
  1008   CairoImage::Data cairoData;
  1009   GetWidth(&cairoData.mSize.width);
  1010   GetHeight(&cairoData.mSize.height);
  1011   cairoData.mSourceSurface = surface;
  1013   nsRefPtr<layers::Image> image = mImageContainer->CreateImage(ImageFormat::CAIRO_SURFACE);
  1014   NS_ASSERTION(image, "Failed to create Image");
  1016   static_cast<CairoImage*>(image.get())->SetData(cairoData);
  1018   return image.forget();
  1022 NS_IMETHODIMP
  1023 RasterImage::GetImageContainer(LayerManager* aManager, ImageContainer **_retval)
  1025   int32_t maxTextureSize = aManager->GetMaxTextureSize();
  1026   if (mSize.width > maxTextureSize || mSize.height > maxTextureSize) {
  1027     *_retval = nullptr;
  1028     return NS_OK;
  1031   if (IsUnlocked() && mStatusTracker) {
  1032     mStatusTracker->OnUnlockedDraw();
  1035   if (!mImageContainer) {
  1036     mImageContainer = mImageContainerCache;
  1039   if (mImageContainer) {
  1040     *_retval = mImageContainer;
  1041     NS_ADDREF(*_retval);
  1042     return NS_OK;
  1045   nsRefPtr<layers::Image> image = GetCurrentImage();
  1046   if (!image) {
  1047     return NS_ERROR_NOT_AVAILABLE;
  1049   mImageContainer->SetCurrentImageInTransaction(image);
  1051   *_retval = mImageContainer;
  1052   NS_ADDREF(*_retval);
  1053   // We only need to be careful about holding on to the image when it is
  1054   // discardable by the OS.
  1055   if (CanForciblyDiscardAndRedecode()) {
  1056     mImageContainerCache = mImageContainer->asWeakPtr();
  1057     mImageContainer = nullptr;
  1060   return NS_OK;
  1063 void
  1064 RasterImage::UpdateImageContainer()
  1066   if (!mImageContainer || IsInUpdateImageContainer()) {
  1067     return;
  1070   SetInUpdateImageContainer(true);
  1072   nsRefPtr<layers::Image> image = GetCurrentImage();
  1073   if (!image) {
  1074     return;
  1076   mImageContainer->SetCurrentImage(image);
  1077   SetInUpdateImageContainer(false);
  1080 size_t
  1081 RasterImage::HeapSizeOfSourceWithComputedFallback(MallocSizeOf aMallocSizeOf) const
  1083   // n == 0 is possible for two reasons.
  1084   // - This is a zero-length image.
  1085   // - We're on a platform where moz_malloc_size_of always returns 0.
  1086   // In either case the fallback works appropriately.
  1087   size_t n = mSourceData.SizeOfExcludingThis(aMallocSizeOf);
  1088   if (n == 0) {
  1089     n = mSourceData.Length();
  1091   return n;
  1094 size_t
  1095 RasterImage::SizeOfDecodedWithComputedFallbackIfHeap(gfxMemoryLocation aLocation,
  1096                                                      MallocSizeOf aMallocSizeOf) const
  1098   size_t n = mFrameBlender.SizeOfDecodedWithComputedFallbackIfHeap(aLocation, aMallocSizeOf);
  1100   if (mScaleResult.status == SCALE_DONE) {
  1101     n += mScaleResult.frame->SizeOfExcludingThisWithComputedFallbackIfHeap(aLocation, aMallocSizeOf);
  1104   return n;
  1107 size_t
  1108 RasterImage::HeapSizeOfDecodedWithComputedFallback(MallocSizeOf aMallocSizeOf) const
  1110   return SizeOfDecodedWithComputedFallbackIfHeap(gfxMemoryLocation::IN_PROCESS_HEAP,
  1111                                                  aMallocSizeOf);
  1114 size_t
  1115 RasterImage::NonHeapSizeOfDecoded() const
  1117   return SizeOfDecodedWithComputedFallbackIfHeap(gfxMemoryLocation::IN_PROCESS_NONHEAP,
  1118                                                  nullptr);
  1121 size_t
  1122 RasterImage::OutOfProcessSizeOfDecoded() const
  1124   return SizeOfDecodedWithComputedFallbackIfHeap(gfxMemoryLocation::OUT_OF_PROCESS,
  1125                                                  nullptr);
  1128 void
  1129 RasterImage::EnsureAnimExists()
  1131   if (!mAnim) {
  1133     // Create the animation context
  1134     mAnim = new FrameAnimator(mFrameBlender, mAnimationMode);
  1136     // We don't support discarding animated images (See bug 414259).
  1137     // Lock the image and throw away the key.
  1138     //
  1139     // Note that this is inefficient, since we could get rid of the source
  1140     // data too. However, doing this is actually hard, because we're probably
  1141     // calling ensureAnimExists mid-decode, and thus we're decoding out of
  1142     // the source buffer. Since we're going to fix this anyway later, and
  1143     // since we didn't kill the source data in the old world either, locking
  1144     // is acceptable for the moment.
  1145     LockImage();
  1147     // Notify our observers that we are starting animation.
  1148     nsRefPtr<imgStatusTracker> statusTracker = CurrentStatusTracker();
  1149     statusTracker->RecordImageIsAnimated();
  1153 nsresult
  1154 RasterImage::InternalAddFrameHelper(uint32_t framenum, imgFrame *aFrame,
  1155                                     uint8_t **imageData, uint32_t *imageLength,
  1156                                     uint32_t **paletteData, uint32_t *paletteLength,
  1157                                     imgFrame** aRetFrame)
  1159   NS_ABORT_IF_FALSE(framenum <= GetNumFrames(), "Invalid frame index!");
  1160   if (framenum > GetNumFrames())
  1161     return NS_ERROR_INVALID_ARG;
  1163   nsAutoPtr<imgFrame> frame(aFrame);
  1165   // We are in the middle of decoding. This will be unlocked when we finish
  1166   // decoding or switch to another frame.
  1167   frame->LockImageData();
  1169   if (paletteData && paletteLength)
  1170     frame->GetPaletteData(paletteData, paletteLength);
  1172   frame->GetImageData(imageData, imageLength);
  1174   *aRetFrame = frame;
  1176   mFrameBlender.InsertFrame(framenum, frame.forget());
  1178   return NS_OK;
  1181 nsresult
  1182 RasterImage::InternalAddFrame(uint32_t framenum,
  1183                               int32_t aX, int32_t aY,
  1184                               int32_t aWidth, int32_t aHeight,
  1185                               gfxImageFormat aFormat,
  1186                               uint8_t aPaletteDepth,
  1187                               uint8_t **imageData,
  1188                               uint32_t *imageLength,
  1189                               uint32_t **paletteData,
  1190                               uint32_t *paletteLength,
  1191                               imgFrame** aRetFrame)
  1193   // We assume that we're in the middle of decoding because we unlock the
  1194   // previous frame when we create a new frame, and only when decoding do we
  1195   // lock frames.
  1196   NS_ABORT_IF_FALSE(mDecoder, "Only decoders may add frames!");
  1198   NS_ABORT_IF_FALSE(framenum <= GetNumFrames(), "Invalid frame index!");
  1199   if (framenum > GetNumFrames())
  1200     return NS_ERROR_INVALID_ARG;
  1202   nsAutoPtr<imgFrame> frame(new imgFrame());
  1204   nsresult rv = frame->Init(aX, aY, aWidth, aHeight, aFormat, aPaletteDepth);
  1205   if (!(mSize.width > 0 && mSize.height > 0))
  1206     NS_WARNING("Shouldn't call InternalAddFrame with zero size");
  1207   if (!NS_SUCCEEDED(rv))
  1208     NS_WARNING("imgFrame::Init should succeed");
  1209   NS_ENSURE_SUCCESS(rv, rv);
  1211   // We know we are in a decoder. Therefore, we must unlock the previous frame
  1212   // when we move on to decoding into the next frame.
  1213   if (GetNumFrames() > 0) {
  1214     imgFrame *prevframe = mFrameBlender.RawGetFrame(GetNumFrames() - 1);
  1215     prevframe->UnlockImageData();
  1218   if (GetNumFrames() == 0) {
  1219     return InternalAddFrameHelper(framenum, frame.forget(), imageData, imageLength,
  1220                                   paletteData, paletteLength, aRetFrame);
  1223   if (GetNumFrames() == 1) {
  1224     // Since we're about to add our second frame, initialize animation stuff
  1225     EnsureAnimExists();
  1227     // If we dispose of the first frame by clearing it, then the
  1228     // First Frame's refresh area is all of itself.
  1229     // RESTORE_PREVIOUS is invalid (assumed to be DISPOSE_CLEAR)
  1230     int32_t frameDisposalMethod = mFrameBlender.RawGetFrame(0)->GetFrameDisposalMethod();
  1231     if (frameDisposalMethod == FrameBlender::kDisposeClear ||
  1232         frameDisposalMethod == FrameBlender::kDisposeRestorePrevious)
  1233       mAnim->SetFirstFrameRefreshArea(mFrameBlender.RawGetFrame(0)->GetRect());
  1236   // Calculate firstFrameRefreshArea
  1237   // Some gifs are huge but only have a small area that they animate
  1238   // We only need to refresh that small area when Frame 0 comes around again
  1239   mAnim->UnionFirstFrameRefreshArea(frame->GetRect());
  1241   rv = InternalAddFrameHelper(framenum, frame.forget(), imageData, imageLength,
  1242                               paletteData, paletteLength, aRetFrame);
  1244   return rv;
  1247 bool
  1248 RasterImage::ApplyDecodeFlags(uint32_t aNewFlags, uint32_t aWhichFrame)
  1250   if (mFrameDecodeFlags == (aNewFlags & DECODE_FLAGS_MASK))
  1251     return true; // Not asking very much of us here.
  1253   if (mDecoded) {
  1254     // If the requested frame is opaque and the current and new decode flags
  1255     // only differ in the premultiply alpha bit then we can use the existing
  1256     // frame, we don't need to discard and re-decode.
  1257     uint32_t currentNonAlphaFlags =
  1258       (mFrameDecodeFlags & DECODE_FLAGS_MASK) & ~FLAG_DECODE_NO_PREMULTIPLY_ALPHA;
  1259     uint32_t newNonAlphaFlags =
  1260       (aNewFlags & DECODE_FLAGS_MASK) & ~FLAG_DECODE_NO_PREMULTIPLY_ALPHA;
  1261     if (currentNonAlphaFlags == newNonAlphaFlags && FrameIsOpaque(aWhichFrame)) {
  1262       return true;
  1265     // if we can't discard, then we're screwed; we have no way
  1266     // to re-decode.  Similarly if we aren't allowed to do a sync
  1267     // decode.
  1268     if (!(aNewFlags & FLAG_SYNC_DECODE))
  1269       return false;
  1270     if (!CanForciblyDiscardAndRedecode())
  1271       return false;
  1272     ForceDiscard();
  1275   mFrameDecodeFlags = aNewFlags & DECODE_FLAGS_MASK;
  1276   return true;
  1279 nsresult
  1280 RasterImage::SetSize(int32_t aWidth, int32_t aHeight, Orientation aOrientation)
  1282   MOZ_ASSERT(NS_IsMainThread());
  1283   mDecodingMonitor.AssertCurrentThreadIn();
  1285   if (mError)
  1286     return NS_ERROR_FAILURE;
  1288   // Ensure that we have positive values
  1289   // XXX - Why isn't the size unsigned? Should this be changed?
  1290   if ((aWidth < 0) || (aHeight < 0))
  1291     return NS_ERROR_INVALID_ARG;
  1293   // if we already have a size, check the new size against the old one
  1294   if (!mMultipart && mHasSize &&
  1295       ((aWidth != mSize.width) ||
  1296        (aHeight != mSize.height) ||
  1297        (aOrientation != mOrientation))) {
  1298     NS_WARNING("Image changed size on redecode! This should not happen!");
  1300     // Make the decoder aware of the error so that it doesn't try to call
  1301     // FinishInternal during ShutdownDecoder.
  1302     if (mDecoder)
  1303       mDecoder->PostResizeError();
  1305     DoError();
  1306     return NS_ERROR_UNEXPECTED;
  1309   // Set the size and flag that we have it
  1310   mSize.SizeTo(aWidth, aHeight);
  1311   mOrientation = aOrientation;
  1312   mHasSize = true;
  1314   mFrameBlender.SetSize(mSize);
  1316   return NS_OK;
  1319 nsresult
  1320 RasterImage::EnsureFrame(uint32_t aFrameNum, int32_t aX, int32_t aY,
  1321                          int32_t aWidth, int32_t aHeight,
  1322                          gfxImageFormat aFormat,
  1323                          uint8_t aPaletteDepth,
  1324                          uint8_t **imageData, uint32_t *imageLength,
  1325                          uint32_t **paletteData, uint32_t *paletteLength,
  1326                          imgFrame** aRetFrame)
  1328   if (mError)
  1329     return NS_ERROR_FAILURE;
  1331   NS_ENSURE_ARG_POINTER(imageData);
  1332   NS_ENSURE_ARG_POINTER(imageLength);
  1333   NS_ENSURE_ARG_POINTER(aRetFrame);
  1334   NS_ABORT_IF_FALSE(aFrameNum <= GetNumFrames(), "Invalid frame index!");
  1336   if (aPaletteDepth > 0) {
  1337     NS_ENSURE_ARG_POINTER(paletteData);
  1338     NS_ENSURE_ARG_POINTER(paletteLength);
  1341   if (aFrameNum > GetNumFrames())
  1342     return NS_ERROR_INVALID_ARG;
  1344   // Adding a frame that doesn't already exist.
  1345   if (aFrameNum == GetNumFrames()) {
  1346     return InternalAddFrame(aFrameNum, aX, aY, aWidth, aHeight, aFormat,
  1347                             aPaletteDepth, imageData, imageLength,
  1348                             paletteData, paletteLength, aRetFrame);
  1351   imgFrame *frame = mFrameBlender.RawGetFrame(aFrameNum);
  1352   if (!frame) {
  1353     return InternalAddFrame(aFrameNum, aX, aY, aWidth, aHeight, aFormat,
  1354                             aPaletteDepth, imageData, imageLength,
  1355                             paletteData, paletteLength, aRetFrame);
  1358   // See if we can re-use the frame that already exists.
  1359   nsIntRect rect = frame->GetRect();
  1360   if (rect.x == aX && rect.y == aY && rect.width == aWidth &&
  1361       rect.height == aHeight && frame->GetFormat() == aFormat &&
  1362       frame->GetPaletteDepth() == aPaletteDepth) {
  1363     frame->GetImageData(imageData, imageLength);
  1364     if (paletteData) {
  1365       frame->GetPaletteData(paletteData, paletteLength);
  1368     *aRetFrame = frame;
  1370     // We can re-use the frame if it has image data.
  1371     if (*imageData && paletteData && *paletteData) {
  1372       return NS_OK;
  1374     if (*imageData && !paletteData) {
  1375       return NS_OK;
  1379   // Not reusable, so replace the frame directly.
  1381   // We know this frame is already locked, because it's the one we're currently
  1382   // writing to.
  1383   frame->UnlockImageData();
  1385   mFrameBlender.RemoveFrame(aFrameNum);
  1386   nsAutoPtr<imgFrame> newFrame(new imgFrame());
  1387   nsresult rv = newFrame->Init(aX, aY, aWidth, aHeight, aFormat, aPaletteDepth);
  1388   NS_ENSURE_SUCCESS(rv, rv);
  1389   return InternalAddFrameHelper(aFrameNum, newFrame.forget(), imageData,
  1390                                 imageLength, paletteData, paletteLength,
  1391                                 aRetFrame);
  1394 nsresult
  1395 RasterImage::EnsureFrame(uint32_t aFramenum, int32_t aX, int32_t aY,
  1396                          int32_t aWidth, int32_t aHeight,
  1397                          gfxImageFormat aFormat,
  1398                          uint8_t** imageData, uint32_t* imageLength,
  1399                          imgFrame** aFrame)
  1401   return EnsureFrame(aFramenum, aX, aY, aWidth, aHeight, aFormat,
  1402                      /* aPaletteDepth = */ 0, imageData, imageLength,
  1403                      /* aPaletteData = */ nullptr,
  1404                      /* aPaletteLength = */ nullptr,
  1405                      aFrame);
  1408 nsresult
  1409 RasterImage::SetFrameAsNonPremult(uint32_t aFrameNum, bool aIsNonPremult)
  1411   if (mError)
  1412     return NS_ERROR_FAILURE;
  1414   NS_ABORT_IF_FALSE(aFrameNum < GetNumFrames(), "Invalid frame index!");
  1415   if (aFrameNum >= GetNumFrames())
  1416     return NS_ERROR_INVALID_ARG;
  1418   imgFrame* frame = mFrameBlender.RawGetFrame(aFrameNum);
  1419   NS_ABORT_IF_FALSE(frame, "Calling SetFrameAsNonPremult on frame that doesn't exist!");
  1420   NS_ENSURE_TRUE(frame, NS_ERROR_FAILURE);
  1422   frame->SetAsNonPremult(aIsNonPremult);
  1424   return NS_OK;
  1427 nsresult
  1428 RasterImage::DecodingComplete()
  1430   MOZ_ASSERT(NS_IsMainThread());
  1432   if (mError)
  1433     return NS_ERROR_FAILURE;
  1435   // Flag that we're done decoding.
  1436   // XXX - these should probably be combined when we fix animated image
  1437   // discarding with bug 500402.
  1438   mDecoded = true;
  1439   mHasBeenDecoded = true;
  1441   nsresult rv;
  1443   // We now have one of the qualifications for discarding. Re-evaluate.
  1444   if (CanDiscard()) {
  1445     NS_ABORT_IF_FALSE(!DiscardingActive(),
  1446                       "We shouldn't have been discardable before this");
  1447     rv = DiscardTracker::Reset(&mDiscardTrackerNode);
  1448     CONTAINER_ENSURE_SUCCESS(rv);
  1451   // If there's only 1 frame, optimize it. Optimizing animated images
  1452   // is not supported.
  1453   //
  1454   // We don't optimize the frame for multipart images because we reuse
  1455   // the frame.
  1456   if ((GetNumFrames() == 1) && !mMultipart) {
  1457     // CanForciblyDiscard is used instead of CanForciblyDiscardAndRedecode
  1458     // because we know decoding is complete at this point and this is not
  1459     // an animation
  1460     if (DiscardingEnabled() && CanForciblyDiscard()) {
  1461       mFrameBlender.RawGetFrame(0)->SetDiscardable();
  1463     rv = mFrameBlender.RawGetFrame(0)->Optimize();
  1464     NS_ENSURE_SUCCESS(rv, rv);
  1467   // Double-buffer our frame in the multipart case, since we'll start decoding
  1468   // into the first frame again immediately and this produces severe tearing.
  1469   if (mMultipart) {
  1470     if (GetNumFrames() == 1) {
  1471       mMultipartDecodedFrame = mFrameBlender.SwapFrame(GetCurrentFrameIndex(),
  1472                                                        mMultipartDecodedFrame);
  1473     } else {
  1474       // Don't double buffer for animated multipart images. It entails more
  1475       // complexity and it's not really needed since we already are smart about
  1476       // not displaying the still-decoding frame of an animated image. We may
  1477       // have already stored an extra frame, though, so we'll release it here.
  1478       delete mMultipartDecodedFrame;
  1479       mMultipartDecodedFrame = nullptr;
  1483   if (mAnim) {
  1484     mAnim->SetDoneDecoding(true);
  1487   return NS_OK;
  1490 NS_IMETHODIMP
  1491 RasterImage::SetAnimationMode(uint16_t aAnimationMode)
  1493   if (mAnim) {
  1494     mAnim->SetAnimationMode(aAnimationMode);
  1496   return SetAnimationModeInternal(aAnimationMode);
  1499 //******************************************************************************
  1500 /* void StartAnimation () */
  1501 nsresult
  1502 RasterImage::StartAnimation()
  1504   if (mError)
  1505     return NS_ERROR_FAILURE;
  1507   NS_ABORT_IF_FALSE(ShouldAnimate(), "Should not animate!");
  1509   EnsureAnimExists();
  1511   imgFrame* currentFrame = GetCurrentImgFrame();
  1512   // A timeout of -1 means we should display this frame forever.
  1513   if (currentFrame && mFrameBlender.GetTimeoutForFrame(GetCurrentImgFrameIndex()) < 0) {
  1514     mAnimationFinished = true;
  1515     return NS_ERROR_ABORT;
  1518   if (mAnim) {
  1519     // We need to set the time that this initial frame was first displayed, as
  1520     // this is used in AdvanceFrame().
  1521     mAnim->InitAnimationFrameTimeIfNecessary();
  1524   return NS_OK;
  1527 //******************************************************************************
  1528 /* void stopAnimation (); */
  1529 nsresult
  1530 RasterImage::StopAnimation()
  1532   NS_ABORT_IF_FALSE(mAnimating, "Should be animating!");
  1534   nsresult rv = NS_OK;
  1535   if (mError) {
  1536     rv = NS_ERROR_FAILURE;
  1537   } else {
  1538     mAnim->SetAnimationFrameTime(TimeStamp());
  1541   mAnimating = false;
  1542   return rv;
  1545 //******************************************************************************
  1546 /* void resetAnimation (); */
  1547 NS_IMETHODIMP
  1548 RasterImage::ResetAnimation()
  1550   if (mError)
  1551     return NS_ERROR_FAILURE;
  1553   if (mAnimationMode == kDontAnimMode ||
  1554       !mAnim || mAnim->GetCurrentAnimationFrameIndex() == 0)
  1555     return NS_OK;
  1557   mAnimationFinished = false;
  1559   if (mAnimating)
  1560     StopAnimation();
  1562   mFrameBlender.ResetAnimation();
  1563   mAnim->ResetAnimation();
  1565   UpdateImageContainer();
  1567   // Note - We probably want to kick off a redecode somewhere around here when
  1568   // we fix bug 500402.
  1570   // Update display
  1571   if (mStatusTracker) {
  1572     nsIntRect rect = mAnim->GetFirstFrameRefreshArea();
  1573     mStatusTracker->FrameChanged(&rect);
  1576   // Start the animation again. It may not have been running before, if
  1577   // mAnimationFinished was true before entering this function.
  1578   EvaluateAnimation();
  1580   return NS_OK;
  1583 //******************************************************************************
  1584 // [notxpcom] void setAnimationStartTime ([const] in TimeStamp aTime);
  1585 NS_IMETHODIMP_(void)
  1586 RasterImage::SetAnimationStartTime(const mozilla::TimeStamp& aTime)
  1588   if (mError || mAnimationMode == kDontAnimMode || mAnimating || !mAnim)
  1589     return;
  1591   mAnim->SetAnimationFrameTime(aTime);
  1594 NS_IMETHODIMP_(float)
  1595 RasterImage::GetFrameIndex(uint32_t aWhichFrame)
  1597   MOZ_ASSERT(aWhichFrame <= FRAME_MAX_VALUE, "Invalid argument");
  1598   return (aWhichFrame == FRAME_FIRST || !mAnim)
  1599          ? 0.0f
  1600          : mAnim->GetCurrentAnimationFrameIndex();
  1603 void
  1604 RasterImage::SetLoopCount(int32_t aLoopCount)
  1606   if (mError)
  1607     return;
  1609   if (mAnim) {
  1610     // No need to set this if we're not an animation
  1611     mFrameBlender.SetLoopCount(aLoopCount);
  1615 nsresult
  1616 RasterImage::AddSourceData(const char *aBuffer, uint32_t aCount)
  1618   ReentrantMonitorAutoEnter lock(mDecodingMonitor);
  1620   if (mError)
  1621     return NS_ERROR_FAILURE;
  1623   NS_ENSURE_ARG_POINTER(aBuffer);
  1624   nsresult rv = NS_OK;
  1626   // We should not call this if we're not initialized
  1627   NS_ABORT_IF_FALSE(mInitialized, "Calling AddSourceData() on uninitialized "
  1628                                   "RasterImage!");
  1630   // We should not call this if we're already finished adding source data
  1631   NS_ABORT_IF_FALSE(!mHasSourceData, "Calling AddSourceData() after calling "
  1632                                      "sourceDataComplete()!");
  1634   // This call should come straight from necko - no reentrancy allowed
  1635   NS_ABORT_IF_FALSE(!mInDecoder, "Re-entrant call to AddSourceData!");
  1637   // Image is already decoded, we shouldn't be getting data, but it could
  1638   // be extra garbage data at the end of a file.
  1639   if (mDecoded) {
  1640     return NS_OK;
  1643   // Starting a new part's frames, let's clean up before we add any
  1644   // This needs to happen just before we start getting EnsureFrame() call(s),
  1645   // so that there's no gap for anything to miss us.
  1646   if (mMultipart && mBytesDecoded == 0) {
  1647     // Our previous state may have been animated, so let's clean up
  1648     if (mAnimating)
  1649       StopAnimation();
  1650     mAnimationFinished = false;
  1651     if (mAnim) {
  1652       delete mAnim;
  1653       mAnim = nullptr;
  1655     // If there's only one frame, this could cause flickering
  1656     int old_frame_count = GetNumFrames();
  1657     if (old_frame_count > 1) {
  1658       mFrameBlender.ClearFrames();
  1662   // If we're not storing source data and we've previously gotten the size,
  1663   // write the data directly to the decoder. (If we haven't gotten the size,
  1664   // we'll queue up the data and write it out when we do.)
  1665   if (!StoringSourceData() && mHasSize) {
  1666     rv = WriteToDecoder(aBuffer, aCount, DECODE_SYNC);
  1667     CONTAINER_ENSURE_SUCCESS(rv);
  1669     // We're not storing source data, so this data is probably coming straight
  1670     // from the network. In this case, we want to display data as soon as we
  1671     // get it, so we want to flush invalidations after every write.
  1672     nsRefPtr<Decoder> kungFuDeathGrip = mDecoder;
  1673     mInDecoder = true;
  1674     mDecoder->FlushInvalidations();
  1675     mInDecoder = false;
  1677     rv = FinishedSomeDecoding();
  1678     CONTAINER_ENSURE_SUCCESS(rv);
  1681   // Otherwise, we're storing data in the source buffer
  1682   else {
  1684     // Store the data
  1685     char *newElem = mSourceData.AppendElements(aBuffer, aCount);
  1686     if (!newElem)
  1687       return NS_ERROR_OUT_OF_MEMORY;
  1689     if (mDecoder) {
  1690       DecodePool::Singleton()->RequestDecode(this);
  1694   // Statistics
  1695   total_source_bytes += aCount;
  1696   if (mDiscardable)
  1697     discardable_source_bytes += aCount;
  1698   PR_LOG (GetCompressedImageAccountingLog(), PR_LOG_DEBUG,
  1699           ("CompressedImageAccounting: Added compressed data to RasterImage %p (%s). "
  1700            "Total Containers: %d, Discardable containers: %d, "
  1701            "Total source bytes: %lld, Source bytes for discardable containers %lld",
  1702            this,
  1703            mSourceDataMimeType.get(),
  1704            num_containers,
  1705            num_discardable_containers,
  1706            total_source_bytes,
  1707            discardable_source_bytes));
  1709   return NS_OK;
  1712 /* Note!  buf must be declared as char buf[9]; */
  1713 // just used for logging and hashing the header
  1714 static void
  1715 get_header_str (char *buf, char *data, size_t data_len)
  1717   int i;
  1718   int n;
  1719   static char hex[] = "0123456789abcdef";
  1721   n = data_len < 4 ? data_len : 4;
  1723   for (i = 0; i < n; i++) {
  1724     buf[i * 2]     = hex[(data[i] >> 4) & 0x0f];
  1725     buf[i * 2 + 1] = hex[data[i] & 0x0f];
  1728   buf[i * 2] = 0;
  1731 nsresult
  1732 RasterImage::DoImageDataComplete()
  1734   MOZ_ASSERT(NS_IsMainThread());
  1736   if (mError)
  1737     return NS_ERROR_FAILURE;
  1739   // If we've been called before, ignore. Otherwise, flag that we have everything
  1740   if (mHasSourceData)
  1741     return NS_OK;
  1742   mHasSourceData = true;
  1744   // If there's a decoder open, synchronously decode the beginning of the image
  1745   // to check for errors and get the image's size.  (If we already have the
  1746   // image's size, this does nothing.)  Then kick off an async decode of the
  1747   // rest of the image.
  1748   if (mDecoder) {
  1749     nsresult rv = DecodePool::Singleton()->DecodeUntilSizeAvailable(this);
  1750     CONTAINER_ENSURE_SUCCESS(rv);
  1754     ReentrantMonitorAutoEnter lock(mDecodingMonitor);
  1756     // If we're not storing any source data, then there's nothing more we can do
  1757     // once we've tried decoding for size.
  1758     if (!StoringSourceData() && mDecoder) {
  1759       nsresult rv = ShutdownDecoder(eShutdownIntent_Done);
  1760       CONTAINER_ENSURE_SUCCESS(rv);
  1763     // If DecodeUntilSizeAvailable didn't finish the decode, let the decode worker
  1764     // finish decoding this image.
  1765     if (mDecoder) {
  1766       DecodePool::Singleton()->RequestDecode(this);
  1769     // Free up any extra space in the backing buffer
  1770     mSourceData.Compact();
  1773   // Log header information
  1774   if (PR_LOG_TEST(GetCompressedImageAccountingLog(), PR_LOG_DEBUG)) {
  1775     char buf[9];
  1776     get_header_str(buf, mSourceData.Elements(), mSourceData.Length());
  1777     PR_LOG (GetCompressedImageAccountingLog(), PR_LOG_DEBUG,
  1778             ("CompressedImageAccounting: RasterImage::SourceDataComplete() - data "
  1779              "is done for container %p (%s) - header %p is 0x%s (length %d)",
  1780              this,
  1781              mSourceDataMimeType.get(),
  1782              mSourceData.Elements(),
  1783              buf,
  1784              mSourceData.Length()));
  1787   // We now have one of the qualifications for discarding. Re-evaluate.
  1788   if (CanDiscard()) {
  1789     nsresult rv = DiscardTracker::Reset(&mDiscardTrackerNode);
  1790     CONTAINER_ENSURE_SUCCESS(rv);
  1792   return NS_OK;
  1795 nsresult
  1796 RasterImage::OnImageDataComplete(nsIRequest*, nsISupports*, nsresult aStatus, bool aLastPart)
  1798   nsresult finalStatus = DoImageDataComplete();
  1800   // Give precedence to Necko failure codes.
  1801   if (NS_FAILED(aStatus))
  1802     finalStatus = aStatus;
  1804   // We just recorded OnStopRequest; we need to inform our listeners.
  1806     ReentrantMonitorAutoEnter lock(mDecodingMonitor);
  1808     nsRefPtr<imgStatusTracker> statusTracker = CurrentStatusTracker();
  1809     statusTracker->GetDecoderObserver()->OnStopRequest(aLastPart, finalStatus);
  1811     FinishedSomeDecoding();
  1814   return finalStatus;
  1817 nsresult
  1818 RasterImage::OnImageDataAvailable(nsIRequest*,
  1819                                   nsISupports*,
  1820                                   nsIInputStream* aInStr,
  1821                                   uint64_t,
  1822                                   uint32_t aCount)
  1824   nsresult rv;
  1826   // WriteToRasterImage always consumes everything it gets
  1827   // if it doesn't run out of memory
  1828   uint32_t bytesRead;
  1829   rv = aInStr->ReadSegments(WriteToRasterImage, this, aCount, &bytesRead);
  1831   NS_ABORT_IF_FALSE(bytesRead == aCount || HasError(),
  1832     "WriteToRasterImage should consume everything or the image must be in error!");
  1834   return rv;
  1837 nsresult
  1838 RasterImage::OnNewSourceData()
  1840   MOZ_ASSERT(NS_IsMainThread());
  1842   nsresult rv;
  1844   if (mError)
  1845     return NS_ERROR_FAILURE;
  1847   // The source data should be complete before calling this
  1848   NS_ABORT_IF_FALSE(mHasSourceData,
  1849                     "Calling NewSourceData before SourceDataComplete!");
  1850   if (!mHasSourceData)
  1851     return NS_ERROR_ILLEGAL_VALUE;
  1853   // Only supported for multipart channels. It wouldn't be too hard to change this,
  1854   // but it would involve making sure that things worked for decode-on-draw and
  1855   // discarding. Presently there's no need for this, so we don't.
  1856   NS_ABORT_IF_FALSE(mMultipart, "NewSourceData only supported for multipart");
  1857   if (!mMultipart)
  1858     return NS_ERROR_ILLEGAL_VALUE;
  1860   // We're multipart, so we shouldn't be storing source data
  1861   NS_ABORT_IF_FALSE(!StoringSourceData(),
  1862                     "Shouldn't be storing source data for multipart");
  1864   // We're not storing the source data and we got SourceDataComplete. We should
  1865   // have shut down the previous decoder
  1866   NS_ABORT_IF_FALSE(!mDecoder, "Shouldn't have a decoder in NewSourceData");
  1868   // The decoder was shut down and we didn't flag an error, so we should be decoded
  1869   NS_ABORT_IF_FALSE(mDecoded, "Should be decoded in NewSourceData");
  1871   // Reset some flags
  1872   mDecoded = false;
  1873   mHasSourceData = false;
  1874   mHasSize = false;
  1875   mWantFullDecode = true;
  1876   mDecodeRequest = nullptr;
  1878   if (mAnim) {
  1879     mAnim->SetDoneDecoding(false);
  1882   // We always need the size first.
  1883   rv = InitDecoder(/* aDoSizeDecode = */ true);
  1884   CONTAINER_ENSURE_SUCCESS(rv);
  1886   return NS_OK;
  1889 nsresult
  1890 RasterImage::SetSourceSizeHint(uint32_t sizeHint)
  1892   if (sizeHint && StoringSourceData())
  1893     return mSourceData.SetCapacity(sizeHint) ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
  1894   return NS_OK;
  1897 /********* Methods to implement lazy allocation of nsIProperties object *************/
  1898 NS_IMETHODIMP
  1899 RasterImage::Get(const char *prop, const nsIID & iid, void * *result)
  1901   if (!mProperties)
  1902     return NS_ERROR_FAILURE;
  1903   return mProperties->Get(prop, iid, result);
  1906 NS_IMETHODIMP
  1907 RasterImage::Set(const char *prop, nsISupports *value)
  1909   if (!mProperties)
  1910     mProperties = do_CreateInstance("@mozilla.org/properties;1");
  1911   if (!mProperties)
  1912     return NS_ERROR_OUT_OF_MEMORY;
  1913   return mProperties->Set(prop, value);
  1916 NS_IMETHODIMP
  1917 RasterImage::Has(const char *prop, bool *_retval)
  1919   NS_ENSURE_ARG_POINTER(_retval);
  1920   if (!mProperties) {
  1921     *_retval = false;
  1922     return NS_OK;
  1924   return mProperties->Has(prop, _retval);
  1927 NS_IMETHODIMP
  1928 RasterImage::Undefine(const char *prop)
  1930   if (!mProperties)
  1931     return NS_ERROR_FAILURE;
  1932   return mProperties->Undefine(prop);
  1935 NS_IMETHODIMP
  1936 RasterImage::GetKeys(uint32_t *count, char ***keys)
  1938   if (!mProperties) {
  1939     *count = 0;
  1940     *keys = nullptr;
  1941     return NS_OK;
  1943   return mProperties->GetKeys(count, keys);
  1946 void
  1947 RasterImage::Discard(bool force)
  1949   MOZ_ASSERT(NS_IsMainThread());
  1951   // We should be ok for discard
  1952   NS_ABORT_IF_FALSE(force ? CanForciblyDiscard() : CanDiscard(), "Asked to discard but can't!");
  1954   // We should never discard when we have an active decoder
  1955   NS_ABORT_IF_FALSE(!mDecoder, "Asked to discard with open decoder!");
  1957   // As soon as an image becomes animated, it becomes non-discardable and any
  1958   // timers are cancelled.
  1959   NS_ABORT_IF_FALSE(!mAnim, "Asked to discard for animated image!");
  1961   // For post-operation logging
  1962   int old_frame_count = GetNumFrames();
  1964   // Delete all the decoded frames
  1965   mFrameBlender.Discard();
  1967   // Clear our downscaled frame.
  1968   mScaleResult.status = SCALE_INVALID;
  1969   mScaleResult.frame = nullptr;
  1971   // Clear the last decoded multipart frame.
  1972   delete mMultipartDecodedFrame;
  1973   mMultipartDecodedFrame = nullptr;
  1975   // Flag that we no longer have decoded frames for this image
  1976   mDecoded = false;
  1978   // Notify that we discarded
  1979   if (mStatusTracker)
  1980     mStatusTracker->OnDiscard();
  1982   mDecodeRequest = nullptr;
  1984   if (force)
  1985     DiscardTracker::Remove(&mDiscardTrackerNode);
  1987   // Log
  1988   PR_LOG(GetCompressedImageAccountingLog(), PR_LOG_DEBUG,
  1989          ("CompressedImageAccounting: discarded uncompressed image "
  1990           "data from RasterImage %p (%s) - %d frames (cached count: %d); "
  1991           "Total Containers: %d, Discardable containers: %d, "
  1992           "Total source bytes: %lld, Source bytes for discardable containers %lld",
  1993           this,
  1994           mSourceDataMimeType.get(),
  1995           old_frame_count,
  1996           GetNumFrames(),
  1997           num_containers,
  1998           num_discardable_containers,
  1999           total_source_bytes,
  2000           discardable_source_bytes));
  2003 // Helper method to determine if we can discard an image
  2004 bool
  2005 RasterImage::CanDiscard() {
  2006   return (DiscardingEnabled() && // Globally enabled...
  2007           mDiscardable &&        // ...Enabled at creation time...
  2008           (mLockCount == 0) &&   // ...not temporarily disabled...
  2009           mHasSourceData &&      // ...have the source data...
  2010           mDecoded);             // ...and have something to discard.
  2013 bool
  2014 RasterImage::CanForciblyDiscard() {
  2015   return mDiscardable &&         // ...Enabled at creation time...
  2016          mHasSourceData;         // ...have the source data...
  2019 bool
  2020 RasterImage::CanForciblyDiscardAndRedecode() {
  2021   return mDiscardable &&         // ...Enabled at creation time...
  2022          mHasSourceData &&       // ...have the source data...
  2023          !mDecoder &&            // Can't discard with an open decoder
  2024          !mAnim;                 // Can never discard animated images
  2027 // Helper method to tell us whether the clock is currently running for
  2028 // discarding this image. Mainly for assertions.
  2029 bool
  2030 RasterImage::DiscardingActive() {
  2031   return mDiscardTrackerNode.isInList();
  2034 // Helper method to determine if we're storing the source data in a buffer
  2035 // or just writing it directly to the decoder
  2036 bool
  2037 RasterImage::StoringSourceData() const {
  2038   return (mDecodeOnDraw || mDiscardable);
  2042 // Sets up a decoder for this image. It is an error to call this function
  2043 // when decoding is already in process (ie - when mDecoder is non-null).
  2044 nsresult
  2045 RasterImage::InitDecoder(bool aDoSizeDecode)
  2047   // Ensure that the decoder is not already initialized
  2048   NS_ABORT_IF_FALSE(!mDecoder, "Calling InitDecoder() while already decoding!");
  2050   // We shouldn't be firing up a decoder if we already have the frames decoded
  2051   NS_ABORT_IF_FALSE(!mDecoded, "Calling InitDecoder() but already decoded!");
  2053   // Since we're not decoded, we should not have a discard timer active
  2054   NS_ABORT_IF_FALSE(!DiscardingActive(), "Discard Timer active in InitDecoder()!");
  2056   // Make sure we actually get size before doing a full decode.
  2057   if (!aDoSizeDecode) {
  2058     NS_ABORT_IF_FALSE(mHasSize, "Must do a size decode before a full decode!");
  2061   // Figure out which decoder we want
  2062   eDecoderType type = GetDecoderType(mSourceDataMimeType.get());
  2063   CONTAINER_ENSURE_TRUE(type != eDecoderType_unknown, NS_IMAGELIB_ERROR_NO_DECODER);
  2065   // Instantiate the appropriate decoder
  2066   switch (type) {
  2067     case eDecoderType_png:
  2068       mDecoder = new nsPNGDecoder(*this);
  2069       break;
  2070     case eDecoderType_gif:
  2071       mDecoder = new nsGIFDecoder2(*this);
  2072       break;
  2073     case eDecoderType_jpeg:
  2074       // If we have all the data we don't want to waste cpu time doing
  2075       // a progressive decode
  2076       mDecoder = new nsJPEGDecoder(*this,
  2077                                    mHasBeenDecoded ? Decoder::SEQUENTIAL :
  2078                                                      Decoder::PROGRESSIVE);
  2079       break;
  2080     case eDecoderType_bmp:
  2081       mDecoder = new nsBMPDecoder(*this);
  2082       break;
  2083     case eDecoderType_ico:
  2084       mDecoder = new nsICODecoder(*this);
  2085       break;
  2086     case eDecoderType_icon:
  2087       mDecoder = new nsIconDecoder(*this);
  2088       break;
  2089     default:
  2090       NS_ABORT_IF_FALSE(0, "Shouldn't get here!");
  2093   // If we already have frames, we're probably in the multipart/x-mixed-replace
  2094   // case. Regardless, we need to lock the last frame. Our invariant is that,
  2095   // while we have a decoder open, the last frame is always locked.
  2096   if (GetNumFrames() > 0) {
  2097     imgFrame *curframe = mFrameBlender.RawGetFrame(GetNumFrames() - 1);
  2098     curframe->LockImageData();
  2101   // Initialize the decoder
  2102   if (!mDecodeRequest) {
  2103     mDecodeRequest = new DecodeRequest(this);
  2105   MOZ_ASSERT(mDecodeRequest->mStatusTracker);
  2106   MOZ_ASSERT(mDecodeRequest->mStatusTracker->GetDecoderObserver());
  2107   mDecoder->SetObserver(mDecodeRequest->mStatusTracker->GetDecoderObserver());
  2108   mDecoder->SetSizeDecode(aDoSizeDecode);
  2109   mDecoder->SetDecodeFlags(mFrameDecodeFlags);
  2110   if (!aDoSizeDecode) {
  2111     // We already have the size; tell the decoder so it can preallocate a
  2112     // frame.  By default, we create an ARGB frame with no offset. If decoders
  2113     // need a different type, they need to ask for it themselves.
  2114     mDecoder->NeedNewFrame(0, 0, 0, mSize.width, mSize.height,
  2115                            gfxImageFormat::ARGB32);
  2116     mDecoder->AllocateFrame();
  2118   mDecoder->Init();
  2119   CONTAINER_ENSURE_SUCCESS(mDecoder->GetDecoderError());
  2121   if (!aDoSizeDecode) {
  2122     Telemetry::GetHistogramById(Telemetry::IMAGE_DECODE_COUNT)->Subtract(mDecodeCount);
  2123     mDecodeCount++;
  2124     Telemetry::GetHistogramById(Telemetry::IMAGE_DECODE_COUNT)->Add(mDecodeCount);
  2126     if (mDecodeCount > sMaxDecodeCount) {
  2127       // Don't subtract out 0 from the histogram, because that causes its count
  2128       // to go negative, which is not kosher.
  2129       if (sMaxDecodeCount > 0) {
  2130         Telemetry::GetHistogramById(Telemetry::IMAGE_MAX_DECODE_COUNT)->Subtract(sMaxDecodeCount);
  2132       sMaxDecodeCount = mDecodeCount;
  2133       Telemetry::GetHistogramById(Telemetry::IMAGE_MAX_DECODE_COUNT)->Add(sMaxDecodeCount);
  2137   return NS_OK;
  2140 // Flushes, closes, and nulls-out a decoder. Cleans up any related decoding
  2141 // state. It is an error to call this function when there is no initialized
  2142 // decoder.
  2143 //
  2144 // aIntent specifies the intent of the shutdown. If aIntent is
  2145 // eShutdownIntent_Done, an error is flagged if we didn't get what we should
  2146 // have out of the decode. If aIntent is eShutdownIntent_NotNeeded, we don't
  2147 // check this. If aIntent is eShutdownIntent_Error, we shut down in error mode.
  2148 nsresult
  2149 RasterImage::ShutdownDecoder(eShutdownIntent aIntent)
  2151   MOZ_ASSERT(NS_IsMainThread());
  2152   mDecodingMonitor.AssertCurrentThreadIn();
  2154   // Ensure that our intent is valid
  2155   NS_ABORT_IF_FALSE((aIntent >= 0) && (aIntent < eShutdownIntent_AllCount),
  2156                     "Invalid shutdown intent");
  2158   // Ensure that the decoder is initialized
  2159   NS_ABORT_IF_FALSE(mDecoder, "Calling ShutdownDecoder() with no active decoder!");
  2161   // Figure out what kind of decode we were doing before we get rid of our decoder
  2162   bool wasSizeDecode = mDecoder->IsSizeDecode();
  2164   // Finalize the decoder
  2165   // null out mDecoder, _then_ check for errors on the close (otherwise the
  2166   // error routine might re-invoke ShutdownDecoder)
  2167   nsRefPtr<Decoder> decoder = mDecoder;
  2168   mDecoder = nullptr;
  2170   mFinishing = true;
  2171   mInDecoder = true;
  2172   decoder->Finish(aIntent);
  2173   mInDecoder = false;
  2174   mFinishing = false;
  2176   // Unlock the last frame (if we have any). Our invariant is that, while we
  2177   // have a decoder open, the last frame is always locked.
  2178   if (GetNumFrames() > 0) {
  2179     imgFrame *curframe = mFrameBlender.RawGetFrame(GetNumFrames() - 1);
  2180     curframe->UnlockImageData();
  2183   // Kill off our decode request, if it's pending.  (If not, this call is
  2184   // harmless.)
  2185   DecodePool::StopDecoding(this);
  2187   nsresult decoderStatus = decoder->GetDecoderError();
  2188   if (NS_FAILED(decoderStatus)) {
  2189     DoError();
  2190     return decoderStatus;
  2193   // We just shut down the decoder. If we didn't get what we want, but expected
  2194   // to, flag an error
  2195   bool failed = false;
  2196   if (wasSizeDecode && !mHasSize)
  2197     failed = true;
  2198   if (!wasSizeDecode && !mDecoded)
  2199     failed = true;
  2200   if ((aIntent == eShutdownIntent_Done) && failed) {
  2201     DoError();
  2202     return NS_ERROR_FAILURE;
  2205   // If we finished a full decode, and we're not meant to be storing source
  2206   // data, stop storing it.
  2207   if (!wasSizeDecode && !StoringSourceData()) {
  2208     mSourceData.Clear();
  2211   mBytesDecoded = 0;
  2213   return NS_OK;
  2216 // Writes the data to the decoder, updating the total number of bytes written.
  2217 nsresult
  2218 RasterImage::WriteToDecoder(const char *aBuffer, uint32_t aCount, DecodeStrategy aStrategy)
  2220   mDecodingMonitor.AssertCurrentThreadIn();
  2222   // We should have a decoder
  2223   NS_ABORT_IF_FALSE(mDecoder, "Trying to write to null decoder!");
  2225   // Write
  2226   nsRefPtr<Decoder> kungFuDeathGrip = mDecoder;
  2227   mInDecoder = true;
  2228   mDecoder->Write(aBuffer, aCount, aStrategy);
  2229   mInDecoder = false;
  2231   CONTAINER_ENSURE_SUCCESS(mDecoder->GetDecoderError());
  2233   // Keep track of the total number of bytes written over the lifetime of the
  2234   // decoder
  2235   mBytesDecoded += aCount;
  2237   return NS_OK;
  2240 // This function is called in situations where it's clear that we want the
  2241 // frames in decoded form (Draw, GetFrame, etc).  If we're completely decoded,
  2242 // this method resets the discard timer (if we're discardable), since wanting
  2243 // the frames now is a good indicator of wanting them again soon. If we're not
  2244 // decoded, this method kicks off asynchronous decoding to generate the frames.
  2245 nsresult
  2246 RasterImage::WantDecodedFrames()
  2248   nsresult rv;
  2250   // If we can discard, the clock should be running. Reset it.
  2251   if (CanDiscard()) {
  2252     NS_ABORT_IF_FALSE(DiscardingActive(),
  2253                       "Decoded and discardable but discarding not activated!");
  2254     rv = DiscardTracker::Reset(&mDiscardTrackerNode);
  2255     CONTAINER_ENSURE_SUCCESS(rv);
  2258   // Request a decode (no-op if we're decoded)
  2259   return StartDecoding();
  2262 //******************************************************************************
  2263 /* void requestDecode() */
  2264 NS_IMETHODIMP
  2265 RasterImage::RequestDecode()
  2267   return RequestDecodeCore(SYNCHRONOUS_NOTIFY);
  2270 /* void startDecode() */
  2271 NS_IMETHODIMP
  2272 RasterImage::StartDecoding()
  2274   if (!NS_IsMainThread()) {
  2275     return NS_DispatchToMainThread(
  2276       NS_NewRunnableMethod(this, &RasterImage::StartDecoding));
  2278   // Here we are explicitly trading off flashing for responsiveness in the case
  2279   // that we're redecoding an image (see bug 845147).
  2280   return RequestDecodeCore(mHasBeenDecoded ?
  2281     SYNCHRONOUS_NOTIFY : SYNCHRONOUS_NOTIFY_AND_SOME_DECODE);
  2284 bool
  2285 RasterImage::IsDecoded()
  2287   return mDecoded || mError;
  2290 NS_IMETHODIMP
  2291 RasterImage::RequestDecodeCore(RequestDecodeType aDecodeType)
  2293   MOZ_ASSERT(NS_IsMainThread());
  2295   nsresult rv;
  2297   if (mError)
  2298     return NS_ERROR_FAILURE;
  2300   // If we're already decoded, there's nothing to do.
  2301   if (mDecoded)
  2302     return NS_OK;
  2304   // mFinishing protects against the case when we enter RequestDecode from
  2305   // ShutdownDecoder -- in that case, we're done with the decode, we're just
  2306   // not quite ready to admit it.  See bug 744309.
  2307   if (mFinishing)
  2308     return NS_OK;
  2310   // If we're currently waiting for a new frame, we can't do anything until
  2311   // that frame is allocated.
  2312   if (mDecoder && mDecoder->NeedsNewFrame())
  2313     return NS_OK;
  2315   // If our callstack goes through a size decoder, we have a problem.
  2316   // We need to shutdown the size decode and replace it with  a full
  2317   // decoder, but can't do that from within the decoder itself. Thus, we post
  2318   // an asynchronous event to the event loop to do it later. Since
  2319   // RequestDecode() is an asynchronous function this works fine (though it's
  2320   // a little slower).
  2321   if (mInDecoder) {
  2322     nsRefPtr<imgDecodeRequestor> requestor = new imgDecodeRequestor(*this);
  2323     return NS_DispatchToCurrentThread(requestor);
  2326   // If we have a size decoder open, make sure we get the size
  2327   if (mDecoder && mDecoder->IsSizeDecode()) {
  2328     nsresult rv = DecodePool::Singleton()->DecodeUntilSizeAvailable(this);
  2329     CONTAINER_ENSURE_SUCCESS(rv);
  2331     // If we didn't get the size out of the image, we won't until we get more
  2332     // data, so signal that we want a full decode and give up for now.
  2333     if (!mHasSize) {
  2334       mWantFullDecode = true;
  2335       return NS_OK;
  2339   ReentrantMonitorAutoEnter lock(mDecodingMonitor);
  2341   // If we don't have any bytes to flush to the decoder, we can't do anything.
  2342   // mBytesDecoded can be bigger than mSourceData.Length() if we're not storing
  2343   // the source data.
  2344   if (mBytesDecoded > mSourceData.Length())
  2345     return NS_OK;
  2347   // If the image is waiting for decode work to be notified, go ahead and do that.
  2348   if (mDecodeRequest &&
  2349       mDecodeRequest->mRequestStatus == DecodeRequest::REQUEST_WORK_DONE &&
  2350       aDecodeType != ASYNCHRONOUS) {
  2351     nsresult rv = FinishedSomeDecoding();
  2352     CONTAINER_ENSURE_SUCCESS(rv);
  2355   // If we're fully decoded, we have nothing to do. We need this check after
  2356   // DecodeUntilSizeAvailable and FinishedSomeDecoding because they can result
  2357   // in us finishing an in-progress decode (or kicking off and finishing a
  2358   // synchronous decode if we're already waiting on a full decode).
  2359   if (mDecoded) {
  2360     return NS_OK;
  2363   // If we've already got a full decoder running, and have already
  2364   // decoded some bytes, we have nothing to do
  2365   if (mDecoder && !mDecoder->IsSizeDecode() && mBytesDecoded) {
  2366     return NS_OK;
  2369   // If we have a size decode open, interrupt it and shut it down; or if
  2370   // the decoder has different flags than what we need
  2371   if (mDecoder && mDecoder->GetDecodeFlags() != mFrameDecodeFlags) {
  2372     nsresult rv = FinishedSomeDecoding(eShutdownIntent_NotNeeded);
  2373     CONTAINER_ENSURE_SUCCESS(rv);
  2376   // If we don't have a decoder, create one
  2377   if (!mDecoder) {
  2378     rv = InitDecoder(/* aDoSizeDecode = */ false);
  2379     CONTAINER_ENSURE_SUCCESS(rv);
  2381     rv = FinishedSomeDecoding();
  2382     CONTAINER_ENSURE_SUCCESS(rv);
  2384     MOZ_ASSERT(mDecoder);
  2387   // If we've read all the data we have, we're done
  2388   if (mHasSourceData && mBytesDecoded == mSourceData.Length())
  2389     return NS_OK;
  2391   // If we can do decoding now, do so.  Small images will decode completely,
  2392   // large images will decode a bit and post themselves to the event loop
  2393   // to finish decoding.
  2394   if (!mDecoded && !mInDecoder && mHasSourceData && aDecodeType == SYNCHRONOUS_NOTIFY_AND_SOME_DECODE) {
  2395     PROFILER_LABEL_PRINTF("RasterImage", "DecodeABitOf", "%s", GetURIString().get());
  2396     DecodePool::Singleton()->DecodeABitOf(this, DECODE_SYNC);
  2397     return NS_OK;
  2400   if (!mDecoded) {
  2401     // If we get this far, dispatch the worker. We do this instead of starting
  2402     // any immediate decoding to guarantee that all our decode notifications are
  2403     // dispatched asynchronously, and to ensure we stay responsive.
  2404     DecodePool::Singleton()->RequestDecode(this);
  2407   return NS_OK;
  2410 // Synchronously decodes as much data as possible
  2411 nsresult
  2412 RasterImage::SyncDecode()
  2414   PROFILER_LABEL_PRINTF("RasterImage", "SyncDecode", "%s", GetURIString().get());;
  2416   // If we have a size decoder open, make sure we get the size
  2417   if (mDecoder && mDecoder->IsSizeDecode()) {
  2418     nsresult rv = DecodePool::Singleton()->DecodeUntilSizeAvailable(this);
  2419     CONTAINER_ENSURE_SUCCESS(rv);
  2421     // If we didn't get the size out of the image, we won't until we get more
  2422     // data, so signal that we want a full decode and give up for now.
  2423     if (!mHasSize) {
  2424       mWantFullDecode = true;
  2425       return NS_ERROR_NOT_AVAILABLE;
  2429   ReentrantMonitorAutoEnter lock(mDecodingMonitor);
  2431   // We really have no good way of forcing a synchronous decode if we're being
  2432   // called in a re-entrant manner (ie, from an event listener fired by a
  2433   // decoder), because the decoding machinery is already tied up. We thus explicitly
  2434   // disallow this type of call in the API, and check for it in API methods.
  2435   NS_ABORT_IF_FALSE(!mInDecoder, "Yikes, forcing sync in reentrant call!");
  2437   if (mDecodeRequest) {
  2438     // If the image is waiting for decode work to be notified, go ahead and do that.
  2439     if (mDecodeRequest->mRequestStatus == DecodeRequest::REQUEST_WORK_DONE) {
  2440       nsresult rv = FinishedSomeDecoding();
  2441       CONTAINER_ENSURE_SUCCESS(rv);
  2445   nsresult rv;
  2447   // If we're decoded already, or decoding until the size was available
  2448   // finished us as a side-effect, no worries
  2449   if (mDecoded)
  2450     return NS_OK;
  2452   // If we don't have any bytes to flush to the decoder, we can't do anything.
  2453   // mBytesDecoded can be bigger than mSourceData.Length() if we're not storing
  2454   // the source data.
  2455   if (mBytesDecoded > mSourceData.Length())
  2456     return NS_OK;
  2458   // If we have a decoder open with different flags than what we need, shut it
  2459   // down
  2460   if (mDecoder && mDecoder->GetDecodeFlags() != mFrameDecodeFlags) {
  2461     nsresult rv = FinishedSomeDecoding(eShutdownIntent_NotNeeded);
  2462     CONTAINER_ENSURE_SUCCESS(rv);
  2464     if (mDecoded) {
  2465       // If we've finished decoding we need to discard so we can re-decode
  2466       // with the new flags. If we can't discard then there isn't
  2467       // anything we can do.
  2468       if (!CanForciblyDiscardAndRedecode())
  2469         return NS_ERROR_NOT_AVAILABLE;
  2470       ForceDiscard();
  2474   // If we're currently waiting on a new frame for this image, we have to create
  2475   // it now.
  2476   if (mDecoder && mDecoder->NeedsNewFrame()) {
  2477     mDecoder->AllocateFrame();
  2478     mDecodeRequest->mAllocatedNewFrame = true;
  2481   // If we don't have a decoder, create one
  2482   if (!mDecoder) {
  2483     rv = InitDecoder(/* aDoSizeDecode = */ false);
  2484     CONTAINER_ENSURE_SUCCESS(rv);
  2487   // Write everything we have
  2488   rv = DecodeSomeData(mSourceData.Length() - mBytesDecoded, DECODE_SYNC);
  2489   CONTAINER_ENSURE_SUCCESS(rv);
  2491   // When we're doing a sync decode, we want to get as much information from the
  2492   // image as possible. We've send the decoder all of our data, so now's a good
  2493   // time  to flush any invalidations (in case we don't have all the data and what
  2494   // we got left us mid-frame).
  2495   nsRefPtr<Decoder> kungFuDeathGrip = mDecoder;
  2496   mInDecoder = true;
  2497   mDecoder->FlushInvalidations();
  2498   mInDecoder = false;
  2500   rv = FinishedSomeDecoding();
  2501   CONTAINER_ENSURE_SUCCESS(rv);
  2503   // If our decoder's still open, there's still work to be done.
  2504   if (mDecoder) {
  2505     DecodePool::Singleton()->RequestDecode(this);
  2508   // All good if no errors!
  2509   return mError ? NS_ERROR_FAILURE : NS_OK;
  2512 bool
  2513 RasterImage::CanQualityScale(const gfxSize& scale)
  2515   // If target size is 1:1 with original, don't scale.
  2516   if (scale.width == 1.0 && scale.height == 1.0)
  2517     return false;
  2519   // To save memory don't quality upscale images bigger than the limit.
  2520   if (scale.width > 1.0 || scale.height > 1.0) {
  2521     uint32_t scaled_size = static_cast<uint32_t>(mSize.width * mSize.height * scale.width * scale.height);
  2522     if (scaled_size > gHQUpscalingMaxSize)
  2523       return false;
  2526   return true;
  2529 bool
  2530 RasterImage::CanScale(GraphicsFilter aFilter,
  2531                       gfxSize aScale, uint32_t aFlags)
  2533 // The high-quality scaler requires Skia.
  2534 #ifdef MOZ_ENABLE_SKIA
  2535   // We don't use the scaler for animated or multipart images to avoid doing a
  2536   // bunch of work on an image that just gets thrown away.
  2537   // We only use the scaler when drawing to the window because, if we're not
  2538   // drawing to a window (eg a canvas), updates to that image will be ignored.
  2539   if (gHQDownscaling && aFilter == GraphicsFilter::FILTER_GOOD &&
  2540       !mAnim && mDecoded && !mMultipart && CanQualityScale(aScale) &&
  2541       (aFlags & imgIContainer::FLAG_HIGH_QUALITY_SCALING)) {
  2542     gfxFloat factor = gHQDownscalingMinFactor / 1000.0;
  2544     return (aScale.width < factor || aScale.height < factor);
  2546 #endif
  2548   return false;
  2551 void
  2552 RasterImage::ScalingStart(ScaleRequest* request)
  2554   MOZ_ASSERT(request);
  2555   mScaleResult.scale = request->scale;
  2556   mScaleResult.status = SCALE_PENDING;
  2557   mScaleRequest = request;
  2560 void
  2561 RasterImage::ScalingDone(ScaleRequest* request, ScaleStatus status)
  2563   MOZ_ASSERT(status == SCALE_DONE || status == SCALE_INVALID);
  2564   MOZ_ASSERT(request);
  2566   if (status == SCALE_DONE) {
  2567     MOZ_ASSERT(request->done);
  2569     imgFrame *scaledFrame = request->dstFrame.forget();
  2570     scaledFrame->ImageUpdated(scaledFrame->GetRect());
  2571     scaledFrame->ApplyDirtToSurfaces();
  2573     if (mStatusTracker) {
  2574       mStatusTracker->FrameChanged(&request->srcRect);
  2577     mScaleResult.status = SCALE_DONE;
  2578     mScaleResult.frame = scaledFrame;
  2579     mScaleResult.scale = request->scale;
  2580   } else {
  2581     mScaleResult.status = SCALE_INVALID;
  2582     mScaleResult.frame = nullptr;
  2585   // If we were waiting for this scale to come through, forget the scale
  2586   // request. Otherwise, we still have a scale outstanding that it's possible
  2587   // for us to (want to) stop.
  2588   if (mScaleRequest == request) {
  2589     mScaleRequest = nullptr;
  2593 bool
  2594 RasterImage::DrawWithPreDownscaleIfNeeded(imgFrame *aFrame,
  2595                                           gfxContext *aContext,
  2596                                           GraphicsFilter aFilter,
  2597                                           const gfxMatrix &aUserSpaceToImageSpace,
  2598                                           const gfxRect &aFill,
  2599                                           const nsIntRect &aSubimage,
  2600                                           uint32_t aFlags)
  2602   imgFrame *frame = aFrame;
  2603   nsIntRect framerect = frame->GetRect();
  2604   gfxMatrix userSpaceToImageSpace = aUserSpaceToImageSpace;
  2605   gfxMatrix imageSpaceToUserSpace = aUserSpaceToImageSpace;
  2606   imageSpaceToUserSpace.Invert();
  2607   gfxSize scale = imageSpaceToUserSpace.ScaleFactors(true);
  2608   nsIntRect subimage = aSubimage;
  2609   nsRefPtr<gfxASurface> surf;
  2611   if (CanScale(aFilter, scale, aFlags) && !frame->IsSinglePixel()) {
  2612     // If scale factor is still the same that we scaled for and
  2613     // ScaleWorker isn't still working, then we can use pre-downscaled frame.
  2614     // If scale factor has changed, order new request.
  2615     // FIXME: Current implementation doesn't support pre-downscale
  2616     // mechanism for multiple sizes from same src, since we cache
  2617     // pre-downscaled frame only for the latest requested scale.
  2618     // The solution is to cache more than one scaled image frame
  2619     // for each RasterImage.
  2620     bool needScaleReq;
  2621     if (mScaleResult.status == SCALE_DONE && mScaleResult.scale == scale) {
  2622       // Grab and hold the surface to make sure the OS didn't destroy it
  2623       mScaleResult.frame->GetSurface(getter_AddRefs(surf));
  2624       needScaleReq = !surf;
  2625       if (surf) {
  2626         frame = mScaleResult.frame;
  2627         userSpaceToImageSpace.Multiply(gfxMatrix().Scale(scale.width,
  2628                                                          scale.height));
  2630         // Since we're switching to a scaled image, we need to transform the
  2631         // area of the subimage to draw accordingly, since imgFrame::Draw()
  2632         // doesn't know about scaled frames.
  2633         subimage.ScaleRoundOut(scale.width, scale.height);
  2635     } else {
  2636       needScaleReq = !(mScaleResult.status == SCALE_PENDING &&
  2637                        mScaleResult.scale == scale);
  2640     // If we're not waiting for exactly this result, and there's only one
  2641     // instance of this image on this page, ask for a scale.
  2642     if (needScaleReq && mLockCount == 1) {
  2643       if (NS_FAILED(frame->LockImageData())) {
  2644         frame->UnlockImageData();
  2645         return false;
  2648       // If we have an outstanding request, signal it to stop (if it can).
  2649       if (mScaleRequest) {
  2650         mScaleRequest->stopped = true;
  2653       nsRefPtr<ScaleRunner> runner = new ScaleRunner(this, scale, frame);
  2654       if (runner->IsOK()) {
  2655         if (!sScaleWorkerThread) {
  2656           NS_NewNamedThread("Image Scaler", getter_AddRefs(sScaleWorkerThread));
  2657           ClearOnShutdown(&sScaleWorkerThread);
  2660         sScaleWorkerThread->Dispatch(runner, NS_DISPATCH_NORMAL);
  2662       frame->UnlockImageData();
  2666   nsIntMargin padding(framerect.y,
  2667                       mSize.width - framerect.XMost(),
  2668                       mSize.height - framerect.YMost(),
  2669                       framerect.x);
  2671   return frame->Draw(aContext, aFilter, userSpaceToImageSpace,
  2672                      aFill, padding, subimage, aFlags);
  2675 //******************************************************************************
  2676 /* [noscript] void draw(in gfxContext aContext,
  2677  *                      in gfxGraphicsFilter aFilter,
  2678  *                      [const] in gfxMatrix aUserSpaceToImageSpace,
  2679  *                      [const] in gfxRect aFill,
  2680  *                      [const] in nsIntRect aSubimage,
  2681  *                      [const] in nsIntSize aViewportSize,
  2682  *                      [const] in SVGImageContext aSVGContext,
  2683  *                      in uint32_t aWhichFrame,
  2684  *                      in uint32_t aFlags); */
  2685 NS_IMETHODIMP
  2686 RasterImage::Draw(gfxContext *aContext,
  2687                   GraphicsFilter aFilter,
  2688                   const gfxMatrix &aUserSpaceToImageSpace,
  2689                   const gfxRect &aFill,
  2690                   const nsIntRect &aSubimage,
  2691                   const nsIntSize& /*aViewportSize - ignored*/,
  2692                   const SVGImageContext* /*aSVGContext - ignored*/,
  2693                   uint32_t aWhichFrame,
  2694                   uint32_t aFlags)
  2696   if (aWhichFrame > FRAME_MAX_VALUE)
  2697     return NS_ERROR_INVALID_ARG;
  2699   if (mError)
  2700     return NS_ERROR_FAILURE;
  2702   // Disallowed in the API
  2703   if (mInDecoder && (aFlags & imgIContainer::FLAG_SYNC_DECODE))
  2704     return NS_ERROR_FAILURE;
  2706   // Illegal -- you can't draw with non-default decode flags.
  2707   // (Disabling colorspace conversion might make sense to allow, but
  2708   // we don't currently.)
  2709   if ((aFlags & DECODE_FLAGS_MASK) != DECODE_FLAGS_DEFAULT)
  2710     return NS_ERROR_FAILURE;
  2712   NS_ENSURE_ARG_POINTER(aContext);
  2714   // We can only draw without discarding and redecoding in these cases:
  2715   //  * We have the default decode flags.
  2716   //  * We have exactly FLAG_DECODE_NO_PREMULTIPLY_ALPHA and the current frame
  2717   //    is opaque.
  2718   bool haveDefaultFlags = (mFrameDecodeFlags == DECODE_FLAGS_DEFAULT);
  2719   bool haveSafeAlphaFlags =
  2720     (mFrameDecodeFlags == FLAG_DECODE_NO_PREMULTIPLY_ALPHA) &&
  2721     FrameIsOpaque(FRAME_CURRENT);
  2723   if (!(haveDefaultFlags || haveSafeAlphaFlags)) {
  2724     if (!CanForciblyDiscardAndRedecode())
  2725       return NS_ERROR_NOT_AVAILABLE;
  2726     ForceDiscard();
  2728     mFrameDecodeFlags = DECODE_FLAGS_DEFAULT;
  2731   // If this image is a candidate for discarding, reset its position in the
  2732   // discard tracker so we're less likely to discard it right away.
  2733   //
  2734   // (We don't normally draw unlocked images, so this conditition will usually
  2735   // be false.  But we will draw unlocked images if image locking is globally
  2736   // disabled via the image.mem.allow_locking_in_content_processes pref.)
  2737   if (DiscardingActive()) {
  2738     DiscardTracker::Reset(&mDiscardTrackerNode);
  2742   if (IsUnlocked() && mStatusTracker) {
  2743     mStatusTracker->OnUnlockedDraw();
  2746   // We use !mDecoded && mHasSourceData to mean discarded.
  2747   if (!mDecoded && mHasSourceData) {
  2748     mDrawStartTime = TimeStamp::Now();
  2751   // If a synchronous draw is requested, flush anything that might be sitting around
  2752   if (aFlags & FLAG_SYNC_DECODE) {
  2753     nsresult rv = SyncDecode();
  2754     NS_ENSURE_SUCCESS(rv, rv);
  2757   uint32_t frameIndex = aWhichFrame == FRAME_FIRST ? 0
  2758                                                    : GetCurrentImgFrameIndex();
  2759   imgFrame* frame = GetDrawableImgFrame(frameIndex);
  2760   if (!frame) {
  2761     return NS_OK; // Getting the frame (above) touches the image and kicks off decoding
  2764   bool drawn = DrawWithPreDownscaleIfNeeded(frame, aContext, aFilter,
  2765                                             aUserSpaceToImageSpace, aFill,
  2766                                             aSubimage, aFlags);
  2767   if (!drawn) {
  2768     // The OS threw out some or all of our buffer. Start decoding again.
  2769     ForceDiscard();
  2770     WantDecodedFrames();
  2771     return NS_OK;
  2774   if (mDecoded && !mDrawStartTime.IsNull()) {
  2775       TimeDuration drawLatency = TimeStamp::Now() - mDrawStartTime;
  2776       Telemetry::Accumulate(Telemetry::IMAGE_DECODE_ON_DRAW_LATENCY, int32_t(drawLatency.ToMicroseconds()));
  2777       // clear the value of mDrawStartTime
  2778       mDrawStartTime = TimeStamp();
  2781   return NS_OK;
  2784 //******************************************************************************
  2785 /* void lockImage() */
  2786 NS_IMETHODIMP
  2787 RasterImage::LockImage()
  2789   MOZ_ASSERT(NS_IsMainThread(),
  2790              "Main thread to encourage serialization with UnlockImage");
  2791   if (mError)
  2792     return NS_ERROR_FAILURE;
  2794   // Cancel the discard timer if it's there
  2795   DiscardTracker::Remove(&mDiscardTrackerNode);
  2797   // Increment the lock count
  2798   mLockCount++;
  2800   return NS_OK;
  2803 //******************************************************************************
  2804 /* void unlockImage() */
  2805 NS_IMETHODIMP
  2806 RasterImage::UnlockImage()
  2808   MOZ_ASSERT(NS_IsMainThread(),
  2809              "Main thread to encourage serialization with LockImage");
  2810   if (mError)
  2811     return NS_ERROR_FAILURE;
  2813   // It's an error to call this function if the lock count is 0
  2814   NS_ABORT_IF_FALSE(mLockCount > 0,
  2815                     "Calling UnlockImage with mLockCount == 0!");
  2816   if (mLockCount == 0)
  2817     return NS_ERROR_ABORT;
  2819   // We're locked, so discarding should not be active
  2820   NS_ABORT_IF_FALSE(!DiscardingActive(), "Locked, but discarding activated");
  2822   // Decrement our lock count
  2823   mLockCount--;
  2825   // If we've decoded this image once before, we're currently decoding again,
  2826   // and our lock count is now zero (so nothing is forcing us to keep the
  2827   // decoded data around), try to cancel the decode and throw away whatever
  2828   // we've decoded.
  2829   if (mHasBeenDecoded && mDecoder &&
  2830       mLockCount == 0 && CanForciblyDiscard()) {
  2831     PR_LOG(GetCompressedImageAccountingLog(), PR_LOG_DEBUG,
  2832            ("RasterImage[0x%p] canceling decode because image "
  2833             "is now unlocked.", this));
  2834     ReentrantMonitorAutoEnter lock(mDecodingMonitor);
  2835     FinishedSomeDecoding(eShutdownIntent_NotNeeded);
  2836     ForceDiscard();
  2837     return NS_OK;
  2840   // Otherwise, we might still be a candidate for discarding in the future.  If
  2841   // we are, add ourselves to the discard tracker.
  2842   if (CanDiscard()) {
  2843     nsresult rv = DiscardTracker::Reset(&mDiscardTrackerNode);
  2844     CONTAINER_ENSURE_SUCCESS(rv);
  2847   return NS_OK;
  2850 //******************************************************************************
  2851 /* void requestDiscard() */
  2852 NS_IMETHODIMP
  2853 RasterImage::RequestDiscard()
  2855   if (CanDiscard() && CanForciblyDiscardAndRedecode()) {
  2856     ForceDiscard();
  2859   return NS_OK;
  2862 // Flushes up to aMaxBytes to the decoder.
  2863 nsresult
  2864 RasterImage::DecodeSomeData(uint32_t aMaxBytes, DecodeStrategy aStrategy)
  2866   // We should have a decoder if we get here
  2867   NS_ABORT_IF_FALSE(mDecoder, "trying to decode without decoder!");
  2869   mDecodingMonitor.AssertCurrentThreadIn();
  2871   // First, if we've just been called because we allocated a frame on the main
  2872   // thread, let the decoder deal with the data it set aside at that time by
  2873   // passing it a null buffer.
  2874   if (mDecodeRequest->mAllocatedNewFrame) {
  2875     mDecodeRequest->mAllocatedNewFrame = false;
  2876     nsresult rv = WriteToDecoder(nullptr, 0, aStrategy);
  2877     if (NS_FAILED(rv) || mDecoder->NeedsNewFrame()) {
  2878       return rv;
  2882   // If we have nothing else to decode, return
  2883   if (mBytesDecoded == mSourceData.Length())
  2884     return NS_OK;
  2886   MOZ_ASSERT(mBytesDecoded < mSourceData.Length());
  2888   // write the proper amount of data
  2889   uint32_t bytesToDecode = std::min(aMaxBytes,
  2890                                     mSourceData.Length() - mBytesDecoded);
  2891   nsresult rv = WriteToDecoder(mSourceData.Elements() + mBytesDecoded,
  2892                                bytesToDecode,
  2893                                aStrategy);
  2895   return rv;
  2898 // There are various indicators that tell us we're finished with the decode
  2899 // task at hand and can shut down the decoder.
  2900 //
  2901 // This method may not be called if there is no decoder.
  2902 bool
  2903 RasterImage::IsDecodeFinished()
  2905   // Precondition
  2906   mDecodingMonitor.AssertCurrentThreadIn();
  2907   NS_ABORT_IF_FALSE(mDecoder, "Can't call IsDecodeFinished() without decoder!");
  2909   // The decode is complete if we got what we wanted.
  2910   if (mDecoder->IsSizeDecode()) {
  2911     if (mDecoder->HasSize()) {
  2912       return true;
  2914   } else if (mDecoder->GetDecodeDone()) {
  2915     return true;
  2918   // If the decoder returned because it needed a new frame and we haven't
  2919   // written to it since then, the decoder may be storing data that it hasn't
  2920   // decoded yet.
  2921   if (mDecoder->NeedsNewFrame() ||
  2922       (mDecodeRequest && mDecodeRequest->mAllocatedNewFrame)) {
  2923     return false;
  2926   // Otherwise, if we have all the source data and wrote all the source data,
  2927   // we're done.
  2928   //
  2929   // (NB - This can be the case even for non-erroneous images because
  2930   // Decoder::GetDecodeDone() might not return true until after we call
  2931   // Decoder::Finish() in ShutdownDecoder())
  2932   if (mHasSourceData && (mBytesDecoded == mSourceData.Length())) {
  2933     return true;
  2936   // If we get here, assume it's not finished.
  2937   return false;
  2940 // Indempotent error flagging routine. If a decoder is open, shuts it down.
  2941 void
  2942 RasterImage::DoError()
  2944   // If we've flagged an error before, we have nothing to do
  2945   if (mError)
  2946     return;
  2948   // We can't safely handle errors off-main-thread, so dispatch a worker to do it.
  2949   if (!NS_IsMainThread()) {
  2950     HandleErrorWorker::DispatchIfNeeded(this);
  2951     return;
  2954   // Calling FinishedSomeDecoding and CurrentStatusTracker requires us to be in
  2955   // the decoding monitor.
  2956   ReentrantMonitorAutoEnter lock(mDecodingMonitor);
  2958   // If we're mid-decode, shut down the decoder.
  2959   if (mDecoder) {
  2960     FinishedSomeDecoding(eShutdownIntent_Error);
  2963   // Put the container in an error state.
  2964   mError = true;
  2966   nsRefPtr<imgStatusTracker> statusTracker = CurrentStatusTracker();
  2967   statusTracker->GetDecoderObserver()->OnError();
  2969   // Log our error
  2970   LOG_CONTAINER_ERROR;
  2973 /* static */ void
  2974 RasterImage::HandleErrorWorker::DispatchIfNeeded(RasterImage* aImage)
  2976   if (!aImage->mPendingError) {
  2977     aImage->mPendingError = true;
  2978     nsRefPtr<HandleErrorWorker> worker = new HandleErrorWorker(aImage);
  2979     NS_DispatchToMainThread(worker);
  2983 RasterImage::HandleErrorWorker::HandleErrorWorker(RasterImage* aImage)
  2984   : mImage(aImage)
  2986   MOZ_ASSERT(mImage, "Should have image");
  2989 NS_IMETHODIMP
  2990 RasterImage::HandleErrorWorker::Run()
  2992   mImage->DoError();
  2994   return NS_OK;
  2997 // nsIInputStream callback to copy the incoming image data directly to the
  2998 // RasterImage without processing. The RasterImage is passed as the closure.
  2999 // Always reads everything it gets, even if the data is erroneous.
  3000 NS_METHOD
  3001 RasterImage::WriteToRasterImage(nsIInputStream* /* unused */,
  3002                                 void*          aClosure,
  3003                                 const char*    aFromRawSegment,
  3004                                 uint32_t       /* unused */,
  3005                                 uint32_t       aCount,
  3006                                 uint32_t*      aWriteCount)
  3008   // Retrieve the RasterImage
  3009   RasterImage* image = static_cast<RasterImage*>(aClosure);
  3011   // Copy the source data. Unless we hit OOM, we squelch the return value
  3012   // here, because returning an error means that ReadSegments stops
  3013   // reading data, violating our invariant that we read everything we get.
  3014   // If we hit OOM then we fail and the load is aborted.
  3015   nsresult rv = image->AddSourceData(aFromRawSegment, aCount);
  3016   if (rv == NS_ERROR_OUT_OF_MEMORY) {
  3017     image->DoError();
  3018     return rv;
  3021   // We wrote everything we got
  3022   *aWriteCount = aCount;
  3024   return NS_OK;
  3027 bool
  3028 RasterImage::ShouldAnimate()
  3030   return ImageResource::ShouldAnimate() && GetNumFrames() >= 2 &&
  3031          !mAnimationFinished;
  3034 /* readonly attribute uint32_t framesNotified; */
  3035 #ifdef DEBUG
  3036 NS_IMETHODIMP
  3037 RasterImage::GetFramesNotified(uint32_t *aFramesNotified)
  3039   NS_ENSURE_ARG_POINTER(aFramesNotified);
  3041   *aFramesNotified = mFramesNotified;
  3043   return NS_OK;
  3045 #endif
  3047 nsresult
  3048 RasterImage::RequestDecodeIfNeeded(nsresult aStatus,
  3049                                    eShutdownIntent aIntent,
  3050                                    bool aDone,
  3051                                    bool aWasSize)
  3053   MOZ_ASSERT(NS_IsMainThread());
  3055   // If we were a size decode and a full decode was requested, now's the time.
  3056   if (NS_SUCCEEDED(aStatus) &&
  3057       aIntent == eShutdownIntent_Done &&
  3058       aDone &&
  3059       aWasSize &&
  3060       mWantFullDecode) {
  3061     mWantFullDecode = false;
  3063     // If we're not meant to be storing source data and we just got the size,
  3064     // we need to synchronously flush all the data we got to a full decoder.
  3065     // When that decoder is shut down, we'll also clear our source data.
  3066     return StoringSourceData() ? RequestDecode()
  3067                                : SyncDecode();
  3070   // We don't need a full decode right now, so just return the existing status.
  3071   return aStatus;
  3074 nsresult
  3075 RasterImage::FinishedSomeDecoding(eShutdownIntent aIntent /* = eShutdownIntent_Done */,
  3076                                   DecodeRequest* aRequest /* = nullptr */)
  3078   MOZ_ASSERT(NS_IsMainThread());
  3080   mDecodingMonitor.AssertCurrentThreadIn();
  3082   nsRefPtr<DecodeRequest> request;
  3083   if (aRequest) {
  3084     request = aRequest;
  3085   } else {
  3086     request = mDecodeRequest;
  3089   // Ensure that, if the decoder is the last reference to the image, we don't
  3090   // destroy it by destroying the decoder.
  3091   nsRefPtr<RasterImage> image(this);
  3093   bool done = false;
  3094   bool wasSize = false;
  3095   nsresult rv = NS_OK;
  3097   if (image->mDecoder) {
  3098     image->mDecoder->MarkFrameDirty();
  3100     if (request && request->mChunkCount && !image->mDecoder->IsSizeDecode()) {
  3101       Telemetry::Accumulate(Telemetry::IMAGE_DECODE_CHUNKS, request->mChunkCount);
  3104     if (!image->mHasSize && image->mDecoder->HasSize()) {
  3105       image->mDecoder->SetSizeOnImage();
  3108     // If the decode finished, or we're specifically being told to shut down,
  3109     // tell the image and shut down the decoder.
  3110     if (image->IsDecodeFinished() || aIntent != eShutdownIntent_Done) {
  3111       done = true;
  3113       // Hold on to a reference to the decoder until we're done with it
  3114       nsRefPtr<Decoder> decoder = image->mDecoder;
  3116       wasSize = decoder->IsSizeDecode();
  3118       // Do some telemetry if this isn't a size decode.
  3119       if (request && !wasSize) {
  3120         Telemetry::Accumulate(Telemetry::IMAGE_DECODE_TIME,
  3121                               int32_t(request->mDecodeTime.ToMicroseconds()));
  3123         // We record the speed for only some decoders. The rest have
  3124         // SpeedHistogram return HistogramCount.
  3125         Telemetry::ID id = decoder->SpeedHistogram();
  3126         if (id < Telemetry::HistogramCount) {
  3127           int32_t KBps = int32_t(request->mImage->mBytesDecoded /
  3128                                  (1024 * request->mDecodeTime.ToSeconds()));
  3129           Telemetry::Accumulate(id, KBps);
  3133       // We need to shut down the decoder first, in order to ensure all
  3134       // decoding routines have been finished.
  3135       rv = image->ShutdownDecoder(aIntent);
  3136       if (NS_FAILED(rv)) {
  3137         image->DoError();
  3142   ImageStatusDiff diff =
  3143     request ? image->mStatusTracker->Difference(request->mStatusTracker)
  3144             : image->mStatusTracker->DecodeStateAsDifference();
  3145   image->mStatusTracker->ApplyDifference(diff);
  3147   if (mNotifying) {
  3148     // Accumulate the status changes. We don't permit recursive notifications
  3149     // because they cause subtle concurrency bugs, so we'll delay sending out
  3150     // the notifications until we pop back to the lowest invocation of
  3151     // FinishedSomeDecoding on the stack.
  3152     NS_WARNING("Recursively notifying in RasterImage::FinishedSomeDecoding!");
  3153     mStatusDiff.Combine(diff);
  3154   } else {
  3155     MOZ_ASSERT(mStatusDiff.IsNoChange(), "Shouldn't have an accumulated change at this point");
  3157     while (!diff.IsNoChange()) {
  3158       // Tell the observers what happened.
  3159       mNotifying = true;
  3160       image->mStatusTracker->SyncNotifyDifference(diff);
  3161       mNotifying = false;
  3163       // Gather any status changes that may have occurred as a result of sending
  3164       // out the previous notifications. If there were any, we'll send out
  3165       // notifications for them next.
  3166       diff = mStatusDiff;
  3167       mStatusDiff = ImageStatusDiff::NoChange();
  3171   return RequestDecodeIfNeeded(rv, aIntent, done, wasSize);
  3174 NS_IMPL_ISUPPORTS(RasterImage::DecodePool,
  3175                   nsIObserver)
  3177 /* static */ RasterImage::DecodePool*
  3178 RasterImage::DecodePool::Singleton()
  3180   if (!sSingleton) {
  3181     MOZ_ASSERT(NS_IsMainThread());
  3182     sSingleton = new DecodePool();
  3183     ClearOnShutdown(&sSingleton);
  3186   return sSingleton;
  3189 already_AddRefed<nsIEventTarget>
  3190 RasterImage::DecodePool::GetEventTarget()
  3192   nsCOMPtr<nsIEventTarget> target = do_QueryInterface(mThreadPool);
  3193   return target.forget();
  3196 #ifdef MOZ_NUWA_PROCESS
  3198 class RIDThreadPoolListener : public nsIThreadPoolListener
  3200 public:
  3201     NS_DECL_THREADSAFE_ISUPPORTS
  3202     NS_DECL_NSITHREADPOOLLISTENER
  3204     RIDThreadPoolListener() {}
  3205     ~RIDThreadPoolListener() {}
  3206 };
  3208 NS_IMPL_ISUPPORTS(RIDThreadPoolListener, nsIThreadPoolListener)
  3210 NS_IMETHODIMP
  3211 RIDThreadPoolListener::OnThreadCreated()
  3213     if (IsNuwaProcess()) {
  3214         NuwaMarkCurrentThread((void (*)(void *))nullptr, nullptr);
  3216     return NS_OK;
  3219 NS_IMETHODIMP
  3220 RIDThreadPoolListener::OnThreadShuttingDown()
  3222     return NS_OK;
  3225 #endif // MOZ_NUWA_PROCESS
  3227 RasterImage::DecodePool::DecodePool()
  3228  : mThreadPoolMutex("Thread Pool")
  3230   if (gMultithreadedDecoding) {
  3231     mThreadPool = do_CreateInstance(NS_THREADPOOL_CONTRACTID);
  3232     if (mThreadPool) {
  3233       mThreadPool->SetName(NS_LITERAL_CSTRING("ImageDecoder"));
  3234       uint32_t limit;
  3235       if (gDecodingThreadLimit <= 0) {
  3236         limit = std::max(PR_GetNumberOfProcessors(), 2) - 1;
  3237       } else {
  3238         limit = static_cast<uint32_t>(gDecodingThreadLimit);
  3241       mThreadPool->SetThreadLimit(limit);
  3242       mThreadPool->SetIdleThreadLimit(limit);
  3244 #ifdef MOZ_NUWA_PROCESS
  3245       if (IsNuwaProcess()) {
  3246         mThreadPool->SetListener(new RIDThreadPoolListener());
  3248 #endif
  3250       nsCOMPtr<nsIObserverService> obsSvc = mozilla::services::GetObserverService();
  3251       if (obsSvc) {
  3252         obsSvc->AddObserver(this, "xpcom-shutdown-threads", false);
  3258 RasterImage::DecodePool::~DecodePool()
  3260   MOZ_ASSERT(NS_IsMainThread(), "Must shut down DecodePool on main thread!");
  3263 NS_IMETHODIMP
  3264 RasterImage::DecodePool::Observe(nsISupports *subject, const char *topic,
  3265                                  const char16_t *data)
  3267   NS_ASSERTION(strcmp(topic, "xpcom-shutdown-threads") == 0, "oops");
  3269   nsCOMPtr<nsIThreadPool> threadPool;
  3272     MutexAutoLock threadPoolLock(mThreadPoolMutex);
  3273     threadPool = mThreadPool;
  3274     mThreadPool = nullptr;
  3277   if (threadPool) {
  3278     threadPool->Shutdown();
  3281   return NS_OK;
  3284 void
  3285 RasterImage::DecodePool::RequestDecode(RasterImage* aImg)
  3287   MOZ_ASSERT(aImg->mDecoder);
  3288   aImg->mDecodingMonitor.AssertCurrentThreadIn();
  3290   // If we're currently waiting on a new frame for this image, we can't do any
  3291   // decoding.
  3292   if (!aImg->mDecoder->NeedsNewFrame()) {
  3293     // No matter whether this is currently being decoded, we need to update the
  3294     // number of bytes we want it to decode.
  3295     aImg->mDecodeRequest->mBytesToDecode = aImg->mSourceData.Length() - aImg->mBytesDecoded;
  3297     if (aImg->mDecodeRequest->mRequestStatus == DecodeRequest::REQUEST_PENDING ||
  3298         aImg->mDecodeRequest->mRequestStatus == DecodeRequest::REQUEST_ACTIVE) {
  3299       // The image is already in our list of images to decode, or currently being
  3300       // decoded, so we don't have to do anything else.
  3301       return;
  3304     aImg->mDecodeRequest->mRequestStatus = DecodeRequest::REQUEST_PENDING;
  3305     nsRefPtr<DecodeJob> job = new DecodeJob(aImg->mDecodeRequest, aImg);
  3307     MutexAutoLock threadPoolLock(mThreadPoolMutex);
  3308     if (!gMultithreadedDecoding || !mThreadPool) {
  3309       NS_DispatchToMainThread(job);
  3310     } else {
  3311       mThreadPool->Dispatch(job, nsIEventTarget::DISPATCH_NORMAL);
  3316 void
  3317 RasterImage::DecodePool::DecodeABitOf(RasterImage* aImg, DecodeStrategy aStrategy)
  3319   MOZ_ASSERT(NS_IsMainThread());
  3320   aImg->mDecodingMonitor.AssertCurrentThreadIn();
  3322   if (aImg->mDecodeRequest) {
  3323     // If the image is waiting for decode work to be notified, go ahead and do that.
  3324     if (aImg->mDecodeRequest->mRequestStatus == DecodeRequest::REQUEST_WORK_DONE) {
  3325       aImg->FinishedSomeDecoding();
  3329   DecodeSomeOfImage(aImg, aStrategy);
  3331   aImg->FinishedSomeDecoding();
  3333   // If the decoder needs a new frame, enqueue an event to get it; that event
  3334   // will enqueue another decode request when it's done.
  3335   if (aImg->mDecoder && aImg->mDecoder->NeedsNewFrame()) {
  3336     FrameNeededWorker::GetNewFrame(aImg);
  3337   } else {
  3338     // If we aren't yet finished decoding and we have more data in hand, add
  3339     // this request to the back of the priority list.
  3340     if (aImg->mDecoder &&
  3341         !aImg->mError &&
  3342         !aImg->IsDecodeFinished() &&
  3343         aImg->mSourceData.Length() > aImg->mBytesDecoded) {
  3344       RequestDecode(aImg);
  3349 /* static */ void
  3350 RasterImage::DecodePool::StopDecoding(RasterImage* aImg)
  3352   aImg->mDecodingMonitor.AssertCurrentThreadIn();
  3354   // If we haven't got a decode request, we're not currently decoding. (Having
  3355   // a decode request doesn't imply we *are* decoding, though.)
  3356   if (aImg->mDecodeRequest) {
  3357     aImg->mDecodeRequest->mRequestStatus = DecodeRequest::REQUEST_STOPPED;
  3361 NS_IMETHODIMP
  3362 RasterImage::DecodePool::DecodeJob::Run()
  3364   ReentrantMonitorAutoEnter lock(mImage->mDecodingMonitor);
  3366   // If we were interrupted, we shouldn't do any work.
  3367   if (mRequest->mRequestStatus == DecodeRequest::REQUEST_STOPPED) {
  3368     DecodeDoneWorker::NotifyFinishedSomeDecoding(mImage, mRequest);
  3369     return NS_OK;
  3372   // If someone came along and synchronously decoded us, there's nothing for us to do.
  3373   if (!mImage->mDecoder || mImage->IsDecodeFinished()) {
  3374     DecodeDoneWorker::NotifyFinishedSomeDecoding(mImage, mRequest);
  3375     return NS_OK;
  3378   // If we're a decode job that's been enqueued since a previous decode that
  3379   // still needs a new frame, we can't do anything. Wait until the
  3380   // FrameNeededWorker enqueues another frame.
  3381   if (mImage->mDecoder->NeedsNewFrame()) {
  3382     return NS_OK;
  3385   mRequest->mRequestStatus = DecodeRequest::REQUEST_ACTIVE;
  3387   uint32_t oldByteCount = mImage->mBytesDecoded;
  3389   DecodeType type = DECODE_TYPE_UNTIL_DONE_BYTES;
  3391   // Multithreaded decoding can be disabled. If we've done so, we don't want to
  3392   // monopolize the main thread, and will allow a timeout in DecodeSomeOfImage.
  3393   if (NS_IsMainThread()) {
  3394     type = DECODE_TYPE_UNTIL_TIME;
  3397   DecodePool::Singleton()->DecodeSomeOfImage(mImage, DECODE_ASYNC, type, mRequest->mBytesToDecode);
  3399   uint32_t bytesDecoded = mImage->mBytesDecoded - oldByteCount;
  3401   mRequest->mRequestStatus = DecodeRequest::REQUEST_WORK_DONE;
  3403   // If the decoder needs a new frame, enqueue an event to get it; that event
  3404   // will enqueue another decode request when it's done.
  3405   if (mImage->mDecoder && mImage->mDecoder->NeedsNewFrame()) {
  3406     FrameNeededWorker::GetNewFrame(mImage);
  3408   // If we aren't yet finished decoding and we have more data in hand, add
  3409   // this request to the back of the list.
  3410   else if (mImage->mDecoder &&
  3411            !mImage->mError &&
  3412            !mImage->mPendingError &&
  3413            !mImage->IsDecodeFinished() &&
  3414            bytesDecoded < mRequest->mBytesToDecode &&
  3415            bytesDecoded > 0) {
  3416     DecodePool::Singleton()->RequestDecode(mImage);
  3417   } else {
  3418     // Nothing more for us to do - let everyone know what happened.
  3419     DecodeDoneWorker::NotifyFinishedSomeDecoding(mImage, mRequest);
  3422   return NS_OK;
  3425 RasterImage::DecodePool::DecodeJob::~DecodeJob()
  3427   if (gMultithreadedDecoding) {
  3428     // Dispatch mImage to main thread to prevent mImage from being destructed by decode thread.
  3429     nsCOMPtr<nsIThread> mainThread = do_GetMainThread();
  3430     NS_WARN_IF_FALSE(mainThread, "Couldn't get the main thread!");
  3431     if (mainThread) {
  3432       // Handle ambiguous nsISupports inheritance
  3433       RasterImage* rawImg = nullptr;
  3434       mImage.swap(rawImg);
  3435       DebugOnly<nsresult> rv = NS_ProxyRelease(mainThread, NS_ISUPPORTS_CAST(ImageResource*, rawImg));
  3436       MOZ_ASSERT(NS_SUCCEEDED(rv), "Failed to proxy release to main thread");
  3441 nsresult
  3442 RasterImage::DecodePool::DecodeUntilSizeAvailable(RasterImage* aImg)
  3444   MOZ_ASSERT(NS_IsMainThread());
  3445   ReentrantMonitorAutoEnter lock(aImg->mDecodingMonitor);
  3447   if (aImg->mDecodeRequest) {
  3448     // If the image is waiting for decode work to be notified, go ahead and do that.
  3449     if (aImg->mDecodeRequest->mRequestStatus == DecodeRequest::REQUEST_WORK_DONE) {
  3450       nsresult rv = aImg->FinishedSomeDecoding();
  3451       if (NS_FAILED(rv)) {
  3452         aImg->DoError();
  3453         return rv;
  3458   // We use DECODE_ASYNC here because we just want to get the size information
  3459   // here and defer the rest of the work.
  3460   nsresult rv = DecodeSomeOfImage(aImg, DECODE_ASYNC, DECODE_TYPE_UNTIL_SIZE);
  3461   if (NS_FAILED(rv)) {
  3462     return rv;
  3465   // If the decoder needs a new frame, enqueue an event to get it; that event
  3466   // will enqueue another decode request when it's done.
  3467   if (aImg->mDecoder && aImg->mDecoder->NeedsNewFrame()) {
  3468     FrameNeededWorker::GetNewFrame(aImg);
  3469   } else {
  3470     rv = aImg->FinishedSomeDecoding();
  3473   return rv;
  3476 nsresult
  3477 RasterImage::DecodePool::DecodeSomeOfImage(RasterImage* aImg,
  3478                                            DecodeStrategy aStrategy,
  3479                                            DecodeType aDecodeType /* = DECODE_TYPE_UNTIL_TIME */,
  3480                                            uint32_t bytesToDecode /* = 0 */)
  3482   NS_ABORT_IF_FALSE(aImg->mInitialized,
  3483                     "Worker active for uninitialized container!");
  3484   aImg->mDecodingMonitor.AssertCurrentThreadIn();
  3486   // If an error is flagged, it probably happened while we were waiting
  3487   // in the event queue.
  3488   if (aImg->mError)
  3489     return NS_OK;
  3491   // If there is an error worker pending (say because the main thread has enqueued
  3492   // another decode request for us before processing the error worker) then bail out.
  3493   if (aImg->mPendingError)
  3494     return NS_OK;
  3496   // If mDecoded or we don't have a decoder, we must have finished already (for
  3497   // example, a synchronous decode request came while the worker was pending).
  3498   if (!aImg->mDecoder || aImg->mDecoded)
  3499     return NS_OK;
  3501   // If we're doing synchronous decodes, and we're waiting on a new frame for
  3502   // this image, get it now.
  3503   if (aStrategy == DECODE_SYNC && aImg->mDecoder->NeedsNewFrame()) {
  3504     MOZ_ASSERT(NS_IsMainThread());
  3506     aImg->mDecoder->AllocateFrame();
  3507     aImg->mDecodeRequest->mAllocatedNewFrame = true;
  3510   // If we're not synchronous, we can't allocate a frame right now.
  3511   else if (aImg->mDecoder->NeedsNewFrame()) {
  3512     return NS_OK;
  3515   nsRefPtr<Decoder> decoderKungFuDeathGrip = aImg->mDecoder;
  3517   uint32_t maxBytes;
  3518   if (aImg->mDecoder->IsSizeDecode()) {
  3519     // Decode all available data if we're a size decode; they're cheap, and we
  3520     // want them to be more or less synchronous.
  3521     maxBytes = aImg->mSourceData.Length();
  3522   } else {
  3523     // We're only guaranteed to decode this many bytes, so in particular,
  3524     // gDecodeBytesAtATime should be set high enough for us to read the size
  3525     // from most images.
  3526     maxBytes = gDecodeBytesAtATime;
  3529   if (bytesToDecode == 0) {
  3530     bytesToDecode = aImg->mSourceData.Length() - aImg->mBytesDecoded;
  3533   int32_t chunkCount = 0;
  3534   TimeStamp start = TimeStamp::Now();
  3535   TimeStamp deadline = start + TimeDuration::FromMilliseconds(gMaxMSBeforeYield);
  3537   // We keep decoding chunks until:
  3538   //  * we don't have any data left to decode,
  3539   //  * the decode completes,
  3540   //  * we're an UNTIL_SIZE decode and we get the size, or
  3541   //  * we run out of time.
  3542   // We also try to decode at least one "chunk" if we've allocated a new frame,
  3543   // even if we have no more data to send to the decoder.
  3544   while ((aImg->mSourceData.Length() > aImg->mBytesDecoded &&
  3545           bytesToDecode > 0 &&
  3546           !aImg->IsDecodeFinished() &&
  3547           !(aDecodeType == DECODE_TYPE_UNTIL_SIZE && aImg->mHasSize) &&
  3548           !aImg->mDecoder->NeedsNewFrame()) ||
  3549          (aImg->mDecodeRequest && aImg->mDecodeRequest->mAllocatedNewFrame)) {
  3550     chunkCount++;
  3551     uint32_t chunkSize = std::min(bytesToDecode, maxBytes);
  3552     nsresult rv = aImg->DecodeSomeData(chunkSize, aStrategy);
  3553     if (NS_FAILED(rv)) {
  3554       aImg->DoError();
  3555       return rv;
  3558     bytesToDecode -= chunkSize;
  3560     // Yield if we've been decoding for too long. We check this _after_ decoding
  3561     // a chunk to ensure that we don't yield without doing any decoding.
  3562     if (aDecodeType == DECODE_TYPE_UNTIL_TIME && TimeStamp::Now() >= deadline)
  3563       break;
  3566   if (aImg->mDecodeRequest) {
  3567     aImg->mDecodeRequest->mDecodeTime += (TimeStamp::Now() - start);
  3568     aImg->mDecodeRequest->mChunkCount += chunkCount;
  3571   // Flush invalidations (and therefore paint) now that we've decoded all the
  3572   // chunks we're going to.
  3573   //
  3574   // However, don't paint if:
  3575   //
  3576   //  * This was an until-size decode.  Until-size decodes are always followed
  3577   //    by normal decodes, so don't bother painting.
  3578   //
  3579   //  * The decoder flagged an error.  The decoder may have written garbage
  3580   //    into the output buffer; don't paint it to the screen.
  3581   //
  3582   //  * We have all the source data.  This disables progressive display of
  3583   //    previously-decoded images, thus letting us finish decoding faster,
  3584   //    since we don't waste time painting while we decode.
  3585   //    Decoder::PostFrameStop() will flush invalidations once the decode is
  3586   //    done.
  3588   if (aDecodeType != DECODE_TYPE_UNTIL_SIZE &&
  3589       !aImg->mDecoder->HasError() &&
  3590       !aImg->mHasSourceData) {
  3591     aImg->mInDecoder = true;
  3592     aImg->mDecoder->FlushInvalidations();
  3593     aImg->mInDecoder = false;
  3596   return NS_OK;
  3599 RasterImage::DecodeDoneWorker::DecodeDoneWorker(RasterImage* image, DecodeRequest* request)
  3600  : mImage(image)
  3601  , mRequest(request)
  3602 {}
  3604 void
  3605 RasterImage::DecodeDoneWorker::NotifyFinishedSomeDecoding(RasterImage* image, DecodeRequest* request)
  3607   image->mDecodingMonitor.AssertCurrentThreadIn();
  3609   nsCOMPtr<nsIRunnable> worker = new DecodeDoneWorker(image, request);
  3610   NS_DispatchToMainThread(worker);
  3613 NS_IMETHODIMP
  3614 RasterImage::DecodeDoneWorker::Run()
  3616   MOZ_ASSERT(NS_IsMainThread());
  3617   ReentrantMonitorAutoEnter lock(mImage->mDecodingMonitor);
  3619   mImage->FinishedSomeDecoding(eShutdownIntent_Done, mRequest);
  3621   return NS_OK;
  3624 RasterImage::FrameNeededWorker::FrameNeededWorker(RasterImage* image)
  3625  : mImage(image)
  3626 {}
  3629 void
  3630 RasterImage::FrameNeededWorker::GetNewFrame(RasterImage* image)
  3632   nsCOMPtr<nsIRunnable> worker = new FrameNeededWorker(image);
  3633   NS_DispatchToMainThread(worker);
  3636 NS_IMETHODIMP
  3637 RasterImage::FrameNeededWorker::Run()
  3639   ReentrantMonitorAutoEnter lock(mImage->mDecodingMonitor);
  3640   nsresult rv = NS_OK;
  3642   // If we got a synchronous decode in the mean time, we don't need to do
  3643   // anything.
  3644   if (mImage->mDecoder && mImage->mDecoder->NeedsNewFrame()) {
  3645     rv = mImage->mDecoder->AllocateFrame();
  3646     mImage->mDecodeRequest->mAllocatedNewFrame = true;
  3649   if (NS_SUCCEEDED(rv) && mImage->mDecoder) {
  3650     // By definition, we're not done decoding, so enqueue us for more decoding.
  3651     DecodePool::Singleton()->RequestDecode(mImage);
  3654   return NS_OK;
  3657 } // namespace image
  3658 } // namespace mozilla

mercurial