Bug 1379508: Part 1 - Apply the correct client offsets to remote frameloaders in popup widgets. r?kats draft
authorKris Maglione <maglione.k@gmail.com>
Thu, 13 Jul 2017 15:31:55 -0700
changeset 608640 367512a1947638dd4993e5f5ad9503c0c110374d
parent 606114 bafb677d3d3c40cb824ef591a5bd096291ee373a
child 608641 65b8fa0eb658dea04d1d8d3e509c61ebd06fad9d
push id68357
push usermaglione.k@gmail.com
push dateThu, 13 Jul 2017 23:08:44 +0000
reviewerskats
bugs1379508
milestone56.0a1
Bug 1379508: Part 1 - Apply the correct client offsets to remote frameloaders in popup widgets. r?kats On-screen coordinates for points in remote frameloads are calculated relative to the screen origin of the top-level window, while event coordinates are calculated relative to the nearest widget. Since popups have their own widgets separate from the top-level window, their native client offsets have no particular relation to the origin of the top-level window, and we need to manually calculate them relative to the origin of the top-level widget instead. MozReview-Commit-ID: EDyEyu37XuY
dom/ipc/TabParent.cpp
dom/ipc/TabParent.h
layout/base/nsLayoutUtils.cpp
layout/base/nsLayoutUtils.h
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -729,17 +729,17 @@ TabParent::UpdateDimensions(const nsIntR
   if (!widget) {
     NS_WARNING("No widget found in TabParent::UpdateDimensions");
     return;
   }
 
   hal::ScreenConfiguration config;
   hal::GetCurrentScreenConfiguration(&config);
   ScreenOrientationInternal orientation = config.orientation();
-  LayoutDeviceIntPoint clientOffset = widget->GetClientOffset();
+  LayoutDeviceIntPoint clientOffset = GetClientOffset();
   LayoutDeviceIntPoint chromeOffset = -GetChildProcessOffset();
 
   if (!mUpdatedDimensions || mOrientation != orientation ||
       mDimensions != size || !mRect.IsEqualEdges(rect) ||
       clientOffset != mClientOffset ||
       chromeOffset != mChromeOffset) {
 
     mUpdatedDimensions = true;
@@ -1987,16 +1987,30 @@ TabParent::GetChildProcessOffset()
   nsPoint pt = nsLayoutUtils::GetEventCoordinatesRelativeTo(widget,
                                                             LayoutDeviceIntPoint(0, 0),
                                                             targetFrame);
 
   return LayoutDeviceIntPoint::FromAppUnitsToNearest(
            pt, targetFrame->PresContext()->AppUnitsPerDevPixel());
 }
 
+LayoutDeviceIntPoint
+TabParent::GetClientOffset()
+{
+  nsCOMPtr<nsIWidget> widget = GetWidget();
+  nsCOMPtr<nsIWidget> docWidget = GetDocWidget();
+
+  if (widget == docWidget) {
+    return widget->GetClientOffset();
+  }
+
+  return (docWidget->GetClientOffset() -
+          nsLayoutUtils::WidgetToWidgetOffset(docWidget, widget));
+}
+
 mozilla::ipc::IPCResult
 TabParent::RecvReplyKeyEvent(const WidgetKeyboardEvent& aEvent)
 {
   NS_ENSURE_TRUE(mFrameElement, IPC_OK());
 
   WidgetKeyboardEvent localEvent(aEvent);
   localEvent.MarkAsHandledInRemoteProcess();
 
@@ -2563,16 +2577,25 @@ TabParent::GetWidget() const
   }
   nsCOMPtr<nsIWidget> widget = nsContentUtils::WidgetForContent(mFrameElement);
   if (!widget) {
     widget = nsContentUtils::WidgetForDocument(mFrameElement->OwnerDoc());
   }
   return widget.forget();
 }
 
