mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-24 05:11:16 +00:00
Bug 697230: Part 2 - Push onload blocking logic down into imagelib. r=joe sr=bz
This commit is contained in:
parent
2e07e6f8c2
commit
ef988eb931
@ -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)
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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:
|
||||
/**
|
||||
|
@ -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)
|
||||
|
@ -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,
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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)
|
||||
|
||||
|
@ -23,6 +23,7 @@ XPIDLSRCS = \
|
||||
imgIDecoderObserver.idl \
|
||||
imgIEncoder.idl \
|
||||
imgILoader.idl \
|
||||
imgIOnloadBlocker.idl \
|
||||
imgIRequest.idl \
|
||||
imgITools.idl \
|
||||
$(NULL)
|
||||
|
64
image/public/imgIOnloadBlocker.idl
Normal file
64
image/public/imgIOnloadBlocker.idl
Normal 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);
|
||||
};
|
@ -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;
|
||||
|
@ -230,6 +230,7 @@ private:
|
||||
bool mIsMultiPartChannel : 1;
|
||||
bool mGotData : 1;
|
||||
bool mIsInCache : 1;
|
||||
bool mBlockingOnload : 1;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user