image/src/RasterImage.h

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/image/src/RasterImage.h	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,827 @@
     1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
     1.5 + *
     1.6 + * This Source Code Form is subject to the terms of the Mozilla Public
     1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.9 +
    1.10 +/** @file
    1.11 + * This file declares the RasterImage class, which
    1.12 + * handles static and animated rasterized images.
    1.13 + *
    1.14 + * @author  Stuart Parmenter <pavlov@netscape.com>
    1.15 + * @author  Chris Saari <saari@netscape.com>
    1.16 + * @author  Arron Mogge <paper@animecity.nu>
    1.17 + * @author  Andrew Smith <asmith15@learn.senecac.on.ca>
    1.18 + */
    1.19 +
    1.20 +#ifndef mozilla_imagelib_RasterImage_h_
    1.21 +#define mozilla_imagelib_RasterImage_h_
    1.22 +
    1.23 +#include "Image.h"
    1.24 +#include "FrameBlender.h"
    1.25 +#include "nsCOMPtr.h"
    1.26 +#include "imgIContainer.h"
    1.27 +#include "nsIProperties.h"
    1.28 +#include "nsTArray.h"
    1.29 +#include "imgFrame.h"
    1.30 +#include "nsThreadUtils.h"
    1.31 +#include "DecodeStrategy.h"
    1.32 +#include "DiscardTracker.h"
    1.33 +#include "Orientation.h"
    1.34 +#include "nsIObserver.h"
    1.35 +#include "mozilla/MemoryReporting.h"
    1.36 +#include "mozilla/Mutex.h"
    1.37 +#include "mozilla/ReentrantMonitor.h"
    1.38 +#include "mozilla/TimeStamp.h"
    1.39 +#include "mozilla/StaticPtr.h"
    1.40 +#include "mozilla/WeakPtr.h"
    1.41 +#ifdef DEBUG
    1.42 +  #include "imgIContainerDebug.h"
    1.43 +#endif
    1.44 +
    1.45 +class nsIInputStream;
    1.46 +class nsIThreadPool;
    1.47 +class nsIRequest;
    1.48 +
    1.49 +#define NS_RASTERIMAGE_CID \
    1.50 +{ /* 376ff2c1-9bf6-418a-b143-3340c00112f7 */         \
    1.51 +     0x376ff2c1,                                     \
    1.52 +     0x9bf6,                                         \
    1.53 +     0x418a,                                         \
    1.54 +    {0xb1, 0x43, 0x33, 0x40, 0xc0, 0x01, 0x12, 0xf7} \
    1.55 +}
    1.56 +
    1.57 +/**
    1.58 + * Handles static and animated image containers.
    1.59 + *
    1.60 + *
    1.61 + * @par A Quick Walk Through
    1.62 + * The decoder initializes this class and calls AppendFrame() to add a frame.
    1.63 + * Once RasterImage detects more than one frame, it starts the animation
    1.64 + * with StartAnimation(). Note that the invalidation events for RasterImage are
    1.65 + * generated automatically using nsRefreshDriver.
    1.66 + *
    1.67 + * @par
    1.68 + * StartAnimation() initializes the animation helper object and sets the time
    1.69 + * the first frame was displayed to the current clock time.
    1.70 + *
    1.71 + * @par
    1.72 + * When the refresh driver corresponding to the imgIContainer that this image is
    1.73 + * a part of notifies the RasterImage that it's time to invalidate,
    1.74 + * RequestRefresh() is called with a given TimeStamp to advance to. As long as
    1.75 + * the timeout of the given frame (the frame's "delay") plus the time that frame
    1.76 + * was first displayed is less than or equal to the TimeStamp given,
    1.77 + * RequestRefresh() calls AdvanceFrame().
    1.78 + *
    1.79 + * @par
    1.80 + * AdvanceFrame() is responsible for advancing a single frame of the animation.
    1.81 + * It can return true, meaning that the frame advanced, or false, meaning that
    1.82 + * the frame failed to advance (usually because the next frame hasn't been
    1.83 + * decoded yet). It is also responsible for performing the final animation stop
    1.84 + * procedure if the final frame of a non-looping animation is reached.
    1.85 + *
    1.86 + * @par
    1.87 + * Each frame can have a different method of removing itself. These are
    1.88 + * listed as imgIContainer::cDispose... constants.  Notify() calls
    1.89 + * DoComposite() to handle any special frame destruction.
    1.90 + *
    1.91 + * @par
    1.92 + * The basic path through DoComposite() is:
    1.93 + * 1) Calculate Area that needs updating, which is at least the area of
    1.94 + *    aNextFrame.
    1.95 + * 2) Dispose of previous frame.
    1.96 + * 3) Draw new image onto compositingFrame.
    1.97 + * See comments in DoComposite() for more information and optimizations.
    1.98 + *
    1.99 + * @par
   1.100 + * The rest of the RasterImage specific functions are used by DoComposite to
   1.101 + * destroy the old frame and build the new one.
   1.102 + *
   1.103 + * @note
   1.104 + * <li> "Mask", "Alpha", and "Alpha Level" are interchangeable phrases in
   1.105 + * respects to RasterImage.
   1.106 + *
   1.107 + * @par
   1.108 + * <li> GIFs never have more than a 1 bit alpha.
   1.109 + * <li> APNGs may have a full alpha channel.
   1.110 + *
   1.111 + * @par
   1.112 + * <li> Background color specified in GIF is ignored by web browsers.
   1.113 + *
   1.114 + * @par
   1.115 + * <li> If Frame 3 wants to dispose by restoring previous, what it wants is to
   1.116 + * restore the composition up to and including Frame 2, as well as Frame 2s
   1.117 + * disposal.  So, in the middle of DoComposite when composing Frame 3, right
   1.118 + * after destroying Frame 2's area, we copy compositingFrame to
   1.119 + * prevCompositingFrame.  When DoComposite gets called to do Frame 4, we
   1.120 + * copy prevCompositingFrame back, and then draw Frame 4 on top.
   1.121 + *
   1.122 + * @par
   1.123 + * The mAnim structure has members only needed for animated images, so
   1.124 + * it's not allocated until the second frame is added.
   1.125 + */
   1.126 +
   1.127 +class ScaleRequest;
   1.128 +
   1.129 +namespace mozilla {
   1.130 +
   1.131 +namespace layers {
   1.132 +class LayerManager;
   1.133 +class ImageContainer;
   1.134 +class Image;
   1.135 +}
   1.136 +
   1.137 +namespace image {
   1.138 +
   1.139 +class Decoder;
   1.140 +class FrameAnimator;
   1.141 +
   1.142 +class RasterImage : public ImageResource
   1.143 +                  , public nsIProperties
   1.144 +                  , public SupportsWeakPtr<RasterImage>
   1.145 +#ifdef DEBUG
   1.146 +                  , public imgIContainerDebug
   1.147 +#endif
   1.148 +{
   1.149 +public:
   1.150 +  MOZ_DECLARE_REFCOUNTED_TYPENAME(RasterImage)
   1.151 +  NS_DECL_THREADSAFE_ISUPPORTS
   1.152 +  NS_DECL_NSIPROPERTIES
   1.153 +  NS_DECL_IMGICONTAINER
   1.154 +#ifdef DEBUG
   1.155 +  NS_DECL_IMGICONTAINERDEBUG
   1.156 +#endif
   1.157 +
   1.158 +  // (no public constructor - use ImageFactory)
   1.159 +  virtual ~RasterImage();
   1.160 +
   1.161 +  virtual nsresult StartAnimation();
   1.162 +  virtual nsresult StopAnimation();
   1.163 +
   1.164 +  // Methods inherited from Image
   1.165 +  nsresult Init(const char* aMimeType,
   1.166 +                uint32_t aFlags);
   1.167 +  virtual nsIntRect FrameRect(uint32_t aWhichFrame) MOZ_OVERRIDE;
   1.168 +
   1.169 +  // Raster-specific methods
   1.170 +  static NS_METHOD WriteToRasterImage(nsIInputStream* aIn, void* aClosure,
   1.171 +                                      const char* aFromRawSegment,
   1.172 +                                      uint32_t aToOffset, uint32_t aCount,
   1.173 +                                      uint32_t* aWriteCount);
   1.174 +
   1.175 +  /* The index of the current frame that would be drawn if the image was to be
   1.176 +   * drawn now. */
   1.177 +  uint32_t GetCurrentFrameIndex();
   1.178 +
   1.179 +  /* The total number of frames in this image. */
   1.180 +  uint32_t GetNumFrames() const;
   1.181 +
   1.182 +  virtual size_t HeapSizeOfSourceWithComputedFallback(mozilla::MallocSizeOf aMallocSizeOf) const;
   1.183 +  virtual size_t HeapSizeOfDecodedWithComputedFallback(mozilla::MallocSizeOf aMallocSizeOf) const;
   1.184 +  virtual size_t NonHeapSizeOfDecoded() const;
   1.185 +  virtual size_t OutOfProcessSizeOfDecoded() const;
   1.186 +
   1.187 +  /* Triggers discarding. */
   1.188 +  void Discard(bool force = false);
   1.189 +  void ForceDiscard() { Discard(/* force = */ true); }
   1.190 +
   1.191 +  /* Callbacks for decoders */
   1.192 +  nsresult SetFrameAsNonPremult(uint32_t aFrameNum, bool aIsNonPremult);
   1.193 +
   1.194 +  /** Sets the size and inherent orientation of the container. This should only
   1.195 +   * be called by the decoder. This function may be called multiple times, but
   1.196 +   * will throw an error if subsequent calls do not match the first.
   1.197 +   */
   1.198 +  nsresult SetSize(int32_t aWidth, int32_t aHeight, Orientation aOrientation);
   1.199 +
   1.200 +  /**
   1.201 +   * Ensures that a given frame number exists with the given parameters, and
   1.202 +   * returns pointers to the data storage for that frame.
   1.203 +   * It is not possible to create sparse frame arrays; you can only append
   1.204 +   * frames to the current frame array.
   1.205 +   */
   1.206 +  nsresult EnsureFrame(uint32_t aFramenum, int32_t aX, int32_t aY,
   1.207 +                       int32_t aWidth, int32_t aHeight,
   1.208 +                       gfxImageFormat aFormat,
   1.209 +                       uint8_t aPaletteDepth,
   1.210 +                       uint8_t** imageData,
   1.211 +                       uint32_t* imageLength,
   1.212 +                       uint32_t** paletteData,
   1.213 +                       uint32_t* paletteLength,
   1.214 +                       imgFrame** aFrame);
   1.215 +
   1.216 +  /**
   1.217 +   * A shorthand for EnsureFrame, above, with aPaletteDepth = 0 and paletteData
   1.218 +   * and paletteLength set to null.
   1.219 +   */
   1.220 +  nsresult EnsureFrame(uint32_t aFramenum, int32_t aX, int32_t aY,
   1.221 +                       int32_t aWidth, int32_t aHeight,
   1.222 +                       gfxImageFormat aFormat,
   1.223 +                       uint8_t** imageData,
   1.224 +                       uint32_t* imageLength,
   1.225 +                       imgFrame** aFrame);
   1.226 +
   1.227 +  /* notification that the entire image has been decoded */
   1.228 +  nsresult DecodingComplete();
   1.229 +
   1.230 +  /**
   1.231 +   * Number of times to loop the image.
   1.232 +   * @note -1 means forever.
   1.233 +   */
   1.234 +  void     SetLoopCount(int32_t aLoopCount);
   1.235 +
   1.236 +  /* Add compressed source data to the imgContainer.
   1.237 +   *
   1.238 +   * The decoder will use this data, either immediately or at draw time, to
   1.239 +   * decode the image.
   1.240 +   *
   1.241 +   * XXX This method's only caller (WriteToContainer) ignores the return
   1.242 +   * value. Should this just return void?
   1.243 +   */
   1.244 +  nsresult AddSourceData(const char *aBuffer, uint32_t aCount);
   1.245 +
   1.246 +  virtual nsresult OnImageDataAvailable(nsIRequest* aRequest,
   1.247 +                                        nsISupports* aContext,
   1.248 +                                        nsIInputStream* aInStr,
   1.249 +                                        uint64_t aSourceOffset,
   1.250 +                                        uint32_t aCount) MOZ_OVERRIDE;
   1.251 +  virtual nsresult OnImageDataComplete(nsIRequest* aRequest,
   1.252 +                                       nsISupports* aContext,
   1.253 +                                       nsresult aStatus,
   1.254 +                                       bool aLastPart) MOZ_OVERRIDE;
   1.255 +  virtual nsresult OnNewSourceData() MOZ_OVERRIDE;
   1.256 +
   1.257 +  static already_AddRefed<nsIEventTarget> GetEventTarget() {
   1.258 +    return DecodePool::Singleton()->GetEventTarget();
   1.259 +  }
   1.260 +
   1.261 +  /**
   1.262 +   * A hint of the number of bytes of source data that the image contains. If
   1.263 +   * called early on, this can help reduce copying and reallocations by
   1.264 +   * appropriately preallocating the source data buffer.
   1.265 +   *
   1.266 +   * We take this approach rather than having the source data management code do
   1.267 +   * something more complicated (like chunklisting) because HTTP is by far the
   1.268 +   * dominant source of images, and the Content-Length header is quite reliable.
   1.269 +   * Thus, pre-allocation simplifies code and reduces the total number of
   1.270 +   * allocations.
   1.271 +   */
   1.272 +  nsresult SetSourceSizeHint(uint32_t sizeHint);
   1.273 +
   1.274 +  /* Provide a hint for the requested resolution of the resulting image. */
   1.275 +  void SetRequestedResolution(const nsIntSize requestedResolution) {
   1.276 +    mRequestedResolution = requestedResolution;
   1.277 +  }
   1.278 +
   1.279 +  nsIntSize GetRequestedResolution() {
   1.280 +    return mRequestedResolution;
   1.281 +  }
   1.282 +  /* Provide a hint for the requested dimension of the resulting image. */
   1.283 +  void SetRequestedSampleSize(int requestedSampleSize) {
   1.284 +    mRequestedSampleSize = requestedSampleSize;
   1.285 +  }
   1.286 +
   1.287 +  int GetRequestedSampleSize() {
   1.288 +    return mRequestedSampleSize;
   1.289 +  }
   1.290 +
   1.291 +
   1.292 +
   1.293 + nsCString GetURIString() {
   1.294 +    nsCString spec;
   1.295 +    if (GetURI()) {
   1.296 +      GetURI()->GetSpec(spec);
   1.297 +    }
   1.298 +    return spec;
   1.299 +  }
   1.300 +
   1.301 +  // Called from module startup. Sets up RasterImage to be used.
   1.302 +  static void Initialize();
   1.303 +
   1.304 +  enum ScaleStatus
   1.305 +  {
   1.306 +    SCALE_INVALID,
   1.307 +    SCALE_PENDING,
   1.308 +    SCALE_DONE
   1.309 +  };
   1.310 +
   1.311 +  // Call this with a new ScaleRequest to mark this RasterImage's scale result
   1.312 +  // as waiting for the results of this request. You call to ScalingDone before
   1.313 +  // request is destroyed!
   1.314 +  void ScalingStart(ScaleRequest* request);
   1.315 +
   1.316 +  // Call this with a finished ScaleRequest to set this RasterImage's scale
   1.317 +  // result. Give it a ScaleStatus of SCALE_DONE if everything succeeded, and
   1.318 +  // SCALE_INVALID otherwise.
   1.319 +  void ScalingDone(ScaleRequest* request, ScaleStatus status);
   1.320 +
   1.321 +  // Decoder shutdown
   1.322 +  enum eShutdownIntent {
   1.323 +    eShutdownIntent_Done        = 0,
   1.324 +    eShutdownIntent_NotNeeded   = 1,
   1.325 +    eShutdownIntent_Error       = 2,
   1.326 +    eShutdownIntent_AllCount    = 3
   1.327 +  };
   1.328 +
   1.329 +  // Decode strategy
   1.330 +
   1.331 +private:
   1.332 +  already_AddRefed<imgStatusTracker> CurrentStatusTracker()
   1.333 +  {
   1.334 +    mDecodingMonitor.AssertCurrentThreadIn();
   1.335 +    nsRefPtr<imgStatusTracker> statusTracker;
   1.336 +    statusTracker = mDecodeRequest ? mDecodeRequest->mStatusTracker
   1.337 +                                   : mStatusTracker;
   1.338 +    MOZ_ASSERT(statusTracker);
   1.339 +    return statusTracker.forget();
   1.340 +  }
   1.341 +
   1.342 +  nsresult OnImageDataCompleteCore(nsIRequest* aRequest, nsISupports*, nsresult aStatus);
   1.343 +
   1.344 +  /**
   1.345 +   * Each RasterImage has a pointer to one or zero heap-allocated
   1.346 +   * DecodeRequests.
   1.347 +   */
   1.348 +  struct DecodeRequest
   1.349 +  {
   1.350 +    DecodeRequest(RasterImage* aImage)
   1.351 +      : mImage(aImage)
   1.352 +      , mBytesToDecode(0)
   1.353 +      , mRequestStatus(REQUEST_INACTIVE)
   1.354 +      , mChunkCount(0)
   1.355 +      , mAllocatedNewFrame(false)
   1.356 +    {
   1.357 +      MOZ_ASSERT(aImage, "aImage cannot be null");
   1.358 +      MOZ_ASSERT(aImage->mStatusTracker,
   1.359 +                 "aImage should have an imgStatusTracker");
   1.360 +      mStatusTracker = aImage->mStatusTracker->CloneForRecording();
   1.361 +    }
   1.362 +
   1.363 +    NS_INLINE_DECL_THREADSAFE_REFCOUNTING(DecodeRequest)
   1.364 +
   1.365 +    // The status tracker that is associated with a given decode request, to
   1.366 +    // ensure their lifetimes are linked.
   1.367 +    nsRefPtr<imgStatusTracker> mStatusTracker;
   1.368 +
   1.369 +    RasterImage* mImage;
   1.370 +
   1.371 +    uint32_t mBytesToDecode;
   1.372 +
   1.373 +    enum DecodeRequestStatus
   1.374 +    {
   1.375 +      REQUEST_INACTIVE,
   1.376 +      REQUEST_PENDING,
   1.377 +      REQUEST_ACTIVE,
   1.378 +      REQUEST_WORK_DONE,
   1.379 +      REQUEST_STOPPED
   1.380 +    } mRequestStatus;
   1.381 +
   1.382 +    /* Keeps track of how much time we've burned decoding this particular decode
   1.383 +     * request. */
   1.384 +    TimeDuration mDecodeTime;
   1.385 +
   1.386 +    /* The number of chunks it took to decode this image. */
   1.387 +    int32_t mChunkCount;
   1.388 +
   1.389 +    /* True if a new frame has been allocated, but DecodeSomeData hasn't yet
   1.390 +     * been called to flush data to it */
   1.391 +    bool mAllocatedNewFrame;
   1.392 +  };
   1.393 +
   1.394 +  /*
   1.395 +   * DecodePool is a singleton class we use when decoding large images.
   1.396 +   *
   1.397 +   * When we wish to decode an image larger than
   1.398 +   * image.mem.max_bytes_for_sync_decode, we call DecodePool::RequestDecode()
   1.399 +   * for the image.  This adds the image to a queue of pending requests and posts
   1.400 +   * the DecodePool singleton to the event queue, if it's not already pending
   1.401 +   * there.
   1.402 +   *
   1.403 +   * When the DecodePool is run from the event queue, it decodes the image (and
   1.404 +   * all others it's managing) in chunks, periodically yielding control back to
   1.405 +   * the event loop.
   1.406 +   */
   1.407 +  class DecodePool : public nsIObserver
   1.408 +  {
   1.409 +  public:
   1.410 +    NS_DECL_THREADSAFE_ISUPPORTS
   1.411 +    NS_DECL_NSIOBSERVER
   1.412 +
   1.413 +    static DecodePool* Singleton();
   1.414 +
   1.415 +    /**
   1.416 +     * Ask the DecodePool to asynchronously decode this image.
   1.417 +     */
   1.418 +    void RequestDecode(RasterImage* aImg);
   1.419 +
   1.420 +    /**
   1.421 +     * Decode aImg for a short amount of time, and post the remainder to the
   1.422 +     * queue.
   1.423 +     */
   1.424 +    void DecodeABitOf(RasterImage* aImg, DecodeStrategy aStrategy);
   1.425 +
   1.426 +    /**
   1.427 +     * Ask the DecodePool to stop decoding this image.  Internally, we also
   1.428 +     * call this function when we finish decoding an image.
   1.429 +     *
   1.430 +     * Since the DecodePool keeps raw pointers to RasterImages, make sure you
   1.431 +     * call this before a RasterImage is destroyed!
   1.432 +     */
   1.433 +    static void StopDecoding(RasterImage* aImg);
   1.434 +
   1.435 +    /**
   1.436 +     * Synchronously decode the beginning of the image until we run out of
   1.437 +     * bytes or we get the image's size.  Note that this done on a best-effort
   1.438 +     * basis; if the size is burried too deep in the image, we'll give up.
   1.439 +     *
   1.440 +     * @return NS_ERROR if an error is encountered, and NS_OK otherwise.  (Note
   1.441 +     *         that we return NS_OK even when the size was not found.)
   1.442 +     */
   1.443 +    nsresult DecodeUntilSizeAvailable(RasterImage* aImg);
   1.444 +
   1.445 +    /**
   1.446 +     * Returns an event target interface to the thread pool; primarily for
   1.447 +     * OnDataAvailable delivery off main thread.
   1.448 +     *
   1.449 +     * @return An nsIEventTarget interface to mThreadPool.
   1.450 +     */
   1.451 +    already_AddRefed<nsIEventTarget> GetEventTarget();
   1.452 +
   1.453 +    virtual ~DecodePool();
   1.454 +
   1.455 +  private: /* statics */
   1.456 +    static StaticRefPtr<DecodePool> sSingleton;
   1.457 +
   1.458 +  private: /* methods */
   1.459 +    DecodePool();
   1.460 +
   1.461 +    enum DecodeType {
   1.462 +      DECODE_TYPE_UNTIL_TIME,
   1.463 +      DECODE_TYPE_UNTIL_SIZE,
   1.464 +      DECODE_TYPE_UNTIL_DONE_BYTES
   1.465 +    };
   1.466 +
   1.467 +    /* Decode some chunks of the given image.  If aDecodeType is UNTIL_SIZE,
   1.468 +     * decode until we have the image's size, then stop. If bytesToDecode is
   1.469 +     * non-0, at most bytesToDecode bytes will be decoded. if aDecodeType is
   1.470 +     * UNTIL_DONE_BYTES, decode until all bytesToDecode bytes are decoded.
   1.471 +     */
   1.472 +    nsresult DecodeSomeOfImage(RasterImage* aImg,
   1.473 +                               DecodeStrategy aStrategy,
   1.474 +                               DecodeType aDecodeType = DECODE_TYPE_UNTIL_TIME,
   1.475 +                               uint32_t bytesToDecode = 0);
   1.476 +
   1.477 +    /* A decode job dispatched to a thread pool by DecodePool.
   1.478 +     */
   1.479 +    class DecodeJob : public nsRunnable
   1.480 +    {
   1.481 +    public:
   1.482 +      DecodeJob(DecodeRequest* aRequest, RasterImage* aImg)
   1.483 +        : mRequest(aRequest)
   1.484 +        , mImage(aImg)
   1.485 +      {}
   1.486 +
   1.487 +      NS_IMETHOD Run();
   1.488 +
   1.489 +    protected:
   1.490 +      virtual ~DecodeJob();
   1.491 +
   1.492 +    private:
   1.493 +      nsRefPtr<DecodeRequest> mRequest;
   1.494 +      nsRefPtr<RasterImage> mImage;
   1.495 +    };
   1.496 +
   1.497 +  private: /* members */
   1.498 +
   1.499 +    // mThreadPoolMutex protects mThreadPool. For all RasterImages R,
   1.500 +    // R::mDecodingMonitor must be acquired before mThreadPoolMutex
   1.501 +    // if both are acquired; the other order may cause deadlock.
   1.502 +    mozilla::Mutex            mThreadPoolMutex;
   1.503 +    nsCOMPtr<nsIThreadPool>   mThreadPool;
   1.504 +  };
   1.505 +
   1.506 +  class DecodeDoneWorker : public nsRunnable
   1.507 +  {
   1.508 +  public:
   1.509 +    /**
   1.510 +     * Called by the DecodePool with an image when it's done some significant
   1.511 +     * portion of decoding that needs to be notified about.
   1.512 +     *
   1.513 +     * Ensures the decode state accumulated by the decoding process gets
   1.514 +     * applied to the image.
   1.515 +     */
   1.516 +    static void NotifyFinishedSomeDecoding(RasterImage* image, DecodeRequest* request);
   1.517 +
   1.518 +    NS_IMETHOD Run();
   1.519 +
   1.520 +  private: /* methods */
   1.521 +    DecodeDoneWorker(RasterImage* image, DecodeRequest* request);
   1.522 +
   1.523 +  private: /* members */
   1.524 +
   1.525 +    nsRefPtr<RasterImage> mImage;
   1.526 +    nsRefPtr<DecodeRequest> mRequest;
   1.527 +  };
   1.528 +
   1.529 +  class FrameNeededWorker : public nsRunnable
   1.530 +  {
   1.531 +  public:
   1.532 +    /**
   1.533 +     * Called by the DecodeJob with an image when it's been told by the
   1.534 +     * decoder that it needs a new frame to be allocated on the main thread.
   1.535 +     *
   1.536 +     * Dispatches an event to do so, which will further dispatch a
   1.537 +     * DecodeRequest event to continue decoding.
   1.538 +     */
   1.539 +    static void GetNewFrame(RasterImage* image);
   1.540 +
   1.541 +    NS_IMETHOD Run();
   1.542 +
   1.543 +  private: /* methods */
   1.544 +    FrameNeededWorker(RasterImage* image);
   1.545 +
   1.546 +  private: /* members */
   1.547 +
   1.548 +    nsRefPtr<RasterImage> mImage;
   1.549 +  };
   1.550 +
   1.551 +  nsresult FinishedSomeDecoding(eShutdownIntent intent = eShutdownIntent_Done,
   1.552 +                                DecodeRequest* request = nullptr);
   1.553 +
   1.554 +  bool DrawWithPreDownscaleIfNeeded(imgFrame *aFrame,
   1.555 +                                    gfxContext *aContext,
   1.556 +                                    GraphicsFilter aFilter,
   1.557 +                                    const gfxMatrix &aUserSpaceToImageSpace,
   1.558 +                                    const gfxRect &aFill,
   1.559 +                                    const nsIntRect &aSubimage,
   1.560 +                                    uint32_t aFlags);
   1.561 +
   1.562 +  nsresult CopyFrame(uint32_t aWhichFrame,
   1.563 +                     uint32_t aFlags,
   1.564 +                     gfxImageSurface **_retval);
   1.565 +
   1.566 +  /**
   1.567 +   * Deletes and nulls out the frame in mFrames[framenum].
   1.568 +   *
   1.569 +   * Does not change the size of mFrames.
   1.570 +   *
   1.571 +   * @param framenum The index of the frame to be deleted.
   1.572 +   *                 Must lie in [0, mFrames.Length() )
   1.573 +   */
   1.574 +  void DeleteImgFrame(uint32_t framenum);
   1.575 +
   1.576 +  imgFrame* GetImgFrameNoDecode(uint32_t framenum);
   1.577 +  imgFrame* GetImgFrame(uint32_t framenum);
   1.578 +  imgFrame* GetDrawableImgFrame(uint32_t framenum);
   1.579 +  imgFrame* GetCurrentImgFrame();
   1.580 +  uint32_t GetCurrentImgFrameIndex() const;
   1.581 +
   1.582 +  size_t SizeOfDecodedWithComputedFallbackIfHeap(gfxMemoryLocation aLocation,
   1.583 +                                                 mozilla::MallocSizeOf aMallocSizeOf) const;
   1.584 +
   1.585 +  void EnsureAnimExists();
   1.586 +
   1.587 +  nsresult InternalAddFrameHelper(uint32_t framenum, imgFrame *frame,
   1.588 +                                  uint8_t **imageData, uint32_t *imageLength,
   1.589 +                                  uint32_t **paletteData, uint32_t *paletteLength,
   1.590 +                                  imgFrame** aRetFrame);
   1.591 +  nsresult InternalAddFrame(uint32_t framenum, int32_t aX, int32_t aY, int32_t aWidth, int32_t aHeight,
   1.592 +                            gfxImageFormat aFormat, uint8_t aPaletteDepth,
   1.593 +                            uint8_t **imageData, uint32_t *imageLength,
   1.594 +                            uint32_t **paletteData, uint32_t *paletteLength,
   1.595 +                            imgFrame** aRetFrame);
   1.596 +
   1.597 +  nsresult DoImageDataComplete();
   1.598 +
   1.599 +  bool ApplyDecodeFlags(uint32_t aNewFlags, uint32_t aWhichFrame);
   1.600 +
   1.601 +  already_AddRefed<layers::Image> GetCurrentImage();
   1.602 +  void UpdateImageContainer();
   1.603 +
   1.604 +  void SetInUpdateImageContainer(bool aInUpdate) { mInUpdateImageContainer = aInUpdate; }
   1.605 +  bool IsInUpdateImageContainer() { return mInUpdateImageContainer; }
   1.606 +  enum RequestDecodeType {
   1.607 +      ASYNCHRONOUS,
   1.608 +      SYNCHRONOUS_NOTIFY,
   1.609 +      SYNCHRONOUS_NOTIFY_AND_SOME_DECODE
   1.610 +  };
   1.611 +  NS_IMETHOD RequestDecodeCore(RequestDecodeType aDecodeType);
   1.612 +
   1.613 +  // We would like to just check if we have a zero lock count, but we can't do
   1.614 +  // that for animated images because in EnsureAnimExists we lock the image and
   1.615 +  // never unlock so that animated images always have their lock count >= 1. In
   1.616 +  // that case we use our animation consumers count as a proxy for lock count.
   1.617 +  bool IsUnlocked() { return (mLockCount == 0 || (mAnim && mAnimationConsumers == 0)); }
   1.618 +
   1.619 +private: // data
   1.620 +  nsIntSize                  mSize;
   1.621 +  Orientation                mOrientation;
   1.622 +
   1.623 +  // Whether our frames were decoded using any special flags.
   1.624 +  // Some flags (e.g. unpremultiplied data) may not be compatible
   1.625 +  // with the browser's needs for displaying the image to the user.
   1.626 +  // As such, we may need to redecode if we're being asked for
   1.627 +  // a frame with different flags.  0 indicates default flags.
   1.628 +  //
   1.629 +  // Valid flag bits are imgIContainer::FLAG_DECODE_NO_PREMULTIPLY_ALPHA
   1.630 +  // and imgIContainer::FLAG_DECODE_NO_COLORSPACE_CONVERSION.
   1.631 +  uint32_t                   mFrameDecodeFlags;
   1.632 +
   1.633 +  //! All the frames of the image
   1.634 +  FrameBlender              mFrameBlender;
   1.635 +
   1.636 +  // The last frame we decoded for multipart images.
   1.637 +  imgFrame*                  mMultipartDecodedFrame;
   1.638 +
   1.639 +  nsCOMPtr<nsIProperties>    mProperties;
   1.640 +
   1.641 +  // IMPORTANT: if you use mAnim in a method, call EnsureImageIsDecoded() first to ensure
   1.642 +  // that the frames actually exist (they may have been discarded to save memory, or
   1.643 +  // we maybe decoding on draw).
   1.644 +  FrameAnimator* mAnim;
   1.645 +
   1.646 +  // Discard members
   1.647 +  uint32_t                   mLockCount;
   1.648 +  DiscardTracker::Node       mDiscardTrackerNode;
   1.649 +
   1.650 +  // Source data members
   1.651 +  nsCString                  mSourceDataMimeType;
   1.652 +
   1.653 +  friend class DiscardTracker;
   1.654 +
   1.655 +  // How many times we've decoded this image.
   1.656 +  // This is currently only used for statistics
   1.657 +  int32_t                        mDecodeCount;
   1.658 +
   1.659 +  // If the image contains multiple resolutions, a hint as to which one should be used
   1.660 +  nsIntSize                  mRequestedResolution;
   1.661 +
   1.662 +  // A hint for image decoder that directly scale the image to smaller buffer
   1.663 +  int                        mRequestedSampleSize;
   1.664 +
   1.665 +  // Cached value for GetImageContainer.
   1.666 +  nsRefPtr<mozilla::layers::ImageContainer> mImageContainer;
   1.667 +
   1.668 +  // If not cached in mImageContainer, this might have our image container
   1.669 +  WeakPtr<mozilla::layers::ImageContainer> mImageContainerCache;
   1.670 +
   1.671 +#ifdef DEBUG
   1.672 +  uint32_t                       mFramesNotified;
   1.673 +#endif
   1.674 +
   1.675 +  // Below are the pieces of data that can be accessed on more than one thread
   1.676 +  // at once, and hence need to be locked by mDecodingMonitor.
   1.677 +
   1.678 +  // BEGIN LOCKED MEMBER VARIABLES
   1.679 +  mozilla::ReentrantMonitor  mDecodingMonitor;
   1.680 +
   1.681 +  FallibleTArray<char>       mSourceData;
   1.682 +
   1.683 +  // Decoder and friends
   1.684 +  nsRefPtr<Decoder>          mDecoder;
   1.685 +  nsRefPtr<DecodeRequest>    mDecodeRequest;
   1.686 +  uint32_t                   mBytesDecoded;
   1.687 +
   1.688 +  bool                       mInDecoder;
   1.689 +  // END LOCKED MEMBER VARIABLES
   1.690 +
   1.691 +  // Notification state. Used to avoid recursive notifications.
   1.692 +  ImageStatusDiff            mStatusDiff;
   1.693 +  bool                       mNotifying:1;
   1.694 +
   1.695 +  // Boolean flags (clustered together to conserve space):
   1.696 +  bool                       mHasSize:1;       // Has SetSize() been called?
   1.697 +  bool                       mDecodeOnDraw:1;  // Decoding on draw?
   1.698 +  bool                       mMultipart:1;     // Multipart?
   1.699 +  bool                       mDiscardable:1;   // Is container discardable?
   1.700 +  bool                       mHasSourceData:1; // Do we have source data?
   1.701 +
   1.702 +  // Do we have the frames in decoded form?
   1.703 +  bool                       mDecoded:1;
   1.704 +  bool                       mHasBeenDecoded:1;
   1.705 +
   1.706 +
   1.707 +  // Whether the animation can stop, due to running out
   1.708 +  // of frames, or no more owning request
   1.709 +  bool                       mAnimationFinished:1;
   1.710 +
   1.711 +  // Whether we're calling Decoder::Finish() from ShutdownDecoder.
   1.712 +  bool                       mFinishing:1;
   1.713 +
   1.714 +  bool                       mInUpdateImageContainer:1;
   1.715 +
   1.716 +  // Whether, once we are done doing a size decode, we should immediately kick
   1.717 +  // off a full decode.
   1.718 +  bool                       mWantFullDecode:1;
   1.719 +
   1.720 +  // Set when a decode worker detects an error off-main-thread. Once the error
   1.721 +  // is handled on the main thread, mError is set, but mPendingError is used to
   1.722 +  // stop decode work immediately.
   1.723 +  bool                       mPendingError:1;
   1.724 +
   1.725 +  // Decoding
   1.726 +  nsresult RequestDecodeIfNeeded(nsresult aStatus,
   1.727 +                                 eShutdownIntent aIntent,
   1.728 +                                 bool aDone,
   1.729 +                                 bool aWasSize);
   1.730 +  nsresult WantDecodedFrames();
   1.731 +  nsresult SyncDecode();
   1.732 +  nsresult InitDecoder(bool aDoSizeDecode);
   1.733 +  nsresult WriteToDecoder(const char *aBuffer, uint32_t aCount, DecodeStrategy aStrategy);
   1.734 +  nsresult DecodeSomeData(uint32_t aMaxBytes, DecodeStrategy aStrategy);
   1.735 +  bool     IsDecodeFinished();
   1.736 +  TimeStamp mDrawStartTime;
   1.737 +
   1.738 +  inline bool CanQualityScale(const gfxSize& scale);
   1.739 +  inline bool CanScale(GraphicsFilter aFilter, gfxSize aScale, uint32_t aFlags);
   1.740 +
   1.741 +  struct ScaleResult
   1.742 +  {
   1.743 +    ScaleResult()
   1.744 +     : status(SCALE_INVALID)
   1.745 +    {}
   1.746 +
   1.747 +    gfxSize scale;
   1.748 +    nsAutoPtr<imgFrame> frame;
   1.749 +    ScaleStatus status;
   1.750 +  };
   1.751 +
   1.752 +  ScaleResult mScaleResult;
   1.753 +
   1.754 +  // We hold on to a bare pointer to a ScaleRequest while it's outstanding so
   1.755 +  // we can mark it as stopped if necessary. The ScaleWorker/DrawWorker duo
   1.756 +  // will inform us when to let go of this pointer.
   1.757 +  ScaleRequest* mScaleRequest;
   1.758 +
   1.759 +  // Initializes imgStatusTracker and resets it on RasterImage destruction.
   1.760 +  nsAutoPtr<imgStatusTrackerInit> mStatusTrackerInit;
   1.761 +
   1.762 +  nsresult ShutdownDecoder(eShutdownIntent aIntent);
   1.763 +
   1.764 +  // Error handling.
   1.765 +  void DoError();
   1.766 +
   1.767 +  class HandleErrorWorker : public nsRunnable
   1.768 +  {
   1.769 +  public:
   1.770 +    /**
   1.771 +     * Called from decoder threads when DoError() is called, since errors can't
   1.772 +     * be handled safely off-main-thread. Dispatches an event which reinvokes
   1.773 +     * DoError on the main thread if there isn't one already pending.
   1.774 +     */
   1.775 +    static void DispatchIfNeeded(RasterImage* aImage);
   1.776 +
   1.777 +    NS_IMETHOD Run();
   1.778 +
   1.779 +  private:
   1.780 +    HandleErrorWorker(RasterImage* aImage);
   1.781 +
   1.782 +    nsRefPtr<RasterImage> mImage;
   1.783 +  };
   1.784 +
   1.785 +  // Helpers
   1.786 +  bool CanDiscard();
   1.787 +  bool CanForciblyDiscard();
   1.788 +  bool CanForciblyDiscardAndRedecode();
   1.789 +  bool DiscardingActive();
   1.790 +  bool StoringSourceData() const;
   1.791 +
   1.792 +protected:
   1.793 +  RasterImage(imgStatusTracker* aStatusTracker = nullptr,
   1.794 +              ImageURL* aURI = nullptr);
   1.795 +
   1.796 +  bool ShouldAnimate();
   1.797 +
   1.798 +  friend class ImageFactory;
   1.799 +};
   1.800 +
   1.801 +inline NS_IMETHODIMP RasterImage::GetAnimationMode(uint16_t *aAnimationMode) {
   1.802 +  return GetAnimationModeInternal(aAnimationMode);
   1.803 +}
   1.804 +
   1.805 +// Asynchronous Decode Requestor
   1.806 +//
   1.807 +// We use this class when someone calls requestDecode() from within a decode
   1.808 +// notification. Since requestDecode() involves modifying the decoder's state
   1.809 +// (for example, possibly shutting down a header-only decode and starting a
   1.810 +// full decode), we don't want to do this from inside a decoder.
   1.811 +class imgDecodeRequestor : public nsRunnable
   1.812 +{
   1.813 +  public:
   1.814 +    imgDecodeRequestor(RasterImage &aContainer) {
   1.815 +      mContainer = aContainer.asWeakPtr();
   1.816 +    }
   1.817 +    NS_IMETHOD Run() {
   1.818 +      if (mContainer)
   1.819 +        mContainer->StartDecoding();
   1.820 +      return NS_OK;
   1.821 +    }
   1.822 +
   1.823 +  private:
   1.824 +    WeakPtr<RasterImage> mContainer;
   1.825 +};
   1.826 +
   1.827 +} // namespace image
   1.828 +} // namespace mozilla
   1.829 +
   1.830 +#endif /* mozilla_imagelib_RasterImage_h_ */

mercurial