Bug 1413102 - Ensure Shadow DOM boundaries are dealt properly in event handling, r=masayuki

This commit is contained in:
Olli Pettay 2018-02-15 12:08:42 +02:00
Родитель a3eb8e6045
Коммит b9ac198b01
14 изменённых файлов: 299 добавлений и 208 удалений

Просмотреть файл

@ -917,6 +917,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)
{
@ -937,24 +953,12 @@ 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.
@ -1070,6 +1074,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;
}

Просмотреть файл

@ -301,6 +301,8 @@ ShadowRoot::GetEventTargetParent(EventChainPreVisitor& aVisitor)
{
aVisitor.mCanHandle = true;
aVisitor.mRootOfClosedTree = IsClosed();
// Inform that we're about to exit the current scope.
aVisitor.mRelatedTargetRetargetedInCurrentScope = false;
// https://dom.spec.whatwg.org/#ref-for-get-the-parent%E2%91%A6
if (!aVisitor.mEvent->mFlags.mComposed) {
@ -323,12 +325,10 @@ ShadowRoot::GetEventTargetParent(EventChainPreVisitor& aVisitor)
nsIContent* shadowHost = GetHost();
aVisitor.SetParentTarget(shadowHost, false);
if (aVisitor.mOriginalTargetIsInAnon) {
nsCOMPtr<nsIContent> content(do_QueryInterface(aVisitor.mEvent->mTarget));
if (content && content->GetBindingParent() == shadowHost) {
aVisitor.mEventTargetAtParent = shadowHost;
}
}
nsCOMPtr<nsIContent> content(do_QueryInterface(aVisitor.mEvent->mTarget));
if (content && content->GetBindingParent() == shadowHost) {
aVisitor.mEventTargetAtParent = shadowHost;
}
return NS_OK;
}

Просмотреть файл

@ -2558,6 +2558,34 @@ nsContentUtils::ContentIsHostIncludingDescendantOf(
return false;
}
bool
nsContentUtils::ContentIsShadowIncludingDescendantOf(
const nsINode* aPossibleDescendant, const nsINode* aPossibleAncestor)
{
MOZ_ASSERT(aPossibleDescendant, "The possible descendant is null!");
MOZ_ASSERT(aPossibleAncestor, "The possible ancestor is null!");
if (aPossibleAncestor == aPossibleDescendant->GetComposedDoc()) {
return true;
}
do {
if (aPossibleDescendant == aPossibleAncestor) {
return true;
}
if (aPossibleDescendant->NodeType() == nsINode::DOCUMENT_FRAGMENT_NODE) {
ShadowRoot* shadowRoot =
ShadowRoot::FromNode(const_cast<nsINode*>(aPossibleDescendant));
aPossibleDescendant = shadowRoot ? shadowRoot->GetHost() : nullptr;
} else {
aPossibleDescendant = aPossibleDescendant->GetParentNode();
}
} while (aPossibleDescendant);
return false;
}
// static
bool
nsContentUtils::ContentIsCrossDocDescendantOf(nsINode* aPossibleDescendant,
@ -2615,6 +2643,30 @@ nsContentUtils::ContentIsFlattenedTreeDescendantOfForStyle(
return false;
}
// static
nsINode*
nsContentUtils::Retarget(nsINode* aTargetA, nsINode* aTargetB)
{
while (true && aTargetA) {
// If A's root is not a shadow root...
nsINode* root = aTargetA->SubtreeRoot();
if (!root->IsShadowRoot()) {
// ...then return A.
return aTargetA;
}
// or A's root is a shadow-including inclusive ancestor of B...
if (nsContentUtils::ContentIsShadowIncludingDescendantOf(aTargetB, root)) {
// ...then return A.
return aTargetA;
}
aTargetA = ShadowRoot::FromNode(root)->GetHost();
}
return nullptr;
}
// static
nsresult
nsContentUtils::GetAncestors(nsINode* aNode,

Просмотреть файл

@ -328,6 +328,13 @@ public:
static bool ContentIsHostIncludingDescendantOf(
const nsINode* aPossibleDescendant, const nsINode* aPossibleAncestor);
/**
* Similar to above, but does special case only ShadowRoot,
* not HTMLTemplateElement.
*/
static bool ContentIsShadowIncludingDescendantOf(
const nsINode* aPossibleDescendant, const nsINode* aPossibleAncestor);
/**
* Similar to ContentIsDescendantOf except it crosses document boundaries,
* this function uses ancestor/descendant relations in the composed document
@ -356,6 +363,13 @@ public:
ContentIsFlattenedTreeDescendantOfForStyle(const nsINode* aPossibleDescendant,
const nsINode* aPossibleAncestor);
/**
* Retarget an object A against an object B
* @see https://dom.spec.whatwg.org/#retarget
*/
static nsINode*
Retarget(nsINode* aTargetA, nsINode* aTargetB);
/*
* This method fills the |aArray| with all ancestor nodes of |aNode|
* including |aNode| at the zero index.

Просмотреть файл

@ -154,6 +154,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Event)
tmp->mEvent->mCurrentTarget = nullptr;
tmp->mEvent->mOriginalTarget = nullptr;
tmp->mEvent->mRelatedTarget = nullptr;
tmp->mEvent->mOriginalRelatedTarget = nullptr;
switch (tmp->mEvent->mClass) {
case eDragEventClass: {
WidgetDragEvent* dragEvent = tmp->mEvent->AsDragEvent();
@ -182,6 +183,7 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Event)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEvent->mCurrentTarget)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEvent->mOriginalTarget)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEvent->mRelatedTarget)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEvent->mOriginalRelatedTarget);
switch (tmp->mEvent->mClass) {
case eDragEventClass: {
WidgetDragEvent* dragEvent = tmp->mEvent->AsDragEvent();
@ -543,8 +545,6 @@ Event::EnsureWebAccessibleRelatedTarget(EventTarget* aRelatedTarget)
nsCOMPtr<EventTarget> relatedTarget = aRelatedTarget;
if (relatedTarget) {
nsCOMPtr<nsIContent> content = do_QueryInterface(relatedTarget);
nsCOMPtr<nsIContent> currentTarget =
do_QueryInterface(mEvent->mCurrentTarget);
if (content && content->ChromeOnlyAccess() &&
!nsContentUtils::CanAccessNativeAnon()) {
@ -552,12 +552,6 @@ Event::EnsureWebAccessibleRelatedTarget(EventTarget* aRelatedTarget)
relatedTarget = do_QueryInterface(content);
}
nsIContent* shadowRelatedTarget =
GetShadowRelatedTarget(currentTarget, content);
if (shadowRelatedTarget) {
relatedTarget = shadowRelatedTarget;
}
if (relatedTarget) {
relatedTarget = relatedTarget->GetTargetForDOMEvent();
}
@ -1218,44 +1212,6 @@ Event::SetOwner(EventTarget* aOwner)
#endif
}
// static
nsIContent*
Event::GetShadowRelatedTarget(nsIContent* aCurrentTarget,
nsIContent* aRelatedTarget)
{
if (!aCurrentTarget || !aRelatedTarget) {
return nullptr;
}
// Walk up the ancestor node trees of the related target until
// we encounter the node tree of the current target in order
// to find the adjusted related target. Walking up the tree may
// not find a common ancestor node tree if the related target is in
// an ancestor tree, but in that case it does not need to be adjusted.
ShadowRoot* currentTargetShadow = aCurrentTarget->GetContainingShadow();
if (!currentTargetShadow) {
return nullptr;
}
nsIContent* relatedTarget = aCurrentTarget;
while (relatedTarget) {
ShadowRoot* ancestorShadow = relatedTarget->GetContainingShadow();
if (currentTargetShadow == ancestorShadow) {
return relatedTarget;
}
// Didn't find the ancestor tree, thus related target does not have to
// adjusted.
if (!ancestorShadow) {
return nullptr;
}
relatedTarget = ancestorShadow->GetHost();
}
return nullptr;
}
void
Event::GetWidgetEventType(WidgetEvent* aEvent, nsAString& aType)
{

Просмотреть файл

@ -267,14 +267,6 @@ public:
return mIsMainThreadEvent;
}
/**
* For a given current target, returns the related target adjusted with
* shadow DOM retargeting rules. Returns nullptr if related target
* is not adjusted.
*/
static nsIContent* GetShadowRelatedTarget(nsIContent* aCurrentTarget,
nsIContent* aRelatedTarget);
void MarkUninitialized()
{
mEvent->mMessage = eVoidEvent;

Просмотреть файл

@ -200,6 +200,16 @@ public:
mNewTarget = aNewTarget;
}
EventTarget* GetRetargetedRelatedTarget()
{
return mRetargetedRelatedTarget;
}
void SetRetargetedRelatedTarget(EventTarget* aTarget)
{
mRetargetedRelatedTarget = aTarget;
}
void SetForceContentDispatch(bool aForce)
{
mFlags.mForceContentDispatch = aForce;
@ -350,6 +360,7 @@ public:
private:
nsCOMPtr<EventTarget> mTarget;
nsCOMPtr<EventTarget> mRetargetedRelatedTarget;
class EventTargetChainFlags
{
@ -418,6 +429,7 @@ EventTargetChainItem::GetEventTargetParent(EventChainPreVisitor& aVisitor)
SetWantsPreHandleEvent(aVisitor.mWantsPreHandleEvent);
SetPreHandleEventOnly(aVisitor.mWantsPreHandleEvent && !aVisitor.mCanHandle);
SetRootOfClosedTree(aVisitor.mRootOfClosedTree);
SetRetargetedRelatedTarget(aVisitor.mRetargetedRelatedTarget);
mItemFlags = aVisitor.mItemFlags;
mItemData = aVisitor.mItemData;
}
@ -450,6 +462,7 @@ EventTargetChainItem::HandleEventTargetChain(
{
// Save the target so that it can be restored later.
nsCOMPtr<EventTarget> firstTarget = aVisitor.mEvent->mTarget;
nsCOMPtr<EventTarget> firstRelatedTarget = aVisitor.mEvent->mRelatedTarget;
uint32_t chainLength = aChain.Length();
uint32_t firstCanHandleEventTargetIdx =
EventTargetChainItem::GetFirstCanHandleEventTargetIdx(aChain);
@ -479,6 +492,30 @@ EventTargetChainItem::HandleEventTargetChain(
}
}
}
// https://dom.spec.whatwg.org/#dispatching-events
// Step 14.2
// "Set event's relatedTarget to tuple's relatedTarget."
// Note, the initial retargeting was done already when creating
// event target chain, so we need to do this only after calling
// HandleEvent, not before, like in the specification.
if (item.GetRetargetedRelatedTarget()) {
bool found = false;
for (uint32_t j = i; j > 0; --j) {
uint32_t childIndex = j - 1;
EventTarget* relatedTarget =
aChain[childIndex].GetRetargetedRelatedTarget();
if (relatedTarget) {
found = true;
aVisitor.mEvent->mRelatedTarget = relatedTarget;
break;
}
}
if (!found) {
aVisitor.mEvent->mRelatedTarget =
aVisitor.mEvent->mOriginalRelatedTarget;
}
}
}
// Target
@ -507,6 +544,14 @@ EventTargetChainItem::HandleEventTargetChain(
aVisitor.mEvent->mTarget = newTarget;
}
// https://dom.spec.whatwg.org/#dispatching-events
// Step 15.2
// "Set event's relatedTarget to tuple's relatedTarget."
EventTarget* relatedTarget = item.GetRetargetedRelatedTarget();
if (relatedTarget) {
aVisitor.mEvent->mRelatedTarget = relatedTarget;
}
if (aVisitor.mEvent->mFlags.mBubbles || newTarget) {
if ((!aVisitor.mEvent->mFlags.mNoContentDispatch ||
item.ForceContentDispatch()) &&
@ -529,6 +574,7 @@ EventTargetChainItem::HandleEventTargetChain(
// Setting back the original target of the event.
aVisitor.mEvent->mTarget = aVisitor.mEvent->mOriginalTarget;
aVisitor.mEvent->mRelatedTarget = aVisitor.mEvent->mOriginalRelatedTarget;
// Special handling if PresShell (or some other caller)
// used a callback object.
@ -539,6 +585,7 @@ EventTargetChainItem::HandleEventTargetChain(
// Retarget for system event group (which does the default handling too).
// Setting back the target which was used also for default event group.
aVisitor.mEvent->mTarget = firstTarget;
aVisitor.mEvent->mRelatedTarget = firstRelatedTarget;
aVisitor.mEvent->mFlags.mInSystemGroup = true;
HandleEventTargetChain(aChain,
aVisitor,
@ -596,6 +643,7 @@ MayRetargetToChromeIfCanNotHandleEvent(
EventTargetChainItem::DestroyLast(aChain, aTargetEtci);
}
if (aPreVisitor.mAutomaticChromeDispatch && aContent) {
aPreVisitor.mRelatedTargetRetargetedInCurrentScope = false;
// Event target couldn't handle the event. Try to propagate to chrome.
EventTargetChainItem* chromeTargetEtci =
EventTargetChainItemForChromeTarget(aChain, aContent, aChildEtci);
@ -767,9 +815,10 @@ EventDispatcher::Dispatch(nsISupports* aTarget,
aEvent->mOriginalTarget = aEvent->mTarget;
}
aEvent->mOriginalRelatedTarget = aEvent->mRelatedTarget;
nsCOMPtr<nsIContent> content = do_QueryInterface(aEvent->mOriginalTarget);
bool isInAnon = (content && (content->IsInAnonymousSubtree() ||
content->IsInShadowTree()));
bool isInAnon = content && content->IsInAnonymousSubtree();
aEvent->mFlags.mIsBeingDispatched = true;
@ -777,7 +826,7 @@ EventDispatcher::Dispatch(nsISupports* aTarget,
// GetEventTargetParent for the original target.
nsEventStatus status = aEventStatus ? *aEventStatus : nsEventStatus_eIgnore;
EventChainPreVisitor preVisitor(aPresContext, aEvent, aDOMEvent, status,
isInAnon);
isInAnon, aEvent->mTarget);
targetEtci->GetEventTargetParent(preVisitor);
if (!preVisitor.mCanHandle) {
@ -815,12 +864,18 @@ EventDispatcher::Dispatch(nsISupports* aTarget,
if (preVisitor.mEventTargetAtParent) {
// Need to set the target of the event
// so that also the next retargeting works.
preVisitor.mTargetInKnownToBeHandledScope = preVisitor.mEvent->mTarget;
preVisitor.mEvent->mTarget = preVisitor.mEventTargetAtParent;
parentEtci->SetNewTarget(preVisitor.mEventTargetAtParent);
}
if (preVisitor.mRetargetedRelatedTarget) {
preVisitor.mEvent->mRelatedTarget = preVisitor.mRetargetedRelatedTarget;
}
parentEtci->GetEventTargetParent(preVisitor);
if (preVisitor.mCanHandle) {
preVisitor.mTargetInKnownToBeHandledScope = preVisitor.mEvent->mTarget;
topEtci = parentEtci;
} else {
nsCOMPtr<nsINode> disabledTarget = do_QueryInterface(parentTarget);
@ -830,6 +885,7 @@ EventDispatcher::Dispatch(nsISupports* aTarget,
topEtci,
disabledTarget);
if (parentEtci && preVisitor.mCanHandle) {
preVisitor.mTargetInKnownToBeHandledScope = preVisitor.mEvent->mTarget;
EventTargetChainItem* item =
EventTargetChainItem::GetFirstCanHandleEventTarget(chain);
item->SetNewTarget(parentTarget);
@ -875,6 +931,18 @@ EventDispatcher::Dispatch(nsISupports* aTarget,
aEvent->mFlags.mIsBeingDispatched = false;
aEvent->mFlags.mDispatchedAtLeastOnce = true;
// https://dom.spec.whatwg.org/#concept-event-dispatch
// Step 18
// "If target's root is a shadow root, then set event's target attribute and
// event's relatedTarget to null."
nsCOMPtr<nsIContent> finalTarget = do_QueryInterface(aEvent->mTarget);
if (finalTarget && finalTarget->SubtreeRoot()->IsShadowRoot()) {
aEvent->mTarget = nullptr;
aEvent->mOriginalTarget = nullptr;
aEvent->mRelatedTarget = nullptr;
aEvent->mOriginalRelatedTarget = nullptr;
}
if (!externalDOMEvent && preVisitor.mDOMEvent) {
// An dom::Event was created while dispatching the event.
// Duplicate private data if someone holds a pointer to it.

Просмотреть файл

@ -115,7 +115,8 @@ public:
WidgetEvent* aEvent,
nsIDOMEvent* aDOMEvent,
nsEventStatus aEventStatus,
bool aIsInAnon)
bool aIsInAnon,
dom::EventTarget* aTargetInKnownToBeHandledScope)
: EventChainVisitor(aPresContext, aEvent, aDOMEvent, aEventStatus)
, mCanHandle(true)
, mAutomaticChromeDispatch(true)
@ -128,8 +129,11 @@ public:
, mRootOfClosedTree(false)
, mParentIsSlotInClosedTree(false)
, mParentIsChromeHandler(false)
, mRelatedTargetRetargetedInCurrentScope(false)
, mParentTarget(nullptr)
, mEventTargetAtParent(nullptr)
, mRetargetedRelatedTarget(nullptr)
, mTargetInKnownToBeHandledScope(aTargetInKnownToBeHandledScope)
{
}
@ -146,8 +150,12 @@ public:
mRootOfClosedTree = false;
mParentIsSlotInClosedTree = false;
mParentIsChromeHandler = false;
// Note, we don't clear mRelatedTargetRetargetedInCurrentScope explicitly,
// since it is used during event path creation to indicate whether
// relatedTarget may need to be retargeted.
mParentTarget = nullptr;
mEventTargetAtParent = nullptr;
mRetargetedRelatedTarget = nullptr;
}
dom::EventTarget* GetParentTarget()
@ -163,6 +171,13 @@ public:
}
}
void IgnoreCurrentTarget()
{
mCanHandle = false;
SetParentTarget(nullptr, false);
mEventTargetAtParent = nullptr;
}
/**
* 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
@ -231,6 +246,12 @@ public:
*/
bool mParentIsChromeHandler;
/**
* True if event's related target has been already retargeted in the
* current 'scope'. This should be set to false initially and whenever
* event path creation crosses shadow boundary.
*/
bool mRelatedTargetRetargetedInCurrentScope;
private:
/**
* Parent item in the event target chain.
@ -243,6 +264,19 @@ public:
* which should be used when the event is handled at mParentTarget.
*/
dom::EventTarget* mEventTargetAtParent;
/**
* If the related target of the event needs to be retargeted, set this
* to a new EventTarget.
*/
dom::EventTarget* mRetargetedRelatedTarget;
/**
* Set to the value of mEvent->mTarget of the previous scope in case of
* Shadow DOM or such, and if there is no anonymous content this just points
* to the initial target.
*/
dom::EventTarget* mTargetInKnownToBeHandledScope;
};
class EventChainPostVisitor : public mozilla::EventChainVisitor

Просмотреть файл

@ -1,43 +0,0 @@
[event-composed-path-with-related-target.html]
[Event path for an event with a relatedTarget. Event shoul be dispatched if 1) target and relatedTarget are same, and 2) they are not in a shadow tree.]
expected: FAIL
[Event path for an event with a relatedTarget. Event should stop at the shadow root]
expected: FAIL
[Event path for an event with a relatedTarget. Event should not be dispatched if 1) target and relatedTarget are same, and 2) both are in a shadow tree.]
expected: FAIL
[Event path for an event with a relatedTarget. target and relaterTarget do not share any shadow-including ancestor. target is in a shadow tree.]
expected: FAIL
[Event path for an event with a relatedTarget. target and relaterTarget do not share any shadow-including ancestor. target is not in a shadow tree]
expected: FAIL
[Event path for an event with a relatedTarget. target and relaterTarget share the same shadow-including ancestor. Both are in shadow trees.]
expected: FAIL
[Event path for an event with a relatedTarget. relaterTarget is a shadow-including ancestor of target.]
expected: FAIL
[Event path for an event with a relatedTarget. target is a shadow-including ancestor of relatedTarget.]
expected: FAIL
[Event path for an event with a relatedTarget. target is assigned to a slot.]
expected: FAIL
[Event path for an event with a relatedTarget. relatedTarget is assigned to a slot.]
expected: FAIL
[Event path for an event with a relatedTarget. Event should be dispatched at every slots.]
expected: FAIL
[Event path for an event with a relatedTarget. Event should be dispatched at every slots. relatedTarget should be correctly retargeted.]
expected: FAIL
[Event path for an event with a relatedTarget which is identical to target. Event should be dispatched and should stop at the shadow root.]
expected: FAIL
[Event path for an event with a relatedTarget. relatedTarget is a shadow-including ancestor of target.]
expected: FAIL

Просмотреть файл

@ -1,25 +0,0 @@
[event-post-dispatch.html]
[Event properties post dispatch with an open ShadowRoot (composed: false).]
expected: FAIL
[Event properties post dispatch with a closed ShadowRoot (composed: false).]
expected: FAIL
[Event properties post dispatch with nested ShadowRoots (composed: false).]
expected: FAIL
[Event properties post dispatch with relatedTarget in the same shadow tree. (composed: true)]
expected: FAIL
[Event properties post dispatch with relatedTarget in the same shadow tree. (composed: false)]
expected: FAIL
[Event properties post dispatch with relatedTarget in the document tree and the shadow tree. (composed: false)]
expected: FAIL
[Event properties post dispatch with relatedTarget in the different shadow trees. (composed: true)]
expected: FAIL
[Event properties post dispatch with relatedTarget in the different shadow trees. (composed: false)]
expected: FAIL

Просмотреть файл

@ -1,55 +0,0 @@
[event-with-related-target.html]
[Firing an event at B1a with relatedNode at B1 with open mode shadow trees]
expected: FAIL
[Firing an event at B1a with relatedNode at B1 with closed mode shadow trees]
expected: FAIL
[Firing an event at B1a with relatedNode at B1b1 with open mode shadow trees]
expected: FAIL
[Firing an event at B1a with relatedNode at B1b1 with closed mode shadow trees]
expected: FAIL
[Firing an event at B1b1 with relatedNode at B1a with open mode shadow trees]
expected: FAIL
[Firing an event at B1b1 with relatedNode at B1a with closed mode shadow trees]
expected: FAIL
[Firing an event at B1a with relatedNode at D1 with open mode shadow trees]
expected: FAIL
[Firing an event at B1a with relatedNode at D1 with closed mode shadow trees]
expected: FAIL
[Firing an event at D1 with relatedNode at B1a with open mode shadow trees]
expected: FAIL
[Firing an event at D1 with relatedNode at B1a with closed mode shadow trees]
expected: FAIL
[Firing an event at B1a with relatedNode at A1a with open mode shadow trees]
expected: FAIL
[Firing an event at B1a with relatedNode at A1a with closed mode shadow trees]
expected: FAIL
[Firing an event at A1a with relatedNode at B1a with open mode shadow trees]
expected: FAIL
[Firing an event at A1a with relatedNode at B1a with closed mode shadow trees]
expected: FAIL
[Firing an event at B1a with relatedNode at A1a (detached) with open mode shadow trees]
expected: FAIL
[Firing an event at B1a with relatedNode at A1a (detached) with closed mode shadow trees]
expected: FAIL
[Firing an event at A1a with relatedNode at B1a (detached) with open mode shadow trees]
expected: FAIL
[Firing an event at A1a with relatedNode at B1a (detached) with closed mode shadow trees]
expected: FAIL

Просмотреть файл

@ -1,4 +0,0 @@
[test-001.html]
[A_05_02_01_T1]
expected: FAIL

Просмотреть файл

@ -1,4 +0,0 @@
[test-002.html]
[A_05_02_02_T01]
expected: FAIL

Просмотреть файл

@ -566,6 +566,7 @@ public:
, mCurrentTarget(Move(aOther.mCurrentTarget))
, mOriginalTarget(Move(aOther.mOriginalTarget))
, mRelatedTarget(Move(aOther.mRelatedTarget))
, mOriginalRelatedTarget(Move(aOther.mOriginalRelatedTarget))
, mPath(Move(aOther.mPath))
{
MOZ_COUNT_CTOR(WidgetEvent);
@ -615,6 +616,7 @@ public:
/// The possible related target
nsCOMPtr<dom::EventTarget> mRelatedTarget;
nsCOMPtr<dom::EventTarget> mOriginalRelatedTarget;
nsTArray<EventTargetChainItem>* mPath;
@ -637,6 +639,8 @@ public:
mCurrentTarget = aCopyTargets ? aEvent.mCurrentTarget : nullptr;
mOriginalTarget = aCopyTargets ? aEvent.mOriginalTarget : nullptr;
mRelatedTarget = aCopyTargets ? aEvent.mRelatedTarget : nullptr;
mOriginalRelatedTarget =
aCopyTargets ? aEvent.mOriginalRelatedTarget : nullptr;
}
/**