Bug 1268544: Refactor ProxyAccessible and dependencies; r=tbsaunde

MozReview-Commit-ID: EHV0JR6NmKf

--HG--
rename : accessible/ipc/ProxyAccessible.cpp => accessible/ipc/ProxyAccessibleBase.cpp
rename : accessible/ipc/ProxyAccessible.h => accessible/ipc/ProxyAccessibleBase.h
rename : accessible/ipc/ProxyAccessible.cpp => accessible/ipc/other/ProxyAccessible.cpp
rename : accessible/ipc/ProxyAccessible.h => accessible/ipc/other/ProxyAccessible.h
rename : accessible/ipc/ProxyAccessible.cpp => accessible/ipc/win/ProxyAccessible.cpp
rename : accessible/ipc/ProxyAccessible.h => accessible/ipc/win/ProxyAccessible.h
This commit is contained in:
Aaron Klotz 2016-08-19 13:16:42 -06:00
parent 1ee837c40c
commit 6691c8cfa8
12 changed files with 746 additions and 270 deletions

View File

@ -0,0 +1,159 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* 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 "DocAccessible.h"
#include "mozilla/a11y/DocAccessibleParent.h"
#include "mozilla/a11y/DocManager.h"
#include "mozilla/a11y/Platform.h"
#include "mozilla/a11y/ProxyAccessibleBase.h"
#include "mozilla/a11y/ProxyAccessible.h"
#include "mozilla/a11y/Role.h"
#include "mozilla/dom/Element.h"
#include "mozilla/dom/TabParent.h"
#include "mozilla/unused.h"
#include "RelationType.h"
#include "xpcAccessibleDocument.h"
namespace mozilla {
namespace a11y {
template <class Derived>
void
ProxyAccessibleBase<Derived>::Shutdown()
{
MOZ_DIAGNOSTIC_ASSERT(!IsDoc());
NS_ASSERTION(!mOuterDoc, "Why do we still have a child doc?");
xpcAccessibleDocument* xpcDoc =
GetAccService()->GetCachedXPCDocument(Document());
if (xpcDoc) {
xpcDoc->NotifyOfShutdown(static_cast<Derived*>(this));
}
// XXX Ideally this wouldn't be necessary, but it seems OuterDoc accessibles
// can be destroyed before the doc they own.
if (!mOuterDoc) {
uint32_t childCount = mChildren.Length();
for (uint32_t idx = 0; idx < childCount; idx++)
mChildren[idx]->Shutdown();
} else {
if (mChildren.Length() != 1)
MOZ_CRASH("outer doc doesn't own adoc!");
mChildren[0]->AsDoc()->Unbind();
}
mChildren.Clear();
ProxyDestroyed(static_cast<Derived*>(this));
mDoc->RemoveAccessible(static_cast<Derived*>(this));
}
template <class Derived>
void
ProxyAccessibleBase<Derived>::SetChildDoc(DocAccessibleParent* aParent)
{
if (aParent) {
MOZ_ASSERT(mChildren.IsEmpty());
mChildren.AppendElement(aParent);
mOuterDoc = true;
} else {
MOZ_ASSERT(mChildren.Length() == 1);
mChildren.Clear();
mOuterDoc = false;
}
}
template <class Derived>
bool
ProxyAccessibleBase<Derived>::MustPruneChildren() const
{
// this is the equivalent to nsAccUtils::MustPrune for proxies and should be
// kept in sync with that.
if (mRole != roles::MENUITEM && mRole != roles::COMBOBOX_OPTION
&& mRole != roles::OPTION && mRole != roles::ENTRY
&& mRole != roles::FLAT_EQUATION && mRole != roles::PASSWORD_TEXT
&& mRole != roles::PUSHBUTTON && mRole != roles::TOGGLE_BUTTON
&& mRole != roles::GRAPHIC && mRole != roles::SLIDER
&& mRole != roles::PROGRESSBAR && mRole != roles::SEPARATOR)
return false;
if (mChildren.Length() != 1)
return false;
return mChildren[0]->Role() == roles::TEXT_LEAF
|| mChildren[0]->Role() == roles::STATICTEXT;
}
template <class Derived>
uint32_t
ProxyAccessibleBase<Derived>::EmbeddedChildCount() const
{
size_t count = 0, kids = mChildren.Length();
for (size_t i = 0; i < kids; i++) {
if (mChildren[i]->IsEmbeddedObject()) {
count++;
}
}
return count;
}
template <class Derived>
int32_t
ProxyAccessibleBase<Derived>::IndexOfEmbeddedChild(const Derived* aChild)
{
size_t index = 0, kids = mChildren.Length();
for (size_t i = 0; i < kids; i++) {
if (mChildren[i]->IsEmbeddedObject()) {
if (mChildren[i] == aChild) {
return index;
}
index++;
}
}
return -1;
}
template <class Derived>
Derived*
ProxyAccessibleBase<Derived>::EmbeddedChildAt(size_t aChildIdx)
{
size_t index = 0, kids = mChildren.Length();
for (size_t i = 0; i < kids; i++) {
if (!mChildren[i]->IsEmbeddedObject()) {
continue;
}
if (index == aChildIdx) {
return mChildren[i];
}
index++;
}
return nullptr;
}
template <class Derived>
Accessible*
ProxyAccessibleBase<Derived>::OuterDocOfRemoteBrowser() const
{
auto tab = static_cast<dom::TabParent*>(mDoc->Manager());
dom::Element* frame = tab->GetOwnerElement();
NS_ASSERTION(frame, "why isn't the tab in a frame!");
if (!frame)
return nullptr;
DocAccessible* chromeDoc = GetExistingDocAccessible(frame->OwnerDoc());
return chromeDoc ? chromeDoc->GetAccessible(frame) : nullptr;
}
template class ProxyAccessibleBase<ProxyAccessible>;
} // namespace a11y
} // namespace mozilla

