diff --git a/layout/generic/nsBulletFrame.cpp b/layout/generic/nsBulletFrame.cpp index 8d8c95846436..0ab19749e457 100644 --- a/layout/generic/nsBulletFrame.cpp +++ b/layout/generic/nsBulletFrame.cpp @@ -12,6 +12,7 @@ #include "mozilla/gfx/2D.h" #include "mozilla/gfx/PathHelpers.h" #include "mozilla/MathAlgorithms.h" +#include "mozilla/Move.h" #include "nsCOMPtr.h" #include "nsFontMetrics.h" #include "nsGkAtoms.h" @@ -51,20 +52,14 @@ NS_QUERYFRAME_TAIL_INHERITING(nsFrame) nsBulletFrame::~nsBulletFrame() { + NS_ASSERTION(!mBlockingOnload, "Still blocking onload in destructor?"); } void nsBulletFrame::DestroyFrom(nsIFrame* aDestructRoot) { - // Stop image loading first - if (mImageRequest) { - // Deregister our image request from the refresh driver - nsLayoutUtils::DeregisterImageRequest(PresContext(), - mImageRequest, - &mRequestRegistered); - mImageRequest->CancelAndForgetObserver(NS_ERROR_FAILURE); - mImageRequest = nullptr; - } + // Stop image loading first. + DeregisterAndCancelImageRequest(); if (mListener) { mListener->SetFrame(nullptr); @@ -132,35 +127,21 @@ nsBulletFrame::DidSetStyleContext(nsStyleContext* aOldStyleContext) } if (needNewRequest) { - nsRefPtr oldRequest = mImageRequest; - newRequest->Clone(mListener, getter_AddRefs(mImageRequest)); + nsRefPtr newRequestClone; + newRequest->Clone(mListener, getter_AddRefs(newRequestClone)); // Deregister the old request. We wait until after Clone is done in case // the old request and the new request are the same underlying image // accessed via different URLs. - if (oldRequest) { - nsLayoutUtils::DeregisterImageRequest(PresContext(), oldRequest, - &mRequestRegistered); - oldRequest->CancelAndForgetObserver(NS_ERROR_FAILURE); - oldRequest = nullptr; - } + DeregisterAndCancelImageRequest(); // Register the new request. - if (mImageRequest) { - nsLayoutUtils::RegisterImageRequestIfAnimated(PresContext(), - mImageRequest, - &mRequestRegistered); - } + mImageRequest = Move(newRequestClone); + RegisterImageRequest(/* aKnownToBeAnimated = */ false); } } else { - // No image request on the new style context - if (mImageRequest) { - nsLayoutUtils::DeregisterImageRequest(PresContext(), mImageRequest, - &mRequestRegistered); - - mImageRequest->CancelAndForgetObserver(NS_ERROR_FAILURE); - mImageRequest = nullptr; - } + // No image request on the new style context. + DeregisterAndCancelImageRequest(); } #ifdef ACCESSIBILITY @@ -692,14 +673,67 @@ nsBulletFrame::Notify(imgIRequest *aRequest, int32_t aType, const nsIntRect* aDa // Register the image request with the refresh driver now that we know it's // animated. if (aRequest == mImageRequest) { - nsLayoutUtils::RegisterImageRequest(PresContext(), mImageRequest, - &mRequestRegistered); + RegisterImageRequest(/* aKnownToBeAnimated = */ true); } } + if (aType == imgINotificationObserver::LOAD_COMPLETE) { + // Unconditionally start decoding for now. + // XXX(seth): We eventually want to decide whether to do this based on + // visibility. We should get that for free from bug 1091236. + if (aRequest == mImageRequest) { + mImageRequest->RequestDecode(); + } + InvalidateFrame(); + } + return NS_OK; } +NS_IMETHODIMP +nsBulletFrame::BlockOnload(imgIRequest* aRequest) +{ + if (aRequest != mImageRequest) { + return NS_OK; + } + + NS_ASSERTION(!mBlockingOnload, "Double BlockOnload for an nsBulletFrame?"); + + nsIDocument* doc = GetOurCurrentDoc(); + if (doc) { + mBlockingOnload = true; + doc->BlockOnload(); + } + + return NS_OK; +} + +NS_IMETHODIMP +nsBulletFrame::UnblockOnload(imgIRequest* aRequest) +{ + if (aRequest != mImageRequest) { + return NS_OK; + } + + NS_ASSERTION(!mBlockingOnload, "Double UnblockOnload for an nsBulletFrame?"); + + nsIDocument* doc = GetOurCurrentDoc(); + if (doc) { + doc->UnblockOnload(false); + } + mBlockingOnload = false; + + return NS_OK; +} + +nsIDocument* +nsBulletFrame::GetOurCurrentDoc() const +{ + nsIContent* parentContent = GetParent()->GetContent(); + return parentContent ? parentContent->GetComposedDoc() + : nullptr; +} + nsresult nsBulletFrame::OnStartContainer(imgIRequest *aRequest, imgIContainer *aImage) { @@ -873,7 +907,57 @@ nsBulletFrame::GetSpokenText(nsAString& aText) } } +void +nsBulletFrame::RegisterImageRequest(bool aKnownToBeAnimated) +{ + if (mImageRequest) { + // mRequestRegistered is a bitfield; unpack it temporarily so we can take + // the address. + bool isRequestRegistered = mRequestRegistered; + if (aKnownToBeAnimated) { + nsLayoutUtils::RegisterImageRequest(PresContext(), mImageRequest, + &isRequestRegistered); + } else { + nsLayoutUtils::RegisterImageRequestIfAnimated(PresContext(), + mImageRequest, + &isRequestRegistered); + } + + isRequestRegistered = mRequestRegistered; + } +} + + +void +nsBulletFrame::DeregisterAndCancelImageRequest() +{ + if (mImageRequest) { + // mRequestRegistered is a bitfield; unpack it temporarily so we can take + // the address. + bool isRequestRegistered = mRequestRegistered; + + // Deregister our image request from the refresh driver. + nsLayoutUtils::DeregisterImageRequest(PresContext(), + mImageRequest, + &isRequestRegistered); + + isRequestRegistered = mRequestRegistered; + + // Unblock onload if we blocked it. + if (mBlockingOnload) { + nsIDocument* doc = GetOurCurrentDoc(); + if (doc) { + doc->UnblockOnload(false); + } + mBlockingOnload = false; + } + + // Cancel the image request and forget about it. + mImageRequest->CancelAndForgetObserver(NS_ERROR_FAILURE); + mImageRequest = nullptr; + } +} @@ -894,7 +978,26 @@ nsBulletListener::~nsBulletListener() NS_IMETHODIMP nsBulletListener::Notify(imgIRequest *aRequest, int32_t aType, const nsIntRect* aData) { - if (!mFrame) + if (!mFrame) { return NS_ERROR_FAILURE; + } return mFrame->Notify(aRequest, aType, aData); } + +NS_IMETHODIMP +nsBulletListener::BlockOnload(imgIRequest* aRequest) +{ + if (!mFrame) { + return NS_ERROR_FAILURE; + } + return mFrame->BlockOnload(aRequest); +} + +NS_IMETHODIMP +nsBulletListener::UnblockOnload(imgIRequest* aRequest) +{ + if (!mFrame) { + return NS_ERROR_FAILURE; + } + return mFrame->UnblockOnload(aRequest); +} diff --git a/layout/generic/nsBulletFrame.h b/layout/generic/nsBulletFrame.h index 91ac2dea88cc..8b9cc3901d73 100644 --- a/layout/generic/nsBulletFrame.h +++ b/layout/generic/nsBulletFrame.h @@ -12,19 +12,22 @@ #include "nsFrame.h" #include "imgINotificationObserver.h" +#include "imgIOnloadBlocker.h" class imgIContainer; class imgRequestProxy; class nsBulletFrame; -class nsBulletListener MOZ_FINAL : public imgINotificationObserver +class nsBulletListener MOZ_FINAL : public imgINotificationObserver, + public imgIOnloadBlocker { public: nsBulletListener(); NS_DECL_ISUPPORTS NS_DECL_IMGINOTIFICATIONOBSERVER + NS_DECL_IMGIONLOADBLOCKER void SetFrame(nsBulletFrame *frame) { mFrame = frame; } @@ -50,11 +53,14 @@ public: : nsFrame(aContext) , mPadding(GetWritingMode()) , mIntrinsicSize(GetWritingMode()) - { - } + , mRequestRegistered(false) + , mBlockingOnload(false) + { } virtual ~nsBulletFrame(); - NS_IMETHOD Notify(imgIRequest *aRequest, int32_t aType, const nsIntRect* aData); + NS_IMETHOD Notify(imgIRequest* aRequest, int32_t aType, const nsIntRect* aData); + NS_IMETHOD BlockOnload(imgIRequest* aRequest); + NS_IMETHOD UnblockOnload(imgIRequest* aRequest); // nsIFrame virtual void DestroyFrom(nsIFrame* aDestructRoot) MOZ_OVERRIDE; @@ -111,6 +117,7 @@ protected: float aFontSizeInflation); void GetLoadGroup(nsPresContext *aPresContext, nsILoadGroup **aLoadGroup); + nsIDocument* GetOurCurrentDoc() const; mozilla::LogicalMargin mPadding; nsRefPtr mImageRequest; @@ -120,10 +127,15 @@ protected: int32_t mOrdinal; private: + void RegisterImageRequest(bool aKnownToBeAnimated); + void DeregisterAndCancelImageRequest(); // This is a boolean flag indicating whether or not the current image request // has been registered with the refresh driver. - bool mRequestRegistered; + bool mRequestRegistered : 1; + + // Whether we're currently blocking onload. + bool mBlockingOnload : 1; }; #endif /* nsBulletFrame_h___ */ diff --git a/layout/reftests/svg/as-image/reftest.list b/layout/reftests/svg/as-image/reftest.list index 353e3c6b0d18..80a3bd055486 100644 --- a/layout/reftests/svg/as-image/reftest.list +++ b/layout/reftests/svg/as-image/reftest.list @@ -127,7 +127,7 @@ skip-if(B2G) == img-fragment-2a.html img-fragment-2-ref.html # bug 773482 skip-if(B2G) == img-fragment-2b.html img-fragment-2-ref.html # bug 773482 skip-if(B2G) == img-fragment-2c.html img-fragment-2-ref.html # bug 773482 -skip-if(B2G) == list-simple-1.html list-simple-1-ref.html # bug 773482 +fuzzy-if(B2G,68,4) == list-simple-1.html list-simple-1-ref.html == svg-image-simple-1.svg lime100x100.svg == svg-image-simple-2.svg lime100x100.svg