nsIFrame* FindFrameTargetedByInputEvent(const WidgetGUIEvent* aEvent, nsIFrame* aRootFrame, const nsPoint& aPointRelativeToRootFrame, uint32_t aFlags) { uint32_t flags = (aFlags & INPUT_IGNORE_ROOT_SCROLL_FRAME) ? nsLayoutUtils::IGNORE_ROOT_SCROLL_FRAME : 0; nsIFrame* target = nsLayoutUtils::GetFrameForPoint(aRootFrame, aPointRelativeToRootFrame, flags); const EventRadiusPrefs* prefs = GetPrefsFor(aEvent->eventStructType); if (!prefs || !prefs->mEnabled || (target && IsElementClickable(target, nsGkAtoms::body))) { return target; } // Do not modify targeting for actual mouse hardware; only for mouse // events generated by touch-screen hardware. if (aEvent->eventStructType == NS_MOUSE_EVENT && prefs->mTouchOnly && aEvent->AsMouseEvent()->inputSource != nsIDOMMouseEvent::MOZ_SOURCE_TOUCH) { return target; } // If the exact target is non-null, only consider candidate targets in the same // document as the exact target. Otherwise, if an ancestor document has // a mouse event handler for example, targets that are !IsElementClickable can // never be targeted --- something nsSubDocumentFrame in an ancestor document // would be targeted instead. nsIFrame* restrictToDescendants = target ? target->PresContext()->PresShell()->GetRootFrame() : aRootFrame; nsRect targetRect = GetTargetRect(aRootFrame, aPointRelativeToRootFrame, restrictToDescendants, prefs); nsAutoTArray<nsIFrame*,8> candidates; nsresult rv = nsLayoutUtils::GetFramesForArea(aRootFrame, targetRect, candidates, flags); if (NS_FAILED(rv)) { return target; } nsIFrame* closestClickable = GetClosest(aRootFrame, aPointRelativeToRootFrame, targetRect, prefs, restrictToDescendants, candidates); return closestClickable ? closestClickable : target; }
nsIFrame* FindFrameTargetedByInputEvent(WidgetGUIEvent* aEvent, nsIFrame* aRootFrame, const nsPoint& aPointRelativeToRootFrame, uint32_t aFlags) { uint32_t flags = (aFlags & INPUT_IGNORE_ROOT_SCROLL_FRAME) ? nsLayoutUtils::IGNORE_ROOT_SCROLL_FRAME : 0; nsIFrame* target = nsLayoutUtils::GetFrameForPoint(aRootFrame, aPointRelativeToRootFrame, flags); PET_LOG("Found initial target %p for event class %s point %s relative to root frame %p\n", target, (aEvent->mClass == eMouseEventClass ? "mouse" : (aEvent->mClass == eTouchEventClass ? "touch" : "other")), mozilla::layers::Stringify(aPointRelativeToRootFrame).c_str(), aRootFrame); const EventRadiusPrefs* prefs = GetPrefsFor(aEvent->mClass); if (!prefs || !prefs->mEnabled) { PET_LOG("Retargeting disabled\n"); return target; } nsIContent* clickableAncestor = nullptr; if (target) { clickableAncestor = GetClickableAncestor(target, nsGkAtoms::body); if (clickableAncestor) { if (!IsElementClickableAndReadable(target, aEvent, prefs)) { aEvent->AsMouseEventBase()->hitCluster = true; } PET_LOG("Target %p is clickable\n", target); // If the target that was directly hit has a clickable ancestor, that // means it too is clickable. And since it is the same as or a descendant // of clickableAncestor, it should become the root for the GetClosest // search. clickableAncestor = target->GetContent(); } } // Do not modify targeting for actual mouse hardware; only for mouse // events generated by touch-screen hardware. if (aEvent->mClass == eMouseEventClass && prefs->mTouchOnly && aEvent->AsMouseEvent()->inputSource != nsIDOMMouseEvent::MOZ_SOURCE_TOUCH) { PET_LOG("Mouse input event is not from a touch source\n"); return target; } // If the exact target is non-null, only consider candidate targets in the same // document as the exact target. Otherwise, if an ancestor document has // a mouse event handler for example, targets that are !GetClickableAncestor can // never be targeted --- something nsSubDocumentFrame in an ancestor document // would be targeted instead. nsIFrame* restrictToDescendants = target ? target->PresContext()->PresShell()->GetRootFrame() : aRootFrame; nsRect targetRect = GetTargetRect(aRootFrame, aPointRelativeToRootFrame, restrictToDescendants, prefs, aFlags); PET_LOG("Expanded point to target rect %s\n", mozilla::layers::Stringify(targetRect).c_str()); AutoTArray<nsIFrame*,8> candidates; nsresult rv = nsLayoutUtils::GetFramesForArea(aRootFrame, targetRect, candidates, flags); if (NS_FAILED(rv)) { return target; } int32_t elementsInCluster = 0; nsIFrame* closestClickable = GetClosest(aRootFrame, aPointRelativeToRootFrame, targetRect, prefs, restrictToDescendants, clickableAncestor, candidates, &elementsInCluster); if (closestClickable) { if ((prefs->mTouchClusterDetectionEnabled && elementsInCluster > 1) || (!IsElementClickableAndReadable(closestClickable, aEvent, prefs))) { if (aEvent->mClass == eMouseEventClass) { WidgetMouseEventBase* mouseEventBase = aEvent->AsMouseEventBase(); mouseEventBase->hitCluster = true; } } target = closestClickable; } PET_LOG("Final target is %p\n", target); // Uncomment this to dump the frame tree to help with debugging. // Note that dumping the frame tree at the top of the function may flood // logcat on Android devices and cause the PET_LOGs to get dropped. // aRootFrame->DumpFrameTree(); 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; } LayoutDeviceIntPoint widgetPoint = nsLayoutUtils::TranslateViewToWidget( aRootFrame->PresContext(), view, point, aEvent->mWidget); if (widgetPoint.x != NS_UNCONSTRAINEDSIZE) { // If that succeeded, we update the point in the event aEvent->refPoint = widgetPoint; } return target; }