From 071de302f404febd7d6d0c0b87597bfba57b46dc Mon Sep 17 00:00:00 2001 From: "jst%netscape.com" Date: Fri, 1 Sep 2000 07:05:08 +0000 Subject: [PATCH] Fixing nsbeta3+ bug 28277. Add a callback to nsHTMLImageElement so that we know when a image created in JavaScript has loaded (or fails to load), this is needed to support onload and onerror event fireing and also to support the '.complete' property on images create in JavaScript. r=nisheeth@netscape.com git-svn-id: svn://10.0.0.236/trunk@77858 18797224-902f-48f8-a5cc-f745e15eee43 --- .../html/content/src/nsHTMLImageElement.cpp | 92 +++++++++++- mozilla/layout/base/nsCSSRendering.cpp | 14 +- mozilla/layout/base/nsFrameManager.cpp | 2 +- mozilla/layout/base/nsPresContext.cpp | 15 +- mozilla/layout/base/nsPresContext.h | 5 +- .../layout/base/public/nsIFrameImageLoader.h | 6 +- mozilla/layout/base/public/nsIPresContext.h | 5 +- mozilla/layout/base/public/nsPresContext.h | 5 +- .../layout/base/src/nsFrameImageLoader.cpp | 131 ++++++++---------- mozilla/layout/base/src/nsFrameImageLoader.h | 7 +- mozilla/layout/base/src/nsPresContext.cpp | 15 +- mozilla/layout/base/src/nsPresContext.h | 5 +- mozilla/layout/generic/nsFrame.cpp | 2 +- mozilla/layout/html/base/src/nsFrame.cpp | 2 +- .../layout/html/base/src/nsFrameManager.cpp | 2 +- .../html/base/src/nsHTMLImageLoader.cpp | 4 +- .../html/content/src/nsHTMLImageElement.cpp | 92 +++++++++++- .../layout/html/style/src/nsCSSRendering.cpp | 14 +- 18 files changed, 288 insertions(+), 130 deletions(-) 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);