diff options
-rw-r--r-- | dom/base/nsContentUtils.cpp | 50 | ||||
-rw-r--r-- | dom/base/nsContentUtils.h | 9 | ||||
-rwxr-xr-x | dom/events/Event.cpp | 5 | ||||
-rw-r--r-- | dom/events/EventStateManager.cpp | 88 | ||||
-rw-r--r-- | dom/events/EventStateManager.h | 3 | ||||
-rw-r--r-- | widget/MouseEvents.h | 4 |
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 |