fune/accessible/android/RootAccessibleWrap.cpp
James Teh b9c87a600d Bug 1649253: Correctly assign an Android a11y id to OOP iframe documents. r=eeejay
The DocProxyAccessibleWrap for an OOP iframe document is always created before we know its parent.
Previously, this resulted in the document getting an id of -1, which is only valid for the root document.
It also broke subsequent assumptions once the parent was set later.

Because we don't have the parent in this case, we can't add the document's id to its parent's hash table.
To deal with this, we no longer add any document to its parent's hash table.
Instead, when finding an accessible by id, we just check the id of each child document before checking that child document's hash table.

Differential Revision: https://phabricator.services.mozilla.com/D81959
2020-07-02 17:20:38 +00:00

97 lines
2.8 KiB
C++

/* -*- Mode: c++; c-basic-offset: 2; tab-width: 20; indent-tabs-mode: nil; -*-
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "RootAccessibleWrap.h"
#include "Accessible-inl.h"
#include "AccessibleOrProxy.h"
#include "DocAccessibleParent.h"
#include "ProxyAccessibleWrap.h"
#include "SessionAccessibility.h"
#include "mozilla/PresShell.h"
using namespace mozilla;
using namespace mozilla::a11y;
RootAccessibleWrap::RootAccessibleWrap(dom::Document* aDoc,
PresShell* aPresShell)
: RootAccessible(aDoc, aPresShell) {}
RootAccessibleWrap::~RootAccessibleWrap() {}
AccessibleWrap* RootAccessibleWrap::GetContentAccessible() {
if (ProxyAccessible* proxy = GetPrimaryRemoteTopLevelContentDoc()) {
return WrapperFor(proxy);
}
// Find first document that is not defunct or hidden.
// This is exclusively for Fennec which has a deck of browser elements.
// Otherwise, standard GeckoView will only have one browser element.
for (size_t i = 0; i < ChildDocumentCount(); i++) {
DocAccessible* childDoc = GetChildDocumentAt(i);
if (childDoc && !childDoc->IsDefunct() && !childDoc->IsHidden()) {
return childDoc;
}
}
return nullptr;
}
AccessibleWrap* RootAccessibleWrap::FindAccessibleById(int32_t aID) {
AccessibleWrap* contentAcc = GetContentAccessible();
if (!contentAcc) {
return nullptr;
}
if (aID == AccessibleWrap::kNoID) {
return contentAcc;
}
if (contentAcc->IsProxy()) {
return FindAccessibleById(static_cast<DocProxyAccessibleWrap*>(contentAcc),
aID);
}
return FindAccessibleById(
static_cast<DocAccessibleWrap*>(contentAcc->AsDoc()), aID);
}
AccessibleWrap* RootAccessibleWrap::FindAccessibleById(
DocProxyAccessibleWrap* aDoc, int32_t aID) {
AccessibleWrap* acc = aDoc->GetAccessibleByID(aID);
uint32_t index = 0;
while (!acc) {
auto child =
static_cast<DocProxyAccessibleWrap*>(aDoc->GetChildDocumentAt(index++));
if (!child) {
break;
}
// A child document's id is not in its parent document's hash table.
if (child->VirtualViewID() == aID) {
acc = child;
} else {
acc = FindAccessibleById(child, aID);
}
}
return acc;
}
AccessibleWrap* RootAccessibleWrap::FindAccessibleById(DocAccessibleWrap* aDoc,
int32_t aID) {
AccessibleWrap* acc = aDoc->GetAccessibleByID(aID);
uint32_t index = 0;
while (!acc) {
auto child =
static_cast<DocAccessibleWrap*>(aDoc->GetChildDocumentAt(index++));
if (!child) {
break;
}
acc = FindAccessibleById(child, aID);
}
return acc;
}