mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-29 11:57:32 +09:00
Issue #2135 - Bug 1413102: Ensure Shadow DOM boundaries are dealt properly in event handling
* RE: BasicEvents.h - our WidgetEvent is not movable (yet), so the change that requires that wasn't included. * Parts of this use code that was introduced in bug 1427511. For now, they were replaced with their equivalents.
This commit is contained in:
parent
e286eb8adb
commit
24572438a0
9 changed files with 299 additions and 70 deletions
|
|
@ -801,6 +801,22 @@ FindChromeAccessOnlySubtreeOwner(nsIContent* aContent)
|
|||
return aContent;
|
||||
}
|
||||
|
||||
already_AddRefed<nsINode>
|
||||
FindChromeAccessOnlySubtreeOwner(EventTarget* aTarget)
|
||||
{
|
||||
nsCOMPtr<nsINode> node = do_QueryInterface(aTarget);
|
||||
if (!node || !node->ChromeOnlyAccess()) {
|
||||
return node.forget();
|
||||
}
|
||||
|
||||
if (!node->IsContent()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
node = FindChromeAccessOnlySubtreeOwner(node->AsContent());
|
||||
return node.forget();
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsIContent::GetEventTargetParent(EventChainPreVisitor& aVisitor)
|
||||
{
|
||||
|
|
@ -821,24 +837,11 @@ nsIContent::GetEventTargetParent(EventChainPreVisitor& aVisitor)
|
|||
// chrome access only subtree or if we are about to propagate out of
|
||||
// a shadow root to a shadow root host.
|
||||
((this == aVisitor.mEvent->mOriginalTarget &&
|
||||
!ChromeOnlyAccess()) || isAnonForEvents || GetShadowRoot())) {
|
||||
!ChromeOnlyAccess()) || isAnonForEvents)) {
|
||||
nsCOMPtr<nsIContent> relatedTarget =
|
||||
do_QueryInterface(aVisitor.mEvent->AsMouseEvent()->mRelatedTarget);
|
||||
if (relatedTarget &&
|
||||
relatedTarget->OwnerDoc() == OwnerDoc()) {
|
||||
|
||||
// In the web components case, we may need to stop propagation of events
|
||||
// at shadow root host.
|
||||
if (GetShadowRoot()) {
|
||||
nsIContent* adjustedTarget =
|
||||
Event::GetShadowRelatedTarget(this, relatedTarget);
|
||||
if (this == adjustedTarget) {
|
||||
aVisitor.SetParentTarget(nullptr, false);
|
||||
aVisitor.mCanHandle = false;
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
// If current target is anonymous for events or we know that related
|
||||
// target is descendant of an element which is anonymous for events,
|
||||
// we may want to stop event propagation.
|
||||
|
|
@ -954,6 +957,104 @@ nsIContent::GetEventTargetParent(EventChainPreVisitor& aVisitor)
|
|||
} else {
|
||||
aVisitor.SetParentTarget(GetComposedDoc(), false);
|
||||
}
|
||||
|
||||
if (!ChromeOnlyAccess() && !aVisitor.mRelatedTargetRetargetedInCurrentScope) {
|
||||
// We don't support Shadow DOM in native anonymous content yet.
|
||||
aVisitor.mRelatedTargetRetargetedInCurrentScope = true;
|
||||
if (aVisitor.mEvent->mOriginalRelatedTarget) {
|
||||
// https://dom.spec.whatwg.org/#concept-event-dispatch
|
||||
// Step 3.
|
||||
// "Let relatedTarget be the result of retargeting event's relatedTarget
|
||||
// against target if event's relatedTarget is non-null, and null
|
||||
// otherwise."
|
||||
//
|
||||
// This is a bit complicated because the event might be from native
|
||||
// anonymous content, but we need to deal with non-native anonymous
|
||||
// content there.
|
||||
bool initialTarget = this == aVisitor.mEvent->mOriginalTarget;
|
||||
nsCOMPtr<nsINode> originalTargetAsNode;
|
||||
// Use of mOriginalTargetIsInAnon is an optimization here.
|
||||
if (!initialTarget && aVisitor.mOriginalTargetIsInAnon) {
|
||||
originalTargetAsNode =
|
||||
FindChromeAccessOnlySubtreeOwner(aVisitor.mEvent->mOriginalTarget);
|
||||
initialTarget = originalTargetAsNode == this;
|
||||
}
|
||||
if (initialTarget) {
|
||||
nsCOMPtr<nsINode> relatedTargetAsNode =
|
||||
FindChromeAccessOnlySubtreeOwner(aVisitor.mEvent->mOriginalRelatedTarget);
|
||||
if (!originalTargetAsNode) {
|
||||
originalTargetAsNode =
|
||||
do_QueryInterface(aVisitor.mEvent->mOriginalTarget);
|
||||
}
|
||||
|
||||
if (relatedTargetAsNode && originalTargetAsNode) {
|
||||
nsINode* retargetedRelatedTarget =
|
||||
nsContentUtils::Retarget(relatedTargetAsNode, originalTargetAsNode);
|
||||
if (originalTargetAsNode == retargetedRelatedTarget &&
|
||||
retargetedRelatedTarget != relatedTargetAsNode) {
|
||||
// Step 4.
|
||||
// "If target is relatedTarget and target is not event's
|
||||
// relatedTarget, then return true."
|
||||
aVisitor.IgnoreCurrentTarget();
|
||||
// Old code relies on mTarget to point to the first element which
|
||||
// was not added to the event target chain because of mCanHandle
|
||||
// being false, but in Shadow DOM case mTarget really should
|
||||
// point to a node in Shadow DOM.
|
||||
aVisitor.mEvent->mTarget = aVisitor.mTargetInKnownToBeHandledScope;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Part of step 5. Retargeting target has happened already higher
|
||||
// up in this method.
|
||||
// "Append to an event path with event, target, targetOverride,
|
||||
// relatedTarget, and false."
|
||||
aVisitor.mRetargetedRelatedTarget = retargetedRelatedTarget;
|
||||
}
|
||||
} else {
|
||||
nsCOMPtr<nsINode> relatedTargetAsNode =
|
||||
FindChromeAccessOnlySubtreeOwner(aVisitor.mEvent->mOriginalRelatedTarget);
|
||||
if (relatedTargetAsNode) {
|
||||
// Step 11.3.
|
||||
// "Let relatedTarget be the result of retargeting event's
|
||||
// relatedTarget against parent if event's relatedTarget is non-null,
|
||||
// and null otherwise.".
|
||||
nsINode* retargetedRelatedTarget =
|
||||
nsContentUtils::Retarget(relatedTargetAsNode, this);
|
||||
nsCOMPtr<nsINode> targetInKnownToBeHandledScope =
|
||||
FindChromeAccessOnlySubtreeOwner(aVisitor.mTargetInKnownToBeHandledScope);
|
||||
if (nsContentUtils::ContentIsShadowIncludingDescendantOf(
|
||||
this, targetInKnownToBeHandledScope->SubtreeRoot())) {
|
||||
// Part of step 11.4.
|
||||
// "If target's root is a shadow-including inclusive ancestor of
|
||||
// parent, then"
|
||||
// "...Append to an event path with event, parent, null, relatedTarget,
|
||||
// " and slot-in-closed-tree."
|
||||
aVisitor.mRetargetedRelatedTarget = retargetedRelatedTarget;
|
||||
} else if (this == retargetedRelatedTarget) {
|
||||
// Step 11.5
|
||||
// "Otherwise, if parent and relatedTarget are identical, then set
|
||||
// parent to null."
|
||||
aVisitor.IgnoreCurrentTarget();
|
||||
// Old code relies on mTarget to point to the first element which
|
||||
// was not added to the event target chain because of mCanHandle
|
||||
// being false, but in Shadow DOM case mTarget really should
|
||||
// point to a node in Shadow DOM.
|
||||
aVisitor.mEvent->mTarget = aVisitor.mTargetInKnownToBeHandledScope;
|
||||
return NS_OK;
|
||||
} else {
|
||||
// Step 11.6
|
||||
aVisitor.mRetargetedRelatedTarget = retargetedRelatedTarget;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (slot) {
|
||||
// Inform that we're about to exit the current scope.
|
||||
aVisitor.mRelatedTargetRetargetedInCurrentScope = false;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue