1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 : *
3 : * ***** BEGIN LICENSE BLOCK *****
4 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 : *
6 : * The contents of this file are subject to the Mozilla Public License Version
7 : * 1.1 (the "License"); you may not use this file except in compliance with
8 : * the License. You may obtain a copy of the License at
9 : * http://www.mozilla.org/MPL/
10 : *
11 : * Software distributed under the License is distributed on an "AS IS" basis,
12 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 : * for the specific language governing rights and limitations under the
14 : * License.
15 : *
16 : * The Original Code is mozilla.org code.
17 : *
18 : * The Initial Developer of the Original Code is
19 : * Netscape Communications Corporation.
20 : * Portions created by the Initial Developer are Copyright (C) 2001
21 : * the Initial Developer. All Rights Reserved.
22 : *
23 : * Contributor(s):
24 : * Stuart Parmenter <pavlov@netscape.com>
25 : * Chris Saari <saari@netscape.com>
26 : * Federico Mena-Quintero <federico@novell.com>
27 : * Bobby Holley <bobbyholley@gmail.com>
28 : *
29 : * Alternatively, the contents of this file may be used under the terms of
30 : * either the GNU General Public License Version 2 or later (the "GPL"), or
31 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
32 : * in which case the provisions of the GPL or the LGPL are applicable instead
33 : * of those above. If you wish to allow use of your version of this file only
34 : * under the terms of either the GPL or the LGPL, and not to allow others to
35 : * use your version of this file under the terms of the MPL, indicate your
36 : * decision by deleting the provisions above and replace them with the notice
37 : * and other provisions required by the GPL or the LGPL. If you do not delete
38 : * the provisions above, a recipient may use your version of this file under
39 : * the terms of any one of the MPL, the GPL or the LGPL.
40 : *
41 : * ***** END LICENSE BLOCK ***** */
42 :
43 : /** @file
44 : * This file declares the RasterImage class, which
45 : * handles static and animated rasterized images.
46 : *
47 : * @author Stuart Parmenter <pavlov@netscape.com>
48 : * @author Chris Saari <saari@netscape.com>
49 : * @author Arron Mogge <paper@animecity.nu>
50 : * @author Andrew Smith <asmith15@learn.senecac.on.ca>
51 : */
52 :
53 : #ifndef mozilla_imagelib_RasterImage_h_
54 : #define mozilla_imagelib_RasterImage_h_
55 :
56 : #include "Image.h"
57 : #include "nsCOMArray.h"
58 : #include "nsCOMPtr.h"
59 : #include "imgIContainer.h"
60 : #include "nsIProperties.h"
61 : #include "nsITimer.h"
62 : #include "nsWeakReference.h"
63 : #include "nsTArray.h"
64 : #include "imgFrame.h"
65 : #include "nsThreadUtils.h"
66 : #include "DiscardTracker.h"
67 : #include "mozilla/TimeStamp.h"
68 : #include "mozilla/Telemetry.h"
69 : #include "mozilla/LinkedList.h"
70 : #ifdef DEBUG
71 : #include "imgIContainerDebug.h"
72 : #endif
73 :
74 : class imgIDecoder;
75 : class imgIContainerObserver;
76 : class nsIInputStream;
77 :
78 : #define NS_RASTERIMAGE_CID \
79 : { /* 376ff2c1-9bf6-418a-b143-3340c00112f7 */ \
80 : 0x376ff2c1, \
81 : 0x9bf6, \
82 : 0x418a, \
83 : {0xb1, 0x43, 0x33, 0x40, 0xc0, 0x01, 0x12, 0xf7} \
84 : }
85 :
86 : /**
87 : * Handles static and animated image containers.
88 : *
89 : *
90 : * @par A Quick Walk Through
91 : * The decoder initializes this class and calls AppendFrame() to add a frame.
92 : * Once RasterImage detects more than one frame, it starts the animation
93 : * with StartAnimation(). Note that the invalidation events for RasterImage are
94 : * generated automatically using nsRefreshDriver.
95 : *
96 : * @par
97 : * StartAnimation() initializes the animation helper object and sets the time
98 : * the first frame was displayed to the current clock time.
99 : *
100 : * @par
101 : * When the refresh driver corresponding to the imgIContainer that this image is
102 : * a part of notifies the RasterImage that it's time to invalidate,
103 : * RequestRefresh() is called with a given TimeStamp to advance to. As long as
104 : * the timeout of the given frame (the frame's "delay") plus the time that frame
105 : * was first displayed is less than or equal to the TimeStamp given,
106 : * RequestRefresh() calls AdvanceFrame().
107 : *
108 : * @par
109 : * AdvanceFrame() is responsible for advancing a single frame of the animation.
110 : * It can return true, meaning that the frame advanced, or false, meaning that
111 : * the frame failed to advance (usually because the next frame hasn't been
112 : * decoded yet). It is also responsible for performing the final animation stop
113 : * procedure if the final frame of a non-looping animation is reached.
114 : *
115 : * @par
116 : * Each frame can have a different method of removing itself. These are
117 : * listed as imgIContainer::cDispose... constants. Notify() calls
118 : * DoComposite() to handle any special frame destruction.
119 : *
120 : * @par
121 : * The basic path through DoComposite() is:
122 : * 1) Calculate Area that needs updating, which is at least the area of
123 : * aNextFrame.
124 : * 2) Dispose of previous frame.
125 : * 3) Draw new image onto compositingFrame.
126 : * See comments in DoComposite() for more information and optimizations.
127 : *
128 : * @par
129 : * The rest of the RasterImage specific functions are used by DoComposite to
130 : * destroy the old frame and build the new one.
131 : *
132 : * @note
133 : * <li> "Mask", "Alpha", and "Alpha Level" are interchangeable phrases in
134 : * respects to RasterImage.
135 : *
136 : * @par
137 : * <li> GIFs never have more than a 1 bit alpha.
138 : * <li> APNGs may have a full alpha channel.
139 : *
140 : * @par
141 : * <li> Background color specified in GIF is ignored by web browsers.
142 : *
143 : * @par
144 : * <li> If Frame 3 wants to dispose by restoring previous, what it wants is to
145 : * restore the composition up to and including Frame 2, as well as Frame 2s
146 : * disposal. So, in the middle of DoComposite when composing Frame 3, right
147 : * after destroying Frame 2's area, we copy compositingFrame to
148 : * prevCompositingFrame. When DoComposite gets called to do Frame 4, we
149 : * copy prevCompositingFrame back, and then draw Frame 4 on top.
150 : *
151 : * @par
152 : * The mAnim structure has members only needed for animated images, so
153 : * it's not allocated until the second frame is added.
154 : *
155 : * @note
156 : * mAnimationMode, mLoopCount and mObserver are not in the mAnim structure
157 : * because the first two have public setters and the observer we only get
158 : * in Init().
159 : */
160 :
161 : namespace mozilla {
162 : namespace layers {
163 : class LayerManager;
164 : class ImageContainer;
165 : }
166 : namespace image {
167 :
168 : class Decoder;
169 :
170 : class RasterImage : public Image
171 : , public nsIProperties
172 : , public nsSupportsWeakReference
173 : #ifdef DEBUG
174 : , public imgIContainerDebug
175 : #endif
176 : {
177 : public:
178 : NS_DECL_ISUPPORTS
179 : NS_DECL_NSIPROPERTIES
180 : #ifdef DEBUG
181 : NS_DECL_IMGICONTAINERDEBUG
182 : #endif
183 :
184 : // BEGIN NS_DECL_IMGICONTAINER (minus GetAnimationMode/SetAnimationMode)
185 : // ** Don't edit this chunk except to mirror changes in imgIContainer.idl **
186 : NS_SCRIPTABLE NS_IMETHOD GetWidth(PRInt32 *aWidth);
187 : NS_SCRIPTABLE NS_IMETHOD GetHeight(PRInt32 *aHeight);
188 : NS_SCRIPTABLE NS_IMETHOD GetType(PRUint16 *aType);
189 : NS_IMETHOD_(PRUint16) GetType(void);
190 : NS_SCRIPTABLE NS_IMETHOD GetAnimated(bool *aAnimated);
191 : NS_SCRIPTABLE NS_IMETHOD GetCurrentFrameIsOpaque(bool *aCurrentFrameIsOpaque);
192 : NS_IMETHOD GetFrame(PRUint32 aWhichFrame, PRUint32 aFlags, gfxASurface **_retval NS_OUTPARAM);
193 : NS_IMETHOD GetImageContainer(mozilla::layers::ImageContainer **_retval NS_OUTPARAM);
194 : NS_IMETHOD CopyFrame(PRUint32 aWhichFrame, PRUint32 aFlags, gfxImageSurface **_retval NS_OUTPARAM);
195 : NS_IMETHOD ExtractFrame(PRUint32 aWhichFrame, const nsIntRect & aRect, PRUint32 aFlags, imgIContainer **_retval NS_OUTPARAM);
196 : NS_IMETHOD Draw(gfxContext *aContext, gfxPattern::GraphicsFilter aFilter, const gfxMatrix & aUserSpaceToImageSpace, const gfxRect & aFill, const nsIntRect & aSubimage, const nsIntSize & aViewportSize, PRUint32 aFlags);
197 : NS_IMETHOD_(nsIFrame *) GetRootLayoutFrame(void);
198 : NS_SCRIPTABLE NS_IMETHOD RequestDecode(void);
199 : NS_SCRIPTABLE NS_IMETHOD LockImage(void);
200 : NS_SCRIPTABLE NS_IMETHOD UnlockImage(void);
201 : NS_SCRIPTABLE NS_IMETHOD RequestDiscard(void);
202 : NS_SCRIPTABLE NS_IMETHOD ResetAnimation(void);
203 : NS_IMETHOD_(void) RequestRefresh(const mozilla::TimeStamp& aTime);
204 : // END NS_DECL_IMGICONTAINER
205 :
206 : RasterImage(imgStatusTracker* aStatusTracker = nsnull);
207 : virtual ~RasterImage();
208 :
209 : virtual nsresult StartAnimation();
210 : virtual nsresult StopAnimation();
211 :
212 : // Methods inherited from Image
213 : nsresult Init(imgIDecoderObserver* aObserver,
214 : const char* aMimeType,
215 : const char* aURIString,
216 : PRUint32 aFlags);
217 : void GetCurrentFrameRect(nsIntRect& aRect);
218 :
219 : // Raster-specific methods
220 : static NS_METHOD WriteToRasterImage(nsIInputStream* aIn, void* aClosure,
221 : const char* aFromRawSegment,
222 : PRUint32 aToOffset, PRUint32 aCount,
223 : PRUint32* aWriteCount);
224 :
225 : /* The index of the current frame that would be drawn if the image was to be
226 : * drawn now. */
227 : PRUint32 GetCurrentFrameIndex();
228 :
229 : /* The total number of frames in this image. */
230 : PRUint32 GetNumFrames();
231 :
232 : virtual size_t HeapSizeOfSourceWithComputedFallback(nsMallocSizeOfFun aMallocSizeOf) const;
233 : virtual size_t HeapSizeOfDecodedWithComputedFallback(nsMallocSizeOfFun aMallocSizeOf) const;
234 : virtual size_t NonHeapSizeOfDecoded() const;
235 : virtual size_t OutOfProcessSizeOfDecoded() const;
236 :
237 : /* Triggers discarding. */
238 : void Discard(bool force = false);
239 0 : void ForceDiscard() { Discard(/* force = */ true); }
240 :
241 : /* Callbacks for decoders */
242 : nsresult SetFrameDisposalMethod(PRUint32 aFrameNum,
243 : PRInt32 aDisposalMethod);
244 : nsresult SetFrameTimeout(PRUint32 aFrameNum, PRInt32 aTimeout);
245 : nsresult SetFrameBlendMethod(PRUint32 aFrameNum, PRInt32 aBlendMethod);
246 : nsresult SetFrameHasNoAlpha(PRUint32 aFrameNum);
247 :
248 : /**
249 : * Sets the size of the container. This should only be called by the
250 : * decoder. This function may be called multiple times, but will throw an
251 : * error if subsequent calls do not match the first.
252 : */
253 : nsresult SetSize(PRInt32 aWidth, PRInt32 aHeight);
254 :
255 :
256 : /**
257 : * Ensures that a given frame number exists with the given parameters, and
258 : * returns pointers to the data storage for that frame.
259 : * It is not possible to create sparse frame arrays; you can only append
260 : * frames to the current frame array.
261 : */
262 : nsresult EnsureFrame(PRUint32 aFramenum, PRInt32 aX, PRInt32 aY,
263 : PRInt32 aWidth, PRInt32 aHeight,
264 : gfxASurface::gfxImageFormat aFormat,
265 : PRUint8 aPaletteDepth,
266 : PRUint8** imageData,
267 : PRUint32* imageLength,
268 : PRUint32** paletteData,
269 : PRUint32* paletteLength);
270 :
271 : /**
272 : * A shorthand for EnsureFrame, above, with aPaletteDepth = 0 and paletteData
273 : * and paletteLength set to null.
274 : */
275 : nsresult EnsureFrame(PRUint32 aFramenum, PRInt32 aX, PRInt32 aY,
276 : PRInt32 aWidth, PRInt32 aHeight,
277 : gfxASurface::gfxImageFormat aFormat,
278 : PRUint8** imageData,
279 : PRUint32* imageLength);
280 :
281 : void FrameUpdated(PRUint32 aFrameNum, nsIntRect& aUpdatedRect);
282 :
283 : /* notification that the entire image has been decoded */
284 : nsresult DecodingComplete();
285 :
286 : /**
287 : * Number of times to loop the image.
288 : * @note -1 means forever.
289 : */
290 : void SetLoopCount(PRInt32 aLoopCount);
291 :
292 : /* Add compressed source data to the imgContainer.
293 : *
294 : * The decoder will use this data, either immediately or at draw time, to
295 : * decode the image.
296 : *
297 : * XXX This method's only caller (WriteToContainer) ignores the return
298 : * value. Should this just return void?
299 : */
300 : nsresult AddSourceData(const char *aBuffer, PRUint32 aCount);
301 :
302 : /* Called after the all the source data has been added with addSourceData. */
303 : nsresult SourceDataComplete();
304 :
305 : /* Called for multipart images when there's a new source image to add. */
306 : nsresult NewSourceData();
307 :
308 : /**
309 : * A hint of the number of bytes of source data that the image contains. If
310 : * called early on, this can help reduce copying and reallocations by
311 : * appropriately preallocating the source data buffer.
312 : *
313 : * We take this approach rather than having the source data management code do
314 : * something more complicated (like chunklisting) because HTTP is by far the
315 : * dominant source of images, and the Content-Length header is quite reliable.
316 : * Thus, pre-allocation simplifies code and reduces the total number of
317 : * allocations.
318 : */
319 : nsresult SetSourceSizeHint(PRUint32 sizeHint);
320 :
321 : // "Blend" method indicates how the current image is combined with the
322 : // previous image.
323 : enum {
324 : // All color components of the frame, including alpha, overwrite the current
325 : // contents of the frame's output buffer region
326 : kBlendSource = 0,
327 :
328 : // The frame should be composited onto the output buffer based on its alpha,
329 : // using a simple OVER operation
330 : kBlendOver
331 : };
332 :
333 : enum {
334 : kDisposeClearAll = -1, // Clear the whole image, revealing
335 : // what was there before the gif displayed
336 : kDisposeNotSpecified, // Leave frame, let new frame draw on top
337 : kDisposeKeep, // Leave frame, let new frame draw on top
338 : kDisposeClear, // Clear the frame's area, revealing bg
339 : kDisposeRestorePrevious // Restore the previous (composited) frame
340 : };
341 :
342 2 : const char* GetURIString() { return mURIString.get();}
343 :
344 : private:
345 : struct Anim
346 : {
347 : //! Area of the first frame that needs to be redrawn on subsequent loops.
348 : nsIntRect firstFrameRefreshArea;
349 : PRUint32 currentAnimationFrameIndex; // 0 to numFrames-1
350 :
351 : // the time that the animation advanced to the current frame
352 : TimeStamp currentAnimationFrameTime;
353 :
354 : //! Track the last composited frame for Optimizations (See DoComposite code)
355 : PRInt32 lastCompositedFrameIndex;
356 : /** For managing blending of frames
357 : *
358 : * Some animations will use the compositingFrame to composite images
359 : * and just hand this back to the caller when it is time to draw the frame.
360 : * NOTE: When clearing compositingFrame, remember to set
361 : * lastCompositedFrameIndex to -1. Code assume that if
362 : * lastCompositedFrameIndex >= 0 then compositingFrame exists.
363 : */
364 : nsAutoPtr<imgFrame> compositingFrame;
365 : /** the previous composited frame, for DISPOSE_RESTORE_PREVIOUS
366 : *
367 : * The Previous Frame (all frames composited up to the current) needs to be
368 : * stored in cases where the image specifies it wants the last frame back
369 : * when it's done with the current frame.
370 : */
371 : nsAutoPtr<imgFrame> compositingPrevFrame;
372 :
373 1 : Anim() :
374 : firstFrameRefreshArea(),
375 : currentAnimationFrameIndex(0),
376 1 : lastCompositedFrameIndex(-1) {}
377 1 : ~Anim() {}
378 : };
379 :
380 : /**
381 : * DecodeWorker keeps a linked list of DecodeRequests to keep track of the
382 : * images it needs to decode.
383 : *
384 : * Each RasterImage has a single DecodeRequest member.
385 : */
386 : struct DecodeRequest : public LinkedListElement<DecodeRequest>
387 : {
388 24 : DecodeRequest(RasterImage* aImage)
389 : : mImage(aImage)
390 24 : , mIsASAP(false)
391 : {
392 24 : }
393 :
394 : RasterImage* const mImage;
395 :
396 : /* Keeps track of how much time we've burned decoding this particular decode
397 : * request. */
398 : TimeDuration mDecodeTime;
399 :
400 : /* True if we need to handle this decode as soon as possible. */
401 : bool mIsASAP;
402 : };
403 :
404 : /*
405 : * DecodeWorker is a singleton class we use when decoding large images.
406 : *
407 : * When we wish to decode an image larger than
408 : * image.mem.max_bytes_for_sync_decode, we call DecodeWorker::RequestDecode()
409 : * for the image. This adds the image to a queue of pending requests and posts
410 : * the DecodeWorker singleton to the event queue, if it's not already pending
411 : * there.
412 : *
413 : * When the DecodeWorker is run from the event queue, it decodes the image (and
414 : * all others it's managing) in chunks, periodically yielding control back to
415 : * the event loop.
416 : *
417 : * An image being decoded may have one of two priorities: normal or ASAP. ASAP
418 : * images are always decoded before normal images. (We currently give ASAP
419 : * priority to images which appear onscreen but are not yet decoded.)
420 : */
421 : class DecodeWorker : public nsRunnable
422 16 : {
423 : public:
424 : static DecodeWorker* Singleton();
425 :
426 : /**
427 : * Ask the DecodeWorker to asynchronously decode this image.
428 : */
429 : void RequestDecode(RasterImage* aImg);
430 :
431 : /**
432 : * Give this image ASAP priority; it will be decoded before all non-ASAP
433 : * images. You can call MarkAsASAP before or after you call RequestDecode
434 : * for the image, but if you MarkAsASAP before you call RequestDecode, you
435 : * still need to call RequestDecode.
436 : *
437 : * StopDecoding() resets the image's ASAP flag.
438 : */
439 : void MarkAsASAP(RasterImage* aImg);
440 :
441 : /**
442 : * Ask the DecodeWorker to stop decoding this image. Internally, we also
443 : * call this function when we finish decoding an image.
444 : *
445 : * Since the DecodeWorker keeps raw pointers to RasterImages, make sure you
446 : * call this before a RasterImage is destroyed!
447 : */
448 : void StopDecoding(RasterImage* aImg);
449 :
450 : /**
451 : * Synchronously decode the beginning of the image until we run out of
452 : * bytes or we get the image's size. Note that this done on a best-effort
453 : * basis; if the size is burried too deep in the image, we'll give up.
454 : *
455 : * @return NS_ERROR if an error is encountered, and NS_OK otherwise. (Note
456 : * that we return NS_OK even when the size was not found.)
457 : */
458 : nsresult DecodeUntilSizeAvailable(RasterImage* aImg);
459 :
460 : NS_IMETHOD Run();
461 :
462 : private: /* statics */
463 : static nsRefPtr<DecodeWorker> sSingleton;
464 :
465 : private: /* methods */
466 4 : DecodeWorker()
467 4 : : mPendingInEventLoop(false)
468 4 : {}
469 :
470 : /* Post ourselves to the event loop if we're not currently pending. */
471 : void EnsurePendingInEventLoop();
472 :
473 : /* Add the given request to the appropriate list of decode requests, but
474 : * don't ensure that we're pending in the event loop. */
475 : void AddDecodeRequest(DecodeRequest* aRequest);
476 :
477 : enum DecodeType {
478 : DECODE_TYPE_NORMAL,
479 : DECODE_TYPE_UNTIL_SIZE
480 : };
481 :
482 : /* Decode some chunks of the given image. If aDecodeType is UNTIL_SIZE,
483 : * decode until we have the image's size, then stop. */
484 : nsresult DecodeSomeOfImage(RasterImage* aImg,
485 : DecodeType aDecodeType = DECODE_TYPE_NORMAL);
486 :
487 : private: /* members */
488 :
489 : LinkedList<DecodeRequest> mASAPDecodeRequests;
490 : LinkedList<DecodeRequest> mNormalDecodeRequests;
491 :
492 : /* True if we've posted ourselves to the event loop and expect Run() to
493 : * be called sometime in the future. */
494 : bool mPendingInEventLoop;
495 : };
496 :
497 : /**
498 : * Advances the animation. Typically, this will advance a single frame, but it
499 : * may advance multiple frames. This may happen if we have infrequently
500 : * "ticking" refresh drivers (e.g. in background tabs), or extremely short-
501 : * lived animation frames.
502 : *
503 : * @param aTime the time that the animation should advance to. This will
504 : * typically be <= TimeStamp::Now().
505 : *
506 : * @param [out] aDirtyRect a pointer to an nsIntRect which encapsulates the
507 : * area to be repainted after the frame is advanced.
508 : *
509 : * @returns true, if the frame was successfully advanced, false if it was not
510 : * able to be advanced (e.g. the frame to which we want to advance is
511 : * still decoding). Note: If false is returned, then aDirtyRect will
512 : * remain unmodified.
513 : */
514 : bool AdvanceFrame(mozilla::TimeStamp aTime, nsIntRect* aDirtyRect);
515 :
516 : /**
517 : * Deletes and nulls out the frame in mFrames[framenum].
518 : *
519 : * Does not change the size of mFrames.
520 : *
521 : * @param framenum The index of the frame to be deleted.
522 : * Must lie in [0, mFrames.Length() )
523 : */
524 : void DeleteImgFrame(PRUint32 framenum);
525 :
526 : imgFrame* GetImgFrameNoDecode(PRUint32 framenum);
527 : imgFrame* GetImgFrame(PRUint32 framenum);
528 : imgFrame* GetDrawableImgFrame(PRUint32 framenum);
529 : imgFrame* GetCurrentImgFrame();
530 : imgFrame* GetCurrentDrawableImgFrame();
531 : PRUint32 GetCurrentImgFrameIndex() const;
532 : mozilla::TimeStamp GetCurrentImgFrameEndTime() const;
533 :
534 1 : inline void EnsureAnimExists()
535 : {
536 1 : if (!mAnim) {
537 :
538 : // Create the animation context
539 1 : mAnim = new Anim();
540 :
541 : // We don't support discarding animated images (See bug 414259).
542 : // Lock the image and throw away the key.
543 : //
544 : // Note that this is inefficient, since we could get rid of the source
545 : // data too. However, doing this is actually hard, because we're probably
546 : // calling ensureAnimExists mid-decode, and thus we're decoding out of
547 : // the source buffer. Since we're going to fix this anyway later, and
548 : // since we didn't kill the source data in the old world either, locking
549 : // is acceptable for the moment.
550 1 : LockImage();
551 :
552 : // Notify our observers that we are starting animation.
553 1 : mStatusTracker->RecordImageIsAnimated();
554 : }
555 1 : }
556 :
557 : /** Function for doing the frame compositing of animations
558 : *
559 : * @param aDirtyRect Area that the display will need to update
560 : * @param aPrevFrame Last Frame seen/processed
561 : * @param aNextFrame Frame we need to incorperate/display
562 : * @param aNextFrameIndex Position of aNextFrame in mFrames list
563 : */
564 : nsresult DoComposite(nsIntRect* aDirtyRect,
565 : imgFrame* aPrevFrame,
566 : imgFrame* aNextFrame,
567 : PRInt32 aNextFrameIndex);
568 :
569 : /** Clears an area of <aFrame> with transparent black.
570 : *
571 : * @param aFrame Target Frame
572 : *
573 : * @note Does also clears the transparancy mask
574 : */
575 : static void ClearFrame(imgFrame* aFrame);
576 :
577 : //! @overload
578 : static void ClearFrame(imgFrame* aFrame, nsIntRect &aRect);
579 :
580 : //! Copy one frames's image and mask into another
581 : static bool CopyFrameImage(imgFrame *aSrcFrame,
582 : imgFrame *aDstFrame);
583 :
584 : /** Draws one frames's image to into another,
585 : * at the position specified by aRect
586 : *
587 : * @param aSrcFrame Frame providing the source image
588 : * @param aDstFrame Frame where the image is drawn into
589 : * @param aRect The position and size to draw the image
590 : */
591 : static nsresult DrawFrameTo(imgFrame *aSrcFrame,
592 : imgFrame *aDstFrame,
593 : nsIntRect& aRect);
594 :
595 : nsresult InternalAddFrameHelper(PRUint32 framenum, imgFrame *frame,
596 : PRUint8 **imageData, PRUint32 *imageLength,
597 : PRUint32 **paletteData, PRUint32 *paletteLength);
598 : nsresult InternalAddFrame(PRUint32 framenum, PRInt32 aX, PRInt32 aY, PRInt32 aWidth, PRInt32 aHeight,
599 : gfxASurface::gfxImageFormat aFormat, PRUint8 aPaletteDepth,
600 : PRUint8 **imageData, PRUint32 *imageLength,
601 : PRUint32 **paletteData, PRUint32 *paletteLength);
602 :
603 : private: // data
604 :
605 : nsIntSize mSize;
606 :
607 : // Whether mFrames below were decoded using any special flags.
608 : // Some flags (e.g. unpremultiplied data) may not be compatible
609 : // with the browser's needs for displaying the image to the user.
610 : // As such, we may need to redecode if we're being asked for
611 : // a frame with different flags. 0 indicates default flags.
612 : //
613 : // Valid flag bits are imgIContainer::FLAG_DECODE_NO_PREMULTIPLY_ALPHA
614 : // and imgIContainer::FLAG_DECODE_NO_COLORSPACE_CONVERSION.
615 : PRUint32 mFrameDecodeFlags;
616 :
617 : //! All the frames of the image
618 : // IMPORTANT: if you use mFrames in a method, call EnsureImageIsDecoded() first
619 : // to ensure that the frames actually exist (they may have been discarded to save
620 : // memory, or we may be decoding on draw).
621 : nsTArray<imgFrame *> mFrames;
622 :
623 : nsCOMPtr<nsIProperties> mProperties;
624 :
625 : // IMPORTANT: if you use mAnim in a method, call EnsureImageIsDecoded() first to ensure
626 : // that the frames actually exist (they may have been discarded to save memory, or
627 : // we maybe decoding on draw).
628 : RasterImage::Anim* mAnim;
629 :
630 : //! # loops remaining before animation stops (-1 no stop)
631 : PRInt32 mLoopCount;
632 :
633 : //! imgIDecoderObserver
634 : nsWeakPtr mObserver;
635 :
636 : // Discard members
637 : PRUint32 mLockCount;
638 : DiscardTrackerNode mDiscardTrackerNode;
639 :
640 : // Source data members
641 : FallibleTArray<char> mSourceData;
642 : nsCString mSourceDataMimeType;
643 : nsCString mURIString;
644 :
645 : friend class DiscardTracker;
646 :
647 : // Decoder and friends
648 : nsRefPtr<Decoder> mDecoder;
649 : DecodeRequest mDecodeRequest;
650 : PRUint32 mBytesDecoded;
651 :
652 : // How many times we've decoded this image.
653 : // This is currently only used for statistics
654 : PRInt32 mDecodeCount;
655 :
656 : // Cached value for GetImageContainer.
657 : nsRefPtr<mozilla::layers::ImageContainer> mImageContainer;
658 :
659 : #ifdef DEBUG
660 : PRUint32 mFramesNotified;
661 : #endif
662 :
663 : // Boolean flags (clustered together to conserve space):
664 : bool mHasSize:1; // Has SetSize() been called?
665 : bool mDecodeOnDraw:1; // Decoding on draw?
666 : bool mMultipart:1; // Multipart?
667 : bool mDiscardable:1; // Is container discardable?
668 : bool mHasSourceData:1; // Do we have source data?
669 :
670 : // Do we have the frames in decoded form?
671 : bool mDecoded:1;
672 : bool mHasBeenDecoded:1;
673 :
674 : bool mInDecoder:1;
675 :
676 : // Whether the animation can stop, due to running out
677 : // of frames, or no more owning request
678 : bool mAnimationFinished:1;
679 :
680 : // Decoding
681 : nsresult WantDecodedFrames();
682 : nsresult SyncDecode();
683 : nsresult InitDecoder(bool aDoSizeDecode);
684 : nsresult WriteToDecoder(const char *aBuffer, PRUint32 aCount);
685 : nsresult DecodeSomeData(PRUint32 aMaxBytes);
686 : bool IsDecodeFinished();
687 : TimeStamp mDrawStartTime;
688 :
689 : // Decoder shutdown
690 : enum eShutdownIntent {
691 : eShutdownIntent_Done = 0,
692 : eShutdownIntent_Interrupted = 1,
693 : eShutdownIntent_Error = 2,
694 : eShutdownIntent_AllCount = 3
695 : };
696 : nsresult ShutdownDecoder(eShutdownIntent aIntent);
697 :
698 : // Helpers
699 : void DoError();
700 : bool CanDiscard();
701 : bool CanForciblyDiscard();
702 : bool DiscardingActive();
703 : bool StoringSourceData() const;
704 :
705 : protected:
706 : bool ShouldAnimate();
707 : };
708 :
709 : // Asynchronous Decode Requestor
710 : //
711 : // We use this class when someone calls requestDecode() from within a decode
712 : // notification. Since requestDecode() involves modifying the decoder's state
713 : // (for example, possibly shutting down a header-only decode and starting a
714 : // full decode), we don't want to do this from inside a decoder.
715 : class imgDecodeRequestor : public nsRunnable
716 0 : {
717 : public:
718 0 : imgDecodeRequestor(imgIContainer *aContainer) {
719 0 : mContainer = do_GetWeakReference(aContainer);
720 0 : }
721 0 : NS_IMETHOD Run() {
722 0 : nsCOMPtr<imgIContainer> con = do_QueryReferent(mContainer);
723 0 : if (con)
724 0 : con->RequestDecode();
725 0 : return NS_OK;
726 : }
727 :
728 : private:
729 : nsWeakPtr mContainer;
730 : };
731 :
732 : } // namespace image
733 : } // namespace mozilla
734 :
735 : #endif /* mozilla_imagelib_RasterImage_h_ */
|