summaryrefslogtreecommitdiffstats
path: root/dom/events/EventDispatcher.cpp
diff options
context:
space:
mode:
authorMatt A. Tobin <email@mattatobin.com>2020-04-17 07:30:43 -0400
committerMatt A. Tobin <email@mattatobin.com>2020-04-17 07:30:43 -0400
commit7e506bd98dab604062bfe12a44c096eb287721bf (patch)
treeebea23264b1fa0f9c23935b253c23bdc0b41c25d /dom/events/EventDispatcher.cpp
parent010f37f47b9c15935a6113cd82e43f0673122016 (diff)
downloadUXP-7e506bd98dab604062bfe12a44c096eb287721bf.tar
UXP-7e506bd98dab604062bfe12a44c096eb287721bf.tar.gz
UXP-7e506bd98dab604062bfe12a44c096eb287721bf.tar.lz
UXP-7e506bd98dab604062bfe12a44c096eb287721bf.tar.xz
UXP-7e506bd98dab604062bfe12a44c096eb287721bf.zip
Bug 1412775 - Implement Event.composedPath
Tag #1375
Diffstat (limited to 'dom/events/EventDispatcher.cpp')
-rw-r--r--dom/events/EventDispatcher.cpp107
1 files changed, 104 insertions, 3 deletions
diff --git a/dom/events/EventDispatcher.cpp b/dom/events/EventDispatcher.cpp
index 740e611e4..1094c08c2 100644
--- a/dom/events/EventDispatcher.cpp
+++ b/dom/events/EventDispatcher.cpp
@@ -246,6 +246,36 @@ public:
return mFlags.mPreHandleEventOnly;
}
+ void SetRootOfClosedTree(bool aSet)
+ {
+ mFlags.mRootOfClosedTree = aSet;
+ }
+
+ bool IsRootOfClosedTree()
+ {
+ return mFlags.mRootOfClosedTree;
+ }
+
+ void SetIsSlotInClosedTree(bool aSet)
+ {
+ mFlags.mIsSlotInClosedTree = aSet;
+ }
+
+ bool IsSlotInClosedTree()
+ {
+ return mFlags.mIsSlotInClosedTree;
+ }
+
+ void SetIsChromeHandler(bool aSet)
+ {
+ mFlags.mIsChromeHandler = aSet;
+ }
+
+ bool IsChromeHandler()
+ {
+ return mFlags.mIsChromeHandler;
+ }
+
void SetMayHaveListenerManager(bool aMayHave)
{
mFlags.mMayHaveManager = aMayHave;
@@ -344,6 +374,9 @@ private:
bool mIsChromeContent : 1;
bool mWantsPreHandleEvent : 1;
bool mPreHandleEventOnly : 1;
+ bool mRootOfClosedTree : 1;
+ bool mIsSlotInClosedTree : 1;
+ bool mIsChromeHandler : 1;
private:
typedef uint32_t RawFlags;
void SetRawFlags(RawFlags aRawFlags)
@@ -390,6 +423,7 @@ EventTargetChainItem::GetEventTargetParent(EventChainPreVisitor& aVisitor)
SetMayHaveListenerManager(aVisitor.mMayHaveListenerManager);
SetWantsPreHandleEvent(aVisitor.mWantsPreHandleEvent);
SetPreHandleEventOnly(aVisitor.mWantsPreHandleEvent && !aVisitor.mCanHandle);
+ SetRootOfClosedTree(aVisitor.mRootOfClosedTree);
mItemFlags = aVisitor.mItemFlags;
mItemData = aVisitor.mItemData;
}
@@ -761,16 +795,19 @@ EventDispatcher::Dispatch(nsISupports* aTarget,
targetEtci->SetNewTarget(t);
EventTargetChainItem* topEtci = targetEtci;
targetEtci = nullptr;
- while (preVisitor.mParentTarget) {
- EventTarget* parentTarget = preVisitor.mParentTarget;
+ while (preVisitor.GetParentTarget()) {
+ EventTarget* parentTarget = preVisitor.GetParentTarget();
EventTargetChainItem* parentEtci =
- EventTargetChainItem::Create(chain, preVisitor.mParentTarget, topEtci);
+ EventTargetChainItem::Create(chain, parentTarget, topEtci);
if (!parentEtci->IsValid()) {
EventTargetChainItem::DestroyLast(chain, parentEtci);
rv = NS_ERROR_FAILURE;
break;
}
+ parentEtci->SetIsSlotInClosedTree(preVisitor.mParentIsSlotInClosedTree);
+ parentEtci->SetIsChromeHandler(preVisitor.mParentIsChromeHandler);
+
// Item needs event retargetting.
if (preVisitor.mEventTargetAtParent) {
// Need to set the target of the event
@@ -814,9 +851,13 @@ EventDispatcher::Dispatch(nsISupports* aTarget,
}
// Handle the chain.
EventChainPostVisitor postVisitor(preVisitor);
+ MOZ_RELEASE_ASSERT(!aEvent->mPath);
+ aEvent->mPath = &chain;
EventTargetChainItem::HandleEventTargetChain(chain, postVisitor,
aCallback, cd);
+ aEvent->mPath = nullptr;
+
preVisitor.mEventStatus = postVisitor.mEventStatus;
// If the DOM event was created during event flow.
if (!preVisitor.mDOMEvent && postVisitor.mDOMEvent) {
@@ -1128,4 +1169,64 @@ EventDispatcher::CreateEvent(EventTarget* aOwner,
return nullptr;
}
+// static
+void
+EventDispatcher::GetComposedPathFor(WidgetEvent* aEvent,
+ nsTArray<RefPtr<EventTarget>>& aPath)
+{
+ nsTArray<EventTargetChainItem>* path = aEvent->mPath;
+ if (!path || path->IsEmpty() || !aEvent->mCurrentTarget) {
+ return;
+ }
+
+ EventTarget* currentTarget =
+ aEvent->mCurrentTarget->GetTargetForEventTargetChain();
+ if (!currentTarget) {
+ return;
+ }
+
+ AutoTArray<EventTarget*, 128> reversedComposedPath;
+ bool hasSeenCurrentTarget = false;
+ uint32_t hiddenSubtreeLevel = 0;
+ for (uint32_t i = path->Length(); i; ) {
+ --i;
+
+ EventTargetChainItem& item = path->ElementAt(i);
+ if (item.PreHandleEventOnly()) {
+ continue;
+ }
+
+ if (!hasSeenCurrentTarget && currentTarget == item.CurrentTarget()) {
+ hasSeenCurrentTarget = true;
+ } else if (hasSeenCurrentTarget && item.IsRootOfClosedTree()) {
+ ++hiddenSubtreeLevel;
+ }
+
+ if (hiddenSubtreeLevel == 0) {
+ reversedComposedPath.AppendElement(item.CurrentTarget());
+ }
+
+ if (item.IsSlotInClosedTree() && hiddenSubtreeLevel > 0) {
+ --hiddenSubtreeLevel;
+ }
+
+ if (item.IsChromeHandler()) {
+ if (hasSeenCurrentTarget) {
+ // The current behavior is to include only EventTargets from
+ // either chrome side of event path or content side, not from both.
+ break;
+ }
+
+ // Need to start all over to collect the composed path on content side.
+ reversedComposedPath.Clear();
+ }
+ }
+
+ aPath.SetCapacity(reversedComposedPath.Length());
+ for (uint32_t i = reversedComposedPath.Length(); i; ) {
+ --i;
+ aPath.AppendElement(reversedComposedPath[i]->GetTargetForDOMEvent());
+ }
+}
+
} // namespace mozilla