Bug 563878. Part 11. Rework the synth mouse move code. r=mats
authorTimothy Nikkel <tnikkel@gmail.com>
Sun, 18 Jul 2010 21:23:47 -0500
changeset 47898 a85ea14c92bff2342a66e0e242a12a03f247fb43
parent 47897 712cbadfd66136f7efa58f780cc76a19cde17be8
child 47899 8f2143a0e3d0cd3995028721eabfd46c0e798d0a
push idunknown
push userunknown
push dateunknown
reviewersmats
bugs563878
milestone2.0b2pre
Bug 563878. Part 11. Rework the synth mouse move code. r=mats
layout/base/nsPresShell.cpp
view/src/nsViewManager.cpp
view/src/nsViewManager.h
--- a/layout/base/nsPresShell.cpp
+++ b/layout/base/nsPresShell.cpp
@@ -4416,19 +4416,18 @@ nsresult PresShell::GetLinkLocation(nsID
 }
 
 NS_IMETHODIMP_(void)
 PresShell::DispatchSynthMouseMove(nsGUIEvent *aEvent,
                                   PRBool aFlushOnHoverChange)
 {
   PRUint32 hoverGenerationBefore = mFrameConstructor->GetHoverGeneration();
   nsEventStatus status;
-  nsIView* targetView;
-  targetView = nsIView::GetViewFor(aEvent->widget);
-  mViewManager->DispatchEvent(aEvent, targetView, &status);
+  nsIView* targetView = nsIView::GetViewFor(aEvent->widget);
+  targetView->GetViewManager()->DispatchEvent(aEvent, targetView, &status);
   if (aFlushOnHoverChange &&
       hoverGenerationBefore != mFrameConstructor->GetHoverGeneration()) {
     // Flush so that the resulting reflow happens now so that our caller
     // can suppress any synthesized mouse moves caused by that reflow.
     FlushPendingNotifications(Flush_Layout);
   }
 }
 
