зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1447993, when handling pointerup while there is pointercapture, do a hit test in order to find the click target, r=masayuki
--HG-- extra : rebase_source : 160ef0aae3922cb32b11476650c15a3f55334691
This commit is contained in:
Родитель
fc6227cd10
Коммит
57fd877895
|
@ -506,7 +506,8 @@ EventStateManager::PreHandleEvent(nsPresContext* aPresContext,
|
|||
WidgetEvent* aEvent,
|
||||
nsIFrame* aTargetFrame,
|
||||
nsIContent* aTargetContent,
|
||||
nsEventStatus* aStatus)
|
||||
nsEventStatus* aStatus,
|
||||
nsIContent* aOverrideClickTarget)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aStatus);
|
||||
NS_ENSURE_ARG(aPresContext);
|
||||
|
@ -655,7 +656,8 @@ EventStateManager::PreHandleEvent(nsPresContext* aPresContext,
|
|||
MOZ_FALLTHROUGH;
|
||||
case WidgetMouseEvent::eRightButton:
|
||||
case WidgetMouseEvent::eMiddleButton:
|
||||
SetClickCount(mouseEvent, aStatus);
|
||||
RefPtr<EventStateManager> esm = ESMFromContentOrThis(aOverrideClickTarget);
|
||||
esm->SetClickCount(mouseEvent, aStatus, aOverrideClickTarget);
|
||||
NotifyTargetUserActivation(aEvent, aTargetContent);
|
||||
break;
|
||||
}
|
||||
|
@ -922,6 +924,26 @@ EventStateManager::NotifyTargetUserActivation(WidgetEvent* aEvent,
|
|||
doc->NotifyUserActivation();
|
||||
}
|
||||
|
||||
already_AddRefed<EventStateManager>
|
||||
EventStateManager::ESMFromContentOrThis(nsIContent* aContent)
|
||||
{
|
||||
if (aContent) {
|
||||
nsIPresShell* shell = aContent->OwnerDoc()->GetShell();
|
||||
if (shell) {
|
||||
nsPresContext* prescontext = shell->GetPresContext();
|
||||
if (prescontext) {
|
||||
RefPtr<EventStateManager> esm = prescontext->EventStateManager();
|
||||
if (esm) {
|
||||
return esm.forget();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RefPtr<EventStateManager> esm = this;
|
||||
return esm.forget();
|
||||
}
|
||||
|
||||
void
|
||||
EventStateManager::HandleQueryContentEvent(WidgetQueryContentEvent* aEvent)
|
||||
{
|
||||
|
@ -3055,7 +3077,8 @@ nsresult
|
|||
EventStateManager::PostHandleEvent(nsPresContext* aPresContext,
|
||||
WidgetEvent* aEvent,
|
||||
nsIFrame* aTargetFrame,
|
||||
nsEventStatus* aStatus)
|
||||
nsEventStatus* aStatus,
|
||||
nsIContent* aOverrideClickTarget)
|
||||
{
|
||||
NS_ENSURE_ARG(aPresContext);
|
||||
NS_ENSURE_ARG_POINTER(aStatus);
|
||||
|
@ -3317,7 +3340,10 @@ EventStateManager::PostHandleEvent(nsPresContext* aPresContext,
|
|||
}
|
||||
// Make sure to dispatch the click even if there is no frame for
|
||||
// the current target element. This is required for Web compatibility.
|
||||
ret = CheckForAndDispatchClick(mouseEvent, aStatus);
|
||||
RefPtr<EventStateManager> esm =
|
||||
ESMFromContentOrThis(aOverrideClickTarget);
|
||||
ret = esm->CheckForAndDispatchClick(mouseEvent, aStatus,
|
||||
aOverrideClickTarget);
|
||||
}
|
||||
|
||||
nsIPresShell *shell = presContext->GetPresShell();
|
||||
|
@ -4786,11 +4812,12 @@ EventStateManager::UpdateDragDataTransfer(WidgetDragEvent* dragEvent)
|
|||
|
||||
nsresult
|
||||
EventStateManager::SetClickCount(WidgetMouseEvent* aEvent,
|
||||
nsEventStatus* aStatus)
|
||||
nsEventStatus* aStatus,
|
||||
nsIContent* aOverrideClickTarget)
|
||||
{
|
||||
nsCOMPtr<nsIContent> mouseContent;
|
||||
nsCOMPtr<nsIContent> mouseContent = aOverrideClickTarget;
|
||||
nsIContent* mouseContentParent = nullptr;
|
||||
if (mCurrentTarget) {
|
||||
if (!mouseContent && mCurrentTarget) {
|
||||
mCurrentTarget->GetContentForEvent(aEvent, getter_AddRefs(mouseContent));
|
||||
}
|
||||
if (mouseContent) {
|
||||
|
@ -4868,7 +4895,8 @@ EventStateManager::InitAndDispatchClickEvent(WidgetMouseEvent* aEvent,
|
|||
nsIPresShell* aPresShell,
|
||||
nsIContent* aMouseTarget,
|
||||
AutoWeakFrame aCurrentTarget,
|
||||
bool aNoContentDispatch)
|
||||
bool aNoContentDispatch,
|
||||
nsIContent* aOverrideClickTarget)
|
||||
{
|
||||
WidgetMouseEvent event(aEvent->IsTrusted(), aMessage,
|
||||
aEvent->mWidget, WidgetMouseEvent::eReal);
|
||||
|
@ -4883,14 +4911,21 @@ EventStateManager::InitAndDispatchClickEvent(WidgetMouseEvent* aEvent,
|
|||
event.button = aEvent->button;
|
||||
event.pointerId = aEvent->pointerId;
|
||||
event.inputSource = aEvent->inputSource;
|
||||
nsIContent* target = aMouseTarget;
|
||||
nsIFrame* targetFrame = aCurrentTarget;
|
||||
if (aOverrideClickTarget) {
|
||||
target = aOverrideClickTarget;
|
||||
targetFrame = aOverrideClickTarget->GetPrimaryFrame();
|
||||
}
|
||||
|
||||
return aPresShell->HandleEventWithTarget(&event, aCurrentTarget,
|
||||
aMouseTarget, aStatus);
|
||||
return aPresShell->HandleEventWithTarget(&event, targetFrame,
|
||||
target, aStatus);
|
||||
}
|
||||
|
||||
nsresult
|
||||
EventStateManager::CheckForAndDispatchClick(WidgetMouseEvent* aEvent,
|
||||
nsEventStatus* aStatus)
|
||||
nsEventStatus* aStatus,
|
||||
nsIContent* aOverrideClickTarget)
|
||||
{
|
||||
nsresult ret = NS_OK;
|
||||
|
||||
|
@ -4920,7 +4955,7 @@ EventStateManager::CheckForAndDispatchClick(WidgetMouseEvent* aEvent,
|
|||
mouseContent = mouseContent->GetParent();
|
||||
}
|
||||
|
||||
if (!mouseContent && !mCurrentTarget) {
|
||||
if (!mouseContent && !mCurrentTarget && !aOverrideClickTarget) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -4928,20 +4963,22 @@ EventStateManager::CheckForAndDispatchClick(WidgetMouseEvent* aEvent,
|
|||
AutoWeakFrame currentTarget = mCurrentTarget;
|
||||
ret = InitAndDispatchClickEvent(aEvent, aStatus, eMouseClick,
|
||||
presShell, mouseContent, currentTarget,
|
||||
notDispatchToContents);
|
||||
notDispatchToContents,
|
||||
aOverrideClickTarget);
|
||||
|
||||
if (NS_SUCCEEDED(ret) && aEvent->mClickCount == 2 &&
|
||||
mouseContent && mouseContent->IsInComposedDoc()) {
|
||||
//fire double click
|
||||
ret = InitAndDispatchClickEvent(aEvent, aStatus, eMouseDoubleClick,
|
||||
presShell, mouseContent, currentTarget,
|
||||
notDispatchToContents);
|
||||
notDispatchToContents,
|
||||
aOverrideClickTarget);
|
||||
}
|
||||
if (NS_SUCCEEDED(ret) && mouseContent && fireAuxClick &&
|
||||
mouseContent->IsInComposedDoc()) {
|
||||
ret = InitAndDispatchClickEvent(aEvent, aStatus, eMouseAuxClick,
|
||||
presShell, mouseContent, currentTarget,
|
||||
false);
|
||||
false, aOverrideClickTarget);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -92,12 +92,17 @@ public:
|
|||
* be conditional based on either DOM or frame processing should occur in
|
||||
* PostHandleEvent. Any centralized event processing which must occur before
|
||||
* DOM or frame event handling should occur here as well.
|
||||
*
|
||||
* aOverrideClickTarget can be used to indicate which element should be
|
||||
* used as the *up target when deciding whether to send click event.
|
||||
* This is used when releasing pointer capture. Otherwise null.
|
||||
*/
|
||||
nsresult PreHandleEvent(nsPresContext* aPresContext,
|
||||
WidgetEvent* aEvent,
|
||||
nsIFrame* aTargetFrame,
|
||||
nsIContent* aTargetContent,
|
||||
nsEventStatus* aStatus);
|
||||
nsEventStatus* aStatus,
|
||||
nsIContent* aOverrideClickTarget);
|
||||
|
||||
/* The PostHandleEvent method should contain all system processing which
|
||||
* should occur conditionally based on DOM or frame processing. It should
|
||||
|
@ -107,7 +112,8 @@ public:
|
|||
nsresult PostHandleEvent(nsPresContext* aPresContext,
|
||||
WidgetEvent* aEvent,
|
||||
nsIFrame* aTargetFrame,
|
||||
nsEventStatus* aStatus);
|
||||
nsEventStatus* aStatus,
|
||||
nsIContent* aOverrideClickTarget);
|
||||
|
||||
void PostHandleKeyboardEvent(WidgetKeyboardEvent* aKeyboardEvent,
|
||||
nsIFrame* aTargetFrame, nsEventStatus& aStatus);
|
||||
|
@ -442,10 +448,13 @@ protected:
|
|||
nsIPresShell* aPresShell,
|
||||
nsIContent* aMouseTarget,
|
||||
AutoWeakFrame aCurrentTarget,
|
||||
bool aNoContentDispatch);
|
||||
nsresult SetClickCount(WidgetMouseEvent* aEvent, nsEventStatus* aStatus);
|
||||
bool aNoContentDispatch,
|
||||
nsIContent* aOverrideClickTarget);
|
||||
nsresult SetClickCount(WidgetMouseEvent* aEvent, nsEventStatus* aStatus,
|
||||
nsIContent* aOverrideClickTarget = nullptr);
|
||||
nsresult CheckForAndDispatchClick(WidgetMouseEvent* aEvent,
|
||||
nsEventStatus* aStatus);
|
||||
nsEventStatus* aStatus,
|
||||
nsIContent* aOverrideClickTarget);
|
||||
void EnsureDocument(nsPresContext* aPresContext);
|
||||
void FlushPendingEvents(nsPresContext* aPresContext);
|
||||
|
||||
|
@ -1023,6 +1032,8 @@ private:
|
|||
void NotifyTargetUserActivation(WidgetEvent* aEvent,
|
||||
nsIContent* aTargetContent);
|
||||
|
||||
already_AddRefed<EventStateManager> ESMFromContentOrThis(nsIContent* aContent);
|
||||
|
||||
int32_t mLockCursor;
|
||||
bool mLastFrameConsumedSetCursor;
|
||||
|
||||
|
|
|
@ -7077,23 +7077,29 @@ PresShell::HandleEvent(nsIFrame* aFrame,
|
|||
frame = pointerCapturingContent->GetPrimaryFrame();
|
||||
|
||||
if (!frame) {
|
||||
RefPtr<PresShell> shell =
|
||||
GetShellForEventTarget(nullptr, pointerCapturingContent);
|
||||
if (!shell) {
|
||||
// If we can't process event for the capturing content, release
|
||||
// the capture.
|
||||
PointerEventHandler::ReleaseIfCaptureByDescendant(
|
||||
pointerCapturingContent);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIContent> overrideClickTarget =
|
||||
GetOverrideClickTarget(aEvent, aFrame);
|
||||
|
||||
// Dispatch events to the capturing content even it's frame is
|
||||
// destroyed.
|
||||
PointerEventHandler::DispatchPointerFromMouseOrTouch(
|
||||
this, nullptr, pointerCapturingContent, aEvent, false,
|
||||
shell, nullptr, pointerCapturingContent, aEvent, false,
|
||||
aEventStatus, nullptr);
|
||||
|
||||
RefPtr<PresShell> shell =
|
||||
GetShellForEventTarget(nullptr, pointerCapturingContent);
|
||||
|
||||
if (!shell) {
|
||||
// The capturing element could be changed when dispatch pointer
|
||||
// events.
|
||||
return NS_OK;
|
||||
}
|
||||
return shell->HandleEventWithTarget(aEvent, nullptr,
|
||||
pointerCapturingContent,
|
||||
aEventStatus, true);
|
||||
aEventStatus, true, nullptr,
|
||||
overrideClickTarget);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -7224,6 +7230,7 @@ PresShell::HandleEvent(nsIFrame* aFrame,
|
|||
}
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIContent> overrideClickTarget;
|
||||
if (PointerEventHandler::IsPointerEventEnabled()) {
|
||||
// Dispatch pointer events from the mouse or touch events. Regarding
|
||||
// pointer events from mouse, we should dispatch those pointer events to
|
||||
|
@ -7239,6 +7246,21 @@ PresShell::HandleEvent(nsIFrame* aFrame,
|
|||
nsIFrame* targetFrame =
|
||||
aEvent->mClass == eTouchEventClass ? aFrame : frame;
|
||||
|
||||
if (pointerCapturingContent) {
|
||||
overrideClickTarget = GetOverrideClickTarget(aEvent, aFrame);
|
||||
shell = GetShellForEventTarget(nullptr, pointerCapturingContent);
|
||||
if (!shell) {
|
||||
// If we can't process event for the capturing content, release
|
||||
// the capture.
|
||||
PointerEventHandler::ReleaseIfCaptureByDescendant(
|
||||
pointerCapturingContent);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
targetFrame = pointerCapturingContent->GetPrimaryFrame();
|
||||
frame = targetFrame;
|
||||
}
|
||||
|
||||
AutoWeakFrame weakFrame(targetFrame);
|
||||
nsCOMPtr<nsIContent> targetContent;
|
||||
PointerEventHandler::DispatchPointerFromMouseOrTouch(
|
||||
|
@ -7288,7 +7310,8 @@ PresShell::HandleEvent(nsIFrame* aFrame,
|
|||
// must have been captured by us or some ancestor shell and we
|
||||
// now ask the subshell to dispatch it normally.
|
||||
shell->PushCurrentEventInfo(frame, targetElement);
|
||||
rv = shell->HandleEventInternal(aEvent, aEventStatus, true);
|
||||
rv = shell->HandleEventInternal(aEvent, aEventStatus, true,
|
||||
overrideClickTarget);
|
||||
#ifdef DEBUG
|
||||
shell->ShowEventTargetDebug();
|
||||
#endif
|
||||
|
@ -7445,7 +7468,8 @@ nsresult
|
|||
PresShell::HandleEventWithTarget(WidgetEvent* aEvent, nsIFrame* aFrame,
|
||||
nsIContent* aContent, nsEventStatus* aStatus,
|
||||
bool aIsHandlingNativeEvent,
|
||||
nsIContent** aTargetContent)
|
||||
nsIContent** aTargetContent,
|
||||
nsIContent* aOverrideClickTarget)
|
||||
{
|
||||
#if DEBUG
|
||||
MOZ_ASSERT(!aFrame || aFrame->PresContext()->GetPresShell() == this,
|
||||
|
@ -7460,7 +7484,8 @@ PresShell::HandleEventWithTarget(WidgetEvent* aEvent, nsIFrame* aFrame,
|
|||
NS_ENSURE_STATE(!aContent || aContent->GetComposedDoc() == mDocument);
|
||||
AutoPointerEventTargetUpdater updater(this, aEvent, aFrame, aTargetContent);
|
||||
PushCurrentEventInfo(aFrame, aContent);
|
||||
nsresult rv = HandleEventInternal(aEvent, aStatus, false);
|
||||
nsresult rv =
|
||||
HandleEventInternal(aEvent, aStatus, false, aOverrideClickTarget);
|
||||
PopCurrentEventInfo();
|
||||
return rv;
|
||||
}
|
||||
|
@ -7468,7 +7493,8 @@ PresShell::HandleEventWithTarget(WidgetEvent* aEvent, nsIFrame* aFrame,
|
|||
nsresult
|
||||
PresShell::HandleEventInternal(WidgetEvent* aEvent,
|
||||
nsEventStatus* aStatus,
|
||||
bool aIsHandlingNativeEvent)
|
||||
bool aIsHandlingNativeEvent,
|
||||
nsIContent* aOverrideClickTarget)
|
||||
{
|
||||
RefPtr<EventStateManager> manager = mPresContext->EventStateManager();
|
||||
nsresult rv = NS_OK;
|
||||
|
@ -7640,7 +7666,8 @@ PresShell::HandleEventInternal(WidgetEvent* aEvent,
|
|||
// 1. Give event to event manager for pre event state changes and
|
||||
// generation of synthetic events.
|
||||
rv = manager->PreHandleEvent(mPresContext, aEvent, mCurrentEventFrame,
|
||||
mCurrentEventContent, aStatus);
|
||||
mCurrentEventContent, aStatus,
|
||||
aOverrideClickTarget);
|
||||
|
||||
// 2. Give event to the DOM for third party and JS use.
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
|
@ -7694,7 +7721,8 @@ PresShell::HandleEventInternal(WidgetEvent* aEvent,
|
|||
// generation of synthetic events.
|
||||
if (!mIsDestroying && NS_SUCCEEDED(rv)) {
|
||||
rv = manager->PostHandleEvent(mPresContext, aEvent,
|
||||
GetCurrentEventFrame(), aStatus);
|
||||
GetCurrentEventFrame(), aStatus,
|
||||
aOverrideClickTarget);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -10641,3 +10669,34 @@ PresShell::NotifyStyleSheetServiceSheetRemoved(StyleSheet* aSheet,
|
|||
|
||||
RemoveSheet(ToSheetType(aSheetType), aSheet);
|
||||
}
|
||||
|
||||
nsIContent*
|
||||
PresShell::GetOverrideClickTarget(WidgetGUIEvent* aEvent,
|
||||
nsIFrame* aFrame)
|
||||
{
|
||||
if (aEvent->mMessage != eMouseUp) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(aEvent->mClass == eMouseEventClass);
|
||||
WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent();
|
||||
|
||||
uint32_t flags = 0;
|
||||
nsPoint eventPoint =
|
||||
nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, aFrame);
|
||||
if (mouseEvent->mIgnoreRootScrollFrame) {
|
||||
flags |= INPUT_IGNORE_ROOT_SCROLL_FRAME;
|
||||
}
|
||||
|
||||
nsIFrame* target =
|
||||
FindFrameTargetedByInputEvent(aEvent, aFrame, eventPoint, flags);
|
||||
if (!target) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsIContent* overrideClickTarget = target->GetContent();
|
||||
while (overrideClickTarget && !overrideClickTarget->IsElement()) {
|
||||
overrideClickTarget = overrideClickTarget->GetFlattenedTreeParent();
|
||||
}
|
||||
return overrideClickTarget;
|
||||
}
|
||||
|
|
|
@ -169,7 +169,9 @@ public:
|
|||
nsIContent* aContent,
|
||||
nsEventStatus* aStatus,
|
||||
bool aIsHandlingNativeEvent = false,
|
||||
nsIContent** aTargetContent = nullptr) override;
|
||||
nsIContent** aTargetContent = nullptr,
|
||||
nsIContent* aOverrideClickTarget = nullptr)
|
||||
override;
|
||||
nsIFrame* GetEventTargetFrame() override;
|
||||
already_AddRefed<nsIContent>
|
||||
GetEventTargetContent(WidgetEvent* aEvent) override;
|
||||
|
@ -673,7 +675,8 @@ private:
|
|||
*/
|
||||
nsresult HandleEventInternal(WidgetEvent* aEvent,
|
||||
nsEventStatus* aStatus,
|
||||
bool aIsHandlingNativeEvent);
|
||||
bool aIsHandlingNativeEvent,
|
||||
nsIContent* aOverrideClickTarget = nullptr);
|
||||
|
||||
/*
|
||||
* This and the next two helper methods are used to target and position the
|
||||
|
@ -754,6 +757,8 @@ private:
|
|||
|
||||
nsresult SetResolutionImpl(float aResolution, bool aScaleToResolution);
|
||||
|
||||
nsIContent* GetOverrideClickTarget(WidgetGUIEvent* aEvent,
|
||||
nsIFrame* aFrame);
|
||||
#ifdef DEBUG
|
||||
// The reflow root under which we're currently reflowing. Null when
|
||||
// not in reflow.
|
||||
|
|
|
@ -927,7 +927,8 @@ public:
|
|||
nsIContent* aContent,
|
||||
nsEventStatus* aStatus,
|
||||
bool aIsHandlingNativeEvent = false,
|
||||
nsIContent** aTargetContent = nullptr) = 0;
|
||||
nsIContent** aTargetContent = nullptr,
|
||||
nsIContent* aOverrideClickTarget = nullptr) = 0;
|
||||
|
||||
/**
|
||||
* Dispatch event to content only (NOT full processing)
|
||||
|
|
Загрузка…
Ссылка в новой задаче