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