diff --git a/content/base/src/nsImageLoadingContent.cpp b/content/base/src/nsImageLoadingContent.cpp index 02b9398e9e8..ec6fceb45e3 100644 --- a/content/base/src/nsImageLoadingContent.cpp +++ b/content/base/src/nsImageLoadingContent.cpp @@ -61,6 +61,7 @@ #include "nsNetUtil.h" #include "nsAsyncDOMEvent.h" #include "nsGenericElement.h" +#include "nsImageFrame.h" #include "nsIPresShell.h" #include "nsEventStates.h" @@ -300,10 +301,7 @@ nsImageLoadingContent::OnStopDecode(imgIRequest* aRequest, // If the pending request is loaded, switch to it. if (aRequest == mPendingRequest) { - PrepareCurrentRequest() = mPendingRequest; - mPendingRequest = nsnull; - mCurrentRequestNeedsResetAnimation = mPendingRequestNeedsResetAnimation; - mPendingRequestNeedsResetAnimation = false; + MakePendingRequestCurrent(); } NS_ABORT_IF_FALSE(aRequest == mCurrentRequest, "One way or another, we should be current by now"); @@ -792,6 +790,26 @@ nsImageLoadingContent::LoadImage(nsIURI* aNewURI, getter_AddRefs(req)); if (NS_SUCCEEDED(rv)) { TrackImage(req); + + // Handle cases when we just ended up with a pending request but it's + // already done. In that situation we have to synchronously switch that + // request to being the current request, because websites depend on that + // behavior. + if (req == mPendingRequest) { + PRUint32 pendingLoadStatus; + rv = req->GetImageStatus(&pendingLoadStatus); + if (NS_SUCCEEDED(rv) && + (pendingLoadStatus & imgIRequest::STATUS_LOAD_COMPLETE)) { + MakePendingRequestCurrent(); + MOZ_ASSERT(mCurrentRequest, + "How could we not have a current request here?"); + + nsImageFrame *f = do_QueryFrame(GetOurPrimaryFrame()); + if (f) { + f->NotifyNewCurrentRequest(mCurrentRequest, NS_OK); + } + } + } } else { // If we don't have a current URI, we might as well store this URI so people // know what we tried (and failed) to load. @@ -1046,6 +1064,16 @@ nsImageLoadingContent::PreparePendingRequest() return mPendingRequest; } +void +nsImageLoadingContent::MakePendingRequestCurrent() +{ + MOZ_ASSERT(mPendingRequest); + PrepareCurrentRequest() = mPendingRequest; + mPendingRequest = nsnull; + mCurrentRequestNeedsResetAnimation = mPendingRequestNeedsResetAnimation; + mPendingRequestNeedsResetAnimation = false; +} + void nsImageLoadingContent::ClearCurrentRequest(nsresult aReason) { diff --git a/content/base/src/nsImageLoadingContent.h b/content/base/src/nsImageLoadingContent.h index cc788a759f3..0dda9ae4eb7 100644 --- a/content/base/src/nsImageLoadingContent.h +++ b/content/base/src/nsImageLoadingContent.h @@ -297,6 +297,12 @@ protected: nsCOMPtr& PrepareCurrentRequest(); nsCOMPtr& PreparePendingRequest(); + /** + * Switch our pending request to be our current request. + * mPendingRequest must be non-null! + */ + void MakePendingRequestCurrent(); + /** * Cancels and nulls-out the "current" and "pending" requests if they exist. */ diff --git a/layout/generic/nsImageFrame.cpp b/layout/generic/nsImageFrame.cpp index 304f99d41ed..7ba4ac0b007 100644 --- a/layout/generic/nsImageFrame.cpp +++ b/layout/generic/nsImageFrame.cpp @@ -642,10 +642,6 @@ nsImageFrame::OnStopDecode(imgIRequest *aRequest, nsresult aStatus, const PRUnichar *aStatusArg) { - nsPresContext *presContext = PresContext(); - nsIPresShell *presShell = presContext->GetPresShell(); - NS_ASSERTION(presShell, "No PresShell."); - // Check what request type we're dealing with nsCOMPtr imageLoader = do_QueryInterface(mContent); NS_ASSERTION(imageLoader, "Who's notifying us??"); @@ -657,41 +653,49 @@ nsImageFrame::OnStopDecode(imgIRequest *aRequest, } if (loadType == nsIImageLoadingContent::PENDING_REQUEST) { - // May have to switch sizes here! - bool intrinsicSizeChanged = true; - if (NS_SUCCEEDED(aStatus)) { - nsCOMPtr imageContainer; - aRequest->GetImage(getter_AddRefs(imageContainer)); - NS_ASSERTION(imageContainer, "Successful load with no container?"); - intrinsicSizeChanged = UpdateIntrinsicSize(imageContainer); - intrinsicSizeChanged = UpdateIntrinsicRatio(imageContainer) || - intrinsicSizeChanged; - } - else { - // Have to size to 0,0 so that GetDesiredSize recalculates the size - mIntrinsicSize.width.SetCoordValue(0); - mIntrinsicSize.height.SetCoordValue(0); - mIntrinsicRatio.SizeTo(0, 0); - } - - if (mState & IMAGE_GOTINITIALREFLOW) { // do nothing if we haven't gotten the initial reflow yet - if (!(mState & IMAGE_SIZECONSTRAINED) && intrinsicSizeChanged) { - if (presShell) { - presShell->FrameNeedsReflow(this, nsIPresShell::eStyleChange, - NS_FRAME_IS_DIRTY); - } - } else { - nsSize s = GetSize(); - nsRect r(0, 0, s.width, s.height); - // Update border+content to account for image change - Invalidate(r); - } - } + NotifyNewCurrentRequest(aRequest, aStatus); } return NS_OK; } +void +nsImageFrame::NotifyNewCurrentRequest(imgIRequest *aRequest, + nsresult aStatus) +{ + // May have to switch sizes here! + bool intrinsicSizeChanged = true; + if (NS_SUCCEEDED(aStatus)) { + nsCOMPtr imageContainer; + aRequest->GetImage(getter_AddRefs(imageContainer)); + NS_ASSERTION(imageContainer, "Successful load with no container?"); + intrinsicSizeChanged = UpdateIntrinsicSize(imageContainer); + intrinsicSizeChanged = UpdateIntrinsicRatio(imageContainer) || + intrinsicSizeChanged; + } + else { + // Have to size to 0,0 so that GetDesiredSize recalculates the size + mIntrinsicSize.width.SetCoordValue(0); + mIntrinsicSize.height.SetCoordValue(0); + mIntrinsicRatio.SizeTo(0, 0); + } + + if (mState & IMAGE_GOTINITIALREFLOW) { // do nothing if we haven't gotten the initial reflow yet + if (!(mState & IMAGE_SIZECONSTRAINED) && intrinsicSizeChanged) { + nsIPresShell *presShell = PresContext()->GetPresShell(); + if (presShell) { + presShell->FrameNeedsReflow(this, nsIPresShell::eStyleChange, + NS_FRAME_IS_DIRTY); + } + } else { + nsSize s = GetSize(); + nsRect r(0, 0, s.width, s.height); + // Update border+content to account for image change + Invalidate(r); + } + } +} + nsresult nsImageFrame::FrameChanged(imgIRequest *aRequest, imgIContainer *aContainer, diff --git a/layout/generic/nsImageFrame.h b/layout/generic/nsImageFrame.h index 84c6351a64f..4c942a25379 100644 --- a/layout/generic/nsImageFrame.h +++ b/layout/generic/nsImageFrame.h @@ -62,6 +62,7 @@ class nsDisplayImage; class nsPresContext; class nsImageFrame; class nsTransform2D; +class nsImageLoadingContent; namespace mozilla { namespace layers { @@ -250,6 +251,7 @@ protected: protected: friend class nsImageListener; + friend class nsImageLoadingContent; nsresult OnStartContainer(imgIRequest *aRequest, imgIContainer *aImage); nsresult OnDataAvailable(imgIRequest *aRequest, bool aCurrentFrame, const nsIntRect *rect); @@ -259,6 +261,10 @@ protected: nsresult FrameChanged(imgIRequest *aRequest, imgIContainer *aContainer, const nsIntRect *aDirtyRect); + /** + * Notification that aRequest will now be the current request. + */ + void NotifyNewCurrentRequest(imgIRequest *aRequest, nsresult aStatus); private: // random helpers diff --git a/layout/reftests/image/blue-16x20.png b/layout/reftests/image/blue-16x20.png new file mode 100644 index 00000000000..f0f4d319e86 Binary files /dev/null and b/layout/reftests/image/blue-16x20.png differ diff --git a/layout/reftests/image/blue-32x32.png b/layout/reftests/image/blue-32x32.png new file mode 100644 index 00000000000..deefd19b2ac Binary files /dev/null and b/layout/reftests/image/blue-32x32.png differ diff --git a/layout/reftests/image/reftest.list b/layout/reftests/image/reftest.list index 59e95fec032..398e90473cc 100644 --- a/layout/reftests/image/reftest.list +++ b/layout/reftests/image/reftest.list @@ -3,3 +3,7 @@ == image-zoom-1.html image-zoom-1-ref.html == image-zoom-2.html image-zoom-1-ref.html == invalid-url-image-1.html invalid-url-image-1-ref.html +== sync-image-switch-1a.html sync-image-switch-1-ref.html +== sync-image-switch-1b.html sync-image-switch-1-ref.html +== sync-image-switch-1c.html sync-image-switch-1-ref.html +== sync-image-switch-1d.html sync-image-switch-1-ref.html diff --git a/layout/reftests/image/sync-image-switch-1-ref.html b/layout/reftests/image/sync-image-switch-1-ref.html new file mode 100644 index 00000000000..654d1a9b708 --- /dev/null +++ b/layout/reftests/image/sync-image-switch-1-ref.html @@ -0,0 +1,4 @@ + + + + diff --git a/layout/reftests/image/sync-image-switch-1a.html b/layout/reftests/image/sync-image-switch-1a.html new file mode 100644 index 00000000000..f1b7d6316fb --- /dev/null +++ b/layout/reftests/image/sync-image-switch-1a.html @@ -0,0 +1,16 @@ + + + + + diff --git a/layout/reftests/image/sync-image-switch-1b.html b/layout/reftests/image/sync-image-switch-1b.html new file mode 100644 index 00000000000..7462ec696d4 --- /dev/null +++ b/layout/reftests/image/sync-image-switch-1b.html @@ -0,0 +1,16 @@ + + + + + diff --git a/layout/reftests/image/sync-image-switch-1c.html b/layout/reftests/image/sync-image-switch-1c.html new file mode 100644 index 00000000000..2182e40db9d --- /dev/null +++ b/layout/reftests/image/sync-image-switch-1c.html @@ -0,0 +1,16 @@ + + + + + diff --git a/layout/reftests/image/sync-image-switch-1d.html b/layout/reftests/image/sync-image-switch-1d.html new file mode 100644 index 00000000000..3001305b0c8 --- /dev/null +++ b/layout/reftests/image/sync-image-switch-1d.html @@ -0,0 +1,16 @@ + + + + +