Bug 1304449: Part 3 - Modify AccessibleWrap to traverse using COM interfaces; r=tbsaunde

MozReview-Commit-ID: Ctimi1xHsj

--HG--
extra : rebase_source : 5b3f4c0783acca1717735216715e63a5bbf9c6f7
This commit is contained in:
Aaron Klotz 2016-10-05 17:52:35 -06:00
Родитель 5a833e9437
Коммит 5dea7c01ee
2 изменённых файлов: 340 добавлений и 253 удалений

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

@ -42,6 +42,7 @@
#include "nsEventMap.h" #include "nsEventMap.h"
#include "nsArrayUtils.h" #include "nsArrayUtils.h"
#include "mozilla/Preferences.h" #include "mozilla/Preferences.h"
#include "nsIXULRuntime.h"
#include "oleacc.h" #include "oleacc.h"
@ -60,9 +61,9 @@ const uint32_t USE_ROLE_STRING = 0;
static gAccessibles = 0; static gAccessibles = 0;
#endif #endif
#ifdef _WIN64 MsaaIdGenerator AccessibleWrap::sIDGen;
IDSet AccessibleWrap::sIDGen;
#endif static const VARIANT kVarChildIdSelf = {VT_I4};
static const int32_t kIEnumVariantDisconnected = -1; static const int32_t kIEnumVariantDisconnected = -1;
@ -77,10 +78,9 @@ AccessibleWrap::AccessibleWrap(nsIContent* aContent, DocAccessible* aDoc) :
AccessibleWrap::~AccessibleWrap() AccessibleWrap::~AccessibleWrap()
{ {
#ifdef _WIN64 if (mID != kNoID) {
if (mID != kNoID && XRE_IsParentProcess()) sIDGen.ReleaseID(this);
sIDGen.ReleaseID(mID); }
#endif
} }
ITypeInfo* AccessibleWrap::gTypeInfo = nullptr; ITypeInfo* AccessibleWrap::gTypeInfo = nullptr;
@ -249,22 +249,82 @@ AccessibleWrap::get_accChild(
// IAccessible::accChild is used to return this accessible or child accessible // IAccessible::accChild is used to return this accessible or child accessible
// at the given index or to get an accessible by child ID in the case of // at the given index or to get an accessible by child ID in the case of
// document accessible (it's handled by overriden GetXPAccessibleFor method // document accessible.
// on the document accessible). The getting an accessible by child ID is used // The getting an accessible by child ID is used by AccessibleObjectFromEvent()
// by AccessibleObjectFromEvent() called by AT when AT handles our MSAA event. // called by AT when AT handles our MSAA event.
Accessible* child = GetXPAccessibleFor(varChild); bool isDefunct = false;
if (!child) RefPtr<IAccessible> child = GetIAccessibleFor(varChild, &isDefunct);
if (!child) {
return E_INVALIDARG; return E_INVALIDARG;
}
if (child->IsDefunct()) if (isDefunct) {
return CO_E_OBJNOTCONNECTED; return CO_E_OBJNOTCONNECTED;
}
*ppdispChild = NativeAccessible(child); child.forget(ppdispChild);
return S_OK; return S_OK;
A11Y_TRYBLOCK_END A11Y_TRYBLOCK_END
} }
/**
* This function is a helper for implementing IAccessible methods that accept
* a Child ID as a parameter. If the child ID is CHILDID_SELF, the function
* returns S_OK but a null *aOutInterface. Otherwise, *aOutInterface points
* to the resolved IAccessible.
*
* The CHILDID_SELF case is special because in that case we actually execute
* the implementation of the IAccessible method, whereas in the non-self case,
* we delegate the method call to that object for execution.
*
* A sample invocation of this would look like:
*
* RefPtr<IAccessible> accessible;
* HRESULT hr = ResolveChild(varChild, getter_AddRefs(accessible));
* if (FAILED(hr)) {
* return hr;
* }
*
* if (accessible) {
* return accessible->get_accFoo(kVarChildIdSelf, pszName);
* }
*
* // Implementation for CHILDID_SELF case goes here
*/
HRESULT
AccessibleWrap::ResolveChild(const VARIANT& aVarChild,
IAccessible** aOutInterface)
{
MOZ_ASSERT(aOutInterface);
*aOutInterface = nullptr;
if (aVarChild.vt != VT_I4) {
return E_INVALIDARG;
}
if (IsDefunct()) {
return CO_E_OBJNOTCONNECTED;
}
if (aVarChild.lVal == CHILDID_SELF) {
return S_OK;
}
bool isDefunct = false;
RefPtr<IAccessible> accessible = GetIAccessibleFor(aVarChild, &isDefunct);
if (!accessible) {
return E_INVALIDARG;
}
if (isDefunct) {
return CO_E_OBJNOTCONNECTED;
}
accessible.forget(aOutInterface);
return S_OK;
}
STDMETHODIMP STDMETHODIMP
AccessibleWrap::get_accName( AccessibleWrap::get_accName(
/* [optional][in] */ VARIANT varChild, /* [optional][in] */ VARIANT varChild,
@ -272,23 +332,23 @@ AccessibleWrap::get_accName(
{ {
A11Y_TRYBLOCK_BEGIN A11Y_TRYBLOCK_BEGIN
if (!pszName) if (!pszName || varChild.vt != VT_I4)
return E_INVALIDARG; return E_INVALIDARG;
*pszName = nullptr; *pszName = nullptr;
if (IsDefunct()) RefPtr<IAccessible> accessible;
return CO_E_OBJNOTCONNECTED; HRESULT hr = ResolveChild(varChild, getter_AddRefs(accessible));
if (FAILED(hr)) {
return hr;
}
Accessible* xpAccessible = GetXPAccessibleFor(varChild); if (accessible) {
if (!xpAccessible) return accessible->get_accName(kVarChildIdSelf, pszName);
return E_INVALIDARG; }
if (xpAccessible->IsDefunct())
return CO_E_OBJNOTCONNECTED;
nsAutoString name; nsAutoString name;
xpAccessible->Name(name); Name(name);
// The name was not provided, e.g. no alt attribute for an image. A screen // The name was not provided, e.g. no alt attribute for an image. A screen
// reader may choose to invent its own accessible name, e.g. from an image src // reader may choose to invent its own accessible name, e.g. from an image src
@ -317,18 +377,18 @@ AccessibleWrap::get_accValue(
*pszValue = nullptr; *pszValue = nullptr;
if (IsDefunct()) RefPtr<IAccessible> accessible;
return CO_E_OBJNOTCONNECTED; HRESULT hr = ResolveChild(varChild, getter_AddRefs(accessible));
if (FAILED(hr)) {
return hr;
}
Accessible* xpAccessible = GetXPAccessibleFor(varChild); if (accessible) {
if (!xpAccessible) return accessible->get_accValue(kVarChildIdSelf, pszValue);
return E_INVALIDARG; }
if (xpAccessible->IsDefunct())
return CO_E_OBJNOTCONNECTED;
nsAutoString value; nsAutoString value;
xpAccessible->Value(value); Value(value);
// See bug 438784: need to expose URL on doc's value attribute. For this, // See bug 438784: need to expose URL on doc's value attribute. For this,
// reverting part of fix for bug 425693 to make this MSAA method behave // reverting part of fix for bug 425693 to make this MSAA method behave
@ -355,18 +415,18 @@ AccessibleWrap::get_accDescription(VARIANT varChild,
*pszDescription = nullptr; *pszDescription = nullptr;
if (IsDefunct()) RefPtr<IAccessible> accessible;
return CO_E_OBJNOTCONNECTED; HRESULT hr = ResolveChild(varChild, getter_AddRefs(accessible));
if (FAILED(hr)) {
return hr;
}
Accessible* xpAccessible = GetXPAccessibleFor(varChild); if (accessible) {
if (!xpAccessible) return accessible->get_accDescription(kVarChildIdSelf, pszDescription);
return E_INVALIDARG; }
if (xpAccessible->IsDefunct())
return CO_E_OBJNOTCONNECTED;
nsAutoString description; nsAutoString description;
xpAccessible->Description(description); Description(description);
*pszDescription = ::SysAllocStringLen(description.get(), *pszDescription = ::SysAllocStringLen(description.get(),
description.Length()); description.Length());
@ -387,23 +447,23 @@ AccessibleWrap::get_accRole(
VariantInit(pvarRole); VariantInit(pvarRole);
if (IsDefunct()) RefPtr<IAccessible> accessible;
return CO_E_OBJNOTCONNECTED; HRESULT hr = ResolveChild(varChild, getter_AddRefs(accessible));
if (FAILED(hr)) {
return hr;
}
Accessible* xpAccessible = GetXPAccessibleFor(varChild); if (accessible) {
if (!xpAccessible) return accessible->get_accRole(kVarChildIdSelf, pvarRole);
return E_INVALIDARG; }
if (xpAccessible->IsDefunct())
return CO_E_OBJNOTCONNECTED;
a11y::role geckoRole; a11y::role geckoRole;
#ifdef DEBUG #ifdef DEBUG
NS_ASSERTION(nsAccUtils::IsTextInterfaceSupportCorrect(xpAccessible), NS_ASSERTION(nsAccUtils::IsTextInterfaceSupportCorrect(this),
"Does not support Text when it should"); "Does not support Text when it should");
#endif #endif
geckoRole = xpAccessible->Role(); geckoRole = Role();
uint32_t msaaRole = 0; uint32_t msaaRole = 0;
@ -440,7 +500,7 @@ AccessibleWrap::get_accRole(
// -- Try BSTR role // -- Try BSTR role
// Could not map to known enumerated MSAA role like ROLE_BUTTON // Could not map to known enumerated MSAA role like ROLE_BUTTON
// Use BSTR role to expose role attribute or tag name + namespace // Use BSTR role to expose role attribute or tag name + namespace
nsIContent *content = xpAccessible->GetContent(); nsIContent *content = GetContent();
if (!content) if (!content)
return E_FAIL; return E_FAIL;
@ -489,15 +549,15 @@ AccessibleWrap::get_accState(
pvarState->vt = VT_I4; pvarState->vt = VT_I4;
pvarState->lVal = 0; pvarState->lVal = 0;
if (IsDefunct()) RefPtr<IAccessible> accessible;
return CO_E_OBJNOTCONNECTED; HRESULT hr = ResolveChild(varChild, getter_AddRefs(accessible));
if (FAILED(hr)) {
return hr;
}
Accessible* xpAccessible = GetXPAccessibleFor(varChild); if (accessible) {
if (!xpAccessible) return accessible->get_accState(kVarChildIdSelf, pvarState);
return E_INVALIDARG; }
if (xpAccessible->IsDefunct())
return CO_E_OBJNOTCONNECTED;
// MSAA only has 31 states and the lowest 31 bits of our state bit mask // MSAA only has 31 states and the lowest 31 bits of our state bit mask
// are the same states as MSAA. // are the same states as MSAA.
@ -563,19 +623,20 @@ AccessibleWrap::get_accKeyboardShortcut(
return E_INVALIDARG; return E_INVALIDARG;
*pszKeyboardShortcut = nullptr; *pszKeyboardShortcut = nullptr;
if (IsDefunct()) RefPtr<IAccessible> accessible;
return CO_E_OBJNOTCONNECTED; HRESULT hr = ResolveChild(varChild, getter_AddRefs(accessible));
if (FAILED(hr)) {
return hr;
}
Accessible* acc = GetXPAccessibleFor(varChild); if (accessible) {
if (!acc) return accessible->get_accKeyboardShortcut(kVarChildIdSelf,
return E_INVALIDARG; pszKeyboardShortcut);
}
if (acc->IsDefunct()) KeyBinding keyBinding = AccessKey();
return CO_E_OBJNOTCONNECTED;
KeyBinding keyBinding = acc->AccessKey();
if (keyBinding.IsEmpty()) if (keyBinding.IsEmpty())
keyBinding = acc->KeyboardShortcut(); keyBinding = KeyboardShortcut();
nsAutoString shortcut; nsAutoString shortcut;
keyBinding.ToString(shortcut); keyBinding.ToString(shortcut);
@ -796,18 +857,18 @@ AccessibleWrap::get_accDefaultAction(
*pszDefaultAction = nullptr; *pszDefaultAction = nullptr;
if (IsDefunct()) RefPtr<IAccessible> accessible;
return CO_E_OBJNOTCONNECTED; HRESULT hr = ResolveChild(varChild, getter_AddRefs(accessible));
if (FAILED(hr)) {
return hr;
}
Accessible* xpAccessible = GetXPAccessibleFor(varChild); if (accessible) {
if (!xpAccessible) return accessible->get_accDefaultAction(kVarChildIdSelf, pszDefaultAction);
return E_INVALIDARG; }
if (xpAccessible->IsDefunct())
return CO_E_OBJNOTCONNECTED;
nsAutoString defaultAction; nsAutoString defaultAction;
xpAccessible->ActionNameAt(0, defaultAction); ActionNameAt(0, defaultAction);
*pszDefaultAction = ::SysAllocStringLen(defaultAction.get(), *pszDefaultAction = ::SysAllocStringLen(defaultAction.get(),
defaultAction.Length()); defaultAction.Length());
@ -823,16 +884,15 @@ AccessibleWrap::accSelect(
{ {
A11Y_TRYBLOCK_BEGIN A11Y_TRYBLOCK_BEGIN
if (IsDefunct()) RefPtr<IAccessible> accessible;
return CO_E_OBJNOTCONNECTED; HRESULT hr = ResolveChild(varChild, getter_AddRefs(accessible));
if (FAILED(hr)) {
return hr;
}
// currently only handle focus and selection if (accessible) {
Accessible* xpAccessible = GetXPAccessibleFor(varChild); return accessible->accSelect(flagsSelect, kVarChildIdSelf);
if (!xpAccessible) }
return E_INVALIDARG;
if (xpAccessible->IsDefunct())
return CO_E_OBJNOTCONNECTED;
if (flagsSelect & SELFLAG_TAKEFOCUS) { if (flagsSelect & SELFLAG_TAKEFOCUS) {
if (XRE_IsContentProcess()) { if (XRE_IsContentProcess()) {
@ -841,26 +901,26 @@ AccessibleWrap::accSelect(
// is happening, so we dispatch TakeFocus from the main thread to // is happening, so we dispatch TakeFocus from the main thread to
// guarantee that we are outside any IPC. // guarantee that we are outside any IPC.
nsCOMPtr<nsIRunnable> runnable = nsCOMPtr<nsIRunnable> runnable =
mozilla::NewRunnableMethod(xpAccessible, &Accessible::TakeFocus); mozilla::NewRunnableMethod(this, &Accessible::TakeFocus);
NS_DispatchToMainThread(runnable, NS_DISPATCH_NORMAL); NS_DispatchToMainThread(runnable, NS_DISPATCH_NORMAL);
return S_OK; return S_OK;
} }
xpAccessible->TakeFocus(); TakeFocus();
return S_OK; return S_OK;
} }
if (flagsSelect & SELFLAG_TAKESELECTION) { if (flagsSelect & SELFLAG_TAKESELECTION) {
xpAccessible->TakeSelection(); TakeSelection();
return S_OK; return S_OK;
} }
if (flagsSelect & SELFLAG_ADDSELECTION) { if (flagsSelect & SELFLAG_ADDSELECTION) {
xpAccessible->SetSelected(true); SetSelected(true);
return S_OK; return S_OK;
} }
if (flagsSelect & SELFLAG_REMOVESELECTION) { if (flagsSelect & SELFLAG_REMOVESELECTION) {
xpAccessible->SetSelected(false); SetSelected(false);
return S_OK; return S_OK;
} }
@ -887,17 +947,18 @@ AccessibleWrap::accLocation(
*pcxWidth = 0; *pcxWidth = 0;
*pcyHeight = 0; *pcyHeight = 0;
if (IsDefunct()) RefPtr<IAccessible> accessible;
return CO_E_OBJNOTCONNECTED; HRESULT hr = ResolveChild(varChild, getter_AddRefs(accessible));
if (FAILED(hr)) {
return hr;
}
Accessible* xpAccessible = GetXPAccessibleFor(varChild); if (accessible) {
if (!xpAccessible) return accessible->accLocation(pxLeft, pyTop, pcxWidth, pcyHeight,
return E_INVALIDARG; kVarChildIdSelf);
}
if (xpAccessible->IsDefunct()) nsIntRect rect = Bounds();
return CO_E_OBJNOTCONNECTED;
nsIntRect rect = xpAccessible->Bounds();
*pxLeft = rect.x; *pxLeft = rect.x;
*pyTop = rect.y; *pyTop = rect.y;
@ -921,15 +982,15 @@ AccessibleWrap::accNavigate(
VariantInit(pvarEndUpAt); VariantInit(pvarEndUpAt);
if (IsDefunct()) RefPtr<IAccessible> accessible;
return CO_E_OBJNOTCONNECTED; HRESULT hr = ResolveChild(varStart, getter_AddRefs(accessible));
if (FAILED(hr)) {
return hr;
}
Accessible* accessible = GetXPAccessibleFor(varStart); if (accessible) {
if (!accessible) return accessible->accNavigate(navDir, kVarChildIdSelf, pvarEndUpAt);
return E_INVALIDARG; }
if (accessible->IsDefunct())
return CO_E_OBJNOTCONNECTED;
Accessible* navAccessible = nullptr; Accessible* navAccessible = nullptr;
Maybe<RelationType> xpRelation; Maybe<RelationType> xpRelation;
@ -941,34 +1002,34 @@ AccessibleWrap::accNavigate(
switch(navDir) { switch(navDir) {
case NAVDIR_FIRSTCHILD: case NAVDIR_FIRSTCHILD:
if (accessible->IsProxy()) { if (IsProxy()) {
if (!accessible->Proxy()->MustPruneChildren()) { if (!Proxy()->MustPruneChildren()) {
navAccessible = WrapperFor(accessible->Proxy()->FirstChild()); navAccessible = WrapperFor(Proxy()->FirstChild());
} }
} else { } else {
if (!nsAccUtils::MustPrune(accessible)) if (!nsAccUtils::MustPrune(this))
navAccessible = accessible->FirstChild(); navAccessible = FirstChild();
} }
break; break;
case NAVDIR_LASTCHILD: case NAVDIR_LASTCHILD:
if (accessible->IsProxy()) { if (IsProxy()) {
if (!accessible->Proxy()->MustPruneChildren()) { if (!Proxy()->MustPruneChildren()) {
navAccessible = WrapperFor(accessible->Proxy()->LastChild()); navAccessible = WrapperFor(Proxy()->LastChild());
} }
} else { } else {
if (!nsAccUtils::MustPrune(accessible)) if (!nsAccUtils::MustPrune(this))
navAccessible = accessible->LastChild(); navAccessible = LastChild();
} }
break; break;
case NAVDIR_NEXT: case NAVDIR_NEXT:
navAccessible = accessible->IsProxy() navAccessible = IsProxy()
? WrapperFor(accessible->Proxy()->NextSibling()) ? WrapperFor(Proxy()->NextSibling())
: accessible->NextSibling(); : NextSibling();
break; break;
case NAVDIR_PREVIOUS: case NAVDIR_PREVIOUS:
navAccessible = accessible->IsProxy() navAccessible = IsProxy()
? WrapperFor(accessible->Proxy()->PrevSibling()) ? WrapperFor(Proxy()->PrevSibling())
: accessible->PrevSibling(); : PrevSibling();
break; break;
case NAVDIR_DOWN: case NAVDIR_DOWN:
case NAVDIR_LEFT: case NAVDIR_LEFT:
@ -1046,17 +1107,17 @@ AccessibleWrap::accDoDefaultAction(
{ {
A11Y_TRYBLOCK_BEGIN A11Y_TRYBLOCK_BEGIN
if (IsDefunct()) RefPtr<IAccessible> accessible;
return CO_E_OBJNOTCONNECTED; HRESULT hr = ResolveChild(varChild, getter_AddRefs(accessible));
if (FAILED(hr)) {
return hr;
}
Accessible* xpAccessible = GetXPAccessibleFor(varChild); if (accessible) {
if (!xpAccessible) return accessible->accDoDefaultAction(kVarChildIdSelf);
return E_INVALIDARG; }
if (xpAccessible->IsDefunct()) return DoAction(0) ? S_OK : E_INVALIDARG;
return CO_E_OBJNOTCONNECTED;
return xpAccessible->DoAction(0) ? S_OK : E_INVALIDARG;
A11Y_TRYBLOCK_END A11Y_TRYBLOCK_END
} }
@ -1148,13 +1209,8 @@ AccessibleWrap::GetNativeInterface(void** aOutAccessible)
void void
AccessibleWrap::SetID(uint32_t aID) AccessibleWrap::SetID(uint32_t aID)
{ {
MOZ_ASSERT(XRE_IsContentProcess()); MOZ_ASSERT(XRE_IsParentProcess() && IsProxy());
mID = aID; mID = aID;
DocAccessibleWrap* doc = static_cast<DocAccessibleWrap*>(Document());
DebugOnly<AccessibleWrap*> checkAcc = nullptr;
MOZ_ASSERT(!(checkAcc = doc->GetAccessibleByID(aID)) ||
checkAcc->GetExistingID() == aID);
doc->AddID(aID, this);
} }
void void
@ -1257,15 +1313,14 @@ AccessibleWrap::GetChildIDFor(Accessible* aAccessible)
return 0; return 0;
} }
// Content should use mID which has been generated by the chrome process. // Chrome should use mID which has been generated by the content process.
if (XRE_IsContentProcess() && !aAccessible->IsApplication()) { if (aAccessible->IsProxy()) {
const uint32_t id = static_cast<AccessibleWrap*>(aAccessible)->mID; const uint32_t id = static_cast<AccessibleWrap*>(aAccessible)->mID;
MOZ_ASSERT(id != kNoID); MOZ_ASSERT(id != kNoID);
return id; return id;
} }
#ifdef _WIN64 if (!aAccessible->Document())
if (!aAccessible->Document() && !aAccessible->IsProxy())
return 0; return 0;
uint32_t* id = & static_cast<AccessibleWrap*>(aAccessible)->mID; uint32_t* id = & static_cast<AccessibleWrap*>(aAccessible)->mID;
@ -1274,27 +1329,12 @@ AccessibleWrap::GetChildIDFor(Accessible* aAccessible)
*id = sIDGen.GetID(); *id = sIDGen.GetID();
if (aAccessible->IsProxy()) { MOZ_ASSERT(!aAccessible->IsProxy());
DocProxyAccessibleWrap* doc =
static_cast<AccessibleWrap*>(aAccessible)->DocProxyWrapper();
doc->AddID(*id, static_cast<AccessibleWrap*>(aAccessible));
} else {
DocAccessibleWrap* doc = DocAccessibleWrap* doc =
static_cast<DocAccessibleWrap*>(aAccessible->Document()); static_cast<DocAccessibleWrap*>(aAccessible->Document());
doc->AddID(*id, static_cast<AccessibleWrap*>(aAccessible)); doc->AddID(*id, static_cast<AccessibleWrap*>(aAccessible));
}
return *id; return *id;
#else
int32_t id = - reinterpret_cast<intptr_t>(aAccessible);
if (aAccessible->IsProxy()) {
DocProxyAccessibleWrap* doc =
static_cast<AccessibleWrap*>(aAccessible)->DocProxyWrapper();
doc->AddID(id, static_cast<AccessibleWrap*>(aAccessible));
}
return id;
#endif
} }
HWND HWND
@ -1396,83 +1436,116 @@ GetAccessibleInSubtree(DocAccessible* aDoc, uint32_t aID)
return nullptr; return nullptr;
} }
static AccessibleWrap* static already_AddRefed<IDispatch>
GetProxiedAccessibleInSubtree(const DocAccessibleParent* aDoc, uint32_t aID) GetProxiedAccessibleInSubtree(const DocAccessibleParent* aDoc,
const VARIANT& aVarChild)
{ {
auto wrapper = static_cast<DocProxyAccessibleWrap*>(WrapperFor(aDoc)); auto wrapper = static_cast<DocProxyAccessibleWrap*>(WrapperFor(aDoc));
AccessibleWrap* child = wrapper->GetAccessibleByID(aID); RefPtr<IAccessible> comProxy;
if (child) { int32_t wrapperChildId = AccessibleWrap::GetChildIDFor(wrapper);
return child; if (wrapperChildId == aVarChild.lVal) {
} wrapper->GetNativeInterface(getter_AddRefs(comProxy));
return comProxy.forget();
size_t childDocs = aDoc->ChildDocCount();
for (size_t i = 0; i < childDocs; i++) {
const DocAccessibleParent* childDoc = aDoc->ChildDocAt(i);
child = GetProxiedAccessibleInSubtree(childDoc, aID);
if (child) {
return child;
}
} }
MOZ_ASSERT(aDoc->IsTopLevel());
if (!aDoc->IsTopLevel()) {
return nullptr; return nullptr;
} }
Accessible* wrapper->GetNativeInterface(getter_AddRefs(comProxy));
AccessibleWrap::GetXPAccessibleFor(const VARIANT& aVarChild)
RefPtr<IDispatch> disp;
if (FAILED(comProxy->get_accChild(aVarChild, getter_AddRefs(disp)))) {
return nullptr;
}
return disp.forget();
}
already_AddRefed<IAccessible>
AccessibleWrap::GetIAccessibleFor(const VARIANT& aVarChild, bool* aIsDefunct)
{ {
if (aVarChild.vt != VT_I4) if (aVarChild.vt != VT_I4)
return nullptr; return nullptr;
// if its us real easy - this seems to always be the case VARIANT varChild = aVarChild;
if (aVarChild.lVal == CHILDID_SELF)
return this; MOZ_ASSERT(aIsDefunct);
*aIsDefunct = false;
RefPtr<IAccessible> result;
if (varChild.lVal == CHILDID_SELF) {
*aIsDefunct = IsDefunct();
if (*aIsDefunct) {
return nullptr;
}
GetNativeInterface(getter_AddRefs(result));
if (result) {
return result.forget();
}
// If we're not a proxy, there's nothing more we can do to attempt to
// resolve the IAccessible, so we just fail.
if (!IsProxy()) {
return nullptr;
}
// Otherwise, since we're a proxy and we have a null native interface, this
// indicates that we need to obtain a COM proxy. To do this, we'll replace
// CHILDID_SELF with our real MSAA ID and continue the search from there.
varChild.lVal = GetExistingID();
}
if (IsProxy() ? Proxy()->MustPruneChildren() : nsAccUtils::MustPrune(this)) { if (IsProxy() ? Proxy()->MustPruneChildren() : nsAccUtils::MustPrune(this)) {
return nullptr; return nullptr;
} }
if (aVarChild.lVal > 0) { // If the MSAA ID is not a chrome id then we already know that we won't
// find it here and should look remotely instead.
if (XRE_IsParentProcess() && !sIDGen.IsChromeID(varChild.lVal)) {
return GetRemoteIAccessibleFor(varChild);
}
MOZ_ASSERT(XRE_IsParentProcess() ||
sIDGen.IsIDForThisContentProcess(varChild.lVal));
if (varChild.lVal > 0) {
// Gecko child indices are 0-based in contrast to indices used in MSAA. // Gecko child indices are 0-based in contrast to indices used in MSAA.
if (IsProxy()) { MOZ_ASSERT(!IsProxy());
if (static_cast<uint32_t>(aVarChild.lVal) > Proxy()->ChildrenCount()) { Accessible* xpAcc = GetChildAt(varChild.lVal - 1);
if (!xpAcc) {
return nullptr; return nullptr;
} }
*aIsDefunct = xpAcc->IsDefunct();
return WrapperFor(Proxy()->ChildAt(aVarChild.lVal - 1)); static_cast<AccessibleWrap*>(xpAcc)->GetNativeInterface(getter_AddRefs(result));
} else { return result.forget();
return GetChildAt(aVarChild.lVal - 1);
}
} }
// If lVal negative then it is treated as child ID and we should look for // If lVal negative then it is treated as child ID and we should look for
// accessible through whole accessible subtree including subdocuments. // accessible through whole accessible subtree including subdocuments.
// Otherwise we treat lVal as index in parent. // Otherwise we treat lVal as index in parent.
// Convert child ID to unique ID.
// First handle the case that both this accessible and the id'd one are in // First handle the case that both this accessible and the id'd one are in
// this process. // this process.
if (!IsProxy()) { if (!IsProxy()) {
void* uniqueID = reinterpret_cast<void*>(intptr_t(-aVarChild.lVal));
DocAccessible* document = Document(); DocAccessible* document = Document();
Accessible* child = Accessible* child =
#ifdef _WIN64 GetAccessibleInSubtree(document, static_cast<uint32_t>(varChild.lVal));
GetAccessibleInSubtree(document, static_cast<uint32_t>(aVarChild.lVal));
#else
XRE_IsContentProcess() ?
GetAccessibleInSubtree(document, static_cast<uint32_t>(aVarChild.lVal)) :
document->GetAccessibleByUniqueIDInSubtree(uniqueID);
#endif
// If it is a document then just return an accessible. // If it is a document then just return an accessible.
if (child && IsDoc()) if (child && IsDoc()) {
return child; *aIsDefunct = child->IsDefunct();
static_cast<AccessibleWrap*>(child)->GetNativeInterface(getter_AddRefs(result));
return result.forget();
}
// Otherwise check whether the accessible is a child (this path works for // Otherwise check whether the accessible is a child (this path works for
// ARIA documents and popups). // ARIA documents and popups).
Accessible* parent = child; Accessible* parent = child;
while (parent && parent != document) { while (parent && parent != document) {
if (parent == this) if (parent == this) {
return child; *aIsDefunct = child->IsDefunct();
static_cast<AccessibleWrap*>(child)->GetNativeInterface(getter_AddRefs(result));
return result.forget();
}
parent = parent->Parent(); parent = parent->Parent();
} }
@ -1480,34 +1553,26 @@ AccessibleWrap::GetXPAccessibleFor(const VARIANT& aVarChild)
// Now see about the case that both this accessible and the target one are // Now see about the case that both this accessible and the target one are
// proxied. // proxied.
uint32_t id = aVarChild.lVal;
if (IsProxy()) { if (IsProxy()) {
DocAccessibleParent* proxyDoc = Proxy()->Document(); DocAccessibleParent* proxyDoc = Proxy()->Document();
AccessibleWrap* wrapper = GetProxiedAccessibleInSubtree(proxyDoc, id); RefPtr<IDispatch> disp = GetProxiedAccessibleInSubtree(proxyDoc, varChild);
if (!wrapper) if (!disp) {
return nullptr; return nullptr;
MOZ_ASSERT(wrapper->IsProxy());
if (proxyDoc == this->Proxy()) {
return wrapper;
} }
ProxyAccessible* parent = wrapper->Proxy(); MOZ_ASSERT(mscom::IsProxy(disp));
while (parent && parent != proxyDoc) { DebugOnly<HRESULT> hr = disp->QueryInterface(IID_IAccessible,
if (parent == this->Proxy()) { getter_AddRefs(result));
return wrapper; MOZ_ASSERT(SUCCEEDED(hr));
} return result.forget();
parent = parent->Parent();
} }
return nullptr; return nullptr;
} }
// Finally we need to handle the case that this accessible is in the main already_AddRefed<IAccessible>
// process, but the target is proxied. This is the case when the target AccessibleWrap::GetRemoteIAccessibleFor(const VARIANT& aVarChild)
// accessible is in a child document of this one. {
DocAccessibleParent* proxyDoc = nullptr; DocAccessibleParent* proxyDoc = nullptr;
DocAccessible* doc = Document(); DocAccessible* doc = Document();
const nsTArray<DocAccessibleParent*>* remoteDocs = const nsTArray<DocAccessibleParent*>* remoteDocs =
@ -1516,9 +1581,18 @@ AccessibleWrap::GetXPAccessibleFor(const VARIANT& aVarChild)
return nullptr; return nullptr;
} }
RefPtr<IAccessible> result;
size_t docCount = remoteDocs->Length(); size_t docCount = remoteDocs->Length();
for (size_t i = 0; i < docCount; i++) { for (size_t i = 0; i < docCount; i++) {
Accessible* outerDoc = remoteDocs->ElementAt(i)->OuterDocOfRemoteBrowser(); DocAccessibleParent* remoteDoc = remoteDocs->ElementAt(i);
uint32_t remoteDocMsaaId = WrapperFor(remoteDoc)->GetExistingID();
if (!sIDGen.IsSameContentProcessFor(aVarChild.lVal, remoteDocMsaaId)) {
continue;
}
Accessible* outerDoc = remoteDoc->OuterDocOfRemoteBrowser();
if (!outerDoc) { if (!outerDoc) {
continue; continue;
} }
@ -1527,28 +1601,16 @@ AccessibleWrap::GetXPAccessibleFor(const VARIANT& aVarChild)
continue; continue;
} }
if (doc == this) { RefPtr<IDispatch> disp =
AccessibleWrap* proxyWrapper = GetProxiedAccessibleInSubtree(remoteDoc, aVarChild);
GetProxiedAccessibleInSubtree(remoteDocs->ElementAt(i), id); if (!disp) {
if (proxyWrapper) {
return proxyWrapper;
}
continue; continue;
} }
Accessible* parent = outerDoc; DebugOnly<HRESULT> hr = disp->QueryInterface(IID_IAccessible,
while (parent && parent != doc) { getter_AddRefs(result));
if (parent == this) { MOZ_ASSERT(SUCCEEDED(hr));
AccessibleWrap* proxyWrapper = return result.forget();
GetProxiedAccessibleInSubtree(remoteDocs->ElementAt(i), id);
if (proxyWrapper) {
return proxyWrapper;
}
}
parent = parent->Parent();
}
} }
return nullptr; return nullptr;
@ -1603,3 +1665,17 @@ AccessibleWrap::GetTI(LCID lcid)
return gTypeInfo; return gTypeInfo;
} }
/* static */
uint32_t
AccessibleWrap::GetContentProcessIdFor(dom::ContentParentId aIPCContentId)
{
return sIDGen.GetContentProcessIDFor(aIPCContentId);
}
/* static */
void
AccessibleWrap::ReleaseContentProcessIdFor(dom::ContentParentId aIPCContentId)
{
sIDGen.ReleaseContentProcessIDFor(aIPCContentId);
}

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

@ -14,8 +14,9 @@
#include "ia2AccessibleComponent.h" #include "ia2AccessibleComponent.h"
#include "ia2AccessibleHyperlink.h" #include "ia2AccessibleHyperlink.h"
#include "ia2AccessibleValue.h" #include "ia2AccessibleValue.h"
#include "mozilla/a11y/MsaaIdGenerator.h"
#include "mozilla/a11y/ProxyAccessible.h" #include "mozilla/a11y/ProxyAccessible.h"
#include "mozilla/a11y/IDSet.h" #include "mozilla/Attributes.h"
#ifdef __GNUC__ #ifdef __GNUC__
// Inheriting from both XPCOM and MSCOM interfaces causes a lot of warnings // Inheriting from both XPCOM and MSCOM interfaces causes a lot of warnings
@ -173,7 +174,8 @@ public: // construction, destruction
/** /**
* Find an accessible by the given child ID in cached documents. * Find an accessible by the given child ID in cached documents.
*/ */
Accessible* GetXPAccessibleFor(const VARIANT& aVarChild); MOZ_MUST_USE already_AddRefed<IAccessible>
GetIAccessibleFor(const VARIANT& aVarChild, bool* aIsDefunct);
virtual void GetNativeInterface(void **aOutAccessible) override; virtual void GetNativeInterface(void **aOutAccessible) override;
@ -181,14 +183,25 @@ public: // construction, destruction
uint32_t GetExistingID() const { return mID; } uint32_t GetExistingID() const { return mID; }
static const uint32_t kNoID = 0; static const uint32_t kNoID = 0;
// This is only valid to call in content
void SetID(uint32_t aID); void SetID(uint32_t aID);
static uint32_t GetContentProcessIdFor(dom::ContentParentId aIPCContentId);
static void ReleaseContentProcessIdFor(dom::ContentParentId aIPCContentId);
protected: protected:
virtual ~AccessibleWrap(); virtual ~AccessibleWrap();
uint32_t mID; uint32_t mID;
HRESULT
ResolveChild(const VARIANT& aVarChild, IAccessible** aOutInterface);
/**
* Find a remote accessible by the given child ID.
*/
MOZ_MUST_USE already_AddRefed<IAccessible>
GetRemoteIAccessibleFor(const VARIANT& aVarChild);
/** /**
* Return the wrapper for the document's proxy. * Return the wrapper for the document's proxy.
*/ */
@ -201,9 +214,7 @@ protected:
static ITypeInfo* gTypeInfo; static ITypeInfo* gTypeInfo;
#ifdef _WIN64 static MsaaIdGenerator sIDGen;
static IDSet sIDGen;
#endif
enum navRelations { enum navRelations {
NAVRELATION_CONTROLLED_BY = 0x1000, NAVRELATION_CONTROLLED_BY = 0x1000,