mirror of
https://github.com/roytam1/basilisk55.git
synced 2026-05-26 15:02:46 +00:00
ported from UXP: Issue #2030 - Dispatch click on common interactive ancestor if mousdown/up are not on the same element (0494d561c)
This commit is contained in:
@@ -2396,6 +2396,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)
|
||||
|
||||
@@ -342,6 +342,15 @@ public:
|
||||
static nsINode* GetCommonAncestor(nsINode* aNode1,
|
||||
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.
|
||||
|
||||
@@ -205,6 +205,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)
|
||||
|
||||
@@ -433,11 +433,8 @@ NS_IMPL_CYCLE_COLLECTION(EventStateManager,
|
||||
mGestureDownContent,
|
||||
mGestureDownFrameOwner,
|
||||
mLastLeftMouseDownContent,
|
||||
mLastLeftMouseDownContentParent,
|
||||
mLastMiddleMouseDownContent,
|
||||
mLastMiddleMouseDownContentParent,
|
||||
mLastRightMouseDownContent,
|
||||
mLastRightMouseDownContentParent,
|
||||
mActiveContent,
|
||||
mHoverContent,
|
||||
mURLTargetContent,
|
||||
@@ -4540,16 +4537,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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4557,54 +4551,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;
|
||||
}
|
||||
@@ -4626,7 +4617,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
|
||||
@@ -4645,7 +4636,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);
|
||||
@@ -4660,6 +4651,10 @@ EventStateManager::InitAndDispatchClickEvent(WidgetMouseEvent* aMouseUpEvent,
|
||||
event.pointerId = aMouseUpEvent->pointerId;
|
||||
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.
|
||||
@@ -4695,22 +4690,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;
|
||||
}
|
||||
@@ -4721,13 +4706,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 ||
|
||||
@@ -4735,12 +4720,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;
|
||||
@@ -4748,21 +4731,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");
|
||||
}
|
||||
|
||||
@@ -1015,11 +1015,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;
|
||||
|
||||
@@ -287,6 +287,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
|
||||
|
||||
Reference in New Issue
Block a user