fixing bug 75185 r=brendan sr=attinasi

This commit is contained in:
pavlov%netscape.com 2001-04-15 02:13:49 +00:00
Родитель 2fa656fb4b
Коммит 4f028f9c98
4 изменённых файлов: 418 добавлений и 154 удалений

Просмотреть файл

@ -69,6 +69,8 @@ static NS_DEFINE_CID(kIOServiceCID, NS_IOSERVICE_CID);
#include "nsIDOMNode.h"
#include "nsContentPolicyUtils.h"
#ifdef DEBUG
#undef NOISY_IMAGE_LOADING
@ -189,13 +191,19 @@ nsImageFrame::Destroy(nsIPresContext* aPresContext)
}
#ifdef USE_IMG2
if (mImageRequest)
mImageRequest->Cancel(NS_ERROR_FAILURE); // NS_BINDING_ABORT ?
if (mLowImageRequest)
mLowImageRequest->Cancel(NS_ERROR_FAILURE); // NS_BINDING_ABORT ?
if (mImageRequest)
mImageRequest->Cancel(NS_ERROR_FAILURE); // NS_BINDING_ABORT ?
if (mLowImageRequest)
mLowImageRequest->Cancel(NS_ERROR_FAILURE); // NS_BINDING_ABORT ?
// set the frame to null so we don't send messages to a dead object.
if (mListener)
NS_REINTERPRET_CAST(nsImageListener*, mListener.get())->SetFrame(nsnull);
mImageRequest = nsnull;
mLowImageRequest = nsnull;
mListener = nsnull;
if (mListener)
NS_REINTERPRET_CAST(nsImageListener*, mListener.get())->SetFrame(nsnull); // set the frame to null so we don't send messages to a dead object.
#endif
#ifndef USE_IMG2
@ -245,19 +253,21 @@ nsImageFrame::Init(nsIPresContext* aPresContext,
nsresult lowSrcResult;
lowSrcResult = mContent->GetAttribute(kNameSpaceID_HTML, nsHTMLAtoms::lowsrc, lowSrc);
// Set the image loader's source URL and base URL
#ifndef USE_IMG2
nsCOMPtr<nsIURI> baseURL;
GetBaseURI(getter_AddRefs(baseURL));
#endif
// Set the image loader's source URL and base URL
#ifdef USE_IMG2
nsImageListener *listener;
NS_NEWXPCOM(listener, nsImageListener);
NS_ADDREF(listener);
listener->SetFrame(this);
listener->QueryInterface(NS_GET_IID(imgIDecoderObserver), getter_AddRefs(mListener));
NS_ASSERTION(mListener, "queryinterface for the listener failed");
NS_RELEASE(listener);
if (!mListener) {
nsImageListener *listener = new nsImageListener(this);
if (!listener) return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(listener);
listener->QueryInterface(NS_GET_IID(imgIDecoderObserver), getter_AddRefs(mListener));
NS_ASSERTION(mListener, "queryinterface for the listener failed");
NS_RELEASE(listener);
}
nsCOMPtr<imgILoader> il(do_GetService("@mozilla.org/image/loader;1", &rv));
if (NS_FAILED(rv))
@ -270,9 +280,11 @@ nsImageFrame::Init(nsIPresContext* aPresContext,
if (NS_CONTENT_ATTR_HAS_VALUE == lowSrcResult && lowSrc.Length() > 0) {
#ifdef USE_IMG2
nsCOMPtr<nsIURI> lowURI;
NS_NewURI(getter_AddRefs(lowURI), src, baseURL);
GetURI(lowSrc, getter_AddRefs(lowURI));
il->LoadImage(lowURI, loadGroup, mListener, aPresContext, getter_AddRefs(mLowImageRequest));
if (CanLoadImage(lowURI)) {
il->LoadImage(lowURI, loadGroup, mListener, aPresContext, getter_AddRefs(mLowImageRequest));
}
#else
mLowSrcImageLoader = new nsHTMLImageLoader;
if (mLowSrcImageLoader) {
@ -287,9 +299,11 @@ nsImageFrame::Init(nsIPresContext* aPresContext,
mCanSendLoadEvent = PR_TRUE;
nsCOMPtr<nsIURI> srcURI;
NS_NewURI(getter_AddRefs(srcURI), src, baseURL);
il->LoadImage(srcURI, loadGroup, mListener, aPresContext, getter_AddRefs(mImageRequest));
// if the image was found in the cache, it is possible that LoadImage will result in a call to OnStartContainer()
GetURI(src, getter_AddRefs(srcURI));
if (CanLoadImage(srcURI)) {
il->LoadImage(srcURI, loadGroup, mListener, aPresContext, getter_AddRefs(mImageRequest));
// if the image was found in the cache, it is possible that LoadImage will result in a call to OnStartContainer()
}
#else
mImageLoader.Init(this, UpdateImageFrame, (void*)&mImageLoader, baseURL, src);
@ -324,10 +338,6 @@ NS_IMETHODIMP nsImageFrame::OnStartDecode(imgIRequest *aRequest, nsIPresContext
NS_IMETHODIMP nsImageFrame::OnStartContainer(imgIRequest *aRequest, nsIPresContext *aPresContext, imgIContainer *aImage)
{
nsCOMPtr<nsIPresShell> presShell;
nsresult rv = aPresContext->GetShell(getter_AddRefs(presShell));
if (NS_FAILED(rv)) return rv;
mInitialLoadCompleted = PR_TRUE;
nscoord w, h;
@ -350,26 +360,16 @@ NS_IMETHODIMP nsImageFrame::OnStartContainer(imgIRequest *aRequest, nsIPresConte
if (mComputedSize.width != 0 && mComputedSize.height != 0)
mTransform.SetToScale((float(mIntrinsicSize.width) / float(mComputedSize.width)), (float(mIntrinsicSize.height) / float(mComputedSize.height)));
if (mParent) {
if (mGotInitialReflow) { // don't reflow if we havn't gotten the inital reflow yet
if (!mSizeConstrained) {
nsCOMPtr<nsIPresShell> presShell;
aPresContext->GetShell(getter_AddRefs(presShell));
NS_ASSERTION(mParent, "No parent to pass the reflow request up to.");
NS_ASSERTION(presShell, "No PresShell.");
if (mParent && presShell && mGotInitialReflow) { // don't reflow if we havn't gotten the inital reflow yet
mState |= NS_FRAME_IS_DIRTY;
mParent->ReflowDirtyChild(presShell, (nsIFrame*) this);
mParent->ReflowDirtyChild(presShell, NS_STATIC_CAST(nsIFrame*, this));
}
}
else {
NS_ASSERTION(0, "No parent to pass the reflow request up to.");
}
}
if (mCanSendLoadEvent && presShell) {
// Send load event
mCanSendLoadEvent = PR_FALSE;
nsEventStatus status = nsEventStatus_eIgnore;
nsEvent event;
event.eventStructType = NS_EVENT;
event.message = NS_IMAGE_LOAD;
presShell->HandleEventWithTarget(&event,this,mContent,NS_EVENT_FLAG_INIT | NS_EVENT_FLAG_CANT_BUBBLE,&status);
}
return NS_OK;
@ -382,19 +382,18 @@ NS_IMETHODIMP nsImageFrame::OnStartFrame(imgIRequest *aRequest, nsIPresContext *
NS_IMETHODIMP nsImageFrame::OnDataAvailable(imgIRequest *aRequest, nsIPresContext *aPresContext, gfxIImageFrame *aFrame, const nsRect *aRect)
{
nsCOMPtr<nsIPresShell> presShell;
nsresult rv = aPresContext->GetShell(getter_AddRefs(presShell));
if (NS_FAILED(rv)) return rv;
// XXX we need to make sure that the reflow from the OnContainerStart has been
// XXX do we need to make sure that the reflow from the OnStartContainer has been
// processed before we start calling invalidate
if (!aRect)
return NS_ERROR_NULL_POINTER;
nsRect r(aRect->x, aRect->y, aRect->width, aRect->height);
/* XXX Why do we subtract 1 here? The rect is (for example): (0, 0, 600, 1)..
Why do we have to make y -1?
*/
// The y coordinate of aRect is passed as a scanline where the first scanline is given
// a value of 1. We need to convert this to the nsFrames coordinate space by subtracting
// 1.
@ -426,15 +425,76 @@ NS_IMETHODIMP nsImageFrame::OnStopContainer(imgIRequest *aRequest, nsIPresContex
NS_IMETHODIMP nsImageFrame::OnStopDecode(imgIRequest *aRequest, nsIPresContext *aPresContext, nsresult aStatus, const PRUnichar *aStatusArg)
{
nsCOMPtr<nsIPresShell> presShell;
aPresContext->GetShell(getter_AddRefs(presShell));
// check to see if an image error occurred
PRBool imageFailedToLoad = PR_FALSE;
if (NS_FAILED(aStatus)) { // We failed to load the image. Notify the pres shell
PRBool lowFailed = PR_FALSE;
PRBool imageFailed = PR_FALSE;
// One of the two images didn't load, which one?
if (mLowImageRequest == aRequest || !mLowImageRequest) {
lowFailed = PR_TRUE;
}
if (mImageRequest == aRequest || !mImageRequest) {
imageFailed = PR_TRUE;
}
if (imageFailed && lowFailed)
imageFailedToLoad = PR_TRUE;
}
// if src failed and there is no lowsrc
// or both failed to load, then notify the PresShell
if (imageFailedToLoad) {
if (presShell) {
nsAutoString usemap;
mContent->GetAttribute(kNameSpaceID_HTML, nsHTMLAtoms::usemap, usemap);
// We failed to load the image. Notify the pres shell if we aren't an image map
if (usemap.IsEmpty()) {
presShell->CantRenderReplacedElement(aPresContext, this);
}
}
}
// After these DOM events are fired its possible that this frame may be deleted. As a result
// the code should not attempt to access any of the frames internal data after this point.
if (presShell) {
if (imageFailedToLoad) {
// Send error event
nsEventStatus status = nsEventStatus_eIgnore;
nsEvent event;
event.eventStructType = NS_EVENT;
event.message = NS_IMAGE_ERROR;
presShell->HandleEventWithTarget(&event,this,mContent,NS_EVENT_FLAG_INIT,&status);
} else if (mCanSendLoadEvent) {
// Send load event
mCanSendLoadEvent = PR_FALSE;
nsEventStatus status = nsEventStatus_eIgnore;
nsEvent event;
event.eventStructType = NS_EVENT;
event.message = NS_IMAGE_LOAD;
presShell->HandleEventWithTarget(&event,this,mContent,NS_EVENT_FLAG_INIT | NS_EVENT_FLAG_CANT_BUBBLE,&status);
}
}
return NS_OK;
}
NS_IMETHODIMP nsImageFrame::FrameChanged(imgIContainer *aContainer, nsIPresContext *aPresContext, gfxIImageFrame *aNewFrame, nsRect *aDirtyRect)
{
nsRect r(*aDirtyRect);
float p2t;
aPresContext->GetPixelsToTwips(&p2t);
nsRect r(*aDirtyRect);
r *= p2t; // convert to twips
r.x = NSIntPixelsToTwips(r.x, p2t);
r.y = NSIntPixelsToTwips(r.y, p2t);
r.width = NSIntPixelsToTwips(r.width, p2t);
r.height = NSIntPixelsToTwips(r.height, p2t);
mTransform.TransformCoord(&r.x, &r.y, &r.width, &r.height);
@ -487,7 +547,7 @@ nsImageFrame::UpdateImage(nsIPresContext* aPresContext, PRUint32 aStatus, void*
nsAutoString usemap;
mContent->GetAttribute(kNameSpaceID_HTML, nsHTMLAtoms::usemap, usemap);
// We failed to load the image. Notify the pres shell if we aren't an image map
if (usemap.Length() == 0) {
if (usemap.IsEmpty()) {
presShell->CantRenderReplacedElement(aPresContext, this);
}
}
@ -616,7 +676,7 @@ nsImageFrame::GetDesiredSize(nsIPresContext* aPresContext,
newHeight = (mIntrinsicSize.height * newWidth) / mIntrinsicSize.width;
haveComputedSize = PR_TRUE;
} else {
newHeight = NSIntPixelsToTwips(1, p2t); // XXX?
newHeight = 0;
needIntrinsicImageSize = PR_TRUE;
}
}
@ -628,30 +688,31 @@ nsImageFrame::GetDesiredSize(nsIPresContext* aPresContext,
newWidth = (mIntrinsicSize.width * newHeight) / mIntrinsicSize.height;
haveComputedSize = PR_TRUE;
} else {
newWidth = NSIntPixelsToTwips(1, p2t);
newWidth = 0;
needIntrinsicImageSize = PR_TRUE;
}
} else {
// auto size the image
if (mIntrinsicSize.width == 0 && mIntrinsicSize.height == 0) {
newWidth = NSIntPixelsToTwips(1, p2t);
newHeight = NSIntPixelsToTwips(1, p2t);
if (mIntrinsicSize.width == 0 && mIntrinsicSize.height == 0)
needIntrinsicImageSize = PR_TRUE;
} else {
newWidth = mIntrinsicSize.width;
newHeight = mIntrinsicSize.height;
else
haveComputedSize = PR_TRUE;
}
newWidth = mIntrinsicSize.width;
newHeight = mIntrinsicSize.height;
}
mComputedSize.width = newWidth;
mComputedSize.height = newHeight;
if (mComputedSize == mIntrinsicSize)
if (mComputedSize == mIntrinsicSize) {
mTransform.SetToIdentity();
else
mTransform.SetToScale((float(mIntrinsicSize.width) / float(mComputedSize.width)), (float(mIntrinsicSize.height) / float(mComputedSize.height)));
} else {
if (mComputedSize.width != 0 && mComputedSize.height != 0) {
mTransform.SetToScale(float(mIntrinsicSize.width) / float(mComputedSize.width),
float(mIntrinsicSize.height) / float(mComputedSize.height));
}
}
aDesiredSize.width = mComputedSize.width;
aDesiredSize.height = mComputedSize.height;
@ -977,12 +1038,12 @@ nsImageFrame::Paint(nsIPresContext* aPresContext,
PRInt32 imgSrcLinesLoaded = -1;
#ifdef USE_IMG2
NS_ASSERTION(mImageRequest, "no image request! this is bad");
nsCOMPtr<imgIContainer> imgCon;
nsCOMPtr<imgIContainer> lowImgCon;
mImageRequest->GetImage(getter_AddRefs(imgCon));
if (mImageRequest) {
mImageRequest->GetImage(getter_AddRefs(imgCon));
}
#else
nsIImage * lowImage = nsnull;
nsIImage * image = nsnull;
@ -1001,8 +1062,10 @@ nsImageFrame::Paint(nsIPresContext* aPresContext,
#endif
#ifdef USE_IMG2
PRUint32 loadStatus;
mImageRequest->GetImageStatus(&loadStatus);
PRUint32 loadStatus = imgIRequest::STATUS_NONE;
if (mImageRequest) {
mImageRequest->GetImageStatus(&loadStatus);
}
if (!(loadStatus & imgIRequest::STATUS_SIZE_AVAILABLE) || (!imgCon && !lowImgCon)) {
#else
image = mImageLoader.GetImage();
@ -1143,7 +1206,7 @@ nsImageFrame::GetImageMap(nsIPresContext* aPresContext)
if (nsnull == mImageMap) {
nsAutoString usemap;
mContent->GetAttribute(kNameSpaceID_HTML, nsHTMLAtoms::usemap, usemap);
if (0 == usemap.Length()) {
if (usemap.IsEmpty()) {
return nsnull;
}
@ -1480,18 +1543,17 @@ nsImageFrame::AttributeChanged(nsIPresContext* aPresContext,
PRUint32 loadStatus;
#ifdef USE_IMG2
nsCOMPtr<nsIURI> baseURI;
GetBaseURI(getter_AddRefs(baseURI));
nsCOMPtr<nsILoadGroup> loadGroup;
GetLoadGroup(aPresContext, getter_AddRefs(loadGroup));
mImageRequest->GetImageStatus(&loadStatus);
if (loadStatus & imgIRequest::STATUS_SIZE_AVAILABLE) {
nsCOMPtr<nsIURI> uri;
NS_NewURI(getter_AddRefs(uri), newSRC, baseURI);
GetURI(newSRC, getter_AddRefs(uri));
nsCOMPtr<imgILoader> il(do_GetService("@mozilla.org/image/loader;1"));
NS_ASSERTION(il, "no image loader!");
il->LoadImage(uri, loadGroup, mListener, aPresContext, getter_AddRefs(mImageRequest));
mImageRequest->GetImageStatus(&loadStatus);
@ -1516,9 +1578,11 @@ nsImageFrame::AttributeChanged(nsIPresContext* aPresContext,
mCanSendLoadEvent = PR_TRUE;
nsCOMPtr<nsIURI> uri;
NS_NewURI(getter_AddRefs(uri), newSRC, baseURI);
GetURI(newSRC, getter_AddRefs(uri));
nsCOMPtr<imgILoader> il(do_GetService("@mozilla.org/image/loader;1"));
NS_ASSERTION(il, "no image loader!");
il->LoadImage(uri, loadGroup, mListener, aPresContext, getter_AddRefs(mImageRequest));
#else
mImageLoader.StopLoadImage(aPresContext);
@ -1619,6 +1683,35 @@ void HaveFixedSize(const nsHTMLReflowState& aReflowState, PRPackedBool& aConstra
heightUnit == eStyleUnit_Percent));
}
#define INTERNAL_GOPHER_STRING "internal-gopher-"
#define INTERNAL_GOPHER_LENGTH 17
void
nsImageFrame::GetURI(const nsAReadableString& aSpec, nsIURI **aURI)
{
nsAutoString newURI;
/* Note: navigator 4.* and earlier releases ignored the base tags
effect on the builtin images. So we do too. Use aSpec instead
of the absolute url...
*/
/* The prefix for special "internal" images that are well known.
Look and see if this is an internal-gopher- url.
*/
if (NS_LITERAL_STRING(INTERNAL_GOPHER_STRING).Equals(Substring(aSpec, 0, INTERNAL_GOPHER_LENGTH))) {
newURI.Assign(NS_LITERAL_STRING("resource:/res/html/gopher-") +
Substring(aSpec, INTERNAL_GOPHER_LENGTH, aSpec.Length() - INTERNAL_GOPHER_LENGTH) +
NS_LITERAL_STRING(".gif"));
} else {
newURI.Assign(aSpec);
}
nsCOMPtr<nsIURI> baseURI;
GetBaseURI(getter_AddRefs(baseURI));
NS_NewURI(aURI, newURI, baseURI);
}
void
nsImageFrame::GetBaseURI(nsIURI **aURI)
{
@ -1664,6 +1757,40 @@ nsImageFrame::GetLoadGroup(nsIPresContext *aPresContext, nsILoadGroup **aLoadGro
}
// Check with the content-policy things to make sure this load is permitted.
PRBool
nsImageFrame::CanLoadImage(nsIURI *aURI)
{
PRBool shouldLoad = PR_TRUE; // default permit
// XXX leave this if 0'd until there is a good way to test it.
#if 0
nsresult rv;
nsCOMPtr<nsIDOMElement> element(do_QueryInterface(mContent));
if (!element) // this would seem bad(tm)
return PR_FALSE;
nsXPIDLCString uric;
aURI->GetSpec(getter_Copies(uric));
nsString uri = NS_ConvertUTF8toUCS2(uric);
rv = NS_CheckContentLoadPolicy(nsIContentPolicy::CONTENT_IMAGE,
uri, element, &shouldLoad);
if (NS_SUCCEEDED(rv) && !shouldLoad)
return PR_FALSE;
/* ... additional checks ? */
#endif
return shouldLoad;
}
#ifdef DEBUG
NS_IMETHODIMP
nsImageFrame::SizeOf(nsISizeOfHandler* aHandler, PRUint32* aResult) const
@ -1692,7 +1819,8 @@ nsImageFrame::SizeOf(nsISizeOfHandler* aHandler, PRUint32* aResult) const
#ifdef USE_IMG2
NS_IMPL_ISUPPORTS2(nsImageListener, imgIDecoderObserver, imgIContainerObserver)
nsImageListener::nsImageListener()
nsImageListener::nsImageListener(nsImageFrame *aFrame) :
mFrame(aFrame)
{
NS_INIT_ISUPPORTS();
}

Просмотреть файл

@ -24,6 +24,7 @@
#include "nsLeafFrame.h"
#include "nsString.h"
#include "nsAReadableString.h"
#include "nsIPresContext.h"
#include "nsHTMLImageLoader.h"
#include "nsIImageFrame.h"
@ -49,7 +50,7 @@ class nsImageFrame;
class nsImageListener : imgIDecoderObserver
{
public:
nsImageListener();
nsImageListener(nsImageFrame *aFrame);
virtual ~nsImageListener();
NS_DECL_ISUPPORTS
@ -182,8 +183,11 @@ protected:
PRUint32 aStatus);
#endif
void GetBaseURI(nsIURI **uri);
void GetLoadGroup(nsIPresContext *aPresContext, nsILoadGroup **aLoadGroup);
PRBool CanLoadImage(nsIURI *aURI);
inline void GetURI(const nsAReadableString& aSpec, nsIURI **aURI);
inline void GetBaseURI(nsIURI **uri);
inline void GetLoadGroup(nsIPresContext *aPresContext, nsILoadGroup **aLoadGroup);
nsHTMLImageLoader mImageLoader;
nsHTMLImageLoader * mLowSrcImageLoader;

Просмотреть файл

@ -69,6 +69,8 @@ static NS_DEFINE_CID(kIOServiceCID, NS_IOSERVICE_CID);
#include "nsIDOMNode.h"
#include "nsContentPolicyUtils.h"
#ifdef DEBUG
#undef NOISY_IMAGE_LOADING
@ -189,13 +191,19 @@ nsImageFrame::Destroy(nsIPresContext* aPresContext)
}
#ifdef USE_IMG2
if (mImageRequest)
mImageRequest->Cancel(NS_ERROR_FAILURE); // NS_BINDING_ABORT ?
if (mLowImageRequest)
mLowImageRequest->Cancel(NS_ERROR_FAILURE); // NS_BINDING_ABORT ?
if (mImageRequest)
mImageRequest->Cancel(NS_ERROR_FAILURE); // NS_BINDING_ABORT ?
if (mLowImageRequest)
mLowImageRequest->Cancel(NS_ERROR_FAILURE); // NS_BINDING_ABORT ?
// set the frame to null so we don't send messages to a dead object.
if (mListener)
NS_REINTERPRET_CAST(nsImageListener*, mListener.get())->SetFrame(nsnull);
mImageRequest = nsnull;
mLowImageRequest = nsnull;
mListener = nsnull;
if (mListener)
NS_REINTERPRET_CAST(nsImageListener*, mListener.get())->SetFrame(nsnull); // set the frame to null so we don't send messages to a dead object.
#endif
#ifndef USE_IMG2
@ -245,19 +253,21 @@ nsImageFrame::Init(nsIPresContext* aPresContext,
nsresult lowSrcResult;
lowSrcResult = mContent->GetAttribute(kNameSpaceID_HTML, nsHTMLAtoms::lowsrc, lowSrc);
// Set the image loader's source URL and base URL
#ifndef USE_IMG2
nsCOMPtr<nsIURI> baseURL;
GetBaseURI(getter_AddRefs(baseURL));
#endif
// Set the image loader's source URL and base URL
#ifdef USE_IMG2
nsImageListener *listener;
NS_NEWXPCOM(listener, nsImageListener);
NS_ADDREF(listener);
listener->SetFrame(this);
listener->QueryInterface(NS_GET_IID(imgIDecoderObserver), getter_AddRefs(mListener));
NS_ASSERTION(mListener, "queryinterface for the listener failed");
NS_RELEASE(listener);
if (!mListener) {
nsImageListener *listener = new nsImageListener(this);
if (!listener) return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(listener);
listener->QueryInterface(NS_GET_IID(imgIDecoderObserver), getter_AddRefs(mListener));
NS_ASSERTION(mListener, "queryinterface for the listener failed");
NS_RELEASE(listener);
}
nsCOMPtr<imgILoader> il(do_GetService("@mozilla.org/image/loader;1", &rv));
if (NS_FAILED(rv))
@ -270,9 +280,11 @@ nsImageFrame::Init(nsIPresContext* aPresContext,
if (NS_CONTENT_ATTR_HAS_VALUE == lowSrcResult && lowSrc.Length() > 0) {
#ifdef USE_IMG2
nsCOMPtr<nsIURI> lowURI;
NS_NewURI(getter_AddRefs(lowURI), src, baseURL);
GetURI(lowSrc, getter_AddRefs(lowURI));
il->LoadImage(lowURI, loadGroup, mListener, aPresContext, getter_AddRefs(mLowImageRequest));
if (CanLoadImage(lowURI)) {
il->LoadImage(lowURI, loadGroup, mListener, aPresContext, getter_AddRefs(mLowImageRequest));
}
#else
mLowSrcImageLoader = new nsHTMLImageLoader;
if (mLowSrcImageLoader) {
@ -287,9 +299,11 @@ nsImageFrame::Init(nsIPresContext* aPresContext,
mCanSendLoadEvent = PR_TRUE;
nsCOMPtr<nsIURI> srcURI;
NS_NewURI(getter_AddRefs(srcURI), src, baseURL);
il->LoadImage(srcURI, loadGroup, mListener, aPresContext, getter_AddRefs(mImageRequest));
// if the image was found in the cache, it is possible that LoadImage will result in a call to OnStartContainer()
GetURI(src, getter_AddRefs(srcURI));
if (CanLoadImage(srcURI)) {
il->LoadImage(srcURI, loadGroup, mListener, aPresContext, getter_AddRefs(mImageRequest));
// if the image was found in the cache, it is possible that LoadImage will result in a call to OnStartContainer()
}
#else
mImageLoader.Init(this, UpdateImageFrame, (void*)&mImageLoader, baseURL, src);
@ -324,10 +338,6 @@ NS_IMETHODIMP nsImageFrame::OnStartDecode(imgIRequest *aRequest, nsIPresContext
NS_IMETHODIMP nsImageFrame::OnStartContainer(imgIRequest *aRequest, nsIPresContext *aPresContext, imgIContainer *aImage)
{
nsCOMPtr<nsIPresShell> presShell;
nsresult rv = aPresContext->GetShell(getter_AddRefs(presShell));
if (NS_FAILED(rv)) return rv;
mInitialLoadCompleted = PR_TRUE;
nscoord w, h;
@ -350,26 +360,16 @@ NS_IMETHODIMP nsImageFrame::OnStartContainer(imgIRequest *aRequest, nsIPresConte
if (mComputedSize.width != 0 && mComputedSize.height != 0)
mTransform.SetToScale((float(mIntrinsicSize.width) / float(mComputedSize.width)), (float(mIntrinsicSize.height) / float(mComputedSize.height)));
if (mParent) {
if (mGotInitialReflow) { // don't reflow if we havn't gotten the inital reflow yet
if (!mSizeConstrained) {
nsCOMPtr<nsIPresShell> presShell;
aPresContext->GetShell(getter_AddRefs(presShell));
NS_ASSERTION(mParent, "No parent to pass the reflow request up to.");
NS_ASSERTION(presShell, "No PresShell.");
if (mParent && presShell && mGotInitialReflow) { // don't reflow if we havn't gotten the inital reflow yet
mState |= NS_FRAME_IS_DIRTY;
mParent->ReflowDirtyChild(presShell, (nsIFrame*) this);
mParent->ReflowDirtyChild(presShell, NS_STATIC_CAST(nsIFrame*, this));
}
}
else {
NS_ASSERTION(0, "No parent to pass the reflow request up to.");
}
}
if (mCanSendLoadEvent && presShell) {
// Send load event
mCanSendLoadEvent = PR_FALSE;
nsEventStatus status = nsEventStatus_eIgnore;
nsEvent event;
event.eventStructType = NS_EVENT;
event.message = NS_IMAGE_LOAD;
presShell->HandleEventWithTarget(&event,this,mContent,NS_EVENT_FLAG_INIT | NS_EVENT_FLAG_CANT_BUBBLE,&status);
}
return NS_OK;
@ -382,19 +382,18 @@ NS_IMETHODIMP nsImageFrame::OnStartFrame(imgIRequest *aRequest, nsIPresContext *
NS_IMETHODIMP nsImageFrame::OnDataAvailable(imgIRequest *aRequest, nsIPresContext *aPresContext, gfxIImageFrame *aFrame, const nsRect *aRect)
{
nsCOMPtr<nsIPresShell> presShell;
nsresult rv = aPresContext->GetShell(getter_AddRefs(presShell));
if (NS_FAILED(rv)) return rv;
// XXX we need to make sure that the reflow from the OnContainerStart has been
// XXX do we need to make sure that the reflow from the OnStartContainer has been
// processed before we start calling invalidate
if (!aRect)
return NS_ERROR_NULL_POINTER;
nsRect r(aRect->x, aRect->y, aRect->width, aRect->height);
/* XXX Why do we subtract 1 here? The rect is (for example): (0, 0, 600, 1)..
Why do we have to make y -1?
*/
// The y coordinate of aRect is passed as a scanline where the first scanline is given
// a value of 1. We need to convert this to the nsFrames coordinate space by subtracting
// 1.
@ -426,15 +425,76 @@ NS_IMETHODIMP nsImageFrame::OnStopContainer(imgIRequest *aRequest, nsIPresContex
NS_IMETHODIMP nsImageFrame::OnStopDecode(imgIRequest *aRequest, nsIPresContext *aPresContext, nsresult aStatus, const PRUnichar *aStatusArg)
{
nsCOMPtr<nsIPresShell> presShell;
aPresContext->GetShell(getter_AddRefs(presShell));
// check to see if an image error occurred
PRBool imageFailedToLoad = PR_FALSE;
if (NS_FAILED(aStatus)) { // We failed to load the image. Notify the pres shell
PRBool lowFailed = PR_FALSE;
PRBool imageFailed = PR_FALSE;
// One of the two images didn't load, which one?
if (mLowImageRequest == aRequest || !mLowImageRequest) {
lowFailed = PR_TRUE;
}
if (mImageRequest == aRequest || !mImageRequest) {
imageFailed = PR_TRUE;
}
if (imageFailed && lowFailed)
imageFailedToLoad = PR_TRUE;
}
// if src failed and there is no lowsrc
// or both failed to load, then notify the PresShell
if (imageFailedToLoad) {
if (presShell) {
nsAutoString usemap;
mContent->GetAttribute(kNameSpaceID_HTML, nsHTMLAtoms::usemap, usemap);
// We failed to load the image. Notify the pres shell if we aren't an image map
if (usemap.IsEmpty()) {
presShell->CantRenderReplacedElement(aPresContext, this);
}
}
}
// After these DOM events are fired its possible that this frame may be deleted. As a result
// the code should not attempt to access any of the frames internal data after this point.
if (presShell) {
if (imageFailedToLoad) {
// Send error event
nsEventStatus status = nsEventStatus_eIgnore;
nsEvent event;
event.eventStructType = NS_EVENT;
event.message = NS_IMAGE_ERROR;
presShell->HandleEventWithTarget(&event,this,mContent,NS_EVENT_FLAG_INIT,&status);
} else if (mCanSendLoadEvent) {
// Send load event
mCanSendLoadEvent = PR_FALSE;
nsEventStatus status = nsEventStatus_eIgnore;
nsEvent event;
event.eventStructType = NS_EVENT;
event.message = NS_IMAGE_LOAD;
presShell->HandleEventWithTarget(&event,this,mContent,NS_EVENT_FLAG_INIT | NS_EVENT_FLAG_CANT_BUBBLE,&status);
}
}
return NS_OK;
}
NS_IMETHODIMP nsImageFrame::FrameChanged(imgIContainer *aContainer, nsIPresContext *aPresContext, gfxIImageFrame *aNewFrame, nsRect *aDirtyRect)
{
nsRect r(*aDirtyRect);
float p2t;
aPresContext->GetPixelsToTwips(&p2t);
nsRect r(*aDirtyRect);
r *= p2t; // convert to twips
r.x = NSIntPixelsToTwips(r.x, p2t);
r.y = NSIntPixelsToTwips(r.y, p2t);
r.width = NSIntPixelsToTwips(r.width, p2t);
r.height = NSIntPixelsToTwips(r.height, p2t);
mTransform.TransformCoord(&r.x, &r.y, &r.width, &r.height);
@ -487,7 +547,7 @@ nsImageFrame::UpdateImage(nsIPresContext* aPresContext, PRUint32 aStatus, void*
nsAutoString usemap;
mContent->GetAttribute(kNameSpaceID_HTML, nsHTMLAtoms::usemap, usemap);
// We failed to load the image. Notify the pres shell if we aren't an image map
if (usemap.Length() == 0) {
if (usemap.IsEmpty()) {
presShell->CantRenderReplacedElement(aPresContext, this);
}
}
@ -616,7 +676,7 @@ nsImageFrame::GetDesiredSize(nsIPresContext* aPresContext,
newHeight = (mIntrinsicSize.height * newWidth) / mIntrinsicSize.width;
haveComputedSize = PR_TRUE;
} else {
newHeight = NSIntPixelsToTwips(1, p2t); // XXX?
newHeight = 0;
needIntrinsicImageSize = PR_TRUE;
}
}
@ -628,30 +688,31 @@ nsImageFrame::GetDesiredSize(nsIPresContext* aPresContext,
newWidth = (mIntrinsicSize.width * newHeight) / mIntrinsicSize.height;
haveComputedSize = PR_TRUE;
} else {
newWidth = NSIntPixelsToTwips(1, p2t);
newWidth = 0;
needIntrinsicImageSize = PR_TRUE;
}
} else {
// auto size the image
if (mIntrinsicSize.width == 0 && mIntrinsicSize.height == 0) {
newWidth = NSIntPixelsToTwips(1, p2t);
newHeight = NSIntPixelsToTwips(1, p2t);
if (mIntrinsicSize.width == 0 && mIntrinsicSize.height == 0)
needIntrinsicImageSize = PR_TRUE;
} else {
newWidth = mIntrinsicSize.width;
newHeight = mIntrinsicSize.height;
else
haveComputedSize = PR_TRUE;
}
newWidth = mIntrinsicSize.width;
newHeight = mIntrinsicSize.height;
}
mComputedSize.width = newWidth;
mComputedSize.height = newHeight;
if (mComputedSize == mIntrinsicSize)
if (mComputedSize == mIntrinsicSize) {
mTransform.SetToIdentity();
else
mTransform.SetToScale((float(mIntrinsicSize.width) / float(mComputedSize.width)), (float(mIntrinsicSize.height) / float(mComputedSize.height)));
} else {
if (mComputedSize.width != 0 && mComputedSize.height != 0) {
mTransform.SetToScale(float(mIntrinsicSize.width) / float(mComputedSize.width),
float(mIntrinsicSize.height) / float(mComputedSize.height));
}
}
aDesiredSize.width = mComputedSize.width;
aDesiredSize.height = mComputedSize.height;
@ -977,12 +1038,12 @@ nsImageFrame::Paint(nsIPresContext* aPresContext,
PRInt32 imgSrcLinesLoaded = -1;
#ifdef USE_IMG2
NS_ASSERTION(mImageRequest, "no image request! this is bad");
nsCOMPtr<imgIContainer> imgCon;
nsCOMPtr<imgIContainer> lowImgCon;
mImageRequest->GetImage(getter_AddRefs(imgCon));
if (mImageRequest) {
mImageRequest->GetImage(getter_AddRefs(imgCon));
}
#else
nsIImage * lowImage = nsnull;
nsIImage * image = nsnull;
@ -1001,8 +1062,10 @@ nsImageFrame::Paint(nsIPresContext* aPresContext,
#endif
#ifdef USE_IMG2
PRUint32 loadStatus;
mImageRequest->GetImageStatus(&loadStatus);
PRUint32 loadStatus = imgIRequest::STATUS_NONE;
if (mImageRequest) {
mImageRequest->GetImageStatus(&loadStatus);
}
if (!(loadStatus & imgIRequest::STATUS_SIZE_AVAILABLE) || (!imgCon && !lowImgCon)) {
#else
image = mImageLoader.GetImage();
@ -1143,7 +1206,7 @@ nsImageFrame::GetImageMap(nsIPresContext* aPresContext)
if (nsnull == mImageMap) {
nsAutoString usemap;
mContent->GetAttribute(kNameSpaceID_HTML, nsHTMLAtoms::usemap, usemap);
if (0 == usemap.Length()) {
if (usemap.IsEmpty()) {
return nsnull;
}
@ -1480,18 +1543,17 @@ nsImageFrame::AttributeChanged(nsIPresContext* aPresContext,
PRUint32 loadStatus;
#ifdef USE_IMG2
nsCOMPtr<nsIURI> baseURI;
GetBaseURI(getter_AddRefs(baseURI));
nsCOMPtr<nsILoadGroup> loadGroup;
GetLoadGroup(aPresContext, getter_AddRefs(loadGroup));
mImageRequest->GetImageStatus(&loadStatus);
if (loadStatus & imgIRequest::STATUS_SIZE_AVAILABLE) {
nsCOMPtr<nsIURI> uri;
NS_NewURI(getter_AddRefs(uri), newSRC, baseURI);
GetURI(newSRC, getter_AddRefs(uri));
nsCOMPtr<imgILoader> il(do_GetService("@mozilla.org/image/loader;1"));
NS_ASSERTION(il, "no image loader!");
il->LoadImage(uri, loadGroup, mListener, aPresContext, getter_AddRefs(mImageRequest));
mImageRequest->GetImageStatus(&loadStatus);
@ -1516,9 +1578,11 @@ nsImageFrame::AttributeChanged(nsIPresContext* aPresContext,
mCanSendLoadEvent = PR_TRUE;
nsCOMPtr<nsIURI> uri;
NS_NewURI(getter_AddRefs(uri), newSRC, baseURI);
GetURI(newSRC, getter_AddRefs(uri));
nsCOMPtr<imgILoader> il(do_GetService("@mozilla.org/image/loader;1"));
NS_ASSERTION(il, "no image loader!");
il->LoadImage(uri, loadGroup, mListener, aPresContext, getter_AddRefs(mImageRequest));
#else
mImageLoader.StopLoadImage(aPresContext);
@ -1619,6 +1683,35 @@ void HaveFixedSize(const nsHTMLReflowState& aReflowState, PRPackedBool& aConstra
heightUnit == eStyleUnit_Percent));
}
#define INTERNAL_GOPHER_STRING "internal-gopher-"
#define INTERNAL_GOPHER_LENGTH 17
void
nsImageFrame::GetURI(const nsAReadableString& aSpec, nsIURI **aURI)
{
nsAutoString newURI;
/* Note: navigator 4.* and earlier releases ignored the base tags
effect on the builtin images. So we do too. Use aSpec instead
of the absolute url...
*/
/* The prefix for special "internal" images that are well known.
Look and see if this is an internal-gopher- url.
*/
if (NS_LITERAL_STRING(INTERNAL_GOPHER_STRING).Equals(Substring(aSpec, 0, INTERNAL_GOPHER_LENGTH))) {
newURI.Assign(NS_LITERAL_STRING("resource:/res/html/gopher-") +
Substring(aSpec, INTERNAL_GOPHER_LENGTH, aSpec.Length() - INTERNAL_GOPHER_LENGTH) +
NS_LITERAL_STRING(".gif"));
} else {
newURI.Assign(aSpec);
}
nsCOMPtr<nsIURI> baseURI;
GetBaseURI(getter_AddRefs(baseURI));
NS_NewURI(aURI, newURI, baseURI);
}
void
nsImageFrame::GetBaseURI(nsIURI **aURI)
{
@ -1664,6 +1757,40 @@ nsImageFrame::GetLoadGroup(nsIPresContext *aPresContext, nsILoadGroup **aLoadGro
}
// Check with the content-policy things to make sure this load is permitted.
PRBool
nsImageFrame::CanLoadImage(nsIURI *aURI)
{
PRBool shouldLoad = PR_TRUE; // default permit
// XXX leave this if 0'd until there is a good way to test it.
#if 0
nsresult rv;
nsCOMPtr<nsIDOMElement> element(do_QueryInterface(mContent));
if (!element) // this would seem bad(tm)
return PR_FALSE;
nsXPIDLCString uric;
aURI->GetSpec(getter_Copies(uric));
nsString uri = NS_ConvertUTF8toUCS2(uric);
rv = NS_CheckContentLoadPolicy(nsIContentPolicy::CONTENT_IMAGE,
uri, element, &shouldLoad);
if (NS_SUCCEEDED(rv) && !shouldLoad)
return PR_FALSE;
/* ... additional checks ? */
#endif
return shouldLoad;
}
#ifdef DEBUG
NS_IMETHODIMP
nsImageFrame::SizeOf(nsISizeOfHandler* aHandler, PRUint32* aResult) const
@ -1692,7 +1819,8 @@ nsImageFrame::SizeOf(nsISizeOfHandler* aHandler, PRUint32* aResult) const
#ifdef USE_IMG2
NS_IMPL_ISUPPORTS2(nsImageListener, imgIDecoderObserver, imgIContainerObserver)
nsImageListener::nsImageListener()
nsImageListener::nsImageListener(nsImageFrame *aFrame) :
mFrame(aFrame)
{
NS_INIT_ISUPPORTS();
}

Просмотреть файл

@ -24,6 +24,7 @@
#include "nsLeafFrame.h"
#include "nsString.h"
#include "nsAReadableString.h"
#include "nsIPresContext.h"
#include "nsHTMLImageLoader.h"
#include "nsIImageFrame.h"
@ -49,7 +50,7 @@ class nsImageFrame;
class nsImageListener : imgIDecoderObserver
{
public:
nsImageListener();
nsImageListener(nsImageFrame *aFrame);
virtual ~nsImageListener();
NS_DECL_ISUPPORTS
@ -182,8 +183,11 @@ protected:
PRUint32 aStatus);
#endif
void GetBaseURI(nsIURI **uri);
void GetLoadGroup(nsIPresContext *aPresContext, nsILoadGroup **aLoadGroup);
PRBool CanLoadImage(nsIURI *aURI);
inline void GetURI(const nsAReadableString& aSpec, nsIURI **aURI);
inline void GetBaseURI(nsIURI **uri);
inline void GetLoadGroup(nsIPresContext *aPresContext, nsILoadGroup **aLoadGroup);
nsHTMLImageLoader mImageLoader;
nsHTMLImageLoader * mLowSrcImageLoader;