summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--dom/base/nsContentUtils.cpp50
-rw-r--r--dom/base/nsContentUtils.h9
-rwxr-xr-xdom/events/Event.cpp5
-rw-r--r--dom/events/EventStateManager.cpp88
-rw-r--r--dom/events/EventStateManager.h3
-rw-r--r--widget/MouseEvents.h4
6 files changed, 103 insertions, 56 deletions
diff --git a/dom/base/nsContentUtils.cpp b/dom/base/nsContentUtils.cpp
index 55bcf473e0..c964f0ce29 100644
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -2377,6 +2377,56 @@ nsContentUtils::GetCommonAncestor(nsINode* aNode1,
return parent;
}
+// static
+nsINode*
+nsContentUtils::GetCommonAncestorUnderInteractiveContent(nsINode* aNode1,
+ nsINode* aNode2)
+{
+ if (!aNode1 || !aNode2) {
+ return nullptr;
+ }
+
+ if (aNode1 == aNode2) {
+ return aNode1;
+ }
+
+ // Build the chain of parents
+ AutoTArray<nsINode*, 30> parents1;
+ do {
+ parents1.AppendElement(aNode1);
+ if (aNode1->IsElement() &&
+ aNode1->AsElement()->IsInteractiveHTMLContent(true)) {
+ break;
+ }
+ aNode1 = aNode1->GetFlattenedTreeParentNode();
+ } while (aNode1);
+
+ AutoTArray<nsINode*, 30> parents2;
+ do {
+ parents2.AppendElement(aNode2);
+ if (aNode2->IsElement() &&
+ aNode2->AsElement()->IsInteractiveHTMLContent(true)) {
+ break;
+ }
+ aNode2 = aNode2->GetFlattenedTreeParentNode();
+ } while (aNode2);
+
+ // Find where the parent chain differs
+ uint32_t pos1 = parents1.Length();
+ uint32_t pos2 = parents2.Length();
+ nsINode* parent = nullptr;
+ for (uint32_t len = std::min(pos1, pos2); len > 0; --len) {
+ nsINode* child1 = parents1.ElementAt(--pos1);
+ nsINode* child2 = parents2.ElementAt(--pos2);
+ if (child1 != child2) {
+ break;
+ }
+ parent = child1;
+ }
+
+ return parent;
+}
+
/* static */
bool
nsContentUtils::PositionIsBefore(nsINode* aNode1, nsINode* aNode2)
diff --git a/dom/base/nsContentUtils.h b/dom/base/nsContentUtils.h
index 3393a30c5c..eb67ff6a6a 100644
--- a/dom/base/nsContentUtils.h
+++ b/dom/base/nsContentUtils.h
@@ -325,6 +325,15 @@ public:
nsINode* aNode2);
/**
+ * Returns the common ancestor under interactive content, if any.
+ * If neither one has interactive content as ancestor, common ancestor will be
+ * returned. If only one has interactive content as ancestor, null will be
+ * returned. If the nodes are the same, that node is returned.
+ */
+ static nsINode* GetCommonAncestorUnderInteractiveContent(nsINode* aNode1,
+ nsINode* aNode2);
+
+ /**
* Returns true if aNode1 is before aNode2 in the same connected
* tree.
*/
diff --git a/dom/events/Event.cpp b/dom/events/Event.cpp
index 3fbb138e7c..864678dd66 100755
--- a/dom/events/Event.cpp
+++ b/dom/events/Event.cpp
@@ -194,6 +194,11 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Event)
default:
break;
}
+
+ if (WidgetMouseEvent* mouseEvent = tmp->mEvent->AsMouseEvent()) {
+ NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mEvent->mClickTarget");
+ cb.NoteXPCOMChild(mouseEvent->mClickTarget);
+ }
}
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPresContext)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mExplicitOriginalTarget)
diff --git a/dom/events/EventStateManager.cpp b/dom/events/EventStateManager.cpp
index 3dcc6cef47..935281916b 100644
--- a/dom/events/EventStateManager.cpp
+++ b/dom/events/EventStateManager.cpp
@@ -432,11 +432,8 @@ NS_IMPL_CYCLE_COLLECTION(EventStateManager,
mGestureDownContent,
mGestureDownFrameOwner,
mLastLeftMouseDownContent,
- mLastLeftMouseDownContentParent,
mLastMiddleMouseDownContent,
- mLastMiddleMouseDownContentParent,
mLastRightMouseDownContent,
- mLastRightMouseDownContentParent,
mActiveContent,
mHoverContent,
mURLTargetContent,
@@ -4570,16 +4567,13 @@ EventStateManager::SetClickCount(WidgetMouseEvent* aEvent,
nsEventStatus* aStatus)
{
nsCOMPtr<nsIContent> mouseContent;
- nsIContent* mouseContentParent = nullptr;
if (mCurrentTarget) {
mCurrentTarget->GetContentForEvent(aEvent, getter_AddRefs(mouseContent));
}
- if (mouseContent) {
- if (mouseContent->IsNodeOfType(nsINode::eTEXT)) {
- mouseContent = mouseContent->GetParent();
- }
- if (mouseContent && mouseContent->IsRootOfNativeAnonymousSubtree()) {
- mouseContentParent = mouseContent->GetParent();
+ if (mouseContent && mouseContent->IsNodeOfType(nsINode::eTEXT)) {
+ nsINode* parent = mouseContent->GetFlattenedTreeParentNode();
+ if (parent && parent->IsContent()) {
+ mouseContent = parent->AsContent();
}
}
@@ -4587,54 +4581,51 @@ EventStateManager::SetClickCount(WidgetMouseEvent* aEvent,
case WidgetMouseEvent::eLeftButton:
if (aEvent->mMessage == eMouseDown) {
mLastLeftMouseDownContent = mouseContent;
- mLastLeftMouseDownContentParent = mouseContentParent;
} else if (aEvent->mMessage == eMouseUp) {
- if (mLastLeftMouseDownContent == mouseContent ||
- mLastLeftMouseDownContentParent == mouseContent ||
- mLastLeftMouseDownContent == mouseContentParent) {
+ aEvent->mClickTarget =
+ nsContentUtils::GetCommonAncestorUnderInteractiveContent(
+ mouseContent, mLastLeftMouseDownContent);
+ if (aEvent->mClickTarget) {
aEvent->mClickCount = mLClickCount;
mLClickCount = 0;
} else {
aEvent->mClickCount = 0;
}
mLastLeftMouseDownContent = nullptr;
- mLastLeftMouseDownContentParent = nullptr;
}
break;
case WidgetMouseEvent::eMiddleButton:
if (aEvent->mMessage == eMouseDown) {
mLastMiddleMouseDownContent = mouseContent;
- mLastMiddleMouseDownContentParent = mouseContentParent;
} else if (aEvent->mMessage == eMouseUp) {
- if (mLastMiddleMouseDownContent == mouseContent ||
- mLastMiddleMouseDownContentParent == mouseContent ||
- mLastMiddleMouseDownContent == mouseContentParent) {
+ aEvent->mClickTarget =
+ nsContentUtils::GetCommonAncestorUnderInteractiveContent(
+ mouseContent, mLastMiddleMouseDownContent);
+ if (aEvent->mClickTarget) {
aEvent->mClickCount = mMClickCount;
mMClickCount = 0;
} else {
aEvent->mClickCount = 0;
}
mLastMiddleMouseDownContent = nullptr;
- mLastMiddleMouseDownContentParent = nullptr;
}
break;
case WidgetMouseEvent::eRightButton:
if (aEvent->mMessage == eMouseDown) {
mLastRightMouseDownContent = mouseContent;
- mLastRightMouseDownContentParent = mouseContentParent;
} else if (aEvent->mMessage == eMouseUp) {
- if (mLastRightMouseDownContent == mouseContent ||
- mLastRightMouseDownContentParent == mouseContent ||
- mLastRightMouseDownContent == mouseContentParent) {
+ aEvent->mClickTarget =
+ nsContentUtils::GetCommonAncestorUnderInteractiveContent(
+ mouseContent, mLastRightMouseDownContent);
+ if (aEvent->mClickTarget) {
aEvent->mClickCount = mRClickCount;
mRClickCount = 0;
} else {
aEvent->mClickCount = 0;
}
mLastRightMouseDownContent = nullptr;
- mLastRightMouseDownContentParent = nullptr;
}
break;
}
@@ -4656,7 +4647,7 @@ EventStateManager::EventCausesClickEvents(const WidgetMouseEvent& aMouseEvent)
}
// If mouse is still over same element, clickcount will be > 1.
// If it has moved it will be zero, so no click.
- if (!aMouseEvent.mClickCount) {
+ if (!aMouseEvent.mClickCount || !aMouseEvent.mClickTarget) {
return false;
}
// Check that the window isn't disabled before firing a click
@@ -4675,7 +4666,7 @@ EventStateManager::InitAndDispatchClickEvent(WidgetMouseEvent* aMouseUpEvent,
{
MOZ_ASSERT(aMouseUpEvent);
MOZ_ASSERT(EventCausesClickEvents(*aMouseUpEvent));
- MOZ_ASSERT(aMouseUpContent || aCurrentTarget || aOverrideClickTarget);
+ MOZ_ASSERT(aMouseUpContent || aCurrentTarget);
WidgetMouseEvent event(aMouseUpEvent->IsTrusted(), aMessage,
aMouseUpEvent->mWidget, WidgetMouseEvent::eReal);
@@ -4689,6 +4680,10 @@ EventStateManager::InitAndDispatchClickEvent(WidgetMouseEvent* aMouseUpEvent,
event.button = aMouseUpEvent->button;
event.inputSource = aMouseUpEvent->inputSource;
+ if (!aMouseUpContent->IsInComposedDoc()) {
+ return NS_OK;
+ }
+
// Use local event status for each click event dispatching since it'll be
// cleared by EventStateManager::PreHandleEvent(). Therefore, dispatching
// an event means that previous event status will be ignored.
@@ -4724,22 +4719,12 @@ EventStateManager::PostHandleMouseUp(WidgetMouseEvent* aMouseUpEvent,
return NS_OK;
}
- nsCOMPtr<nsIContent> mouseUpContent = GetEventTargetContent(aMouseUpEvent);
- // Click events apply to *elements* not nodes. At this point the target
- // content may have been reset to some non-element content, and so we need
- // to walk up the closest ancestor element, just like we do in
- // nsPresShell::HandlePositionedEvent.
- while (mouseUpContent && !mouseUpContent->IsElement()) {
- mouseUpContent = mouseUpContent->GetFlattenedTreeParent();
- }
-
- if (!mouseUpContent && !mCurrentTarget) {
- return NS_OK;
- }
+ nsCOMPtr<nsIContent> clickTarget = do_QueryInterface(aMouseUpEvent->mClickTarget);
+ NS_ENSURE_STATE(clickTarget);
// Fire click events if the event target is still available.
nsresult rv = DispatchClickEvents(presShell, aMouseUpEvent, aStatus,
- mouseUpContent);
+ clickTarget);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
@@ -4750,13 +4735,13 @@ nsresult
EventStateManager::DispatchClickEvents(nsIPresShell* aPresShell,
WidgetMouseEvent* aMouseUpEvent,
nsEventStatus* aStatus,
- nsIContent* aMouseUpContent)
+ nsIContent* aClickTarget)
{
MOZ_ASSERT(aPresShell);
MOZ_ASSERT(aMouseUpEvent);
MOZ_ASSERT(EventCausesClickEvents(*aMouseUpEvent));
MOZ_ASSERT(aStatus);
- MOZ_ASSERT(aMouseUpContent || mCurrentTarget || aOverrideClickTarget);
+ MOZ_ASSERT(aClickTarget);
bool notDispatchToContents =
(aMouseUpEvent->button == WidgetMouseEvent::eMiddleButton ||
@@ -4764,12 +4749,10 @@ EventStateManager::DispatchClickEvents(nsIPresShell* aPresShell,
bool fireAuxClick = notDispatchToContents;
-
- // HandleEvent clears out mCurrentTarget which we might need again
- nsWeakFrame currentTarget = mCurrentTarget;
+ nsWeakFrame currentTarget = aClickTarget->GetPrimaryFrame();
nsresult ret =
InitAndDispatchClickEvent(aMouseUpEvent, aStatus, eMouseClick,
- aPresShell, aMouseUpContent, currentTarget,
+ aPresShell, aClickTarget, currentTarget,
notDispatchToContents);
if (NS_WARN_IF(NS_FAILED(ret))) {
return ret;
@@ -4777,21 +4760,20 @@ EventStateManager::DispatchClickEvents(nsIPresShell* aPresShell,
// Fire double click event if click count is 2.
if (aMouseUpEvent->mClickCount == 2 &&
- aMouseUpContent && aMouseUpContent->IsInComposedDoc()) {
+ aClickTarget && aClickTarget->IsInComposedDoc()) {
ret = InitAndDispatchClickEvent(aMouseUpEvent, aStatus, eMouseDoubleClick,
- aPresShell, aMouseUpContent, currentTarget,
+ aPresShell, aClickTarget, currentTarget,
notDispatchToContents);
if (NS_WARN_IF(NS_FAILED(ret))) {
return ret;
-
- }
- }
+ }
+ }
// Fire auxclick even if necessary.
if (fireAuxClick &&
- aMouseUpContent && aMouseUpContent->IsInComposedDoc()) {
+ aClickTarget && aClickTarget->IsInComposedDoc()) {
ret = InitAndDispatchClickEvent(aMouseUpEvent, aStatus, eMouseAuxClick,
- aPresShell, aMouseUpContent, currentTarget,
+ aPresShell, aClickTarget, currentTarget,
false);
NS_WARNING_ASSERTION(NS_SUCCEEDED(ret), "Failed to dispatch eMouseAuxClick");
}
diff --git a/dom/events/EventStateManager.h b/dom/events/EventStateManager.h
index 6bf457b842..e0c250f3b7 100644
--- a/dom/events/EventStateManager.h
+++ b/dom/events/EventStateManager.h
@@ -1014,11 +1014,8 @@ private:
uint16_t mGestureDownButtons;
nsCOMPtr<nsIContent> mLastLeftMouseDownContent;
- nsCOMPtr<nsIContent> mLastLeftMouseDownContentParent;
nsCOMPtr<nsIContent> mLastMiddleMouseDownContent;
- nsCOMPtr<nsIContent> mLastMiddleMouseDownContentParent;
nsCOMPtr<nsIContent> mLastRightMouseDownContent;
- nsCOMPtr<nsIContent> mLastRightMouseDownContentParent;
nsCOMPtr<nsIContent> mActiveContent;
nsCOMPtr<nsIContent> mHoverContent;
diff --git a/widget/MouseEvents.h b/widget/MouseEvents.h
index 4b8ff44ce6..c9a608bb4a 100644
--- a/widget/MouseEvents.h
+++ b/widget/MouseEvents.h
@@ -275,6 +275,10 @@ public:
return result;
}
+ // If during mouseup handling we detect that click event might need to be
+ // dispatched, this is setup to be the target of the click event.
+ nsCOMPtr<dom::EventTarget> mClickTarget;
+
// mReason indicates the reason why the event is fired:
// - Representing mouse operation.
// - Synthesized for emulating mousemove event when the content under the