Bumping manifests a=b2g-bump
[gecko.git] / image / src / RasterImage.h
blob7e3f5b55e5bc557f8e9cc2f268930aa696e75c8e
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 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.
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>
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} \
54 /**
55 * Handles static and animated image containers.
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.
64 * @par
65 * StartAnimation() initializes the animation helper object and sets the time
66 * the first frame was displayed to the current clock time.
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().
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.
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.
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.
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.
100 * @note
101 * <li> "Mask", "Alpha", and "Alpha Level" are interchangeable phrases in
102 * respects to RasterImage.
104 * @par
105 * <li> GIFs never have more than a 1 bit alpha.
106 * <li> APNGs may have a full alpha channel.
108 * @par
109 * <li> Background color specified in GIF is ignored by web browsers.
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.
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.
124 namespace mozilla {
126 namespace layers {
127 class LayerManager;
128 class ImageContainer;
129 class Image;
132 namespace image {
134 class ScaleRequest;
135 class Decoder;
136 class FrameAnimator;
138 class RasterImage MOZ_FINAL : public ImageResource
139 , public nsIProperties
140 , public SupportsWeakPtr<RasterImage>
141 #ifdef DEBUG
142 , public imgIContainerDebug
143 #endif
145 // (no public constructor - use ImageFactory)
146 virtual ~RasterImage();
148 public:
149 MOZ_DECLARE_REFCOUNTED_TYPENAME(RasterImage)
150 NS_DECL_THREADSAFE_ISUPPORTS
151 NS_DECL_NSIPROPERTIES
152 NS_DECL_IMGICONTAINER
153 #ifdef DEBUG
154 NS_DECL_IMGICONTAINERDEBUG
155 #endif
157 virtual nsresult StartAnimation();
158 virtual nsresult StopAnimation();
160 // Methods inherited from Image
161 nsresult Init(const char* aMimeType,
162 uint32_t aFlags);
163 virtual nsIntRect FrameRect(uint32_t aWhichFrame) MOZ_OVERRIDE;
165 // Raster-specific methods
166 static NS_METHOD WriteToRasterImage(nsIInputStream* aIn, void* aClosure,
167 const char* aFromRawSegment,
168 uint32_t aToOffset, uint32_t aCount,
169 uint32_t* aWriteCount);
171 /* The index of the current frame that would be drawn if the image was to be
172 * drawn now. */
173 uint32_t GetCurrentFrameIndex();
175 /* The total number of frames in this image. */
176 uint32_t GetNumFrames() const;
178 virtual size_t HeapSizeOfSourceWithComputedFallback(MallocSizeOf aMallocSizeOf) const;
179 virtual size_t HeapSizeOfDecodedWithComputedFallback(MallocSizeOf aMallocSizeOf) const;
180 virtual size_t NonHeapSizeOfDecoded() const;
181 virtual size_t OutOfProcessSizeOfDecoded() const;
183 virtual size_t HeapSizeOfVectorImageDocument(nsACString* aDocURL = nullptr) const MOZ_OVERRIDE {
184 return 0;
187 /* Triggers discarding. */
188 void Discard(bool force = false);
189 void ForceDiscard() { Discard(/* force = */ true); }
191 /* Callbacks for decoders */
192 nsresult SetFrameAsNonPremult(uint32_t aFrameNum, bool aIsNonPremult);
194 /** Sets the size and inherent orientation of the container. This should only
195 * be called by the decoder. This function may be called multiple times, but
196 * will throw an error if subsequent calls do not match the first.
198 nsresult SetSize(int32_t aWidth, int32_t aHeight, Orientation aOrientation);
201 * Ensures that a given frame number exists with the given parameters, and
202 * returns pointers to the data storage for that frame.
203 * It is not possible to create sparse frame arrays; you can only append
204 * frames to the current frame array.
206 nsresult EnsureFrame(uint32_t aFramenum, int32_t aX, int32_t aY,
207 int32_t aWidth, int32_t aHeight,
208 gfx::SurfaceFormat aFormat,
209 uint8_t aPaletteDepth,
210 uint8_t** imageData,
211 uint32_t* imageLength,
212 uint32_t** paletteData,
213 uint32_t* paletteLength,
214 imgFrame** aFrame);
217 * A shorthand for EnsureFrame, above, with aPaletteDepth = 0 and paletteData
218 * and paletteLength set to null.
220 nsresult EnsureFrame(uint32_t aFramenum, int32_t aX, int32_t aY,
221 int32_t aWidth, int32_t aHeight,
222 gfx::SurfaceFormat aFormat,
223 uint8_t** imageData,
224 uint32_t* imageLength,
225 imgFrame** aFrame);
227 /* notification that the entire image has been decoded */
228 nsresult DecodingComplete();
231 * Number of times to loop the image.
232 * @note -1 means forever.
234 void SetLoopCount(int32_t aLoopCount);
236 /* Add compressed source data to the imgContainer.
238 * The decoder will use this data, either immediately or at draw time, to
239 * decode the image.
241 * XXX This method's only caller (WriteToContainer) ignores the return
242 * value. Should this just return void?
244 nsresult AddSourceData(const char *aBuffer, uint32_t aCount);
246 virtual nsresult OnImageDataAvailable(nsIRequest* aRequest,
247 nsISupports* aContext,
248 nsIInputStream* aInStr,
249 uint64_t aSourceOffset,
250 uint32_t aCount) MOZ_OVERRIDE;
251 virtual nsresult OnImageDataComplete(nsIRequest* aRequest,
252 nsISupports* aContext,
253 nsresult aStatus,
254 bool aLastPart) MOZ_OVERRIDE;
255 virtual nsresult OnNewSourceData() MOZ_OVERRIDE;
257 static already_AddRefed<nsIEventTarget> GetEventTarget() {
258 return DecodePool::Singleton()->GetEventTarget();
262 * A hint of the number of bytes of source data that the image contains. If
263 * called early on, this can help reduce copying and reallocations by
264 * appropriately preallocating the source data buffer.
266 * We take this approach rather than having the source data management code do
267 * something more complicated (like chunklisting) because HTTP is by far the
268 * dominant source of images, and the Content-Length header is quite reliable.
269 * Thus, pre-allocation simplifies code and reduces the total number of
270 * allocations.
272 nsresult SetSourceSizeHint(uint32_t sizeHint);
274 /* Provide a hint for the requested resolution of the resulting image. */
275 void SetRequestedResolution(const nsIntSize requestedResolution) {
276 mRequestedResolution = requestedResolution;
279 nsIntSize GetRequestedResolution() {
280 return mRequestedResolution;
282 /* Provide a hint for the requested dimension of the resulting image. */
283 void SetRequestedSampleSize(int requestedSampleSize) {
284 mRequestedSampleSize = requestedSampleSize;
287 int GetRequestedSampleSize() {
288 return mRequestedSampleSize;
293 nsCString GetURIString() {
294 nsCString spec;
295 if (GetURI()) {
296 GetURI()->GetSpec(spec);
298 return spec;
301 // Called from module startup. Sets up RasterImage to be used.
302 static void Initialize();
304 enum ScaleStatus
306 SCALE_INVALID,
307 SCALE_PENDING,
308 SCALE_DONE
311 // Call this with a new ScaleRequest to mark this RasterImage's scale result
312 // as waiting for the results of this request. You call to ScalingDone before
313 // request is destroyed!
314 void ScalingStart(ScaleRequest* request);
316 // Call this with a finished ScaleRequest to set this RasterImage's scale
317 // result. Give it a ScaleStatus of SCALE_DONE if everything succeeded, and
318 // SCALE_INVALID otherwise.
319 void ScalingDone(ScaleRequest* request, ScaleStatus status);
321 // Decoder shutdown
322 enum eShutdownIntent {
323 eShutdownIntent_Done = 0,
324 eShutdownIntent_NotNeeded = 1,
325 eShutdownIntent_Error = 2,
326 eShutdownIntent_AllCount = 3
329 // Decode strategy
331 private:
332 // Initiates an HQ scale for the given frame, if possible.
333 void RequestScale(imgFrame* aFrame, nsIntSize aScale);
335 already_AddRefed<imgStatusTracker> CurrentStatusTracker()
337 mDecodingMonitor.AssertCurrentThreadIn();
338 nsRefPtr<imgStatusTracker> statusTracker;
339 statusTracker = mDecodeRequest ? mDecodeRequest->mStatusTracker
340 : mStatusTracker;
341 MOZ_ASSERT(statusTracker);
342 return statusTracker.forget();
345 nsresult OnImageDataCompleteCore(nsIRequest* aRequest, nsISupports*, nsresult aStatus);
348 * Each RasterImage has a pointer to one or zero heap-allocated
349 * DecodeRequests.
351 struct DecodeRequest
353 DecodeRequest(RasterImage* aImage)
354 : mImage(aImage)
355 , mBytesToDecode(0)
356 , mRequestStatus(REQUEST_INACTIVE)
357 , mChunkCount(0)
358 , mAllocatedNewFrame(false)
360 MOZ_ASSERT(aImage, "aImage cannot be null");
361 MOZ_ASSERT(aImage->mStatusTracker,
362 "aImage should have an imgStatusTracker");
363 mStatusTracker = aImage->mStatusTracker->CloneForRecording();
366 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(DecodeRequest)
368 // The status tracker that is associated with a given decode request, to
369 // ensure their lifetimes are linked.
370 nsRefPtr<imgStatusTracker> mStatusTracker;
372 RasterImage* mImage;
374 size_t mBytesToDecode;
376 enum DecodeRequestStatus
378 REQUEST_INACTIVE,
379 REQUEST_PENDING,
380 REQUEST_ACTIVE,
381 REQUEST_WORK_DONE,
382 REQUEST_STOPPED
383 } mRequestStatus;
385 /* Keeps track of how much time we've burned decoding this particular decode
386 * request. */
387 TimeDuration mDecodeTime;
389 /* The number of chunks it took to decode this image. */
390 int32_t mChunkCount;
392 /* True if a new frame has been allocated, but DecodeSomeData hasn't yet
393 * been called to flush data to it */
394 bool mAllocatedNewFrame;
396 private:
397 ~DecodeRequest() {}
401 * DecodePool is a singleton class we use when decoding large images.
403 * When we wish to decode an image larger than
404 * image.mem.max_bytes_for_sync_decode, we call DecodePool::RequestDecode()
405 * for the image. This adds the image to a queue of pending requests and posts
406 * the DecodePool singleton to the event queue, if it's not already pending
407 * there.
409 * When the DecodePool is run from the event queue, it decodes the image (and
410 * all others it's managing) in chunks, periodically yielding control back to
411 * the event loop.
413 class DecodePool : public nsIObserver
415 public:
416 NS_DECL_THREADSAFE_ISUPPORTS
417 NS_DECL_NSIOBSERVER
419 static DecodePool* Singleton();
422 * Ask the DecodePool to asynchronously decode this image.
424 void RequestDecode(RasterImage* aImg);
427 * Decode aImg for a short amount of time, and post the remainder to the
428 * queue.
430 void DecodeABitOf(RasterImage* aImg, DecodeStrategy aStrategy);
433 * Ask the DecodePool to stop decoding this image. Internally, we also
434 * call this function when we finish decoding an image.
436 * Since the DecodePool keeps raw pointers to RasterImages, make sure you
437 * call this before a RasterImage is destroyed!
439 static void StopDecoding(RasterImage* aImg);
442 * Synchronously decode the beginning of the image until we run out of
443 * bytes or we get the image's size. Note that this done on a best-effort
444 * basis; if the size is burried too deep in the image, we'll give up.
446 * @return NS_ERROR if an error is encountered, and NS_OK otherwise. (Note
447 * that we return NS_OK even when the size was not found.)
449 nsresult DecodeUntilSizeAvailable(RasterImage* aImg);
452 * Returns an event target interface to the thread pool; primarily for
453 * OnDataAvailable delivery off main thread.
455 * @return An nsIEventTarget interface to mThreadPool.
457 already_AddRefed<nsIEventTarget> GetEventTarget();
459 private: /* statics */
460 static StaticRefPtr<DecodePool> sSingleton;
462 private: /* methods */
463 DecodePool();
464 virtual ~DecodePool();
466 enum DecodeType {
467 DECODE_TYPE_UNTIL_TIME,
468 DECODE_TYPE_UNTIL_SIZE,
469 DECODE_TYPE_UNTIL_DONE_BYTES
472 /* Decode some chunks of the given image. If aDecodeType is UNTIL_SIZE,
473 * decode until we have the image's size, then stop. If bytesToDecode is
474 * non-0, at most bytesToDecode bytes will be decoded. if aDecodeType is
475 * UNTIL_DONE_BYTES, decode until all bytesToDecode bytes are decoded.
477 nsresult DecodeSomeOfImage(RasterImage* aImg,
478 DecodeStrategy aStrategy,
479 DecodeType aDecodeType = DECODE_TYPE_UNTIL_TIME,
480 uint32_t bytesToDecode = 0);
482 /* A decode job dispatched to a thread pool by DecodePool.
484 class DecodeJob : public nsRunnable
486 public:
487 DecodeJob(DecodeRequest* aRequest, RasterImage* aImg)
488 : mRequest(aRequest)
489 , mImage(aImg)
492 NS_IMETHOD Run();
494 protected:
495 virtual ~DecodeJob();
497 private:
498 nsRefPtr<DecodeRequest> mRequest;
499 nsRefPtr<RasterImage> mImage;
502 private: /* members */
504 // mThreadPoolMutex protects mThreadPool. For all RasterImages R,
505 // R::mDecodingMonitor must be acquired before mThreadPoolMutex
506 // if both are acquired; the other order may cause deadlock.
507 Mutex mThreadPoolMutex;
508 nsCOMPtr<nsIThreadPool> mThreadPool;
511 class DecodeDoneWorker : public nsRunnable
513 public:
515 * Called by the DecodePool with an image when it's done some significant
516 * portion of decoding that needs to be notified about.
518 * Ensures the decode state accumulated by the decoding process gets
519 * applied to the image.
521 static void NotifyFinishedSomeDecoding(RasterImage* image, DecodeRequest* request);
523 NS_IMETHOD Run();
525 private: /* methods */
526 DecodeDoneWorker(RasterImage* image, DecodeRequest* request);
528 private: /* members */
530 nsRefPtr<RasterImage> mImage;
531 nsRefPtr<DecodeRequest> mRequest;
534 class FrameNeededWorker : public nsRunnable
536 public:
538 * Called by the DecodeJob with an image when it's been told by the
539 * decoder that it needs a new frame to be allocated on the main thread.
541 * Dispatches an event to do so, which will further dispatch a
542 * DecodeRequest event to continue decoding.
544 static void GetNewFrame(RasterImage* image);
546 NS_IMETHOD Run();
548 private: /* methods */
549 FrameNeededWorker(RasterImage* image);
551 private: /* members */
553 nsRefPtr<RasterImage> mImage;
556 nsresult FinishedSomeDecoding(eShutdownIntent intent = eShutdownIntent_Done,
557 DecodeRequest* request = nullptr);
559 bool DrawWithPreDownscaleIfNeeded(imgFrame *aFrame,
560 gfxContext *aContext,
561 const nsIntSize& aSize,
562 const ImageRegion& aRegion,
563 GraphicsFilter aFilter,
564 uint32_t aFlags);
566 TemporaryRef<gfx::SourceSurface> CopyFrame(uint32_t aWhichFrame,
567 uint32_t aFlags);
570 * Deletes and nulls out the frame in mFrames[framenum].
572 * Does not change the size of mFrames.
574 * @param framenum The index of the frame to be deleted.
575 * Must lie in [0, mFrames.Length() )
577 void DeleteImgFrame(uint32_t framenum);
579 already_AddRefed<imgFrame> GetImgFrameNoDecode(uint32_t framenum);
580 already_AddRefed<imgFrame> GetImgFrame(uint32_t framenum);
581 already_AddRefed<imgFrame> GetDrawableImgFrame(uint32_t framenum);
582 already_AddRefed<imgFrame> GetCurrentImgFrame();
583 uint32_t GetCurrentImgFrameIndex() const;
585 size_t SizeOfDecodedWithComputedFallbackIfHeap(gfxMemoryLocation aLocation,
586 MallocSizeOf aMallocSizeOf) const;
588 void EnsureAnimExists();
590 nsresult InternalAddFrameHelper(uint32_t framenum, imgFrame *frame,
591 uint8_t **imageData, uint32_t *imageLength,
592 uint32_t **paletteData, uint32_t *paletteLength,
593 imgFrame** aRetFrame);
594 nsresult InternalAddFrame(uint32_t framenum, int32_t aX, int32_t aY, int32_t aWidth, int32_t aHeight,
595 gfx::SurfaceFormat aFormat, uint8_t aPaletteDepth,
596 uint8_t **imageData, uint32_t *imageLength,
597 uint32_t **paletteData, uint32_t *paletteLength,
598 imgFrame** aRetFrame);
600 nsresult DoImageDataComplete();
602 bool ApplyDecodeFlags(uint32_t aNewFlags, uint32_t aWhichFrame);
604 already_AddRefed<layers::Image> GetCurrentImage();
605 void UpdateImageContainer();
607 void SetInUpdateImageContainer(bool aInUpdate) { mInUpdateImageContainer = aInUpdate; }
608 bool IsInUpdateImageContainer() { return mInUpdateImageContainer; }
609 enum RequestDecodeType {
610 ASYNCHRONOUS,
611 SYNCHRONOUS_NOTIFY,
612 SYNCHRONOUS_NOTIFY_AND_SOME_DECODE
614 NS_IMETHOD RequestDecodeCore(RequestDecodeType aDecodeType);
616 // We would like to just check if we have a zero lock count, but we can't do
617 // that for animated images because in EnsureAnimExists we lock the image and
618 // never unlock so that animated images always have their lock count >= 1. In
619 // that case we use our animation consumers count as a proxy for lock count.
620 bool IsUnlocked() { return (mLockCount == 0 || (mAnim && mAnimationConsumers == 0)); }
622 private: // data
623 nsIntSize mSize;
624 Orientation mOrientation;
626 // Whether our frames were decoded using any special flags.
627 // Some flags (e.g. unpremultiplied data) may not be compatible
628 // with the browser's needs for displaying the image to the user.
629 // As such, we may need to redecode if we're being asked for
630 // a frame with different flags. 0 indicates default flags.
632 // Valid flag bits are imgIContainer::FLAG_DECODE_NO_PREMULTIPLY_ALPHA
633 // and imgIContainer::FLAG_DECODE_NO_COLORSPACE_CONVERSION.
634 uint32_t mFrameDecodeFlags;
636 //! All the frames of the image
637 FrameBlender mFrameBlender;
639 // The last frame we decoded for multipart images.
640 nsRefPtr<imgFrame> mMultipartDecodedFrame;
642 nsCOMPtr<nsIProperties> mProperties;
644 // IMPORTANT: if you use mAnim in a method, call EnsureImageIsDecoded() first to ensure
645 // that the frames actually exist (they may have been discarded to save memory, or
646 // we maybe decoding on draw).
647 FrameAnimator* mAnim;
649 // Discard members
650 uint32_t mLockCount;
651 DiscardTracker::Node mDiscardTrackerNode;
653 // Source data members
654 nsCString mSourceDataMimeType;
656 friend class DiscardTracker;
658 // How many times we've decoded this image.
659 // This is currently only used for statistics
660 int32_t mDecodeCount;
662 // If the image contains multiple resolutions, a hint as to which one should be used
663 nsIntSize mRequestedResolution;
665 // A hint for image decoder that directly scale the image to smaller buffer
666 int mRequestedSampleSize;
668 // Cached value for GetImageContainer.
669 nsRefPtr<layers::ImageContainer> mImageContainer;
671 // If not cached in mImageContainer, this might have our image container
672 WeakPtr<layers::ImageContainer> mImageContainerCache;
674 #ifdef DEBUG
675 uint32_t mFramesNotified;
676 #endif
678 // Below are the pieces of data that can be accessed on more than one thread
679 // at once, and hence need to be locked by mDecodingMonitor.
681 // BEGIN LOCKED MEMBER VARIABLES
682 ReentrantMonitor mDecodingMonitor;
684 FallibleTArray<char> mSourceData;
686 // Decoder and friends
687 nsRefPtr<Decoder> mDecoder;
688 nsRefPtr<DecodeRequest> mDecodeRequest;
689 size_t mBytesDecoded;
691 bool mInDecoder;
692 // END LOCKED MEMBER VARIABLES
694 // Notification state. Used to avoid recursive notifications.
695 ImageStatusDiff mStatusDiff;
696 bool mNotifying:1;
698 // Boolean flags (clustered together to conserve space):
699 bool mHasSize:1; // Has SetSize() been called?
700 bool mDecodeOnDraw:1; // Decoding on draw?
701 bool mMultipart:1; // Multipart?
702 bool mDiscardable:1; // Is container discardable?
703 bool mHasSourceData:1; // Do we have source data?
705 // Do we have the frames in decoded form?
706 bool mDecoded:1;
707 bool mHasBeenDecoded:1;
710 // Whether the animation can stop, due to running out
711 // of frames, or no more owning request
712 bool mAnimationFinished:1;
714 // Whether we're calling Decoder::Finish() from ShutdownDecoder.
715 bool mFinishing:1;
717 bool mInUpdateImageContainer:1;
719 // Whether, once we are done doing a size decode, we should immediately kick
720 // off a full decode.
721 bool mWantFullDecode:1;
723 // Set when a decode worker detects an error off-main-thread. Once the error
724 // is handled on the main thread, mError is set, but mPendingError is used to
725 // stop decode work immediately.
726 bool mPendingError:1;
728 // Decoding
729 nsresult RequestDecodeIfNeeded(nsresult aStatus,
730 eShutdownIntent aIntent,
731 bool aDone,
732 bool aWasSize);
733 nsresult WantDecodedFrames();
734 nsresult SyncDecode();
735 nsresult InitDecoder(bool aDoSizeDecode);
736 nsresult WriteToDecoder(const char *aBuffer, uint32_t aCount, DecodeStrategy aStrategy);
737 nsresult DecodeSomeData(size_t aMaxBytes, DecodeStrategy aStrategy);
738 bool IsDecodeFinished();
739 TimeStamp mDrawStartTime;
741 inline bool CanQualityScale(const gfx::Size& scale);
742 inline bool CanScale(GraphicsFilter aFilter, gfx::Size aScale, uint32_t aFlags);
744 struct ScaleResult
746 ScaleResult()
747 : status(SCALE_INVALID)
750 nsIntSize scaledSize;
751 nsRefPtr<imgFrame> frame;
752 ScaleStatus status;
755 ScaleResult mScaleResult;
757 // We hold on to a bare pointer to a ScaleRequest while it's outstanding so
758 // we can mark it as stopped if necessary. The ScaleWorker/DrawWorker duo
759 // will inform us when to let go of this pointer.
760 ScaleRequest* mScaleRequest;
762 // Initializes imgStatusTracker and resets it on RasterImage destruction.
763 nsAutoPtr<imgStatusTrackerInit> mStatusTrackerInit;
765 nsresult ShutdownDecoder(eShutdownIntent aIntent);
767 // Error handling.
768 void DoError();
770 class HandleErrorWorker : public nsRunnable
772 public:
774 * Called from decoder threads when DoError() is called, since errors can't
775 * be handled safely off-main-thread. Dispatches an event which reinvokes
776 * DoError on the main thread if there isn't one already pending.
778 static void DispatchIfNeeded(RasterImage* aImage);
780 NS_IMETHOD Run();
782 private:
783 HandleErrorWorker(RasterImage* aImage);
785 nsRefPtr<RasterImage> mImage;
788 // Helpers
789 bool CanDiscard();
790 bool CanForciblyDiscard();
791 bool CanForciblyDiscardAndRedecode();
792 bool DiscardingActive();
793 bool StoringSourceData() const;
795 protected:
796 RasterImage(imgStatusTracker* aStatusTracker = nullptr,
797 ImageURL* aURI = nullptr);
799 bool ShouldAnimate();
801 friend class ImageFactory;
804 inline NS_IMETHODIMP RasterImage::GetAnimationMode(uint16_t *aAnimationMode) {
805 return GetAnimationModeInternal(aAnimationMode);
808 // Asynchronous Decode Requestor
810 // We use this class when someone calls requestDecode() from within a decode
811 // notification. Since requestDecode() involves modifying the decoder's state
812 // (for example, possibly shutting down a header-only decode and starting a
813 // full decode), we don't want to do this from inside a decoder.
814 class imgDecodeRequestor : public nsRunnable
816 public:
817 imgDecodeRequestor(RasterImage &aContainer) {
818 mContainer = &aContainer;
820 NS_IMETHOD Run() {
821 if (mContainer)
822 mContainer->StartDecoding();
823 return NS_OK;
826 private:
827 WeakPtr<RasterImage> mContainer;
830 } // namespace image
831 } // namespace mozilla
833 #endif /* mozilla_imagelib_RasterImage_h_ */