Bug 697230: Part 2 - Push onload blocking logic down into imagelib. r=joe sr=bz

This commit is contained in:
Kyle Huey 2012-08-13 15:58:53 -07:00
parent 2e07e6f8c2
commit ef988eb931
19 changed files with 291 additions and 85 deletions

View File

@ -1672,6 +1672,21 @@ extern const nsIID kThisPtrOffsetsSID;
NS_OFFSET_AND_INTERFACE_TABLE_END \
NS_OFFSET_AND_INTERFACE_TABLE_TO_MAP_SEGUE
#define NS_NODE_INTERFACE_TABLE9(_class, _i1, _i2, _i3, _i4, _i5, _i6, _i7, \
_i8, _i9) \
NS_NODE_OFFSET_AND_INTERFACE_TABLE_BEGIN(_class) \
NS_INTERFACE_TABLE_ENTRY(_class, _i1) \
NS_INTERFACE_TABLE_ENTRY(_class, _i2) \
NS_INTERFACE_TABLE_ENTRY(_class, _i3) \
NS_INTERFACE_TABLE_ENTRY(_class, _i4) \
NS_INTERFACE_TABLE_ENTRY(_class, _i5) \
NS_INTERFACE_TABLE_ENTRY(_class, _i6) \
NS_INTERFACE_TABLE_ENTRY(_class, _i7) \
NS_INTERFACE_TABLE_ENTRY(_class, _i8) \
NS_INTERFACE_TABLE_ENTRY(_class, _i9) \
NS_OFFSET_AND_INTERFACE_TABLE_END \
NS_OFFSET_AND_INTERFACE_TABLE_TO_MAP_SEGUE
NS_DEFINE_STATIC_IID_ACCESSOR(nsINode, NS_INODE_IID)

View File

