summaryrefslogtreecommitdiffstats
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
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
-rw-r--r--content/browser/accessibility/browser_accessibility.cc12
-rw-r--r--content/browser/accessibility/browser_accessibility.h3
-rw-r--r--content/browser/accessibility/browser_accessibility_cocoa.mm22
-rw-r--r--content/browser/accessibility/browser_accessibility_win.cc221
-rw-r--r--content/browser/accessibility/browser_accessibility_win.h27
-rw-r--r--webkit/glue/webaccessibility.cc5
-rw-r--r--webkit/glue/webaccessibility.h3
7 files changed, 279 insertions, 14 deletions
diff --git a/content/browser/accessibility/browser_accessibility.cc b/content/browser/accessibility/browser_accessibility.cc
index f9ed6a2..6a6b5f7 100644
--- a/content/browser/accessibility/browser_accessibility.cc
+++ b/content/browser/accessibility/browser_accessibility.cc
@@ -255,3 +255,15 @@ bool BrowserAccessibility::IsEditableText() const {
return (role_ == WebAccessibility::ROLE_TEXT_FIELD ||
role_ == WebAccessibility::ROLE_TEXTAREA);
}
+
+string16 BrowserAccessibility::GetTextRecursive() const {
+ if (!name_.empty()) {
+ return name_;
+ }
+
+ string16 result;
+ for (size_t i = 0; i < children_.size(); ++i)
+ result += children_[i]->GetTextRecursive();
+ return result;
+}
+
diff --git a/content/browser/accessibility/browser_accessibility.h b/content/browser/accessibility/browser_accessibility.h
index 80a0250..9ae0dc9 100644
--- a/content/browser/accessibility/browser_accessibility.h
+++ b/content/browser/accessibility/browser_accessibility.h
@@ -220,6 +220,9 @@ class CONTENT_EXPORT BrowserAccessibility {
// Returns true if this node is an editable text field of any kind.
bool IsEditableText() const;
+ // Append the text from this node and its children.
+ string16 GetTextRecursive() const;
+
protected:
BrowserAccessibility();
diff --git a/content/browser/accessibility/browser_accessibility_cocoa.mm b/content/browser/accessibility/browser_accessibility_cocoa.mm
index 162d0f8..cf3ecc3 100644
--- a/content/browser/accessibility/browser_accessibility_cocoa.mm
+++ b/content/browser/accessibility/browser_accessibility_cocoa.mm
@@ -194,6 +194,7 @@ static const AttributeToMethodNameEntry attributeToMethodNameContainer[] = {
{ NSAccessibilitySubroleAttribute, @"subrole" },
{ NSAccessibilityTabsAttribute, @"tabs" },
{ NSAccessibilityTitleAttribute, @"title" },
+ { NSAccessibilityTitleUIElementAttribute, @"titleUIElement" },
{ NSAccessibilityTopLevelUIElementAttribute, @"window" },
{ NSAccessibilityURLAttribute, @"url" },
{ NSAccessibilityValueAttribute, @"value" },
@@ -570,6 +571,18 @@ NSDictionary* attributeToMethodNameMap = nil;
return base::SysUTF16ToNSString(browserAccessibility_->name());
}
+- (id)titleUIElement {
+ int titleElementId;
+ if (browserAccessibility_->GetIntAttribute(
+ WebAccessibility::ATTR_TITLE_UI_ELEMENT, &titleElementId)) {
+ BrowserAccessibility* titleElement =
+ browserAccessibility_->manager()->GetFromRendererID(titleElementId);
+ if (titleElement)
+ return titleElement->toBrowserAccessibilityCocoa();
+ }
+ return nil;
+}
+
- (NSString*)url {
StringAttribute urlAttribute =
[[self role] isEqualToString:@"AXWebArea"] ?
@@ -862,6 +875,15 @@ NSDictionary* attributeToMethodNameMap = nil;
nil]];
}
+ // Title UI Element.
+ int i;
+ if (browserAccessibility_->GetIntAttribute(
+ WebAccessibility::ATTR_TITLE_UI_ELEMENT, &i)) {
+ [ret addObjectsFromArray:[NSArray arrayWithObjects:
+ NSAccessibilityTitleUIElementAttribute,
+ nil]];
+ }
+
return ret;
}
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() {
diff --git a/content/browser/accessibility/browser_accessibility_win.h b/content/browser/accessibility/browser_accessibility_win.h
index dcd53b1..d20b650 100644
--- a/content/browser/accessibility/browser_accessibility_win.h
+++ b/content/browser/accessibility/browser_accessibility_win.h
@@ -21,6 +21,7 @@
#include "webkit/glue/webaccessibility.h"
class BrowserAccessibilityManagerWin;
+class BrowserAccessibilityRelation;
using webkit_glue::WebAccessibility;
@@ -33,7 +34,8 @@ using webkit_glue::WebAccessibility;
// to be used by screen readers and other assistive technology (AT).
//
////////////////////////////////////////////////////////////////////////////////
-class BrowserAccessibilityWin
+class __declspec(uuid("562072fe-3390-43b1-9e2c-dd4118f5ac79"))
+BrowserAccessibilityWin
: public BrowserAccessibility,
public CComObjectRootEx<CComMultiThreadModel>,
public IDispatchImpl<IAccessible2, &IID_IAccessible2,
@@ -179,20 +181,17 @@ class BrowserAccessibilityWin
// Get this object's index in its parent object.
CONTENT_EXPORT STDMETHODIMP get_indexInParent(LONG* index_in_parent);
- // IAccessible2 methods not implemented.
- CONTENT_EXPORT STDMETHODIMP get_extendedRole(BSTR* extended_role) {
- return E_NOTIMPL;
- }
- CONTENT_EXPORT STDMETHODIMP get_nRelations(LONG* n_relations) {
- return E_NOTIMPL;
- }
+ CONTENT_EXPORT STDMETHODIMP get_nRelations(LONG* n_relations);
+
CONTENT_EXPORT STDMETHODIMP get_relation(LONG relation_index,
- IAccessibleRelation** relation) {
- return E_NOTIMPL;
- }
+ IAccessibleRelation** relation);
+
CONTENT_EXPORT STDMETHODIMP get_relations(LONG max_relations,
IAccessibleRelation** relations,
- LONG* n_relations) {
+ LONG* n_relations);
+
+ // IAccessible2 methods not implemented.
+ CONTENT_EXPORT STDMETHODIMP get_extendedRole(BSTR* extended_role) {
return E_NOTIMPL;
}
CONTENT_EXPORT STDMETHODIMP scrollTo(enum IA2ScrollType scroll_type) {
@@ -713,8 +712,12 @@ class BrowserAccessibilityWin
// is initialized again but the text doesn't change.
string16 old_text_;
+ // Relationships between this node and other nodes.
+ std::vector<BrowserAccessibilityRelation*> relations_;
+
// Give BrowserAccessibility::Create access to our constructor.
friend class BrowserAccessibility;
+ friend class BrowserAccessibilityRelation;
DISALLOW_COPY_AND_ASSIGN(BrowserAccessibilityWin);
};
diff --git a/webkit/glue/webaccessibility.cc b/webkit/glue/webaccessibility.cc
index 8edac6f..92de74f 100644
--- a/webkit/glue/webaccessibility.cc
+++ b/webkit/glue/webaccessibility.cc
@@ -615,6 +615,9 @@ std::string WebAccessibility::DebugString(bool recursive,
case ATTR_TABLE_CELL_ROW_SPAN:
result += " rowspan=" + value;
break;
+ case ATTR_TITLE_UI_ELEMENT:
+ result += " title_elem=" + value;
+ break;
}
}
@@ -787,6 +790,8 @@ void WebAccessibility::Init(const WebKit::WebAccessibilityObject& src,
string_attributes[ATTR_HELP] = src.helpText();
if (src.keyboardShortcut().length())
string_attributes[ATTR_SHORTCUT] = src.keyboardShortcut();
+ if (src.titleUIElement().isValid())
+ int_attributes[ATTR_TITLE_UI_ELEMENT] = src.titleUIElement().axID();
if (!src.url().isEmpty())
string_attributes[ATTR_URL] = src.url().spec().utf16();
diff --git a/webkit/glue/webaccessibility.h b/webkit/glue/webaccessibility.h
index 9bddd5e..4167dce 100644
--- a/webkit/glue/webaccessibility.h
+++ b/webkit/glue/webaccessibility.h
@@ -209,6 +209,9 @@ struct WebAccessibility {
// Tree control attributes.
ATTR_HIERARCHICAL_LEVEL,
+
+ // Relationships between this element and other elements.
+ ATTR_TITLE_UI_ELEMENT,
};
enum FloatAttribute {