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_ */