Bug 507902 - nsImageFrame static Icon Loads should not use the mListener of the first instantiated nsImageFrame.r=bz,joe

This commit is contained in:
Bobby Holley 2009-08-12 16:23:38 +02:00
Родитель fc065395c8
Коммит 4275f152b5
4 изменённых файлов: 211 добавлений и 116 удалений

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

@ -101,14 +101,6 @@
#include "nsBidiUtils.h"
#include "nsBidiPresUtils.h"
#ifdef DEBUG
#undef NOISY_IMAGE_LOADING
#undef NOISY_ICON_LOADING
#else
#undef NOISY_IMAGE_LOADING
#undef NOISY_ICON_LOADING
#endif
// sizes (pixels) for image icon, padding and border frame
#define ICON_SIZE (16)
#define ICON_PADDING (3)
@ -173,7 +165,8 @@ NS_NewImageFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
nsImageFrame::nsImageFrame(nsStyleContext* aContext) :
ImageFrameSuper(aContext),
mComputedSize(0, 0),
mIntrinsicSize(0, 0)
mIntrinsicSize(0, 0),
mDisplayingIcon(PR_FALSE)
{
// We assume our size is not constrained and we haven't gotten an
// initial reflow yet, so don't touch those flags.
@ -223,6 +216,10 @@ nsImageFrame::Destroy()
mListener = nsnull;
// If we were displaying an icon, take ourselves off the list
if (mDisplayingIcon)
gIconLoad->RemoveIconObserver(this);
nsSplittableFrame::Destroy();
}
@ -473,11 +470,6 @@ nsImageFrame::OnStartContainer(imgIRequest *aRequest, imgIContainer *aImage)
{
if (!aImage) return NS_ERROR_INVALID_ARG;
// handle iconLoads first...
if (HandleIconLoads(aRequest, PR_FALSE)) {
return NS_OK;
}
/* Get requested animation policy from the pres context:
* normal = 0
* one frame = 1
@ -539,13 +531,6 @@ nsImageFrame::OnDataAvailable(imgIRequest *aRequest,
// image scaling!
nsRect r = SourceRectToDest(*aRect);
// handle iconLoads first...
if (HandleIconLoads(aRequest, PR_FALSE)) {
// Image changed, invalidate
Invalidate(r);
return NS_OK;
}
if (IsPendingLoad(aRequest)) {
// We don't care
return NS_OK;
@ -576,11 +561,6 @@ nsImageFrame::OnStopDecode(imgIRequest *aRequest,
nsIPresShell *presShell = presContext->GetPresShell();
NS_ASSERTION(presShell, "No PresShell.");
// handle iconLoads first...
if (HandleIconLoads(aRequest, NS_SUCCEEDED(aStatus))) {
return NS_OK;
}
// Check what request type we're dealing with
nsCOMPtr<nsIImageLoadingContent> imageLoader = do_QueryInterface(mContent);
NS_ASSERTION(imageLoader, "Who's notifying us??");
@ -648,19 +628,23 @@ nsImageFrame::EnsureIntrinsicSize(nsPresContext* aPresContext)
// if mIntrinsicSize.width and height are 0, then we should
// check to see if the size is already known by the image container.
if (mIntrinsicSize.width == 0 && mIntrinsicSize.height == 0) {
// Jump through all the hoops to get the status of the request
nsCOMPtr<imgIRequest> currentRequest;
nsCOMPtr<nsIImageLoadingContent> imageLoader = do_QueryInterface(mContent);
if (imageLoader) {
if (imageLoader)
imageLoader->GetRequest(nsIImageLoadingContent::CURRENT_REQUEST,
getter_AddRefs(currentRequest));
}
nsCOMPtr<imgIContainer> currentContainer;
if (currentRequest) {
currentRequest->GetImage(getter_AddRefs(currentContainer));
}
PRUint32 status = 0;
if (currentRequest)
currentRequest->GetImageStatus(&status);
if (currentContainer) {
UpdateIntrinsicSize(currentContainer);
// If we know the size, we can grab it and use it for an update
if (status & imgIRequest::STATUS_SIZE_AVAILABLE) {
nsCOMPtr<imgIContainer> imgCon;
currentRequest->GetImage(getter_AddRefs(imgCon));
NS_ABORT_IF_FALSE(imgCon, "SIZE_AVAILABLE, but no imgContainer?");
UpdateIntrinsicSize(imgCon);
} else {
// image request is null or image size not known, probably an
// invalid image specified
@ -998,6 +982,12 @@ nsImageFrame::DisplayAltFeedback(nsIRenderingContext& aRenderingContext,
imgIRequest* aRequest,
nsPoint aPt)
{
// We should definitely have a gIconLoad here.
NS_ABORT_IF_FALSE(gIconLoad, "How did we succeed in Init then?");
// We always call this function with an image
NS_ABORT_IF_FALSE(aRequest, "Calling DisplayAltFeedback without an image");
// Calculate the inner area
nsRect inner = GetInnerArea() + aPt;
@ -1033,34 +1023,39 @@ nsImageFrame::DisplayAltFeedback(nsIRenderingContext& aRenderingContext,
aRenderingContext.PushState();
aRenderingContext.SetClipRect(inner, nsClipCombine_kIntersect);
PRBool dispIcon = gIconLoad ? gIconLoad->mPrefShowPlaceholders : PR_TRUE;
// Check if we should display image placeholders
if (dispIcon) {
if (gIconLoad->mPrefShowPlaceholders) {
const nsStyleVisibility* vis = GetStyleVisibility();
nscoord size = nsPresContext::CSSPixelsToAppUnits(ICON_SIZE);
PRBool iconUsed = PR_FALSE;
// see if the icon images are present...
if (gIconLoad && gIconLoad->mIconsLoaded) {
// pick the correct image
nsCOMPtr<imgIContainer> imgCon;
if (aRequest) {
aRequest->GetImage(getter_AddRefs(imgCon));
}
if (imgCon) {
// draw it
nsRect dest((vis->mDirection == NS_STYLE_DIRECTION_RTL) ?
inner.XMost() - size : inner.x,
inner.y, size, size);
nsLayoutUtils::DrawSingleImage(&aRenderingContext, imgCon,
nsLayoutUtils::GetGraphicsFilterForFrame(this), dest, aDirtyRect);
iconUsed = PR_TRUE;
}
// If we weren't previously displaying an icon, register ourselves
// as an observer for load and animation updates and flag that we're
// doing so now.
if (!mDisplayingIcon) {
gIconLoad->AddIconObserver(this);
mDisplayingIcon = PR_TRUE;
}
// if we could not draw the image, then just draw some graffiti
// If the image in question is loaded and decoded, draw it
PRUint32 imageStatus;
aRequest->GetImageStatus(&imageStatus);
if (imageStatus & imgIRequest::STATUS_FRAME_COMPLETE) {
nsCOMPtr<imgIContainer> imgCon;
aRequest->GetImage(getter_AddRefs(imgCon));
NS_ABORT_IF_FALSE(imgCon, "Frame Complete, but no image container?");
nsRect dest((vis->mDirection == NS_STYLE_DIRECTION_RTL) ?
inner.XMost() - size : inner.x,
inner.y, size, size);
nsLayoutUtils::DrawSingleImage(&aRenderingContext, imgCon,
nsLayoutUtils::GetGraphicsFilterForFrame(this), dest, aDirtyRect);
iconUsed = PR_TRUE;
}
// if we could not draw the icon, flag that we're waiting for it and
// just draw some graffiti in the mean time
if (!iconUsed) {
nscolor oldColor;
nscoord iconXPos = (vis->mDirection == NS_STYLE_DIRECTION_RTL) ?
@ -1214,7 +1209,18 @@ nsImageFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
currentRequest->GetImage(getter_AddRefs(imgCon));
}
if (!imageOK || !imgCon) {
// Determine if the size is available
PRBool haveSize = PR_FALSE;
PRUint32 imageStatus = 0;
if (currentRequest)
currentRequest->GetImageStatus(&imageStatus);
if (imageStatus & imgIRequest::STATUS_SIZE_AVAILABLE)
haveSize = PR_TRUE;
// We should never have the size and not have an image container
NS_ABORT_IF_FALSE(!haveSize || imgCon, "Have size but not container?");
if (!imageOK || !haveSize) {
// No image yet, or image load failed. Draw the alt-text and an icon
// indicating the status
rv = aLists.Content()->AppendNewToTop(new (aBuilder)
@ -1225,6 +1231,13 @@ nsImageFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
rv = aLists.Content()->AppendNewToTop(new (aBuilder)
nsDisplayImage(this, imgCon));
NS_ENSURE_SUCCESS(rv, rv);
// If we were previously displaying an icon, we're not anymore
if (mDisplayingIcon) {
gIconLoad->RemoveIconObserver(this);
mDisplayingIcon = PR_FALSE;
}
#ifdef DEBUG
if (GetShowFrameBorders() && GetImageMap(PresContext())) {
@ -1628,7 +1641,7 @@ nsImageFrame::LoadIcon(const nsAString& aSpec,
apply to icons. */
nsnull, /* referrer (not relevant for icons) */
loadGroup,
mListener,
gIconLoad,
nsnull, /* Not associated with any particular document */
loadFlags,
nsnull,
@ -1688,7 +1701,7 @@ nsresult nsImageFrame::LoadIcons(nsPresContext *aPresContext)
NS_NAMED_LITERAL_STRING(loadingSrc,"resource://gre/res/loading-image.png");
NS_NAMED_LITERAL_STRING(brokenSrc,"resource://gre/res/broken-image.png");
gIconLoad = new IconLoad(mListener);
gIconLoad = new IconLoad();
if (!gIconLoad)
return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(gIconLoad);
@ -1698,11 +1711,6 @@ nsresult nsImageFrame::LoadIcons(nsPresContext *aPresContext)
rv = LoadIcon(loadingSrc,
aPresContext,
getter_AddRefs(gIconLoad->mLoadingImage));
#ifdef NOISY_ICON_LOADING
printf("Loading request %p, rv=%u\n",
gIconLoad->mLoadingImage.get(), rv);
#endif
if (NS_FAILED(rv)) {
return rv;
}
@ -1710,56 +1718,18 @@ nsresult nsImageFrame::LoadIcons(nsPresContext *aPresContext)
rv = LoadIcon(brokenSrc,
aPresContext,
getter_AddRefs(gIconLoad->mBrokenImage));
#ifdef NOISY_ICON_LOADING
printf("Loading request %p, rv=%u\n",
gIconLoad->mBrokenImage.get(), rv);
#endif
// ImageLoader will callback into OnStartContainer, which will
// handle the mIconsLoaded flag
return rv;
}
PRBool nsImageFrame::HandleIconLoads(imgIRequest* aRequest, PRBool aLoaded)
{
PRBool result = PR_FALSE;
if (gIconLoad) {
// check which image it is
if (aRequest == gIconLoad->mLoadingImage ||
aRequest == gIconLoad->mBrokenImage) {
result = PR_TRUE;
if (aLoaded && (++gIconLoad->mIconsLoaded == 2))
gIconLoad->mLoadObserver = nsnull;
}
#ifdef NOISY_ICON_LOADING
if (gIconLoad->mIconsLoaded && result) {
printf( "Icons Loaded: request for %s\n",
aRequest == gIconLoad->mLoadingImage
? "mLoadingImage" : "mBrokenImage" );
}
#endif
}
#ifdef NOISY_ICON_LOADING
printf( "HandleIconLoads returned %s (%p)\n", result ? "TRUE" : "FALSE", this);
#endif
return result;
}
NS_IMPL_ISUPPORTS1(nsImageFrame::IconLoad, nsIObserver)
NS_IMPL_ISUPPORTS2(nsImageFrame::IconLoad, nsIObserver,
imgIDecoderObserver)
static const char kIconLoadPrefs[][40] = {
"browser.display.force_inline_alttext",
"browser.display.show_image_placeholders"
};
nsImageFrame::IconLoad::IconLoad(imgIDecoderObserver *aObserver)
: mLoadObserver(aObserver),
mIconsLoaded(0)
nsImageFrame::IconLoad::IconLoad()
{
nsCOMPtr<nsIPrefBranch2> prefBranch =
do_QueryInterface(nsContentUtils::GetPrefBranch());
@ -1800,6 +1770,94 @@ void nsImageFrame::IconLoad::GetPrefs()
PR_TRUE);
}
NS_IMETHODIMP
nsImageFrame::IconLoad::OnStartRequest(imgIRequest *aRequest)
{
return NS_OK;
}
NS_IMETHODIMP
nsImageFrame::IconLoad::OnStartDecode(imgIRequest *aRequest)
{
return NS_OK;
}
NS_IMETHODIMP
nsImageFrame::IconLoad::OnStartContainer(imgIRequest *aRequest,
imgIContainer *aContainer)
{
return NS_OK;
}
NS_IMETHODIMP
nsImageFrame::IconLoad::OnStartFrame(imgIRequest *aRequest,
PRUint32 aFrame)
{
return NS_OK;
}
NS_IMETHODIMP
nsImageFrame::IconLoad::OnDataAvailable(imgIRequest *aRequest,
PRBool aCurrentFrame,
const nsIntRect * aRect)
{
return NS_OK;
}
NS_IMETHODIMP
nsImageFrame::IconLoad::OnStopFrame(imgIRequest *aRequest,
PRUint32 aFrame)
{
return NS_OK;
}
NS_IMETHODIMP
nsImageFrame::IconLoad::OnStopContainer(imgIRequest *aRequest,
imgIContainer *aContainer)
{
return NS_OK;
}
NS_IMETHODIMP
nsImageFrame::IconLoad::OnStopDecode(imgIRequest *aRequest,
nsresult status,
const PRUnichar *statusArg)
{
return NS_OK;
}
NS_IMETHODIMP
nsImageFrame::IconLoad::OnStopRequest(imgIRequest *aRequest,
PRBool aIsLastPart)
{
nsTObserverArray<nsImageFrame*>::ForwardIterator iter(mIconObservers);
nsImageFrame *frame;
while (iter.HasMore()) {
frame = iter.GetNext();
frame->Invalidate(frame->GetRect());
}
return NS_OK;
}
NS_IMETHODIMP
nsImageFrame::IconLoad::FrameChanged(imgIContainer *aContainer,
nsIntRect * aDirtyRect)
{
nsTObserverArray<nsImageFrame*>::ForwardIterator iter(mIconObservers);
nsImageFrame *frame;
while (iter.HasMore()) {
frame = iter.GetNext();
frame->Invalidate(frame->GetRect());
}
return NS_OK;
}
NS_IMPL_ISUPPORTS2(nsImageListener, imgIDecoderObserver, imgIContainerObserver)
nsImageListener::nsImageListener(nsImageFrame *aFrame) :

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

