Bug 517543 - need a STATUS_DECODE_COMPLETE for imgIRequest.r=joe
authorBobby Holley <bobbyholley@stanford.edu>
Tue, 06 Oct 2009 21:39:30 -0700
changeset 33531 6ac9e403c8a54b0b7ad7db5787331555366b589b
parent 33530 ccc6dad9010cb1ace2836f6f24d4071fc7106f3a
child 33532 5c891266e32ac66f7a6952d3cf83b34a3d58f37e
push idunknown
push userunknown
push dateunknown
reviewersjoe
bugs517543
milestone1.9.3a1pre
Bug 517543 - need a STATUS_DECODE_COMPLETE for imgIRequest.r=joe
layout/xul/base/src/tree/src/nsTreeBodyFrame.cpp
modules/libpr0n/public/imgIContainer.idl
modules/libpr0n/public/imgIRequest.idl
modules/libpr0n/src/imgContainer.cpp
modules/libpr0n/src/imgContainer.h
modules/libpr0n/src/imgRequest.cpp
--- a/layout/xul/base/src/tree/src/nsTreeBodyFrame.cpp
+++ b/layout/xul/base/src/tree/src/nsTreeBodyFrame.cpp
@@ -2170,18 +2170,20 @@ nsTreeBodyFrame::GetImage(PRInt32 aRowIn
   // Look the image up in our cache.
   nsTreeImageCacheEntry entry;
   if (mImageCache.Get(imageSrc, &entry)) {
     // Find out if the image has loaded.
     PRUint32 status;
     imgIRequest *imgReq = entry.request;
     imgReq->GetImageStatus(&status);
     imgReq->GetImage(aResult); // We hand back the image here.  The GetImage call addrefs *aResult.
-    PRBool animated = PR_FALSE;
-    if (*aResult)
+    PRBool animated = PR_TRUE; // Assuming animated is the safe option
+
+    // We can only call GetAnimated if we're decoded
+    if (*aResult && (status & imgIRequest::STATUS_DECODE_COMPLETE))
       (*aResult)->GetAnimated(&animated);
 
     if ((!(status & imgIRequest::STATUS_LOAD_COMPLETE)) || animated) {
       // We either aren't done loading, or we're animating. Add our row as a listener for invalidations.
       nsCOMPtr<imgIDecoderObserver> obs;
       imgReq->GetDecoderObserver(getter_AddRefs(obs));
       nsCOMPtr<nsITreeImageListener> listener(do_QueryInterface(obs));
       if (listener)
--- a/modules/libpr0n/public/imgIContainer.idl
+++ b/modules/libpr0n/public/imgIContainer.idl
@@ -80,17 +80,20 @@ interface imgIContainer : nsISupports
   readonly attribute PRInt32 width;
 
   /**
    * The height of the container rectangle.
    */
   readonly attribute PRInt32 height;
 
   /**
-   * Whether this image is animated.
+   * Whether this image is animated. You can only be guaranteed that querying
+   * this will not throw if STATUS_DECODE_COMPLETE is set on the imgIRequest.
+   *
+   * @throws NS_ERROR_NOT_AVAILABLE if the animated state cannot be determined.
    */
   readonly attribute boolean animated;
 
   /**
    * Whether the current frame is opaque; that is, needs the background painted
    * behind it.
    */
   readonly attribute boolean currentFrameIsOpaque;
--- a/modules/libpr0n/public/imgIRequest.idl
+++ b/modules/libpr0n/public/imgIRequest.idl
@@ -85,24 +85,27 @@ interface imgIRequest : nsIRequest
    *
    * STATUS_LOAD_COMPLETE: The data has been fully loaded
    * to memory, but not necessarily fully decoded.
    *
    * STATUS_ERROR: An error occured loading the image.
    *
    * STATUS_FRAME_COMPLETE: The first frame has been
    * completely decoded.
+   *
+   * STATUS_DECODE_COMPLETE: The whole image has been decoded.
    */
   //@{
   const long STATUS_NONE             = 0x0;
   const long STATUS_SIZE_AVAILABLE   = 0x1;
   const long STATUS_LOAD_PARTIAL     = 0x2;
   const long STATUS_LOAD_COMPLETE    = 0x4;
   const long STATUS_ERROR            = 0x8;
   const long STATUS_FRAME_COMPLETE   = 0x10;
+  const long STATUS_DECODE_COMPLETE  = 0x20;
   //@}
 
   /**
    * Status flags of the STATUS_* variety.
    */
   readonly attribute unsigned long imageStatus;
 
   /**
--- a/modules/libpr0n/src/imgContainer.cpp
+++ b/modules/libpr0n/src/imgContainer.cpp
@@ -147,16 +147,17 @@ imgContainer::imgContainer() :
   mDecodeOnDraw(PR_FALSE),
   mMultipart(PR_FALSE),
   mInitialized(PR_FALSE),
   mDiscardable(PR_FALSE),
   mLockCount(0),
   mDiscardTimer(nsnull),
   mHasSourceData(PR_FALSE),
   mDecoded(PR_FALSE),
+  mHasBeenDecoded(PR_FALSE),
   mDecoder(nsnull),
   mWorker(nsnull),
   mBytesDecoded(0),
   mDecoderInput(nsnull),
   mDecoderFlags(imgIDecoder::DECODER_FLAG_NONE),
   mWorkerPending(PR_FALSE),
   mInDecoder(PR_FALSE),
   mError(PR_FALSE)
@@ -294,16 +295,17 @@ NS_IMETHODIMP imgContainer::ExtractFrame
   NS_ENSURE_TRUE(img, NS_ERROR_OUT_OF_MEMORY);
 
   // We don't actually have a mimetype in this case. The empty string tells the
   // init routine not to try to instantiate a decoder. This should be fixed in
   // bug 505959.
   img->Init(nsnull, "", INIT_FLAG_NONE);
   img->SetSize(aRegion.width, aRegion.height);
   img->mDecoded = PR_TRUE; // Also, we need to mark the image as decoded
+  img->mHasBeenDecoded = PR_TRUE;
 
   // If a synchronous decode was requested, do it
   if (aFlags & FLAG_SYNC_DECODE) {
     rv = SyncDecode();
     CONTAINER_ENSURE_SUCCESS(rv);
   }
 
   // Get the frame. If it's not there, it's probably the caller's fault for
@@ -478,18 +480,30 @@ NS_IMETHODIMP imgContainer::GetNumFrames
 /* readonly attribute boolean animated; */
 NS_IMETHODIMP imgContainer::GetAnimated(PRBool *aAnimated)
 {
   if (mError)
     return NS_ERROR_FAILURE;
 
   NS_ENSURE_ARG_POINTER(aAnimated);
 
-  *aAnimated = (mAnim != nsnull);
-  
+  // If we have mAnim, we can know for sure
+  if (mAnim) {
+    *aAnimated = PR_TRUE;
+    return NS_OK;
+  }
+
+  // Otherwise, we need to have been decoded to know for sure, since if we were
+  // decoded at least once mAnim would have been created for animated images
+  if (!mHasBeenDecoded)
+    return NS_ERROR_NOT_AVAILABLE;
+
+  // We know for sure
+  *aAnimated = PR_FALSE;
+
   return NS_OK;
 }
 
 
 //******************************************************************************
 /* [noscript] gfxImageSurface copyFrame(in PRUint32 aWhichFrame,
  *                                      in PRUint32 aFlags); */
 NS_IMETHODIMP imgContainer::CopyFrame(PRUint32 aWhichFrame,
@@ -948,16 +962,17 @@ NS_IMETHODIMP imgContainer::DecodingComp
 {
   if (mError)
     return NS_ERROR_FAILURE;
 
   // Flag that we're done decoding.
   // XXX - these should probably be combined when we fix animated image
   // discarding with bug 500402.
   mDecoded = PR_TRUE;
+  mHasBeenDecoded = PR_TRUE;
   if (mAnim)
     mAnim->doneDecoding = PR_TRUE;
 
   nsresult rv;
 
   // We now have one of the qualifications for discarding. Re-evaluate.
   if (CanDiscard()) {
     NS_ABORT_IF_FALSE(!mDiscardTimer,
--- a/modules/libpr0n/src/imgContainer.h
+++ b/modules/libpr0n/src/imgContainer.h
@@ -322,16 +322,17 @@ private: // data
 
   // Source data members
   nsTArray<char>             mSourceData;
   PRBool                     mHasSourceData;
   nsCString                  mSourceDataMimeType;
 
   // Do we have the frames in decoded form?
   PRBool                     mDecoded;
+  PRBool                     mHasBeenDecoded;
 
   friend class imgDecodeWorker;
 
   // Decoder and friends
   nsCOMPtr<imgIDecoder>          mDecoder;
   nsRefPtr<imgDecodeWorker>      mWorker;
   PRUint32                       mBytesDecoded;
   nsCOMPtr<nsIStringInputStream> mDecoderInput;
--- a/modules/libpr0n/src/imgRequest.cpp
+++ b/modules/libpr0n/src/imgRequest.cpp
@@ -676,16 +676,20 @@ NS_IMETHODIMP imgRequest::OnStopDecode(i
                                        const PRUnichar *aStatusArg)
 {
   LOG_SCOPE(gImgLog, "imgRequest::OnStopDecode");
 
   // We finished the decode, and thus have the decoded frames. Update the cache
   // entry size to take this into account.
   UpdateCacheEntrySize();
 
+  // If we were successful, set STATUS_DECODE_COMPLETE
+  if (NS_SUCCEEDED(aStatus))
+    mImageStatus |= imgIRequest::STATUS_DECODE_COMPLETE;
+
   // ImgContainer and everything below it is completely correct and
   // bulletproof about its handling of decoder notifications.
   // Unfortunately, here and above we have to make some gross and
   // inappropriate use of things to get things to work without
   // completely overhauling the decoder observer interface (this will,
   // thankfully, happen in bug 505385). From imgRequest and above (for
   // the time being), OnStopDecode is just a companion to OnStopRequest
   // that signals success or failure of the _load_ (not the _decode_).
@@ -706,17 +710,18 @@ NS_IMETHODIMP imgRequest::OnStopRequest(
 /* void onDiscard (in imgIRequest request); */
 NS_IMETHODIMP imgRequest::OnDiscard(imgIRequest *aRequest)
 {
   // Clear the state bits we no longer deserve.
   PRUint32 stateBitsToClear = stateDecodeStarted;
   mState &= ~stateBitsToClear;
 
   // Clear the status bits we no longer deserve.
-  PRUint32 statusBitsToClear = imgIRequest::STATUS_FRAME_COMPLETE;
+  PRUint32 statusBitsToClear = imgIRequest::STATUS_FRAME_COMPLETE
+                               | imgIRequest::STATUS_DECODE_COMPLETE;
   mImageStatus &= ~statusBitsToClear;
 
   // Update the cache entry size, since we just got rid of frame data
   UpdateCacheEntrySize();
 
   nsTObserverArray<imgRequestProxy*>::ForwardIterator iter(mObservers);
   while (iter.HasMore()) {
     iter.GetNext()->OnDiscard();