Bug 666446, Part 4/18 - Implement refresh driver based animations in nsImageLoadingContent to improve efficiency of animated GIF images. [r=roc][sr=mats]

This commit is contained in:
Scott Johnson 2011-10-03 13:39:05 -07:00
Родитель 6b33216408
Коммит 48e6539470
8 изменённых файлов: 204 добавлений и 2 удалений

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

@ -42,6 +42,7 @@ interface nsIChannel;
interface nsIStreamListener;
interface nsIURI;
interface nsIDocument;
interface nsIFrame;
/**
* This interface represents a content node that loads images. The interface
@ -65,7 +66,7 @@ interface nsIDocument;
* sufficient, when combined with the imageBlockingStatus information.)
*/
[scriptable, uuid(95c74255-df9a-4060-b5a0-0d111fcafe08)]
[scriptable, uuid(f7debb84-2854-4731-a57b-1bd752ad71f8)]
interface nsIImageLoadingContent : imgIDecoderObserver
{
/**
@ -128,6 +129,18 @@ interface nsIImageLoadingContent : imgIDecoderObserver
*/
imgIRequest getRequest(in long aRequestType);
/**
* Used to notify the image loading content node that a frame has been
* created.
*/
void frameCreated(in nsIFrame aFrame);
/**
* Used to notify the image loading content node that a frame has been
* destroyed.
*/
void frameDestroyed(in nsIFrame aFrame);
/**
* Used to find out what type of request one is dealing with (eg
* which request got passed through to the imgIDecoderObserver

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

@ -3220,6 +3220,7 @@ nsDocument::DeleteShell()
if (IsEventHandlingEnabled()) {
RevokeAnimationFrameNotifications();
}
mPresShell = nsnull;
}

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

@ -72,6 +72,7 @@
#include "nsIDOMNode.h"
#include "nsContentUtils.h"
#include "nsLayoutUtils.h"
#include "nsIContentPolicy.h"
#include "nsContentPolicyUtils.h"
#include "nsEventDispatcher.h"
@ -116,7 +117,9 @@ nsImageLoadingContent::nsImageLoadingContent()
mNewRequestsWillNeedAnimationReset(PR_FALSE),
mPendingRequestNeedsResetAnimation(PR_FALSE),
mCurrentRequestNeedsResetAnimation(PR_FALSE),
mStateChangerDepth(0)
mStateChangerDepth(0),
mCurrentRequestRegistered(false),
mPendingRequestRegistered(false)
{
if (!nsContentUtils::GetImgLoader()) {
mLoadingEnabled = PR_FALSE;
@ -330,6 +333,13 @@ nsImageLoadingContent::OnStopDecode(imgIRequest* aRequest,
nsIPresShell* shell = doc ? doc->GetShell() : nsnull;
if (shell) {
// Make sure that our image requests are deregistered from the refresh
// driver if they aren't animated. Note that this must be mCurrentRequest,
// or we would have aborted up above.
nsLayoutUtils::DeregisterImageRequestIfNotAnimated(GetFramePresContext(),
mCurrentRequest,
&mCurrentRequestRegistered);
// We need to figure out whether to kick off decoding
bool doRequestDecode = false;
@ -502,6 +512,48 @@ nsImageLoadingContent::GetRequest(PRInt32 aRequestType,
return NS_OK;
}
NS_IMETHODIMP
nsImageLoadingContent::FrameCreated(nsIFrame* aFrame)
{
NS_ASSERTION(aFrame, "aFrame is null");
// We need to make sure that our image request is registered.
nsPresContext* presContext = aFrame->PresContext();
if (mCurrentRequest) {
nsLayoutUtils::RegisterImageRequest(presContext, mCurrentRequest,
&mCurrentRequestRegistered);
nsLayoutUtils::DeregisterImageRequestIfNotAnimated(presContext,
mCurrentRequest,
&mCurrentRequestRegistered);
} else if (mPendingRequest) {
// We don't need to do the same check for animation, because this will be
// done when decoding is finished.
nsLayoutUtils::RegisterImageRequest(presContext, mPendingRequest,
&mPendingRequestRegistered);
}
return NS_OK;
}
NS_IMETHODIMP
nsImageLoadingContent::FrameDestroyed(nsIFrame* aFrame)
{
NS_ASSERTION(aFrame, "aFrame is null");
// We need to make sure that our image request is deregistered.
if (mCurrentRequest) {
nsLayoutUtils::DeregisterImageRequest(GetFramePresContext(),
mCurrentRequest,
&mCurrentRequestRegistered);
} else if (mPendingRequest) {
nsLayoutUtils::DeregisterImageRequest(GetFramePresContext(),
mPendingRequest,
&mPendingRequestRegistered);
}
return NS_OK;
}
NS_IMETHODIMP
nsImageLoadingContent::GetRequestType(imgIRequest* aRequest,
@ -868,6 +920,23 @@ nsImageLoadingContent::GetOurDocument()
return thisContent->GetOwnerDoc();
}
nsIFrame*
nsImageLoadingContent::GetOurPrimaryFrame()
{
nsCOMPtr<nsIContent> thisContent = do_QueryInterface(this);
return thisContent->GetPrimaryFrame();
}
nsPresContext* nsImageLoadingContent::GetFramePresContext()
{
nsIFrame* frame = GetOurPrimaryFrame();
if (!frame) {
return nsnull;
}
return frame->PresContext();
}
nsresult
nsImageLoadingContent::StringToURI(const nsAString& aSpec,
nsIDocument* aDocument,
@ -987,6 +1056,11 @@ nsImageLoadingContent::ClearCurrentRequest(nsresult aReason)
NS_ABORT_IF_FALSE(!mCurrentURI,
"Shouldn't have both mCurrentRequest and mCurrentURI!");
// Deregister this image from the refresh driver so it no longer receives
// notifications.
nsLayoutUtils::DeregisterImageRequest(GetFramePresContext(), mCurrentRequest,
&mCurrentRequestRegistered);
// Clean up the request.
UntrackImage(mCurrentRequest);
mCurrentRequest->CancelAndForgetObserver(aReason);
@ -1010,12 +1084,29 @@ nsImageLoadingContent::ClearPendingRequest(nsresult aReason)
nsCxPusher pusher;
pusher.PushNull();
// Deregister this image from the refresh driver so it no longer receives
// notifications.
nsLayoutUtils::DeregisterImageRequest(GetFramePresContext(), mPendingRequest,
&mPendingRequestRegistered);
UntrackImage(mPendingRequest);
mPendingRequest->CancelAndForgetObserver(aReason);
mPendingRequest = nsnull;
mPendingRequestNeedsResetAnimation = PR_FALSE;
}
bool*
nsImageLoadingContent::GetRegisteredFlagForRequest(imgIRequest* aRequest)
{
if (aRequest == mCurrentRequest) {
return &mCurrentRequestRegistered;
} else if (aRequest == mPendingRequest) {
return &mPendingRequestRegistered;
} else {
return nsnull;
}
}
bool
nsImageLoadingContent::HaveSize(imgIRequest *aImage)
{

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

@ -146,6 +146,24 @@ protected:
*/
nsIDocument* GetOurDocument();
/**
* Helper function to get the frame associated with this content. Not named
* GetPrimaryFrame to prevent ambiguous method names in subclasses.
*
* @return The frame which we belong to, or nsnull if it doesn't exist.
*/
nsIFrame* GetOurPrimaryFrame();
/**
* Helper function to get the PresContext associated with this content's
* frame. Not named GetPresContext to prevent ambiguous method names in
* subclasses.
*
* @return The nsPresContext associated with our frame, or nsnull if either
* the frame doesn't exist, or the frame's prescontext doesn't exist.
*/
nsPresContext* GetFramePresContext();
/**
* CancelImageRequests is called by subclasses when they want to
* cancel all image requests (for example when the subclass is
@ -302,6 +320,16 @@ protected:
void ClearCurrentRequest(nsresult aReason);
void ClearPendingRequest(nsresult aReason);
/**
* Retrieve a pointer to the 'registered with the refresh driver' flag for
* which a particular image request corresponds.
*
* @returns A pointer to the boolean flag for a given image request, or
* |nsnull| if the request is not either |mPendingRequest| or
* |mCurrentRequest|.
*/
bool* GetRegisteredFlagForRequest(imgIRequest* aRequest);
/**
* Static helper method to tell us if we have the size of a request. The
* image may be null.
@ -382,6 +410,11 @@ private:
/* The number of nested AutoStateChangers currently tracking our state. */
PRUint8 mStateChangerDepth;
// Flags to indicate whether each of the current and pending requests are
// registered with the refresh driver.
bool mCurrentRequestRegistered;
bool mPendingRequestRegistered;
};
#endif // nsImageLoadingContent_h__

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

