diff --git a/mozilla/content/html/content/src/nsHTMLImageElement.cpp b/mozilla/content/html/content/src/nsHTMLImageElement.cpp index ac36c8207d9..285f49875f3 100644 --- a/mozilla/content/html/content/src/nsHTMLImageElement.cpp +++ b/mozilla/content/html/content/src/nsHTMLImageElement.cpp @@ -50,8 +50,10 @@ #include "nsIWebShell.h" #include "nsIFrame.h" #include "nsImageFrame.h" +#include "nsFrameImageLoader.h" #include "nsLayoutAtoms.h" #include "nsNodeInfoManager.h" +#include "nsIFrameImageLoader.h" static NS_DEFINE_CID(kIOServiceCID, NS_IOSERVICE_CID); @@ -137,6 +139,14 @@ public: protected: nsGenericHTMLLeafElement mInner; nsIDocument* mOwnerDocument; // Only used if this is a script constructed image + + static nsresult ImageLibCallBack(nsIPresContext* aPresContext, + nsIFrameImageLoader* aLoader, + nsIFrame* aFrame, + void* aClosure, + PRUint32 aStatus); + + nsCOMPtr mLoader; }; nsresult @@ -181,6 +191,9 @@ nsHTMLImageElement::nsHTMLImageElement(nsINodeInfo *aNodeInfo) nsHTMLImageElement::~nsHTMLImageElement() { NS_IF_RELEASE(mOwnerDocument); + + if (mLoader) + mLoader->RemoveFrame(this); } NS_IMPL_ADDREF(nsHTMLImageElement) @@ -309,8 +322,12 @@ nsHTMLImageElement::GetComplete(PRBool* aComplete) nsImageFrame* imageFrame; result = GetImageFrame(&imageFrame); - if (NS_SUCCEEDED(result)) { + if (NS_SUCCEEDED(result) && imageFrame) { result = imageFrame->IsImageComplete(aComplete); + } else { + result = NS_OK; + + *aComplete = !mLoader; } return NS_OK; @@ -849,13 +866,70 @@ nsHTMLImageElement::GetSrc(nsAWritableString& aSrc) return rv; } +nsresult nsHTMLImageElement::ImageLibCallBack(nsIPresContext* aPresContext, + nsIFrameImageLoader* aLoader, + nsIFrame* aFrame, + void* aClosure, + PRUint32 aStatus) +{ + nsHTMLImageElement *img = (nsHTMLImageElement *)aClosure; + + if (!img || !img->mLoader) + return NS_OK; + + if ((aStatus & NS_IMAGE_LOAD_STATUS_SIZE_AVAILABLE) && + !(aStatus & NS_IMAGE_LOAD_STATUS_ERROR)) { + nsCOMPtr cx; + aLoader->GetPresContext(getter_AddRefs(cx)); + + float t2p; + cx->GetTwipsToPixels(&t2p); + + nsSize size; + aLoader->GetSize(size); + + nsAutoString tmpStr; + tmpStr.AppendInt(NSTwipsToIntPixels(size.width, t2p)); + img->SetAttribute(kNameSpaceID_None, nsHTMLAtoms::width, tmpStr, + PR_FALSE); + + tmpStr.Truncate(); + tmpStr.AppendInt(NSTwipsToIntPixels(size.height, t2p)); + img->SetAttribute(kNameSpaceID_None, nsHTMLAtoms::height, tmpStr, + PR_FALSE); + } + + if (aStatus & (NS_IMAGE_LOAD_STATUS_IMAGE_READY | + NS_IMAGE_LOAD_STATUS_ERROR)) { + // We set mLoader = nsnull to indicate that we're complete. + img->mLoader->RemoveFrame(img); + img->mLoader = nsnull; + + // Fire the onload event. + nsEventStatus status = nsEventStatus_eIgnore; + nsEvent event; + event.eventStructType = NS_EVENT; + + if (aStatus & NS_IMAGE_LOAD_STATUS_IMAGE_READY) { + event.message = NS_IMAGE_LOAD; + } else { + event.message = NS_IMAGE_ERROR; + } + + img->HandleDOMEvent(aPresContext, &event, nsnull, NS_EVENT_FLAG_INIT, + &status); + } + + return NS_OK; +} + + nsresult nsHTMLImageElement::SetSrcInner(nsIURI* aBaseURL, const nsAReadableString& aSrc) { nsresult result = NS_OK; if (nsnull != mOwnerDocument) { - PRInt32 i, count = mOwnerDocument->GetNumberOfShells(); nsIPresShell* shell; @@ -902,11 +976,17 @@ nsHTMLImageElement::SetSrcInner(nsIURI* aBaseURL, const nsAReadableString& aSrc) specifiedSize = &size; } - // Start the image loading. We don't care about notification - // or holding on to the image loader. + // If we have a loader we're in the middle of loading a image, + // we'll cancel that load and start a new one. + if (mLoader) { + mLoader->RemoveFrame(this); + } + + // Start the image loading. We don't care about holding on to + // the image loader. result = context->StartLoadImage(url, nsnull, specifiedSize, - nsnull, nsnull, nsnull, - nsnull); + nsnull, ImageLibCallBack, this, this, + getter_AddRefs(mLoader)); NS_RELEASE(context); } diff --git a/mozilla/layout/base/nsCSSRendering.cpp b/mozilla/layout/base/nsCSSRendering.cpp index f254f026602..63cfb71afed 100644 --- a/mozilla/layout/base/nsCSSRendering.cpp +++ b/mozilla/layout/base/nsCSSRendering.cpp @@ -2096,13 +2096,13 @@ nsCSSRendering::PaintBackground(nsIPresContext* aPresContext, nsCOMPtr image; nsIFrameImageLoader* loader = nsnull; nsresult rv = aPresContext->StartLoadImage(aColor.mBackgroundImage, - transparentBG - ? nsnull - : &aColor.mBackgroundColor, - nsnull, - pBGFrame, - nsnull, nsnull, - &loader); + transparentBG + ? nsnull + : &aColor.mBackgroundColor, + nsnull, + pBGFrame, + nsnull, nsnull, + pBGFrame, &loader); if ((NS_OK != rv) || (nsnull == loader) || (loader->GetImage(getter_AddRefs(image)), (!image))) { NS_IF_RELEASE(loader); diff --git a/mozilla/layout/base/nsFrameManager.cpp b/mozilla/layout/base/nsFrameManager.cpp index f93c09748d0..9fa1916d57b 100644 --- a/mozilla/layout/base/nsFrameManager.cpp +++ b/mozilla/layout/base/nsFrameManager.cpp @@ -1292,7 +1292,7 @@ FrameManager::ReResolveStyleContext(nsIPresContext* aPresContext, if(oldColor.mBackgroundImage.Length() > 0 && oldColor.mBackgroundImage != newColor.mBackgroundImage ){ // stop the image loading for the frame, the image has changed - aPresContext->StopAllLoadImagesFor(aFrame); + aPresContext->StopAllLoadImagesFor(aFrame, aFrame); } } else { diff --git a/mozilla/layout/base/nsPresContext.cpp b/mozilla/layout/base/nsPresContext.cpp index 8ad9a0e0464..0b056a7e838 100644 --- a/mozilla/layout/base/nsPresContext.cpp +++ b/mozilla/layout/base/nsPresContext.cpp @@ -880,6 +880,7 @@ nsPresContext::StartLoadImage(const nsString& aURL, nsIFrame* aTargetFrame, nsIFrameImageLoaderCB aCallBack, void* aClosure, + void* aKey, nsIFrameImageLoader** aResult) { if (mStopped) { @@ -916,7 +917,7 @@ nsPresContext::StartLoadImage(const nsString& aURL, } // Add frame to list of interested frames for this loader - loader->AddFrame(aTargetFrame, aCallBack, aClosure); + loader->AddFrame(aTargetFrame, aCallBack, aClosure, aKey); return NS_OK; } } @@ -963,7 +964,8 @@ nsPresContext::StartLoadImage(const nsString& aURL, } rv = loader->Init(this, mImageGroup, aURL, aBackgroundColor, aDesiredSize, - aTargetFrame, mImageAnimationMode, aCallBack, aClosure); + aTargetFrame, mImageAnimationMode, aCallBack, aClosure, + aKey); if (NS_OK != rv) { mImageLoaders.RemoveElement(loader); loader->StopImageLoad(); @@ -995,8 +997,7 @@ nsPresContext::Stop(void) } NS_IMETHODIMP -nsPresContext::StopLoadImage(nsIFrame* aTargetFrame, - nsIFrameImageLoader* aLoader) +nsPresContext::StopLoadImage(void* aKey, nsIFrameImageLoader* aLoader) { PRInt32 i, n = mImageLoaders.Count(); nsIFrameImageLoader* loader; @@ -1004,7 +1005,7 @@ nsPresContext::StopLoadImage(nsIFrame* aTargetFrame, loader = (nsIFrameImageLoader*) mImageLoaders.ElementAt(i); if (loader == aLoader) { // Remove frame from list of interested frames for this loader - loader->RemoveFrame(aTargetFrame); + loader->RemoveFrame(aKey); // If loader is no longer loading for anybody and its safe to // nuke it, nuke it. @@ -1023,7 +1024,7 @@ nsPresContext::StopLoadImage(nsIFrame* aTargetFrame, } NS_IMETHODIMP -nsPresContext::StopAllLoadImagesFor(nsIFrame* aTargetFrame) +nsPresContext::StopAllLoadImagesFor(nsIFrame* aTargetFrame, void *aKey) { nsFrameState state; aTargetFrame->GetFrameState(&state); @@ -1033,7 +1034,7 @@ nsPresContext::StopAllLoadImagesFor(nsIFrame* aTargetFrame) for (i = 0; i < n; i++) { PRBool safe; loader = (nsIFrameImageLoader*) mImageLoaders.ElementAt(i); - loader->RemoveFrame(aTargetFrame); + loader->RemoveFrame(aKey); loader->SafeToDestroy(&safe); if (safe) { loader->StopImageLoad(); diff --git a/mozilla/layout/base/nsPresContext.h b/mozilla/layout/base/nsPresContext.h index 92c0435bec8..cc8086a8b4c 100644 --- a/mozilla/layout/base/nsPresContext.h +++ b/mozilla/layout/base/nsPresContext.h @@ -251,18 +251,19 @@ public: nsIFrame* aTargetFrame, nsIFrameImageLoaderCB aCallBack, void* aClosure, + void* aKey, nsIFrameImageLoader** aResult) = 0; /** * Stop a specific image load being done on behalf of the argument frame. */ - NS_IMETHOD StopLoadImage(nsIFrame* aForFrame, + NS_IMETHOD StopLoadImage(void* aKey, nsIFrameImageLoader* aLoader) = 0; /** * Stop any image loading being done on behalf of the argument frame. */ - NS_IMETHOD StopAllLoadImagesFor(nsIFrame* aForFrame) = 0; + NS_IMETHOD StopAllLoadImagesFor(nsIFrame* aTargetFrame, void* aKey) = 0; NS_IMETHOD SetContainer(nsISupports* aContainer) = 0; diff --git a/mozilla/layout/base/public/nsIFrameImageLoader.h b/mozilla/layout/base/public/nsIFrameImageLoader.h index 9161cbda426..7a3e13cdb8c 100644 --- a/mozilla/layout/base/public/nsIFrameImageLoader.h +++ b/mozilla/layout/base/public/nsIFrameImageLoader.h @@ -71,7 +71,7 @@ public: nsIFrame* aFrame, nsImageAnimation aAnimationMode, nsIFrameImageLoaderCB aCallBack, - void* aClosure) = 0; + void* aClosure, void* aKey) = 0; NS_IMETHOD StopImageLoad() = 0; @@ -83,9 +83,9 @@ public: PRBool* aResult) = 0; NS_IMETHOD AddFrame(nsIFrame* aFrame, nsIFrameImageLoaderCB aCallBack, - void* aClosure) = 0; + void* aClosure, void* aKey) = 0; - NS_IMETHOD RemoveFrame(nsIFrame* aFrame) = 0; + NS_IMETHOD RemoveFrame(void* aKey) = 0; NS_IMETHOD SafeToDestroy(PRBool* aResult) = 0; diff --git a/mozilla/layout/base/public/nsIPresContext.h b/mozilla/layout/base/public/nsIPresContext.h index 92c0435bec8..cc8086a8b4c 100644 --- a/mozilla/layout/base/public/nsIPresContext.h +++ b/mozilla/layout/base/public/nsIPresContext.h @@ -251,18 +251,19 @@ public: nsIFrame* aTargetFrame, nsIFrameImageLoaderCB aCallBack, void* aClosure, + void* aKey, nsIFrameImageLoader** aResult) = 0; /** * Stop a specific image load being done on behalf of the argument frame. */ - NS_IMETHOD StopLoadImage(nsIFrame* aForFrame, + NS_IMETHOD StopLoadImage(void* aKey, nsIFrameImageLoader* aLoader) = 0; /** * Stop any image loading being done on behalf of the argument frame. */ - NS_IMETHOD StopAllLoadImagesFor(nsIFrame* aForFrame) = 0; + NS_IMETHOD StopAllLoadImagesFor(nsIFrame* aTargetFrame, void* aKey) = 0; NS_IMETHOD SetContainer(nsISupports* aContainer) = 0; diff --git a/mozilla/layout/base/public/nsPresContext.h b/mozilla/layout/base/public/nsPresContext.h index 92c0435bec8..cc8086a8b4c 100644 --- a/mozilla/layout/base/public/nsPresContext.h +++ b/mozilla/layout/base/public/nsPresContext.h @@ -251,18 +251,19 @@ public: nsIFrame* aTargetFrame, nsIFrameImageLoaderCB aCallBack, void* aClosure, + void* aKey, nsIFrameImageLoader** aResult) = 0; /** * Stop a specific image load being done on behalf of the argument frame. */ - NS_IMETHOD StopLoadImage(nsIFrame* aForFrame, + NS_IMETHOD StopLoadImage(void* aKey, nsIFrameImageLoader* aLoader) = 0; /** * Stop any image loading being done on behalf of the argument frame. */ - NS_IMETHOD StopAllLoadImagesFor(nsIFrame* aForFrame) = 0; + NS_IMETHOD StopAllLoadImagesFor(nsIFrame* aTargetFrame, void* aKey) = 0; NS_IMETHOD SetContainer(nsISupports* aContainer) = 0; diff --git a/mozilla/layout/base/src/nsFrameImageLoader.cpp b/mozilla/layout/base/src/nsFrameImageLoader.cpp index eb2ed5a578f..8f1453b94b5 100644 --- a/mozilla/layout/base/src/nsFrameImageLoader.cpp +++ b/mozilla/layout/base/src/nsFrameImageLoader.cpp @@ -124,7 +124,8 @@ nsFrameImageLoader::Init(nsIPresContext* aPresContext, nsIFrame* aTargetFrame, nsImageAnimation aAnimationMode, nsIFrameImageLoaderCB aCallBack, - void* aClosure) + void* aClosure, + void* aKey) { NS_PRECONDITION(nsnull != aPresContext, "null ptr"); if (nsnull == aPresContext) { @@ -162,16 +163,17 @@ nsFrameImageLoader::Init(nsIPresContext* aPresContext, desiredHeight = NSToCoordRound((mDesiredSize.height * t2p)/devScale); } - if (nsnull != aTargetFrame) { + if (aTargetFrame || aCallBack) { PerFrameData* pfd = new PerFrameData; if (nsnull == pfd) { return NS_ERROR_OUT_OF_MEMORY; } pfd->mFrame = aTargetFrame; + pfd->mKey = aKey; pfd->mCallBack = aCallBack; pfd->mClosure = aClosure; pfd->mNext = mFrames; - pfd->mNeedSizeUpdate = PR_TRUE; + pfd->mNeedSizeUpdate = aTargetFrame ? PR_TRUE : PR_FALSE; mFrames = pfd; } @@ -187,11 +189,12 @@ nsFrameImageLoader::Init(nsIPresContext* aPresContext, NS_IMETHODIMP nsFrameImageLoader::AddFrame(nsIFrame* aFrame, nsIFrameImageLoaderCB aCallBack, - void* aClosure) + void* aClosure, + void* aKey) { PerFrameData* pfd = mFrames; while (pfd) { - if (pfd->mFrame == aFrame) { + if (pfd->mKey == aKey) { pfd->mCallBack = aCallBack; pfd->mClosure = aClosure; return NS_OK; @@ -199,42 +202,41 @@ nsFrameImageLoader::AddFrame(nsIFrame* aFrame, pfd = pfd->mNext; } - if (nsnull != aFrame) { - pfd = new PerFrameData; - if (nsnull == pfd) { - return NS_ERROR_OUT_OF_MEMORY; - } - pfd->mFrame = aFrame; - pfd->mCallBack = aCallBack; - pfd->mClosure = aClosure; - pfd->mNext = mFrames; - pfd->mNeedSizeUpdate = PR_TRUE; - mFrames = pfd; - if (aCallBack && mPresContext && - ((NS_IMAGE_LOAD_STATUS_SIZE_AVAILABLE | - NS_IMAGE_LOAD_STATUS_ERROR) & mImageLoadStatus)) { - // Fire notification callback right away so that caller doesn't - // miss it... + pfd = new PerFrameData; + if (nsnull == pfd) { + return NS_ERROR_OUT_OF_MEMORY; + } + pfd->mFrame = aFrame; + pfd->mKey = aKey; + pfd->mCallBack = aCallBack; + pfd->mClosure = aClosure; + pfd->mNext = mFrames; + pfd->mNeedSizeUpdate = PR_TRUE; + mFrames = pfd; + if (aCallBack && mPresContext && + ((NS_IMAGE_LOAD_STATUS_SIZE_AVAILABLE | + NS_IMAGE_LOAD_STATUS_ERROR) & mImageLoadStatus)) { + // Fire notification callback right away so that caller doesn't + // miss it... #ifdef NOISY_IMAGE_LOADING - printf("%p: AddFrame: notify frame=%p status=%x\n", - this, pfd->mFrame, mImageLoadStatus); + printf("%p: AddFrame: notify frame=%p status=%x\n", + this, pfd->mFrame, mImageLoadStatus); #endif - (*aCallBack)(mPresContext, this, pfd->mFrame, pfd->mClosure, - mImageLoadStatus); - pfd->mNeedSizeUpdate = PR_FALSE; - } + (*aCallBack)(mPresContext, this, pfd->mFrame, pfd->mClosure, + mImageLoadStatus); + pfd->mNeedSizeUpdate = PR_FALSE; } return NS_OK; } NS_IMETHODIMP -nsFrameImageLoader::RemoveFrame(nsIFrame* aFrame) +nsFrameImageLoader::RemoveFrame(void* aKey) { PerFrameData** pfdp = &mFrames; PerFrameData* pfd; while (nsnull != (pfd = *pfdp)) { - if (pfd->mFrame == aFrame) { + if (pfd->mKey == aKey) { *pfdp = pfd->mNext; delete pfd; return NS_OK; @@ -494,9 +496,11 @@ nsFrameImageLoader::Notify(nsIImageRequest *aImageRequest, // XXX this is pretty vile; change this so that we set another frame status bit and then pass on a notification *or* lets just start passing on the notifications directly to the frames and eliminate all of this code. pfd = mFrames; while (pfd) { - pfd->mFrame->GetView(mPresContext, &view); - if (view) { - view->SetContentTransparency(PR_TRUE); + if (pfd->mFrame) { + pfd->mFrame->GetView(mPresContext, &view); + if (view) { + view->SetContentTransparency(PR_TRUE); + } } pfd = pfd->mNext; } @@ -567,52 +571,39 @@ nsFrameImageLoader::DamageRepairFrames(const nsRect* aDamageRect) while (nsnull != pfd) { nsIFrame* frame = pfd->mFrame; - // NOTE: It is not sufficient to invalidate only the size of the image: - // the image may be tiled! - // The best option is to call into the frame, however lacking this - // we have to at least invalidate the frame's bounds, hence - // as long as we have a frame we'll use its size. - // - // XXX - Add a NotifyImageLoaded to nsIFrame and call that, passing the - // damage rect (image size) - - NS_ASSERTION(frame, "Frame should not be null and be remembered"); if (frame) { + // NOTE: It is not sufficient to invalidate only the size of the image: + // the image may be tiled! + // The best option is to call into the frame, however lacking this + // we have to at least invalidate the frame's bounds, hence + // as long as we have a frame we'll use its size. + // + // XXX - Add a NotifyImageLoaded to nsIFrame and call that, passing the + // damage rect (image size) + // Invalidate the entire frame // XXX We really only need to invalidate the client area of the frame... frame->GetRect(bounds); bounds.x = bounds.y = 0; - } - else { - // aDamageRect represents the part of the content area that - // needs updating. - bounds = *aDamageRect; - // Offset damage origin by border/padding - // XXX This is pretty sleazy. See the XXX remark below... - const nsStyleSpacing* space; - nsMargin borderPadding; - frame->GetStyleData(eStyleStruct_Spacing, (const nsStyleStruct*&)space); - space->CalcBorderPaddingFor(frame, borderPadding); - bounds.MoveBy(borderPadding.left, borderPadding.top); + // XXX We should tell the frame the damage area and let it invalidate + // itself. Add some API calls to nsIFrame to allow a caller to invalidate + // parts of the frame... + frame->GetView(mPresContext, &view); + if (nsnull == view) { + frame->GetOffsetFromView(mPresContext, offset, &view); + bounds.x += offset.x; + bounds.y += offset.y; + } + + nsCOMPtr vm = nsnull; + nsresult rv = NS_OK; + rv = view->GetViewManager(*getter_AddRefs(vm)); + if (NS_SUCCEEDED(rv) && nsnull != vm) { + vm->UpdateView(view, bounds, NS_VMREFRESH_NO_SYNC); + } } - // XXX We should tell the frame the damage area and let it invalidate - // itself. Add some API calls to nsIFrame to allow a caller to invalidate - // parts of the frame... - frame->GetView(mPresContext, &view); - if (nsnull == view) { - frame->GetOffsetFromView(mPresContext, offset, &view); - bounds.x += offset.x; - bounds.y += offset.y; - } - - nsCOMPtr vm = nsnull; - nsresult rv = NS_OK; - rv = view->GetViewManager(*getter_AddRefs(vm)); - if (NS_SUCCEEDED(rv) && nsnull != vm) { - vm->UpdateView(view, bounds, NS_VMREFRESH_NO_SYNC); - } pfd = pfd->mNext; } } diff --git a/mozilla/layout/base/src/nsFrameImageLoader.h b/mozilla/layout/base/src/nsFrameImageLoader.h index 191de942c34..8e57fda9d1e 100644 --- a/mozilla/layout/base/src/nsFrameImageLoader.h +++ b/mozilla/layout/base/src/nsFrameImageLoader.h @@ -59,7 +59,7 @@ public: nsIFrame* aTargetFrame, nsImageAnimation aAnimationMode, nsIFrameImageLoaderCB aCallBack, - void* aClosure); + void* aClosure, void* aKey); NS_IMETHOD StopImageLoad(); @@ -71,9 +71,9 @@ public: PRBool* aResult); NS_IMETHOD AddFrame(nsIFrame* aFrame, nsIFrameImageLoaderCB aCallBack, - void* aClosure); + void* aClosure, void* aKey); - NS_IMETHOD RemoveFrame(nsIFrame* aFrame); + NS_IMETHOD RemoveFrame(void* aKey); // See if its safe to destroy this image loader. Its safe if there // are no more frames using the loader and we aren't in the middle @@ -122,6 +122,7 @@ protected: nsIFrame* mFrame; nsIFrameImageLoaderCB mCallBack; void* mClosure; + void* mKey; PRBool mNeedSizeUpdate; }; PerFrameData* mFrames; diff --git a/mozilla/layout/base/src/nsPresContext.cpp b/mozilla/layout/base/src/nsPresContext.cpp index 8ad9a0e0464..0b056a7e838 100644 --- a/mozilla/layout/base/src/nsPresContext.cpp +++ b/mozilla/layout/base/src/nsPresContext.cpp @@ -880,6 +880,7 @@ nsPresContext::StartLoadImage(const nsString& aURL, nsIFrame* aTargetFrame, nsIFrameImageLoaderCB aCallBack, void* aClosure, + void* aKey, nsIFrameImageLoader** aResult) { if (mStopped) { @@ -916,7 +917,7 @@ nsPresContext::StartLoadImage(const nsString& aURL, } // Add frame to list of interested frames for this loader - loader->AddFrame(aTargetFrame, aCallBack, aClosure); + loader->AddFrame(aTargetFrame, aCallBack, aClosure, aKey); return NS_OK; } } @@ -963,7 +964,8 @@ nsPresContext::StartLoadImage(const nsString& aURL, } rv = loader->Init(this, mImageGroup, aURL, aBackgroundColor, aDesiredSize, - aTargetFrame, mImageAnimationMode, aCallBack, aClosure); + aTargetFrame, mImageAnimationMode, aCallBack, aClosure, + aKey); if (NS_OK != rv) { mImageLoaders.RemoveElement(loader); loader->StopImageLoad(); @@ -995,8 +997,7 @@ nsPresContext::Stop(void) } NS_IMETHODIMP -nsPresContext::StopLoadImage(nsIFrame* aTargetFrame, - nsIFrameImageLoader* aLoader) +nsPresContext::StopLoadImage(void* aKey, nsIFrameImageLoader* aLoader) { PRInt32 i, n = mImageLoaders.Count(); nsIFrameImageLoader* loader; @@ -1004,7 +1005,7 @@ nsPresContext::StopLoadImage(nsIFrame* aTargetFrame, loader = (nsIFrameImageLoader*) mImageLoaders.ElementAt(i); if (loader == aLoader) { // Remove frame from list of interested frames for this loader - loader->RemoveFrame(aTargetFrame); + loader->RemoveFrame(aKey); // If loader is no longer loading for anybody and its safe to // nuke it, nuke it. @@ -1023,7 +1024,7 @@ nsPresContext::StopLoadImage(nsIFrame* aTargetFrame, } NS_IMETHODIMP -nsPresContext::StopAllLoadImagesFor(nsIFrame* aTargetFrame) +nsPresContext::StopAllLoadImagesFor(nsIFrame* aTargetFrame, void *aKey) { nsFrameState state; aTargetFrame->GetFrameState(&state); @@ -1033,7 +1034,7 @@ nsPresContext::StopAllLoadImagesFor(nsIFrame* aTargetFrame) for (i = 0; i < n; i++) { PRBool safe; loader = (nsIFrameImageLoader*) mImageLoaders.ElementAt(i); - loader->RemoveFrame(aTargetFrame); + loader->RemoveFrame(aKey); loader->SafeToDestroy(&safe); if (safe) { loader->StopImageLoad(); diff --git a/mozilla/layout/base/src/nsPresContext.h b/mozilla/layout/base/src/nsPresContext.h index 8a948eeb9ec..d2c26ea54d2 100644 --- a/mozilla/layout/base/src/nsPresContext.h +++ b/mozilla/layout/base/src/nsPresContext.h @@ -120,9 +120,10 @@ public: nsIFrame* aTargetFrame, nsIFrameImageLoaderCB aCallBack, void* aClosure, + void* aKey, nsIFrameImageLoader** aResult); - NS_IMETHOD StopLoadImage(nsIFrame* aForFrame, nsIFrameImageLoader* aLoader); - NS_IMETHOD StopAllLoadImagesFor(nsIFrame* aForFrame); + NS_IMETHOD StopLoadImage(void* aKey, nsIFrameImageLoader* aLoader); + NS_IMETHOD StopAllLoadImagesFor(nsIFrame* aTargetFrame, void* aKey); NS_IMETHOD SetContainer(nsISupports* aContainer); NS_IMETHOD GetContainer(nsISupports** aResult); NS_IMETHOD SetLinkHandler(nsILinkHandler* aHandler); diff --git a/mozilla/layout/generic/nsFrame.cpp b/mozilla/layout/generic/nsFrame.cpp index 1ae32ea22ed..88eb6072289 100644 --- a/mozilla/layout/generic/nsFrame.cpp +++ b/mozilla/layout/generic/nsFrame.cpp @@ -409,7 +409,7 @@ nsFrame::Destroy(nsIPresContext* aPresContext) //XXX Why is this done in nsFrame instead of some frame class // that actually loads images? - aPresContext->StopAllLoadImagesFor(this); + aPresContext->StopAllLoadImagesFor(this, this); if (view) { // Break association between view and frame diff --git a/mozilla/layout/html/base/src/nsFrame.cpp b/mozilla/layout/html/base/src/nsFrame.cpp index 1ae32ea22ed..88eb6072289 100644 --- a/mozilla/layout/html/base/src/nsFrame.cpp +++ b/mozilla/layout/html/base/src/nsFrame.cpp @@ -409,7 +409,7 @@ nsFrame::Destroy(nsIPresContext* aPresContext) //XXX Why is this done in nsFrame instead of some frame class // that actually loads images? - aPresContext->StopAllLoadImagesFor(this); + aPresContext->StopAllLoadImagesFor(this, this); if (view) { // Break association between view and frame diff --git a/mozilla/layout/html/base/src/nsFrameManager.cpp b/mozilla/layout/html/base/src/nsFrameManager.cpp index f93c09748d0..9fa1916d57b 100644 --- a/mozilla/layout/html/base/src/nsFrameManager.cpp +++ b/mozilla/layout/html/base/src/nsFrameManager.cpp @@ -1292,7 +1292,7 @@ FrameManager::ReResolveStyleContext(nsIPresContext* aPresContext, if(oldColor.mBackgroundImage.Length() > 0 && oldColor.mBackgroundImage != newColor.mBackgroundImage ){ // stop the image loading for the frame, the image has changed - aPresContext->StopAllLoadImagesFor(aFrame); + aPresContext->StopAllLoadImagesFor(aFrame, aFrame); } } else { diff --git a/mozilla/layout/html/base/src/nsHTMLImageLoader.cpp b/mozilla/layout/html/base/src/nsHTMLImageLoader.cpp index 32cd4485d78..c6250ecc456 100644 --- a/mozilla/layout/html/base/src/nsHTMLImageLoader.cpp +++ b/mozilla/layout/html/base/src/nsHTMLImageLoader.cpp @@ -107,7 +107,7 @@ nsHTMLImageLoader::StopLoadImage(nsIPresContext* aPresContext) void nsHTMLImageLoader::StopAllLoadImages(nsIPresContext* aPresContext) { - aPresContext->StopAllLoadImagesFor(mFrame); + aPresContext->StopAllLoadImagesFor(mFrame, mFrame); } nsresult @@ -203,7 +203,7 @@ nsHTMLImageLoader::StartLoadImage(nsIPresContext* aPresContext) nsresult rv = aPresContext->StartLoadImage(*urlSpec, nsnull, sizeToLoadWidth, mFrame, ImageLoadCB, (void*)this, - &mImageLoader); + mFrame, &mImageLoader); #ifdef NOISY_IMAGE_LOADING nsFrame::ListTag(stdout, mFrame); printf(": loading image '"); diff --git a/mozilla/layout/html/content/src/nsHTMLImageElement.cpp b/mozilla/layout/html/content/src/nsHTMLImageElement.cpp index ac36c8207d9..285f49875f3 100644 --- a/mozilla/layout/html/content/src/nsHTMLImageElement.cpp +++ b/mozilla/layout/html/content/src/nsHTMLImageElement.cpp @@ -50,8 +50,10 @@ #include "nsIWebShell.h" #include "nsIFrame.h" #include "nsImageFrame.h" +#include "nsFrameImageLoader.h" #include "nsLayoutAtoms.h" #include "nsNodeInfoManager.h" +#include "nsIFrameImageLoader.h" static NS_DEFINE_CID(kIOServiceCID, NS_IOSERVICE_CID); @@ -137,6 +139,14 @@ public: protected: nsGenericHTMLLeafElement mInner; nsIDocument* mOwnerDocument; // Only used if this is a script constructed image + + static nsresult ImageLibCallBack(nsIPresContext* aPresContext, + nsIFrameImageLoader* aLoader, + nsIFrame* aFrame, + void* aClosure, + PRUint32 aStatus); + + nsCOMPtr mLoader; }; nsresult @@ -181,6 +191,9 @@ nsHTMLImageElement::nsHTMLImageElement(nsINodeInfo *aNodeInfo) nsHTMLImageElement::~nsHTMLImageElement() { NS_IF_RELEASE(mOwnerDocument); + + if (mLoader) + mLoader->RemoveFrame(this); } NS_IMPL_ADDREF(nsHTMLImageElement) @@ -309,8 +322,12 @@ nsHTMLImageElement::GetComplete(PRBool* aComplete) nsImageFrame* imageFrame; result = GetImageFrame(&imageFrame); - if (NS_SUCCEEDED(result)) { + if (NS_SUCCEEDED(result) && imageFrame) { result = imageFrame->IsImageComplete(aComplete); + } else { + result = NS_OK; + + *aComplete = !mLoader; } return NS_OK; @@ -849,13 +866,70 @@ nsHTMLImageElement::GetSrc(nsAWritableString& aSrc) return rv; } +nsresult nsHTMLImageElement::ImageLibCallBack(nsIPresContext* aPresContext, + nsIFrameImageLoader* aLoader, + nsIFrame* aFrame, + void* aClosure, + PRUint32 aStatus) +{ + nsHTMLImageElement *img = (nsHTMLImageElement *)aClosure; + + if (!img || !img->mLoader) + return NS_OK; + + if ((aStatus & NS_IMAGE_LOAD_STATUS_SIZE_AVAILABLE) && + !(aStatus & NS_IMAGE_LOAD_STATUS_ERROR)) { + nsCOMPtr cx; + aLoader->GetPresContext(getter_AddRefs(cx)); + + float t2p; + cx->GetTwipsToPixels(&t2p); + + nsSize size; + aLoader->GetSize(size); + + nsAutoString tmpStr; + tmpStr.AppendInt(NSTwipsToIntPixels(size.width, t2p)); + img->SetAttribute(kNameSpaceID_None, nsHTMLAtoms::width, tmpStr, + PR_FALSE); + + tmpStr.Truncate(); + tmpStr.AppendInt(NSTwipsToIntPixels(size.height, t2p)); + img->SetAttribute(kNameSpaceID_None, nsHTMLAtoms::height, tmpStr, + PR_FALSE); + } + + if (aStatus & (NS_IMAGE_LOAD_STATUS_IMAGE_READY | + NS_IMAGE_LOAD_STATUS_ERROR)) { + // We set mLoader = nsnull to indicate that we're complete. + img->mLoader->RemoveFrame(img); + img->mLoader = nsnull; + + // Fire the onload event. + nsEventStatus status = nsEventStatus_eIgnore; + nsEvent event; + event.eventStructType = NS_EVENT; + + if (aStatus & NS_IMAGE_LOAD_STATUS_IMAGE_READY) { + event.message = NS_IMAGE_LOAD; + } else { + event.message = NS_IMAGE_ERROR; + } + + img->HandleDOMEvent(aPresContext, &event, nsnull, NS_EVENT_FLAG_INIT, + &status); + } + + return NS_OK; +} + + nsresult nsHTMLImageElement::SetSrcInner(nsIURI* aBaseURL, const nsAReadableString& aSrc) { nsresult result = NS_OK; if (nsnull != mOwnerDocument) { - PRInt32 i, count = mOwnerDocument->GetNumberOfShells(); nsIPresShell* shell; @@ -902,11 +976,17 @@ nsHTMLImageElement::SetSrcInner(nsIURI* aBaseURL, const nsAReadableString& aSrc) specifiedSize = &size; } - // Start the image loading. We don't care about notification - // or holding on to the image loader. + // If we have a loader we're in the middle of loading a image, + // we'll cancel that load and start a new one. + if (mLoader) { + mLoader->RemoveFrame(this); + } + + // Start the image loading. We don't care about holding on to + // the image loader. result = context->StartLoadImage(url, nsnull, specifiedSize, - nsnull, nsnull, nsnull, - nsnull); + nsnull, ImageLibCallBack, this, this, + getter_AddRefs(mLoader)); NS_RELEASE(context); } diff --git a/mozilla/layout/html/style/src/nsCSSRendering.cpp b/mozilla/layout/html/style/src/nsCSSRendering.cpp index f254f026602..63cfb71afed 100644 --- a/mozilla/layout/html/style/src/nsCSSRendering.cpp +++ b/mozilla/layout/html/style/src/nsCSSRendering.cpp @@ -2096,13 +2096,13 @@ nsCSSRendering::PaintBackground(nsIPresContext* aPresContext, nsCOMPtr image; nsIFrameImageLoader* loader = nsnull; nsresult rv = aPresContext->StartLoadImage(aColor.mBackgroundImage, - transparentBG - ? nsnull - : &aColor.mBackgroundColor, - nsnull, - pBGFrame, - nsnull, nsnull, - &loader); + transparentBG + ? nsnull + : &aColor.mBackgroundColor, + nsnull, + pBGFrame, + nsnull, nsnull, + pBGFrame, &loader); if ((NS_OK != rv) || (nsnull == loader) || (loader->GetImage(getter_AddRefs(image)), (!image))) { NS_IF_RELEASE(loader);