author | Kyle Huey <khuey@kylehuey.com> |
Sat, 07 Apr 2012 09:00:04 -0700 | |
changeset 94488 | 23fcc967bfce44719de2b6fbad7a7cc8df45a69b |
parent 94487 | 90c888efe410a66865b3f0cf4fcf8ba69704e6ae |
child 94489 | dd39182f70cbde594f6caf5ed6ce3e0b02a25665 |
push id | 886 |
push user | lsblakk@mozilla.com |
push date | Mon, 04 Jun 2012 19:57:52 +0000 |
treeherder | mozilla-beta@bbd8d5efd6d1 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | joe, bz |
bugs | 697230 |
milestone | 14.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/content/base/public/nsINode.h +++ b/content/base/public/nsINode.h @@ -1653,16 +1653,31 @@ extern const nsIID kThisPtrOffsetsSID; 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_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) #define NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER \ nsContentUtils::TraceWrapper(tmp, aCallback, aClosure); #define NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER \
--- a/content/base/src/nsGenConImageContent.cpp +++ b/content/base/src/nsGenConImageContent.cpp @@ -71,18 +71,22 @@ public: private: virtual ~nsGenConImageContent(); 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, imgIRequest* aImageRequest) { NS_PRECONDITION(aImageRequest, "Must have request!"); nsGenConImageContent *it = new nsGenConImageContent(aNodeInfo); if (!it)
--- a/content/base/src/nsImageLoadingContent.cpp +++ b/content/base/src/nsImageLoadingContent.cpp @@ -182,33 +182,16 @@ nsImageLoadingContent::OnStartRequest(im return NS_OK; } NS_IMETHODIMP 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; } NS_IMETHODIMP nsImageLoadingContent::OnStartContainer(imgIRequest* aRequest, imgIContainer* aContainer) { @@ -244,39 +227,26 @@ nsImageLoadingContent::OnDataAvailable(i } NS_IMETHODIMP nsImageLoadingContent::OnStopFrame(imgIRequest* aRequest, PRUint32 aFrame) { 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; } NS_IMETHODIMP nsImageLoadingContent::OnStopContainer(imgIRequest* aRequest, imgIContainer* aContainer) { 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; } // Warning - This isn't actually fired when decode is complete. Rather, it's // fired when load is complete. See bug 505385, and in the mean time use // OnStopContainer. NS_IMETHODIMP @@ -344,17 +314,17 @@ nsImageLoadingContent::OnStopDecode(imgI // Fire the appropriate DOM event. if (NS_SUCCEEDED(aStatus)) { FireEvent(NS_LITERAL_STRING("load")); } else { 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; } NS_IMETHODIMP nsImageLoadingContent::OnStopRequest(imgIRequest* aRequest, bool aLastPart) { @@ -632,16 +602,46 @@ NS_IMETHODIMP nsImageLoadingContent::For GetCurrentURI(getter_AddRefs(currentURI)); if (!currentURI) { return NS_ERROR_NOT_AVAILABLE; } return LoadImage(currentURI, true, true, nsnull, nsIRequest::VALIDATE_ALWAYS); } +NS_IMETHODIMP +nsImageLoadingContent::BlockOnload(imgIRequest* aRequest) +{ + if (aRequest != mCurrentRequest) { + return NS_OK; + } + + nsIDocument* doc = GetOurDocument(); + if (doc) { + doc->BlockOnload(); + } + + return NS_OK; +} + +NS_IMETHODIMP +nsImageLoadingContent::UnblockOnload(imgIRequest* aRequest) +{ + if (aRequest != mCurrentRequest) { + return NS_OK; + } + + nsIDocument* doc = GetOurDocument(); + if (doc) { + doc->UnblockOnload(false); + } + + return NS_OK; +} + /* * Non-interface methods */ void nsImageLoadingContent::NotifyOwnerDocumentChanged(nsIDocument *aOldDoc) { // If we had a document before, unregister ourselves with it. @@ -741,26 +741,29 @@ nsImageLoadingContent::LoadImage(nsIURI* // From this point on, our image state could change. Watch it. AutoStateChanger changer(this, aNotify); // Sanity check. // // 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?"); #endif // 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); return NS_OK; } nsLoadFlags loadFlags = aLoadFlags; PRInt32 corsmode = GetCORSMode(); @@ -855,17 +858,17 @@ nsImageLoadingContent::UpdateImageState( // changer is destroyed. Need this to work around the fact that some libpr0n // stuff is actually sync and hence we can get OnStopDecode called while // we're still under LoadImage, and OnStopDecode doesn't know anything about // aNotify. // XXX - This machinery should be removed after bug 521604. return; } - nsCOMPtr<nsIContent> thisContent = do_QueryInterface(this); + nsCOMPtr<nsIContent> thisContent = do_QueryInterface(static_cast<nsIImageLoadingContent*>(this)); if (!thisContent) { return; } mLoading = mBroken = mUserDisabled = mSuppressed = false; // If we were blocked by server-based content policy, we claim to be // suppressed. If we were blocked by type-based content policy, we claim to @@ -919,26 +922,26 @@ nsImageLoadingContent::UseAsPrimaryReque return rv; return NS_OK; } nsIDocument* nsImageLoadingContent::GetOurDocument() { - nsCOMPtr<nsIContent> thisContent = do_QueryInterface(this); + nsCOMPtr<nsIContent> thisContent = do_QueryInterface(static_cast<nsIImageLoadingContent*>(this)); NS_ENSURE_TRUE(thisContent, nsnull); return thisContent->OwnerDoc(); } nsIFrame* nsImageLoadingContent::GetOurPrimaryFrame() { - nsCOMPtr<nsIContent> thisContent = do_QueryInterface(this); + nsCOMPtr<nsIContent> thisContent = do_QueryInterface(static_cast<nsIImageLoadingContent*>(this)); return thisContent->GetPrimaryFrame(); } nsPresContext* nsImageLoadingContent::GetFramePresContext() { nsIFrame* frame = GetOurPrimaryFrame(); if (!frame) { return nsnull; @@ -951,17 +954,17 @@ nsresult nsImageLoadingContent::StringToURI(const nsAString& aSpec, nsIDocument* aDocument, nsIURI** aURI) { NS_PRECONDITION(aDocument, "Must have a document"); 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(); // (2) Get the charset const nsAFlatCString &charset = aDocument->GetDocumentCharacterSet(); // (3) Construct the silly thing return NS_NewURI(aURI, @@ -973,17 +976,17 @@ nsImageLoadingContent::StringToURI(const nsresult nsImageLoadingContent::FireEvent(const nsAString& aEventType) { // We have to fire the event asynchronously so that we won't go into infinite // 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); event->PostDOMEvent(); return NS_OK; } @@ -1081,20 +1084,16 @@ nsImageLoadingContent::ClearCurrentReque nsLayoutUtils::DeregisterImageRequest(GetFramePresContext(), mCurrentRequest, &mCurrentRequestRegistered); // Clean up the request. UntrackImage(mCurrentRequest); mCurrentRequest->CancelAndForgetObserver(aReason); mCurrentRequest = nsnull; mCurrentRequestNeedsResetAnimation = false; - - // We only block onload during the decoding of "current" images. This one is - // going away, so we should unblock unconditionally here. - SetBlockingOnload(false); } void nsImageLoadingContent::ClearPendingRequest(nsresult aReason) { if (!mPendingRequest) return; @@ -1135,38 +1134,16 @@ nsImageLoadingContent::HaveSize(imgIRequ return false; // Query the image PRUint32 status; nsresult rv = aImage->GetImageStatus(&status); 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 = GetOurDocument(); - - if (doc) { - // Take the appropriate action - if (aBlocking) - doc->BlockOnload(); - else - doc->UnblockOnload(false); - - // Update our state - mBlockingOnload = aBlocking; - } -} - nsresult nsImageLoadingContent::TrackImage(imgIRequest* aImage) { if (!aImage) return NS_OK; nsIDocument* doc = GetOurDocument(); if (doc)
--- a/content/base/src/nsImageLoadingContent.h +++ b/content/base/src/nsImageLoadingContent.h @@ -42,38 +42,41 @@ * loading functionality (eg <img>, <object>, etc). */ #ifndef nsImageLoadingContent_h__ #define nsImageLoadingContent_h__ #include "imgIContainerObserver.h" #include "imgIDecoderObserver.h" +#include "imgIOnloadBlocker.h" #include "mozilla/CORSMode.h" #include "nsCOMPtr.h" #include "nsContentUtils.h" // NS_CONTENT_DELETE_LIST_MEMBER #include "nsEventStates.h" #include "nsIImageLoadingContent.h" #include "nsIRequest.h" class nsIURI; class nsIDocument; class imgILoader; class nsIIOService; -class nsImageLoadingContent : public nsIImageLoadingContent +class nsImageLoadingContent : public nsIImageLoadingContent, + public imgIOnloadBlocker { /* METHODS */ public: nsImageLoadingContent(); virtual ~nsImageLoadingContent(); NS_DECL_IMGICONTAINEROBSERVER NS_DECL_IMGIDECODEROBSERVER NS_DECL_NSIIMAGELOADINGCONTENT + NS_DECL_IMGIONLOADBLOCKER protected: /** * LoadImage is called by subclasses when the appropriate * attributes (eg 'src' for <img> tags) change. The string passed * in is the new uri string; this consolidates the code for getting * the charset, constructing URI objects, and any other incidentals * into this superclass.
--- a/content/html/content/src/nsHTMLImageElement.cpp +++ b/content/html/content/src/nsHTMLImageElement.cpp @@ -214,22 +214,23 @@ nsHTMLImageElement::~nsHTMLImageElement( NS_IMPL_ADDREF_INHERITED(nsHTMLImageElement, nsGenericElement) NS_IMPL_RELEASE_INHERITED(nsHTMLImageElement, nsGenericElement) 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) NS_IMPL_ELEMENT_CLONE(nsHTMLImageElement)
--- a/content/html/content/src/nsHTMLInputElement.cpp +++ b/content/html/content/src/nsHTMLInputElement.cpp @@ -650,23 +650,24 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_END NS_IMPL_ADDREF_INHERITED(nsHTMLInputElement, nsGenericElement) NS_IMPL_RELEASE_INHERITED(nsHTMLInputElement, nsGenericElement) 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, nsGenericHTMLFormElement) NS_HTML_CONTENT_INTERFACE_TABLE_TAIL_CLASSINFO(HTMLInputElement) // nsIConstraintValidation NS_IMPL_NSICONSTRAINTVALIDATION_EXCEPT_SETCUSTOMVALIDITY(nsHTMLInputElement)
--- a/content/html/content/src/nsHTMLObjectElement.cpp +++ b/content/html/content/src/nsHTMLObjectElement.cpp @@ -228,16 +228,17 @@ NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION NS_HTML_CONTENT_INTERFACE_TABLE_BEGIN(nsHTMLObjectElement) NS_INTERFACE_TABLE_ENTRY(nsHTMLObjectElement, nsIDOMHTMLObjectElement) NS_INTERFACE_TABLE_ENTRY(nsHTMLObjectElement, imgIDecoderObserver) NS_INTERFACE_TABLE_ENTRY(nsHTMLObjectElement, nsIRequestObserver) NS_INTERFACE_TABLE_ENTRY(nsHTMLObjectElement, nsIStreamListener) 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) NS_INTERFACE_TABLE_ENTRY(nsHTMLObjectElement, nsIConstraintValidation) NS_INTERFACE_TABLE_ENTRY(nsHTMLObjectElement, nsIDOMGetSVGDocument) NS_OFFSET_AND_INTERFACE_TABLE_END NS_HTML_CONTENT_INTERFACE_TABLE_TO_MAP_SEGUE(nsHTMLObjectElement, nsGenericHTMLFormElement)
--- a/content/html/content/src/nsHTMLSharedObjectElement.cpp +++ b/content/html/content/src/nsHTMLSharedObjectElement.cpp @@ -253,16 +253,17 @@ NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION nsIDOMHTMLAppletElement) NS_INTERFACE_TABLE_ENTRY(nsHTMLSharedObjectElement, nsIRequestObserver) NS_INTERFACE_TABLE_ENTRY(nsHTMLSharedObjectElement, nsIStreamListener) NS_INTERFACE_TABLE_ENTRY(nsHTMLSharedObjectElement, nsIFrameLoaderOwner) NS_INTERFACE_TABLE_ENTRY(nsHTMLSharedObjectElement, imgIContainerObserver) 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 NS_HTML_CONTENT_INTERFACE_TABLE_TO_MAP_SEGUE_AMBIGUOUS(nsHTMLSharedObjectElement, nsGenericHTMLElement, nsIDOMHTMLAppletElement) NS_INTERFACE_MAP_ENTRY_IF_TAG(nsIDOMHTMLAppletElement, applet) NS_INTERFACE_MAP_ENTRY_IF_TAG(nsIDOMHTMLEmbedElement, embed)
--- a/content/svg/content/src/nsSVGFilters.cpp +++ b/content/svg/content/src/nsSVGFilters.cpp @@ -5458,21 +5458,22 @@ NS_IMPL_NS_NEW_SVG_ELEMENT(FEImage) // nsISupports methods NS_IMPL_ADDREF_INHERITED(nsSVGFEImageElement,nsSVGFEImageElementBase) 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) //---------------------------------------------------------------------- // Implementation nsSVGFEImageElement::nsSVGFEImageElement(already_AddRefed<nsINodeInfo> aNodeInfo) : nsSVGFEImageElementBase(aNodeInfo)
--- a/content/svg/content/src/nsSVGImageElement.cpp +++ b/content/svg/content/src/nsSVGImageElement.cpp @@ -67,21 +67,21 @@ NS_IMPL_NS_NEW_SVG_ELEMENT(Image) // nsISupports methods NS_IMPL_ADDREF_INHERITED(nsSVGImageElement,nsSVGImageElementBase) 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) //---------------------------------------------------------------------- // Implementation nsSVGImageElement::nsSVGImageElement(already_AddRefed<nsINodeInfo> aNodeInfo) : nsSVGImageElementBase(aNodeInfo)
--- a/image/public/Makefile.in +++ b/image/public/Makefile.in @@ -50,14 +50,15 @@ EXPORTS = ImageErrors.h ImageLogging.h XPIDLSRCS = \ imgICache.idl \ imgIContainer.idl \ imgIContainerDebug.idl \ imgIContainerObserver.idl \ imgIDecoderObserver.idl \ imgIEncoder.idl \ imgILoader.idl \ + imgIOnloadBlocker.idl \ imgIRequest.idl \ imgITools.idl \ $(NULL) include $(topsrcdir)/config/rules.mk
new file mode 100644 --- /dev/null +++ b/image/public/imgIOnloadBlocker.idl @@ -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); +};
--- a/image/src/imgRequest.cpp +++ b/image/src/imgRequest.cpp @@ -112,17 +112,17 @@ NS_IMPL_ISUPPORTS8(imgRequest, nsIChannelEventSink, nsIInterfaceRequestor, nsIAsyncVerifyRedirectCallback) imgRequest::imgRequest() : mValidator(nsnull), 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)) { InitPrefCaches(); } } imgRequest::~imgRequest() @@ -307,16 +307,28 @@ void imgRequest::CancelAndAbort(nsresult void imgRequest::Cancel(nsresult aStatus) { /* The Cancel() method here should only be called by this class. */ 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(); if (mRequest && statusTracker.IsLoading()) mRequest->Cancel(aStatus); } @@ -540,21 +552,34 @@ NS_IMETHODIMP imgRequest::FrameChanged(i /* void onStartDecode (in imgIRequest request); */ NS_IMETHODIMP imgRequest::OnStartDecode(imgIRequest *request) { LOG_SCOPE(gImgLog, "imgRequest::OnStartDecode"); NS_ABORT_IF_FALSE(mImage, "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 indicates the beginning of a new decode. The cache entry's size therefore needs to be reset to 0 here. If we do not do this, the code in imgRequest::OnStopFrame will continue to increase the data size cumulatively. */ if (mCacheEntry) @@ -631,39 +656,69 @@ NS_IMETHODIMP imgRequest::OnDataAvailabl /* void onStopFrame (in imgIRequest request, in unsigned long frame); */ NS_IMETHODIMP imgRequest::OnStopFrame(imgIRequest *request, PRUint32 frame) { LOG_SCOPE(gImgLog, "imgRequest::OnStopFrame"); 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; } /* void onStopContainer (in imgIRequest request, in imgIContainer image); */ NS_IMETHODIMP imgRequest::OnStopContainer(imgIRequest *request, imgIContainer *image) { LOG_SCOPE(gImgLog, "imgRequest::OnStopContainer"); 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; } /* void onStopDecode (in imgIRequest request, in nsresult status, in wstring statusArg); */ NS_IMETHODIMP imgRequest::OnStopDecode(imgIRequest *aRequest, nsresult aStatus,
--- a/image/src/imgRequest.h +++ b/image/src/imgRequest.h @@ -257,11 +257,12 @@ private: // Sometimes consumers want to do things before the image is ready. Let them, // and apply the action when the image becomes available. bool mDecodeRequested : 1; bool mIsMultiPartChannel : 1; bool mGotData : 1; bool mIsInCache : 1; + bool mBlockingOnload : 1; }; #endif
--- a/image/src/imgRequestProxy.cpp +++ b/image/src/imgRequestProxy.cpp @@ -33,16 +33,17 @@ * 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 "imgRequestProxy.h" +#include "imgIOnloadBlocker.h" #include "nsIInputStream.h" #include "nsIComponentManager.h" #include "nsIServiceManager.h" #include "nsIMultiPartChannel.h" #include "nsString.h" #include "nsXPIDLString.h" @@ -784,16 +785,44 @@ void imgRequestProxy::OnStopRequest(bool // everything. Note that this can cancel us and other fun things // like that. Don't add anything in this method after this point. imgIDecoderObserver* obs = mListener; mListenerIsStrongRef = false; NS_RELEASE(obs); } } +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 if (mListener) ClearAnimationConsumers(); if (mListenerIsStrongRef) { // Releasing could do weird reentery stuff, so just play it super-safe
--- a/image/src/imgRequestProxy.h +++ b/image/src/imgRequestProxy.h @@ -181,16 +181,20 @@ protected: /* non-virtual imgIContainerObserver methods */ void FrameChanged(imgIContainer *aContainer, const nsIntRect *aDirtyRect); /* non-virtual sort-of-nsIRequestObserver methods */ void OnStartRequest(); void OnStopRequest(bool aLastPart); + /* non-virtual imgIOnloadBlocker methods */ + void BlockOnload(); + void UnblockOnload(); + /* Finish up canceling ourselves */ void DoCancel(nsresult status); /* Do the proper refcount management to null out mListener */ void NullOutListener(); void DoRemoveFromLoadGroup() { RemoveFromLoadGroup(true);
--- a/image/src/imgStatusTracker.cpp +++ b/image/src/imgStatusTracker.cpp @@ -228,16 +228,20 @@ imgStatusTracker::SyncNotify(imgRequestP // OnStartContainer if (mState & stateHasSize) proxy->OnStartContainer(mImage); // OnStartDecode if (mState & stateDecodeStarted) proxy->OnStartDecode(); + // BlockOnload + if (mState & stateBlockingOnload) + proxy->BlockOnload(); + if (mImage) { PRInt16 imageType = mImage->GetType(); // Send frame messages (OnStartFrame, OnDataAvailable, OnStopFrame) if (imageType == imgIContainer::TYPE_VECTOR || static_cast<RasterImage*>(mImage)->GetNumFrames() > 0) { PRUint32 frame = (imageType == imgIContainer::TYPE_VECTOR) ? 0 : static_cast<RasterImage*>(mImage)->GetCurrentFrameIndex(); @@ -511,16 +515,17 @@ imgStatusTracker::RecordStartRequest() // load/decode mImageStatus &= ~imgIRequest::STATUS_LOAD_PARTIAL; mImageStatus &= ~imgIRequest::STATUS_LOAD_COMPLETE; mImageStatus &= ~imgIRequest::STATUS_FRAME_COMPLETE; mState &= ~stateRequestStarted; mState &= ~stateDecodeStarted; mState &= ~stateDecodeStopped; mState &= ~stateRequestStopped; + mState &= ~stateBlockingOnload; mState |= stateRequestStarted; } void imgStatusTracker::SendStartRequest(imgRequestProxy* aProxy) { if (!aProxy->NotificationsDeferred()) @@ -543,8 +548,38 @@ imgStatusTracker::SendStopRequest(imgReq { // See bug 505385 and imgRequest::OnStopDecode for more information on why // OnStopDecode is called with OnStopRequest. if (!aProxy->NotificationsDeferred()) { aProxy->OnStopDecode(GetResultFromImageStatus(mImageStatus), nsnull); 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(); + } +}
--- a/image/src/imgStatusTracker.h +++ b/image/src/imgStatusTracker.h @@ -59,17 +59,18 @@ class Image; #include "nscore.h" enum { stateRequestStarted = PR_BIT(0), stateHasSize = PR_BIT(1), stateDecodeStarted = PR_BIT(2), stateDecodeStopped = PR_BIT(3), stateFrameStopped = PR_BIT(4), - stateRequestStopped = PR_BIT(5) + stateRequestStopped = PR_BIT(5), + stateBlockingOnload = PR_BIT(6) }; /* * The image status tracker is a class that encapsulates all the loading and * decoding status about an Image, and makes it possible to send notifications * to imgRequestProxys, both synchronously (i.e., the status now) and * asynchronously (the status later). * @@ -169,16 +170,25 @@ public: const nsIntRect* aDirtyRect); /* non-virtual sort-of-nsIRequestObserver methods */ void RecordStartRequest(); void SendStartRequest(imgRequestProxy* aProxy); 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; nsCOMPtr<nsIRunnable> mRequestRunnable; // A weak pointer to the Image, because it owns us, and we // can't create a cycle.
--- a/image/test/unit/image_load_helpers.js +++ b/image/test/unit/image_load_helpers.js @@ -70,17 +70,17 @@ function ImageListener(start_callback, s do_check_false(this.synchronous); // onStopDecode must always be called before, and with, onStopRequest. See // imgRequest::OnStopDecode for more information. do_check_true(!!(this.state & STOP_DECODE)); // 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; if (this.stop_callback) this.stop_callback(this, aRequest); } // Initialize the synchronous flag to true to start. This must be set to