Bug 1449560 - clear event.target and .relatedTarget in case they would otherwise reveal targets in shadow DOM, r=bz

This commit is contained in:
Olli Pettay 2018-05-05 02:21:15 +03:00
parent 7d559398bd
commit 96c6253308
4 changed files with 44 additions and 9 deletions

View File

@ -1091,7 +1091,11 @@ nsIContent::GetEventTargetParent(EventChainPreVisitor& aVisitor)
// point to a node in Shadow DOM.
aVisitor.mEvent->mTarget = aVisitor.mTargetInKnownToBeHandledScope;
return;
} else {
} else if (targetInKnownToBeHandledScope) {
// Note, if targetInKnownToBeHandledScope is null,
// mTargetInKnownToBeHandledScope could be Window object in content
// page and we're in chrome document in the same process.
// Step 11.6
aVisitor.mRetargetedRelatedTarget = retargetedRelatedTarget;
}

View File

@ -656,6 +656,26 @@ MayRetargetToChromeIfCanNotHandleEvent(
return nullptr;
}
static bool
ShouldClearTargets(WidgetEvent* aEvent)
{
nsCOMPtr<nsIContent> finalTarget;
nsCOMPtr<nsIContent> finalRelatedTarget;
if ((finalTarget = do_QueryInterface(aEvent->mTarget)) &&
finalTarget->SubtreeRoot()->IsShadowRoot()) {
return true;
}
if ((finalRelatedTarget =
do_QueryInterface(aEvent->mRelatedTarget)) &&
finalRelatedTarget->SubtreeRoot()->IsShadowRoot()) {
return true;
}
//XXXsmaug Check also all the touch objects.
return false;
}
/* static */ nsresult
EventDispatcher::Dispatch(nsISupports* aTarget,
nsPresContext* aPresContext,
@ -836,6 +856,8 @@ EventDispatcher::Dispatch(nsISupports* aTarget,
aEvent->mOriginalRelatedTarget = aEvent->mRelatedTarget;
bool clearTargets = false;
nsCOMPtr<nsIContent> content = do_QueryInterface(aEvent->mOriginalTarget);
bool isInAnon = content && content->IsInAnonymousSubtree();
@ -859,6 +881,8 @@ EventDispatcher::Dispatch(nsISupports* aTarget,
for (uint32_t i = 0; i < chain.Length(); ++i) {
chain[i].PreHandleEvent(preVisitor);
}
clearTargets = ShouldClearTargets(aEvent);
} else {
// At least the original target can handle the event.
// Setting the retarget to the |target| simplifies retargeting code.
@ -927,6 +951,9 @@ EventDispatcher::Dispatch(nsISupports* aTarget,
for (uint32_t i = 0; i < chain.Length(); ++i) {
chain[i].PreHandleEvent(preVisitor);
}
clearTargets = ShouldClearTargets(aEvent);
// Handle the chain.
EventChainPostVisitor postVisitor(preVisitor);
MOZ_RELEASE_ASSERT(!aEvent->mPath);
@ -951,15 +978,16 @@ EventDispatcher::Dispatch(nsISupports* aTarget,
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()) {
// step 10. If clearTargets, then:
// 1. Set event's target to null.
// 2. Set event's relatedTarget to null.
// 3. Set event's touch target list to the empty list.
if (clearTargets) {
aEvent->mTarget = nullptr;
aEvent->mOriginalTarget = nullptr;
aEvent->mRelatedTarget = nullptr;
aEvent->mOriginalRelatedTarget = nullptr;
//XXXsmaug Check also all the touch objects.
}
if (!externalDOMEvent && preVisitor.mDOMEvent) {

View File

@ -1,4 +1,5 @@
[relatedTarget.window.html]
[Untitled]
prefs: [dom.webcomponents.shadowdom.enabled:true]
[Reset targets before activation behavior]
expected: FAIL

View File

@ -41,13 +41,15 @@ async_test(t => {
async_test(t => {
const shadowChild = shadow.appendChild(document.createElement("div"));
shadowChild.addEventListener("demo", t.step_func(() => document.body.appendChild(shadowChild)));
const shadowChild2 = shadow.appendChild(document.createElement("div"));
shadowChild2.addEventListener("demo", t.step_func(() => document.body.appendChild(shadowChild)));
const event = new FocusEvent("demo", { relatedTarget: shadowChild });
document.body.dispatchEvent(event);
shadowChild2.dispatchEvent(event);
assert_equals(shadowChild.parentNode, document.body);
assert_equals(event.target, null);
assert_equals(event.relatedTarget, null);
shadowChild.remove();
shadowChild2.remove();
t.done();
}, "Reset if relatedTarget pointed to a shadow tree pre-dispatch");