+already_AddRefed<nsIWidget>
+TabParent::GetDocWidget() const
+{
+  if (!mFrameElement) {
+    return nullptr;
+  }
+  return do_AddRef(nsContentUtils::WidgetForDocument(mFrameElement->OwnerDoc()));
+}
+
 void
 TabParent::ApzAwareEventRoutingToChild(ScrollableLayerGuid* aOutTargetGuid,
                                        uint64_t* aOutInputBlockId,
                                        nsEventStatus* aOutApzResponse)
 {
   // Let the widget know that the event will be sent to the child process,
   // which will (hopefully) send a confirmation notice back to APZ.
   // Do this even if APZ is off since we need it for swipe gesture support on
--- a/dom/ipc/TabParent.h
+++ b/dom/ipc/TabParent.h
@@ -533,24 +533,35 @@ public:
   nsIContentParent* Manager() const { return mManager; }
 
   /**
    * Let managees query if Destroy() is already called so they don't send out
    * messages when the PBrowser actor is being destroyed.
    */
   bool IsDestroyed() const { return mIsDestroyed; }
 
+  // Returns the closest widget for our frameloader's content.
   already_AddRefed<nsIWidget> GetWidget() const;
 
+  // Returns the top-level widget for our frameloader's document.
+  already_AddRefed<nsIWidget> GetDocWidget() const;
+
   const TabId GetTabId() const
   {
     return mTabId;
   }
 
   LayoutDeviceIntPoint GetChildProcessOffset();
+
+  // Returns the offset from the on-screen origin of our top-level window's
+  // widget (including window decorations) to the origin of our frameloader's
+  // nearest widget. This offset is used to translate coordinates from the
+  // PuppetWidget's origin to absolute screen coordinates in the child.
+  LayoutDeviceIntPoint GetClientOffset();
+
   LayoutDevicePoint AdjustTapToChildWidget(const LayoutDevicePoint& aPoint);
 
   /**
    * Native widget remoting protocol for use with windowed plugins with e10s.
    */
   virtual PPluginWidgetParent* AllocPPluginWidgetParent() override;
 
   virtual bool
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -3090,18 +3090,18 @@ static LayoutDeviceIntPoint GetWidgetOff
     LayoutDeviceIntRect bounds = aWidget->GetBounds();
     offset += bounds.TopLeft();
     aWidget = parent;
   }
   aRootWidget = aWidget;
   return offset;
 }
 
-static LayoutDeviceIntPoint
-WidgetToWidgetOffset(nsIWidget* aFrom, nsIWidget* aTo) {
+LayoutDeviceIntPoint
+nsLayoutUtils::WidgetToWidgetOffset(nsIWidget* aFrom, nsIWidget* aTo) {
   nsIWidget* fromRoot;
   LayoutDeviceIntPoint fromOffset = GetWidgetOffset(aFrom, fromRoot);
   nsIWidget* toRoot;
   LayoutDeviceIntPoint toOffset = GetWidgetOffset(aTo, toRoot);
 
   if (fromRoot == toRoot) {
     return fromOffset - toOffset;
   }
--- a/layout/base/nsLayoutUtils.h
+++ b/layout/base/nsLayoutUtils.h
@@ -780,16 +780,19 @@ public:
    * @param aWidget the widget to which returned coordinates are relative
    * @return the point in the view's coordinates
    */
   static mozilla::LayoutDeviceIntPoint
     TranslateViewToWidget(nsPresContext* aPresContext,
                           nsView* aView, nsPoint aPt,
                           nsIWidget* aWidget);
 
+  static mozilla::LayoutDeviceIntPoint
+    WidgetToWidgetOffset(nsIWidget* aFromWidget, nsIWidget* aToWidget);
+
   enum FrameForPointFlags {
     /**
      * When set, paint suppression is ignored, so we'll return non-root page
      * elements even if paint suppression is stopping them from painting.
      */
     IGNORE_PAINT_SUPPRESSION = 0x01,
     /**
      * When set, clipping due to the root scroll frame (and any other viewport-