Bug 1473234: make a11y listen to DOM events from iframes and shadow DOM. r=eeejay
1. Register with the root document window's parent target, since this receives events for iframes and shadow DOM. (The root document itself doesn't.) 2. Hold onto the target node when scheduling processing of the DOM event, as GetOriginalTarget returns null when we process shadow DOM events async. Depends on D21349 Differential Revision: https://phabricator.services.mozilla.com/D21350
This commit is contained in:
@@ -161,7 +161,11 @@ nsresult RootAccessible::AddEventListeners() {
|
||||
// receive untrusted events (synthetic events generated by untrusted code).
|
||||
// For example, XBL bindings implementations for elements that are hosted in
|
||||
// non chrome document fire untrusted events.
|
||||
nsCOMPtr<EventTarget> nstarget = mDocumentNode;
|
||||
// We must use the window's parent target in order to receive events from
|
||||
// iframes and shadow DOM; e.g. ValueChange events from a <select> in an
|
||||
// iframe or shadow DOM. The root document itself doesn't receive these.
|
||||
nsPIDOMWindowOuter* window = mDocumentNode->GetWindow();
|
||||
nsCOMPtr<EventTarget> nstarget = window ? window->GetParentTarget() : nullptr;
|
||||
|
||||
if (nstarget) {
|
||||
for (const char *const *e = kEventTypes, *const *e_end =
|
||||
@@ -177,7 +181,8 @@ nsresult RootAccessible::AddEventListeners() {
|
||||
}
|
||||
|
||||
nsresult RootAccessible::RemoveEventListeners() {
|
||||
nsCOMPtr<EventTarget> target = mDocumentNode;
|
||||
nsPIDOMWindowOuter* window = mDocumentNode->GetWindow();
|
||||
nsCOMPtr<EventTarget> target = window ? window->GetParentTarget() : nullptr;
|
||||
if (target) {
|
||||
for (const char *const *e = kEventTypes, *const *e_end =
|
||||
ArrayEnd(kEventTypes);
|
||||
@@ -203,6 +208,14 @@ void RootAccessible::DocumentActivated(DocAccessible* aDocument) {}
|
||||
NS_IMETHODIMP
|
||||
RootAccessible::HandleEvent(Event* aDOMEvent) {
|
||||
MOZ_ASSERT(aDOMEvent);
|
||||
if (IsDefunct()) {
|
||||
// Even though we've been shut down, RemoveEventListeners might not have
|
||||
// removed the event handlers on the window's parent target if GetWindow
|
||||
// returned null, so we might still get events here in this case. We should
|
||||
// just ignore these events.
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsINode> origTargetNode =
|
||||
do_QueryInterface(aDOMEvent->GetOriginalTarget());
|
||||
if (!origTargetNode) return NS_OK;
|
||||
@@ -222,46 +235,41 @@ RootAccessible::HandleEvent(Event* aDOMEvent) {
|
||||
// Root accessible exists longer than any of its descendant documents so
|
||||
// that we are guaranteed notification is processed before root accessible
|
||||
// is destroyed.
|
||||
document->HandleNotification<RootAccessible, Event>(
|
||||
this, &RootAccessible::ProcessDOMEvent, aDOMEvent);
|
||||
// For shadow DOM, GetOriginalTarget on the Event returns null if we
|
||||
// process the event async, so we must pass the target node as well.
|
||||
document->HandleNotification<RootAccessible, Event, nsINode>(
|
||||
this, &RootAccessible::ProcessDOMEvent, aDOMEvent, origTargetNode);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// RootAccessible protected
|
||||
void RootAccessible::ProcessDOMEvent(Event* aDOMEvent) {
|
||||
void RootAccessible::ProcessDOMEvent(Event* aDOMEvent, nsINode* aTarget) {
|
||||
MOZ_ASSERT(aDOMEvent);
|
||||
nsCOMPtr<nsINode> origTargetNode =
|
||||
do_QueryInterface(aDOMEvent->GetOriginalTarget());
|
||||
MOZ_ASSERT(aTarget);
|
||||
|
||||
nsAutoString eventType;
|
||||
aDOMEvent->GetType(eventType);
|
||||
|
||||
#ifdef A11Y_LOG
|
||||
if (logging::IsEnabled(logging::eDOMEvents))
|
||||
logging::DOMEvent("processed", origTargetNode, eventType);
|
||||
logging::DOMEvent("processed", aTarget, eventType);
|
||||
#endif
|
||||
|
||||
if (!origTargetNode) {
|
||||
// Original target has ceased to exist.
|
||||
return;
|
||||
}
|
||||
|
||||
if (eventType.EqualsLiteral("popuphiding")) {
|
||||
HandlePopupHidingEvent(origTargetNode);
|
||||
HandlePopupHidingEvent(aTarget);
|
||||
return;
|
||||
}
|
||||
|
||||
DocAccessible* targetDocument =
|
||||
GetAccService()->GetDocAccessible(origTargetNode->OwnerDoc());
|
||||
GetAccService()->GetDocAccessible(aTarget->OwnerDoc());
|
||||
if (!targetDocument) {
|
||||
// Document has ceased to exist.
|
||||
return;
|
||||
}
|
||||
|
||||
Accessible* accessible =
|
||||
targetDocument->GetAccessibleOrContainer(origTargetNode);
|
||||
Accessible* accessible = targetDocument->GetAccessibleOrContainer(aTarget);
|
||||
if (!accessible) return;
|
||||
|
||||
#ifdef MOZ_XUL
|
||||
|
||||
Reference in New Issue
Block a user