зеркало из https://github.com/mozilla/gecko-dev.git
Bug 455988. Optimize MozAfterPaint so we never even dispatch an XPCOM event if there are no listeners. r=smaug,sr=mats
This commit is contained in:
Родитель
7211ccf1cd
Коммит
6899d04162
|
@ -590,6 +590,9 @@ nsNodeUtils::CloneAndAdopt(nsINode *aNode, PRBool aClone, PRBool aDeep,
|
|||
aNode->GetListenerManager(PR_FALSE, getter_AddRefs(elm));
|
||||
if (elm) {
|
||||
window->SetMutationListeners(elm->MutationListenerBits());
|
||||
if (elm->MayHavePaintEventListener()) {
|
||||
window->SetHasPaintEventListeners();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,7 +38,7 @@
|
|||
#ifndef nsIEventListenerManager_h__
|
||||
#define nsIEventListenerManager_h__
|
||||
|
||||
#include "nsEvent.h"
|
||||
#include "nsGUIEvent.h"
|
||||
#include "nsISupports.h"
|
||||
|
||||
class nsPresContext;
|
||||
|
@ -53,15 +53,19 @@ class nsPIDOMEventTarget;
|
|||
* Event listener manager interface.
|
||||
*/
|
||||
#define NS_IEVENTLISTENERMANAGER_IID \
|
||||
{ 0x0cdf1660, 0x3ac1, 0x4b84, \
|
||||
{ 0xa9, 0x35, 0xc0, 0xc0, 0xe5, 0x5d, 0x73, 0xca } }
|
||||
|
||||
{ 0xadfdc265, 0xea1c, 0x4c0b, \
|
||||
{ 0x91, 0xca, 0x37, 0x67, 0x2c, 0x83, 0x92, 0x1f } }
|
||||
|
||||
class nsIEventListenerManager : public nsISupports {
|
||||
|
||||
public:
|
||||
NS_DECLARE_STATIC_IID_ACCESSOR(NS_IEVENTLISTENERMANAGER_IID)
|
||||
|
||||
nsIEventListenerManager() : mMayHavePaintEventListener(PR_FALSE),
|
||||
mMayHaveMutationListeners(PR_FALSE),
|
||||
mNoListenerForEvent(NS_EVENT_TYPE_NULL)
|
||||
{}
|
||||
|
||||
/**
|
||||
* Sets events listeners of all types.
|
||||
* @param an event listener
|
||||
|
@ -194,6 +198,21 @@ public:
|
|||
* Returns PR_TRUE if there is at least one event listener.
|
||||
*/
|
||||
virtual PRBool HasListeners() = 0;
|
||||
|
||||
|
||||
/**
|
||||
* Returns PR_TRUE if there may be a paint event listener registered,
|
||||
* PR_FALSE if there definitely isn't.
|
||||
*/
|
||||
PRBool MayHavePaintEventListener() { return mMayHavePaintEventListener; }
|
||||
|
||||
protected:
|
||||
PRUint32 mMayHavePaintEventListener : 1;
|
||||
PRUint32 mMayHaveMutationListeners : 1;
|
||||
// These two member variables are used to cache the information
|
||||
// about the last event which was handled but for which event listener manager
|
||||
// didn't have event listeners.
|
||||
PRUint32 mNoListenerForEvent : 30;
|
||||
};
|
||||
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(nsIEventListenerManager,
|
||||
|
|
|
@ -342,9 +342,7 @@ PRUint32 nsEventListenerManager::mInstanceCount = 0;
|
|||
PRUint32 nsEventListenerManager::sCreatedCount = 0;
|
||||
|
||||
nsEventListenerManager::nsEventListenerManager() :
|
||||
mTarget(nsnull),
|
||||
mMayHaveMutationListeners(PR_FALSE),
|
||||
mNoListenerForEvent(NS_EVENT_TYPE_NULL)
|
||||
mTarget(nsnull)
|
||||
{
|
||||
++mInstanceCount;
|
||||
++sCreatedCount;
|
||||
|
@ -430,6 +428,27 @@ nsEventListenerManager::GetTypeDataForEventName(nsIAtom* aName)
|
|||
return nsnull;
|
||||
}
|
||||
|
||||
nsPIDOMWindow*
|
||||
nsEventListenerManager::GetInnerWindowForTarget()
|
||||
{
|
||||
nsCOMPtr<nsINode> node = do_QueryInterface(mTarget);
|
||||
if (node) {
|
||||
// XXX sXBL/XBL2 issue -- do we really want the owner here? What
|
||||
// if that's the XBL document?
|
||||
nsIDocument* document = node->GetOwnerDoc();
|
||||
if (document)
|
||||
return document->GetInnerWindow();
|
||||
}
|
||||
|
||||
nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(mTarget);
|
||||
if (window) {
|
||||
NS_ASSERTION(window->IsInnerWindow(), "Target should not be an outer window");
|
||||
return window;
|
||||
}
|
||||
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsEventListenerManager::AddEventListener(nsIDOMEventListener *aListener,
|
||||
PRUint32 aType,
|
||||
|
@ -497,29 +516,19 @@ nsEventListenerManager::AddEventListener(nsIDOMEventListener *aListener,
|
|||
ls->mHandlerIsString = PR_FALSE;
|
||||
ls->mTypeData = aTypeData;
|
||||
|
||||
// For mutation listeners, we need to update the global bit on the DOM window.
|
||||
// Otherwise we won't actually fire the mutation event.
|
||||
if (aType >= NS_MUTATION_START && aType <= NS_MUTATION_END) {
|
||||
if (aType == NS_AFTERPAINT) {
|
||||
mMayHavePaintEventListener = PR_TRUE;
|
||||
nsPIDOMWindow* window = GetInnerWindowForTarget();
|
||||
if (window) {
|
||||
window->SetHasPaintEventListener();
|
||||
}
|
||||
} else if (aType >= NS_MUTATION_START && aType <= NS_MUTATION_END) {
|
||||
// For mutation listeners, we need to update the global bit on the DOM window.
|
||||
// Otherwise we won't actually fire the mutation event.
|
||||
mMayHaveMutationListeners = PR_TRUE;
|
||||
// Go from our target to the nearest enclosing DOM window.
|
||||
nsCOMPtr<nsPIDOMWindow> window;
|
||||
nsCOMPtr<nsIDocument> document;
|
||||
nsCOMPtr<nsINode> node(do_QueryInterface(mTarget));
|
||||
if (node) {
|
||||
// XXX sXBL/XBL2 issue -- do we really want the owner here? What
|
||||
// if that's the XBL document?
|
||||
document = node->GetOwnerDoc();
|
||||
if (document) {
|
||||
window = document->GetInnerWindow();
|
||||
}
|
||||
}
|
||||
|
||||
if (!window) {
|
||||
window = do_QueryInterface(mTarget);
|
||||
}
|
||||
nsPIDOMWindow* window = GetInnerWindowForTarget();
|
||||
if (window) {
|
||||
NS_ASSERTION(window->IsInnerWindow(),
|
||||
"Setting mutation listener bits on outer window?");
|
||||
// If aType is NS_MUTATION_SUBTREEMODIFIED, we need to listen all
|
||||
// mutations. nsContentUtils::HasMutationListeners relies on this.
|
||||
window->SetMutationListeners((aType == NS_MUTATION_SUBTREEMODIFIED) ?
|
||||
|
|
|
@ -191,14 +191,10 @@ protected:
|
|||
nsIPresShell *aPresShell, nsPoint& aTargetPt);
|
||||
nsresult GetDOM2EventGroup(nsIDOMEventGroup** aGroup);
|
||||
PRBool ListenerCanHandle(nsListenerStruct* aLs, nsEvent* aEvent);
|
||||
nsPIDOMWindow* GetInnerWindowForTarget();
|
||||
|
||||
nsAutoTObserverArray<nsListenerStruct, 2> mListeners;
|
||||
nsISupports* mTarget; //WEAK
|
||||
PRUint32 mMayHaveMutationListeners : 1;
|
||||
// These two member variables are used to cache the information
|
||||
// about the last event which was handled but for which event listener manager
|
||||
// didn't have event listeners.
|
||||
PRUint32 mNoListenerForEvent : 31;
|
||||
nsCOMPtr<nsIAtom> mNoListenerForEventAtom;
|
||||
|
||||
static PRUint32 mInstanceCount;
|
||||
|
|
|
@ -76,8 +76,8 @@ class nsScriptObjectHolder;
|
|||
class nsXBLPrototypeHandler;
|
||||
|
||||
#define NS_PIDOMWINDOW_IID \
|
||||
{ 0x909852b5, 0xb9e6, 0x4d94, \
|
||||
{ 0x8d, 0xe3, 0x05, 0x16, 0x34, 0x80, 0x0b, 0x73 } }
|
||||
{ 0x3d2b6b38, 0x810d, 0x4ac5, \
|
||||
{ 0x81, 0x7c, 0xb9, 0x70, 0x81, 0x80, 0x4d, 0x9f } }
|
||||
|
||||
class nsPIDOMWindow : public nsIDOMWindowInternal
|
||||
{
|
||||
|
@ -379,6 +379,24 @@ public:
|
|||
return mIsModalContentWindow;
|
||||
}
|
||||
|
||||
/**
|
||||
* Call this to indicate that some node (this window, its document,
|
||||
* or content in that document) has a paint event listener.
|
||||
*/
|
||||
void SetHasPaintEventListeners()
|
||||
{
|
||||
mMayHavePaintEventListener = PR_TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Call this to check whether some node (this window, its document,
|
||||
* or content in that document) has a paint event listener.
|
||||
*/
|
||||
PRBool HasPaintEventListeners()
|
||||
{
|
||||
return mMayHavePaintEventListener;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize window.java and window.Packages, and start LiveConnect
|
||||
* if we're running with a non-NPRuntime enabled Java plugin.
|
||||
|
@ -398,6 +416,7 @@ protected:
|
|||
: mFrameElement(nsnull), mDocShell(nsnull), mModalStateDepth(0),
|
||||
mRunningTimeout(nsnull), mMutationBits(0), mIsDocumentLoaded(PR_FALSE),
|
||||
mIsHandlingResizeEvent(PR_FALSE), mIsInnerWindow(aOuterWindow != nsnull),
|
||||
mMayHavePaintEventListener(PR_FALSE),
|
||||
mIsModalContentWindow(PR_FALSE), mInnerWindow(nsnull),
|
||||
mOuterWindow(aOuterWindow)
|
||||
{
|
||||
|
@ -427,6 +446,7 @@ protected:
|
|||
PRPackedBool mIsDocumentLoaded;
|
||||
PRPackedBool mIsHandlingResizeEvent;
|
||||
PRPackedBool mIsInnerWindow;
|
||||
PRPackedBool mMayHavePaintEventListener;
|
||||
|
||||
// This variable is used on both inner and outer windows (and they
|
||||
// should match).
|
||||
|
|
|
@ -84,6 +84,7 @@
|
|||
#include "nsRuleNode.h"
|
||||
#include "nsEventDispatcher.h"
|
||||
#include "gfxUserFontSet.h"
|
||||
#include "nsIEventListenerManager.h"
|
||||
|
||||
#ifdef IBMBIDI
|
||||
#include "nsBidiPresUtils.h"
|
||||
|
@ -1541,10 +1542,10 @@ nsPresContext::SetUserFontSet(gfxUserFontSet *aUserFontSet)
|
|||
void
|
||||
nsPresContext::FireDOMPaintEvent()
|
||||
{
|
||||
nsCOMPtr<nsIDocShell> docShell(do_QueryReferent(mContainer));
|
||||
if (!docShell)
|
||||
nsCOMPtr<nsPIDOMWindow> ourWindow = mDocument->GetWindow();
|
||||
if (!ourWindow)
|
||||
return;
|
||||
nsCOMPtr<nsPIDOMWindow> ourWindow = do_GetInterface(docShell);
|
||||
|
||||
nsISupports* eventTarget = ourWindow;
|
||||
if (mSameDocDirtyRegion.IsEmpty() && !IsChrome()) {
|
||||
// Don't tell the window about this event, it should not know that
|
||||
|
@ -1570,10 +1571,43 @@ nsPresContext::FireDOMPaintEvent()
|
|||
nsEventDispatcher::Dispatch(eventTarget, this, &event);
|
||||
}
|
||||
|
||||
static PRBool MayHavePaintEventListener(nsPIDOMWindow* aInnerWindow)
|
||||
{
|
||||
if (!aInnerWindow)
|
||||
return PR_FALSE;
|
||||
if (aInnerWindow->HasPaintEventListeners())
|
||||
return PR_TRUE;
|
||||
|
||||
nsPIDOMEventTarget* chromeEventHandler = aInnerWindow->GetChromeEventHandler();
|
||||
if (!chromeEventHandler)
|
||||
return PR_FALSE;
|
||||
|
||||
nsCOMPtr<nsIEventListenerManager> manager;
|
||||
chromeEventHandler->GetListenerManager(PR_FALSE, getter_AddRefs(manager));
|
||||
if (manager && manager->MayHavePaintEventListener())
|
||||
return PR_TRUE;
|
||||
|
||||
nsCOMPtr<nsINode> node = do_QueryInterface(chromeEventHandler);
|
||||
if (node)
|
||||
return MayHavePaintEventListener(node->GetOwnerDoc()->GetInnerWindow());
|
||||
|
||||
nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(chromeEventHandler);
|
||||
if (window)
|
||||
return MayHavePaintEventListener(window);
|
||||
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
void
|
||||
nsPresContext::NotifyInvalidation(const nsRect& aRect, PRBool aIsCrossDoc)
|
||||
{
|
||||
if (aRect.IsEmpty())
|
||||
// If there is no paint event listener, then we don't need to fire
|
||||
// the asynchronous event. We don't even need to record invalidation.
|
||||
// MayHavePaintEventListener is pretty cheap and we could make it
|
||||
// even cheaper by providing a more efficient
|
||||
// nsPIDOMWindow::GetListenerManager.
|
||||
if (aRect.IsEmpty() ||
|
||||
!MayHavePaintEventListener(mDocument->GetInnerWindow()))
|
||||
return;
|
||||
|
||||
if (mSameDocDirtyRegion.IsEmpty() && mCrossDocDirtyRegion.IsEmpty()) {
|
||||
|
|
Загрузка…
Ссылка в новой задаче