From 95281be87c3627b13128c8a3d8d338b6697d2164 Mon Sep 17 00:00:00 2001 From: Henri Sivonen Date: Tue, 9 Apr 2019 10:26:31 +0000 Subject: [PATCH] Bug 1532901 - Fix event.screenX and event.screenY inside out-of-process iframes. r=nika Differential Revision: https://phabricator.services.mozilla.com/D25582 --HG-- extra : moz-landing-system : lando --- dom/events/Event.cpp | 15 +++++++++++++-- dom/ipc/PBrowser.ipdl | 4 +++- dom/ipc/TabChild.cpp | 15 +++++++++++++++ dom/ipc/TabChild.h | 9 +++++++++ dom/ipc/TabParent.cpp | 4 ++++ widget/PuppetWidget.cpp | 9 +++++++++ widget/PuppetWidget.h | 7 +++++++ widget/nsIWidget.h | 20 ++++++++++++++++++++ 8 files changed, 80 insertions(+), 3 deletions(-) diff --git a/dom/events/Event.cpp b/dom/events/Event.cpp index dcb3f53039da..3fa7025e466e 100644 --- a/dom/events/Event.cpp +++ b/dom/events/Event.cpp @@ -529,8 +529,19 @@ CSSIntPoint Event::GetScreenCoords(nsPresContext* aPresContext, return CSSIntPoint(aPoint.x, aPoint.y); } + // (Potentially) transform the point from the coordinate space of an + // out-of-process iframe to the coordinate space of the native + // window. The transform can only be applied to a point whose components + // are floating-point values, so convert the integer point first, then + // transform, and then round the result back to an integer point. + LayoutDevicePoint floatPoint(aPoint); + LayoutDevicePoint topLevelPoint = + guiEvent->mWidget->WidgetToTopLevelWidgetTransform().TransformPoint( + floatPoint); + LayoutDeviceIntPoint rounded = RoundedToInt(topLevelPoint); + nsPoint pt = LayoutDevicePixel::ToAppUnits( - aPoint, + rounded, aPresContext->DeviceContext()->AppUnitsPerDevPixelAtUnitFullZoom()); if (PresShell* presShell = aPresContext->GetPresShell()) { @@ -539,7 +550,7 @@ CSSIntPoint Event::GetScreenCoords(nsPresContext* aPresContext, } pt += LayoutDevicePixel::ToAppUnits( - guiEvent->mWidget->WidgetToScreenOffset(), + guiEvent->mWidget->TopLevelWidgetToScreenOffset(), aPresContext->DeviceContext()->AppUnitsPerDevPixelAtUnitFullZoom()); return CSSPixel::FromAppUnitsRounded(pt); diff --git a/dom/ipc/PBrowser.ipdl b/dom/ipc/PBrowser.ipdl index 103fd83895a5..f3a245de44ea 100644 --- a/dom/ipc/PBrowser.ipdl +++ b/dom/ipc/PBrowser.ipdl @@ -32,7 +32,7 @@ include "mozilla/layers/LayersMessageUtils.h"; using class IPC::Principal from "mozilla/dom/PermissionMessageUtils.h"; using moveonly mozilla::gfx::PaintFragment from "mozilla/gfx/CrossProcessPaint.h"; -using mozilla::gfx::Matrix from "mozilla/gfx/Matrix.h"; +using mozilla::gfx::Matrix4x4 from "mozilla/gfx/Matrix.h"; using mozilla::gfx::SurfaceFormat from "mozilla/gfx/Types.h"; using mozilla::LayoutDeviceIntPoint from "Units.h"; using mozilla::LayoutDevicePoint from "Units.h"; @@ -643,6 +643,8 @@ child: async SizeModeChanged(nsSizeMode sizeMode); + async ChildToParentMatrix(Matrix4x4 aMatrix); + async ParentActivated(bool aActivated); async SetKeyboardIndicators(UIStateChangeType showAccelerators, diff --git a/dom/ipc/TabChild.cpp b/dom/ipc/TabChild.cpp index e7cebe64d6e7..6552c81d30eb 100644 --- a/dom/ipc/TabChild.cpp +++ b/dom/ipc/TabChild.cpp @@ -1216,6 +1216,13 @@ mozilla::ipc::IPCResult TabChild::RecvSizeModeChanged( return IPC_OK(); } +mozilla::ipc::IPCResult TabChild::RecvChildToParentMatrix( + const mozilla::gfx::Matrix4x4& aMatrix) { + mChildToParentConversionMatrix = + Some(LayoutDeviceToLayoutDeviceMatrix4x4::FromUnknownMatrix(aMatrix)); + return IPC_OK(); +} + bool TabChild::UpdateFrame(const RepaintRequest& aRequest) { return TabChildBase::UpdateFrameHandler(aRequest); } @@ -1456,6 +1463,14 @@ void TabChild::ProcessPendingCoalescedMouseDataAndDispatchEvents() { } } +LayoutDeviceToLayoutDeviceMatrix4x4 TabChild::GetChildToParentConversionMatrix() const { + if (mChildToParentConversionMatrix) { + return *mChildToParentConversionMatrix; + } + LayoutDevicePoint offset(GetChromeOffset()); + return LayoutDeviceToLayoutDeviceMatrix4x4::Translation(offset); +} + void TabChild::FlushAllCoalescedMouseData() { MOZ_ASSERT(mCoalesceMouseMoveEvents); diff --git a/dom/ipc/TabChild.h b/dom/ipc/TabChild.h index c4ab3b875976..7de7cb1cb7db 100644 --- a/dom/ipc/TabChild.h +++ b/dom/ipc/TabChild.h @@ -312,6 +312,9 @@ class TabChild final : public TabChildBase, virtual mozilla::ipc::IPCResult RecvSizeModeChanged( const nsSizeMode& aSizeMode) override; + virtual mozilla::ipc::IPCResult RecvChildToParentMatrix( + const mozilla::gfx::Matrix4x4& aMatrix) override; + mozilla::ipc::IPCResult RecvActivate(); mozilla::ipc::IPCResult RecvDeactivate(); @@ -637,6 +640,10 @@ class TabChild final : public TabChildBase, // The HANDLE object for the widget this TabChild in. WindowsHandle WidgetNativeData() { return mWidgetNativeData; } + // The transform from the coordinate space of this TabChild to the coordinate + // space of the native window its TabParent is in. + mozilla::LayoutDeviceToLayoutDeviceMatrix4x4 GetChildToParentConversionMatrix() const; + // Prepare to dispatch all coalesced mousemove events. We'll move all data // in mCoalescedMouseData to a nsDeque; then we start processing them. We // can't fetch the coalesced event one by one and dispatch it because we may @@ -905,6 +912,8 @@ class TabChild final : public TabChildBase, WindowsHandle mWidgetNativeData; + Maybe mChildToParentConversionMatrix; + // This state is used to keep track of the current visible tabs (the ones // rendering layers). There may be more than one if there are multiple browser // windows open, or tabs are being warmed up. There may be none if this diff --git a/dom/ipc/TabParent.cpp b/dom/ipc/TabParent.cpp index 51e4bdd6c2ac..7e41d93cf339 100644 --- a/dom/ipc/TabParent.cpp +++ b/dom/ipc/TabParent.cpp @@ -2062,6 +2062,10 @@ TabParent::GetChildToParentConversionMatrix() { void TabParent::SetChildToParentConversionMatrix( const LayoutDeviceToLayoutDeviceMatrix4x4& aMatrix) { mChildToParentConversionMatrix = Some(aMatrix); + if (mIsDestroyed) { + return; + } + mozilla::Unused << SendChildToParentMatrix(aMatrix.ToUnknownMatrix()); } LayoutDeviceIntPoint TabParent::GetChildProcessOffset() { diff --git a/widget/PuppetWidget.cpp b/widget/PuppetWidget.cpp index 9b0ddb74e2b4..939aaf01d494 100644 --- a/widget/PuppetWidget.cpp +++ b/widget/PuppetWidget.cpp @@ -286,6 +286,15 @@ void PuppetWidget::Invalidate(const LayoutDeviceIntRect& aRect) { } } +mozilla::LayoutDeviceToLayoutDeviceMatrix4x4 +PuppetWidget::WidgetToTopLevelWidgetTransform() { + if (!GetOwningTabChild()) { + NS_WARNING("PuppetWidget without Tab does not have transform information."); + return mozilla::LayoutDeviceToLayoutDeviceMatrix4x4(); + } + return GetOwningTabChild()->GetChildToParentConversionMatrix(); +} + void PuppetWidget::InitEvent(WidgetGUIEvent& aEvent, LayoutDeviceIntPoint* aPoint) { if (nullptr == aPoint) { diff --git a/widget/PuppetWidget.h b/widget/PuppetWidget.h index 351fd61dac30..9cda6011849f 100644 --- a/widget/PuppetWidget.h +++ b/widget/PuppetWidget.h @@ -129,10 +129,17 @@ class PuppetWidget : public nsBaseWidget, return NS_ERROR_UNEXPECTED; } + virtual mozilla::LayoutDeviceToLayoutDeviceMatrix4x4 + WidgetToTopLevelWidgetTransform() override; + virtual LayoutDeviceIntPoint WidgetToScreenOffset() override { return GetWindowPosition() + GetChromeOffset(); } + virtual LayoutDeviceIntPoint TopLevelWidgetToScreenOffset() override { + return GetWindowPosition(); + } + int32_t RoundsWidgetCoordinatesTo() override; void InitEvent(WidgetGUIEvent& aEvent, diff --git a/widget/nsIWidget.h b/widget/nsIWidget.h index 7b492353711b..56be84064ac6 100644 --- a/widget/nsIWidget.h +++ b/widget/nsIWidget.h @@ -1345,6 +1345,26 @@ class nsIWidget : public nsISupports { */ virtual LayoutDeviceIntPoint WidgetToScreenOffset() = 0; + /** + * The same as WidgetToScreenOffset(), except in the case of + * PuppetWidget where this method omits the chrome offset. + */ + virtual LayoutDeviceIntPoint TopLevelWidgetToScreenOffset() { + return WidgetToScreenOffset(); + } + + /** + * For a PuppetWidget, returns the transform from the coordinate + * space of the PuppetWidget to the coordinate space of the + * top-level native widget. + * + * Identity transform in other cases. + */ + virtual mozilla::LayoutDeviceToLayoutDeviceMatrix4x4 + WidgetToTopLevelWidgetTransform() { + return mozilla::LayoutDeviceToLayoutDeviceMatrix4x4(); + } + /** * Given the specified client size, return the corresponding window size, * which includes the area for the borders and titlebar. This method