@ -576,6 +576,10 @@ protected:
/**
* Implements Destroy(). Do not call this directly except from within a
* DestroyFrom() implementation.
*
* @note This will always be called, so it is not necessary to override
* Destroy() in subclasses of nsFrame, just DestroyFrom().
*
* @param aDestructRoot is the root of the subtree being destroyed
*/
virtual void DestroyFrom(nsIFrame* aDestructRoot) = 0;

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

@ -223,6 +223,10 @@ nsImageFrame::DestroyFrom(nsIFrame* aDestructRoot)
nsCxPusher pusher;
pusher.PushNull();
// Notify our image loading content that we are going away so it can
// deregister with our refresh driver.
imageLoader->FrameDestroyed(this);
imageLoader->RemoveObserver(mListener);
}
@ -268,6 +272,10 @@ nsImageFrame::Init(nsIContent* aContent,
if (!gIconLoad)
LoadIcons(aPresContext);
// We have a PresContext now, so we need to notify the image content node
// that it can register images.
imageLoader->FrameCreated(this);
// Give image loads associated with an image frame a small priority boost!
nsCOMPtr<imgIRequest> currentRequest;
imageLoader->GetRequest(nsIImageLoadingContent::CURRENT_REQUEST,

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

@ -100,6 +100,7 @@ public:
NS_IMETHOD Init(nsIContent* aContent,
nsIFrame* aParent,
nsIFrame* aPrevInFlow);
virtual void DestroyFrom(nsIFrame* aDestructRoot);
/**
* Get the "type" of the frame
@ -176,6 +177,10 @@ nsSVGImageFrame::Init(nsIContent* aContent,
nsCOMPtr<nsIImageLoadingContent> imageLoader = do_QueryInterface(mContent);
NS_ENSURE_TRUE(imageLoader, NS_ERROR_UNEXPECTED);
// We should have a PresContext now, so let's notify our image loader that
// we need to register any image animations with the refresh driver.
imageLoader->FrameCreated(this);
// Push a null JSContext on the stack so that code that runs within
// the below code doesn't think it's being called by JS. See bug
// 604262.
@ -187,6 +192,19 @@ nsSVGImageFrame::Init(nsIContent* aContent,
return NS_OK;
}
/* virtual */ void
nsSVGImageFrame::DestroyFrom(nsIFrame* aDestructRoot)
{
nsCOMPtr<nsIImageLoadingContent> imageLoader =
do_QueryInterface(nsFrame::mContent);
if (imageLoader) {
imageLoader->FrameDestroyed(this);
}
nsFrame::DestroyFrom(aDestructRoot);
}
//----------------------------------------------------------------------
// nsIFrame methods:

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

@ -36,6 +36,7 @@
#include "nsFrame.h"
#include "nsSVGEffects.h"
#include "nsImageLoadingContent.h"
class nsSVGLeafFrame : public nsFrame
{
@ -47,6 +48,12 @@ protected:
public:
NS_DECL_FRAMEARENA_HELPERS
NS_IMETHOD Init(nsIContent* aContent,
nsIFrame* aParent,
nsIFrame* asPrevInFlow);
virtual void DestroyFrom(nsIFrame* aDestructRoot);
virtual bool IsFrameOfType(PRUint32 aFlags) const
{
return nsFrame::IsFrameOfType(aFlags & ~(nsIFrame::eSVG));
@ -70,6 +77,33 @@ NS_NewSVGLeafFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
NS_IMPL_FRAMEARENA_HELPERS(nsSVGLeafFrame)
NS_IMETHODIMP
nsSVGLeafFrame::Init(nsIContent* aContent, nsIFrame* aParent, nsIFrame* asPrevInFlow)
{
nsFrame::Init(aContent, aParent, asPrevInFlow);
nsCOMPtr<nsIImageLoadingContent> imageLoader =
do_QueryInterface(nsFrame::mContent);
if (imageLoader) {
imageLoader->FrameCreated(this);
}
return NS_OK;
}
/* virtual */ void
nsSVGLeafFrame::DestroyFrom(nsIFrame* aDestructRoot)
{
nsCOMPtr<nsIImageLoadingContent> imageLoader =
do_QueryInterface(nsFrame::mContent);
if (imageLoader) {
imageLoader->FrameDestroyed(this);
}
nsFrame::DestroyFrom(aDestructRoot);
}
/* virtual */ void
nsSVGLeafFrame::DidSetStyleContext(nsStyleContext* aOldStyleContext)
{