backout 387a5f8b5e4f and b45a4dcb88c1
authorWes Johnston <wjohnston@mozilla.com>
Mon, 29 Oct 2012 15:45:52 -0700
changeset 111706 4d4051649e96
parent 111705 eca4483a58cf
child 111707 73a1b4cc15cc
push id17213
push userwjohnston@mozilla.com
push dateMon, 29 Oct 2012 22:46:04 +0000
treeherdermozilla-inbound@4d4051649e96 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone19.0a1
backs out387a5f8b5e4f
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
backout 387a5f8b5e4f and b45a4dcb88c1
layout/base/nsPresShell.cpp
--- a/layout/base/nsPresShell.cpp
+++ b/layout/base/nsPresShell.cpp
@@ -5647,33 +5647,16 @@ static PLDHashOperator
 AppendToTouchList(const uint32_t& aKey, nsCOMPtr<nsIDOMTouch>& aData, void *aTouchList)
 {
   nsTArray<nsCOMPtr<nsIDOMTouch> > *touches = static_cast<nsTArray<nsCOMPtr<nsIDOMTouch> > *>(aTouchList);
   aData->mChanged = false;
   touches->AppendElement(aData);
   return PL_DHASH_NEXT;
 }
 
-static PLDHashOperator
-FindAnyTarget(const uint32_t& aKey, nsCOMPtr<nsIDOMTouch>& aData,
-              void* aAnyTarget)
-{
-  if (aData) {
-    nsCOMPtr<nsIDOMEventTarget> target;
-    aData->GetTarget(getter_AddRefs(target));
-    if (target) {
-      nsCOMPtr<nsIContent>* content =
-        static_cast<nsCOMPtr<nsIContent>*>(aAnyTarget);
-      *content = do_QueryInterface(target);
-      return PL_DHASH_STOP;
-    }
-  }
-  return PL_DHASH_NEXT;
-}
-
 nsIFrame* GetNearestFrameContainingPresShell(nsIPresShell* aPresShell)
 {
   nsIView* view = aPresShell->GetViewManager()->GetRootView();
   while (view && !view->GetFrame()) {
     view = view->GetParent();
   }
 
   nsIFrame* frame = nullptr;
@@ -5867,103 +5850,42 @@ PresShell::HandleEvent(nsIFrame        *
     // Get the frame at the event point. However, don't do this if we're
     // capturing and retargeting the event because the captured frame will
     // be used instead below. Also keep using the root frame if we're dealing
     // with a window-level mouse exit event since we want to start sending
     // mouse out events at the root EventStateManager.
     if (!captureRetarget && !isWindowLevelMouseExit) {
       nsPoint eventPoint;
       if (aEvent->message == NS_TOUCH_START) {
+        // Add any new touches to the queue
         nsTouchEvent* touchEvent = static_cast<nsTouchEvent*>(aEvent);
         // if there is only one touch in this touchstart event, assume that it is
         // the start of a new touch session and evict any old touches in the
         // queue
         if (touchEvent->touches.Length() == 1) {
           nsTArray<nsCOMPtr<nsIDOMTouch> > touches;
           gCaptureTouchList.Enumerate(&AppendToTouchList, (void *)&touches);
           for (uint32_t i = 0; i < touches.Length(); ++i) {
             EvictTouchPoint(touches[i]);
           }
         }
-        // if this is a continuing session, ensure that all these events are
-        // in the same document by taking the target of the events already in
-        // the capture list
-        nsCOMPtr<nsIContent> anyTarget;
-        if (gCaptureTouchList.Count() > 0) {
-          gCaptureTouchList.Enumerate(&FindAnyTarget, &anyTarget);
-        } else {
-          gPreventMouseEvents = false;
-        }
-
-        // Add any new touches to the queue
-        for (int32_t i = touchEvent->touches.Length(); i; ) {
-          --i;
+        for (uint32_t i = 0; i < touchEvent->touches.Length(); ++i) {
           nsIDOMTouch *touch = touchEvent->touches[i];
           nsDOMTouch *domtouch = static_cast<nsDOMTouch*>(touch);
           touch->mMessage = aEvent->message;
 
           int32_t id = 0;
           touch->GetIdentifier(&id);
           if (!gCaptureTouchList.Get(id, nullptr)) {
             // This event is a new touch. Mark it as a changedTouch and
             // add it to the queue.
             touch->mChanged = true;
-
-            // find the target for this touch
-            uint32_t flags = 0;
-            eventPoint = nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent,
-                                                              touch->mRefPoint,
-                                                              frame);
-            nsIFrame* target =
-                          FindFrameTargetedByInputEvent(aEvent->eventStructType,
-                                                        frame,
-                                                        eventPoint,
-                                                        flags);
-            if (target && !anyTarget) {
-              target->GetContentForEvent(aEvent, getter_AddRefs(anyTarget));
-              while (anyTarget && !anyTarget->IsElement()) {
-                anyTarget = anyTarget->GetParent();
-              }
-              domtouch->SetTarget(anyTarget);
-              gCaptureTouchList.Put(id, touch);
-            } else {
-              nsIFrame* newTargetFrame = nullptr;
-              for (nsIFrame* f = target; f;
-                   f = nsLayoutUtils::GetParentOrPlaceholderForCrossDoc(f)) {
-                if (f->PresContext()->Document() == anyTarget->OwnerDoc()) {
-                  newTargetFrame = f;
-                  break;
-                }
-                // We must be in a subdocument so jump directly to the root frame.
-                // GetParentOrPlaceholderForCrossDoc gets called immediately to
-                // jump up to the containing document.
-                f = f->PresContext()->GetPresShell()->GetRootFrame();
-              }
-    
-              // if we couldn't find a target frame in the same document as
-              // anyTarget, remove the touch from the capture touch list, as
-              // well as the event->touches array. touchmove events that aren't
-              // in the captured touch list will be discarded
-              if (!newTargetFrame) {
-                touchEvent->touches.RemoveElementAt(i);
-              } else {
-                target = newTargetFrame;
-                nsCOMPtr<nsIContent> targetContent;
-                target->GetContentForEvent(aEvent, getter_AddRefs(targetContent));
-                while (targetContent && !targetContent->IsElement()) {
-                  targetContent = targetContent->GetParent();
-                }
-                touch->SetTarget(targetContent);
-                gCaptureTouchList.Put(id, touch);
-              }
-            }
-
-            if (target) {
-              frame = target;
-            }
+            gCaptureTouchList.Put(id, touch);
+
+            eventPoint = nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, touch->mRefPoint, frame);
           } else {
             // This touch is an old touch, we need to ensure that is not
             // marked as changed and set its target correctly
             touch->mChanged = false;
             int32_t id;
             touch->GetIdentifier(&id);
 
             nsCOMPtr<nsIDOMTouch> oldTouch;
@@ -6024,16 +5946,57 @@ PresShell::HandleEvent(nsIFrame        *
       }
 
       return NS_OK;
     }
 
     PresShell* shell =
         static_cast<PresShell*>(frame->PresContext()->PresShell());
 
+    switch (aEvent->message) {
+      case NS_TOUCH_MOVE:
+      case NS_TOUCH_CANCEL:
+      case NS_TOUCH_END: {
+        // Remove the changed touches
+        // need to make sure we only remove touches that are ending here
+        nsTouchEvent* touchEvent = static_cast<nsTouchEvent*>(aEvent);
+        nsTArray<nsCOMPtr<nsIDOMTouch> >  &touches = touchEvent->touches;
+        for (uint32_t i = 0; i < touches.Length(); ++i) {
+          nsIDOMTouch *touch = touches[i];
+          if (!touch) {
+            break;
+          }
+  
+          int32_t id;
+          touch->GetIdentifier(&id);
+          nsCOMPtr<nsIDOMTouch> oldTouch;
+          gCaptureTouchList.Get(id, getter_AddRefs(oldTouch));
+          if (!oldTouch) {
+            break;
+          }
+  
+          nsCOMPtr<nsPIDOMEventTarget> targetPtr;
+          oldTouch->GetTarget(getter_AddRefs(targetPtr));
+          nsCOMPtr<nsIContent> content = do_QueryInterface(targetPtr);
+          if (!content) {
+            break;
+          }
+
+          nsIFrame* contentFrame = content->GetPrimaryFrame();
+          if (!contentFrame) {
+            break;
+          }
+
+          shell = static_cast<PresShell*>(
+                      contentFrame->PresContext()->PresShell());
+        }
+        break;
+      }
+    }
+
     // Check if we have an active EventStateManager which isn't the
     // EventStateManager of the current PresContext.
     // If that is the case, and mouse is over some ancestor document,
     // forward event handling to the active document.
     // This way content can get mouse events even when
     // mouse is over the chrome or outside the window.
     //
     // Note, currently for backwards compatibility we don't forward mouse events
@@ -6386,46 +6349,40 @@ PresShell::HandleEventInternal(nsEvent* 
         }
         // add any touches left in the touch list, but ensure changed=false
         gCaptureTouchList.Enumerate(&AppendToTouchList, (void *)&touches);
         break;
       }
       case NS_TOUCH_MOVE: {
         // Check for touches that changed. Mark them add to queue
         nsTouchEvent* touchEvent = static_cast<nsTouchEvent*>(aEvent);
-        nsTArray<nsCOMPtr<nsIDOMTouch> >& touches = touchEvent->touches;
+        nsTArray<nsCOMPtr<nsIDOMTouch> > touches = touchEvent->touches;
         bool haveChanged = false;
-        for (int32_t i = touches.Length(); i; ) {
-          --i;
+        for (uint32_t i = 0; i < touches.Length(); ++i) {
           nsIDOMTouch *touch = touches[i];
           nsDOMTouch *domtouch = static_cast<nsDOMTouch*>(touch);
           if (!touch) {
             continue;
           }
           int32_t id;
           touch->GetIdentifier(&id);
           touch->mMessage = aEvent->message;
 
           nsCOMPtr<nsIDOMTouch> oldTouch;
           gCaptureTouchList.Get(id, getter_AddRefs(oldTouch));
           if (!oldTouch) {
-            touches.RemoveElementAt(i);
             continue;
           }
           if(domtouch->Equals(oldTouch)) {
             touch->mChanged = true;
             haveChanged = true;
           }
 
           nsCOMPtr<nsPIDOMEventTarget> targetPtr;
           oldTouch->GetTarget(getter_AddRefs(targetPtr));
-          if (!targetPtr) {
-            touches.RemoveElementAt(i);
-            continue;
-          }
           domtouch->SetTarget(targetPtr);
 
           gCaptureTouchList.Put(id, touch);
           // if we're moving from touchstart to touchmove for this touch
           // we allow preventDefault to prevent mouse events
           if (oldTouch->mMessage != touch->mMessage) {
             touchIsNew = true;
           }
@@ -6547,73 +6504,103 @@ PresShell::HandleEventInternal(nsEvent* 
 }
 
 void
 PresShell::DispatchTouchEvent(nsEvent *aEvent,
                               nsEventStatus* aStatus,
                               nsPresShellEventCB* aEventCB,
                               bool aTouchIsNew)
 {
+  nsresult rv = NS_OK;
   // calling preventDefault on touchstart or the first touchmove for a
   // point prevents mouse events
   bool canPrevent = aEvent->message == NS_TOUCH_START ||
               (aEvent->message == NS_TOUCH_MOVE && aTouchIsNew);
   bool preventDefault = false;
   nsEventStatus tmpStatus = nsEventStatus_eIgnore;
   nsTouchEvent* touchEvent = static_cast<nsTouchEvent*>(aEvent);
-
-  // loop over all touches and dispatch events on any that have changed
-  for (uint32_t i = 0; i < touchEvent->touches.Length(); ++i) {
-    nsIDOMTouch *touch = touchEvent->touches[i];
-    if (!touch || !touch->mChanged) {
-      continue;
-    }
-
-    nsCOMPtr<nsPIDOMEventTarget> targetPtr;
-    touch->GetTarget(getter_AddRefs(targetPtr));
-    nsCOMPtr<nsIContent> content = do_QueryInterface(targetPtr);
-    if (!content) {
-      continue;
-    }
-
-    nsIContent* capturingContent = GetCapturingContent();
-    if (capturingContent) {
-      if (capturingContent->OwnerDoc() != content->OwnerDoc()) {
-        // Wrong document, don't dispatch anything.
+  // touch events should fire on all targets
+  if (aEvent->message != NS_TOUCH_START) {
+    for (uint32_t i = 0; i < touchEvent->touches.Length(); ++i) {
+      nsIDOMTouch *touch = touchEvent->touches[i];
+      if (!touch || !touch->mChanged) {
+        continue;
+      }
+      // copy the event
+      nsCOMPtr<nsPIDOMEventTarget> targetPtr;
+      touch->GetTarget(getter_AddRefs(targetPtr));
+      if (!targetPtr) {
         continue;
       }
-      content = capturingContent;
-    }
-    // copy the event
-    nsTouchEvent newEvent(NS_IS_TRUSTED_EVENT(touchEvent) ?
-                            true : false,
-                          touchEvent);
-    newEvent.target = targetPtr;
-
-    nsRefPtr<PresShell> contentPresShell;
-    if (content->OwnerDoc() == mDocument) {
-      contentPresShell = static_cast<PresShell*>
-          (content->OwnerDoc()->GetShell());
+
+      nsTouchEvent newEvent(NS_IS_TRUSTED_EVENT(touchEvent) ?
+                              true : false,
+                            touchEvent);
+      newEvent.target = targetPtr;
+
+      // If someone is capturing, all touch events are filtered to their target
+      nsCOMPtr<nsIContent> content = GetCapturingContent();
+
+      // if no one is capturing, set the capturing target
+      if (!content) {
+        content = do_QueryInterface(targetPtr);
+      }
+      nsRefPtr<PresShell> contentPresShell;
+      if (content && content->OwnerDoc() == mDocument) {
+        contentPresShell = static_cast<PresShell*>
+            (content->OwnerDoc()->GetShell());
+        if (contentPresShell) {
+          contentPresShell->PushCurrentEventInfo(
+              content->GetPrimaryFrame(), content);
+        }
+      }
+      nsPresContext *context = nsContentUtils::GetContextForContent(content);
+      if (!context) {
+        context = mPresContext;
+      }
+      tmpStatus = nsEventStatus_eIgnore;
+      nsEventDispatcher::Dispatch(targetPtr, context,
+                                  &newEvent, nullptr, &tmpStatus, aEventCB);
+      if (nsEventStatus_eConsumeNoDefault == tmpStatus) {
+        preventDefault = true;
+      }
       if (contentPresShell) {
-        //XXXsmaug huge hack. Pushing possibly capturing content,
-        //         even though event target is something else.
-        contentPresShell->PushCurrentEventInfo(
-            content->GetPrimaryFrame(), content);
+        contentPresShell->PopCurrentEventInfo();
+      }
+    }
+  } else {
+    // touchevents need to have the target attribute set on each touch
+    for (uint32_t i = 0; i < touchEvent->touches.Length(); ++i) {
+      nsIDOMTouch *touch = touchEvent->touches[i];
+      if (touch->mChanged) {
+        touch->SetTarget(mCurrentEventContent);
       }
     }
-    nsPresContext *context = nsContentUtils::GetContextForContent(content);
-    tmpStatus = nsEventStatus_eIgnore;
-    nsEventDispatcher::Dispatch(targetPtr, context,
-                                &newEvent, nullptr, &tmpStatus, aEventCB);
+
+    if (mCurrentEventContent) {
+      nsEventDispatcher::Dispatch(mCurrentEventContent, mPresContext,
+                                  aEvent, nullptr, &tmpStatus, aEventCB);
+    } else {
+      nsCOMPtr<nsIContent> targetContent;
+      rv = mCurrentEventFrame->GetContentForEvent(aEvent,
+                                                  getter_AddRefs(targetContent));
+      if (NS_SUCCEEDED(rv) && targetContent) {
+        nsEventDispatcher::Dispatch(targetContent, mPresContext, aEvent,
+                                    nullptr, &tmpStatus, aEventCB);
+      } else if (mDocument) {
+        nsEventDispatcher::Dispatch(mDocument, mPresContext, aEvent,
+                                    nullptr, &tmpStatus, nullptr);
+      }
+    }
     if (nsEventStatus_eConsumeNoDefault == tmpStatus) {
       preventDefault = true;
     }
 
-    if (contentPresShell) {
-      contentPresShell->PopCurrentEventInfo();
+    if (touchEvent->touches.Length() == 1) {
+      gPreventMouseEvents = false;
     }
   }
 
   // if preventDefault was called on any of the events dispatched
   // and this is touchstart, or the first touchmove, widget should consume
   // other events that would be associated with this touch session
   if (preventDefault && canPrevent) {
     gPreventMouseEvents = true;