@ -48,8 +48,12 @@ public:
NS_DECL_ISUPPORTS_INHERITED
};
NS_IMPL_ISUPPORTS_INHERITED3(nsGenConImageContent, nsXMLElement,
nsIImageLoadingContent, imgIContainerObserver, imgIDecoderObserver)
NS_IMPL_ISUPPORTS_INHERITED4(nsGenConImageContent,
nsXMLElement,
nsIImageLoadingContent,
imgIContainerObserver,
imgIDecoderObserver,
imgIOnloadBlocker)
nsresult
NS_NewGenConImageContent(nsIContent** aResult, already_AddRefed<nsINodeInfo> aNodeInfo,

View File

@ -153,23 +153,6 @@ nsImageLoadingContent::OnStartDecode(imgIRequest* aRequest)
{
NS_ENSURE_TRUE(nsContentUtils::IsCallerChrome(), NS_ERROR_NOT_AVAILABLE);
// Onload blocking. This only applies for the current request.
if (aRequest == mCurrentRequest) {
// Determine whether this is a background request (this can be the case
// with multipart/x-mixed-replace images, for example).
PRUint32 loadFlags;
nsresult rv = aRequest->GetLoadFlags(&loadFlags);
bool background =
(NS_SUCCEEDED(rv) && (loadFlags & nsIRequest::LOAD_BACKGROUND));
// Block onload for non-background requests
if (!background) {
NS_ABORT_IF_FALSE(!mBlockingOnload, "Shouldn't already be blocking");
SetBlockingOnload(true);
}
}
LOOP_OVER_OBSERVERS(OnStartDecode(aRequest));
return NS_OK;
}
@ -215,10 +198,6 @@ nsImageLoadingContent::OnStopFrame(imgIRequest* aRequest,
{
NS_ENSURE_TRUE(nsContentUtils::IsCallerChrome(), NS_ERROR_NOT_AVAILABLE);
// If we're blocking a load, one frame is enough
if (aRequest == mCurrentRequest)
SetBlockingOnload(false);
LOOP_OVER_OBSERVERS(OnStopFrame(aRequest, aFrame));
return NS_OK;
}
@ -229,15 +208,6 @@ nsImageLoadingContent::OnStopContainer(imgIRequest* aRequest,
{
NS_ENSURE_TRUE(nsContentUtils::IsCallerChrome(), NS_ERROR_NOT_AVAILABLE);
// This is really hacky. We need to handle the case where we start decoding,
// block onload, but then hit an error before we get to our first frame. In
// theory we would just hook in at OnStopDecode, but OnStopDecode is broken
// until we fix bug 505385. OnStopContainer is actually going away at that
// point. So for now we take advantage of the fact that OnStopContainer is
// always fired in the decoders at the same time as OnStopDecode.
if (aRequest == mCurrentRequest)
SetBlockingOnload(false);
LOOP_OVER_OBSERVERS(OnStopContainer(aRequest, aContainer));
return NS_OK;
}
@ -309,7 +279,7 @@ nsImageLoadingContent::OnStopDecode(imgIRequest* aRequest,
FireEvent(NS_LITERAL_STRING("error"));
}
nsCOMPtr<nsINode> thisNode = do_QueryInterface(this);
nsCOMPtr<nsINode> thisNode = do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
nsSVGEffects::InvalidateDirectRenderingObservers(thisNode->AsElement());
return NS_OK;
@ -598,6 +568,36 @@ NS_IMETHODIMP nsImageLoadingContent::ForceReload()
return LoadImage(currentURI, true, true, nullptr, nsIRequest::VALIDATE_ALWAYS);
}
NS_IMETHODIMP
nsImageLoadingContent::BlockOnload(imgIRequest* aRequest)
{
if (aRequest != mCurrentRequest) {
return NS_OK;
}
nsIDocument* doc = GetOurCurrentDoc();
if (doc) {
doc->BlockOnload();
}
return NS_OK;
}
NS_IMETHODIMP
nsImageLoadingContent::UnblockOnload(imgIRequest* aRequest)
{
if (aRequest != mCurrentRequest) {
return NS_OK;
}
nsIDocument* doc = GetOurCurrentDoc();
if (doc) {
doc->UnblockOnload(false);
}
return NS_OK;
}
/*
* Non-interface methods
*/
@ -691,7 +691,7 @@ nsImageLoadingContent::LoadImage(nsIURI* aNewURI,
// We use the principal of aDocument to avoid having to QI |this| an extra
// time. It should always be the same as the principal of this node.
#ifdef DEBUG
nsCOMPtr<nsIContent> thisContent = do_QueryInterface(this);
nsCOMPtr<nsIContent> thisContent = do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
NS_ABORT_IF_FALSE(thisContent &&
thisContent->NodePrincipal() == aDocument->NodePrincipal(),
"Principal mismatch?");
@ -699,8 +699,11 @@ nsImageLoadingContent::LoadImage(nsIURI* aNewURI,
// Are we blocked?
PRInt16 cpDecision = nsIContentPolicy::REJECT_REQUEST;
nsContentUtils::CanLoadImage(aNewURI, this, aDocument,
aDocument->NodePrincipal(), &cpDecision);
nsContentUtils::CanLoadImage(aNewURI,
static_cast<nsIImageLoadingContent*>(this),
aDocument,
aDocument->NodePrincipal(),
&cpDecision);
if (!NS_CP_ACCEPTED(cpDecision)) {
FireEvent(NS_LITERAL_STRING("error"));
SetBlockedRequest(aNewURI, cpDecision);
@ -806,7 +809,7 @@ nsImageLoadingContent::UpdateImageState(bool aNotify)
return;
}
nsCOMPtr<nsIContent> thisContent = do_QueryInterface(this);
nsCOMPtr<nsIContent> thisContent = do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
if (!thisContent) {
return;
}
@ -870,7 +873,8 @@ nsImageLoadingContent::UseAsPrimaryRequest(imgIRequest* aRequest,
nsIDocument*
nsImageLoadingContent::GetOurOwnerDoc()
{
nsCOMPtr<nsIContent> thisContent = do_QueryInterface(this);
nsCOMPtr<nsIContent> thisContent =
do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
NS_ENSURE_TRUE(thisContent, nullptr);
return thisContent->OwnerDoc();
@ -879,7 +883,8 @@ nsImageLoadingContent::GetOurOwnerDoc()
nsIDocument*
nsImageLoadingContent::GetOurCurrentDoc()
{
nsCOMPtr<nsIContent> thisContent = do_QueryInterface(this);
nsCOMPtr<nsIContent> thisContent =
do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
NS_ENSURE_TRUE(thisContent, nullptr);
return thisContent->GetCurrentDoc();
@ -888,7 +893,8 @@ nsImageLoadingContent::GetOurCurrentDoc()
nsIFrame*
nsImageLoadingContent::GetOurPrimaryFrame()
{
nsCOMPtr<nsIContent> thisContent = do_QueryInterface(this);
nsCOMPtr<nsIContent> thisContent =
do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
return thisContent->GetPrimaryFrame();
}
@ -911,7 +917,7 @@ nsImageLoadingContent::StringToURI(const nsAString& aSpec,
NS_PRECONDITION(aURI, "Null out param");
// (1) Get the base URI
nsCOMPtr<nsIContent> thisContent = do_QueryInterface(this);
nsCOMPtr<nsIContent> thisContent = do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
NS_ASSERTION(thisContent, "An image loading content must be an nsIContent");
nsCOMPtr<nsIURI> baseURL = thisContent->GetBaseURI();
@ -933,7 +939,7 @@ nsImageLoadingContent::FireEvent(const nsAString& aEventType)
// loops in cases when onLoad handlers reset the src and the new src is in
// cache.
nsCOMPtr<nsINode> thisNode = do_QueryInterface(this);
nsCOMPtr<nsINode> thisNode = do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
nsRefPtr<nsAsyncDOMEvent> event =
new nsLoadBlockingAsyncDOMEvent(thisNode, aEventType, false, false);
@ -1080,10 +1086,6 @@ nsImageLoadingContent::ClearCurrentRequest(nsresult aReason)
mCurrentRequest->CancelAndForgetObserver(aReason);
mCurrentRequest = nullptr;
mCurrentRequestFlags = 0;
// We only block onload during the decoding of "current" images. This one is
// going away, so we should unblock unconditionally here.
SetBlockingOnload(false);
}
void
@ -1147,28 +1149,6 @@ nsImageLoadingContent::HaveSize(imgIRequest *aImage)
return (NS_SUCCEEDED(rv) && (status & imgIRequest::STATUS_SIZE_AVAILABLE));
}
void
nsImageLoadingContent::SetBlockingOnload(bool aBlocking)
{
// If we're already in the desired state, we have nothing to do
if (mBlockingOnload == aBlocking)
return;
// Get the document
nsIDocument* doc = GetOurOwnerDoc();
if (doc) {
// Take the appropriate action
if (aBlocking)
doc->BlockOnload();
else
doc->UnblockOnload(false);
// Update our state
mBlockingOnload = aBlocking;
}
}
void
nsImageLoadingContent::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
nsIContent* aBindingParent,

View File

@ -15,6 +15,7 @@
#include "imgIContainerObserver.h"
#include "imgIDecoderObserver.h"
#include "imgIOnloadBlocker.h"
#include "mozilla/CORSMode.h"
#include "nsCOMPtr.h"
#include "nsContentUtils.h" // NS_CONTENT_DELETE_LIST_MEMBER
@ -27,7 +28,8 @@ class nsIDocument;
class imgILoader;
class nsIIOService;
class nsImageLoadingContent : public nsIImageLoadingContent
class nsImageLoadingContent : public nsIImageLoadingContent,
public imgIOnloadBlocker
{
/* METHODS */
public:
@ -37,6 +39,7 @@ public:
NS_DECL_IMGICONTAINEROBSERVER
NS_DECL_IMGIDECODEROBSERVER
NS_DECL_NSIIMAGELOADINGCONTENT
NS_DECL_IMGIONLOADBLOCKER
protected:
/**

View File

@ -89,12 +89,13 @@ DOMCI_NODE_DATA(HTMLImageElement, nsHTMLImageElement)
// QueryInterface implementation for nsHTMLImageElement
NS_INTERFACE_TABLE_HEAD(nsHTMLImageElement)
NS_HTML_CONTENT_INTERFACE_TABLE5(nsHTMLImageElement,
NS_HTML_CONTENT_INTERFACE_TABLE6(nsHTMLImageElement,
nsIDOMHTMLImageElement,
nsIJSNativeInitializer,
imgIDecoderObserver,
nsIImageLoadingContent,
imgIContainerObserver)
imgIContainerObserver,
imgIOnloadBlocker)
NS_HTML_CONTENT_INTERFACE_TABLE_TO_MAP_SEGUE(nsHTMLImageElement,
nsGenericHTMLElement)
NS_HTML_CONTENT_INTERFACE_TABLE_TAIL_CLASSINFO(HTMLImageElement)

View File

@ -616,13 +616,14 @@ DOMCI_NODE_DATA(HTMLInputElement, nsHTMLInputElement)
// QueryInterface implementation for nsHTMLInputElement
NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION_INHERITED(nsHTMLInputElement)
NS_HTML_CONTENT_INTERFACE_TABLE8(nsHTMLInputElement,
NS_HTML_CONTENT_INTERFACE_TABLE9(nsHTMLInputElement,
nsIDOMHTMLInputElement,
nsITextControlElement,
nsIPhonetic,
imgIDecoderObserver,
nsIImageLoadingContent,
imgIContainerObserver,
imgIOnloadBlocker,
nsIDOMNSEditableElement,
nsIConstraintValidation)
NS_HTML_CONTENT_INTERFACE_TABLE_TO_MAP_SEGUE(nsHTMLInputElement,

View File

@ -206,6 +206,7 @@ NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION_INHERITED(nsHTMLObjectElement)
NS_INTERFACE_TABLE_ENTRY(nsHTMLObjectElement, nsIFrameLoaderOwner)
NS_INTERFACE_TABLE_ENTRY(nsHTMLObjectElement, nsIObjectLoadingContent)
NS_INTERFACE_TABLE_ENTRY(nsHTMLObjectElement, nsIImageLoadingContent)
NS_INTERFACE_TABLE_ENTRY(nsHTMLObjectElement, imgIOnloadBlocker)
NS_INTERFACE_TABLE_ENTRY(nsHTMLObjectElement, imgIContainerObserver)
NS_INTERFACE_TABLE_ENTRY(nsHTMLObjectElement, nsIInterfaceRequestor)
NS_INTERFACE_TABLE_ENTRY(nsHTMLObjectElement, nsIChannelEventSink)

View File

@ -254,6 +254,7 @@ NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION_INHERITED(nsHTMLSharedObjectElement)
NS_INTERFACE_TABLE_ENTRY(nsHTMLSharedObjectElement, nsIObjectLoadingContent)
NS_INTERFACE_TABLE_ENTRY(nsHTMLSharedObjectElement, imgIDecoderObserver)
NS_INTERFACE_TABLE_ENTRY(nsHTMLSharedObjectElement, nsIImageLoadingContent)
NS_INTERFACE_TABLE_ENTRY(nsHTMLSharedObjectElement, imgIOnloadBlocker)
NS_INTERFACE_TABLE_ENTRY(nsHTMLSharedObjectElement, nsIInterfaceRequestor)
NS_INTERFACE_TABLE_ENTRY(nsHTMLSharedObjectElement, nsIChannelEventSink)
NS_OFFSET_AND_INTERFACE_TABLE_END

View File

@ -5490,11 +5490,12 @@ NS_IMPL_RELEASE_INHERITED(nsSVGFEImageElement,nsSVGFEImageElementBase)
DOMCI_NODE_DATA(SVGFEImageElement, nsSVGFEImageElement)
NS_INTERFACE_TABLE_HEAD(nsSVGFEImageElement)
NS_NODE_INTERFACE_TABLE8(nsSVGFEImageElement, nsIDOMNode, nsIDOMElement,
NS_NODE_INTERFACE_TABLE9(nsSVGFEImageElement, nsIDOMNode, nsIDOMElement,
nsIDOMSVGElement,
nsIDOMSVGFilterPrimitiveStandardAttributes,
nsIDOMSVGFEImageElement, nsIDOMSVGURIReference,
imgIDecoderObserver, nsIImageLoadingContent)
imgIDecoderObserver, nsIImageLoadingContent,
imgIOnloadBlocker)
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(SVGFEImageElement)
NS_INTERFACE_MAP_END_INHERITING(nsSVGFEImageElementBase)

View File

@ -39,11 +39,11 @@ NS_IMPL_RELEASE_INHERITED(nsSVGImageElement,nsSVGImageElementBase)
DOMCI_NODE_DATA(SVGImageElement, nsSVGImageElement)
NS_INTERFACE_TABLE_HEAD(nsSVGImageElement)
NS_NODE_INTERFACE_TABLE8(nsSVGImageElement, nsIDOMNode, nsIDOMElement,
NS_NODE_INTERFACE_TABLE9(nsSVGImageElement, nsIDOMNode, nsIDOMElement,
nsIDOMSVGElement, nsIDOMSVGTests,
nsIDOMSVGImageElement,
nsIDOMSVGURIReference, imgIDecoderObserver,
nsIImageLoadingContent)
nsIImageLoadingContent, imgIOnloadBlocker)
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(SVGImageElement)
NS_INTERFACE_MAP_END_INHERITING(nsSVGImageElementBase)

View File

@ -23,6 +23,7 @@ XPIDLSRCS = \
imgIDecoderObserver.idl \
imgIEncoder.idl \
imgILoader.idl \
imgIOnloadBlocker.idl \
imgIRequest.idl \
imgITools.idl \
$(NULL)

View File

@ -0,0 +1,64 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2012
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Kyle Huey <me@kylehuey.com> (original author)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "nsISupports.idl"
interface imgIRequest;
[uuid(dc126d90-0ee0-4683-b942-2fa66e443abc)]
interface imgIOnloadBlocker : nsISupports
{
/**
* blockOnload
* Called when it is appropriate to block onload for the given imgIRequest.
*
* @param aRequest
* The request that should block onload.
*/
void blockOnload(in imgIRequest aRequest);
/**
* unblockOnload
* Called when it is appropriate to unblock onload for the given
* imgIRequest.
*
* @param aRequest
* The request that should unblock onload.
*/
void unblockOnload(in imgIRequest aRequest);
};

View File

@ -83,7 +83,7 @@ imgRequest::imgRequest() :
mValidator(nullptr), mImageSniffers("image-sniffing-services"),
mInnerWindowId(0), mCORSMode(imgIRequest::CORS_NONE),
mDecodeRequested(false), mIsMultiPartChannel(false), mGotData(false),
mIsInCache(false)
mIsInCache(false), mBlockingOnload(false)
{
// Register our pref observers if we haven't yet.
if (NS_UNLIKELY(!gInitializedPrefCaches)) {
@ -278,6 +278,18 @@ void imgRequest::Cancel(nsresult aStatus)
LOG_SCOPE(gImgLog, "imgRequest::Cancel");
imgStatusTracker& statusTracker = GetStatusTracker();
if (mBlockingOnload) {
mBlockingOnload = false;
statusTracker.RecordUnblockOnload();
nsTObserverArray<imgRequestProxy*>::ForwardIterator iter(mObservers);
while (iter.HasMore()) {
statusTracker.SendUnblockOnload(iter.GetNext());
}
}
statusTracker.RecordCancel();
RemoveFromCache();
@ -511,11 +523,24 @@ NS_IMETHODIMP imgRequest::OnStartDecode(imgIRequest *request)
"OnStartDecode callback before we've created our image");
mImage->GetStatusTracker().RecordStartDecode();
imgStatusTracker& tracker = mImage->GetStatusTracker();
tracker.RecordStartDecode();
nsTObserverArray<imgRequestProxy*>::ForwardIterator iter(mObservers);
while (iter.HasMore()) {
mImage->GetStatusTracker().SendStartDecode(iter.GetNext());
tracker.SendStartDecode(iter.GetNext());
}
if (!mIsMultiPartChannel) {
MOZ_ASSERT(!mBlockingOnload);
mBlockingOnload = true;
tracker.RecordBlockOnload();
nsTObserverArray<imgRequestProxy*>::ForwardIterator iter(mObservers);
while (iter.HasMore()) {
tracker.SendBlockOnload(iter.GetNext());
}
}
/* In the case of streaming jpegs, it is possible to get multiple OnStartDecodes which
@ -602,11 +627,23 @@ NS_IMETHODIMP imgRequest::OnStopFrame(imgIRequest *request,
NS_ABORT_IF_FALSE(mImage,
"OnStopFrame callback before we've created our image");
mImage->GetStatusTracker().RecordStopFrame(frame);
imgStatusTracker& tracker = mImage->GetStatusTracker();
tracker.RecordStopFrame(frame);
nsTObserverArray<imgRequestProxy*>::ForwardIterator iter(mObservers);
while (iter.HasMore()) {
mImage->GetStatusTracker().SendStopFrame(iter.GetNext(), frame);
tracker.SendStopFrame(iter.GetNext(), frame);
}
if (mBlockingOnload) {
mBlockingOnload = false;
tracker.RecordUnblockOnload();
nsTObserverArray<imgRequestProxy*>::ForwardIterator iter(mObservers);
while (iter.HasMore()) {
tracker.SendUnblockOnload(iter.GetNext());
}
}
return NS_OK;
@ -620,11 +657,29 @@ NS_IMETHODIMP imgRequest::OnStopContainer(imgIRequest *request,
NS_ABORT_IF_FALSE(mImage,
"OnDataContainer callback before we've created our image");
mImage->GetStatusTracker().RecordStopContainer(image);
imgStatusTracker& tracker = mImage->GetStatusTracker();
tracker.RecordStopContainer(image);
nsTObserverArray<imgRequestProxy*>::ForwardIterator iter(mObservers);
while (iter.HasMore()) {
mImage->GetStatusTracker().SendStopContainer(iter.GetNext(), image);
tracker.SendStopContainer(iter.GetNext(), image);
}
// This is really hacky. We need to handle the case where we start decoding,
// block onload, but then hit an error before we get to our first frame. In
// theory we would just hook in at OnStopDecode, but OnStopDecode is broken
// until we fix bug 505385. OnStopContainer is actually going away at that
// point. So for now we take advantage of the fact that OnStopContainer is
// always fired in the decoders at the same time as OnStopDecode.
if (mBlockingOnload) {
mBlockingOnload = false;
tracker.RecordUnblockOnload();
nsTObserverArray<imgRequestProxy*>::ForwardIterator iter(mObservers);
while (iter.HasMore()) {
tracker.SendUnblockOnload(iter.GetNext());
}
}
return NS_OK;

View File

@ -230,6 +230,7 @@ private:
bool mIsMultiPartChannel : 1;
bool mGotData : 1;
bool mIsInCache : 1;
bool mBlockingOnload : 1;
};
#endif

View File

@ -5,6 +5,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "imgRequestProxy.h"
#include "imgIOnloadBlocker.h"
#include "nsIInputStream.h"
#include "nsIComponentManager.h"
@ -771,6 +772,34 @@ void imgRequestProxy::OnStopRequest(bool lastPart)
}
}
void imgRequestProxy::BlockOnload()
{
#ifdef PR_LOGGING
nsCAutoString name;
GetName(name);
LOG_FUNC_WITH_PARAM(gImgLog, "imgRequestProxy::BlockOnload", "name", name.get());
#endif
nsCOMPtr<imgIOnloadBlocker> blocker = do_QueryInterface(mListener);
if (blocker) {
blocker->BlockOnload(this);
}
}
void imgRequestProxy::UnblockOnload()
{
#ifdef PR_LOGGING
nsCAutoString name;
GetName(name);
LOG_FUNC_WITH_PARAM(gImgLog, "imgRequestProxy::UnblockOnload", "name", name.get());
#endif
nsCOMPtr<imgIOnloadBlocker> blocker = do_QueryInterface(mListener);
if (blocker) {
blocker->UnblockOnload(this);
}
}
void imgRequestProxy::NullOutListener()
{
// If we have animation consumers, then they don't matter anymore

View File

@ -153,6 +153,10 @@ protected:
void OnStartRequest();
void OnStopRequest(bool aLastPart);
/* non-virtual imgIOnloadBlocker methods */
void BlockOnload();
void UnblockOnload();
/* Finish up canceling ourselves */
void DoCancel(nsresult status);

View File

@ -200,6 +200,10 @@ imgStatusTracker::SyncNotify(imgRequestProxy* proxy)
if (mState & stateDecodeStarted)
proxy->OnStartDecode();
// BlockOnload
if (mState & stateBlockingOnload)
proxy->BlockOnload();
if (mImage) {
PRInt16 imageType = mImage->GetType();
// Send frame messages (OnStartFrame, OnDataAvailable, OnStopFrame)
@ -483,6 +487,7 @@ imgStatusTracker::RecordStartRequest()
mState &= ~stateDecodeStarted;
mState &= ~stateDecodeStopped;
mState &= ~stateRequestStopped;
mState &= ~stateBlockingOnload;
mState |= stateRequestStarted;
}
@ -515,3 +520,33 @@ imgStatusTracker::SendStopRequest(imgRequestProxy* aProxy, bool aLastPart, nsres
aProxy->OnStopRequest(aLastPart);
}
}
void
imgStatusTracker::RecordBlockOnload()
{
MOZ_ASSERT(!(mState & stateBlockingOnload));
mState |= stateBlockingOnload;
}
void
imgStatusTracker::SendBlockOnload(imgRequestProxy* aProxy)
{
if (!aProxy->NotificationsDeferred()) {
aProxy->BlockOnload();
}
}
void
imgStatusTracker::RecordUnblockOnload()
{
MOZ_ASSERT(mState & stateBlockingOnload);
mState &= ~stateBlockingOnload;
}
void
imgStatusTracker::SendUnblockOnload(imgRequestProxy* aProxy)
{
if (!aProxy->NotificationsDeferred()) {
aProxy->UnblockOnload();
}
}

View File

@ -31,7 +31,8 @@ enum {
stateDecodeStarted = PR_BIT(2),
stateDecodeStopped = PR_BIT(3),
stateFrameStopped = PR_BIT(4),
stateRequestStopped = PR_BIT(5)
stateRequestStopped = PR_BIT(5),
stateBlockingOnload = PR_BIT(6)
};
/*
@ -141,6 +142,15 @@ public:
void RecordStopRequest(bool aLastPart, nsresult aStatus);
void SendStopRequest(imgRequestProxy* aProxy, bool aLastPart, nsresult aStatus);
/* non-virtual imgIOnloadBlocker methods */
// NB: If UnblockOnload is sent, and then we are asked to replay the
// notifications, we will not send a BlockOnload/UnblockOnload pair. This
// is different from all the other notifications.
void RecordBlockOnload();
void SendBlockOnload(imgRequestProxy* aProxy);
void RecordUnblockOnload();
void SendUnblockOnload(imgRequestProxy* aProxy);
private:
friend class imgStatusNotifyRunnable;
friend class imgRequestNotifyRunnable;

View File

@ -75,7 +75,7 @@ function ImageListener(start_callback, stop_callback)
// We have to cancel the request when we're done with it to break any
// reference loops!
aRequest.cancel(0);
aRequest.cancelAndForgetObserver(0);
this.state |= STOP_REQUEST;