Bug 1205466, make HasApzAwareListeners check faster, r=masayuki
authorOlli Pettay <Olli.Pettay@helsinki.fi>
Thu, 17 Sep 2015 13:16:20 +0300
changeset 263034 2074a0012421534e32c094dc36edff8c720d31b6
parent 263033 86bd982df1f9b339dd94d3dac25cbba7d5f20a15
child 263035 47d056b3af7fa5fca6174f3e050c7f4a69102ef2
push id29387
push userkwierso@gmail.com
push dateThu, 17 Sep 2015 21:59:18 +0000
treeherdermozilla-central@3929b8fc6c33 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmasayuki
bugs1205466
milestone43.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1205466, make HasApzAwareListeners check faster, r=masayuki
dom/base/Element.h
dom/base/nsIAttribute.h
dom/base/nsIContent.h
dom/base/nsIDocument.h
dom/base/nsINode.cpp
dom/base/nsINode.h
dom/base/nsPIWindowRoot.h
dom/events/EventListenerManager.cpp
dom/events/EventListenerManager.h
dom/events/EventTarget.cpp
dom/events/EventTarget.h
layout/base/nsLayoutUtils.cpp
layout/base/nsLayoutUtils.h
layout/generic/nsFrame.cpp
--- a/dom/base/Element.h
+++ b/dom/base/Element.h
@@ -130,18 +130,18 @@ class Animation;
 class Link;
 class UndoManager;
 class DOMRect;
 class DOMRectList;
 class DestinationInsertionPointList;
 
 // IID for the dom::Element interface
 #define NS_ELEMENT_IID \
-{ 0x31d3f3fb, 0xcdf8, 0x4e40, \
- { 0xb7, 0x09, 0x1a, 0x11, 0x43, 0x93, 0x61, 0x71 } }
+{ 0xc67ed254, 0xfd3b, 0x4b10, \
+  { 0x96, 0xa2, 0xc5, 0x8b, 0x7b, 0x64, 0x97, 0xd1 } }
 
 class Element : public FragmentOrElement
 {
 public:
 #ifdef MOZILLA_INTERNAL_API
   explicit Element(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo) :
     FragmentOrElement(aNodeInfo),
     mState(NS_EVENT_STATE_MOZ_READONLY)
--- a/dom/base/nsIAttribute.h
+++ b/dom/base/nsIAttribute.h
@@ -7,18 +7,18 @@
 #ifndef nsIAttribute_h___
 #define nsIAttribute_h___
 
 #include "nsINode.h"
 
 class nsDOMAttributeMap;
 
 #define NS_IATTRIBUTE_IID  \
-{ 0x233a9c4d, 0xb27f, 0x4662, \
-    { 0xbd, 0x90, 0xba, 0xd6, 0x2e, 0x76, 0xc8, 0xe1 } }
+{ 0x84d43da7, 0xb45d, 0x47ae, \
+  { 0x8f, 0xbf, 0x95, 0x26, 0x78, 0x4d, 0x5e, 0x47 } }
 
 class nsIAttribute : public nsINode
 {
 public:
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_IATTRIBUTE_IID)
 
   virtual void SetMap(nsDOMAttributeMap *aMap) = 0;
   
--- a/dom/base/nsIContent.h
+++ b/dom/base/nsIContent.h
@@ -35,18 +35,18 @@ struct IMEState;
 enum nsLinkState {
   eLinkState_Unvisited  = 1,
   eLinkState_Visited    = 2,
   eLinkState_NotLink    = 3 
 };
 
 // IID for the nsIContent interface
 #define NS_ICONTENT_IID \
-{ 0x70f7e9ea, 0xa9bf, 0x48cc, \
-  { 0xad, 0x9d, 0x8a, 0xca, 0xee, 0xd2, 0x9b, 0x68 } }
+{ 0x52cebfc8, 0x79ba, 0x4e38, \
+  { 0x8a, 0x4c, 0x7f, 0x9d, 0xb1, 0xa2, 0xb6, 0x1d } }
 
 /**
  * A node of content in a document's content model. This interface
  * is supported by all content objects.
  */
 class nsIContent : public nsINode {
 public:
   typedef mozilla::widget::IMEState IMEState;
--- a/dom/base/nsIDocument.h
+++ b/dom/base/nsIDocument.h
@@ -150,18 +150,18 @@ template<typename> class Sequence;
 
 template<typename, typename> class CallbackObjectHolder;
 typedef CallbackObjectHolder<NodeFilter, nsIDOMNodeFilter> NodeFilterHolder;
 
 } // namespace dom
 } // namespace mozilla
 
 #define NS_IDOCUMENT_IID \
