Bug 459604: add an optional parameter to SendMouseEvent to ignore the scroll frame, r+sr=roc
authorGavin Sharp <gavin@mozilla.com>
Mon, 27 Oct 2008 16:16:23 -0400
changeset 20863 7b456bc0eb3071a29b670109b43ee9ef968cc49c
parent 20862 653cd7bf1bb4005dacd8e462d5a246a986012df7
child 20864 1e477902f74dc12400427bd021aa612107f43fde
push id3207
push usergsharp@mozilla.com
push dateMon, 27 Oct 2008 20:17:05 +0000
treeherdermozilla-central@7b456bc0eb30 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs459604
milestone1.9.1b2pre
Bug 459604: add an optional parameter to SendMouseEvent to ignore the scroll frame, r+sr=roc
dom/public/idl/base/nsIDOMWindowUtils.idl
dom/src/base/nsDOMWindowUtils.cpp
layout/base/nsLayoutUtils.cpp
layout/base/nsLayoutUtils.h
layout/base/nsPresShell.cpp
widget/public/nsGUIEvent.h
--- a/dom/public/idl/base/nsIDOMWindowUtils.idl
+++ b/dom/public/idl/base/nsIDOMWindowUtils.idl
@@ -42,17 +42,17 @@
  * to the current nsIDOMWindow.  Some of the methods may require
  * elevated privileges; the method implementations should contain the
  * necessary security checks.  Access this interface by calling
  * getInterface on a DOMWindow.
  */
 
 interface nsIDOMElement;
 
