diff options
author | Matt A. Tobin <email@mattatobin.com> | 2020-04-17 07:30:43 -0400 |
---|---|---|
committer | Matt A. Tobin <email@mattatobin.com> | 2020-04-17 07:30:43 -0400 |
commit | 7e506bd98dab604062bfe12a44c096eb287721bf (patch) | |
tree | ebea23264b1fa0f9c23935b253c23bdc0b41c25d /dom/events | |
parent | 010f37f47b9c15935a6113cd82e43f0673122016 (diff) | |
download | uxp-7e506bd98dab604062bfe12a44c096eb287721bf.tar.gz |
Bug 1412775 - Implement Event.composedPath
Tag #1375
Diffstat (limited to 'dom/events')
-rw-r--r-- | dom/events/DOMEventTargetHelper.cpp | 2 | ||||
-rwxr-xr-x | dom/events/Event.cpp | 7 | ||||
-rwxr-xr-x | dom/events/Event.h | 2 | ||||
-rw-r--r-- | dom/events/EventDispatcher.cpp | 107 | ||||
-rw-r--r-- | dom/events/EventDispatcher.h | 41 |
5 files changed, 155 insertions, 4 deletions
diff --git a/dom/events/DOMEventTargetHelper.cpp b/dom/events/DOMEventTargetHelper.cpp index ee03463ef4..90ee610594 100644 --- a/dom/events/DOMEventTargetHelper.cpp +++ b/dom/events/DOMEventTargetHelper.cpp @@ -331,7 +331,7 @@ nsresult DOMEventTargetHelper::GetEventTargetParent(EventChainPreVisitor& aVisitor) { aVisitor.mCanHandle = true; - aVisitor.mParentTarget = nullptr; + aVisitor.SetParentTarget(nullptr, false); return NS_OK; } diff --git a/dom/events/Event.cpp b/dom/events/Event.cpp index 280e40ad57..def298228d 100755 --- a/dom/events/Event.cpp +++ b/dom/events/Event.cpp @@ -11,6 +11,7 @@ #include "mozilla/dom/ShadowRoot.h" #include "mozilla/ContentEvents.h" #include "mozilla/DOMEventTargetHelper.h" +#include "mozilla/EventDispatcher.h" #include "mozilla/EventStateManager.h" #include "mozilla/InternalMutationEvent.h" #include "mozilla/dom/Performance.h" @@ -298,6 +299,12 @@ Event::GetCurrentTarget() const return mEvent->GetCurrentDOMEventTarget(); } +void +Event::ComposedPath(nsTArray<RefPtr<EventTarget>>& aPath) +{ + EventDispatcher::GetComposedPathFor(mEvent, aPath); +} + NS_IMETHODIMP Event::GetCurrentTarget(nsIDOMEventTarget** aCurrentTarget) { diff --git a/dom/events/Event.h b/dom/events/Event.h index 0817aa809e..4f1fcc8270 100755 --- a/dom/events/Event.h +++ b/dom/events/Event.h @@ -157,6 +157,8 @@ public: EventTarget* GetTarget() const; EventTarget* GetCurrentTarget() const; + void ComposedPath(nsTArray<RefPtr<EventTarget>>& aPath); + uint16_t EventPhase() const; // xpidl implementation diff --git a/dom/events/EventDispatcher.cpp b/dom/events/EventDispatcher.cpp index 740e611e49..1094c08c20 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 diff --git a/dom/events/EventDispatcher.h b/dom/events/EventDispatcher.h index 618c863d5c..8a34e6bf78 100644 --- a/dom/events/EventDispatcher.h +++ b/dom/events/EventDispatcher.h @@ -124,6 +124,9 @@ public: , mWantsWillHandleEvent(false) , mMayHaveListenerManager(true) , mWantsPreHandleEvent(false) + , mRootOfClosedTree(false) + , mParentIsSlotInClosedTree(false) + , mParentIsChromeHandler(false) , mParentTarget(nullptr) , mEventTargetAtParent(nullptr) { @@ -139,10 +142,26 @@ public: mWantsWillHandleEvent = false; mMayHaveListenerManager = true; mWantsPreHandleEvent = false; + mRootOfClosedTree = false; + mParentIsSlotInClosedTree = false; + mParentIsChromeHandler = false; mParentTarget = nullptr; mEventTargetAtParent = nullptr; } + dom::EventTarget* GetParentTarget() + { + return mParentTarget; + } + + void SetParentTarget(dom::EventTarget* aParentTarget, bool aIsChromeHandler) + { + mParentTarget = aParentTarget; + if (mParentTarget) { + mParentIsChromeHandler = aIsChromeHandler; + } + } + /** * Member that must be set in GetEventTargetParent by event targets. If set to * false, indicates that this event target will not be handling the event and @@ -195,10 +214,29 @@ public: bool mWantsPreHandleEvent; /** + * True if the current target is either closed ShadowRoot or root of + * chrome only access tree (for example native anonymous content). + */ + bool mRootOfClosedTree; + + /** + * True if mParentTarget is HTMLSlotElement in a closed shadow tree and the + * current target is assigned to that slot. + */ + bool mParentIsSlotInClosedTree; + + /** + * True if mParentTarget is a chrome handler in the event path. + */ + bool mParentIsChromeHandler; + +private: + /** * Parent item in the event target chain. */ dom::EventTarget* mParentTarget; +public: /** * If the event needs to be retargeted, this is the event target, * which should be used when the event is handled at mParentTarget. @@ -281,6 +319,9 @@ public: WidgetEvent* aEvent, const nsAString& aEventType); + static void GetComposedPathFor(WidgetEvent* aEvent, + nsTArray<RefPtr<dom::EventTarget>>& aPath); + /** * Called at shutting down. */ |