summaryrefslogtreecommitdiffstats
path: root/content/browser/accessibility/browser_accessibility_win.cc
diff options
context:
space:
mode:
authordmazzoni@chromium.org <dmazzoni@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-10-21 21:59:51 +0000
committerdmazzoni@chromium.org <dmazzoni@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-10-21 21:59:51 +0000
commitd1029c57273282ad53b0291e43d63c40ee5ec841 (patch)
treea6b2aa433d8c3e8f7faebafde3d85e7ddc1576ee /content/browser/accessibility/browser_accessibility_win.cc
parentaae9eeb10159ca2e345408f74d8425a41bb81ab4 (diff)
downloadchromium_src-d1029c57273282ad53b0291e43d63c40ee5ec841.zip
chromium_src-d1029c57273282ad53b0291e43d63c40ee5ec841.tar.gz
chromium_src-d1029c57273282ad53b0291e43d63c40ee5ec841.tar.bz2
Add support for accessible labels for controls.
This implements TitleUIElement on Mac, and IAccessibleRelation on Windows. BUG=89197 TEST=Manual testing with JAWS, NVDA, and VoiceOver. Review URL: http://codereview.chromium.org/8359012 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@106787 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'content/browser/accessibility/browser_accessibility_win.cc')
-rw-r--r--content/browser/accessibility/browser_accessibility_win.cc221
1 files changed, 219 insertions, 2 deletions
diff --git a/content/browser/accessibility/browser_accessibility_win.cc b/content/browser/accessibility/browser_accessibility_win.cc
index 12960ea..7be2664 100644
--- a/content/browser/accessibility/browser_accessibility_win.cc
+++ b/content/browser/accessibility/browser_accessibility_win.cc
@@ -7,6 +7,7 @@
#include "base/string_number_conversions.h"
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
+#include "base/win/scoped_comptr.h"
#include "content/browser/accessibility/browser_accessibility_manager_win.h"
#include "content/common/view_messages.h"
#include "net/base/escape.h"
@@ -22,6 +23,133 @@ const GUID GUID_ISimpleDOM = {
0x0c539790, 0x12e4, 0x11cf,
0xb6, 0x61, 0x00, 0xaa, 0x00, 0x4c, 0xd6, 0xd8};
+//
+// BrowserAccessibilityRelation
+//
+// A simple implementation of IAccessibleRelation, used to represent
+// a relationship between two accessible nodes in the tree.
+//
+
+class BrowserAccessibilityRelation
+ : public CComObjectRootEx<CComMultiThreadModel>,
+ public IAccessibleRelation {
+ BEGIN_COM_MAP(BrowserAccessibilityRelation)
+ COM_INTERFACE_ENTRY(IAccessibleRelation)
+ END_COM_MAP()
+
+ CONTENT_EXPORT BrowserAccessibilityRelation() {}
+ CONTENT_EXPORT virtual ~BrowserAccessibilityRelation() {}
+
+ CONTENT_EXPORT void Initialize(BrowserAccessibilityWin* owner,
+ const string16& type);
+ CONTENT_EXPORT void AddTarget(int target_id);
+
+ // IAccessibleRelation methods.
+ CONTENT_EXPORT STDMETHODIMP get_relationType(BSTR* relation_type);
+ CONTENT_EXPORT STDMETHODIMP get_nTargets(long* n_targets);
+ CONTENT_EXPORT STDMETHODIMP get_target(long target_index, IUnknown** target);
+ CONTENT_EXPORT STDMETHODIMP get_targets(long max_targets,
+ IUnknown** targets,
+ long* n_targets);
+
+ // IAccessibleRelation methods not implemented.
+ CONTENT_EXPORT STDMETHODIMP get_localizedRelationType(BSTR* relation_type) {
+ return E_NOTIMPL;
+ }
+
+ private:
+ string16 type_;
+ base::win::ScopedComPtr<BrowserAccessibilityWin> owner_;
+ std::vector<int> target_ids_;
+};
+
+void BrowserAccessibilityRelation::Initialize(BrowserAccessibilityWin* owner,
+ const string16& type) {
+ owner_ = owner;
+ type_ = type;
+}
+
+void BrowserAccessibilityRelation::AddTarget(int target_id) {
+ target_ids_.push_back(target_id);
+}
+
+STDMETHODIMP BrowserAccessibilityRelation::get_relationType(
+ BSTR* relation_type) {
+ if (!relation_type)
+ return E_INVALIDARG;
+
+ if (!owner_->instance_active())
+ return E_FAIL;
+
+ *relation_type = SysAllocString(type_.c_str());
+ DCHECK(*relation_type);
+ return S_OK;
+}
+
+STDMETHODIMP BrowserAccessibilityRelation::get_nTargets(long* n_targets) {
+ if (!n_targets)
+ return E_INVALIDARG;
+
+ if (!owner_->instance_active())
+ return E_FAIL;
+
+ *n_targets = static_cast<long>(target_ids_.size());
+ return S_OK;
+}
+
+STDMETHODIMP BrowserAccessibilityRelation::get_target(
+ long target_index, IUnknown** target) {
+ if (!target)
+ return E_INVALIDARG;
+
+ if (!owner_->instance_active())
+ return E_FAIL;
+
+ if (target_index < 0 ||
+ target_index >= static_cast<long>(target_ids_.size())) {
+ return E_INVALIDARG;
+ }
+
+ BrowserAccessibilityManager* manager = owner_->manager();
+ BrowserAccessibility* result =
+ manager->GetFromRendererID(target_ids_[target_index]);
+ if (!result->instance_active())
+ return E_FAIL;
+
+ *target = static_cast<IAccessible*>(
+ result->toBrowserAccessibilityWin()->NewReference());
+ return S_OK;
+}
+
+STDMETHODIMP BrowserAccessibilityRelation::get_targets(
+ long max_targets, IUnknown** targets, long* n_targets) {
+ if (!targets || !n_targets)
+ return E_INVALIDARG;
+
+ if (!owner_->instance_active())
+ return E_FAIL;
+
+ long count = static_cast<long>(target_ids_.size());
+ if (count > max_targets)
+ count = max_targets;
+
+ *n_targets = count;
+ if (count == 0)
+ return S_FALSE;
+
+ for (long i = 0; i < count; ++i) {
+ HRESULT result = get_target(i, &targets[i]);
+ if (result != S_OK)
+ return result;
+ }
+
+ return S_OK;
+}
+
+//
+// BrowserAccessibilityWin
+//
+
// static
BrowserAccessibility* BrowserAccessibility::Create() {
CComObject<BrowserAccessibilityWin>* instance;
@@ -43,6 +171,8 @@ BrowserAccessibilityWin::BrowserAccessibilityWin()
}
BrowserAccessibilityWin::~BrowserAccessibilityWin() {
+ for (size_t i = 0; i < relations_.size(); ++i)
+ relations_[i]->Release();
}
//
@@ -286,10 +416,24 @@ STDMETHODIMP BrowserAccessibilityWin::get_accName(VARIANT var_id, BSTR* name) {
if (!target)
return E_INVALIDARG;
- if (target->name_.empty())
+ string16 name_str = target->name_;
+
+ // If the name is empty, see if it's labeled by another element.
+ if (name_str.empty()) {
+ int title_elem_id;
+ if (target->GetIntAttribute(WebAccessibility::ATTR_TITLE_UI_ELEMENT,
+ &title_elem_id)) {
+ BrowserAccessibility* title_elem =
+ manager_->GetFromRendererID(title_elem_id);
+ if (title_elem)
+ name_str = title_elem->GetTextRecursive();
+ }
+ }
+
+ if (name_str.empty())
return S_FALSE;
- *name = SysAllocString(target->name_.c_str());
+ *name = SysAllocString(name_str.c_str());
DCHECK(*name);
return S_OK;
@@ -485,6 +629,59 @@ STDMETHODIMP BrowserAccessibilityWin::get_indexInParent(LONG* index_in_parent) {
return S_OK;
}
+STDMETHODIMP BrowserAccessibilityWin::get_nRelations(LONG* n_relations) {
+ if (!instance_active_)
+ return E_FAIL;
+
+ if (!n_relations)
+ return E_INVALIDARG;
+
+ *n_relations = relations_.size();
+ return S_OK;
+}
+
+STDMETHODIMP BrowserAccessibilityWin::get_relation(
+ LONG relation_index,
+ IAccessibleRelation** relation) {
+ if (!instance_active_)
+ return E_FAIL;
+
+ if (relation_index < 0 ||
+ relation_index >= static_cast<long>(relations_.size())) {
+ return E_INVALIDARG;
+ }
+
+ if (!relation)
+ return E_INVALIDARG;
+
+ relations_[relation_index]->AddRef();
+ *relation = relations_[relation_index];
+ return S_OK;
+}
+
+STDMETHODIMP BrowserAccessibilityWin::get_relations(
+ LONG max_relations,
+ IAccessibleRelation** relations,
+ LONG* n_relations) {
+ if (!instance_active_)
+ return E_FAIL;
+
+ if (!relations || !n_relations)
+ return E_INVALIDARG;
+
+ long count = static_cast<long>(relations_.size());
+ *n_relations = count;
+ if (count == 0)
+ return S_FALSE;
+
+ for (long i = 0; i < count; ++i) {
+ relations_[i]->AddRef();
+ relations[i] = relations_[i];
+ }
+
+ return S_OK;
+}
+
//
// IAccessibleImage methods.
//
@@ -2200,6 +2397,26 @@ void BrowserAccessibilityWin::Initialize() {
string16 url;
if (value_.empty() && (ia_state_ & STATE_SYSTEM_LINKED))
GetStringAttribute(WebAccessibility::ATTR_URL, &value_);
+
+ // Clear any old relationships between this node and other nodes.
+ for (size_t i = 0; i < relations_.size(); ++i)
+ relations_[i]->Release();
+ relations_.clear();
+
+ // Handle title UI element.
+ int title_elem_id;
+ if (GetIntAttribute(WebAccessibility::ATTR_TITLE_UI_ELEMENT,
+ &title_elem_id)) {
+ // Add a labelled by relationship.
+ CComObject<BrowserAccessibilityRelation>* relation;
+ HRESULT hr = CComObject<BrowserAccessibilityRelation>::CreateInstance(
+ &relation);
+ DCHECK(SUCCEEDED(hr));
+ relation->AddRef();
+ relation->Initialize(this, IA2_RELATION_LABELLED_BY);
+ relation->AddTarget(title_elem_id);
+ relations_.push_back(relation);
+ }
}
void BrowserAccessibilityWin::SendNodeUpdateEvents() {