Bug 689623. Part 8. Add an 'unlocked draw' notification for images that are drawn when not locked so we catch any images that become visible through a means other than scrolling. r=joe,mats

This commit is contained in:
Timothy Nikkel 2013-02-24 18:59:22 -06:00
parent 4c9c378b53
commit 45f8b4f1f9
12 changed files with 107 additions and 5 deletions

View File

@ -122,6 +122,11 @@ nsImageLoadingContent::Notify(imgIRequest* aRequest,
return OnImageIsAnimated(aRequest);
}
if (aType == imgINotificationObserver::UNLOCKED_DRAW) {
OnUnlockedDraw();
return NS_OK;
}
if (aType == imgINotificationObserver::LOAD_COMPLETE) {
// We should definitely have a request here
NS_ABORT_IF_FALSE(aRequest, "no request?");
@ -229,6 +234,20 @@ nsImageLoadingContent::OnStopRequest(imgIRequest* aRequest,
return NS_OK;
}
void
nsImageLoadingContent::OnUnlockedDraw()
{
nsPresContext* presContext = GetFramePresContext();
if (!presContext)
return;
nsIPresShell* presShell = presContext->PresShell();
if (!presShell)
return;
presShell->EnsureImageInVisibleList(this);
}
nsresult
nsImageLoadingContent::OnImageIsAnimated(imgIRequest *aRequest)
{

View File

@ -183,6 +183,7 @@ protected:
void UnbindFromTree(bool aDeep, bool aNullParent);
nsresult OnStopRequest(imgIRequest* aRequest, nsresult aStatus);
void OnUnlockedDraw();
nsresult OnImageIsAnimated(imgIRequest *aRequest);
private:

View File

@ -14,7 +14,7 @@ interface imgIRequest;
[ptr] native nsIntRect(nsIntRect);
[scriptable, builtinclass, uuid(90b3d21c-317d-4d96-93c0-12add64a26bf)]
[scriptable, builtinclass, uuid(ac65c702-7771-4f6d-b18b-1c7d806ce3c1)]
interface imgINotificationObserver : nsISupports
{
const long SIZE_AVAILABLE = 1;
@ -23,7 +23,8 @@ interface imgINotificationObserver : nsISupports
const long LOAD_COMPLETE = 4;
const long DECODE_COMPLETE = 5;
const long DISCARD = 6;
const long IS_ANIMATED = 7;
const long UNLOCKED_DRAW = 7;
const long IS_ANIMATED = 8;
[noscript] void notify(in imgIRequest aProxy, in long aType, [const] in nsIntRect aRect);
};

View File

@ -3107,6 +3107,15 @@ RasterImage::Draw(gfxContext *aContext,
DiscardTracker::Reset(&mDiscardTrackerNode);
}
// We would like to just check if we have a zero lock count, but we can't do
// that for animated images because in EnsureAnimExists we lock the image and
// never unlock so that animated images always have their lock count >= 1. In
// that case we use our animation consumers count as a proxy for lock count.
if (mLockCount == 0 || (mAnim && mAnimationConsumers == 0)) {
if (mStatusTracker)
mStatusTracker->GetDecoderObserver()->OnUnlockedDraw();
}
// We use !mDecoded && mHasSourceData to mean discarded.
if (!mDecoded && mHasSourceData) {
mDrawStartTime = TimeStamp::Now();

View File

@ -109,6 +109,11 @@ public:
* image will initiate a new series of progressive decode notifications.
*/
virtual void OnDiscard() = 0;
/**
* Called when we are asked to Draw an image that is not locked.
*/
virtual void OnUnlockedDraw() = 0;
};
// We must define a destructor because derived classes call our destructor from

View File

@ -767,6 +767,17 @@ void imgRequestProxy::OnDiscard()
}
}
void imgRequestProxy::OnUnlockedDraw()
{
LOG_FUNC(GetImgLog(), "imgRequestProxy::OnUnlockedDraw");
if (mListener && !mCanceled) {
// Hold a ref to the listener while we call it, just in case.
nsCOMPtr<imgINotificationObserver> kungFuDeathGrip(mListener);
mListener->Notify(this, imgINotificationObserver::UNLOCKED_DRAW, nullptr);
}
}
void imgRequestProxy::OnImageIsAnimated()
{
LOG_FUNC(GetImgLog(), "imgRequestProxy::OnImageIsAnimated");

View File

@ -143,6 +143,7 @@ protected:
void OnStopFrame ();
void OnStopDecode ();
void OnDiscard ();
void OnUnlockedDraw ();
void OnImageIsAnimated ();
/* non-virtual sort-of-nsIRequestObserver methods */

View File

@ -165,6 +165,18 @@ public:
}
}
virtual void OnUnlockedDraw()
{
NS_ABORT_IF_FALSE(mTracker->GetImage(),
"OnUnlockedDraw callback before we've created our image");
mTracker->RecordUnlockedDraw();
nsTObserverArray<imgRequestProxy*>::ForwardIterator iter(mTracker->mConsumers);
while (iter.HasMore()) {
mTracker->SendUnlockedDraw(iter.GetNext());
}
}
virtual void OnImageIsAnimated()
{
NS_ABORT_IF_FALSE(mTracker->GetImage(),
@ -568,6 +580,13 @@ imgStatusTracker::RecordDiscard()
mImageStatus &= ~statusBitsToClear;
}
void
imgStatusTracker::RecordUnlockedDraw()
{
NS_ABORT_IF_FALSE(mImage,
"RecordUnlockedDraw called before we have an Image");
}
void
imgStatusTracker::SendImageIsAnimated(imgRequestProxy* aProxy)
{
@ -593,6 +612,13 @@ imgStatusTracker::SendDiscard(imgRequestProxy* aProxy)
aProxy->OnDiscard();
}
void
imgStatusTracker::SendUnlockedDraw(imgRequestProxy* aProxy)
{
if (!aProxy->NotificationsDeferred())
aProxy->OnUnlockedDraw();
}
void
imgStatusTracker::RecordFrameChanged(const nsIntRect* aDirtyRect)
{

View File

@ -145,6 +145,8 @@ public:
void SendStopDecode(imgRequestProxy* aProxy, nsresult aStatus);
void RecordDiscard();
void SendDiscard(imgRequestProxy* aProxy);
void RecordUnlockedDraw();
void SendUnlockedDraw(imgRequestProxy* aProxy);
void RecordImageIsAnimated();
void SendImageIsAnimated(imgRequestProxy *aProxy);

View File

@ -38,6 +38,7 @@
#include "nsInterfaceHashtable.h"
#include "nsEventStates.h"
#include "nsPresArena.h"
#include "nsIImageLoadingContent.h"
class nsIContent;
class nsIDocument;
@ -120,10 +121,10 @@ typedef struct CapturingContentInfo {
nsIContent* mContent;
} CapturingContentInfo;
// 15f6c268-e40f-42a9-a7eb-e5e10a5840a1
// 835b3946-1a4f-4132-b3ce-2e2e8be377c8
#define NS_IPRESSHELL_IID \
{ 0x15f6c268, 0xe40f, 0x42a9, \
{ 0xa7, 0xeb, 0xe5, 0xe1, 0x0a, 0x58, 0x40, 0xa1 } }
{ 0x835b3946, 0x1a4f, 0x4132, \
{ 0xb3, 0xce, 0x2e, 0x2e, 0x8b, 0xe3, 0x77, 0xc8 } }
// debug VerifyReflow flags
#define VERIFY_REFLOW_ON 0x01
@ -1327,6 +1328,9 @@ public:
// with images that are in the display list aList.
virtual void RebuildImageVisibility(const nsDisplayList& aList) = 0;
// Ensures the image is in the list of visible images.
virtual void EnsureImageInVisibleList(nsIImageLoadingContent* aImage) = 0;
/**
* Refresh observer management.
*/

View File

@ -5415,6 +5415,27 @@ PresShell::ScheduleImageVisibilityUpdate()
}
}
void
PresShell::EnsureImageInVisibleList(nsIImageLoadingContent* aImage)
{
#ifdef DEBUG
// if it has a frame make sure its in this presshell
nsCOMPtr<nsIContent> content = do_QueryInterface(aImage);
if (content) {
PresShell* shell = static_cast<PresShell*>(content->OwnerDoc()->GetShell());
MOZ_ASSERT(!shell || shell == this, "wrong shell");
}
#endif
// This check could be slow.
if (mVisibleImages.Contains(aImage)) {
return;
}
mVisibleImages.AppendElement(aImage);
aImage->IncrementVisibleCount();
}
class nsAutoNotifyDidPaint
{
public:

View File

@ -339,6 +339,8 @@ public:
virtual void RebuildImageVisibility(const nsDisplayList& aList);
virtual void EnsureImageInVisibleList(nsIImageLoadingContent* aImage);
protected:
virtual ~PresShell();