image/src/RasterImage.h

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
     2  *
     3  * This Source Code Form is subject to the terms of the Mozilla Public
     4  * License, v. 2.0. If a copy of the MPL was not distributed with this
     5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     7 /** @file
     8  * This file declares the RasterImage class, which
     9  * handles static and animated rasterized images.
    10  *
    11  * @author  Stuart Parmenter <pavlov@netscape.com>
    12  * @author  Chris Saari <saari@netscape.com>
    13  * @author  Arron Mogge <paper@animecity.nu>
    14  * @author  Andrew Smith <asmith15@learn.senecac.on.ca>
    15  */
    17 #ifndef mozilla_imagelib_RasterImage_h_
    18 #define mozilla_imagelib_RasterImage_h_
    20 #include "Image.h"
    21 #include "FrameBlender.h"
    22 #include "nsCOMPtr.h"
    23 #include "imgIContainer.h"
    24 #include "nsIProperties.h"
    25 #include "nsTArray.h"
    26 #include "imgFrame.h"
    27 #include "nsThreadUtils.h"
    28 #include "DecodeStrategy.h"
    29 #include "DiscardTracker.h"
    30 #include "Orientation.h"
    31 #include "nsIObserver.h"
    32 #include "mozilla/MemoryReporting.h"
    33 #include "mozilla/Mutex.h"
    34 #include "mozilla/ReentrantMonitor.h"
    35 #include "mozilla/TimeStamp.h"
    36 #include "mozilla/StaticPtr.h"
    37 #include "mozilla/WeakPtr.h"
    38 #ifdef DEBUG
    39   #include "imgIContainerDebug.h"
    40 #endif
    42 class nsIInputStream;
    43 class nsIThreadPool;
    44 class nsIRequest;
    46 #define NS_RASTERIMAGE_CID \
    47 { /* 376ff2c1-9bf6-418a-b143-3340c00112f7 */         \
    48      0x376ff2c1,                                     \
    49      0x9bf6,                                         \
    50      0x418a,                                         \
    51     {0xb1, 0x43, 0x33, 0x40, 0xc0, 0x01, 0x12, 0xf7} \
    52 }
    54 /**
    55  * Handles static and animated image containers.
    56  *
    57  *
    58  * @par A Quick Walk Through
    59  * The decoder initializes this class and calls AppendFrame() to add a frame.
    60  * Once RasterImage detects more than one frame, it starts the animation
    61  * with StartAnimation(). Note that the invalidation events for RasterImage are
    62  * generated automatically using nsRefreshDriver.
    63  *
    64  * @par
    65  * StartAnimation() initializes the animation helper object and sets the time
    66  * the first frame was displayed to the current clock time.
    67  *
    68  * @par
    69  * When the refresh driver corresponding to the imgIContainer that this image is
    70  * a part of notifies the RasterImage that it's time to invalidate,
    71  * RequestRefresh() is called with a given TimeStamp to advance to. As long as
    72  * the timeout of the given frame (the frame's "delay") plus the time that frame
    73  * was first displayed is less than or equal to the TimeStamp given,
    74  * RequestRefresh() calls AdvanceFrame().
    75  *
    76  * @par
    77  * AdvanceFrame() is responsible for advancing a single frame of the animation.
    78  * It can return true, meaning that the frame advanced, or false, meaning that
    79  * the frame failed to advance (usually because the next frame hasn't been
    80  * decoded yet). It is also responsible for performing the final animation stop
    81  * procedure if the final frame of a non-looping animation is reached.
    82  *
    83  * @par
    84  * Each frame can have a different method of removing itself. These are
    85  * listed as imgIContainer::cDispose... constants.  Notify() calls
    86  * DoComposite() to handle any special frame destruction.
    87  *
    88  * @par
    89  * The basic path through DoComposite() is:
    90  * 1) Calculate Area that needs updating, which is at least the area of
    91  *    aNextFrame.
    92  * 2) Dispose of previous frame.
    93  * 3) Draw new image onto compositingFrame.
    94  * See comments in DoComposite() for more information and optimizations.
    95  *
    96  * @par
    97  * The rest of the RasterImage specific functions are used by DoComposite to
    98  * destroy the old frame and build the new one.
    99  *
   100  * @note
   101  * <li> "Mask", "Alpha", and "Alpha Level" are interchangeable phrases in
   102  * respects to RasterImage.
   103  *
   104  * @par
   105  * <li> GIFs never have more than a 1 bit alpha.
   106  * <li> APNGs may have a full alpha channel.
   107  *
   108  * @par
   109  * <li> Background color specified in GIF is ignored by web browsers.
   110  *
   111  * @par
   112  * <li> If Frame 3 wants to dispose by restoring previous, what it wants is to
   113  * restore the composition up to and including Frame 2, as well as Frame 2s
   114  * disposal.  So, in the middle of DoComposite when composing Frame 3, right
   115  * after destroying Frame 2's area, we copy compositingFrame to
   116  * prevCompositingFrame.  When DoComposite gets called to do Frame 4, we
   117  * copy prevCompositingFrame back, and then draw Frame 4 on top.
   118  *
   119  * @par
   120  * The mAnim structure has members only needed for animated images, so
   121  * it's not allocated until the second frame is added.
   122  */
   124 class ScaleRequest;
   126 namespace mozilla {
   128 namespace layers {
   129 class LayerManager;
   130 class ImageContainer;
   131 class Image;
   132 }
   134 namespace image {
   136 class Decoder;
   137 class FrameAnimator;
   139 class RasterImage : public ImageResource
   140                   , public nsIProperties
   141                   , public SupportsWeakPtr<RasterImage>
   142 #ifdef DEBUG
   143                   , public imgIContainerDebug
   144 #endif
   145 {
   146 public:
   147   MOZ_DECLARE_REFCOUNTED_TYPENAME(RasterImage)
   148   NS_DECL_THREADSAFE_ISUPPORTS
   149   NS_DECL_NSIPROPERTIES
   150   NS_DECL_IMGICONTAINER
   151 #ifdef DEBUG
   152   NS_DECL_IMGICONTAINERDEBUG
   153 #endif
   155   // (no public constructor - use ImageFactory)
   156   virtual ~RasterImage();
   158   virtual nsresult StartAnimation();
   159   virtual nsresult StopAnimation();
   161   // Methods inherited from Image
   162   nsresult Init(const char* aMimeType,
   163                 uint32_t aFlags);
   164   virtual nsIntRect FrameRect(uint32_t aWhichFrame) MOZ_OVERRIDE;
   166   // Raster-specific methods
   167   static NS_METHOD WriteToRasterImage(nsIInputStream* aIn, void* aClosure,
   168                                       const char* aFromRawSegment,
   169                                       uint32_t aToOffset, uint32_t aCount,
   170                                       uint32_t* aWriteCount);
   172   /* The index of the current frame that would be drawn if the image was to be
   173    * drawn now. */
   174   uint32_t GetCurrentFrameIndex();
   176   /* The total number of frames in this image. */
   177   uint32_t GetNumFrames() const;
   179   virtual size_t HeapSizeOfSourceWithComputedFallback(mozilla::MallocSizeOf aMallocSizeOf) const;
   180   virtual size_t HeapSizeOfDecodedWithComputedFallback(mozilla::MallocSizeOf aMallocSizeOf) const;
   181   virtual size_t NonHeapSizeOfDecoded() const;
   182   virtual size_t OutOfProcessSizeOfDecoded() const;
   184   /* Triggers discarding. */
   185   void Discard(bool force = false);
   186   void ForceDiscard() { Discard(/* force = */ true); }
   188   /* Callbacks for decoders */
   189   nsresult SetFrameAsNonPremult(uint32_t aFrameNum, bool aIsNonPremult);
   191   /** Sets the size and inherent orientation of the container. This should only
   192    * be called by the decoder. This function may be called multiple times, but
   193    * will throw an error if subsequent calls do not match the first.
   194    */
   195   nsresult SetSize(int32_t aWidth, int32_t aHeight, Orientation aOrientation);
   197   /**
   198    * Ensures that a given frame number exists with the given parameters, and
   199    * returns pointers to the data storage for that frame.
   200    * It is not possible to create sparse frame arrays; you can only append
   201    * frames to the current frame array.
   202    */
   203   nsresult EnsureFrame(uint32_t aFramenum, int32_t aX, int32_t aY,
   204                        int32_t aWidth, int32_t aHeight,
   205                        gfxImageFormat aFormat,
   206                        uint8_t aPaletteDepth,
   207                        uint8_t** imageData,
   208                        uint32_t* imageLength,
   209                        uint32_t** paletteData,
   210                        uint32_t* paletteLength,
   211                        imgFrame** aFrame);
   213   /**
   214    * A shorthand for EnsureFrame, above, with aPaletteDepth = 0 and paletteData
   215    * and paletteLength set to null.
   216    */
   217   nsresult EnsureFrame(uint32_t aFramenum, int32_t aX, int32_t aY,
   218                        int32_t aWidth, int32_t aHeight,
   219                        gfxImageFormat aFormat,
   220                        uint8_t** imageData,
   221                        uint32_t* imageLength,
   222                        imgFrame** aFrame);
   224   /* notification that the entire image has been decoded */
   225   nsresult DecodingComplete();
   227   /**
   228    * Number of times to loop the image.
   229    * @note -1 means forever.
   230    */
   231   void     SetLoopCount(int32_t aLoopCount);
   233   /* Add compressed source data to the imgContainer.
   234    *
   235    * The decoder will use this data, either immediately or at draw time, to
   236    * decode the image.
   237    *
   238    * XXX This method's only caller (WriteToContainer) ignores the return
   239    * value. Should this just return void?
   240    */
   241   nsresult AddSourceData(const char *aBuffer, uint32_t aCount);
   243   virtual nsresult OnImageDataAvailable(nsIRequest* aRequest,
   244                                         nsISupports* aContext,
   245                                         nsIInputStream* aInStr,
   246                                         uint64_t aSourceOffset,
   247                                         uint32_t aCount) MOZ_OVERRIDE;
   248   virtual nsresult OnImageDataComplete(nsIRequest* aRequest,
   249                                        nsISupports* aContext,
   250                                        nsresult aStatus,
   251                                        bool aLastPart) MOZ_OVERRIDE;
   252   virtual nsresult OnNewSourceData() MOZ_OVERRIDE;
   254   static already_AddRefed<nsIEventTarget> GetEventTarget() {
   255     return DecodePool::Singleton()->GetEventTarget();
   256   }
   258   /**
   259    * A hint of the number of bytes of source data that the image contains. If
   260    * called early on, this can help reduce copying and reallocations by
   261    * appropriately preallocating the source data buffer.
   262    *
   263    * We take this approach rather than having the source data management code do
   264    * something more complicated (like chunklisting) because HTTP is by far the
   265    * dominant source of images, and the Content-Length header is quite reliable.
   266    * Thus, pre-allocation simplifies code and reduces the total number of
   267    * allocations.
   268    */
   269   nsresult SetSourceSizeHint(uint32_t sizeHint);
   271   /* Provide a hint for the requested resolution of the resulting image. */
   272   void SetRequestedResolution(const nsIntSize requestedResolution) {
   273     mRequestedResolution = requestedResolution;
   274   }
   276   nsIntSize GetRequestedResolution() {
   277     return mRequestedResolution;
   278   }
   279   /* Provide a hint for the requested dimension of the resulting image. */
   280   void SetRequestedSampleSize(int requestedSampleSize) {
   281     mRequestedSampleSize = requestedSampleSize;
   282   }
   284   int GetRequestedSampleSize() {
   285     return mRequestedSampleSize;
   286   }
   290  nsCString GetURIString() {
   291     nsCString spec;
   292     if (GetURI()) {
   293       GetURI()->GetSpec(spec);
   294     }
   295     return spec;
   296   }
   298   // Called from module startup. Sets up RasterImage to be used.
   299   static void Initialize();
   301   enum ScaleStatus
   302   {
   303     SCALE_INVALID,
   304     SCALE_PENDING,
   305     SCALE_DONE
   306   };
   308   // Call this with a new ScaleRequest to mark this RasterImage's scale result
   309   // as waiting for the results of this request. You call to ScalingDone before
   310   // request is destroyed!
   311   void ScalingStart(ScaleRequest* request);
   313   // Call this with a finished ScaleRequest to set this RasterImage's scale
   314   // result. Give it a ScaleStatus of SCALE_DONE if everything succeeded, and
   315   // SCALE_INVALID otherwise.
   316   void ScalingDone(ScaleRequest* request, ScaleStatus status);
   318   // Decoder shutdown
   319   enum eShutdownIntent {
   320     eShutdownIntent_Done        = 0,
   321     eShutdownIntent_NotNeeded   = 1,
   322     eShutdownIntent_Error       = 2,
   323     eShutdownIntent_AllCount    = 3
   324   };
   326   // Decode strategy
   328 private:
   329   already_AddRefed<imgStatusTracker> CurrentStatusTracker()
   330   {
   331     mDecodingMonitor.AssertCurrentThreadIn();
   332     nsRefPtr<imgStatusTracker> statusTracker;
   333     statusTracker = mDecodeRequest ? mDecodeRequest->mStatusTracker
   334                                    : mStatusTracker;
   335     MOZ_ASSERT(statusTracker);
   336     return statusTracker.forget();
   337   }
   339   nsresult OnImageDataCompleteCore(nsIRequest* aRequest, nsISupports*, nsresult aStatus);
   341   /**
   342    * Each RasterImage has a pointer to one or zero heap-allocated
   343    * DecodeRequests.
   344    */
   345   struct DecodeRequest
   346   {
   347     DecodeRequest(RasterImage* aImage)
   348       : mImage(aImage)
   349       , mBytesToDecode(0)
   350       , mRequestStatus(REQUEST_INACTIVE)
   351       , mChunkCount(0)
   352       , mAllocatedNewFrame(false)
   353     {
   354       MOZ_ASSERT(aImage, "aImage cannot be null");
   355       MOZ_ASSERT(aImage->mStatusTracker,
   356                  "aImage should have an imgStatusTracker");
   357       mStatusTracker = aImage->mStatusTracker->CloneForRecording();
   358     }
   360     NS_INLINE_DECL_THREADSAFE_REFCOUNTING(DecodeRequest)
   362     // The status tracker that is associated with a given decode request, to
   363     // ensure their lifetimes are linked.
   364     nsRefPtr<imgStatusTracker> mStatusTracker;
   366     RasterImage* mImage;
   368     uint32_t mBytesToDecode;
   370     enum DecodeRequestStatus
   371     {
   372       REQUEST_INACTIVE,
   373       REQUEST_PENDING,
   374       REQUEST_ACTIVE,
   375       REQUEST_WORK_DONE,
   376       REQUEST_STOPPED
   377     } mRequestStatus;
   379     /* Keeps track of how much time we've burned decoding this particular decode
   380      * request. */
   381     TimeDuration mDecodeTime;
   383     /* The number of chunks it took to decode this image. */
   384     int32_t mChunkCount;
   386     /* True if a new frame has been allocated, but DecodeSomeData hasn't yet
   387      * been called to flush data to it */
   388     bool mAllocatedNewFrame;
   389   };
   391   /*
   392    * DecodePool is a singleton class we use when decoding large images.
   393    *
   394    * When we wish to decode an image larger than
   395    * image.mem.max_bytes_for_sync_decode, we call DecodePool::RequestDecode()
   396    * for the image.  This adds the image to a queue of pending requests and posts
   397    * the DecodePool singleton to the event queue, if it's not already pending
   398    * there.
   399    *
   400    * When the DecodePool is run from the event queue, it decodes the image (and
   401    * all others it's managing) in chunks, periodically yielding control back to
   402    * the event loop.
   403    */
   404   class DecodePool : public nsIObserver
   405   {
   406   public:
   407     NS_DECL_THREADSAFE_ISUPPORTS
   408     NS_DECL_NSIOBSERVER
   410     static DecodePool* Singleton();
   412     /**
   413      * Ask the DecodePool to asynchronously decode this image.
   414      */
   415     void RequestDecode(RasterImage* aImg);
   417     /**
   418      * Decode aImg for a short amount of time, and post the remainder to the
   419      * queue.
   420      */
   421     void DecodeABitOf(RasterImage* aImg, DecodeStrategy aStrategy);
   423     /**
   424      * Ask the DecodePool to stop decoding this image.  Internally, we also
   425      * call this function when we finish decoding an image.
   426      *
   427      * Since the DecodePool keeps raw pointers to RasterImages, make sure you
   428      * call this before a RasterImage is destroyed!
   429      */
   430     static void StopDecoding(RasterImage* aImg);
   432     /**
   433      * Synchronously decode the beginning of the image until we run out of
   434      * bytes or we get the image's size.  Note that this done on a best-effort
   435      * basis; if the size is burried too deep in the image, we'll give up.
   436      *
   437      * @return NS_ERROR if an error is encountered, and NS_OK otherwise.  (Note
   438      *         that we return NS_OK even when the size was not found.)
   439      */
   440     nsresult DecodeUntilSizeAvailable(RasterImage* aImg);
   442     /**
   443      * Returns an event target interface to the thread pool; primarily for
   444      * OnDataAvailable delivery off main thread.
   445      *
   446      * @return An nsIEventTarget interface to mThreadPool.
   447      */
   448     already_AddRefed<nsIEventTarget> GetEventTarget();
   450     virtual ~DecodePool();
   452   private: /* statics */
   453     static StaticRefPtr<DecodePool> sSingleton;
   455   private: /* methods */
   456     DecodePool();
   458     enum DecodeType {
   459       DECODE_TYPE_UNTIL_TIME,
   460       DECODE_TYPE_UNTIL_SIZE,
   461       DECODE_TYPE_UNTIL_DONE_BYTES
   462     };
   464     /* Decode some chunks of the given image.  If aDecodeType is UNTIL_SIZE,
   465      * decode until we have the image's size, then stop. If bytesToDecode is
   466      * non-0, at most bytesToDecode bytes will be decoded. if aDecodeType is
   467      * UNTIL_DONE_BYTES, decode until all bytesToDecode bytes are decoded.
   468      */
   469     nsresult DecodeSomeOfImage(RasterImage* aImg,
   470                                DecodeStrategy aStrategy,
   471                                DecodeType aDecodeType = DECODE_TYPE_UNTIL_TIME,
   472                                uint32_t bytesToDecode = 0);
   474     /* A decode job dispatched to a thread pool by DecodePool.
   475      */
   476     class DecodeJob : public nsRunnable
   477     {
   478     public:
   479       DecodeJob(DecodeRequest* aRequest, RasterImage* aImg)
   480         : mRequest(aRequest)
   481         , mImage(aImg)
   482       {}
   484       NS_IMETHOD Run();
   486     protected:
   487       virtual ~DecodeJob();
   489     private:
   490       nsRefPtr<DecodeRequest> mRequest;
   491       nsRefPtr<RasterImage> mImage;
   492     };
   494   private: /* members */
   496     // mThreadPoolMutex protects mThreadPool. For all RasterImages R,
   497     // R::mDecodingMonitor must be acquired before mThreadPoolMutex
   498     // if both are acquired; the other order may cause deadlock.
   499     mozilla::Mutex            mThreadPoolMutex;
   500     nsCOMPtr<nsIThreadPool>   mThreadPool;
   501   };
   503   class DecodeDoneWorker : public nsRunnable
   504   {
   505   public:
   506     /**
   507      * Called by the DecodePool with an image when it's done some significant
   508      * portion of decoding that needs to be notified about.
   509      *
   510      * Ensures the decode state accumulated by the decoding process gets
   511      * applied to the image.
   512      */
   513     static void NotifyFinishedSomeDecoding(RasterImage* image, DecodeRequest* request);
   515     NS_IMETHOD Run();
   517   private: /* methods */
   518     DecodeDoneWorker(RasterImage* image, DecodeRequest* request);
   520   private: /* members */
   522     nsRefPtr<RasterImage> mImage;
   523     nsRefPtr<DecodeRequest> mRequest;
   524   };
   526   class FrameNeededWorker : public nsRunnable
   527   {
   528   public:
   529     /**
   530      * Called by the DecodeJob with an image when it's been told by the
   531      * decoder that it needs a new frame to be allocated on the main thread.
   532      *
   533      * Dispatches an event to do so, which will further dispatch a
   534      * DecodeRequest event to continue decoding.
   535      */
   536     static void GetNewFrame(RasterImage* image);
   538     NS_IMETHOD Run();
   540   private: /* methods */
   541     FrameNeededWorker(RasterImage* image);
   543   private: /* members */
   545     nsRefPtr<RasterImage> mImage;
   546   };
   548   nsresult FinishedSomeDecoding(eShutdownIntent intent = eShutdownIntent_Done,
   549                                 DecodeRequest* request = nullptr);
   551   bool DrawWithPreDownscaleIfNeeded(imgFrame *aFrame,
   552                                     gfxContext *aContext,
   553                                     GraphicsFilter aFilter,
   554                                     const gfxMatrix &aUserSpaceToImageSpace,
   555                                     const gfxRect &aFill,
   556                                     const nsIntRect &aSubimage,
   557                                     uint32_t aFlags);
   559   nsresult CopyFrame(uint32_t aWhichFrame,
   560                      uint32_t aFlags,
   561                      gfxImageSurface **_retval);
   563   /**
   564    * Deletes and nulls out the frame in mFrames[framenum].
   565    *
   566    * Does not change the size of mFrames.
   567    *
   568    * @param framenum The index of the frame to be deleted.
   569    *                 Must lie in [0, mFrames.Length() )
   570    */
   571   void DeleteImgFrame(uint32_t framenum);
   573   imgFrame* GetImgFrameNoDecode(uint32_t framenum);
   574   imgFrame* GetImgFrame(uint32_t framenum);
   575   imgFrame* GetDrawableImgFrame(uint32_t framenum);
   576   imgFrame* GetCurrentImgFrame();
   577   uint32_t GetCurrentImgFrameIndex() const;
   579   size_t SizeOfDecodedWithComputedFallbackIfHeap(gfxMemoryLocation aLocation,
   580                                                  mozilla::MallocSizeOf aMallocSizeOf) const;
   582   void EnsureAnimExists();
   584   nsresult InternalAddFrameHelper(uint32_t framenum, imgFrame *frame,
   585                                   uint8_t **imageData, uint32_t *imageLength,
   586                                   uint32_t **paletteData, uint32_t *paletteLength,
   587                                   imgFrame** aRetFrame);
   588   nsresult InternalAddFrame(uint32_t framenum, int32_t aX, int32_t aY, int32_t aWidth, int32_t aHeight,
   589                             gfxImageFormat aFormat, uint8_t aPaletteDepth,
   590                             uint8_t **imageData, uint32_t *imageLength,
   591                             uint32_t **paletteData, uint32_t *paletteLength,
   592                             imgFrame** aRetFrame);
   594   nsresult DoImageDataComplete();
   596   bool ApplyDecodeFlags(uint32_t aNewFlags, uint32_t aWhichFrame);
   598   already_AddRefed<layers::Image> GetCurrentImage();
   599   void UpdateImageContainer();
   601   void SetInUpdateImageContainer(bool aInUpdate) { mInUpdateImageContainer = aInUpdate; }
   602   bool IsInUpdateImageContainer() { return mInUpdateImageContainer; }
   603   enum RequestDecodeType {
   604       ASYNCHRONOUS,
   605       SYNCHRONOUS_NOTIFY,
   606       SYNCHRONOUS_NOTIFY_AND_SOME_DECODE
   607   };
   608   NS_IMETHOD RequestDecodeCore(RequestDecodeType aDecodeType);
   610   // We would like to just check if we have a zero lock count, but we can't do
   611   // that for animated images because in EnsureAnimExists we lock the image and
   612   // never unlock so that animated images always have their lock count >= 1. In
   613   // that case we use our animation consumers count as a proxy for lock count.
   614   bool IsUnlocked() { return (mLockCount == 0 || (mAnim && mAnimationConsumers == 0)); }
   616 private: // data
   617   nsIntSize                  mSize;
   618   Orientation                mOrientation;
   620   // Whether our frames were decoded using any special flags.
   621   // Some flags (e.g. unpremultiplied data) may not be compatible
   622   // with the browser's needs for displaying the image to the user.
   623   // As such, we may need to redecode if we're being asked for
   624   // a frame with different flags.  0 indicates default flags.
   625   //
   626   // Valid flag bits are imgIContainer::FLAG_DECODE_NO_PREMULTIPLY_ALPHA
   627   // and imgIContainer::FLAG_DECODE_NO_COLORSPACE_CONVERSION.
   628   uint32_t                   mFrameDecodeFlags;
   630   //! All the frames of the image
   631   FrameBlender              mFrameBlender;
   633   // The last frame we decoded for multipart images.
   634   imgFrame*                  mMultipartDecodedFrame;
   636   nsCOMPtr<nsIProperties>    mProperties;
   638   // IMPORTANT: if you use mAnim in a method, call EnsureImageIsDecoded() first to ensure
   639   // that the frames actually exist (they may have been discarded to save memory, or
   640   // we maybe decoding on draw).
   641   FrameAnimator* mAnim;
   643   // Discard members
   644   uint32_t                   mLockCount;
   645   DiscardTracker::Node       mDiscardTrackerNode;
   647   // Source data members
   648   nsCString                  mSourceDataMimeType;
   650   friend class DiscardTracker;
   652   // How many times we've decoded this image.
   653   // This is currently only used for statistics
   654   int32_t                        mDecodeCount;
   656   // If the image contains multiple resolutions, a hint as to which one should be used
   657   nsIntSize                  mRequestedResolution;
   659   // A hint for image decoder that directly scale the image to smaller buffer
   660   int                        mRequestedSampleSize;
   662   // Cached value for GetImageContainer.
   663   nsRefPtr<mozilla::layers::ImageContainer> mImageContainer;
   665   // If not cached in mImageContainer, this might have our image container
   666   WeakPtr<mozilla::layers::ImageContainer> mImageContainerCache;
   668 #ifdef DEBUG
   669   uint32_t                       mFramesNotified;
   670 #endif
   672   // Below are the pieces of data that can be accessed on more than one thread
   673   // at once, and hence need to be locked by mDecodingMonitor.
   675   // BEGIN LOCKED MEMBER VARIABLES
   676   mozilla::ReentrantMonitor  mDecodingMonitor;
   678   FallibleTArray<char>       mSourceData;
   680   // Decoder and friends
   681   nsRefPtr<Decoder>          mDecoder;
   682   nsRefPtr<DecodeRequest>    mDecodeRequest;
   683   uint32_t                   mBytesDecoded;
   685   bool                       mInDecoder;
   686   // END LOCKED MEMBER VARIABLES
   688   // Notification state. Used to avoid recursive notifications.
   689   ImageStatusDiff            mStatusDiff;
   690   bool                       mNotifying:1;
   692   // Boolean flags (clustered together to conserve space):
   693   bool                       mHasSize:1;       // Has SetSize() been called?
   694   bool                       mDecodeOnDraw:1;  // Decoding on draw?
   695   bool                       mMultipart:1;     // Multipart?
   696   bool                       mDiscardable:1;   // Is container discardable?
   697   bool                       mHasSourceData:1; // Do we have source data?
   699   // Do we have the frames in decoded form?
   700   bool                       mDecoded:1;
   701   bool                       mHasBeenDecoded:1;
   704   // Whether the animation can stop, due to running out
   705   // of frames, or no more owning request
   706   bool                       mAnimationFinished:1;
   708   // Whether we're calling Decoder::Finish() from ShutdownDecoder.
   709   bool                       mFinishing:1;
   711   bool                       mInUpdateImageContainer:1;
   713   // Whether, once we are done doing a size decode, we should immediately kick
   714   // off a full decode.
   715   bool                       mWantFullDecode:1;
   717   // Set when a decode worker detects an error off-main-thread. Once the error
   718   // is handled on the main thread, mError is set, but mPendingError is used to
   719   // stop decode work immediately.
   720   bool                       mPendingError:1;
   722   // Decoding
   723   nsresult RequestDecodeIfNeeded(nsresult aStatus,
   724                                  eShutdownIntent aIntent,
   725                                  bool aDone,
   726                                  bool aWasSize);
   727   nsresult WantDecodedFrames();
   728   nsresult SyncDecode();
   729   nsresult InitDecoder(bool aDoSizeDecode);
   730   nsresult WriteToDecoder(const char *aBuffer, uint32_t aCount, DecodeStrategy aStrategy);
   731   nsresult DecodeSomeData(uint32_t aMaxBytes, DecodeStrategy aStrategy);
   732   bool     IsDecodeFinished();
   733   TimeStamp mDrawStartTime;
   735   inline bool CanQualityScale(const gfxSize& scale);
   736   inline bool CanScale(GraphicsFilter aFilter, gfxSize aScale, uint32_t aFlags);
   738   struct ScaleResult
   739   {
   740     ScaleResult()
   741      : status(SCALE_INVALID)
   742     {}
   744     gfxSize scale;
   745     nsAutoPtr<imgFrame> frame;
   746     ScaleStatus status;
   747   };
   749   ScaleResult mScaleResult;
   751   // We hold on to a bare pointer to a ScaleRequest while it's outstanding so
   752   // we can mark it as stopped if necessary. The ScaleWorker/DrawWorker duo
   753   // will inform us when to let go of this pointer.
   754   ScaleRequest* mScaleRequest;
   756   // Initializes imgStatusTracker and resets it on RasterImage destruction.
   757   nsAutoPtr<imgStatusTrackerInit> mStatusTrackerInit;
   759   nsresult ShutdownDecoder(eShutdownIntent aIntent);
   761   // Error handling.
   762   void DoError();
   764   class HandleErrorWorker : public nsRunnable
   765   {
   766   public:
   767     /**
   768      * Called from decoder threads when DoError() is called, since errors can't
   769      * be handled safely off-main-thread. Dispatches an event which reinvokes
   770      * DoError on the main thread if there isn't one already pending.
   771      */
   772     static void DispatchIfNeeded(RasterImage* aImage);
   774     NS_IMETHOD Run();
   776   private:
   777     HandleErrorWorker(RasterImage* aImage);
   779     nsRefPtr<RasterImage> mImage;
   780   };
   782   // Helpers
   783   bool CanDiscard();
   784   bool CanForciblyDiscard();
   785   bool CanForciblyDiscardAndRedecode();
   786   bool DiscardingActive();
   787   bool StoringSourceData() const;
   789 protected:
   790   RasterImage(imgStatusTracker* aStatusTracker = nullptr,
   791               ImageURL* aURI = nullptr);
   793   bool ShouldAnimate();
   795   friend class ImageFactory;
   796 };
   798 inline NS_IMETHODIMP RasterImage::GetAnimationMode(uint16_t *aAnimationMode) {
   799   return GetAnimationModeInternal(aAnimationMode);
   800 }
   802 // Asynchronous Decode Requestor
   803 //
   804 // We use this class when someone calls requestDecode() from within a decode
   805 // notification. Since requestDecode() involves modifying the decoder's state
   806 // (for example, possibly shutting down a header-only decode and starting a
   807 // full decode), we don't want to do this from inside a decoder.
   808 class imgDecodeRequestor : public nsRunnable
   809 {
   810   public:
   811     imgDecodeRequestor(RasterImage &aContainer) {
   812       mContainer = aContainer.asWeakPtr();
   813     }
   814     NS_IMETHOD Run() {
   815       if (mContainer)
   816         mContainer->StartDecoding();
   817       return NS_OK;
   818     }
   820   private:
   821     WeakPtr<RasterImage> mContainer;
   822 };
   824 } // namespace image
   825 } // namespace mozilla
   827 #endif /* mozilla_imagelib_RasterImage_h_ */

mercurial