-[scriptable, uuid(3fe733aa-823b-443a-9945-b02f973ab439)]
+[scriptable, uuid(6db7b95f-0a35-4c16-ac50-094adb3372f9)]
 interface nsIDOMWindowUtils : nsISupports {
 
   /**
    * Image animation mode of the window. When this attribute's value
    * is changed, the implementation should set all images in the window
    * to the given value. That is, when set to kDontAnimMode, all images
    * will stop animating. The attribute's value must be one of the
    * animationMode values from imgIContainer.
@@ -114,23 +114,26 @@ interface nsIDOMWindowUtils : nsISupport
    * privileges.
    *
    * @param aType event type
    * @param aX x offset
    * @param aY y offset
    * @param aButton button to synthesize
    * @param aClickCount number of clicks that have been performed
    * @param aModifiers modifiers pressed, using constants defined in nsIDOMNSEvent
+   * @param aIgnoreScrollFrame whether the event should ignore viewport bounds
+   *                           during dispatch
    */
   void sendMouseEvent(in AString aType,
                       in long aX,
                       in long aY,
                       in long aButton,
                       in long aClickCount,
-                      in long aModifiers);
+                      in long aModifiers,
+                      [optional] in boolean aIgnoreScrollFrame);
 
   /** Synthesize a mouse scroll event for a window. The event types supported
    *  are: 
    *    DOMMouseScroll
    *    MozMousePixelScroll
    *
    * Events are sent in coordinates offset by aX and aY from the window.
    *
--- a/dom/src/base/nsDOMWindowUtils.cpp
+++ b/dom/src/base/nsDOMWindowUtils.cpp
@@ -194,17 +194,18 @@ nsDOMWindowUtils::Redraw(PRUint32 aCount
 }
 
 NS_IMETHODIMP
 nsDOMWindowUtils::SendMouseEvent(const nsAString& aType,
                                  PRInt32 aX,
                                  PRInt32 aY,
                                  PRInt32 aButton,
                                  PRInt32 aClickCount,
-                                 PRInt32 aModifiers)
+                                 PRInt32 aModifiers,
+                                 PRBool aIgnoreScrollFrame)
 {
   PRBool hasCap = PR_FALSE;
   if (NS_FAILED(nsContentUtils::GetSecurityManager()->IsCapabilityEnabled("UniversalXPConnect", &hasCap))
       || !hasCap)
     return NS_ERROR_DOM_SECURITY_ERR;
 
   // get the widget to send the event to
   nsCOMPtr<nsIWidget> widget = GetWidget();
@@ -238,16 +239,17 @@ nsDOMWindowUtils::SendMouseEvent(const n
   event.isMeta = (aModifiers & nsIDOMNSEvent::META_MASK) ? PR_TRUE : PR_FALSE;
   event.button = aButton;
   event.widget = widget;
 
   event.clickCount = aClickCount;
   event.time = PR_IntervalNow();
   event.refPoint.x = aX;
   event.refPoint.y = aY;
+  event.ignoreScrollFrame = aIgnoreScrollFrame;
 
   nsEventStatus status;
   return widget->DispatchEvent(&event, status);
 }
 
 NS_IMETHODIMP
 nsDOMWindowUtils::SendMouseScrollEvent(const nsAString& aType,
                                        PRInt32 aX,
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -901,24 +901,34 @@ nsLayoutUtils::IsInitialContainingBlock(
 
 static PRBool gDumpPaintList = PR_FALSE;
 static PRBool gDumpEventList = PR_FALSE;
 static PRBool gDumpRepaintRegionForCopy = PR_FALSE;
 #endif
 
 nsIFrame*
 nsLayoutUtils::GetFrameForPoint(nsIFrame* aFrame, nsPoint aPt,
-                                PRBool aShouldIgnoreSuppression)
+                                PRBool aShouldIgnoreSuppression,
+                                PRBool aIgnoreScrollFrame)
 {
   nsDisplayListBuilder builder(aFrame, PR_TRUE, PR_FALSE);
   nsDisplayList list;
   nsRect target(aPt, nsSize(1, 1));
 
   if (aShouldIgnoreSuppression)
     builder.IgnorePaintSuppression();
+
+  if (aIgnoreScrollFrame) {
+    nsIFrame* rootScrollFrame =
+      aFrame->PresContext()->PresShell()->GetRootScrollFrame();
+    if (rootScrollFrame) {
+      builder.SetIgnoreScrollFrame(rootScrollFrame);
+    }
+  }
+
   builder.EnterPresShell(aFrame, target);
 
   nsresult rv =
     aFrame->BuildDisplayListForStackingContext(&builder, target, &list);
 
   builder.LeavePresShell(aFrame, target);
   NS_ENSURE_SUCCESS(rv, nsnull);
 
--- a/layout/base/nsLayoutUtils.h
+++ b/layout/base/nsLayoutUtils.h
@@ -404,17 +404,18 @@ public:
    * Given aFrame, the root frame of a stacking context, find its descendant
    * frame under the point aPt that receives a mouse event at that location,
    * or nsnull if there is no such frame.
    * @param aPt the point, relative to the frame origin
    * @param aShouldIgnoreSuppression a boolean to control if the display
    * list builder should ignore paint suppression or not
    */
   static nsIFrame* GetFrameForPoint(nsIFrame* aFrame, nsPoint aPt,
-                                    PRBool aShouldIgnoreSuppression = PR_FALSE);
+                                    PRBool aShouldIgnoreSuppression = PR_FALSE,
+                                    PRBool aIgnoreScrollFrame = PR_FALSE);
 
   /**
    * Given a point in the global coordinate space, returns that point expressed
    * in the coordinate system of aFrame.  This effectively inverts all transforms
    * between this point and the root frame.
    *
    * @param aFrame The frame that acts as the coordinate space container.
    * @param aPoint The point, in the global space, to get in the frame-local space.
--- a/layout/base/nsPresShell.cpp
+++ b/layout/base/nsPresShell.cpp
@@ -5648,17 +5648,22 @@ PresShell::HandleEvent(nsIView         *
 #endif
     }
 
     nsPoint eventPoint
         = nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, frame);
     nsIFrame* targetFrame;
     {
       nsAutoDisableGetUsedXAssertions disableAssert;
-      targetFrame = nsLayoutUtils::GetFrameForPoint(frame, eventPoint);
+      PRBool ignoreScrollFrame = PR_FALSE;
+      if (aEvent->eventStructType == NS_MOUSE_EVENT) {
+        ignoreScrollFrame = static_cast<nsMouseEvent*>(aEvent)->ignoreScrollFrame;
+      }
+      targetFrame = nsLayoutUtils::GetFrameForPoint(frame, eventPoint,
+                                                    PR_FALSE, ignoreScrollFrame);
     }
 
     if (targetFrame) {
       PresShell* shell =
           static_cast<PresShell*>(targetFrame->PresContext()->PresShell());
       if (shell != this) {
         // Handle the event in the correct shell.
         // Prevent deletion until we're done with event handling (bug 336582).
--- a/widget/public/nsGUIEvent.h
+++ b/widget/public/nsGUIEvent.h
@@ -490,19 +490,20 @@ protected:
 public:
   nsGUIEvent(PRBool isTrusted, PRUint32 msg, nsIWidget *w)
     : nsEvent(isTrusted, msg, NS_GUI_EVENT),
       widget(w), nativeMsg(nsnull)
   {
   }
 
   /// Originator of the event
-  nsCOMPtr<nsIWidget> widget;           
+  nsCOMPtr<nsIWidget> widget;
+
   /// Internal platform specific message.
-  void* nativeMsg;        
+  void* nativeMsg;
 };
 
 /**
  * Script error event
  */
 
 class nsScriptErrorEvent : public nsEvent
 {
@@ -694,30 +695,30 @@ public:
   enum contextType { eNormal, eContextMenuKey };
   enum exitType    { eChild, eTopLevel };
 
 protected:
   nsMouseEvent(PRBool isTrusted, PRUint32 msg, nsIWidget *w,
                PRUint8 structType, reasonType aReason)
     : nsMouseEvent_base(isTrusted, msg, w, structType),
       acceptActivation(PR_FALSE), reason(aReason), context(eNormal),
-      exit(eChild), clickCount(0)
+      exit(eChild), clickCount(0), ignoreScrollFrame(PR_FALSE)
   {
     if (msg == NS_MOUSE_MOVE) {
       flags |= NS_EVENT_FLAG_CANT_CANCEL;
     }
   }
 
 public:
 
   nsMouseEvent(PRBool isTrusted, PRUint32 msg, nsIWidget *w,
                reasonType aReason, contextType aContext = eNormal)
     : nsMouseEvent_base(isTrusted, msg, w, NS_MOUSE_EVENT),
       acceptActivation(PR_FALSE), reason(aReason), context(aContext),
-      exit(eChild), clickCount(0)
+      exit(eChild), clickCount(0), ignoreScrollFrame(PR_FALSE)
   {
     if (msg == NS_MOUSE_MOVE) {
       flags |= NS_EVENT_FLAG_CANT_CANCEL;
     } else if (msg == NS_CONTEXTMENU) {
       button = (context == eNormal) ? eRightButton : eLeftButton;
     }
   }
 #ifdef NS_DEBUG
@@ -727,16 +728,20 @@ public:
                        ((context == eNormal) ? eRightButton : eLeftButton),
                      "Wrong button set to NS_CONTEXTMENU event?");
   }
 #endif
 
   /// Special return code for MOUSE_ACTIVATE to signal
   /// if the target accepts activation (1), or denies it (0)
   PRPackedBool acceptActivation;
+  // Whether the event should ignore scroll frame bounds
+  // during dispatch.
+  PRPackedBool ignoreScrollFrame;
+
   reasonType   reason : 4;
   contextType  context : 4;
   exitType     exit;
 
   /// The number of mouse clicks
   PRUint32     clickCount;
 };