-{ 0x292450a1, 0x285e, 0x4a09, \
-  { 0x9a, 0xf9, 0x61, 0xf9, 0xb1, 0xbd, 0x27, 0xcc } }
+{ 0x72391609, 0x673d, 0x4bec, \
+  { 0xbd, 0x75, 0x64, 0xbf, 0x1f, 0x6a, 0x6b, 0x5e } }
 
 // Enum for requesting a particular type of document when creating a doc
 enum DocumentFlavor {
   DocumentFlavorLegacyGuess, // compat with old code until made HTML5-compliant
   DocumentFlavorHTML, // HTMLDocument with HTMLness bit set to true
   DocumentFlavorSVG, // SVGDocument
   DocumentFlavorPlain, // Just a Document
 };
--- a/dom/base/nsINode.cpp
+++ b/dom/base/nsINode.cpp
@@ -2828,8 +2828,17 @@ nsINode::AddAnimationObserver(nsIAnimati
 
 void
 nsINode::AddAnimationObserverUnlessExists(
                                nsIAnimationObserver* aAnimationObserver)
 {
   AddMutationObserverUnlessExists(aAnimationObserver);
   OwnerDoc()->SetMayHaveAnimationObservers();
 }
+
+bool
+nsINode::HasApzAwareListeners() const
+{
+  if (NodeMayHaveApzAwareListeners()) {
+    return EventTarget::HasApzAwareListeners();
+  }
+  return false;
+}
--- a/dom/base/nsINode.h
+++ b/dom/base/nsINode.h
@@ -245,18 +245,18 @@ private:
 
 // Categories of node properties
 // 0 is global.
 #define DOM_USER_DATA         1
 #define SMIL_MAPPED_ATTR_ANIMVAL 2
 
 // IID for the nsINode interface
 #define NS_INODE_IID \
-{ 0xe8fdd227, 0x27da, 0x46ee, \
-  { 0xbe, 0xf3, 0x1a, 0xef, 0x5a, 0x8f, 0xc5, 0xb4 } }
+{ 0x70ba4547, 0x7699, 0x44fc, \
+  { 0xb3, 0x20, 0x52, 0xdb, 0xe3, 0xd1, 0xf9, 0x0a } }
 
 /**
  * An internal interface that abstracts some DOMNode-related parts that both
  * nsIContent and nsIDocument share.  An instance of this interface has a list
  * of nsIContent children and provides access to them.
  */
 class nsINode : public mozilla::dom::EventTarget
 {
@@ -944,16 +944,19 @@ public:
   using mozilla::dom::EventTarget::RemoveEventListener;
   using nsIDOMEventTarget::AddEventListener;
   virtual void AddEventListener(const nsAString& aType,
                                 mozilla::dom::EventListener* aListener,
                                 bool aUseCapture,
                                 const mozilla::dom::Nullable<bool>& aWantsUntrusted,
                                 mozilla::ErrorResult& aRv) override;
   using nsIDOMEventTarget::AddSystemEventListener;
+
+  virtual bool HasApzAwareListeners() const override;
+
   virtual nsIDOMWindow* GetOwnerGlobalForBindings() override;
   virtual nsIGlobalObject* GetOwnerGlobal() const override;
 
   /**
    * Adds a mutation observer to be notified when this node, or any of its
    * descendants, are modified. The node will hold a weak reference to the
    * observer, which means that it is the responsibility of the observer to
    * remove itself in case it dies before the node.  If an observer is added
@@ -1490,16 +1493,18 @@ private:
     NodeHandlingClick,
     // Set if the node has had :hover selectors matched against it
     NodeHasRelevantHoverRules,
     // Set if the element has a parser insertion mode other than "in body",
     // per the HTML5 "Parse state" section.
     ElementHasWeirdParserInsertionMode,
     // Parser sets this flag if it has notified about the node.
     ParserHasNotified,
+    // EventListenerManager sets this flag in case we have apz aware listeners.
+    MayHaveApzAwareListeners,
     // Guard value
     BooleanFlagCount
   };
 
   void SetBoolFlag(BooleanFlag name, bool value) {
     static_assert(BooleanFlagCount <= 8*sizeof(mBoolFlags),
                   "Too many boolean flags");
     mBoolFlags = (mBoolFlags & ~(1 << name)) | (value << name);
@@ -1632,16 +1637,22 @@ public:
 
   void SetIsScopedStyleRoot() { SetBoolFlag(ElementIsScopedStyleRoot); }
   void ClearIsScopedStyleRoot() { ClearBoolFlag(ElementIsScopedStyleRoot); }
   bool IsScopedStyleRoot() { return GetBoolFlag(ElementIsScopedStyleRoot); }
   bool HasRelevantHoverRules() const { return GetBoolFlag(NodeHasRelevantHoverRules); }
   void SetHasRelevantHoverRules() { SetBoolFlag(NodeHasRelevantHoverRules); }
   void SetParserHasNotified() { SetBoolFlag(ParserHasNotified); };
   bool HasParserNotified() { return GetBoolFlag(ParserHasNotified); }
+
+  void SetMayHaveApzAwareListeners() { SetBoolFlag(MayHaveApzAwareListeners); }
+  bool NodeMayHaveApzAwareListeners() const
+  {
+    return GetBoolFlag(MayHaveApzAwareListeners);
+  }
 protected:
   void SetParentIsContent(bool aValue) { SetBoolFlag(ParentIsContent, aValue); }
   void SetInDocument() { SetBoolFlag(IsInDocument); }
   void SetNodeIsContent() { SetBoolFlag(NodeIsContent); }
   void ClearInDocument() { ClearBoolFlag(IsInDocument); }
   void SetIsElement() { SetBoolFlag(NodeIsElement); }
   void SetHasID() { SetBoolFlag(ElementHasID); }
   void ClearHasID() { ClearBoolFlag(ElementHasID); }
--- a/dom/base/nsPIWindowRoot.h
+++ b/dom/base/nsPIWindowRoot.h
@@ -17,18 +17,18 @@ class nsIController;
 
 namespace mozilla {
 namespace dom {
 class TabParent;
 } // namespace dom
 } // namespace mozilla
 
 #define NS_IWINDOWROOT_IID \
-{ 0x238edca0, 0xb30d, 0x46d3, \
- { 0xb2, 0x6a, 0x17, 0xb6, 0x21, 0x28, 0x89, 0x7e } }
+{ 0xb8724c49, 0xc398, 0x4f9b, \
+  { 0x82, 0x59, 0x87, 0x27, 0xa6, 0x47, 0xdd, 0x0f } }
 
 class nsPIWindowRoot : public mozilla::dom::EventTarget
 {
 public:
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_IWINDOWROOT_IID)
 
   virtual nsPIDOMWindow* GetWindow()=0;
 
--- a/dom/events/EventListenerManager.cpp
+++ b/dom/events/EventListenerManager.cpp
@@ -400,16 +400,23 @@ EventListenerManager::AddEventListenerIn
              aTypeAtom == nsGkAtoms::oncompositionstart ||
              aTypeAtom == nsGkAtoms::oncompositionupdate ||
              aTypeAtom == nsGkAtoms::oninput) {
     if (!aFlags.mInSystemGroup) {
       mMayHaveInputOrCompositionEventListener = true;
     }
   }
 
+  if (IsApzAwareEvent(aTypeAtom)) {
+    nsCOMPtr<nsINode> node = do_QueryInterface(mTarget);
+    if (node) {
+      node->SetMayHaveApzAwareListeners();
+    }
+  }
+
   if (aTypeAtom && mTarget) {
     mTarget->EventListenerAdded(aTypeAtom);
   }
 
   if (mIsMainThreadELM && mTarget) {
     EventListenerService::NotifyAboutMainThreadListenerChange(mTarget,
                                                               aTypeAtom);
   }
@@ -1485,16 +1492,40 @@ EventListenerManager::TraceListeners(JST
     } else if (listener.mListenerType == Listener::eWebIDLListener) {
       mozilla::TraceScriptHolder(listener.mListener.GetWebIDLCallback(), aTrc);
     }
     // We might have eWrappedJSListener, but that is the legacy type for
     // JS implemented event listeners, and trickier to handle here.
   }
 }
 
+bool
+EventListenerManager::HasApzAwareListeners()
+{
+  uint32_t count = mListeners.Length();
+  for (uint32_t i = 0; i < count; ++i) {
+    Listener* listener = &mListeners.ElementAt(i);
+    if (IsApzAwareEvent(listener->mTypeAtom)) {
+      return true;
+    }
+  }
+  return false;
+}
+
+bool
+EventListenerManager::IsApzAwareEvent(nsIAtom* aEvent)
+{
+  return aEvent == nsGkAtoms::ontouchstart ||
+         aEvent == nsGkAtoms::ontouchmove ||
+         aEvent == nsGkAtoms::onwheel ||
+         aEvent == nsGkAtoms::onDOMMouseScroll ||
+         aEvent == nsHtml5Atoms::onmousewheel ||
+         aEvent == nsGkAtoms::onMozMousePixelScroll;
+}
+
 already_AddRefed<nsIScriptGlobalObject>
 EventListenerManager::GetScriptGlobalAndDocument(nsIDocument** aDoc)
 {
   nsCOMPtr<nsINode> node(do_QueryInterface(mTarget));
   nsCOMPtr<nsIDocument> doc;
   nsCOMPtr<nsIScriptGlobalObject> global;
   if (node) {
     // Try to get context from doc
--- a/dom/events/EventListenerManager.h
+++ b/dom/events/EventListenerManager.h
@@ -438,16 +438,20 @@ public:
   }
 
   void MarkForCC();
 
   void TraceListeners(JSTracer* aTrc);
 
   dom::EventTarget* GetTarget() { return mTarget; }
 
+  bool HasApzAwareListeners();
+
+  bool IsApzAwareEvent(nsIAtom* aEvent);
+
 protected:
   void HandleEventInternal(nsPresContext* aPresContext,
                            WidgetEvent* aEvent,
                            nsIDOMEvent** aDOMEvent,
                            dom::EventTarget* aCurrentTarget,
                            nsEventStatus* aEventStatus);
 
   nsresult HandleEventSubType(Listener* aListener,
--- a/dom/events/EventTarget.cpp
+++ b/dom/events/EventTarget.cpp
@@ -51,10 +51,17 @@ EventTarget::SetEventHandler(const nsASt
 
 void
 EventTarget::SetEventHandler(nsIAtom* aType, const nsAString& aTypeString,
                              EventHandlerNonNull* aHandler)
 {
   GetOrCreateListenerManager()->SetEventHandler(aType, aTypeString, aHandler);
 }
 
+bool
+EventTarget::HasApzAwareListeners() const
+{
+  EventListenerManager* elm = GetExistingListenerManager();
+  return elm && elm->HasApzAwareListeners();
+}
+
 } // namespace dom
 } // namespace mozilla
--- a/dom/events/EventTarget.h
+++ b/dom/events/EventTarget.h
@@ -23,18 +23,18 @@ namespace dom {
 
 class Event;
 class EventListener;
 class EventHandlerNonNull;
 template <class T> struct Nullable;
 
 // IID for the dom::EventTarget interface
 #define NS_EVENTTARGET_IID \
-{ 0x605158a9, 0xe229, 0x45b1, \
- { 0xbc, 0x12, 0x02, 0x9f, 0xa3, 0xa9, 0x3f, 0xcb } }
+{ 0xde651c36, 0x0053, 0x4c67, \
+  { 0xb1, 0x3d, 0x67, 0xb9, 0x40, 0xfc, 0x82, 0xe4 } }
 
 class EventTarget : public nsIDOMEventTarget,
                     public nsWrapperCache
 {
 public:
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_EVENTTARGET_IID)
 
   // WebIDL API
@@ -83,16 +83,18 @@ public:
   virtual EventListenerManager* GetOrCreateListenerManager() = 0;
 
   /**
    * Get the event listener manager, returning null if it does not already
    * exist.
    */
   virtual EventListenerManager* GetExistingListenerManager() const = 0;
 
+  virtual bool HasApzAwareListeners() const;
+
 protected:
   EventHandlerNonNull* GetEventHandler(nsIAtom* aType,
                                        const nsAString& aTypeString);
   void SetEventHandler(nsIAtom* aType, const nsAString& aTypeString,
                        EventHandlerNonNull* aHandler);
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(EventTarget, NS_EVENTTARGET_IID)
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -8195,40 +8195,26 @@ nsLayoutUtils::SetBSizeFromFontMetrics(c
     aMetrics.SetBlockStartAscent(aMetrics.BSize(aLineWM) = 0);
   }
   aMetrics.SetBlockStartAscent(aMetrics.BlockStartAscent() +
                                aFramePadding.BStart(aFrameWM));
   aMetrics.BSize(aLineWM) += aFramePadding.BStartEnd(aFrameWM);
 }
 
 /* static */ bool
-nsLayoutUtils::HasApzAwareListeners(EventListenerManager* aElm)
-{
-  if (!aElm) {
-    return false;
-  }
-  return aElm->HasListenersFor(nsGkAtoms::ontouchstart) ||
-         aElm->HasListenersFor(nsGkAtoms::ontouchmove) ||
-         aElm->HasListenersFor(nsGkAtoms::onwheel) ||
-         aElm->HasListenersFor(nsGkAtoms::onDOMMouseScroll) ||
-         aElm->HasListenersFor(nsHtml5Atoms::onmousewheel) ||
-         aElm->HasListenersFor(nsGkAtoms::onMozMousePixelScroll);
-}
-
-/* static */ bool
 nsLayoutUtils::HasDocumentLevelListenersForApzAwareEvents(nsIPresShell* aShell)
 {
   if (nsIDocument* doc = aShell->GetDocument()) {
     WidgetEvent event(true, eVoidEvent);
     nsTArray<EventTarget*> targets;
     nsresult rv = EventDispatcher::Dispatch(doc, nullptr, &event, nullptr,
         nullptr, nullptr, &targets);
     NS_ENSURE_SUCCESS(rv, false);
     for (size_t i = 0; i < targets.Length(); i++) {
-      if (HasApzAwareListeners(targets[i]->GetExistingListenerManager())) {
+      if (targets[i]->HasApzAwareListeners()) {
         return true;
       }
     }
   }
   return false;
 }
 
 /* static */ float
--- a/layout/base/nsLayoutUtils.h
+++ b/layout/base/nsLayoutUtils.h
@@ -2689,17 +2689,16 @@ public:
   static bool IsOutlineStyleAutoEnabled();
 
   static void SetBSizeFromFontMetrics(const nsIFrame* aFrame,
                                       nsHTMLReflowMetrics& aMetrics,
                                       const mozilla::LogicalMargin& aFramePadding,
                                       mozilla::WritingMode aLineWM,
                                       mozilla::WritingMode aFrameWM);
 
-  static bool HasApzAwareListeners(mozilla::EventListenerManager* aElm);
   static bool HasDocumentLevelListenersForApzAwareEvents(nsIPresShell* aShell);
 
   /**
    * Get the resolution at which rescalable web content is drawn
    * (see nsIDOMWindowUtils.getResolution).
    */
   static float GetResolution(nsIPresShell* aPresShell);
 
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -2004,18 +2004,18 @@ public:
 
 static void
 CheckForApzAwareEventHandlers(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame)
 {
   nsIContent* content = aFrame->GetContent();
   if (!content) {
     return;
   }
-  EventListenerManager* elm = nsContentUtils::GetExistingListenerManagerForNode(content);
-  if (nsLayoutUtils::HasApzAwareListeners(elm)) {
+
+  if (content->HasApzAwareListeners()) {
     aBuilder->SetAncestorHasApzAwareEventHandler(true);
   }
 }
 
 void
 nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder,
                                              const nsRect&         aDirtyRect,
                                              nsDisplayList*        aList) {