зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1078029 - Add code to reposition input event coordinates into the target frame. r=roc
The PositionedEventTargeting code allows input events to be dispatched to a target not directly under the input event point. However, the coordinates of the input event can then end up outside the bounding rect of the event target. This state is generally unexpected by web content and may cause compatibility issues. Fennec's front-end code used to deal with this by repositioning the input event coordinates to be inside the bounding rect; now that Fennec is using the shared C++ code we need to have that code here. This behaviour is guarded by a pref and disabled by default (but enabled on Fennec).
This commit is contained in:
Родитель
da1d284214
Коммит
7644286079
|
@ -68,6 +68,7 @@ struct EventRadiusPrefs
|
|||
bool mEnabled;
|
||||
bool mRegistered;
|
||||
bool mTouchOnly;
|
||||
bool mRepositionEventCoords;
|
||||
};
|
||||
|
||||
static EventRadiusPrefs sMouseEventRadiusPrefs;
|
||||
|
@ -111,6 +112,9 @@ GetPrefsFor(EventClassID aEventClassID)
|
|||
} else {
|
||||
prefs->mTouchOnly = false;
|
||||
}
|
||||
|
||||
nsPrintfCString repositionPref("ui.%s.radius.reposition", prefBranch);
|
||||
Preferences::AddBoolVarCache(&prefs->mRepositionEventCoords, repositionPref.get(), false);
|
||||
}
|
||||
|
||||
return prefs;
|
||||
|
@ -360,7 +364,7 @@ GetClosest(nsIFrame* aRoot, const nsPoint& aPointRelativeToRootFrame,
|
|||
}
|
||||
|
||||
nsIFrame*
|
||||
FindFrameTargetedByInputEvent(const WidgetGUIEvent* aEvent,
|
||||
FindFrameTargetedByInputEvent(WidgetGUIEvent* aEvent,
|
||||
nsIFrame* aRootFrame,
|
||||
const nsPoint& aPointRelativeToRootFrame,
|
||||
uint32_t aFlags)
|
||||
|
@ -403,7 +407,38 @@ FindFrameTargetedByInputEvent(const WidgetGUIEvent* aEvent,
|
|||
nsIFrame* closestClickable =
|
||||
GetClosest(aRootFrame, aPointRelativeToRootFrame, targetRect, prefs,
|
||||
restrictToDescendants, candidates);
|
||||
return closestClickable ? closestClickable : target;
|
||||
if (closestClickable) {
|
||||
target = closestClickable;
|
||||
}
|
||||
|
||||
if (!target || !prefs->mRepositionEventCoords) {
|
||||
// No repositioning required for this event
|
||||
return target;
|
||||
}
|
||||
|
||||
// Take the point relative to the root frame, make it relative to the target,
|
||||
// clamp it to the bounds, and then make it relative to the root frame again.
|
||||
nsPoint point = aPointRelativeToRootFrame;
|
||||
if (nsLayoutUtils::TRANSFORM_SUCCEEDED != nsLayoutUtils::TransformPoint(aRootFrame, target, point)) {
|
||||
return target;
|
||||
}
|
||||
point = target->GetRectRelativeToSelf().ClampPoint(point);
|
||||
if (nsLayoutUtils::TRANSFORM_SUCCEEDED != nsLayoutUtils::TransformPoint(target, aRootFrame, point)) {
|
||||
return target;
|
||||
}
|
||||
// Now we basically undo the operations in GetEventCoordinatesRelativeTo, to
|
||||
// get back the (now-clamped) coordinates in the event's widget's space.
|
||||
nsView* view = aRootFrame->GetView();
|
||||
if (!view) {
|
||||
return target;
|
||||
}
|
||||
nsIntPoint widgetPoint = nsLayoutUtils::TranslateViewToWidget(
|
||||
aRootFrame->PresContext(), view, point, aEvent->widget);
|
||||
if (widgetPoint.x != NS_UNCONSTRAINEDSIZE) {
|
||||
// If that succeeded, we update the point in the event
|
||||
aEvent->refPoint = LayoutDeviceIntPoint::FromUntyped(widgetPoint);
|
||||
}
|
||||
return target;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ enum {
|
|||
* that are suitable targets, to account for inaccurate pointing devices.
|
||||
*/
|
||||
nsIFrame*
|
||||
FindFrameTargetedByInputEvent(const WidgetGUIEvent* aEvent,
|
||||
FindFrameTargetedByInputEvent(WidgetGUIEvent* aEvent,
|
||||
nsIFrame* aRootFrame,
|
||||
const nsPoint& aPointRelativeToRootFrame,
|
||||
uint32_t aFlags = 0);
|
||||
|
|
|
@ -2611,6 +2611,18 @@ static nsIntPoint GetWidgetOffset(nsIWidget* aWidget, nsIWidget*& aRootWidget) {
|
|||
return offset;
|
||||
}
|
||||
|
||||
static nsIntPoint WidgetToWidgetOffset(nsIWidget* aFrom, nsIWidget* aTo) {
|
||||
nsIWidget* fromRoot;
|
||||
nsIntPoint fromOffset = GetWidgetOffset(aFrom, fromRoot);
|
||||
nsIWidget* toRoot;
|
||||
nsIntPoint toOffset = GetWidgetOffset(aTo, toRoot);
|
||||
|
||||
if (fromRoot == toRoot) {
|
||||
return fromOffset - toOffset;
|
||||
}
|
||||
return aFrom->WidgetToScreenOffset() - aTo->WidgetToScreenOffset();
|
||||
}
|
||||
|
||||
nsPoint
|
||||
nsLayoutUtils::TranslateWidgetToView(nsPresContext* aPresContext,
|
||||
nsIWidget* aWidget, nsIntPoint aPt,
|
||||
|
@ -2622,24 +2634,28 @@ nsLayoutUtils::TranslateWidgetToView(nsPresContext* aPresContext,
|
|||
return nsPoint(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE);
|
||||
}
|
||||
|
||||
nsIWidget* fromRoot;
|
||||
nsIntPoint fromOffset = GetWidgetOffset(aWidget, fromRoot);
|
||||
nsIWidget* toRoot;
|
||||
nsIntPoint toOffset = GetWidgetOffset(viewWidget, toRoot);
|
||||
|
||||
nsIntPoint widgetPoint;
|
||||
if (fromRoot == toRoot) {
|
||||
widgetPoint = aPt + fromOffset - toOffset;
|
||||
} else {
|
||||
nsIntPoint screenPoint = aWidget->WidgetToScreenOffset();
|
||||
widgetPoint = aPt + screenPoint - viewWidget->WidgetToScreenOffset();
|
||||
}
|
||||
|
||||
nsIntPoint widgetPoint = aPt + WidgetToWidgetOffset(aWidget, viewWidget);
|
||||
nsPoint widgetAppUnits(aPresContext->DevPixelsToAppUnits(widgetPoint.x),
|
||||
aPresContext->DevPixelsToAppUnits(widgetPoint.y));
|
||||
return widgetAppUnits - viewOffset;
|
||||
}
|
||||
|
||||
nsIntPoint
|
||||
nsLayoutUtils::TranslateViewToWidget(nsPresContext* aPresContext,
|
||||
nsView* aView, nsPoint aPt,
|
||||
nsIWidget* aWidget)
|
||||
{
|
||||
nsPoint viewOffset;
|
||||
nsIWidget* viewWidget = aView->GetNearestWidget(&viewOffset);
|
||||
if (!viewWidget) {
|
||||
return nsIntPoint(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE);
|
||||
}
|
||||
|
||||
nsIntPoint relativeToViewWidget(aPresContext->AppUnitsToDevPixels(aPt.x + viewOffset.x),
|
||||
aPresContext->AppUnitsToDevPixels(aPt.y + viewOffset.y));
|
||||
return relativeToViewWidget + WidgetToWidgetOffset(viewWidget, aWidget);
|
||||
}
|
||||
|
||||
// Combine aNewBreakType with aOrigBreakType, but limit the break types
|
||||
// to NS_STYLE_CLEAR_LEFT, RIGHT, BOTH.
|
||||
uint8_t
|
||||
|
|
|
@ -673,6 +673,18 @@ public:
|
|||
nsIWidget* aWidget, nsIntPoint aPt,
|
||||
nsView* aView);
|
||||
|
||||
/**
|
||||
* Translate from view coordinates to the widget's coordinates.
|
||||
* @param aPresContext the PresContext for the view
|
||||
* @param aView the view
|
||||
* @param aPt the point relative to the view
|
||||
* @param aWidget the widget to which returned coordinates are relative
|
||||
* @return the point in the view's coordinates
|
||||
*/
|
||||
static nsIntPoint TranslateViewToWidget(nsPresContext* aPresContext,
|
||||
nsView* aView, nsPoint aPt,
|
||||
nsIWidget* aWidget);
|
||||
|
||||
enum FrameForPointFlags {
|
||||
/**
|
||||
* When set, paint suppression is ignored, so we'll return non-root page
|
||||
|
|
|
@ -417,6 +417,7 @@ pref("ui.mouse.radius.topmm", 5);
|
|||
pref("ui.mouse.radius.rightmm", 3);
|
||||
pref("ui.mouse.radius.bottommm", 2);
|
||||
pref("ui.mouse.radius.visitedWeight", 120);
|
||||
pref("ui.mouse.radius.reposition", true);
|
||||
|
||||
// The percentage of the screen that needs to be scrolled before margins are exposed.
|
||||
pref("browser.ui.show-margins-threshold", 10);
|
||||
|
|
Загрузка…
Ссылка в новой задаче