View File

@ -0,0 +1,189 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* 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/. */
#ifndef mozilla_a11y_ProxyAccessibleBase_h
#define mozilla_a11y_ProxyAccessibleBase_h
#include "mozilla/a11y/Role.h"
#include "nsIAccessibleText.h"
#include "nsIAccessibleTypes.h"
#include "Accessible.h"
#include "nsString.h"
#include "nsTArray.h"
#include "nsRect.h"
#include "Accessible.h"
namespace mozilla {
namespace a11y {
class Accessible;
class Attribute;
class DocAccessibleParent;
class ProxyAccessible;
enum class RelationType;
enum Interfaces
{
HYPERTEXT = 1,
HYPERLINK = 1 << 1,
IMAGE = 1 << 2,
VALUE = 1 << 3,
TABLE = 1 << 4,
TABLECELL = 1 << 5,
DOCUMENT = 1 << 6,
SELECTION = 1 << 7,
ACTION = 1 << 8,
};
template <class Derived>
class ProxyAccessibleBase
{
public:
~ProxyAccessibleBase()
{
MOZ_ASSERT(!mWrapper);
}
void AddChildAt(uint32_t aIdx, Derived* aChild)
{ mChildren.InsertElementAt(aIdx, aChild); }
uint32_t ChildrenCount() const { return mChildren.Length(); }
Derived* ChildAt(uint32_t aIdx) const { return mChildren[aIdx]; }
Derived* FirstChild() const
{ return mChildren.Length() ? mChildren[0] : nullptr; }
Derived* LastChild() const
{ return mChildren.Length() ? mChildren[mChildren.Length() - 1] : nullptr; }
Derived* PrevSibling() const
{
size_t idx = IndexInParent();
return idx > 0 ? Parent()->mChildren[idx - 1] : nullptr;
}
Derived* NextSibling() const
{
size_t idx = IndexInParent();
return idx + 1 < Parent()->mChildren.Length() ? Parent()->mChildren[idx + 1]
: nullptr;
}
// XXX evaluate if this is fast enough.
size_t IndexInParent() const { return
Parent()->mChildren.IndexOf(static_cast<const Derived*>(this)); }
uint32_t EmbeddedChildCount() const;
int32_t IndexOfEmbeddedChild(const Derived* aChild);
Derived* EmbeddedChildAt(size_t aChildIdx);
bool MustPruneChildren() const;
void Shutdown();
void SetChildDoc(DocAccessibleParent*);
/**
* Remove The given child.
*/
void RemoveChild(Derived* aChild)
{ mChildren.RemoveElement(aChild); }
/**
* Return the proxy for the parent of the wrapped accessible.
*/
Derived* Parent() const { return mParent; }
Accessible* OuterDocOfRemoteBrowser() const;
/**
* Get the role of the accessible we're proxying.
*/
role Role() const { return mRole; }
/**
* Return true if this is an embedded object.
*/
bool IsEmbeddedObject() const
{
role role = Role();
return role != roles::TEXT_LEAF &&
role != roles::WHITESPACE &&
role != roles::STATICTEXT;
}
/**
* Allow the platform to store a pointers worth of data on us.
*/
uintptr_t GetWrapper() const { return mWrapper; }
void SetWrapper(uintptr_t aWrapper) { mWrapper = aWrapper; }
/*
* Return the ID of the accessible being proxied.
*/
uint64_t ID() const { return mID; }
/**
* Return the document containing this proxy, or the proxy itself if it is a
* document.
*/
DocAccessibleParent* Document() const { return mDoc; }
/**
* Return true if this proxy is a DocAccessibleParent.
*/
bool IsDoc() const { return mIsDoc; }
DocAccessibleParent* AsDoc() const { return IsDoc() ? mDoc : nullptr; }
protected:
ProxyAccessibleBase(uint64_t aID, Derived* aParent,
DocAccessibleParent* aDoc, role aRole,
uint32_t aInterfaces)
: mParent(aParent)
, mDoc(aDoc)
, mWrapper(0)
, mID(aID)
, mRole(aRole)
, mOuterDoc(false)
, mIsDoc(false)
, mHasValue(aInterfaces & Interfaces::VALUE)
, mIsHyperLink(aInterfaces & Interfaces::HYPERLINK)
, mIsHyperText(aInterfaces & Interfaces::HYPERTEXT)
{
}
explicit ProxyAccessibleBase(DocAccessibleParent* aThisAsDoc) :
mParent(nullptr), mDoc(aThisAsDoc), mWrapper(0), mID(0),
mRole(roles::DOCUMENT), mOuterDoc(false), mIsDoc(true), mHasValue(false),
mIsHyperLink(false), mIsHyperText(false)
{}
protected:
Derived* mParent;
private:
friend Derived;
nsTArray<Derived*> mChildren;
DocAccessibleParent* mDoc;
uintptr_t mWrapper;
uint64_t mID;
protected:
// XXX DocAccessibleParent gets to change this to change the role of
// documents.
role mRole : 27;
private:
bool mOuterDoc : 1;
public:
const bool mIsDoc: 1;
const bool mHasValue: 1;
const bool mIsHyperLink: 1;
const bool mIsHyperText: 1;
};
extern template class ProxyAccessibleBase<ProxyAccessible>;
}
}
#endif

