Bug 467291 - Reduce Addrefing while creating event target chain, r+sr=jst
authorOlli Pettay <Olli.Pettay@helsinki.fi>
Wed, 03 Dec 2008 11:26:38 +0200
changeset 22211 ab6b2cedc491551a2e3f8624f9c49a9229ec9044
parent 22210 32c453ca17eda4ab9dcb8a8f7c496bf0cd1f6904
child 22212 121e491cbafef91f543794171df52ff1337071e8
push idunknown
push userunknown
push dateunknown
bugs467291
milestone1.9.2a1pre
Bug 467291 - Reduce Addrefing while creating event target chain, r+sr=jst
content/base/src/nsGenericElement.cpp
content/events/public/nsEventDispatcher.h
content/events/src/nsEventDispatcher.cpp
--- a/content/base/src/nsGenericElement.cpp
+++ b/content/base/src/nsGenericElement.cpp
@@ -2797,25 +2797,27 @@ nsGenericElement::doPreHandleEvent(nsICo
               return NS_OK;
             }
           }
         }
       }
     }
   }
 
-  nsCOMPtr<nsIContent> parent = aContent->GetParent();
+  nsIContent* parent = aContent->GetParent();
+  // Event may need to be retargeted if aContent is the root of a native
+  // anonymous content subtree or event is dispatched somewhere inside XBL.
   if (isAnonForEvents) {
     // If a DOM event is explicitly dispatched using node.dispatchEvent(), then
     // all the events are allowed even in the native anonymous content..
     NS_ASSERTION(aVisitor.mEvent->eventStructType != NS_MUTATION_EVENT ||
                  aVisitor.mDOMEvent,
                  "Mutation event dispatched in native anonymous content!?!");
     aVisitor.mEventTargetAtParent = parent;
-  } else if (parent) {
+  } else if (parent && aVisitor.mOriginalTargetIsInAnon) {
     nsCOMPtr<nsIContent> content(do_QueryInterface(aVisitor.mEvent->target));
     if (content && content->GetBindingParent() == parent) {
       aVisitor.mEventTargetAtParent = parent;
     }
   }
 
   // check for an anonymous parent
   // XXX XBL2/sXBL issue
--- a/content/events/public/nsEventDispatcher.h
+++ b/content/events/public/nsEventDispatcher.h
@@ -124,21 +124,23 @@ public:
   nsCOMPtr<nsISupports> mItemData;
 };
 
 class nsEventChainPreVisitor : public nsEventChainVisitor {
 public:
   nsEventChainPreVisitor(nsPresContext* aPresContext,
                          nsEvent* aEvent,
                          nsIDOMEvent* aDOMEvent,
-                         nsEventStatus aEventStatus = nsEventStatus_eIgnore)
+                         nsEventStatus aEventStatus,
+                         PRBool aIsInAnon)
   : nsEventChainVisitor(aPresContext, aEvent, aDOMEvent, aEventStatus),
     mCanHandle(PR_TRUE), mForceContentDispatch(PR_FALSE),
-    mRelatedTargetIsInAnon(PR_FALSE), mWantsWillHandleEvent(PR_FALSE),
-    mParentTarget(nsnull), mEventTargetAtParent(nsnull) {}
+    mRelatedTargetIsInAnon(PR_FALSE), mOriginalTargetIsInAnon(aIsInAnon),
+    mWantsWillHandleEvent(PR_FALSE), mParentTarget(nsnull),
+    mEventTargetAtParent(nsnull) {}
 
   void Reset() {
     mItemFlags = 0;
     mItemData = nsnull;
     mCanHandle = PR_TRUE;
     mForceContentDispatch = PR_FALSE;
     mWantsWillHandleEvent = PR_FALSE;
     mParentTarget = nsnull;
@@ -160,17 +162,22 @@ public:
    */
   PRPackedBool          mForceContentDispatch;
 
   /**
    * PR_TRUE if it is known that related target is or is a descendant of an
    * element which is anonymous for events.
    */
   PRPackedBool          mRelatedTargetIsInAnon;
-  
+
+  /**
+   * PR_TRUE if the original target of the event is inside anonymous content.
+   * This is set before calling PreHandleEvent on event targets.
+   */
+  PRPackedBool          mOriginalTargetIsInAnon;
 
   /**
    * Whether or not nsPIDOMEventTarget::WillHandleEvent will be
    * called. Default is PR_FALSE;
    */
   PRPackedBool          mWantsWillHandleEvent;
 
   /**
--- a/content/events/src/nsEventDispatcher.cpp
+++ b/content/events/src/nsEventDispatcher.cpp
@@ -454,23 +454,26 @@ nsEventDispatcher::Dispatch(nsISupports*
     //
     // Make sure that the event target points to the right object.
     nsCOMPtr<nsPIDOMEventTarget> t = do_QueryInterface(aEvent->target);
     NS_ENSURE_STATE(t);
     aEvent->target = t->GetTargetForEventTargetChain();
     NS_ENSURE_STATE(aEvent->target);
   }
   aEvent->originalTarget = aEvent->target;
+  nsCOMPtr<nsIContent> content = do_QueryInterface(aEvent->originalTarget);
+  PRBool isInAnon = (content && content->IsInAnonymousSubtree());
 
   NS_MARK_EVENT_DISPATCH_STARTED(aEvent);
 
   // Create visitor object and start event dispatching.
   // PreHandleEvent for the original target.
   nsEventStatus status = aEventStatus ? *aEventStatus : nsEventStatus_eIgnore;
-  nsEventChainPreVisitor preVisitor(aPresContext, aEvent, aDOMEvent, status);
+  nsEventChainPreVisitor preVisitor(aPresContext, aEvent, aDOMEvent, status,
+                                    isInAnon);
   targetEtci->PreHandleEvent(preVisitor);
 
   if (preVisitor.mCanHandle) {
     // At least the original target can handle the event.
     // Setting the retarget to the |target| simplifies retargeting code.
     nsCOMPtr<nsPIDOMEventTarget> t = do_QueryInterface(aEvent->target);
     targetEtci->SetNewTarget(t);
     nsEventTargetChainItem* topEtci = targetEtci;