--- a/view/src/nsViewManager.cpp
+++ b/view/src/nsViewManager.cpp
@@ -938,31 +938,33 @@ NS_IMETHODIMP nsViewManager::DispatchEve
 
         if (NS_IsEventUsingCoordinates(aEvent)) {
           // will dispatch using coordinates. Pretty bogus but it's consistent
           // with what presshell does.
           view = GetDisplayRootFor(baseView);
         }
 
         if (nsnull != view) {
-          PRInt32 p2a = AppUnitsPerDevPixel();
+          PRInt32 APD = AppUnitsPerDevPixel();
 
           if ((aEvent->message == NS_MOUSE_MOVE &&
                static_cast<nsMouseEvent*>(aEvent)->reason ==
                  nsMouseEvent::eReal) ||
               aEvent->message == NS_MOUSE_ENTER ||
               aEvent->message == NS_MOUSE_BUTTON_DOWN ||
               aEvent->message == NS_MOUSE_BUTTON_UP) {
-            // aEvent->point is relative to the widget, i.e. the view top-left,
-            // so we need to add the offset to the view origin
-            nsPoint rootOffset = baseView->GetDimensions().TopLeft();
-            rootOffset += baseView->GetOffsetTo(RootViewManager()->mRootView);
-            RootViewManager()->mMouseLocation = aEvent->refPoint +
-                nsIntPoint(NSAppUnitsToIntPixels(rootOffset.x, p2a),
-                           NSAppUnitsToIntPixels(rootOffset.y, p2a));
+            // aEvent->point is relative to the widget, so we convert it to be
+            // relative to the view origin
+            nsPoint pt = -baseView->ViewToWidgetOffset();
+            pt += baseView->GetOffsetTo(RootViewManager()->mRootView);
+            pt.x += NSIntPixelsToAppUnits(aEvent->refPoint.x, APD);
+            pt.y += NSIntPixelsToAppUnits(aEvent->refPoint.y, APD);
+            PRInt32 rootAPD = RootViewManager()->AppUnitsPerDevPixel();
+            pt = pt.ConvertAppUnits(APD, rootAPD);
+            RootViewManager()->mMouseLocation = pt;
 #ifdef DEBUG_MOUSE_LOCATION
             if (aEvent->message == NS_MOUSE_ENTER)
               printf("[vm=%p]got mouse enter for %p\n",
                      this, aEvent->widget);
             printf("[vm=%p]setting mouse location to (%d,%d)\n",
                    this, mMouseLocation.x, mMouseLocation.y);
 #endif
             if (aEvent->message == NS_MOUSE_ENTER)
@@ -970,17 +972,18 @@ NS_IMETHODIMP nsViewManager::DispatchEve
           } else if (aEvent->message == NS_MOUSE_EXIT) {
             // Although we only care about the mouse moving into an area
             // for which this view manager doesn't receive mouse move
             // events, we don't check which view the mouse exit was for
             // since this seems to vary by platform.  Hopefully this
             // won't matter at all since we'll get the mouse move or
             // enter after the mouse exit when the mouse moves from one
             // of our widgets into another.
-            RootViewManager()->mMouseLocation = nsIntPoint(NSCOORD_NONE, NSCOORD_NONE);
+            RootViewManager()->mMouseLocation =
+              nsPoint(NSCOORD_NONE, NSCOORD_NONE);
 #ifdef DEBUG_MOUSE_LOCATION
             printf("[vm=%p]got mouse exit for %p\n",
                    this, aEvent->widget);
             printf("[vm=%p]clearing mouse location\n",
                    this);
 #endif
           }
 
@@ -1649,17 +1652,17 @@ private:
 };
 
 NS_IMETHODIMP
 nsViewManager::SynthesizeMouseMove(PRBool aFromScroll)
 {
   if (!IsRootVM())
     return RootViewManager()->SynthesizeMouseMove(aFromScroll);
 
-  if (mMouseLocation == nsIntPoint(NSCOORD_NONE, NSCOORD_NONE))
+  if (mMouseLocation == nsPoint(NSCOORD_NONE, NSCOORD_NONE))
     return NS_OK;
 
   if (!mSynthMouseMoveEvent.IsPending()) {
     nsRefPtr<nsViewManagerEvent> ev =
         new nsSynthMouseMoveEvent(this, aFromScroll);
 
     if (NS_FAILED(NS_DispatchToCurrentThread(ev))) {
       NS_WARNING("failed to dispatch nsSynthMouseMoveEvent");
@@ -1686,17 +1689,17 @@ nsViewManager::SynthesizeMouseMove(PRBoo
  */
 static nsView* FindFloatingViewContaining(nsView* aView, nsPoint aPt)
 {
   if (aView->GetVisibility() == nsViewVisibility_kHide)
     // No need to look into descendants.
     return nsnull;
 
   for (nsView* v = aView->GetFirstChild(); v; v = v->GetNextSibling()) {
-    nsView* r = FindFloatingViewContaining(v, aPt - v->GetOffsetTo(aView));
+    nsView* r = FindFloatingViewContaining(v, v->ConvertFromParentCoords(aPt));
     if (r)
       return r;
   }
 
   if (aView->GetFloating() && aView->HasWidget() &&
       aView->GetDimensions().Contains(aPt))
     return aView;
     
@@ -1715,17 +1718,17 @@ static nsView* FindFloatingViewContainin
 static nsView* FindViewContaining(nsView* aView, nsPoint aPt)
 {
   if (!aView->GetDimensions().Contains(aPt) ||
       aView->GetVisibility() == nsViewVisibility_kHide) {
     return nsnull;
   }
 
   for (nsView* v = aView->GetFirstChild(); v; v = v->GetNextSibling()) {
-    nsView* r = FindViewContaining(v, aPt - v->GetOffsetTo(aView));
+    nsView* r = FindViewContaining(v, v->ConvertFromParentCoords(aPt));
     if (r)
       return r;
   }
 
   return aView;
 }
 
 void
@@ -1733,53 +1736,60 @@ nsViewManager::ProcessSynthMouseMoveEven
 {
   // allow new event to be posted while handling this one only if the
   // source of the event is a scroll (to prevent infinite reflow loops)
   if (aFromScroll)
     mSynthMouseMoveEvent.Forget();
 
   NS_ASSERTION(IsRootVM(), "Only the root view manager should be here");
 
-  if (mMouseLocation == nsIntPoint(NSCOORD_NONE, NSCOORD_NONE) || !mRootView) {
+  if (mMouseLocation == nsPoint(NSCOORD_NONE, NSCOORD_NONE) || !mRootView) {
     mSynthMouseMoveEvent.Forget();
     return;
   }
 
   // Hold a ref to ourselves so DispatchEvent won't destroy us (since
   // we need to access members after we call DispatchEvent).
   nsCOMPtr<nsIViewManager> kungFuDeathGrip(this);
   
 #ifdef DEBUG_MOUSE_LOCATION
   printf("[vm=%p]synthesizing mouse move to (%d,%d)\n",
          this, mMouseLocation.x, mMouseLocation.y);
 #endif
-                                                       
-  nsPoint pt;
-  PRInt32 p2a = AppUnitsPerDevPixel();
-  pt.x = NSIntPixelsToAppUnits(mMouseLocation.x, p2a);
-  pt.y = NSIntPixelsToAppUnits(mMouseLocation.y, p2a);
+
+  PRInt32 APD = AppUnitsPerDevPixel();
+
+  // this will be mMouseLocation relative to the widget of |view|, the widget
+  // we will put in the event we dispatch, in viewAPD appunits
+  nsPoint refpoint(0, 0);
+  PRInt32 viewAPD;
+  // the VM of the view the point is in
+  nsViewManager *pointVM;
+
   // This could be a bit slow (traverses entire view hierarchy)
   // but it's OK to do it once per synthetic mouse event
-  nsView* view = FindFloatingViewContaining(mRootView, pt);
-  nsIntPoint offset(0, 0);
-  nsViewManager *pointVM;
+  nsView* view = FindFloatingViewContaining(mRootView, mMouseLocation);
   if (!view) {
     view = mRootView;
-    nsView *pointView = FindViewContaining(mRootView, pt);
+    nsView *pointView = FindViewContaining(mRootView, mMouseLocation);
     // pointView can be null in situations related to mouse capture
     pointVM = (pointView ? pointView : view)->GetViewManager();
+    refpoint = mMouseLocation + mRootView->ViewToWidgetOffset();
+    viewAPD = APD;
   } else {
-    nsPoint viewoffset = view->GetOffsetTo(mRootView);
-    offset.x = NSAppUnitsToIntPixels(viewoffset.x, p2a);
-    offset.y = NSAppUnitsToIntPixels(viewoffset.y, p2a);
     pointVM = view->GetViewManager();
+    viewAPD = pointVM->AppUnitsPerDevPixel();
+    refpoint = mMouseLocation.ConvertAppUnits(APD, viewAPD);
+    refpoint -= view->GetOffsetTo(mRootView);
+    refpoint += view->ViewToWidgetOffset();
   }
+  NS_ASSERTION(view->GetWidget(), "view should have a widget here");
   nsMouseEvent event(PR_TRUE, NS_MOUSE_MOVE, view->GetWidget(),
                      nsMouseEvent::eSynthesized);
-  event.refPoint = mMouseLocation - offset;
+  event.refPoint = refpoint.ToNearestPixels(viewAPD);
   event.time = PR_IntervalNow();
   // XXX set event.isShift, event.isControl, event.isAlt, event.isMeta ?
 
   nsCOMPtr<nsIViewObserver> observer = pointVM->GetViewObserver();
   if (observer) {
     observer->DispatchSynthMouseMove(&event, !aFromScroll);
   }
 
--- a/view/src/nsViewManager.h
+++ b/view/src/nsViewManager.h
@@ -265,17 +265,18 @@ public: // NOT in nsIViewManager, so pri
   PRInt32 AppUnitsPerDevPixel() const
   {
     return mContext->AppUnitsPerDevPixel();
   }
 
 private:
   nsCOMPtr<nsIDeviceContext> mContext;
   nsIViewObserver   *mObserver;
-  nsIntPoint        mMouseLocation; // device units, relative to mRootView
+  // relative to mRootView and set only on the root view manager
+  nsPoint           mMouseLocation;
 
   // The size for a resize that we delayed until the root view becomes
   // visible again.
   nsSize            mDelayedResize;
 
   nsCOMPtr<nsIFactory> mRegionFactory;
   nsView            *mRootView;
   // mRootViewManager is a strong ref unless it equals |this|.  It's