View File

@ -38,13 +38,13 @@ if CONFIG['ACCESSIBILITY']:
EXPORTS.mozilla.a11y += [
'DocAccessibleChildBase.h',
'DocAccessibleParent.h',
'ProxyAccessible.h'
'ProxyAccessibleBase.h',
]
UNIFIED_SOURCES += [
'DocAccessibleChildBase.cpp',
'DocAccessibleParent.cpp',
'ProxyAccessible.cpp'
'ProxyAccessibleBase.cpp',
]
LOCAL_INCLUDES += [

View File

@ -5,7 +5,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "ProxyAccessible.h"
#include "DocAccessibleParent.h"
#include "mozilla/a11y/DocAccessibleParent.h"
#include "DocAccessible.h"
#include "mozilla/a11y/DocManager.h"
#include "mozilla/dom/Element.h"
@ -19,69 +19,6 @@
namespace mozilla {
namespace a11y {
void
ProxyAccessible::Shutdown()
{
MOZ_DIAGNOSTIC_ASSERT(!IsDoc());
NS_ASSERTION(!mOuterDoc, "Why do we still have a child doc?");
xpcAccessibleDocument* xpcDoc =
GetAccService()->GetCachedXPCDocument(Document());
if (xpcDoc) {
xpcDoc->NotifyOfShutdown(this);
}
// XXX Ideally this wouldn't be necessary, but it seems OuterDoc accessibles
// can be destroyed before the doc they own.
if (!mOuterDoc) {
uint32_t childCount = mChildren.Length();
for (uint32_t idx = 0; idx < childCount; idx++)
mChildren[idx]->Shutdown();
} else {
if (mChildren.Length() != 1)
MOZ_CRASH("outer doc doesn't own adoc!");
mChildren[0]->AsDoc()->Unbind();
}
mChildren.Clear();
ProxyDestroyed(this);
mDoc->RemoveAccessible(this);
}
void
ProxyAccessible::SetChildDoc(DocAccessibleParent* aParent)
{
if (aParent) {
MOZ_ASSERT(mChildren.IsEmpty());
mChildren.AppendElement(aParent);
mOuterDoc = true;
} else {
MOZ_ASSERT(mChildren.Length() == 1);
mChildren.Clear();
mOuterDoc = false;
}
}
bool
ProxyAccessible::MustPruneChildren() const
{
// this is the equivalent to nsAccUtils::MustPrune for proxies and should be
// kept in sync with that.
if (mRole != roles::MENUITEM && mRole != roles::COMBOBOX_OPTION
&& mRole != roles::OPTION && mRole != roles::ENTRY
&& mRole != roles::FLAT_EQUATION && mRole != roles::PASSWORD_TEXT
&& mRole != roles::PUSHBUTTON && mRole != roles::TOGGLE_BUTTON
&& mRole != roles::GRAPHIC && mRole != roles::SLIDER
&& mRole != roles::PROGRESSBAR && mRole != roles::SEPARATOR)
return false;
if (mChildren.Length() != 1)
return false;
return mChildren[0]->Role() == roles::TEXT_LEAF
|| mChildren[0]->Role() == roles::STATICTEXT;
}
uint64_t
ProxyAccessible::State() const
{
@ -1032,55 +969,6 @@ ProxyAccessible::TakeFocus()
Unused << mDoc->SendTakeFocus(mID);
}
uint32_t
ProxyAccessible::EmbeddedChildCount() const
{
size_t count = 0, kids = mChildren.Length();
for (size_t i = 0; i < kids; i++) {
if (mChildren[i]->IsEmbeddedObject()) {
count++;
}
}
return count;
}
int32_t
ProxyAccessible::IndexOfEmbeddedChild(const ProxyAccessible* aChild)
{
size_t index = 0, kids = mChildren.Length();
for (size_t i = 0; i < kids; i++) {
if (mChildren[i]->IsEmbeddedObject()) {
if (mChildren[i] == aChild) {
return index;
}
index++;
}
}
return -1;
}
ProxyAccessible*
ProxyAccessible::EmbeddedChildAt(size_t aChildIdx)
{
size_t index = 0, kids = mChildren.Length();
for (size_t i = 0; i < kids; i++) {
if (!mChildren[i]->IsEmbeddedObject()) {
continue;
}
if (index == aChildIdx) {
return mChildren[i];
}
index++;
}
return nullptr;
}
ProxyAccessible*
ProxyAccessible::FocusedChild()
{
@ -1175,18 +1063,5 @@ ProxyAccessible::DOMNodeID(nsString& aID)
Unused << mDoc->SendDOMNodeID(mID, &aID);
}
Accessible*
ProxyAccessible::OuterDocOfRemoteBrowser() const
{
auto tab = static_cast<dom::TabParent*>(mDoc->Manager());
dom::Element* frame = tab->GetOwnerElement();
NS_ASSERTION(frame, "why isn't the tab in a frame!");
if (!frame)
return nullptr;
DocAccessible* chromeDoc = GetExistingDocAccessible(frame->OwnerDoc());
return chromeDoc ? chromeDoc->GetAccessible(frame) : nullptr;
}
}
}

View File

@ -7,115 +7,33 @@
#ifndef mozilla_a11y_ProxyAccessible_h
#define mozilla_a11y_ProxyAccessible_h
#include "Accessible.h"
#include "mozilla/a11y/ProxyAccessibleBase.h"
#include "mozilla/a11y/Role.h"
#include "nsIAccessibleText.h"
#include "nsIAccessibleTypes.h"
#include "Accessible.h"
#include "nsString.h"
#include "nsTArray.h"
#include "nsRect.h"
#include "Accessible.h"
namespace mozilla {
namespace a11y {
class Accessible;
class Attribute;
class DocAccessibleParent;
enum class RelationType;
enum Interfaces
{
HYPERTEXT = 1,
HYPERLINK = 1 << 1,
IMAGE = 1 << 2,
VALUE = 1 << 3,
TABLE = 1 << 4,
TABLECELL = 1 << 5,
DOCUMENT = 1 << 6,
SELECTION = 1 << 7,
ACTION = 1 << 8,
};
class ProxyAccessible
class ProxyAccessible : public ProxyAccessibleBase<ProxyAccessible>
{
public:
ProxyAccessible(uint64_t aID, ProxyAccessible* aParent,
DocAccessibleParent* aDoc, role aRole, uint32_t aInterfaces) :
mParent(aParent), mDoc(aDoc), mWrapper(0), mID(aID), mRole(aRole),
mOuterDoc(false), mIsDoc(false),
mHasValue(aInterfaces & Interfaces::VALUE),
mIsHyperLink(aInterfaces & Interfaces::HYPERLINK),
mIsHyperText(aInterfaces & Interfaces::HYPERTEXT)
DocAccessibleParent* aDoc, role aRole, uint32_t aInterfaces)
: ProxyAccessibleBase(aID, aParent, aDoc, aRole, aInterfaces)
{
MOZ_COUNT_CTOR(ProxyAccessible);
}
~ProxyAccessible()
{
MOZ_COUNT_DTOR(ProxyAccessible);
MOZ_ASSERT(!mWrapper);
}
void AddChildAt(uint32_t aIdx, ProxyAccessible* aChild)
{ mChildren.InsertElementAt(aIdx, aChild); }
uint32_t ChildrenCount() const { return mChildren.Length(); }
ProxyAccessible* ChildAt(uint32_t aIdx) const { return mChildren[aIdx]; }
ProxyAccessible* FirstChild() const
{ return mChildren.Length() ? mChildren[0] : nullptr; }
ProxyAccessible* LastChild() const
{ return mChildren.Length() ? mChildren[mChildren.Length() - 1] : nullptr; }
ProxyAccessible* PrevSibling() const
{
size_t idx = IndexInParent();
return idx > 0 ? Parent()->mChildren[idx - 1] : nullptr;
}
ProxyAccessible* NextSibling() const
{
size_t idx = IndexInParent();
return idx + 1 < Parent()->mChildren.Length() ? Parent()->mChildren[idx + 1]
: nullptr;
}
// XXX evaluate if this is fast enough.
size_t IndexInParent() const { return Parent()->mChildren.IndexOf(this); }
uint32_t EmbeddedChildCount() const;
int32_t IndexOfEmbeddedChild(const ProxyAccessible*);
ProxyAccessible* EmbeddedChildAt(size_t aChildIdx);
bool MustPruneChildren() const;
void Shutdown();
void SetChildDoc(DocAccessibleParent*);
/**
* Remove The given child.
*/
void RemoveChild(ProxyAccessible* aChild)
{ mChildren.RemoveElement(aChild); }
/**
* Return the proxy for the parent of the wrapped accessible.
*/
ProxyAccessible* Parent() const { return mParent; }
Accessible* OuterDocOfRemoteBrowser() const;
/**
* Get the role of the accessible we're proxying.
*/
role Role() const { return mRole; }
/**
* Return true if this is an embedded object.
*/
bool IsEmbeddedObject() const
{
role role = Role();
return role != roles::TEXT_LEAF &&
role != roles::WHITESPACE &&
role != roles::STATICTEXT;
}
/*
@ -396,56 +314,10 @@ public:
*/
void DOMNodeID(nsString& aID);
/**
* Allow the platform to store a pointers worth of data on us.
*/
uintptr_t GetWrapper() const { return mWrapper; }
void SetWrapper(uintptr_t aWrapper) { mWrapper = aWrapper; }
/*
* Return the ID of the accessible being proxied.
*/
uint64_t ID() const { return mID; }
/**
* Return the document containing this proxy, or the proxy itself if it is a
* document.
*/
DocAccessibleParent* Document() const { return mDoc; }
/**
* Return true if this proxy is a DocAccessibleParent.
*/
bool IsDoc() const { return mIsDoc; }
DocAccessibleParent* AsDoc() const { return IsDoc() ? mDoc : nullptr; }
protected:
explicit ProxyAccessible(DocAccessibleParent* aThisAsDoc) :
mParent(nullptr), mDoc(aThisAsDoc), mWrapper(0), mID(0),
mRole(roles::DOCUMENT), mOuterDoc(false), mIsDoc(true), mHasValue(false),
mIsHyperLink(false), mIsHyperText(false)
explicit ProxyAccessible(DocAccessibleParent* aThisAsDoc)
: ProxyAccessibleBase(aThisAsDoc)
{ MOZ_COUNT_CTOR(ProxyAccessible); }
protected:
ProxyAccessible* mParent;
private:
nsTArray<ProxyAccessible*> mChildren;
DocAccessibleParent* mDoc;
uintptr_t mWrapper;
uint64_t mID;
protected:
// XXX DocAccessibleParent gets to change this to change the role of
// documents.
role mRole : 27;
private:
bool mOuterDoc : 1;
public:
const bool mIsDoc: 1;
const bool mHasValue: 1;
const bool mIsHyperLink: 1;
const bool mIsHyperText: 1;
};
}

View File

@ -11,12 +11,12 @@ IPDL_SOURCES += ['PDocAccessible.ipdl']
if CONFIG['ACCESSIBILITY']:
EXPORTS.mozilla.a11y += [
'DocAccessibleChild.h',
'ProxyAccessible.h'
'ProxyAccessible.h',
]
SOURCES += [
'DocAccessibleChild.cpp',
'ProxyAccessible.cpp'
'ProxyAccessible.cpp',
]
LOCAL_INCLUDES += [

View File

@ -0,0 +1,280 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* 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 "Accessible2.h"
#include "ProxyAccessible.h"
#include "mozilla/a11y/DocAccessibleParent.h"
#include "DocAccessible.h"
#include "mozilla/a11y/DocManager.h"
#include "mozilla/dom/Element.h"
#include "mozilla/dom/TabParent.h"
#include "mozilla/unused.h"
#include "mozilla/a11y/Platform.h"
#include "RelationType.h"
#include "mozilla/a11y/Role.h"
#include "xpcAccessibleDocument.h"
#include <comutil.h>
namespace mozilla {
namespace a11y {
bool
ProxyAccessible::GetCOMInterface(void** aOutAccessible) const
{
if (!aOutAccessible) {
return false;
}
RefPtr<IAccessible> addRefed = mCOMProxy;
addRefed.forget(aOutAccessible);
return !!mCOMProxy;
}
void
ProxyAccessible::Name(nsString& aName) const
{
aName.Truncate();
RefPtr<IAccessible> acc;
if (!GetCOMInterface((void**)getter_AddRefs(acc))) {
return;
}
VARIANT id;
id.vt = VT_I4;
id.lVal = CHILDID_SELF;
BSTR result;
HRESULT hr = acc->get_accName(id, &result);
_bstr_t resultWrap(result, false);
if (FAILED(hr)) {
return;
}
aName = (wchar_t*)resultWrap;
}
void
ProxyAccessible::Value(nsString& aValue) const
{
aValue.Truncate();
RefPtr<IAccessible> acc;
if (!GetCOMInterface((void**)getter_AddRefs(acc))) {
return;
}
VARIANT id;
id.vt = VT_I4;
id.lVal = CHILDID_SELF;
BSTR result;
HRESULT hr = acc->get_accValue(id, &result);
_bstr_t resultWrap(result, false);
if (FAILED(hr)) {
return;
}
aValue = (wchar_t*)resultWrap;
}
void
ProxyAccessible::Description(nsString& aDesc) const
{
aDesc.Truncate();
RefPtr<IAccessible> acc;
if (!GetCOMInterface((void**)getter_AddRefs(acc))) {
return;
}
VARIANT id;
id.vt = VT_I4;
id.lVal = CHILDID_SELF;
BSTR result;
HRESULT hr = acc->get_accDescription(id, &result);
_bstr_t resultWrap(result, false);
if (FAILED(hr)) {
return;
}
aDesc = (wchar_t*)resultWrap;
}
uint64_t
ProxyAccessible::State() const
{
uint64_t state = 0;
RefPtr<IAccessible> acc;
if (!GetCOMInterface((void**)getter_AddRefs(acc))) {
return state;
}
VARIANT id;
id.vt = VT_I4;
id.lVal = CHILDID_SELF;
VARIANT varState;
HRESULT hr = acc->get_accState(id, &varState);
if (FAILED(hr)) {
return state;
}
return uint64_t(varState.lVal);
}
nsIntRect
ProxyAccessible::Bounds()
{
nsIntRect rect;
RefPtr<IAccessible> acc;
if (!GetCOMInterface((void**)getter_AddRefs(acc))) {
return rect;
}
long left;
long top;
long width;
long height;
VARIANT id;
id.vt = VT_I4;
id.lVal = CHILDID_SELF;
HRESULT hr = acc->accLocation(&left, &top, &width, &height, id);
if (FAILED(hr)) {
return rect;
}
rect.x = left;
rect.y = top;
rect.width = width;
rect.height = height;
return rect;
}
void
ProxyAccessible::Language(nsString& aLocale)
{
aLocale.Truncate();
RefPtr<IAccessible> acc;
if (!GetCOMInterface((void**)getter_AddRefs(acc))) {
return;
}
RefPtr<IAccessible2> acc2;
if (FAILED(acc->QueryInterface(IID_IAccessible2, (void**)getter_AddRefs(acc2)))) {
return;
}
IA2Locale locale;
HRESULT hr = acc2->get_locale(&locale);
_bstr_t langWrap(locale.language, false);
_bstr_t countryWrap(locale.country, false);
_bstr_t variantWrap(locale.variant, false);
if (FAILED(hr)) {
return;
}
// The remaining code should essentially be the inverse of the
// ia2Accessible::get_locale conversion to IA2Locale.
if (!!variantWrap) {
aLocale = (wchar_t*)variantWrap;
return;
}
if (!!langWrap) {
aLocale = (wchar_t*)langWrap;
if (!!countryWrap) {
aLocale += L"-";
aLocale += (wchar_t*)countryWrap;
}
}
}
static bool
IsEscapedChar(const wchar_t c)
{
return c == L'\\' || c == L':' || c == ',' || c == '=' || c == ';';
}
static bool
ConvertBSTRAttributesToArray(const nsAString& aStr,
nsTArray<Attribute>* aAttrs)
{
if (!aAttrs) {
return false;
}
enum
{
eName = 0,
eValue = 1,
eNumStates
} state;
nsAutoString tokens[eNumStates];
auto itr = aStr.BeginReading(), end = aStr.EndReading();
state = eName;
while (itr != end) {
switch (*itr) {
case L'\\':
// Skip the backslash so that we're looking at the escaped char
++itr;
if (itr == end || !IsEscapedChar(*itr)) {
// Invalid state
return false;
}
break;
case L':':
if (state != eName) {
// Bad, should be looking at name
return false;
}
state = eValue;
++itr;
continue;
case L';':
if (state != eValue) {
// Bad, should be looking at value
return false;
}
state = eName;
aAttrs->AppendElement(Attribute(NS_ConvertUTF16toUTF8(tokens[eName]),
tokens[eValue]));
tokens[eName].Truncate();
tokens[eValue].Truncate();
++itr;
continue;
default:
break;
}
tokens[state] += *itr;
}
return true;
}
void
ProxyAccessible::Attributes(nsTArray<Attribute>* aAttrs) const
{
aAttrs->Clear();
RefPtr<IAccessible> acc;
if (!GetCOMInterface((void**)getter_AddRefs(acc))) {
return;
}
RefPtr<IAccessible2> acc2;
if (FAILED(acc->QueryInterface(IID_IAccessible2, (void**)getter_AddRefs(acc2)))) {
return;
}
BSTR attrs;
HRESULT hr = acc2->get_attributes(&attrs);
_bstr_t attrsWrap(attrs, false);
if (FAILED(hr)) {
return;
}
ConvertBSTRAttributesToArray(nsDependentString((wchar_t*)attrs,
attrsWrap.length()),
aAttrs);
}
} // namespace a11y
} // namespace mozilla

View File

@ -0,0 +1,88 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* 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/. */
#ifndef mozilla_a11y_ProxyAccessible_h
#define mozilla_a11y_ProxyAccessible_h
#include "Accessible.h"
#include "mozilla/a11y/ProxyAccessibleBase.h"
#include "mozilla/a11y/Role.h"
#include "nsIAccessibleText.h"
#include "nsIAccessibleTypes.h"
#include "nsString.h"
#include "nsTArray.h"
#include "nsRect.h"
#include <oleacc.h>
namespace mozilla {
namespace a11y {
class ProxyAccessible : public ProxyAccessibleBase<ProxyAccessible>
{
public:
ProxyAccessible(uint64_t aID, ProxyAccessible* aParent,
DocAccessibleParent* aDoc, role aRole, uint32_t aInterfaces,
const RefPtr<IAccessible>& aIAccessible)
: ProxyAccessibleBase(aID, aParent, aDoc, aRole, aInterfaces)
, mCOMProxy(aIAccessible)
{
MOZ_COUNT_CTOR(ProxyAccessible);
}
~ProxyAccessible()
{
MOZ_COUNT_DTOR(ProxyAccessible);
}
/*
* Return the states for the proxied accessible.
*/
uint64_t State() const;
/*
* Set aName to the name of the proxied accessible.
*/
void Name(nsString& aName) const;
/*
* Set aValue to the value of the proxied accessible.
*/
void Value(nsString& aValue) const;
/**
* Set aDesc to the description of the proxied accessible.
*/
void Description(nsString& aDesc) const;
/**
* Get the set of attributes on the proxied accessible.
*/
void Attributes(nsTArray<Attribute> *aAttrs) const;
nsIntRect Bounds();
void Language(nsString& aLocale);
bool GetCOMInterface(void** aOutAccessible) const;
protected:
explicit ProxyAccessible(DocAccessibleParent* aThisAsDoc)
: ProxyAccessibleBase(aThisAsDoc)
{ MOZ_COUNT_CTOR(ProxyAccessibleBase); }
void SetCOMInterface(const RefPtr<IAccessible>& aIAccessible)
{ mCOMProxy = aIAccessible; }
private:
RefPtr<IAccessible> mCOMProxy;
};
}
}
#endif

View File

@ -12,11 +12,13 @@ if CONFIG['ACCESSIBILITY']:
EXPORTS.mozilla.a11y += [
'COMPtrTypes.h',
'DocAccessibleChild.h',
'ProxyAccessible.h'
]
SOURCES += [
'COMPtrTypes.cpp',
'DocAccessibleChild.cpp',
'ProxyAccessible.cpp',
]
LOCAL_INCLUDES += [

View File

@ -15,7 +15,7 @@ namespace a11y {
class ProxyAccessibleWrap : public AccessibleWrap
{
public:
public:
ProxyAccessibleWrap(ProxyAccessible* aProxy) :
AccessibleWrap(nullptr, nullptr)
{
@ -28,6 +28,11 @@ class ProxyAccessibleWrap : public AccessibleWrap
mBits.proxy = nullptr;
mStateFlags |= eIsDefunct;
}
virtual void GetNativeInterface(void** aOutAccessible) override
{
mBits.proxy->GetCOMInterface(aOutAccessible);
}
};
class HyperTextProxyAccessibleWrap : public HyperTextAccessibleWrap
@ -43,7 +48,12 @@ public:
virtual void Shutdown() override
{
mBits.proxy = nullptr;
mStateFlags |= eIsDefunct;
mStateFlags |= eIsDefunct;
}
virtual void GetNativeInterface(void** aOutAccessible) override
{
mBits.proxy->GetCOMInterface(aOutAccessible);
}
};

View File

@ -96,6 +96,7 @@ private:
friend class DocManager;
friend class DocAccessible;
friend class ProxyAccessible;
friend class ProxyAccessibleBase<ProxyAccessible>;
xpcAccessibleDocument(const xpcAccessibleDocument&) = delete;
xpcAccessibleDocument& operator =(const xpcAccessibleDocument&) = delete;

View File

@ -34,7 +34,7 @@ skip-if = true # "Bug 896046"
[test_log.py]
[test_about_pages.py]
skip-if = buildapp == 'b2g'
skip-if = buildapp == 'b2g' || (e10s && os == 'win')
[test_execute_async_script.py]
[test_execute_script.py]