Bug 1091229 - Make nsBulletFrame block onload when it loads images. r=tn

--HG--
extra : rebase_source : e6b4ed67cab9d0d674a6a5f194c14c7362723440
This commit is contained in:
Seth Fowler 2014-11-10 13:37:49 -08:00
Родитель 2d5dbdb879
Коммит 552b8dfc85
3 изменённых файлов: 154 добавлений и 39 удалений

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

@ -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<imgRequestProxy> oldRequest = mImageRequest;
newRequest->Clone(mListener, getter_AddRefs(mImageRequest));
nsRefPtr<imgRequestProxy> 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);
}

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

@ -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<imgRequestProxy> 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___ */

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

@ -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