@ -52,6 +52,7 @@
#include "nsTransform2D.h"
#include "imgIRequest.h"
#include "nsStubImageDecoderObserver.h"
#include "imgIDecoderObserver.h"
class nsIFrame;
class nsImageMap;
@ -268,7 +269,8 @@ private:
nsSize mComputedSize;
nsSize mIntrinsicSize;
nsTransform2D mTransform;
PRBool mDisplayingIcon;
static nsIIOService* sIOService;
/* loading / broken image icon support */
@ -282,17 +284,13 @@ private:
nsresult LoadIcons(nsPresContext *aPresContext);
nsresult LoadIcon(const nsAString& aSpec, nsPresContext *aPresContext,
imgIRequest **aRequest);
// HandleIconLoads: See if the request is for an Icon load. If it
// is, handle it and return TRUE otherwise, return FALSE (aCompleted
// is an input arg telling the routine if the request has completed)
PRBool HandleIconLoads(imgIRequest* aRequest, PRBool aCompleted);
class IconLoad : public nsIObserver {
// private class that wraps the data and logic needed for
class IconLoad : public nsIObserver,
public imgIDecoderObserver {
// private class that wraps the data and logic needed for
// broken image and loading image icons
public:
IconLoad(imgIDecoderObserver* aObserver);
IconLoad();
void Shutdown()
{
@ -309,15 +307,29 @@ private:
NS_DECL_ISUPPORTS
NS_DECL_NSIOBSERVER
NS_DECL_IMGICONTAINEROBSERVER
NS_DECL_IMGIDECODEROBSERVER
void AddIconObserver(nsImageFrame *frame) {
NS_ABORT_IF_FALSE(mIconObservers.IndexOf(frame) ==
nsTArray<nsImageFrame*>::NoIndex,
"Observer shouldn't aleady be in array");
mIconObservers.AppendElement(frame);
}
void RemoveIconObserver(nsImageFrame *frame) {
PRBool rv = mIconObservers.RemoveElement(frame);
NS_ABORT_IF_FALSE(rv, "Observer not in array");
}
private:
void GetPrefs();
nsTObserverArray<nsImageFrame*> mIconObservers;
public:
nsCOMPtr<imgIRequest> mLoadingImage;
nsCOMPtr<imgIRequest> mBrokenImage;
nsCOMPtr<imgIDecoderObserver> mLoadObserver; // keeps the observer alive
PRUint8 mIconsLoaded;
PRPackedBool mPrefForceInlineAltText;
PRPackedBool mPrefShowPlaceholders;
};

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

@ -67,7 +67,7 @@ interface imgILoader : nsISupports
* @param aInitialDocumentURI the URI that 'initiated' the load -- used for 3rd party cookie blocking
* @param aReferrerURI the 'referring' URI
* @param aLoadGroup Loadgroup to put the image load into
* @param aObserver the observer
* @param aObserver the observer (may be null)
* @param aCX some random data
* @param aLoadFlags Load flags for the request
* @param aCacheKey cache key to use for a load if the original
@ -96,7 +96,7 @@ interface imgILoader : nsISupports
* @param aChannel the channel to load the image from. This must
* already be opened before ths method is called, and there
* must have been no OnDataAvailable calls for it yet.
* @param aObserver the observer
* @param aObserver the observer (may be null)
* @param cx some random data
* @param aListener [out]
* A listener that should receive the data. Can be null, in which

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

@ -65,6 +65,31 @@ interface imgIRequest : nsIRequest
/**
* Bits set in the return value from imageStatus
* @name statusflags
*
* Meanings:
*
* STATUS_NONE: Nothing to report.
*
* STATUS_SIZE_AVAILABLE: We received enough image data
* from the network or filesystem that we know the width
* and height of the image, and have thus called SetSize()
* on the container.
*
* STATUS_LOAD_PARTIAL: Used internally by imgRequest to
* flag that a request is being cancelled as a result of
* a failure of a proxy holder and not an internal failure.
* At least I think that's what it does. Regardless, there's
* no reason for this flag to be public, and it should either
* go away or become a private state flag within imgRequest.
* Don't rely on it.
*
* STATUS_LOAD_COMPLETE: The data has been fully loaded
* to memory, but not necessarily fully decoded.
*
* STATUS_ERROR: An error occured loading the image.
*
* STATUS_FRAME_COMPLETE: The first frame has been
* completely decoded.
*/
//@{
const long STATUS_NONE = 0x0;