summaryrefslogtreecommitdiffstats
path: root/content
diff options
context:
space:
mode:
authordmazzoni@chromium.org <dmazzoni@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-06-23 21:07:33 +0000
committerdmazzoni@chromium.org <dmazzoni@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-06-23 21:07:33 +0000
commitfc1926184af3507865502a92b5102e12680b7c21 (patch)
tree129b46aec9b7028f900a7e8e4d3634708a597259 /content
parent6131fb5ed032194875383f386b682cdc38338809 (diff)
downloadchromium_src-fc1926184af3507865502a92b5102e12680b7c21.zip
chromium_src-fc1926184af3507865502a92b5102e12680b7c21.tar.gz
chromium_src-fc1926184af3507865502a92b5102e12680b7c21.tar.bz2
Move browser accessibility code from chrome to content.
BUG=85932 TEST=none Review URL: http://codereview.chromium.org/7233022 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@90265 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'content')
-rw-r--r--content/browser/accessibility/OWNERS3
-rw-r--r--content/browser/accessibility/browser_accessibility.cc204
-rw-r--r--content/browser/accessibility/browser_accessibility.h227
-rw-r--r--content/browser/accessibility/browser_accessibility_cocoa.h76
-rw-r--r--content/browser/accessibility/browser_accessibility_cocoa.mm822
-rw-r--r--content/browser/accessibility/browser_accessibility_delegate_mac.h24
-rw-r--r--content/browser/accessibility/browser_accessibility_mac.h46
-rw-r--r--content/browser/accessibility/browser_accessibility_mac.mm59
-rw-r--r--content/browser/accessibility/browser_accessibility_manager.cc373
-rw-r--r--content/browser/accessibility/browser_accessibility_manager.h177
-rw-r--r--content/browser/accessibility/browser_accessibility_manager_mac.h31
-rw-r--r--content/browser/accessibility/browser_accessibility_manager_mac.mm63
-rw-r--r--content/browser/accessibility/browser_accessibility_manager_win.cc90
-rw-r--r--content/browser/accessibility/browser_accessibility_manager_win.h48
-rw-r--r--content/browser/accessibility/browser_accessibility_state.cc27
-rw-r--r--content/browser/accessibility/browser_accessibility_state.h53
-rw-r--r--content/browser/accessibility/browser_accessibility_win.cc1634
-rw-r--r--content/browser/accessibility/browser_accessibility_win.h499
-rw-r--r--content/browser/renderer_host/render_widget_host.cc4
-rw-r--r--content/content_browser.gypi24
20 files changed, 4483 insertions, 1 deletions
diff --git a/content/browser/accessibility/OWNERS b/content/browser/accessibility/OWNERS
new file mode 100644
index 0000000..ab8afa4
--- /dev/null
+++ b/content/browser/accessibility/OWNERS
@@ -0,0 +1,3 @@
+ctguil@chromium.org
+dmazzoni@chromium.org
+dtseng@chromium.org
diff --git a/content/browser/accessibility/browser_accessibility.cc b/content/browser/accessibility/browser_accessibility.cc
new file mode 100644
index 0000000..784bae0
--- /dev/null
+++ b/content/browser/accessibility/browser_accessibility.cc
@@ -0,0 +1,204 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/accessibility/browser_accessibility.h"
+
+#include "base/logging.h"
+#include "base/string_number_conversions.h"
+#include "content/browser/accessibility/browser_accessibility_manager.h"
+
+#if defined(OS_POSIX) && !defined(OS_MACOSX)
+// There's no OS-specific implementation of BrowserAccessibilityManager
+// on Unix, so just instantiate the base class.
+// static
+BrowserAccessibility* BrowserAccessibility::Create() {
+ return new BrowserAccessibility();
+}
+#endif
+
+BrowserAccessibility::BrowserAccessibility()
+ : manager_(NULL),
+ parent_(NULL),
+ child_id_(0),
+ index_in_parent_(0),
+ renderer_id_(0),
+ ref_count_(1),
+ role_(0),
+ state_(0),
+ instance_active_(false) {
+}
+
+BrowserAccessibility::~BrowserAccessibility() {
+}
+
+void BrowserAccessibility::DetachTree(
+ std::vector<BrowserAccessibility*>* nodes) {
+ nodes->push_back(this);
+ for (size_t i = 0; i < children_.size(); i++)
+ children_[i]->DetachTree(nodes);
+ children_.clear();
+ parent_ = NULL;
+}
+
+void BrowserAccessibility::Initialize(
+ BrowserAccessibilityManager* manager,
+ BrowserAccessibility* parent,
+ int32 child_id,
+ int32 index_in_parent,
+ const webkit_glue::WebAccessibility& src) {
+ manager_ = manager;
+ parent_ = parent;
+ child_id_ = child_id;
+ index_in_parent_ = index_in_parent;
+
+ renderer_id_ = src.id;
+ name_ = src.name;
+ value_ = src.value;
+ attributes_ = src.attributes;
+ html_attributes_ = src.html_attributes;
+ location_ = src.location;
+ role_ = src.role;
+ state_ = src.state;
+ indirect_child_ids_ = src.indirect_child_ids;
+ line_breaks_ = src.line_breaks;
+
+ Initialize();
+}
+
+void BrowserAccessibility::Initialize() {
+ instance_active_ = true;
+}
+
+void BrowserAccessibility::AddChild(BrowserAccessibility* child) {
+ children_.push_back(child);
+}
+
+void BrowserAccessibility::UpdateParent(BrowserAccessibility* parent,
+ int index_in_parent) {
+ parent_ = parent;
+ index_in_parent_ = index_in_parent;
+}
+
+bool BrowserAccessibility::IsDescendantOf(
+ BrowserAccessibility* ancestor) {
+ if (this == ancestor) {
+ return true;
+ } else if (parent_) {
+ return parent_->IsDescendantOf(ancestor);
+ }
+
+ return false;
+}
+
+BrowserAccessibility* BrowserAccessibility::GetChild(uint32 child_index) {
+ DCHECK(child_index < children_.size());
+ return children_[child_index];
+}
+
+BrowserAccessibility* BrowserAccessibility::GetPreviousSibling() {
+ if (parent_ && index_in_parent_ > 0)
+ return parent_->children_[index_in_parent_ - 1];
+
+ return NULL;
+}
+
+BrowserAccessibility* BrowserAccessibility::GetNextSibling() {
+ if (parent_ &&
+ index_in_parent_ >= 0 &&
+ index_in_parent_ < static_cast<int>(parent_->children_.size() - 1)) {
+ return parent_->children_[index_in_parent_ + 1];
+ }
+
+ return NULL;
+}
+
+gfx::Rect BrowserAccessibility::GetBoundsRect() {
+ gfx::Rect bounds = location_;
+
+ // Adjust the bounds by the top left corner of the containing view's bounds
+ // in screen coordinates.
+ gfx::Point top_left = manager_->GetViewBounds().origin();
+ bounds.Offset(top_left);
+
+ // Adjust top left position by the root document's scroll offset.
+ BrowserAccessibility* root = manager_->GetRoot();
+ int scroll_x = 0;
+ int scroll_y = 0;
+ root->GetAttributeAsInt(
+ WebAccessibility::ATTR_DOC_SCROLLX, &scroll_x);
+ root->GetAttributeAsInt(
+ WebAccessibility::ATTR_DOC_SCROLLY, &scroll_y);
+ bounds.Offset(-scroll_x, -scroll_y);
+
+ return bounds;
+}
+
+BrowserAccessibility* BrowserAccessibility::BrowserAccessibilityForPoint(
+ const gfx::Point& point) {
+ // Walk the children recursively looking for the BrowserAccessibility that
+ // most tightly encloses the specified point.
+ for (int i = children_.size() - 1; i >= 0; --i) {
+ BrowserAccessibility* child = children_[i];
+ if (child->GetBoundsRect().Contains(point))
+ return child->BrowserAccessibilityForPoint(point);
+ }
+ return this;
+}
+
+void BrowserAccessibility::InternalAddReference() {
+ ref_count_++;
+}
+
+void BrowserAccessibility::InternalReleaseReference(bool recursive) {
+ DCHECK_GT(ref_count_, 0);
+
+ if (recursive || ref_count_ == 1) {
+ for (std::vector<BrowserAccessibility*>::iterator iter = children_.begin();
+ iter != children_.end();
+ ++iter) {
+ (*iter)->InternalReleaseReference(true);
+ }
+ }
+
+ ref_count_--;
+ if (ref_count_ == 0) {
+ instance_active_ = false;
+ children_.clear();
+ manager_->Remove(child_id_, renderer_id_);
+ NativeReleaseReference();
+ }
+}
+
+void BrowserAccessibility::NativeReleaseReference() {
+ delete this;
+}
+
+bool BrowserAccessibility::HasAttribute(
+ WebAccessibility::Attribute attribute) {
+ return (attributes_.find(attribute) != attributes_.end());
+}
+
+bool BrowserAccessibility::GetAttribute(
+ WebAccessibility::Attribute attribute, string16* value) {
+ std::map<int32, string16>::iterator iter = attributes_.find(attribute);
+ if (iter != attributes_.end()) {
+ *value = iter->second;
+ return true;
+ }
+
+ return false;
+}
+
+bool BrowserAccessibility::GetAttributeAsInt(
+ WebAccessibility::Attribute attribute, int* value_int) {
+ string16 value_str;
+
+ if (!GetAttribute(attribute, &value_str))
+ return false;
+
+ if (!base::StringToInt(value_str, value_int))
+ return false;
+
+ return true;
+}
diff --git a/content/browser/accessibility/browser_accessibility.h b/content/browser/accessibility/browser_accessibility.h
new file mode 100644
index 0000000..dbd3e13
--- /dev/null
+++ b/content/browser/accessibility/browser_accessibility.h
@@ -0,0 +1,227 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_ACCESSIBILITY_BROWSER_ACCESSIBILITY_H_
+#define CONTENT_BROWSER_ACCESSIBILITY_BROWSER_ACCESSIBILITY_H_
+#pragma once
+
+#include <map>
+#include <utility>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "build/build_config.h"
+#include "webkit/glue/webaccessibility.h"
+
+class BrowserAccessibilityManager;
+#if defined(OS_MACOSX) && __OBJC__
+@class BrowserAccessibilityCocoa;
+#elif defined(OS_WIN)
+class BrowserAccessibilityWin;
+#endif
+
+using webkit_glue::WebAccessibility;
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// BrowserAccessibility
+//
+// Class implementing the cross platform interface for the Browser-Renderer
+// communication of accessibility information, providing accessibility
+// to be used by screen readers and other assistive technology (AT).
+//
+// An implementation for each platform handles platform specific accessibility
+// APIs.
+//
+////////////////////////////////////////////////////////////////////////////////
+class BrowserAccessibility {
+ public:
+ // Creates a platform specific BrowserAccessibility. Ownership passes to the
+ // caller.
+ static BrowserAccessibility* Create();
+
+ virtual ~BrowserAccessibility();
+
+ // Detach all descendants of this subtree and push all of the node pointers,
+ // including this node, onto the end of |nodes|.
+ virtual void DetachTree(std::vector<BrowserAccessibility*>* nodes);
+
+ // Perform platform specific initialization. This can be called multiple times
+ // during the lifetime of this instance after the members of this base object
+ // have been reset with new values from the renderer process.
+ virtual void Initialize();
+
+ // Initialize this object, reading attributes from |src|. Does not
+ // recurse into children of |src| and build the whole subtree.
+ void Initialize(BrowserAccessibilityManager* manager,
+ BrowserAccessibility* parent,
+ int32 child_id,
+ int32 index_in_parent,
+ const WebAccessibility& src);
+
+ // Add a child of this object.
+ void AddChild(BrowserAccessibility* child);
+
+ // Update the parent and index in parent if this node has been moved.
+ void UpdateParent(BrowserAccessibility* parent, int index_in_parent);
+
+ // Return true if this object is equal to or a descendant of |ancestor|.
+ bool IsDescendantOf(BrowserAccessibility* ancestor);
+
+ // Returns the parent of this object, or NULL if it's the root.
+ BrowserAccessibility* parent() { return parent_; }
+
+ // Returns the number of children of this object.
+ uint32 child_count() const { return children_.size(); }
+
+ // Return a pointer to the child with the given index.
+ BrowserAccessibility* GetChild(uint32 child_index);
+
+ // Return the previous sibling of this object, or NULL if it's the first
+ // child of its parent.
+ BrowserAccessibility* GetPreviousSibling();
+
+ // Return the next sibling of this object, or NULL if it's the last child
+ // of its parent.
+ BrowserAccessibility* GetNextSibling();
+
+ // Returns the bounds of this object in screen coordinates.
+ gfx::Rect GetBoundsRect();
+
+ // Returns the deepest descendant that contains the specified point.
+ BrowserAccessibility* BrowserAccessibilityForPoint(const gfx::Point& point);
+
+ //
+ // Reference counting
+ //
+ // Each object has an internal reference count and many platform
+ // implementations may also use native reference counting.
+ //
+ // The internal reference counting is used because sometimes
+ // multiple references to the same object exist temporarily during
+ // an update. When the internal reference count reaches zero,
+ // NativeReleaseReference is called.
+ //
+ // Native reference counting is used on some platforms because the
+ // operating system may hold onto a reference to a BrowserAccessibility
+ // object even after we're through with it. On these platforms, when
+ // the internal reference count reaches zero, instance_active is set
+ // to zero, and all queries on this object should return failure.
+ // The object isn't actually deleted until the operating system releases
+ // all of its references.
+ //
+
+ // Increment this node's internal reference count.
+ virtual void InternalAddReference();
+
+ // Decrement this node's internal reference count. If the reference count
+ // reaches zero, call NativeReleaseReference().
+ virtual void InternalReleaseReference(bool recursive);
+
+ // Subclasses should override this to support platform reference counting.
+ virtual void NativeAddReference() { }
+
+ // Subclasses should override this to support platform reference counting.
+ virtual void NativeReleaseReference();
+
+ //
+ // Accessors
+ //
+
+ const std::map<int32, string16>& attributes() const { return attributes_; }
+ int32 child_id() const { return child_id_; }
+ const std::vector<BrowserAccessibility*>& children() const {
+ return children_;
+ }
+ const std::vector<std::pair<string16, string16> >& html_attributes() const {
+ return html_attributes_;
+ }
+ int32 index_in_parent() const { return index_in_parent_; }
+ const std::vector<int32>& indirect_child_ids() const {
+ return indirect_child_ids_;
+ }
+ const std::vector<int32>& line_breaks() const {
+ return line_breaks_;
+ }
+ gfx::Rect location() const { return location_; }
+ BrowserAccessibilityManager* manager() const { return manager_; }
+ const string16& name() const { return name_; }
+ int32 renderer_id() const { return renderer_id_; }
+ int32 role() const { return role_; }
+ const string16& role_name() const { return role_name_; }
+ int32 state() const { return state_; }
+ const string16& value() const { return value_; }
+ bool instance_active() const { return instance_active_; }
+ int32 ref_count() const { return ref_count_; }
+
+#if defined(OS_MACOSX) && __OBJC__
+ BrowserAccessibilityCocoa* toBrowserAccessibilityCocoa();
+#elif defined(OS_WIN)
+ BrowserAccessibilityWin* toBrowserAccessibilityWin();
+#endif
+
+ // BrowserAccessibilityCocoa needs access to these methods.
+ // Return true if this attribute is in the attributes map.
+ bool HasAttribute(WebAccessibility::Attribute attribute);
+
+ // Retrieve the string value of an attribute from the attribute map and
+ // returns true if found.
+ bool GetAttribute(WebAccessibility::Attribute attribute, string16* value);
+
+ // Retrieve the value of an attribute from the attribute map and
+ // if found and nonempty, try to convert it to an integer.
+ // Returns true only if both the attribute was found and it was successfully
+ // converted to an integer.
+ bool GetAttributeAsInt(
+ WebAccessibility::Attribute attribute, int* value_int);
+
+ protected:
+ BrowserAccessibility();
+
+ // The manager of this tree of accessibility objects; needed for
+ // global operations like focus tracking.
+ BrowserAccessibilityManager* manager_;
+
+ // The parent of this object, may be NULL if we're the root object.
+ BrowserAccessibility* parent_;
+
+ // The ID of this object; globally unique within the browser process.
+ int32 child_id_;
+
+ // The index of this within its parent object.
+ int32 index_in_parent_;
+
+ // The ID of this object in the renderer process.
+ int32 renderer_id_;
+
+ // The children of this object.
+ std::vector<BrowserAccessibility*> children_;
+
+ // The number of internal references to this object.
+ int32 ref_count_;
+
+ // Accessibility metadata from the renderer
+ string16 name_;
+ string16 value_;
+ std::map<int32, string16> attributes_;
+ std::vector<std::pair<string16, string16> > html_attributes_;
+ int32 role_;
+ int32 state_;
+ string16 role_name_;
+ gfx::Rect location_;
+ std::vector<int32> indirect_child_ids_;
+ std::vector<int32> line_breaks_;
+
+ // BrowserAccessibility objects are reference-counted on some platforms.
+ // When we're done with this object and it's removed from our accessibility
+ // tree, a client may still be holding onto a pointer to this object, so
+ // we mark it as inactive so that calls to any of this object's methods
+ // immediately return failure.
+ bool instance_active_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(BrowserAccessibility);
+};
+
+#endif // CONTENT_BROWSER_ACCESSIBILITY_BROWSER_ACCESSIBILITY_H_
diff --git a/content/browser/accessibility/browser_accessibility_cocoa.h b/content/browser/accessibility/browser_accessibility_cocoa.h
new file mode 100644
index 0000000..ab4044f
--- /dev/null
+++ b/content/browser/accessibility/browser_accessibility_cocoa.h
@@ -0,0 +1,76 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_ACCESSIBILITY_BROWSER_ACCESSIBILITY_COCOA_H_
+#define CONTENT_BROWSER_ACCESSIBILITY_BROWSER_ACCESSIBILITY_COCOA_H_
+#pragma once
+
+#import <Cocoa/Cocoa.h>
+
+#import "base/memory/scoped_nsobject.h"
+#import "content/browser/accessibility/browser_accessibility_delegate_mac.h"
+#include "content/browser/accessibility/browser_accessibility.h"
+
+// BrowserAccessibilityCocoa is a cocoa wrapper around the BrowserAccessibility
+// object. The renderer converts webkit's accessibility tree into a
+// WebAccessibility tree and passes it to the browser process over IPC.
+// This class converts it into a format Cocoa can query.
+// Inheriting from NSView rather than NSObject as clients cannot add
+// observers to pure NSObject derived classes.
+@interface BrowserAccessibilityCocoa : NSView {
+ @private
+ BrowserAccessibility* browserAccessibility_;
+ scoped_nsobject<NSMutableArray> children_;
+ id<BrowserAccessibilityDelegateCocoa> delegate_;
+}
+
+// This creates a cocoa browser accessibility object around
+// the cross platform BrowserAccessibility object. The delegate is
+// used to communicate with the host renderer. None of these
+// parameters can be null.
+- (id)initWithObject:(BrowserAccessibility*)accessibility
+ delegate:(id<BrowserAccessibilityDelegateCocoa>)delegate;
+
+// Invalidate children for a non-ignored ancestor (including self).
+- (void)childrenChanged;
+
+// Children is an array of BrowserAccessibility objects, representing
+// the accessibility children of this object.
+@property(nonatomic, readonly) NSArray* children;
+@property(nonatomic, readonly) NSArray* columns;
+@property(nonatomic, readonly) NSString* description;
+@property(nonatomic, readonly) NSNumber* enabled;
+@property(nonatomic, readonly) NSNumber* focused;
+@property(nonatomic, readonly) NSString* help;
+// isIgnored returns whether or not the accessibility object
+// should be ignored by the accessibility hierarchy.
+@property(nonatomic, readonly, getter=isIgnored) BOOL ignored;
+// The origin of this object in the page's document.
+// This is relative to webkit's top-left origin, not Cocoa's
+// bottom-left origin.
+@property(nonatomic, readonly) NSPoint origin;
+@property(nonatomic, readonly) NSNumber* numberOfCharacters;
+@property(nonatomic, readonly) id parent;
+@property(nonatomic, readonly) NSValue* position;
+// A string indicating the role of this object as far as accessibility
+// is concerned.
+@property(nonatomic, readonly) NSString* role;
+@property(nonatomic, readonly) NSString* roleDescription;
+@property(nonatomic, readonly) NSArray* rows;
+// The size of this object.
+@property(nonatomic, readonly) NSValue* size;
+// A string indicating the subrole of this object as far as accessibility
+// is concerned.
+@property(nonatomic, readonly) NSString* subrole;
+// The tabs owned by a tablist.
+@property(nonatomic, readonly) NSArray* tabs;
+@property(nonatomic, readonly) NSString* title;
+@property(nonatomic, readonly) NSString* url;
+@property(nonatomic, readonly) NSString* value;
+@property(nonatomic, readonly) NSValue* visibleCharacterRange;
+@property(nonatomic, readonly) NSNumber* visited;
+@property(nonatomic, readonly) id window;
+@end
+
+#endif // CONTENT_BROWSER_ACCESSIBILITY_BROWSER_ACCESSIBILITY_COCOA_H_
diff --git a/content/browser/accessibility/browser_accessibility_cocoa.mm b/content/browser/accessibility/browser_accessibility_cocoa.mm
new file mode 100644
index 0000000..1920493
--- /dev/null
+++ b/content/browser/accessibility/browser_accessibility_cocoa.mm
@@ -0,0 +1,822 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <execinfo.h>
+
+#import "content/browser/accessibility/browser_accessibility_cocoa.h"
+
+#include <map>
+
+#include "base/string16.h"
+#include "base/sys_string_conversions.h"
+#include "base/utf_string_conversions.h"
+#include "content/browser/accessibility/browser_accessibility_manager.h"
+#include "grit/webkit_strings.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebRect.h"
+#include "ui/base/l10n/l10n_util_mac.h"
+
+namespace {
+
+// Returns an autoreleased copy of the WebAccessibility's attribute.
+NSString* NSStringForWebAccessibilityAttribute(
+ const std::map<int32, string16>& attributes,
+ WebAccessibility::Attribute attribute) {
+ std::map<int32, string16>::const_iterator iter =
+ attributes.find(attribute);
+ NSString* returnValue = @"";
+ if (iter != attributes.end()) {
+ returnValue = base::SysUTF16ToNSString(iter->second);
+ }
+ return returnValue;
+}
+
+struct MapEntry {
+ WebAccessibility::Role webKitValue;
+ NSString* nativeValue;
+};
+
+struct AttributeToMethodNameEntry {
+ NSString* attribute;
+ NSString* methodName;
+};
+
+static const MapEntry roles[] = {
+ { WebAccessibility::ROLE_NONE, NSAccessibilityUnknownRole },
+ { WebAccessibility::ROLE_ALERT, NSAccessibilityGroupRole },
+ { WebAccessibility::ROLE_ALERT_DIALOG, NSAccessibilityGroupRole },
+ { WebAccessibility::ROLE_ANNOTATION, NSAccessibilityUnknownRole },
+ { WebAccessibility::ROLE_APPLICATION, NSAccessibilityGroupRole },
+ { WebAccessibility::ROLE_ARTICLE, NSAccessibilityGroupRole },
+ { WebAccessibility::ROLE_BROWSER, NSAccessibilityBrowserRole },
+ { WebAccessibility::ROLE_BUSY_INDICATOR, NSAccessibilityBusyIndicatorRole },
+ { WebAccessibility::ROLE_BUTTON, NSAccessibilityButtonRole },
+ { WebAccessibility::ROLE_CELL, @"AXCell" },
+ { WebAccessibility::ROLE_CHECKBOX, NSAccessibilityCheckBoxRole },
+ { WebAccessibility::ROLE_COLOR_WELL, NSAccessibilityColorWellRole },
+ { WebAccessibility::ROLE_COLUMN, NSAccessibilityColumnRole },
+ { WebAccessibility::ROLE_COLUMN_HEADER, @"AXCell" },
+ { WebAccessibility::ROLE_DEFINITION_LIST_DEFINITION,
+ NSAccessibilityGroupRole },
+ { WebAccessibility::ROLE_DEFINITION_LIST_TERM, NSAccessibilityGroupRole },
+ { WebAccessibility::ROLE_DIALOG, NSAccessibilityGroupRole },
+ { WebAccessibility::ROLE_DIRECTORY, NSAccessibilityListRole },
+ { WebAccessibility::ROLE_DISCLOSURE_TRIANGLE,
+ NSAccessibilityDisclosureTriangleRole },
+ { WebAccessibility::ROLE_DOCUMENT, NSAccessibilityGroupRole },
+ { WebAccessibility::ROLE_DRAWER, NSAccessibilityDrawerRole },
+ { WebAccessibility::ROLE_EDITABLE_TEXT, NSAccessibilityTextFieldRole },
+ { WebAccessibility::ROLE_GRID, NSAccessibilityGridRole },
+ { WebAccessibility::ROLE_GROUP, NSAccessibilityGroupRole },
+ { WebAccessibility::ROLE_GROW_AREA, NSAccessibilityGrowAreaRole },
+ { WebAccessibility::ROLE_HEADING, @"AXHeading" },
+ { WebAccessibility::ROLE_HELP_TAG, NSAccessibilityHelpTagRole },
+ { WebAccessibility::ROLE_IGNORED, NSAccessibilityUnknownRole },
+ { WebAccessibility::ROLE_IMAGE, NSAccessibilityImageRole },
+ { WebAccessibility::ROLE_IMAGE_MAP, NSAccessibilityGroupRole },
+ { WebAccessibility::ROLE_IMAGE_MAP_LINK, NSAccessibilityLinkRole },
+ { WebAccessibility::ROLE_INCREMENTOR, NSAccessibilityIncrementorRole },
+ { WebAccessibility::ROLE_LANDMARK_APPLICATION, NSAccessibilityGroupRole },
+ { WebAccessibility::ROLE_LANDMARK_BANNER, NSAccessibilityGroupRole },
+ { WebAccessibility::ROLE_LANDMARK_COMPLEMENTARY, NSAccessibilityGroupRole },
+ { WebAccessibility::ROLE_LANDMARK_CONTENTINFO, NSAccessibilityGroupRole },
+ { WebAccessibility::ROLE_LANDMARK_MAIN, NSAccessibilityGroupRole },
+ { WebAccessibility::ROLE_LANDMARK_NAVIGATION, NSAccessibilityGroupRole },
+ { WebAccessibility::ROLE_LANDMARK_SEARCH, NSAccessibilityGroupRole },
+ { WebAccessibility::ROLE_LINK, NSAccessibilityLinkRole },
+ { WebAccessibility::ROLE_LIST, NSAccessibilityListRole },
+ { WebAccessibility::ROLE_LIST_ITEM, NSAccessibilityGroupRole },
+ { WebAccessibility::ROLE_LIST_MARKER, NSAccessibilityGroupRole },
+ { WebAccessibility::ROLE_LISTBOX, NSAccessibilityListRole },
+ { WebAccessibility::ROLE_LISTBOX_OPTION, NSAccessibilityGroupRole },
+ { WebAccessibility::ROLE_LOG, NSAccessibilityGroupRole },
+ { WebAccessibility::ROLE_MARQUEE, NSAccessibilityGroupRole },
+ { WebAccessibility::ROLE_MATH, NSAccessibilityGroupRole },
+ { WebAccessibility::ROLE_MATTE, NSAccessibilityMatteRole },
+ { WebAccessibility::ROLE_MENU, NSAccessibilityMenuRole },
+ { WebAccessibility::ROLE_MENU_ITEM, NSAccessibilityMenuItemRole },
+ { WebAccessibility::ROLE_MENU_BUTTON, NSAccessibilityButtonRole },
+ { WebAccessibility::ROLE_MENU_LIST_OPTION, NSAccessibilityMenuItemRole },
+ { WebAccessibility::ROLE_MENU_LIST_POPUP, NSAccessibilityUnknownRole },
+ { WebAccessibility::ROLE_NOTE, NSAccessibilityGroupRole },
+ { WebAccessibility::ROLE_OUTLINE, NSAccessibilityOutlineRole },
+ { WebAccessibility::ROLE_POPUP_BUTTON, NSAccessibilityPopUpButtonRole },
+ { WebAccessibility::ROLE_PROGRESS_INDICATOR,
+ NSAccessibilityProgressIndicatorRole },
+ { WebAccessibility::ROLE_RADIO_BUTTON, NSAccessibilityRadioButtonRole },
+ { WebAccessibility::ROLE_RADIO_GROUP, NSAccessibilityRadioGroupRole },
+ { WebAccessibility::ROLE_REGION, NSAccessibilityGroupRole },
+ { WebAccessibility::ROLE_ROW, NSAccessibilityRowRole },
+ { WebAccessibility::ROLE_ROW_HEADER, @"AXCell" },
+ { WebAccessibility::ROLE_RULER, NSAccessibilityRulerRole },
+ { WebAccessibility::ROLE_RULER_MARKER, NSAccessibilityRulerMarkerRole },
+ { WebAccessibility::ROLE_SCROLLAREA, NSAccessibilityScrollAreaRole },
+ { WebAccessibility::ROLE_SCROLLBAR, NSAccessibilityScrollBarRole },
+ { WebAccessibility::ROLE_SHEET, NSAccessibilitySheetRole },
+ { WebAccessibility::ROLE_SLIDER, NSAccessibilitySliderRole },
+ { WebAccessibility::ROLE_SLIDER_THUMB, NSAccessibilityGroupRole },
+ { WebAccessibility::ROLE_SPLITTER, NSAccessibilitySplitterRole },
+ { WebAccessibility::ROLE_SPLIT_GROUP, NSAccessibilitySplitGroupRole },
+ { WebAccessibility::ROLE_STATIC_TEXT, NSAccessibilityStaticTextRole },
+ { WebAccessibility::ROLE_STATUS, NSAccessibilityGroupRole },
+ { WebAccessibility::ROLE_SYSTEM_WIDE, NSAccessibilityUnknownRole },
+ { WebAccessibility::ROLE_TAB, NSAccessibilityRadioButtonRole },
+ { WebAccessibility::ROLE_TAB_LIST, NSAccessibilityTabGroupRole },
+ { WebAccessibility::ROLE_TAB_PANEL, NSAccessibilityGroupRole },
+ { WebAccessibility::ROLE_TABLE, NSAccessibilityTableRole },
+ { WebAccessibility::ROLE_TABLE_HEADER_CONTAINER, NSAccessibilityGroupRole },
+ { WebAccessibility::ROLE_TAB_GROUP, NSAccessibilityTabGroupRole },
+ { WebAccessibility::ROLE_TEXTAREA, NSAccessibilityTextAreaRole },
+ { WebAccessibility::ROLE_TEXT_FIELD, NSAccessibilityTextFieldRole },
+ { WebAccessibility::ROLE_TIMER, NSAccessibilityGroupRole },
+ { WebAccessibility::ROLE_TOOLBAR, NSAccessibilityToolbarRole },
+ { WebAccessibility::ROLE_TOOLTIP, NSAccessibilityGroupRole },
+ { WebAccessibility::ROLE_TREE, NSAccessibilityOutlineRole },
+ { WebAccessibility::ROLE_TREE_GRID, NSAccessibilityTableRole },
+ { WebAccessibility::ROLE_TREE_ITEM, NSAccessibilityRowRole },
+ { WebAccessibility::ROLE_VALUE_INDICATOR, NSAccessibilityValueIndicatorRole },
+ { WebAccessibility::ROLE_WEBCORE_LINK, NSAccessibilityLinkRole },
+ { WebAccessibility::ROLE_WEB_AREA, @"AXWebArea" },
+ { WebAccessibility::ROLE_WINDOW, NSAccessibilityUnknownRole },
+};
+
+static const MapEntry subroles[] = {
+ { WebAccessibility::ROLE_ALERT, @"AXApplicationAlert" },
+ { WebAccessibility::ROLE_ALERT_DIALOG, @"AXApplicationAlertDialog" },
+ { WebAccessibility::ROLE_ARTICLE, @"AXDocumentArticle" },
+ { WebAccessibility::ROLE_DEFINITION_LIST_DEFINITION, @"AXDefinition" },
+ { WebAccessibility::ROLE_DEFINITION_LIST_TERM, @"AXTerm" },
+ { WebAccessibility::ROLE_DIALOG, @"AXApplicationDialog" },
+ { WebAccessibility::ROLE_DOCUMENT, @"AXDocument" },
+ { WebAccessibility::ROLE_LANDMARK_APPLICATION, @"AXLandmarkApplication" },
+ { WebAccessibility::ROLE_LANDMARK_BANNER, @"AXLandmarkBanner" },
+ { WebAccessibility::ROLE_LANDMARK_COMPLEMENTARY, @"AXLandmarkComplementary" },
+ { WebAccessibility::ROLE_LANDMARK_CONTENTINFO, @"AXLandmarkContentInfo" },
+ { WebAccessibility::ROLE_LANDMARK_MAIN, @"AXLandmarkMain" },
+ { WebAccessibility::ROLE_LANDMARK_NAVIGATION, @"AXLandmarkNavigation" },
+ { WebAccessibility::ROLE_LANDMARK_SEARCH, @"AXLandmarkSearch" },
+ { WebAccessibility::ROLE_LOG, @"AXApplicationLog" },
+ { WebAccessibility::ROLE_MARQUEE, @"AXApplicationMarquee" },
+ { WebAccessibility::ROLE_MATH, @"AXDocumentMath" },
+ { WebAccessibility::ROLE_NOTE, @"AXDocumentNote" },
+ { WebAccessibility::ROLE_REGION, @"AXDocumentRegion" },
+ { WebAccessibility::ROLE_STATUS, @"AXApplicationStatus" },
+ { WebAccessibility::ROLE_TAB_PANEL, @"AXTabPanel" },
+ { WebAccessibility::ROLE_TIMER, @"AXApplicationTimer" },
+ { WebAccessibility::ROLE_TOOLTIP, @"AXUserInterfaceTooltip" },
+ { WebAccessibility::ROLE_TREE_ITEM, NSAccessibilityOutlineRowSubrole },
+};
+
+static const AttributeToMethodNameEntry attributeToMethodNameContainer[] = {
+ { NSAccessibilityChildrenAttribute, @"children" },
+ { NSAccessibilityColumnsAttribute, @"columns" },
+ { NSAccessibilityDescriptionAttribute, @"description" },
+ { NSAccessibilityEnabledAttribute, @"enabled" },
+ { NSAccessibilityFocusedAttribute, @"focused" },
+ { NSAccessibilityHelpAttribute, @"help" },
+ { NSAccessibilityNumberOfCharactersAttribute, @"numberOfCharacters" },
+ { NSAccessibilityParentAttribute, @"parent" },
+ { NSAccessibilityPositionAttribute, @"position" },
+ { NSAccessibilityRoleAttribute, @"role" },
+ { NSAccessibilityRoleDescriptionAttribute, @"roleDescription" },
+ { NSAccessibilityRowsAttribute, @"rows" },
+ { NSAccessibilitySizeAttribute, @"size" },
+ { NSAccessibilitySubroleAttribute, @"subrole" },
+ { NSAccessibilityTabsAttribute, @"tabs" },
+ { NSAccessibilityTitleAttribute, @"title" },
+ { NSAccessibilityTopLevelUIElementAttribute, @"window" },
+ { NSAccessibilityURLAttribute, @"url" },
+ { NSAccessibilityValueAttribute, @"value" },
+ { NSAccessibilityVisibleCharacterRangeAttribute, @"visibleCharacterRange" },
+ { NSAccessibilityWindowAttribute, @"window" },
+ { @"AXVisited", @"visited" },
+};
+
+// GetState checks the bitmask used in webaccessibility.h to check
+// if the given state was set on the accessibility object.
+bool GetState(BrowserAccessibility* accessibility, int state) {
+ return ((accessibility->state() >> state) & 1);
+}
+
+// A mapping of webkit roles to native roles.
+std::map<WebAccessibility::Role, NSString*> webAccessibilityToNativeRole;
+// A mapping of webkit roles to native subroles.
+std::map<WebAccessibility::Role, NSString*> webAccessibilityToNativeSubrole;
+// A mapping from an accessibility attribute to its method name.
+NSDictionary* attributeToMethodNameMap = nil;
+
+} // namespace
+
+@implementation BrowserAccessibilityCocoa
+
++ (void)initialize {
+ const size_t numRoles = sizeof(roles) / sizeof(roles[0]);
+ for (size_t i = 0; i < numRoles; ++i) {
+ webAccessibilityToNativeRole[roles[i].webKitValue] = roles[i].nativeValue;
+ }
+
+ const size_t numSubroles = sizeof(subroles) / sizeof(subroles[0]);
+ for (size_t i = 0; i < numSubroles; ++i) {
+ webAccessibilityToNativeSubrole[subroles[i].webKitValue] =
+ subroles[i].nativeValue;
+ }
+
+ NSMutableDictionary* dict = [[NSMutableDictionary alloc] init];
+ const size_t numAttributes = sizeof(attributeToMethodNameContainer) /
+ sizeof(attributeToMethodNameContainer[0]);
+ for (size_t i = 0; i < numAttributes; ++i) {
+ [dict setObject:attributeToMethodNameContainer[i].methodName
+ forKey:attributeToMethodNameContainer[i].attribute];
+ }
+ attributeToMethodNameMap = dict;
+ dict = nil;
+}
+
+- (id)initWithObject:(BrowserAccessibility*)accessibility
+ delegate:(id<BrowserAccessibilityDelegateCocoa>)delegate {
+ if ((self = [super init])) {
+ browserAccessibility_ = accessibility;
+ delegate_ = delegate;
+ }
+ return self;
+}
+
+// Deletes our associated BrowserAccessibilityMac.
+- (void)dealloc {
+ if (browserAccessibility_) {
+ delete browserAccessibility_;
+ browserAccessibility_ = NULL;
+ }
+
+ [super dealloc];
+}
+
+// Returns an array of BrowserAccessibilityCocoa objects, representing the
+// accessibility children of this object.
+- (NSArray*)children {
+ if (!children_.get()) {
+ children_.reset([[NSMutableArray alloc]
+ initWithCapacity:browserAccessibility_->child_count()] );
+ for (uint32 index = 0;
+ index < browserAccessibility_->child_count();
+ ++index) {
+ BrowserAccessibilityCocoa* child =
+ browserAccessibility_->GetChild(index)->toBrowserAccessibilityCocoa();
+ if ([child isIgnored])
+ [children_ addObjectsFromArray:[child children]];
+ else
+ [children_ addObject:child];
+ }
+
+ // Also, add indirect children (if any).
+ for (uint32 i = 0;
+ i < browserAccessibility_->indirect_child_ids().size();
+ ++i) {
+ int32 child_id = browserAccessibility_->indirect_child_ids()[i];
+ BrowserAccessibilityCocoa* child =
+ browserAccessibility_->manager()->GetFromRendererID(child_id)->
+ toBrowserAccessibilityCocoa();
+ [children_ addObject:child];
+ }
+ }
+ return children_;
+}
+
+- (void)childrenChanged {
+ if (![self isIgnored]) {
+ children_.reset();
+ } else {
+ [browserAccessibility_->parent()->toBrowserAccessibilityCocoa()
+ childrenChanged];
+ }
+}
+
+- (NSArray*)columns {
+ NSMutableArray* ret = [[[NSMutableArray alloc] init] autorelease];
+ for (BrowserAccessibilityCocoa* child in [self children]) {
+ if ([[child role] isEqualToString:NSAccessibilityColumnRole])
+ [ret addObject:child];
+ }
+ return ret;
+}
+
+- (NSString*)description {
+ return NSStringForWebAccessibilityAttribute(
+ browserAccessibility_->attributes(),
+ WebAccessibility::ATTR_DESCRIPTION);
+}
+
+- (NSNumber*)enabled {
+ return [NSNumber numberWithBool:
+ !GetState(browserAccessibility_, WebAccessibility::STATE_UNAVAILABLE)];
+}
+
+- (NSNumber*)focused {
+ NSNumber* ret = [NSNumber numberWithBool:
+ GetState(browserAccessibility_, WebAccessibility::STATE_FOCUSED)];
+ return ret;
+}
+
+- (NSString*)help {
+ return NSStringForWebAccessibilityAttribute(
+ browserAccessibility_->attributes(),
+ WebAccessibility::ATTR_HELP);
+}
+
+// Returns whether or not this node should be ignored in the
+// accessibility tree.
+- (BOOL)isIgnored {
+ return [[self role] isEqualToString:NSAccessibilityUnknownRole];
+}
+
+- (NSNumber*)loaded {
+ return [NSNumber numberWithBool:YES];
+}
+
+// The origin of this accessibility object in the page's document.
+// This is relative to webkit's top-left origin, not Cocoa's
+// bottom-left origin.
+- (NSPoint)origin {
+ return NSMakePoint(browserAccessibility_->location().x(),
+ browserAccessibility_->location().y());
+}
+
+- (NSNumber*)numberOfCharacters {
+ return [NSNumber numberWithInt:browserAccessibility_->value().length()];
+}
+
+- (id)parent {
+ // A nil parent means we're the root.
+ if (browserAccessibility_->parent()) {
+ return NSAccessibilityUnignoredAncestor(
+ browserAccessibility_->parent()->toBrowserAccessibilityCocoa());
+ } else {
+ // Hook back up to RenderWidgetHostViewCocoa.
+ return browserAccessibility_->manager()->GetParentView();
+ }
+}
+
+- (NSValue*)position {
+ return [NSValue valueWithPoint:[delegate_ accessibilityPointInScreen:self]];
+}
+
+// Returns a string indicating the role of this object.
+- (NSString*)role {
+ WebAccessibility::Role browserAccessibilityRole =
+ static_cast<WebAccessibility::Role>( browserAccessibility_->role());
+
+ // Roles that we only determine at runtime.
+ if (browserAccessibilityRole == WebAccessibility::ROLE_TEXT_FIELD &&
+ GetState(browserAccessibility_, WebAccessibility::STATE_PROTECTED)) {
+ return @"AXSecureTextField";
+ }
+
+ std::map<WebAccessibility::Role, NSString*>::iterator it =
+ webAccessibilityToNativeRole.find(browserAccessibilityRole);
+
+ if (it != webAccessibilityToNativeRole.end())
+ return it->second;
+ else
+ return NSAccessibilityUnknownRole;
+}
+
+// Returns a string indicating the role description of this object.
+- (NSString*)roleDescription {
+ NSString* role = [self role];
+ // The following descriptions are specific to webkit.
+ if ([role isEqualToString:@"AXWebArea"])
+ return l10n_util::GetNSString(IDS_AX_ROLE_WEB_AREA);
+
+ if ([role isEqualToString:@"NSAccessibilityLinkRole"])
+ return l10n_util::GetNSString(IDS_AX_ROLE_LINK);
+
+ if ([role isEqualToString:@"AXHeading"])
+ return l10n_util::GetNSString(IDS_AX_ROLE_HEADING);
+
+ if ([role isEqualToString:NSAccessibilityGroupRole] ||
+ [role isEqualToString:NSAccessibilityRadioButtonRole]) {
+ const std::vector<std::pair<string16, string16> >& htmlAttributes =
+ browserAccessibility_->html_attributes();
+ WebAccessibility::Role browserAccessibilityRole =
+ static_cast<WebAccessibility::Role>(browserAccessibility_->role());
+
+ if ((browserAccessibilityRole != WebAccessibility::ROLE_GROUP &&
+ browserAccessibilityRole != WebAccessibility::ROLE_LIST_ITEM) ||
+ browserAccessibilityRole == WebAccessibility::ROLE_TAB) {
+ for (size_t i = 0; i < htmlAttributes.size(); ++i) {
+ const std::pair<string16, string16>& htmlAttribute = htmlAttributes[i];
+ if (htmlAttribute.first == ASCIIToUTF16("role")) {
+ // TODO(dtseng): This is not localized; see crbug/84814.
+ return base::SysUTF16ToNSString(htmlAttribute.second);
+ }
+ }
+ }
+ }
+
+ return NSAccessibilityRoleDescription(role, nil);
+}
+
+- (NSArray*)rows {
+ NSMutableArray* ret = [[[NSMutableArray alloc] init] autorelease];
+ for (BrowserAccessibilityCocoa* child in [self children]) {
+ if ([[child role] isEqualToString:NSAccessibilityRowRole])
+ [ret addObject:child];
+ }
+
+ return ret;
+}
+
+// Returns the size of this object.
+- (NSValue*)size {
+ return [NSValue valueWithSize:NSMakeSize(
+ browserAccessibility_->location().width(),
+ browserAccessibility_->location().height())];
+}
+
+// Returns a subrole based upon the role.
+- (NSString*) subrole {
+ // TODO: support password field -> NSAccessibilitySecureTextFieldSubrole
+ // TODO: support attachments
+ // TODO: support lists -> NSAccessibilityContentListSubrole ||
+ // NSAccessibilityDefinitionListSubrole
+
+ WebAccessibility::Role browserAccessibilityRole =
+ static_cast<WebAccessibility::Role>( browserAccessibility_->role());
+
+ std::map<WebAccessibility::Role, NSString*>::iterator it =
+ webAccessibilityToNativeSubrole.find(browserAccessibilityRole);
+
+ if (it != webAccessibilityToNativeSubrole.end())
+ return it->second;
+ else
+ return nil;
+}
+
+// Returns all tabs in this subtree.
+- (NSArray*)tabs {
+ NSMutableArray* tabSubtree = [[[NSMutableArray alloc] init] autorelease];
+
+ if (browserAccessibility_->role() == WebAccessibility::ROLE_TAB)
+ [tabSubtree addObject:self];
+
+ for (uint i=0; i < [[self children] count]; ++i) {
+ NSArray* tabChildren = [[[self children] objectAtIndex:i] tabs];
+ if ([tabChildren count] > 0)
+ [tabSubtree addObjectsFromArray:tabChildren];
+ }
+
+ return tabSubtree;
+}
+
+- (NSString*)title {
+ return base::SysUTF16ToNSString(browserAccessibility_->name());
+}
+
+- (NSString*)url {
+ WebAccessibility::Attribute urlAttribute =
+ [[self role] isEqualToString:@"AXWebArea"] ?
+ WebAccessibility::ATTR_DOC_URL :
+ WebAccessibility::ATTR_URL;
+ return NSStringForWebAccessibilityAttribute(
+ browserAccessibility_->attributes(),
+ urlAttribute);
+}
+
+- (id)value {
+ // WebCore uses an attachmentView to get the below behavior.
+ // We do not have any native views backing this object, so need
+ // to approximate Cocoa ax behavior best as we can.
+ NSString* role = [self role];
+ if ([role isEqualToString:@"AXHeading"]) {
+ NSString* headingLevel =
+ NSStringForWebAccessibilityAttribute(
+ browserAccessibility_->attributes(),
+ WebAccessibility::ATTR_HTML_TAG);
+ if ([headingLevel length] >= 2) {
+ return [NSNumber numberWithInt:
+ [[headingLevel substringFromIndex:1] intValue]];
+ }
+ } else if ([role isEqualToString:NSAccessibilityButtonRole]) {
+ // AXValue does not make sense for pure buttons.
+ return @"";
+ } else if ([role isEqualToString:NSAccessibilityCheckBoxRole] ||
+ [role isEqualToString:NSAccessibilityRadioButtonRole]) {
+ return [NSNumber numberWithInt:GetState(
+ browserAccessibility_, WebAccessibility::STATE_CHECKED) ? 1 : 0];
+ }
+ return base::SysUTF16ToNSString(browserAccessibility_->value());
+}
+
+- (NSValue*)visibleCharacterRange {
+ return [NSValue valueWithRange:
+ NSMakeRange(0, browserAccessibility_->value().length())];
+}
+
+- (NSNumber*)visited {
+ return [NSNumber numberWithBool:
+ GetState(browserAccessibility_, WebAccessibility::STATE_TRAVERSED)];
+}
+
+- (id)window {
+ return [delegate_ window];
+}
+
+// Returns the accessibility value for the given attribute. If the value isn't
+// supported this will return nil.
+- (id)accessibilityAttributeValue:(NSString*)attribute {
+ SEL selector =
+ NSSelectorFromString([attributeToMethodNameMap objectForKey:attribute]);
+ if (selector)
+ return [self performSelector:selector];
+
+ // TODO(dtseng): refactor remaining attributes.
+ int selStart, selEnd;
+ if (browserAccessibility_->GetAttributeAsInt(
+ WebAccessibility::ATTR_TEXT_SEL_START, &selStart) &&
+ browserAccessibility_->
+ GetAttributeAsInt(WebAccessibility::ATTR_TEXT_SEL_END, &selEnd)) {
+ if (selStart > selEnd)
+ std::swap(selStart, selEnd);
+ int selLength = selEnd - selStart;
+ if ([attribute isEqualToString:
+ NSAccessibilityInsertionPointLineNumberAttribute]) {
+ const std::vector<int32>& line_breaks =
+ browserAccessibility_->line_breaks();
+ for (int i = 0; i < static_cast<int>(line_breaks.size()); ++i) {
+ if (line_breaks[i] > selStart)
+ return [NSNumber numberWithInt:i];
+ }
+ return [NSNumber numberWithInt:static_cast<int>(line_breaks.size())];
+ }
+ if ([attribute isEqualToString:NSAccessibilitySelectedTextAttribute]) {
+ return base::SysUTF16ToNSString(browserAccessibility_->value().substr(
+ selStart, selLength));
+ }
+ if ([attribute isEqualToString:NSAccessibilitySelectedTextRangeAttribute]) {
+ return [NSValue valueWithRange:NSMakeRange(selStart, selLength)];
+ }
+ }
+ return nil;
+}
+
+// Returns the accessibility value for the given attribute and parameter. If the
+// value isn't supported this will return nil.
+- (id)accessibilityAttributeValue:(NSString*)attribute
+ forParameter:(id)parameter {
+ const std::vector<int32>& line_breaks = browserAccessibility_->line_breaks();
+ int len = static_cast<int>(browserAccessibility_->value().size());
+
+ if ([attribute isEqualToString:
+ NSAccessibilityStringForRangeParameterizedAttribute]) {
+ NSRange range = [(NSValue*)parameter rangeValue];
+ return base::SysUTF16ToNSString(
+ browserAccessibility_->value().substr(range.location, range.length));
+ }
+
+ if ([attribute isEqualToString:
+ NSAccessibilityLineForIndexParameterizedAttribute]) {
+ int index = [(NSNumber*)parameter intValue];
+ for (int i = 0; i < static_cast<int>(line_breaks.size()); ++i) {
+ if (line_breaks[i] > index)
+ return [NSNumber numberWithInt:i];
+ }
+ return [NSNumber numberWithInt:static_cast<int>(line_breaks.size())];
+ }
+
+ if ([attribute isEqualToString:
+ NSAccessibilityRangeForLineParameterizedAttribute]) {
+ int line_index = [(NSNumber*)parameter intValue];
+ int line_count = static_cast<int>(line_breaks.size()) + 1;
+ if (line_index < 0 || line_index >= line_count)
+ return nil;
+ int start = line_index > 0 ? line_breaks[line_index - 1] : 0;
+ int end = line_index < line_count - 1 ? line_breaks[line_index] : len;
+ return [NSValue valueWithRange:
+ NSMakeRange(start, end - start)];
+ }
+
+ // TODO(dtseng): support the following attributes.
+ if ([attribute isEqualTo:
+ NSAccessibilityRangeForPositionParameterizedAttribute] ||
+ [attribute isEqualTo:
+ NSAccessibilityRangeForIndexParameterizedAttribute] ||
+ [attribute isEqualTo:
+ NSAccessibilityBoundsForRangeParameterizedAttribute] ||
+ [attribute isEqualTo:NSAccessibilityRTFForRangeParameterizedAttribute] ||
+ [attribute isEqualTo:
+ NSAccessibilityStyleRangeForIndexParameterizedAttribute]) {
+ return nil;
+ }
+ return nil;
+}
+
+// Returns an array of parameterized attributes names that this object will
+// respond to.
+- (NSArray*)accessibilityParameterizedAttributeNames {
+ if ([[self role] isEqualToString:NSAccessibilityTextFieldRole] ||
+ [[self role] isEqualToString:NSAccessibilityTextAreaRole]) {
+ return [NSArray arrayWithObjects:
+ NSAccessibilityLineForIndexParameterizedAttribute,
+ NSAccessibilityRangeForLineParameterizedAttribute,
+ NSAccessibilityStringForRangeParameterizedAttribute,
+ NSAccessibilityRangeForPositionParameterizedAttribute,
+ NSAccessibilityRangeForIndexParameterizedAttribute,
+ NSAccessibilityBoundsForRangeParameterizedAttribute,
+ NSAccessibilityRTFForRangeParameterizedAttribute,
+ NSAccessibilityAttributedStringForRangeParameterizedAttribute,
+ NSAccessibilityStyleRangeForIndexParameterizedAttribute,
+ nil];
+ }
+ return nil;
+}
+
+// Returns an array of action names that this object will respond to.
+- (NSArray*)accessibilityActionNames {
+ NSMutableArray* ret =
+ [NSMutableArray arrayWithObject:NSAccessibilityShowMenuAction];
+ NSString* role = [self role];
+ // TODO(dtseng): this should only get set when there's a default action.
+ if (![role isEqualToString:NSAccessibilityStaticTextRole] &&
+ ![role isEqualToString:NSAccessibilityTextAreaRole] &&
+ ![role isEqualToString:NSAccessibilityTextFieldRole]) {
+ [ret addObject:NSAccessibilityPressAction];
+ }
+
+ return ret;
+}
+
+// Returns a sub-array of values for the given attribute value, starting at
+// index, with up to maxCount items. If the given index is out of bounds,
+// or there are no values for the given attribute, it will return nil.
+// This method is used for querying subsets of values, without having to
+// return a large set of data, such as elements with a large number of
+// children.
+- (NSArray*)accessibilityArrayAttributeValues:(NSString*)attribute
+ index:(NSUInteger)index
+ maxCount:(NSUInteger)maxCount {
+ NSArray* fullArray = [self accessibilityAttributeValue:attribute];
+ if (!fullArray)
+ return nil;
+ NSUInteger arrayCount = [fullArray count];
+ if (index >= arrayCount)
+ return nil;
+ NSRange subRange;
+ if ((index + maxCount) > arrayCount) {
+ subRange = NSMakeRange(index, arrayCount - index);
+ } else {
+ subRange = NSMakeRange(index, maxCount);
+ }
+ return [fullArray subarrayWithRange:subRange];
+}
+
+// Returns the count of the specified accessibility array attribute.
+- (NSUInteger)accessibilityArrayAttributeCount:(NSString*)attribute {
+ NSArray* fullArray = [self accessibilityAttributeValue:attribute];
+ return [fullArray count];
+}
+
+// Returns the list of accessibility attributes that this object supports.
+- (NSArray*)accessibilityAttributeNames {
+ // General attributes.
+ NSMutableArray* ret = [NSMutableArray arrayWithObjects:
+ NSAccessibilityChildrenAttribute,
+ NSAccessibilityDescriptionAttribute,
+ NSAccessibilityEnabledAttribute,
+ NSAccessibilityFocusedAttribute,
+ NSAccessibilityHelpAttribute,
+ NSAccessibilityParentAttribute,
+ NSAccessibilityPositionAttribute,
+ NSAccessibilityRoleAttribute,
+ NSAccessibilityRoleDescriptionAttribute,
+ NSAccessibilitySizeAttribute,
+ NSAccessibilitySubroleAttribute,
+ NSAccessibilityTitleAttribute,
+ NSAccessibilityTopLevelUIElementAttribute,
+ NSAccessibilityValueAttribute,
+ NSAccessibilityWindowAttribute,
+ NSAccessibilityURLAttribute,
+ @"AXVisited",
+ nil];
+
+ // Specific role attributes.
+ NSString* role = [self role];
+ if ([role isEqualToString:NSAccessibilityTableRole]) {
+ [ret addObjectsFromArray:[NSArray arrayWithObjects:
+ NSAccessibilityColumnsAttribute,
+ NSAccessibilityRowsAttribute,
+ nil]];
+ } else if ([role isEqualToString:@"AXWebArea"]) {
+ [ret addObject:@"AXLoaded"];
+ } else if ([role isEqualToString:NSAccessibilityTextFieldRole] ||
+ [role isEqualToString:NSAccessibilityTextAreaRole]) {
+ [ret addObjectsFromArray:[NSArray arrayWithObjects:
+ NSAccessibilityInsertionPointLineNumberAttribute,
+ NSAccessibilityNumberOfCharactersAttribute,
+ NSAccessibilitySelectedTextAttribute,
+ NSAccessibilitySelectedTextRangeAttribute,
+ NSAccessibilityVisibleCharacterRangeAttribute,
+ nil]];
+ } else if ([role isEqualToString:NSAccessibilityTabGroupRole]) {
+ [ret addObject:NSAccessibilityTabsAttribute];
+ }
+
+ return ret;
+}
+
+// Returns the index of the child in this objects array of children.
+- (NSUInteger)accessibilityGetIndexOf:(id)child {
+ NSUInteger index = 0;
+ for (BrowserAccessibilityCocoa* childToCheck in [self children]) {
+ if ([child isEqual:childToCheck])
+ return index;
+ ++index;
+ }
+ return NSNotFound;
+}
+
+// Returns whether or not the specified attribute can be set by the
+// accessibility API via |accessibilitySetValue:forAttribute:|.
+- (BOOL)accessibilityIsAttributeSettable:(NSString*)attribute {
+ if ([attribute isEqualToString:NSAccessibilityFocusedAttribute])
+ return GetState(browserAccessibility_, WebAccessibility::STATE_FOCUSABLE);
+ if ([attribute isEqualToString:NSAccessibilityValueAttribute])
+ return !GetState(browserAccessibility_, WebAccessibility::STATE_READONLY);
+ return NO;
+}
+
+// Returns whether or not this object should be ignored in the accessibilty
+// tree.
+- (BOOL)accessibilityIsIgnored {
+ return [self isIgnored];
+}
+
+// Performs the given accessibilty action on the webkit accessibility object
+// that backs this object.
+- (void)accessibilityPerformAction:(NSString*)action {
+ // TODO(feldstein): Support more actions.
+ if ([action isEqualToString:NSAccessibilityPressAction])
+ [delegate_ doDefaultAction:browserAccessibility_->renderer_id()];
+ else if ([action isEqualToString:NSAccessibilityShowMenuAction])
+ [delegate_ performShowMenuAction:self];
+}
+
+// Returns the description of the given action.
+- (NSString*)accessibilityActionDescription:(NSString*)action {
+ return NSAccessibilityActionDescription(action);
+}
+
+// Sets an override value for a specific accessibility attribute.
+// This class does not support this.
+- (BOOL)accessibilitySetOverrideValue:(id)value
+ forAttribute:(NSString*)attribute {
+ return NO;
+}
+
+// Sets the value for an accessibility attribute via the accessibility API.
+- (void)accessibilitySetValue:(id)value forAttribute:(NSString*)attribute {
+ if ([attribute isEqualToString:NSAccessibilityFocusedAttribute]) {
+ NSNumber* focusedNumber = value;
+ BOOL focused = [focusedNumber intValue];
+ [delegate_ setAccessibilityFocus:focused
+ accessibilityId:browserAccessibility_->renderer_id()];
+ }
+}
+
+// Returns the deepest accessibility child that should not be ignored.
+// It is assumed that the hit test has been narrowed down to this object
+// or one of its children, so this will never return nil.
+- (id)accessibilityHitTest:(NSPoint)point {
+ BrowserAccessibilityCocoa* hit = self;
+ for (BrowserAccessibilityCocoa* child in [self children]) {
+ NSPoint origin = [child origin];
+ NSSize size = [[child size] sizeValue];
+ NSRect rect;
+ rect.origin = origin;
+ rect.size = size;
+ if (NSPointInRect(point, rect)) {
+ hit = child;
+ id childResult = [child accessibilityHitTest:point];
+ if (![childResult accessibilityIsIgnored]) {
+ hit = childResult;
+ break;
+ }
+ }
+ }
+ return NSAccessibilityUnignoredAncestor(hit);
+}
+
+- (BOOL)isEqual:(id)object {
+ if (![object isKindOfClass:[BrowserAccessibilityCocoa class]])
+ return NO;
+ return ([self hash] == [object hash]);
+}
+
+- (NSUInteger)hash {
+ // Potentially called during dealloc.
+ if (!browserAccessibility_)
+ return [super hash];
+ return browserAccessibility_->renderer_id();
+}
+
+@end
+
diff --git a/content/browser/accessibility/browser_accessibility_delegate_mac.h b/content/browser/accessibility/browser_accessibility_delegate_mac.h
new file mode 100644
index 0000000..680ab87
--- /dev/null
+++ b/content/browser/accessibility/browser_accessibility_delegate_mac.h
@@ -0,0 +1,24 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_ACCESSIBILITY_BROWSER_ACCESSIBILITY_DELEGATE_MAC_H_
+#define CONTENT_BROWSER_ACCESSIBILITY_BROWSER_ACCESSIBILITY_DELEGATE_MAC_H_
+#pragma once
+
+@class BrowserAccessibilityCocoa;
+@class NSWindow;
+
+// This protocol is used by the BrowserAccessibility objects to pass messages
+// to, or otherwise communicate with, their underlying WebAccessibility
+// objects over the IPC boundary.
+@protocol BrowserAccessibilityDelegateCocoa
+- (NSPoint)accessibilityPointInScreen:(BrowserAccessibilityCocoa*)accessibility;
+- (void)doDefaultAction:(int32)accessibilityObjectId;
+- (void)performShowMenuAction:(BrowserAccessibilityCocoa*)accessibility;
+- (void)setAccessibilityFocus:(BOOL)focus
+ accessibilityId:(int32)accessibilityObjectId;
+- (NSWindow*)window;
+@end
+
+#endif // CONTENT_BROWSER_ACCESSIBILITY_BROWSER_ACCESSIBILITY_DELEGATE_MAC_H_
diff --git a/content/browser/accessibility/browser_accessibility_mac.h b/content/browser/accessibility/browser_accessibility_mac.h
new file mode 100644
index 0000000..ee6cfca
--- /dev/null
+++ b/content/browser/accessibility/browser_accessibility_mac.h
@@ -0,0 +1,46 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_ACCESSIBILITY_BROWSER_ACCESSIBILITY_MAC_H_
+#define CONTENT_BROWSER_ACCESSIBILITY_BROWSER_ACCESSIBILITY_MAC_H_
+#pragma once
+
+#include <map>
+#include <utility>
+#include <vector>
+
+#include "base/memory/scoped_nsobject.h"
+#include "content/browser/accessibility/browser_accessibility.h"
+
+@class BrowserAccessibilityCocoa;
+
+class BrowserAccessibilityMac : public BrowserAccessibility {
+ public:
+ // Implementation of BrowserAccessibility.
+ virtual void Initialize();
+ virtual void NativeReleaseReference();
+
+ // Overrides from BrowserAccessibility.
+ virtual void DetachTree(std::vector<BrowserAccessibility*>* nodes);
+
+ // The BrowserAccessibilityCocoa associated with us.
+ BrowserAccessibilityCocoa* native_view() const {
+ return browser_accessibility_cocoa_;
+ }
+
+ private:
+ // This gives BrowserAccessibility::Create access to the class constructor.
+ friend class BrowserAccessibility;
+
+ BrowserAccessibilityMac();
+
+ // Allows access to the BrowserAccessibilityCocoa which wraps this.
+ // BrowserAccessibility.
+ // We own this object until our manager calls ReleaseReference;
+ // thereafter, the cocoa object owns us.
+ BrowserAccessibilityCocoa* browser_accessibility_cocoa_;
+ DISALLOW_COPY_AND_ASSIGN(BrowserAccessibilityMac);
+};
+
+#endif // CONTENT_BROWSER_ACCESSIBILITY_BROWSER_ACCESSIBILITY_MAC_H_
diff --git a/content/browser/accessibility/browser_accessibility_mac.mm b/content/browser/accessibility/browser_accessibility_mac.mm
new file mode 100644
index 0000000..145294d
--- /dev/null
+++ b/content/browser/accessibility/browser_accessibility_mac.mm
@@ -0,0 +1,59 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import <Cocoa/Cocoa.h>
+
+#import "content/browser/accessibility/browser_accessibility_mac.h"
+
+#import "content/browser/accessibility/browser_accessibility_cocoa.h"
+#import "content/browser/accessibility/browser_accessibility_delegate_mac.h"
+#include "content/browser/accessibility/browser_accessibility_manager.h"
+
+
+// Static.
+BrowserAccessibility* BrowserAccessibility::Create() {
+ return new BrowserAccessibilityMac();
+}
+
+BrowserAccessibilityMac::BrowserAccessibilityMac()
+ : browser_accessibility_cocoa_(NULL) {
+}
+
+void BrowserAccessibilityMac::Initialize() {
+ BrowserAccessibility::Initialize();
+
+ if (browser_accessibility_cocoa_)
+ return;
+
+ // We take ownership of the cocoa obj here.
+ browser_accessibility_cocoa_ = [[BrowserAccessibilityCocoa alloc]
+ initWithObject:this
+ delegate:
+ (id<BrowserAccessibilityDelegateCocoa>)manager_->GetParentView()];
+}
+
+void BrowserAccessibilityMac::NativeReleaseReference() {
+ if (browser_accessibility_cocoa_) {
+ BrowserAccessibilityCocoa* temp = browser_accessibility_cocoa_;
+ browser_accessibility_cocoa_ = nil;
+ // Relinquish ownership of the cocoa obj.
+ [temp release];
+ // At this point, other processes may have a reference to
+ // the cocoa object. When the retain count hits zero, it will
+ // destroy us in dealloc.
+ // For that reason, do *not* make any more calls here after
+ // as we might have been deleted.
+ }
+}
+
+void BrowserAccessibilityMac::DetachTree(
+ std::vector<BrowserAccessibility*>* nodes) {
+ [browser_accessibility_cocoa_ childrenChanged];
+ BrowserAccessibility::DetachTree(nodes);
+}
+
+BrowserAccessibilityCocoa* BrowserAccessibility::toBrowserAccessibilityCocoa() {
+ return static_cast<BrowserAccessibilityMac*>(this)->
+ native_view();
+}
diff --git a/content/browser/accessibility/browser_accessibility_manager.cc b/content/browser/accessibility/browser_accessibility_manager.cc
new file mode 100644
index 0000000..a99c782
--- /dev/null
+++ b/content/browser/accessibility/browser_accessibility_manager.cc
@@ -0,0 +1,373 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/accessibility/browser_accessibility_manager.h"
+
+#include "base/logging.h"
+#include "content/browser/accessibility/browser_accessibility.h"
+#include "content/common/view_messages.h"
+
+using webkit_glue::WebAccessibility;
+
+BrowserAccessibility* BrowserAccessibilityFactory::Create() {
+ return BrowserAccessibility::Create();
+}
+
+// Start child IDs at -1 and decrement each time, because clients use
+// child IDs of 1, 2, 3, ... to access the children of an object by
+// index, so we use negative IDs to clearly distinguish between indices
+// and unique IDs.
+// static
+int32 BrowserAccessibilityManager::next_child_id_ = -1;
+
+#if defined(OS_POSIX) && !defined(OS_MACOSX)
+// There's no OS-specific implementation of BrowserAccessibilityManager
+// on Unix, so just instantiate the base class.
+// static
+BrowserAccessibilityManager* BrowserAccessibilityManager::Create(
+ gfx::NativeView parent_view,
+ const WebAccessibility& src,
+ BrowserAccessibilityDelegate* delegate,
+ BrowserAccessibilityFactory* factory) {
+ return new BrowserAccessibilityManager(
+ parent_view, src, delegate, factory);
+}
+#endif
+
+BrowserAccessibilityManager::BrowserAccessibilityManager(
+ gfx::NativeView parent_view,
+ const WebAccessibility& src,
+ BrowserAccessibilityDelegate* delegate,
+ BrowserAccessibilityFactory* factory)
+ : parent_view_(parent_view),
+ delegate_(delegate),
+ factory_(factory),
+ focus_(NULL) {
+ root_ = CreateAccessibilityTree(NULL, src, 0);
+ if (!focus_)
+ SetFocus(root_, false);
+}
+
+// static
+int32 BrowserAccessibilityManager::GetNextChildID() {
+ // Get the next child ID, and wrap around when we get near the end
+ // of a 32-bit integer range. It's okay to wrap around; we just want
+ // to avoid it as long as possible because clients may cache the ID of
+ // an object for a while to determine if they've seen it before.
+ next_child_id_--;
+ if (next_child_id_ == -2000000000)
+ next_child_id_ = -1;
+
+ return next_child_id_;
+}
+
+BrowserAccessibilityManager::~BrowserAccessibilityManager() {
+ // Clients could still hold references to some nodes of the tree, so
+ // calling InternalReleaseReference will make sure that as many nodes
+ // as possible are released now, and remaining nodes are marked as
+ // inactive so that calls to any methods on them will fail gracefully.
+ focus_->InternalReleaseReference(false);
+ root_->InternalReleaseReference(true);
+}
+
+BrowserAccessibility* BrowserAccessibilityManager::GetRoot() {
+ return root_;
+}
+
+BrowserAccessibility* BrowserAccessibilityManager::GetFromChildID(
+ int32 child_id) {
+ base::hash_map<int32, BrowserAccessibility*>::iterator iter =
+ child_id_map_.find(child_id);
+ if (iter != child_id_map_.end()) {
+ return iter->second;
+ } else {
+ return NULL;
+ }
+}
+
+BrowserAccessibility* BrowserAccessibilityManager::GetFromRendererID(
+ int32 renderer_id) {
+ base::hash_map<int32, int32>::iterator iter =
+ renderer_id_to_child_id_map_.find(renderer_id);
+ if (iter == renderer_id_to_child_id_map_.end())
+ return NULL;
+
+ int32 child_id = iter->second;
+ return GetFromChildID(child_id);
+}
+
+void BrowserAccessibilityManager::Remove(int32 child_id, int32 renderer_id) {
+ child_id_map_.erase(child_id);
+ renderer_id_to_child_id_map_.erase(renderer_id);
+}
+
+void BrowserAccessibilityManager::OnAccessibilityNotifications(
+ const std::vector<ViewHostMsg_AccessibilityNotification_Params>& params) {
+ for (uint32 index = 0; index < params.size(); index++) {
+ const ViewHostMsg_AccessibilityNotification_Params& param = params[index];
+
+ switch (param.notification_type) {
+ case ViewHostMsg_AccessibilityNotification_Type::
+ NOTIFICATION_TYPE_CHECK_STATE_CHANGED:
+ OnAccessibilityObjectStateChange(param.acc_obj);
+ break;
+ case ViewHostMsg_AccessibilityNotification_Type::
+ NOTIFICATION_TYPE_CHILDREN_CHANGED:
+ OnAccessibilityObjectChildrenChange(param.acc_obj);
+ break;
+ case ViewHostMsg_AccessibilityNotification_Type::
+ NOTIFICATION_TYPE_FOCUS_CHANGED:
+ OnAccessibilityObjectFocusChange(param.acc_obj);
+ break;
+ case ViewHostMsg_AccessibilityNotification_Type::
+ NOTIFICATION_TYPE_LOAD_COMPLETE:
+ OnAccessibilityObjectLoadComplete(param.acc_obj);
+ break;
+ case ViewHostMsg_AccessibilityNotification_Type::
+ NOTIFICATION_TYPE_VALUE_CHANGED:
+ OnAccessibilityObjectValueChange(param.acc_obj);
+ break;
+ case ViewHostMsg_AccessibilityNotification_Type::
+ NOTIFICATION_TYPE_SELECTED_TEXT_CHANGED:
+ OnAccessibilityObjectTextChange(param.acc_obj);
+ break;
+ default:
+ DCHECK(0);
+ break;
+ }
+ }
+}
+
+void BrowserAccessibilityManager::OnAccessibilityObjectStateChange(
+ const WebAccessibility& acc_obj) {
+ BrowserAccessibility* new_browser_acc = UpdateNode(acc_obj, false);
+ if (!new_browser_acc)
+ return;
+
+ NotifyAccessibilityEvent(
+ ViewHostMsg_AccessibilityNotification_Type::
+ NOTIFICATION_TYPE_CHECK_STATE_CHANGED,
+ new_browser_acc);
+}
+
+void BrowserAccessibilityManager::OnAccessibilityObjectChildrenChange(
+ const WebAccessibility& acc_obj) {
+ BrowserAccessibility* new_browser_acc = UpdateNode(acc_obj, true);
+ if (!new_browser_acc)
+ return;
+
+ NotifyAccessibilityEvent(
+ ViewHostMsg_AccessibilityNotification_Type::
+ NOTIFICATION_TYPE_CHILDREN_CHANGED,
+ new_browser_acc);
+}
+
+void BrowserAccessibilityManager::OnAccessibilityObjectFocusChange(
+ const WebAccessibility& acc_obj) {
+ BrowserAccessibility* new_browser_acc = UpdateNode(acc_obj, false);
+ if (!new_browser_acc)
+ return;
+
+ SetFocus(new_browser_acc, false);
+ if (delegate_ && delegate_->HasFocus()) {
+ GotFocus();
+ } else if (!delegate_) {
+ // Mac currently does not have a BrowserAccessibilityDelegate.
+ NotifyAccessibilityEvent(
+ ViewHostMsg_AccessibilityNotification_Type::
+ NOTIFICATION_TYPE_FOCUS_CHANGED,
+ focus_);
+ }
+}
+
+void BrowserAccessibilityManager::OnAccessibilityObjectLoadComplete(
+ const WebAccessibility& acc_obj) {
+ SetFocus(NULL, false);
+ root_->InternalReleaseReference(true);
+
+ root_ = CreateAccessibilityTree(NULL, acc_obj, 0);
+ if (!focus_)
+ SetFocus(root_, false);
+
+ NotifyAccessibilityEvent(
+ ViewHostMsg_AccessibilityNotification_Type::
+ NOTIFICATION_TYPE_LOAD_COMPLETE,
+ root_);
+ if (delegate_ && delegate_->HasFocus())
+ GotFocus();
+}
+
+void BrowserAccessibilityManager::OnAccessibilityObjectValueChange(
+ const WebAccessibility& acc_obj) {
+ BrowserAccessibility* new_browser_acc = UpdateNode(acc_obj, false);
+ if (!new_browser_acc)
+ return;
+
+ NotifyAccessibilityEvent(
+ ViewHostMsg_AccessibilityNotification_Type::
+ NOTIFICATION_TYPE_VALUE_CHANGED,
+ new_browser_acc);
+}
+
+void BrowserAccessibilityManager::OnAccessibilityObjectTextChange(
+ const WebAccessibility& acc_obj) {
+ BrowserAccessibility* new_browser_acc = UpdateNode(acc_obj, false);
+ if (!new_browser_acc)
+ return;
+
+ NotifyAccessibilityEvent(
+ ViewHostMsg_AccessibilityNotification_Type::
+ NOTIFICATION_TYPE_SELECTED_TEXT_CHANGED,
+ new_browser_acc);
+}
+
+void BrowserAccessibilityManager::GotFocus() {
+ // TODO(ctguil): Remove when tree update logic handles focus changes.
+ if (!focus_)
+ return;
+
+ NotifyAccessibilityEvent(
+ ViewHostMsg_AccessibilityNotification_Type::
+ NOTIFICATION_TYPE_FOCUS_CHANGED,
+ focus_);
+}
+
+gfx::NativeView BrowserAccessibilityManager::GetParentView() {
+ return parent_view_;
+}
+
+BrowserAccessibility* BrowserAccessibilityManager::GetFocus(
+ BrowserAccessibility* root) {
+ if (focus_ && (!root || focus_->IsDescendantOf(root)))
+ return focus_;
+
+ return NULL;
+}
+
+void BrowserAccessibilityManager::SetFocus(
+ BrowserAccessibility* node, bool notify) {
+ if (focus_)
+ focus_->InternalReleaseReference(false);
+ focus_ = node;
+ if (focus_)
+ focus_->InternalAddReference();
+
+ if (notify && node && delegate_)
+ delegate_->SetAccessibilityFocus(node->renderer_id());
+}
+
+void BrowserAccessibilityManager::DoDefaultAction(
+ const BrowserAccessibility& node) {
+ if (delegate_)
+ delegate_->AccessibilityDoDefaultAction(node.renderer_id());
+}
+
+gfx::Rect BrowserAccessibilityManager::GetViewBounds() {
+ if (delegate_)
+ return delegate_->GetViewBounds();
+ return gfx::Rect();
+}
+
+BrowserAccessibility* BrowserAccessibilityManager::UpdateNode(
+ const WebAccessibility& src,
+ bool include_children) {
+ base::hash_map<int32, int32>::iterator iter =
+ renderer_id_to_child_id_map_.find(src.id);
+ if (iter == renderer_id_to_child_id_map_.end())
+ return NULL;
+
+ int32 child_id = iter->second;
+ BrowserAccessibility* current = GetFromChildID(child_id);
+ if (!current)
+ return NULL;
+
+ if (!include_children) {
+ DCHECK_EQ(0U, src.children.size());
+ current->Initialize(
+ this,
+ current->parent(),
+ current->child_id(),
+ current->index_in_parent(),
+ src);
+ return current;
+ }
+
+ BrowserAccessibility* current_parent = current->parent();
+ int current_index_in_parent = current->index_in_parent();
+
+ // Detach all of the nodes in the old tree and get a single flat vector
+ // of all node pointers.
+ std::vector<BrowserAccessibility*> old_tree_nodes;
+ current->DetachTree(&old_tree_nodes);
+
+ // Build a new tree, reusing old nodes if possible. Each node that's
+ // reused will have its reference count incremented by one.
+ current =
+ CreateAccessibilityTree(current_parent, src, current_index_in_parent);
+
+ // Decrement the reference count of all nodes in the old tree, which will
+ // delete any nodes no longer needed.
+ for (int i = 0; i < static_cast<int>(old_tree_nodes.size()); i++)
+ old_tree_nodes[i]->InternalReleaseReference(false);
+
+ DCHECK(focus_);
+ if (!focus_->instance_active())
+ SetFocus(root_, false);
+
+ return current;
+}
+
+BrowserAccessibility* BrowserAccessibilityManager::CreateAccessibilityTree(
+ BrowserAccessibility* parent,
+ const WebAccessibility& src,
+ int index_in_parent) {
+ BrowserAccessibility* instance = NULL;
+ int32 child_id = 0;
+ base::hash_map<int32, int32>::iterator iter =
+ renderer_id_to_child_id_map_.find(src.id);
+
+ // If a BrowserAccessibility instance for this ID already exists, add a
+ // new reference to it and retrieve its children vector.
+ if (iter != renderer_id_to_child_id_map_.end()) {
+ child_id = iter->second;
+ instance = GetFromChildID(child_id);
+ }
+
+ // If the node has changed roles, don't reuse a BrowserAccessibility
+ // object, that could confuse a screen reader.
+ if (instance && instance->role() != src.role)
+ instance = NULL;
+
+ // If we're reusing a node, it should already be detached from a parent
+ // and any children. If not, that means we have a serious bug somewhere,
+ // like the same child is reachable from two places in the same tree.
+ if (instance && (instance->parent() != NULL || instance->child_count() > 0)) {
+ NOTREACHED();
+ instance = NULL;
+ }
+
+ if (instance) {
+ // If we're reusing a node, update its parent and increment its
+ // reference count.
+ instance->UpdateParent(parent, index_in_parent);
+ instance->InternalAddReference();
+ } else {
+ // Otherwise, create a new instance.
+ instance = factory_->Create();
+ child_id = GetNextChildID();
+ }
+
+ instance->Initialize(this, parent, child_id, index_in_parent, src);
+ child_id_map_[child_id] = instance;
+ renderer_id_to_child_id_map_[src.id] = child_id;
+ if ((src.state >> WebAccessibility::STATE_FOCUSED) & 1)
+ SetFocus(instance, false);
+ for (int i = 0; i < static_cast<int>(src.children.size()); ++i) {
+ BrowserAccessibility* child = CreateAccessibilityTree(
+ instance, src.children[i], i);
+ instance->AddChild(child);
+ }
+
+ return instance;
+}
diff --git a/content/browser/accessibility/browser_accessibility_manager.h b/content/browser/accessibility/browser_accessibility_manager.h
new file mode 100644
index 0000000..bbb7d77
--- /dev/null
+++ b/content/browser/accessibility/browser_accessibility_manager.h
@@ -0,0 +1,177 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_ACCESSIBILITY_BROWSER_ACCESSIBILITY_MANAGER_H_
+#define CONTENT_BROWSER_ACCESSIBILITY_BROWSER_ACCESSIBILITY_MANAGER_H_
+#pragma once
+
+#include <vector>
+
+#include "base/hash_tables.h"
+#include "base/memory/scoped_ptr.h"
+#include "build/build_config.h"
+#include "ui/gfx/native_widget_types.h"
+#include "webkit/glue/webaccessibility.h"
+
+class BrowserAccessibility;
+#if defined(OS_WIN)
+class BrowserAccessibilityManagerWin;
+#endif
+
+struct ViewHostMsg_AccessibilityNotification_Params;
+
+using webkit_glue::WebAccessibility;
+
+// Class that can perform actions on behalf of the BrowserAccessibilityManager.
+class BrowserAccessibilityDelegate {
+ public:
+ virtual ~BrowserAccessibilityDelegate() {}
+ virtual void SetAccessibilityFocus(int acc_obj_id) = 0;
+ virtual void AccessibilityDoDefaultAction(int acc_obj_id) = 0;
+ virtual bool HasFocus() = 0;
+ virtual gfx::Rect GetViewBounds() const = 0;
+};
+
+class BrowserAccessibilityFactory {
+ public:
+ virtual ~BrowserAccessibilityFactory() {}
+
+ // Create an instance of BrowserAccessibility and return a new
+ // reference to it.
+ virtual BrowserAccessibility* Create();
+};
+
+// Manages a tree of BrowserAccessibility objects.
+class BrowserAccessibilityManager {
+ public:
+ // Creates the platform specific BrowserAccessibilityManager. Ownership passes
+ // to the caller.
+ static BrowserAccessibilityManager* Create(
+ gfx::NativeView parent_view,
+ const WebAccessibility& src,
+ BrowserAccessibilityDelegate* delegate,
+ BrowserAccessibilityFactory* factory = new BrowserAccessibilityFactory());
+
+ virtual ~BrowserAccessibilityManager();
+
+ // Type is a ViewHostMsg_AccessibilityNotification_Params::NotificationType.
+ // We pass it as int so that we don't include the render message declaration
+ // header here.
+ virtual void NotifyAccessibilityEvent(
+ int type,
+ BrowserAccessibility* node) { }
+
+ // Returns the next unique child id.
+ static int32 GetNextChildID();
+
+ // Return a pointer to the root of the tree, does not make a new reference.
+ BrowserAccessibility* GetRoot();
+
+ // Removes the BrowserAccessibility child_id and renderer_id from the manager.
+ void Remove(int32 child_id, int32 renderer_id);
+
+ // Return a pointer to the object corresponding to the given child_id,
+ // does not make a new reference.
+ BrowserAccessibility* GetFromChildID(int32 child_id);
+
+ // Return a pointer to the object corresponding to the given renderer_id,
+ // does not make a new reference.
+ BrowserAccessibility* GetFromRendererID(int32 renderer_id);
+
+ // Called to notify the accessibility manager that its associated native
+ // view got focused.
+ void GotFocus();
+
+ // Update the focused node to |node|, which may be null.
+ // If |notify| is true, send a message to the renderer to set focus
+ // to this node.
+ void SetFocus(BrowserAccessibility* node, bool notify);
+
+ // Tell the renderer to do the default action for this node.
+ void DoDefaultAction(const BrowserAccessibility& node);
+
+ // Retrieve the bounds of the parent View in screen coordinates.
+ gfx::Rect GetViewBounds();
+
+ // Called when the renderer process has notified us of about tree changes.
+ // Send a notification to MSAA clients of the change.
+ void OnAccessibilityNotifications(
+ const std::vector<ViewHostMsg_AccessibilityNotification_Params>& params);
+
+ gfx::NativeView GetParentView();
+
+#if defined(OS_WIN)
+ BrowserAccessibilityManagerWin* toBrowserAccessibilityManagerWin();
+#endif
+
+ // Return the object that has focus, if it's a descandant of the
+ // given root (inclusive). Does not make a new reference.
+ BrowserAccessibility* GetFocus(BrowserAccessibility* root);
+
+ protected:
+ BrowserAccessibilityManager(
+ gfx::NativeView parent_view,
+ const WebAccessibility& src,
+ BrowserAccessibilityDelegate* delegate,
+ BrowserAccessibilityFactory* factory);
+
+ private:
+ void OnAccessibilityObjectStateChange(
+ const WebAccessibility& acc_obj);
+ void OnAccessibilityObjectChildrenChange(
+ const WebAccessibility& acc_obj);
+ void OnAccessibilityObjectFocusChange(
+ const WebAccessibility& acc_obj);
+ void OnAccessibilityObjectLoadComplete(
+ const WebAccessibility& acc_obj);
+ void OnAccessibilityObjectValueChange(
+ const WebAccessibility& acc_obj);
+ void OnAccessibilityObjectTextChange(
+ const WebAccessibility& acc_obj);
+
+ // Update an accessibility node with an updated WebAccessibility node
+ // received from the renderer process. When |include_children| is true
+ // the node's children will also be updated, otherwise only the node
+ // itself is updated. Returns the updated node or NULL if no node was
+ // updated.
+ BrowserAccessibility* UpdateNode(
+ const WebAccessibility& src,
+ bool include_children);
+
+ // Recursively build a tree of BrowserAccessibility objects from
+ // the WebAccessibility tree received from the renderer process.
+ BrowserAccessibility* CreateAccessibilityTree(
+ BrowserAccessibility* parent,
+ const WebAccessibility& src,
+ int index_in_parent);
+
+ protected:
+ // The next unique id for a BrowserAccessibility instance.
+ static int32 next_child_id_;
+
+ // The parent view.
+ gfx::NativeView parent_view_;
+
+ // The object that can perform actions on our behalf.
+ BrowserAccessibilityDelegate* delegate_;
+
+ // Factory to create BrowserAccessibility objects (for dependency injection).
+ scoped_ptr<BrowserAccessibilityFactory> factory_;
+
+ // The root of the tree of IAccessible objects and the element that
+ // currently has focus, if any.
+ BrowserAccessibility* root_;
+ BrowserAccessibility* focus_;
+
+ // A mapping from the IDs of objects in the renderer, to the child IDs
+ // we use internally here.
+ base::hash_map<int32, int32> renderer_id_to_child_id_map_;
+
+ // A mapping from child IDs to BrowserAccessibility objects.
+ base::hash_map<int32, BrowserAccessibility*> child_id_map_;
+
+ DISALLOW_COPY_AND_ASSIGN(BrowserAccessibilityManager);
+};
+
+#endif // CONTENT_BROWSER_ACCESSIBILITY_BROWSER_ACCESSIBILITY_MANAGER_H_
diff --git a/content/browser/accessibility/browser_accessibility_manager_mac.h b/content/browser/accessibility/browser_accessibility_manager_mac.h
new file mode 100644
index 0000000..c7c5089
--- /dev/null
+++ b/content/browser/accessibility/browser_accessibility_manager_mac.h
@@ -0,0 +1,31 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_ACCESSIBILITY_BROWSER_ACCESSIBILITY_MANAGER_MAC_H_
+#define CONTENT_BROWSER_ACCESSIBILITY_BROWSER_ACCESSIBILITY_MANAGER_MAC_H_
+#pragma once
+
+#import <Cocoa/Cocoa.h>
+
+#include "content/browser/accessibility/browser_accessibility_manager.h"
+
+class BrowserAccessibilityManagerMac : public BrowserAccessibilityManager {
+ public:
+ // Implementation of BrowserAccessibilityManager.
+ virtual void NotifyAccessibilityEvent(int type, BrowserAccessibility* node);
+
+ private:
+ // This gives BrowserAccessibilityManager::Create access to the class
+ // constructor.
+ friend class BrowserAccessibilityManager;
+
+ BrowserAccessibilityManagerMac(gfx::NativeView parent_view,
+ const webkit_glue::WebAccessibility& src,
+ BrowserAccessibilityDelegate* delegate,
+ BrowserAccessibilityFactory* factory);
+
+ DISALLOW_COPY_AND_ASSIGN(BrowserAccessibilityManagerMac);
+};
+
+#endif // CONTENT_BROWSER_ACCESSIBILITY_BROWSER_ACCESSIBILITY_MANAGER_MAC_H_
diff --git a/content/browser/accessibility/browser_accessibility_manager_mac.mm b/content/browser/accessibility/browser_accessibility_manager_mac.mm
new file mode 100644
index 0000000..b5618fe3
--- /dev/null
+++ b/content/browser/accessibility/browser_accessibility_manager_mac.mm
@@ -0,0 +1,63 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/accessibility/browser_accessibility_manager_mac.h"
+
+#import "base/logging.h"
+#import "content/browser/accessibility/browser_accessibility_cocoa.h"
+#include "content/common/view_messages.h"
+
+// static
+BrowserAccessibilityManager* BrowserAccessibilityManager::Create(
+ gfx::NativeView parent_view,
+ const WebAccessibility& src,
+ BrowserAccessibilityDelegate* delegate,
+ BrowserAccessibilityFactory* factory) {
+ return new BrowserAccessibilityManagerMac(
+ parent_view, src, delegate, factory);
+}
+
+BrowserAccessibilityManagerMac::BrowserAccessibilityManagerMac(
+ gfx::NativeView parent_window,
+ const webkit_glue::WebAccessibility& src,
+ BrowserAccessibilityDelegate* delegate,
+ BrowserAccessibilityFactory* factory)
+ : BrowserAccessibilityManager(parent_window, src, delegate, factory) {
+}
+
+void BrowserAccessibilityManagerMac::NotifyAccessibilityEvent(
+ int type,
+ BrowserAccessibility* node) {
+ // Refer to AXObjectCache.mm (webkit).
+ NSString* event_id = @"";
+ switch (type) {
+ case ViewHostMsg_AccessibilityNotification_Type::
+ NOTIFICATION_TYPE_CHECK_STATE_CHANGED:
+ // Does not exist on Mac.
+ return;
+ case ViewHostMsg_AccessibilityNotification_Type::
+ NOTIFICATION_TYPE_CHILDREN_CHANGED:
+ // TODO(dtseng): no clear equivalent on Mac.
+ return;
+ case ViewHostMsg_AccessibilityNotification_Type::
+ NOTIFICATION_TYPE_FOCUS_CHANGED:
+ event_id = NSAccessibilityFocusedUIElementChangedNotification;
+ break;
+ case ViewHostMsg_AccessibilityNotification_Type::
+ NOTIFICATION_TYPE_LOAD_COMPLETE:
+ event_id = @"AXLoadComplete";
+ break;
+ case ViewHostMsg_AccessibilityNotification_Type::
+ NOTIFICATION_TYPE_VALUE_CHANGED:
+ event_id = NSAccessibilityValueChangedNotification;
+ break;
+ case ViewHostMsg_AccessibilityNotification_Type::
+ NOTIFICATION_TYPE_SELECTED_TEXT_CHANGED:
+ event_id = NSAccessibilitySelectedTextChangedNotification;
+ break;
+ }
+ BrowserAccessibilityCocoa* native_node = node->toBrowserAccessibilityCocoa();
+ DCHECK(native_node);
+ NSAccessibilityPostNotification(native_node, event_id);
+}
diff --git a/content/browser/accessibility/browser_accessibility_manager_win.cc b/content/browser/accessibility/browser_accessibility_manager_win.cc
new file mode 100644
index 0000000..7b992e7
--- /dev/null
+++ b/content/browser/accessibility/browser_accessibility_manager_win.cc
@@ -0,0 +1,90 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/accessibility/browser_accessibility_manager_win.h"
+
+#include "content/browser/accessibility/browser_accessibility_win.h"
+#include "content/common/view_messages.h"
+
+using webkit_glue::WebAccessibility;
+
+// static
+BrowserAccessibilityManager* BrowserAccessibilityManager::Create(
+ gfx::NativeView parent_view,
+ const WebAccessibility& src,
+ BrowserAccessibilityDelegate* delegate,
+ BrowserAccessibilityFactory* factory) {
+ return new BrowserAccessibilityManagerWin(
+ parent_view,
+ src,
+ delegate,
+ factory);
+}
+
+BrowserAccessibilityManagerWin*
+BrowserAccessibilityManager::toBrowserAccessibilityManagerWin() {
+ return static_cast<BrowserAccessibilityManagerWin*>(this);
+}
+
+BrowserAccessibilityManagerWin::BrowserAccessibilityManagerWin(
+ HWND parent_view,
+ const WebAccessibility& src,
+ BrowserAccessibilityDelegate* delegate,
+ BrowserAccessibilityFactory* factory)
+ : BrowserAccessibilityManager(parent_view, src, delegate, factory) {
+ // Allow NULL parent_view for unit testing.
+ if (parent_view == NULL) {
+ window_iaccessible_ = NULL;
+ return;
+ }
+
+ HRESULT hr = ::CreateStdAccessibleObject(
+ parent_view, OBJID_WINDOW, IID_IAccessible,
+ reinterpret_cast<void **>(&window_iaccessible_));
+ DCHECK(SUCCEEDED(hr));
+}
+
+BrowserAccessibilityManagerWin::~BrowserAccessibilityManagerWin() {
+}
+
+IAccessible* BrowserAccessibilityManagerWin::GetParentWindowIAccessible() {
+ return window_iaccessible_;
+}
+
+void BrowserAccessibilityManagerWin::NotifyAccessibilityEvent(
+ int type,
+ BrowserAccessibility* node) {
+ LONG event_id = EVENT_MIN;
+ switch (type) {
+ case ViewHostMsg_AccessibilityNotification_Type::
+ NOTIFICATION_TYPE_CHECK_STATE_CHANGED:
+ event_id = EVENT_OBJECT_STATECHANGE;
+ break;
+ case ViewHostMsg_AccessibilityNotification_Type::
+ NOTIFICATION_TYPE_CHILDREN_CHANGED:
+ event_id = EVENT_OBJECT_REORDER;
+ break;
+ case ViewHostMsg_AccessibilityNotification_Type::
+ NOTIFICATION_TYPE_FOCUS_CHANGED:
+ event_id = EVENT_OBJECT_FOCUS;
+ break;
+ case ViewHostMsg_AccessibilityNotification_Type::
+ NOTIFICATION_TYPE_LOAD_COMPLETE:
+ event_id = IA2_EVENT_DOCUMENT_LOAD_COMPLETE;
+ break;
+ case ViewHostMsg_AccessibilityNotification_Type::
+ NOTIFICATION_TYPE_VALUE_CHANGED:
+ event_id = EVENT_OBJECT_VALUECHANGE;
+ break;
+ case ViewHostMsg_AccessibilityNotification_Type::
+ NOTIFICATION_TYPE_SELECTED_TEXT_CHANGED:
+ event_id = IA2_EVENT_TEXT_CARET_MOVED;
+ break;
+ default:
+ NOTREACHED();
+ break;
+ }
+
+ NotifyWinEvent(event_id, GetParentView(), OBJID_CLIENT, node->child_id());
+}
diff --git a/content/browser/accessibility/browser_accessibility_manager_win.h b/content/browser/accessibility/browser_accessibility_manager_win.h
new file mode 100644
index 0000000..04ea53f
--- /dev/null
+++ b/content/browser/accessibility/browser_accessibility_manager_win.h
@@ -0,0 +1,48 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_ACCESSIBILITY_BROWSER_ACCESSIBILITY_MANAGER_WIN_H_
+#define CONTENT_BROWSER_ACCESSIBILITY_BROWSER_ACCESSIBILITY_MANAGER_WIN_H_
+#pragma once
+
+#include <oleacc.h>
+
+#include "base/win/scoped_comptr.h"
+#include "content/browser/accessibility/browser_accessibility_manager.h"
+#include "webkit/glue/webaccessibility.h"
+
+class BrowserAccessibilityWin;
+struct ViewHostMsg_AccessibilityNotification_Params;
+
+using webkit_glue::WebAccessibility;
+
+// Manages a tree of BrowserAccessibilityWin objects.
+class BrowserAccessibilityManagerWin : public BrowserAccessibilityManager {
+ public:
+ virtual ~BrowserAccessibilityManagerWin();
+
+ // Get a the default IAccessible for the parent window, does not make a
+ // new reference.
+ IAccessible* GetParentWindowIAccessible();
+
+ // BrowserAccessibilityManager methods
+ virtual void NotifyAccessibilityEvent(int type, BrowserAccessibility* node);
+
+ private:
+ BrowserAccessibilityManagerWin(
+ HWND parent_window,
+ const WebAccessibility& src,
+ BrowserAccessibilityDelegate* delegate,
+ BrowserAccessibilityFactory* factory);
+
+ // A default IAccessible instance for the parent window.
+ base::win::ScopedComPtr<IAccessible> window_iaccessible_;
+
+ // Give BrowserAccessibilityManager::Create access to our constructor.
+ friend class BrowserAccessibilityManager;
+
+ DISALLOW_COPY_AND_ASSIGN(BrowserAccessibilityManagerWin);
+};
+
+#endif // CONTENT_BROWSER_ACCESSIBILITY_BROWSER_ACCESSIBILITY_MANAGER_WIN_H_
diff --git a/content/browser/accessibility/browser_accessibility_state.cc b/content/browser/accessibility/browser_accessibility_state.cc
new file mode 100644
index 0000000..45b3a3b
--- /dev/null
+++ b/content/browser/accessibility/browser_accessibility_state.cc
@@ -0,0 +1,27 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/accessibility/browser_accessibility_state.h"
+
+#include "base/memory/singleton.h"
+
+BrowserAccessibilityState::BrowserAccessibilityState()
+ : screen_reader_active_(false) {
+}
+
+BrowserAccessibilityState::~BrowserAccessibilityState() {
+}
+
+// static
+BrowserAccessibilityState* BrowserAccessibilityState::GetInstance() {
+ return Singleton<BrowserAccessibilityState>::get();
+}
+
+void BrowserAccessibilityState::OnScreenReaderDetected() {
+ screen_reader_active_ = true;
+}
+
+bool BrowserAccessibilityState::IsAccessibleBrowser() {
+ return screen_reader_active_;
+}
diff --git a/content/browser/accessibility/browser_accessibility_state.h b/content/browser/accessibility/browser_accessibility_state.h
new file mode 100644
index 0000000..82cb8a3
--- /dev/null
+++ b/content/browser/accessibility/browser_accessibility_state.h
@@ -0,0 +1,53 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_ACCESSIBILITY_BROWSER_ACCESSIBILITY_STATE_H_
+#define CONTENT_BROWSER_ACCESSIBILITY_BROWSER_ACCESSIBILITY_STATE_H_
+#pragma once
+
+#include "base/basictypes.h"
+
+template <typename T> struct DefaultSingletonTraits;
+
+// The BrowserAccessibilityState class is used to determine if Chrome should be
+// customized for users with assistive technology, such as screen readers. We
+// modify the behavior of certain user interfaces to provide a better experience
+// for screen reader users. The way we detect a screen reader program is
+// different for each platform.
+//
+// Screen Reader Detection
+// (1) On windows many screen reader detection mechinisms will give false
+// positives like relying on the SPI_GETSCREENREADER system parameter. In Chrome
+// we attempt to dynamically detect a MSAA client screen reader by calling
+// NotifiyWinEvent in NativeWidgetWin with a custom ID and wait to see if the ID
+// is requested by a subsequent call to WM_GETOBJECT.
+// (2) On mac we detect dynamically if VoiceOver is running. We rely upon the
+// undocumented accessibility attribute @"AXEnhancedUserInterface" which is set
+// when VoiceOver is launched and unset when VoiceOver is closed. This is an
+// improvement over reading defaults preference values (which has no callback
+// mechanism).
+class BrowserAccessibilityState {
+ public:
+ // Returns the singleton instance.
+ static BrowserAccessibilityState* GetInstance();
+
+ ~BrowserAccessibilityState();
+
+ // Called when screen reader client is detected.
+ void OnScreenReaderDetected();
+
+ // Returns true if the browser should be customized for accessibility.
+ bool IsAccessibleBrowser();
+
+ private:
+ BrowserAccessibilityState();
+ friend struct DefaultSingletonTraits<BrowserAccessibilityState>;
+
+ // Set to true when a screen reader client is detected.
+ bool screen_reader_active_;
+
+ DISALLOW_COPY_AND_ASSIGN(BrowserAccessibilityState);
+};
+
+#endif // CONTENT_BROWSER_ACCESSIBILITY_BROWSER_ACCESSIBILITY_STATE_H_
diff --git a/content/browser/accessibility/browser_accessibility_win.cc b/content/browser/accessibility/browser_accessibility_win.cc
new file mode 100644
index 0000000..8cd1566
--- /dev/null
+++ b/content/browser/accessibility/browser_accessibility_win.cc
@@ -0,0 +1,1634 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/accessibility/browser_accessibility_win.h"
+
+#include "base/string_number_conversions.h"
+#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
+#include "content/browser/accessibility/browser_accessibility_manager_win.h"
+#include "net/base/escape.h"
+
+using webkit_glue::WebAccessibility;
+
+// The GUID for the ISimpleDOM service is not defined in the IDL files.
+// This is taken directly from the Mozilla sources
+// (accessible/src/msaa/nsAccessNodeWrap.cpp) and it's also documented at:
+// http://developer.mozilla.org/en/Accessibility/AT-APIs/ImplementationFeatures/MSAA
+
+const GUID GUID_ISimpleDOM = {
+ 0x0c539790, 0x12e4, 0x11cf,
+ 0xb6, 0x61, 0x00, 0xaa, 0x00, 0x4c, 0xd6, 0xd8};
+
+// static
+BrowserAccessibility* BrowserAccessibility::Create() {
+ CComObject<BrowserAccessibilityWin>* instance;
+ HRESULT hr = CComObject<BrowserAccessibilityWin>::CreateInstance(&instance);
+ DCHECK(SUCCEEDED(hr));
+ return instance->NewReference();
+}
+
+BrowserAccessibilityWin* BrowserAccessibility::toBrowserAccessibilityWin() {
+ return static_cast<BrowserAccessibilityWin*>(this);
+}
+
+BrowserAccessibilityWin::BrowserAccessibilityWin()
+ : ia_role_(0),
+ ia_state_(0),
+ ia2_role_(0),
+ ia2_state_(0) {
+}
+
+BrowserAccessibilityWin::~BrowserAccessibilityWin() {
+}
+
+//
+// IAccessible methods.
+//
+// Conventions:
+// * Always test for instance_active_ first and return E_FAIL if it's false.
+// * Always check for invalid arguments first, even if they're unused.
+// * Return S_FALSE if the only output is a string argument and it's empty.
+//
+
+HRESULT BrowserAccessibilityWin::accDoDefaultAction(VARIANT var_id) {
+ if (!instance_active_)
+ return E_FAIL;
+
+ BrowserAccessibilityWin* target = GetTargetFromChildID(var_id);
+ if (!target)
+ return E_INVALIDARG;
+
+ manager_->DoDefaultAction(*target);
+ return S_OK;
+}
+
+STDMETHODIMP BrowserAccessibilityWin::accHitTest(LONG x_left,
+ LONG y_top,
+ VARIANT* child) {
+ if (!instance_active_)
+ return E_FAIL;
+
+ if (!child)
+ return E_INVALIDARG;
+
+ gfx::Point point(x_left, y_top);
+ if (!GetBoundsRect().Contains(point)) {
+ // Return S_FALSE and VT_EMPTY when the outside the object's boundaries.
+ child->vt = VT_EMPTY;
+ return S_FALSE;
+ }
+
+ BrowserAccessibility* result = BrowserAccessibilityForPoint(point);
+ if (result == this) {
+ // Point is within this object.
+ child->vt = VT_I4;
+ child->lVal = CHILDID_SELF;
+ } else {
+ child->vt = VT_DISPATCH;
+ child->pdispVal = result->toBrowserAccessibilityWin()->NewReference();
+ }
+ return S_OK;
+}
+
+STDMETHODIMP BrowserAccessibilityWin::accLocation(LONG* x_left, LONG* y_top,
+ LONG* width, LONG* height,
+ VARIANT var_id) {
+ if (!instance_active_)
+ return E_FAIL;
+
+ if (!x_left || !y_top || !width || !height)
+ return E_INVALIDARG;
+
+ BrowserAccessibilityWin* target = GetTargetFromChildID(var_id);
+ if (!target)
+ return E_INVALIDARG;
+
+ gfx::Rect bounds = target->GetBoundsRect();
+ *x_left = bounds.x();
+ *y_top = bounds.y();
+ *width = bounds.width();
+ *height = bounds.height();
+
+ return S_OK;
+}
+
+STDMETHODIMP BrowserAccessibilityWin::accNavigate(
+ LONG nav_dir, VARIANT start, VARIANT* end) {
+ BrowserAccessibilityWin* target = GetTargetFromChildID(start);
+ if (!target)
+ return E_INVALIDARG;
+
+ if ((nav_dir == NAVDIR_LASTCHILD || nav_dir == NAVDIR_FIRSTCHILD) &&
+ start.lVal != CHILDID_SELF) {
+ // MSAA states that navigating to first/last child can only be from self.
+ return E_INVALIDARG;
+ }
+
+ BrowserAccessibility* result = NULL;
+ switch (nav_dir) {
+ case NAVDIR_DOWN:
+ case NAVDIR_UP:
+ case NAVDIR_LEFT:
+ case NAVDIR_RIGHT:
+ // These directions are not implemented, matching Mozilla and IE.
+ return E_NOTIMPL;
+ case NAVDIR_FIRSTCHILD:
+ if (!target->children_.empty())
+ result = target->children_.front();
+ break;
+ case NAVDIR_LASTCHILD:
+ if (!target->children_.empty())
+ result = target->children_.back();
+ break;
+ case NAVDIR_NEXT:
+ result = target->GetNextSibling();
+ break;
+ case NAVDIR_PREVIOUS:
+ result = target->GetPreviousSibling();
+ break;
+ }
+
+ if (!result) {
+ end->vt = VT_EMPTY;
+ return S_FALSE;
+ }
+
+ end->vt = VT_DISPATCH;
+ end->pdispVal = result->toBrowserAccessibilityWin()->NewReference();
+ return S_OK;
+}
+
+STDMETHODIMP BrowserAccessibilityWin::get_accChild(VARIANT var_child,
+ IDispatch** disp_child) {
+ if (!instance_active_)
+ return E_FAIL;
+
+ if (!disp_child)
+ return E_INVALIDARG;
+
+ *disp_child = NULL;
+
+ BrowserAccessibilityWin* target = GetTargetFromChildID(var_child);
+ if (!target)
+ return E_INVALIDARG;
+
+ (*disp_child) = target->NewReference();
+ return S_OK;
+}
+
+STDMETHODIMP BrowserAccessibilityWin::get_accChildCount(LONG* child_count) {
+ if (!instance_active_)
+ return E_FAIL;
+
+ if (!child_count)
+ return E_INVALIDARG;
+
+ *child_count = children_.size();
+ return S_OK;
+}
+
+STDMETHODIMP BrowserAccessibilityWin::get_accDefaultAction(VARIANT var_id,
+ BSTR* def_action) {
+ if (!instance_active_)
+ return E_FAIL;
+
+ if (!def_action)
+ return E_INVALIDARG;
+
+ BrowserAccessibilityWin* target = GetTargetFromChildID(var_id);
+ if (!target)
+ return E_INVALIDARG;
+
+ return target->GetAttributeAsBstr(
+ WebAccessibility::ATTR_SHORTCUT, def_action);
+}
+
+STDMETHODIMP BrowserAccessibilityWin::get_accDescription(VARIANT var_id,
+ BSTR* desc) {
+ if (!instance_active_)
+ return E_FAIL;
+
+ if (!desc)
+ return E_INVALIDARG;
+
+ BrowserAccessibilityWin* target = GetTargetFromChildID(var_id);
+ if (!target)
+ return E_INVALIDARG;
+
+ return target->GetAttributeAsBstr(WebAccessibility::ATTR_DESCRIPTION, desc);
+}
+
+STDMETHODIMP BrowserAccessibilityWin::get_accFocus(VARIANT* focus_child) {
+ if (!instance_active_)
+ return E_FAIL;
+
+ if (!focus_child)
+ return E_INVALIDARG;
+
+ BrowserAccessibilityWin* focus = static_cast<BrowserAccessibilityWin*>(
+ manager_->GetFocus(this));
+ if (focus == this) {
+ focus_child->vt = VT_I4;
+ focus_child->lVal = CHILDID_SELF;
+ } else if (focus == NULL) {
+ focus_child->vt = VT_EMPTY;
+ } else {
+ focus_child->vt = VT_DISPATCH;
+ focus_child->pdispVal = focus->NewReference();
+ }
+
+ return S_OK;
+}
+
+STDMETHODIMP BrowserAccessibilityWin::get_accHelp(VARIANT var_id, BSTR* help) {
+ if (!instance_active_)
+ return E_FAIL;
+
+ if (!help)
+ return E_INVALIDARG;
+
+ BrowserAccessibilityWin* target = GetTargetFromChildID(var_id);
+ if (!target)
+ return E_INVALIDARG;
+
+ return target->GetAttributeAsBstr(WebAccessibility::ATTR_HELP, help);
+}
+
+STDMETHODIMP BrowserAccessibilityWin::get_accKeyboardShortcut(VARIANT var_id,
+ BSTR* acc_key) {
+ if (!instance_active_)
+ return E_FAIL;
+
+ if (!acc_key)
+ return E_INVALIDARG;
+
+ BrowserAccessibilityWin* target = GetTargetFromChildID(var_id);
+ if (!target)
+ return E_INVALIDARG;
+
+ return target->GetAttributeAsBstr(WebAccessibility::ATTR_SHORTCUT, acc_key);
+}
+
+STDMETHODIMP BrowserAccessibilityWin::get_accName(VARIANT var_id, BSTR* name) {
+ if (!instance_active_)
+ return E_FAIL;
+
+ if (!name)
+ return E_INVALIDARG;
+
+ BrowserAccessibilityWin* target = GetTargetFromChildID(var_id);
+ if (!target)
+ return E_INVALIDARG;
+
+ if (target->name_.empty())
+ return S_FALSE;
+
+ *name = SysAllocString(target->name_.c_str());
+
+ DCHECK(*name);
+ return S_OK;
+}
+
+STDMETHODIMP BrowserAccessibilityWin::get_accParent(IDispatch** disp_parent) {
+ if (!instance_active_)
+ return E_FAIL;
+
+ if (!disp_parent)
+ return E_INVALIDARG;
+
+ IAccessible* parent = parent_->toBrowserAccessibilityWin();
+ if (parent == NULL) {
+ // This happens if we're the root of the tree;
+ // return the IAccessible for the window.
+ parent = manager_->toBrowserAccessibilityManagerWin()->
+ GetParentWindowIAccessible();
+ }
+
+ parent->AddRef();
+ *disp_parent = parent;
+ return S_OK;
+}
+
+STDMETHODIMP BrowserAccessibilityWin::get_accRole(
+ VARIANT var_id, VARIANT* role) {
+ if (!instance_active_)
+ return E_FAIL;
+
+ if (!role)
+ return E_INVALIDARG;
+
+ BrowserAccessibilityWin* target = GetTargetFromChildID(var_id);
+ if (!target)
+ return E_INVALIDARG;
+
+ if (!target->role_name_.empty()) {
+ role->vt = VT_BSTR;
+ role->bstrVal = SysAllocString(target->role_name_.c_str());
+ } else {
+ role->vt = VT_I4;
+ role->lVal = target->ia_role_;
+ }
+ return S_OK;
+}
+
+STDMETHODIMP BrowserAccessibilityWin::get_accState(VARIANT var_id,
+ VARIANT* state) {
+ if (!instance_active_)
+ return E_FAIL;
+
+ if (!state)
+ return E_INVALIDARG;
+
+ BrowserAccessibilityWin* target = GetTargetFromChildID(var_id);
+ if (!target)
+ return E_INVALIDARG;
+
+ state->vt = VT_I4;
+ state->lVal = target->ia_state_;
+ if (manager_->GetFocus(NULL) == this)
+ state->lVal |= STATE_SYSTEM_FOCUSED;
+
+ return S_OK;
+}
+
+STDMETHODIMP BrowserAccessibilityWin::get_accValue(
+ VARIANT var_id, BSTR* value) {
+ if (!instance_active_)
+ return E_FAIL;
+
+ if (!value)
+ return E_INVALIDARG;
+
+ BrowserAccessibilityWin* target = GetTargetFromChildID(var_id);
+ if (!target)
+ return E_INVALIDARG;
+
+ *value = SysAllocString(target->value_.c_str());
+
+ DCHECK(*value);
+ return S_OK;
+}
+
+STDMETHODIMP BrowserAccessibilityWin::get_accHelpTopic(
+ BSTR* help_file, VARIANT var_id, LONG* topic_id) {
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP BrowserAccessibilityWin::get_accSelection(VARIANT* selected) {
+ if (!instance_active_)
+ return E_FAIL;
+
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP BrowserAccessibilityWin::accSelect(
+ LONG flags_sel, VARIANT var_id) {
+ if (!instance_active_)
+ return E_FAIL;
+
+ if (flags_sel & SELFLAG_TAKEFOCUS) {
+ manager_->SetFocus(this, true);
+ return S_OK;
+ }
+
+ return S_FALSE;
+}
+
+//
+// IAccessible2 methods.
+//
+
+STDMETHODIMP BrowserAccessibilityWin::role(LONG* role) {
+ if (!instance_active_)
+ return E_FAIL;
+
+ if (!role)
+ return E_INVALIDARG;
+
+ *role = ia2_role_;
+
+ return S_OK;
+}
+
+STDMETHODIMP BrowserAccessibilityWin::get_attributes(BSTR* attributes) {
+ if (!instance_active_)
+ return E_FAIL;
+
+ if (!attributes)
+ return E_INVALIDARG;
+
+ // Follow Firefox's convention, which is to return a set of key-value pairs
+ // separated by semicolons, with a colon between the key and the value.
+ string16 str;
+ for (unsigned int i = 0; i < html_attributes_.size(); i++) {
+ if (i != 0)
+ str += L';';
+ str += Escape(html_attributes_[i].first);
+ str += L':';
+ str += Escape(html_attributes_[i].second);
+ }
+
+ if (str.empty())
+ return S_FALSE;
+
+ *attributes = SysAllocString(str.c_str());
+ DCHECK(*attributes);
+ return S_OK;
+}
+
+STDMETHODIMP BrowserAccessibilityWin::get_states(AccessibleStates* states) {
+ if (!instance_active_)
+ return E_FAIL;
+
+ if (!states)
+ return E_INVALIDARG;
+
+ *states = ia2_state_;
+
+ return S_OK;
+}
+
+STDMETHODIMP BrowserAccessibilityWin::get_uniqueID(LONG* unique_id) {
+ if (!instance_active_)
+ return E_FAIL;
+
+ if (!unique_id)
+ return E_INVALIDARG;
+
+ *unique_id = child_id_;
+ return S_OK;
+}
+
+STDMETHODIMP BrowserAccessibilityWin::get_windowHandle(HWND* window_handle) {
+ if (!instance_active_)
+ return E_FAIL;
+
+ if (!window_handle)
+ return E_INVALIDARG;
+
+ *window_handle = manager_->GetParentView();
+ return S_OK;
+}
+
+STDMETHODIMP BrowserAccessibilityWin::get_indexInParent(LONG* index_in_parent) {
+ if (!instance_active_)
+ return E_FAIL;
+
+ if (!index_in_parent)
+ return E_INVALIDARG;
+
+ *index_in_parent = index_in_parent_;
+ return S_OK;
+}
+
+//
+// IAccessibleImage methods.
+//
+
+STDMETHODIMP BrowserAccessibilityWin::get_description(BSTR* desc) {
+ if (!instance_active_)
+ return E_FAIL;
+
+ if (!desc)
+ return E_INVALIDARG;
+
+ return GetAttributeAsBstr(WebAccessibility::ATTR_DESCRIPTION, desc);
+}
+
+STDMETHODIMP BrowserAccessibilityWin::get_imagePosition(
+ enum IA2CoordinateType coordinate_type, LONG* x, LONG* y) {
+ if (!instance_active_)
+ return E_FAIL;
+
+ if (!x || !y)
+ return E_INVALIDARG;
+
+ if (coordinate_type == IA2_COORDTYPE_SCREEN_RELATIVE) {
+ HWND parent_hwnd = manager_->GetParentView();
+ POINT top_left = {0, 0};
+ ::ClientToScreen(parent_hwnd, &top_left);
+ *x = location_.x() + top_left.x;
+ *y = location_.y() + top_left.y;
+ } else if (coordinate_type == IA2_COORDTYPE_PARENT_RELATIVE) {
+ *x = location_.x();
+ *y = location_.y();
+ if (parent_) {
+ *x -= parent_->location().x();
+ *y -= parent_->location().y();
+ }
+ } else {
+ return E_INVALIDARG;
+ }
+
+ return S_OK;
+}
+
+STDMETHODIMP BrowserAccessibilityWin::get_imageSize(LONG* height, LONG* width) {
+ if (!instance_active_)
+ return E_FAIL;
+
+ if (!height || !width)
+ return E_INVALIDARG;
+
+ *height = location_.height();
+ *width = location_.width();
+ return S_OK;
+}
+
+//
+// IAccessibleText methods.
+//
+
+STDMETHODIMP BrowserAccessibilityWin::get_nCharacters(LONG* n_characters) {
+ if (!instance_active_)
+ return E_FAIL;
+
+ if (!n_characters)
+ return E_INVALIDARG;
+
+ if (role_ == WebAccessibility::ROLE_TEXT_FIELD ||
+ role_ == WebAccessibility::ROLE_TEXTAREA) {
+ *n_characters = value_.length();
+ } else {
+ *n_characters = name_.length();
+ }
+
+ return S_OK;
+}
+
+STDMETHODIMP BrowserAccessibilityWin::get_caretOffset(LONG* offset) {
+ if (!instance_active_)
+ return E_FAIL;
+
+ if (!offset)
+ return E_INVALIDARG;
+
+ if (role_ == WebAccessibility::ROLE_TEXT_FIELD ||
+ role_ == WebAccessibility::ROLE_TEXTAREA) {
+ int sel_start = 0;
+ if (GetAttributeAsInt(WebAccessibility::ATTR_TEXT_SEL_START, &sel_start)) {
+ *offset = sel_start;
+ } else {
+ *offset = 0;
+ }
+ } else {
+ *offset = 0;
+ }
+
+ return S_OK;
+}
+
+STDMETHODIMP BrowserAccessibilityWin::get_nSelections(LONG* n_selections) {
+ if (!instance_active_)
+ return E_FAIL;
+
+ if (!n_selections)
+ return E_INVALIDARG;
+
+ if (role_ == WebAccessibility::ROLE_TEXT_FIELD ||
+ role_ == WebAccessibility::ROLE_TEXTAREA) {
+ int sel_start = 0;
+ int sel_end = 0;
+ if (GetAttributeAsInt(WebAccessibility::ATTR_TEXT_SEL_START, &sel_start) &&
+ GetAttributeAsInt(WebAccessibility::ATTR_TEXT_SEL_END, &sel_end) &&
+ sel_start != sel_end) {
+ *n_selections = 1;
+ } else {
+ *n_selections = 0;
+ }
+ } else {
+ *n_selections = 0;
+ }
+
+ return S_OK;
+}
+
+STDMETHODIMP BrowserAccessibilityWin::get_selection(LONG selection_index,
+ LONG* start_offset,
+ LONG* end_offset) {
+ if (!instance_active_)
+ return E_FAIL;
+
+ if (!start_offset || !end_offset || selection_index != 0)
+ return E_INVALIDARG;
+
+ if (role_ == WebAccessibility::ROLE_TEXT_FIELD ||
+ role_ == WebAccessibility::ROLE_TEXTAREA) {
+ int sel_start = 0;
+ int sel_end = 0;
+ if (GetAttributeAsInt(WebAccessibility::ATTR_TEXT_SEL_START, &sel_start) &&
+ GetAttributeAsInt(WebAccessibility::ATTR_TEXT_SEL_END, &sel_end)) {
+ *start_offset = sel_start;
+ *end_offset = sel_end;
+ } else {
+ *start_offset = 0;
+ *end_offset = 0;
+ }
+ } else {
+ *start_offset = 0;
+ *end_offset = 0;
+ }
+
+ return S_OK;
+}
+
+STDMETHODIMP BrowserAccessibilityWin::get_text(
+ LONG start_offset, LONG end_offset, BSTR* text) {
+ if (!instance_active_)
+ return E_FAIL;
+
+ if (!text)
+ return E_INVALIDARG;
+
+ const string16& text_str = TextForIAccessibleText();
+
+ // Handle special text offsets.
+ HandleSpecialTextOffset(text_str, &start_offset);
+ HandleSpecialTextOffset(text_str, &end_offset);
+
+ // The spec allows the arguments to be reversed.
+ if (start_offset > end_offset) {
+ LONG tmp = start_offset;
+ start_offset = end_offset;
+ end_offset = tmp;
+ }
+
+ // The spec does not allow the start or end offsets to be out or range;
+ // we must return an error if so.
+ LONG len = text_str.length();
+ if (start_offset < 0)
+ return E_INVALIDARG;
+ if (end_offset > len)
+ return E_INVALIDARG;
+
+ string16 substr = text_str.substr(start_offset, end_offset - start_offset);
+ if (substr.empty())
+ return S_FALSE;
+
+ *text = SysAllocString(substr.c_str());
+ DCHECK(*text);
+ return S_OK;
+}
+
+STDMETHODIMP BrowserAccessibilityWin::get_textAtOffset(
+ LONG offset,
+ enum IA2TextBoundaryType boundary_type,
+ LONG* start_offset, LONG* end_offset,
+ BSTR* text) {
+ if (!instance_active_)
+ return E_FAIL;
+
+ if (!start_offset || !end_offset || !text)
+ return E_INVALIDARG;
+
+ // The IAccessible2 spec says we don't have to implement the "sentence"
+ // boundary type, we can just let the screenreader handle it.
+ if (boundary_type == IA2_TEXT_BOUNDARY_SENTENCE) {
+ *start_offset = 0;
+ *end_offset = 0;
+ *text = NULL;
+ return S_FALSE;
+ }
+
+ const string16& text_str = TextForIAccessibleText();
+
+ *start_offset = FindBoundary(text_str, boundary_type, offset, -1);
+ *end_offset = FindBoundary(text_str, boundary_type, offset, 1);
+ return get_text(*start_offset, *end_offset, text);
+}
+
+STDMETHODIMP BrowserAccessibilityWin::get_textBeforeOffset(
+ LONG offset,
+ enum IA2TextBoundaryType boundary_type,
+ LONG* start_offset, LONG* end_offset,
+ BSTR* text) {
+ if (!instance_active_)
+ return E_FAIL;
+
+ if (!start_offset || !end_offset || !text)
+ return E_INVALIDARG;
+
+ // The IAccessible2 spec says we don't have to implement the "sentence"
+ // boundary type, we can just let the screenreader handle it.
+ if (boundary_type == IA2_TEXT_BOUNDARY_SENTENCE) {
+ *start_offset = 0;
+ *end_offset = 0;
+ *text = NULL;
+ return S_FALSE;
+ }
+
+ const string16& text_str = TextForIAccessibleText();
+
+ *start_offset = FindBoundary(text_str, boundary_type, offset, -1);
+ *end_offset = offset;
+ return get_text(*start_offset, *end_offset, text);
+}
+
+STDMETHODIMP BrowserAccessibilityWin::get_textAfterOffset(
+ LONG offset,
+ enum IA2TextBoundaryType boundary_type,
+ LONG* start_offset, LONG* end_offset,
+ BSTR* text) {
+ if (!instance_active_)
+ return E_FAIL;
+
+ if (!start_offset || !end_offset || !text)
+ return E_INVALIDARG;
+
+ // The IAccessible2 spec says we don't have to implement the "sentence"
+ // boundary type, we can just let the screenreader handle it.
+ if (boundary_type == IA2_TEXT_BOUNDARY_SENTENCE) {
+ *start_offset = 0;
+ *end_offset = 0;
+ *text = NULL;
+ return S_FALSE;
+ }
+
+ const string16& text_str = TextForIAccessibleText();
+
+ *start_offset = offset;
+ *end_offset = FindBoundary(text_str, boundary_type, offset, 1);
+ return get_text(*start_offset, *end_offset, text);
+}
+
+//
+// ISimpleDOMDocument methods.
+//
+
+STDMETHODIMP BrowserAccessibilityWin::get_URL(BSTR* url) {
+ if (!instance_active_)
+ return E_FAIL;
+
+ if (!url)
+ return E_INVALIDARG;
+
+ return GetAttributeAsBstr(WebAccessibility::ATTR_DOC_URL, url);
+}
+
+STDMETHODIMP BrowserAccessibilityWin::get_title(BSTR* title) {
+ if (!instance_active_)
+ return E_FAIL;
+
+ if (!title)
+ return E_INVALIDARG;
+
+ return GetAttributeAsBstr(WebAccessibility::ATTR_DOC_TITLE, title);
+}
+
+STDMETHODIMP BrowserAccessibilityWin::get_mimeType(BSTR* mime_type) {
+ if (!instance_active_)
+ return E_FAIL;
+
+ if (!mime_type)
+ return E_INVALIDARG;
+
+ return GetAttributeAsBstr(WebAccessibility::ATTR_DOC_MIMETYPE, mime_type);
+}
+
+STDMETHODIMP BrowserAccessibilityWin::get_docType(BSTR* doc_type) {
+ if (!instance_active_)
+ return E_FAIL;
+
+ if (!doc_type)
+ return E_INVALIDARG;
+
+ return GetAttributeAsBstr(WebAccessibility::ATTR_DOC_DOCTYPE, doc_type);
+}
+
+//
+// ISimpleDOMNode methods.
+//
+
+STDMETHODIMP BrowserAccessibilityWin::get_nodeInfo(
+ BSTR* node_name,
+ short* name_space_id,
+ BSTR* node_value,
+ unsigned int* num_children,
+ unsigned int* unique_id,
+ unsigned short* node_type) {
+ if (!instance_active_)
+ return E_FAIL;
+
+ if (!node_name || !name_space_id || !node_value || !num_children ||
+ !unique_id || !node_type) {
+ return E_INVALIDARG;
+ }
+
+ string16 tag;
+ if (GetAttribute(WebAccessibility::ATTR_HTML_TAG, &tag))
+ *node_name = SysAllocString(tag.c_str());
+ else
+ *node_name = NULL;
+
+ *name_space_id = 0;
+ *node_value = SysAllocString(value_.c_str());
+ *num_children = children_.size();
+ *unique_id = child_id_;
+
+ if (ia_role_ == ROLE_SYSTEM_DOCUMENT) {
+ *node_type = NODETYPE_DOCUMENT;
+ } else if (ia_role_ == ROLE_SYSTEM_TEXT &&
+ ((ia2_state_ & IA2_STATE_EDITABLE) == 0)) {
+ *node_type = NODETYPE_TEXT;
+ } else {
+ *node_type = NODETYPE_ELEMENT;
+ }
+
+ return S_OK;
+}
+
+STDMETHODIMP BrowserAccessibilityWin::get_attributes(
+ unsigned short max_attribs,
+ BSTR* attrib_names,
+ short* name_space_id,
+ BSTR* attrib_values,
+ unsigned short* num_attribs) {
+ if (!instance_active_)
+ return E_FAIL;
+
+ if (!attrib_names || !name_space_id || !attrib_values || !num_attribs)
+ return E_INVALIDARG;
+
+ *num_attribs = max_attribs;
+ if (*num_attribs > html_attributes_.size())
+ *num_attribs = html_attributes_.size();
+
+ for (unsigned short i = 0; i < *num_attribs; ++i) {
+ attrib_names[i] = SysAllocString(html_attributes_[i].first.c_str());
+ name_space_id[i] = 0;
+ attrib_values[i] = SysAllocString(html_attributes_[i].second.c_str());
+ }
+ return S_OK;
+}
+
+STDMETHODIMP BrowserAccessibilityWin::get_attributesForNames(
+ unsigned short num_attribs,
+ BSTR* attrib_names,
+ short* name_space_id,
+ BSTR* attrib_values) {
+ if (!instance_active_)
+ return E_FAIL;
+
+ if (!attrib_names || !name_space_id || !attrib_values)
+ return E_INVALIDARG;
+
+ for (unsigned short i = 0; i < num_attribs; ++i) {
+ name_space_id[i] = 0;
+ bool found = false;
+ string16 name = (LPCWSTR)attrib_names[i];
+ for (unsigned int j = 0; j < html_attributes_.size(); ++j) {
+ if (html_attributes_[j].first == name) {
+ attrib_values[i] = SysAllocString(html_attributes_[j].second.c_str());
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ attrib_values[i] = NULL;
+ }
+ }
+ return S_OK;
+}
+
+STDMETHODIMP BrowserAccessibilityWin::get_computedStyle(
+ unsigned short max_style_properties,
+ boolean use_alternate_view,
+ BSTR *style_properties,
+ BSTR *style_values,
+ unsigned short *num_style_properties) {
+ if (!instance_active_)
+ return E_FAIL;
+
+ if (!style_properties || !style_values)
+ return E_INVALIDARG;
+
+ // We only cache a single style property for now: DISPLAY
+
+ if (max_style_properties == 0 ||
+ !HasAttribute(WebAccessibility::ATTR_DISPLAY)) {
+ *num_style_properties = 0;
+ return S_OK;
+ }
+
+ string16 display;
+ GetAttribute(WebAccessibility::ATTR_DISPLAY, &display);
+ *num_style_properties = 1;
+ style_properties[0] = SysAllocString(L"display");
+ style_values[0] = SysAllocString(display.c_str());
+
+ return S_OK;
+}
+
+STDMETHODIMP BrowserAccessibilityWin::get_computedStyleForProperties(
+ unsigned short num_style_properties,
+ boolean use_alternate_view,
+ BSTR* style_properties,
+ BSTR* style_values) {
+ if (!instance_active_)
+ return E_FAIL;
+
+ if (!style_properties || !style_values)
+ return E_INVALIDARG;
+
+ // We only cache a single style property for now: DISPLAY
+
+ for (unsigned short i = 0; i < num_style_properties; i++) {
+ string16 name = (LPCWSTR)style_properties[i];
+ StringToLowerASCII(&name);
+ if (name == L"display") {
+ string16 display;
+ GetAttribute(WebAccessibility::ATTR_DISPLAY, &display);
+ style_values[i] = SysAllocString(display.c_str());
+ } else {
+ style_values[i] = NULL;
+ }
+ }
+
+ return S_OK;
+}
+
+STDMETHODIMP BrowserAccessibilityWin::scrollTo(boolean placeTopLeft) {
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP BrowserAccessibilityWin::get_parentNode(ISimpleDOMNode** node) {
+ if (!instance_active_)
+ return E_FAIL;
+
+ if (!node)
+ return E_INVALIDARG;
+
+ *node = parent_->toBrowserAccessibilityWin()->NewReference();
+ return S_OK;
+}
+
+STDMETHODIMP BrowserAccessibilityWin::get_firstChild(ISimpleDOMNode** node) {
+ if (!instance_active_)
+ return E_FAIL;
+
+ if (!node)
+ return E_INVALIDARG;
+
+ if (children_.size()) {
+ *node = children_[0]->toBrowserAccessibilityWin()->NewReference();
+ return S_OK;
+ } else {
+ *node = NULL;
+ return S_FALSE;
+ }
+}
+
+STDMETHODIMP BrowserAccessibilityWin::get_lastChild(ISimpleDOMNode** node) {
+ if (!instance_active_)
+ return E_FAIL;
+
+ if (!node)
+ return E_INVALIDARG;
+
+ if (children_.size()) {
+ *node = children_[children_.size() - 1]->toBrowserAccessibilityWin()->
+ NewReference();
+ return S_OK;
+ } else {
+ *node = NULL;
+ return S_FALSE;
+ }
+}
+
+STDMETHODIMP BrowserAccessibilityWin::get_previousSibling(
+ ISimpleDOMNode** node) {
+ if (!instance_active_)
+ return E_FAIL;
+
+ if (!node)
+ return E_INVALIDARG;
+
+ if (parent_ && index_in_parent_ > 0) {
+ *node = parent_->children()[index_in_parent_ - 1]->
+ toBrowserAccessibilityWin()->NewReference();
+ return S_OK;
+ } else {
+ *node = NULL;
+ return S_FALSE;
+ }
+}
+
+STDMETHODIMP BrowserAccessibilityWin::get_nextSibling(ISimpleDOMNode** node) {
+ if (!instance_active_)
+ return E_FAIL;
+
+ if (!node)
+ return E_INVALIDARG;
+
+ if (parent_ &&
+ index_in_parent_ >= 0 &&
+ index_in_parent_ < static_cast<int>(parent_->children().size()) - 1) {
+ *node = parent_->children()[index_in_parent_ + 1]->
+ toBrowserAccessibilityWin()->NewReference();
+ return S_OK;
+ } else {
+ *node = NULL;
+ return S_FALSE;
+ }
+}
+
+STDMETHODIMP BrowserAccessibilityWin::get_childAt(
+ unsigned int child_index,
+ ISimpleDOMNode** node) {
+ if (!instance_active_)
+ return E_FAIL;
+
+ if (!node)
+ return E_INVALIDARG;
+
+ if (child_index < children_.size()) {
+ *node = children_[child_index]->toBrowserAccessibilityWin()->NewReference();
+ return S_OK;
+ } else {
+ *node = NULL;
+ return S_FALSE;
+ }
+}
+
+//
+// ISimpleDOMText methods.
+//
+
+STDMETHODIMP BrowserAccessibilityWin::get_domText(BSTR* dom_text) {
+ if (!instance_active_)
+ return E_FAIL;
+
+ if (!dom_text)
+ return E_INVALIDARG;
+
+ if (name_.empty())
+ return S_FALSE;
+
+ *dom_text = SysAllocString(name_.c_str());
+ DCHECK(*dom_text);
+ return S_OK;
+}
+
+//
+// IServiceProvider methods.
+//
+
+STDMETHODIMP BrowserAccessibilityWin::QueryService(
+ REFGUID guidService, REFIID riid, void** object) {
+ if (!instance_active_)
+ return E_FAIL;
+
+ if (guidService == IID_IAccessible ||
+ guidService == IID_IAccessible2 ||
+ guidService == IID_IAccessibleImage ||
+ guidService == IID_IAccessibleText ||
+ guidService == IID_ISimpleDOMDocument ||
+ guidService == IID_ISimpleDOMNode ||
+ guidService == IID_ISimpleDOMText ||
+ guidService == GUID_ISimpleDOM) {
+ return QueryInterface(riid, object);
+ }
+
+ *object = NULL;
+ return E_FAIL;
+}
+
+//
+// CComObjectRootEx methods.
+//
+
+HRESULT WINAPI BrowserAccessibilityWin::InternalQueryInterface(
+ void* this_ptr,
+ const _ATL_INTMAP_ENTRY* entries,
+ REFIID iid,
+ void** object) {
+ if (iid == IID_IAccessibleText) {
+ if (ia_role_ != ROLE_SYSTEM_LINK && ia_role_ != ROLE_SYSTEM_TEXT) {
+ *object = NULL;
+ return E_NOINTERFACE;
+ }
+ } else if (iid == IID_IAccessibleImage) {
+ if (ia_role_ != ROLE_SYSTEM_GRAPHIC) {
+ *object = NULL;
+ return E_NOINTERFACE;
+ }
+ } else if (iid == IID_ISimpleDOMDocument) {
+ if (ia_role_ != ROLE_SYSTEM_DOCUMENT) {
+ *object = NULL;
+ return E_NOINTERFACE;
+ }
+ }
+
+ return CComObjectRootBase::InternalQueryInterface(
+ this_ptr, entries, iid, object);
+}
+
+//
+// Private methods.
+//
+
+// Initialize this object and mark it as active.
+void BrowserAccessibilityWin::Initialize() {
+ BrowserAccessibility::Initialize();
+
+ InitRoleAndState();
+
+ // Expose headings levels to NVDA with the "level" object attribute.
+ if (role_ == WebAccessibility::ROLE_HEADING && role_name_.size() == 2 &&
+ IsAsciiDigit(role_name_[1])) {
+ html_attributes_.push_back(std::make_pair(L"level", role_name_.substr(1)));
+ }
+
+ // Expose the "display" object attribute.
+ string16 display;
+ if (GetAttribute(WebAccessibility::ATTR_DISPLAY, &display))
+ html_attributes_.push_back(std::make_pair(L"display", display));
+
+ // If this is static text, put the text in the name rather than the value.
+ if (role_ == WebAccessibility::ROLE_STATIC_TEXT && name_.empty())
+ name_.swap(value_);
+
+ // If this object doesn't have a name but it does have a description,
+ // use the description as its name - because some screen readers only
+ // announce the name.
+ if (name_.empty() && HasAttribute(WebAccessibility::ATTR_DESCRIPTION))
+ GetAttribute(WebAccessibility::ATTR_DESCRIPTION, &name_);
+
+ // If this doesn't have a value and is linked then set its value to the url
+ // attribute. This allows screen readers to read an empty link's destination.
+ if (value_.empty() && (ia_state_ & STATE_SYSTEM_LINKED) &&
+ HasAttribute(WebAccessibility::ATTR_URL)) {
+ GetAttribute(WebAccessibility::ATTR_URL, &value_);
+ }
+}
+
+void BrowserAccessibilityWin::NativeAddReference() {
+ AddRef();
+}
+
+void BrowserAccessibilityWin::NativeReleaseReference() {
+ Release();
+}
+
+BrowserAccessibilityWin* BrowserAccessibilityWin::NewReference() {
+ AddRef();
+ return this;
+}
+
+BrowserAccessibilityWin* BrowserAccessibilityWin::GetTargetFromChildID(
+ const VARIANT& var_id) {
+ if (var_id.vt != VT_I4)
+ return NULL;
+
+ LONG child_id = var_id.lVal;
+ if (child_id == CHILDID_SELF)
+ return this;
+
+ if (child_id >= 1 && child_id <= static_cast<LONG>(children_.size()))
+ return children_[child_id - 1]->toBrowserAccessibilityWin();
+
+ return manager_->GetFromChildID(child_id)->toBrowserAccessibilityWin();
+}
+
+HRESULT BrowserAccessibilityWin::GetAttributeAsBstr(
+ WebAccessibility::Attribute attribute, BSTR* value_bstr) {
+ string16 str;
+
+ if (!GetAttribute(attribute, &str))
+ return S_FALSE;
+
+ if (str.empty())
+ return S_FALSE;
+
+ *value_bstr = SysAllocString(str.c_str());
+ DCHECK(*value_bstr);
+
+ return S_OK;
+}
+
+string16 BrowserAccessibilityWin::Escape(const string16& str) {
+ return EscapeQueryParamValueUTF8(str, false);
+}
+
+const string16& BrowserAccessibilityWin::TextForIAccessibleText() {
+ if (role_ == WebAccessibility::ROLE_TEXT_FIELD ||
+ role_ == WebAccessibility::ROLE_TEXTAREA) {
+ return value_;
+ } else {
+ return name_;
+ }
+}
+
+void BrowserAccessibilityWin::HandleSpecialTextOffset(
+ const string16& text, LONG* offset) {
+ if (*offset == IA2_TEXT_OFFSET_LENGTH) {
+ *offset = static_cast<LONG>(text.size());
+ } else if (*offset == IA2_TEXT_OFFSET_CARET) {
+ get_caretOffset(offset);
+ }
+}
+
+LONG BrowserAccessibilityWin::FindBoundary(
+ const string16& text,
+ IA2TextBoundaryType boundary,
+ LONG start_offset,
+ LONG direction) {
+ LONG text_size = static_cast<LONG>(text.size());
+ DCHECK((start_offset >= 0 && start_offset <= text_size) ||
+ start_offset == IA2_TEXT_OFFSET_LENGTH ||
+ start_offset == IA2_TEXT_OFFSET_CARET);
+ DCHECK(direction == 1 || direction == -1);
+
+ HandleSpecialTextOffset(text, &start_offset);
+
+ if (boundary == IA2_TEXT_BOUNDARY_CHAR) {
+ if (direction == 1 && start_offset < text_size)
+ return start_offset + 1;
+ else
+ return start_offset;
+ } else if (boundary == IA2_TEXT_BOUNDARY_LINE) {
+ if (direction == 1) {
+ for (int j = 0; j < static_cast<int>(line_breaks_.size()); j++) {
+ if (line_breaks_[j] > start_offset)
+ return line_breaks_[j];
+ }
+ return text_size;
+ } else {
+ for (int j = static_cast<int>(line_breaks_.size()) - 1; j >= 0; j--) {
+ if (line_breaks_[j] <= start_offset)
+ return line_breaks_[j];
+ }
+ return 0;
+ }
+ }
+
+ LONG result = start_offset;
+ for (;;) {
+ LONG pos;
+ if (direction == 1) {
+ if (result >= text_size)
+ return text_size;
+ pos = result;
+ } else {
+ if (result <= 0)
+ return 0;
+ pos = result - 1;
+ }
+
+ switch (boundary) {
+ case IA2_TEXT_BOUNDARY_CHAR:
+ case IA2_TEXT_BOUNDARY_LINE:
+ NOTREACHED(); // These are handled above.
+ break;
+ case IA2_TEXT_BOUNDARY_WORD:
+ if (IsWhitespace(text[pos]))
+ return result;
+ break;
+ case IA2_TEXT_BOUNDARY_PARAGRAPH:
+ if (text[pos] == '\n')
+ return result;
+ case IA2_TEXT_BOUNDARY_SENTENCE:
+ // Note that we don't actually have to implement sentence support;
+ // currently IAccessibleText functions return S_FALSE so that
+ // screenreaders will handle it on their own.
+ if ((text[pos] == '.' || text[pos] == '!' || text[pos] == '?') &&
+ (pos == text_size - 1 || IsWhitespace(text[pos + 1]))) {
+ return result;
+ }
+ case IA2_TEXT_BOUNDARY_ALL:
+ default:
+ break;
+ }
+
+ if (direction > 0) {
+ result++;
+ } else if (direction < 0) {
+ result--;
+ } else {
+ NOTREACHED();
+ return result;
+ }
+ }
+}
+
+void BrowserAccessibilityWin::InitRoleAndState() {
+ ia_state_ = 0;
+ ia2_state_ = IA2_STATE_OPAQUE;
+
+ if ((state_ >> WebAccessibility::STATE_CHECKED) & 1)
+ ia_state_ |= STATE_SYSTEM_CHECKED;
+ if ((state_ >> WebAccessibility::STATE_COLLAPSED) & 1)
+ ia_state_|= STATE_SYSTEM_COLLAPSED;
+ if ((state_ >> WebAccessibility::STATE_EXPANDED) & 1)
+ ia_state_|= STATE_SYSTEM_EXPANDED;
+ if ((state_ >> WebAccessibility::STATE_FOCUSABLE) & 1)
+ ia_state_|= STATE_SYSTEM_FOCUSABLE;
+ if ((state_ >> WebAccessibility::STATE_HASPOPUP) & 1)
+ ia_state_|= STATE_SYSTEM_HASPOPUP;
+ if ((state_ >> WebAccessibility::STATE_HOTTRACKED) & 1)
+ ia_state_|= STATE_SYSTEM_HOTTRACKED;
+ if ((state_ >> WebAccessibility::STATE_INDETERMINATE) & 1)
+ ia_state_|= STATE_SYSTEM_INDETERMINATE;
+ if ((state_ >> WebAccessibility::STATE_INVISIBLE) & 1)
+ ia_state_|= STATE_SYSTEM_INVISIBLE;
+ if ((state_ >> WebAccessibility::STATE_LINKED) & 1)
+ ia_state_|= STATE_SYSTEM_LINKED;
+ if ((state_ >> WebAccessibility::STATE_MULTISELECTABLE) & 1)
+ ia_state_|= STATE_SYSTEM_MULTISELECTABLE;
+ // TODO(ctguil): Support STATE_SYSTEM_EXTSELECTABLE/accSelect.
+ if ((state_ >> WebAccessibility::STATE_OFFSCREEN) & 1)
+ ia_state_|= STATE_SYSTEM_OFFSCREEN;
+ if ((state_ >> WebAccessibility::STATE_PRESSED) & 1)
+ ia_state_|= STATE_SYSTEM_PRESSED;
+ if ((state_ >> WebAccessibility::STATE_PROTECTED) & 1)
+ ia_state_|= STATE_SYSTEM_PROTECTED;
+ if ((state_ >> WebAccessibility::STATE_SELECTABLE) & 1)
+ ia_state_|= STATE_SYSTEM_SELECTABLE;
+ if ((state_ >> WebAccessibility::STATE_SELECTED) & 1)
+ ia_state_|= STATE_SYSTEM_SELECTED;
+ if ((state_ >> WebAccessibility::STATE_READONLY) & 1)
+ ia_state_|= STATE_SYSTEM_READONLY;
+ if ((state_ >> WebAccessibility::STATE_TRAVERSED) & 1)
+ ia_state_|= STATE_SYSTEM_TRAVERSED;
+ if ((state_ >> WebAccessibility::STATE_BUSY) & 1)
+ ia_state_|= STATE_SYSTEM_BUSY;
+ if ((state_ >> WebAccessibility::STATE_UNAVAILABLE) & 1)
+ ia_state_|= STATE_SYSTEM_UNAVAILABLE;
+
+ string16 html_tag;
+ GetAttribute(WebAccessibility::ATTR_HTML_TAG, &html_tag);
+ ia_role_ = 0;
+ ia2_role_ = 0;
+ switch (role_) {
+ case WebAccessibility::ROLE_ALERT:
+ case WebAccessibility::ROLE_ALERT_DIALOG:
+ ia_role_ = ROLE_SYSTEM_ALERT;
+ break;
+ case WebAccessibility::ROLE_APPLICATION:
+ ia_role_ = ROLE_SYSTEM_APPLICATION;
+ break;
+ case WebAccessibility::ROLE_ARTICLE:
+ ia_role_ = ROLE_SYSTEM_GROUPING;
+ ia2_role_ = IA2_ROLE_SECTION;
+ break;
+ case WebAccessibility::ROLE_BUSY_INDICATOR:
+ ia_role_ = ROLE_SYSTEM_ANIMATION;
+ break;
+ case WebAccessibility::ROLE_BUTTON:
+ ia_role_ = ROLE_SYSTEM_PUSHBUTTON;
+ break;
+ case WebAccessibility::ROLE_CELL:
+ ia_role_ = ROLE_SYSTEM_CELL;
+ break;
+ case WebAccessibility::ROLE_CHECKBOX:
+ ia_role_ = ROLE_SYSTEM_CHECKBUTTON;
+ break;
+ case WebAccessibility::ROLE_COLOR_WELL:
+ ia_role_ = ROLE_SYSTEM_CLIENT;
+ ia2_role_ = IA2_ROLE_COLOR_CHOOSER;
+ break;
+ case WebAccessibility::ROLE_COLUMN:
+ ia_role_ = ROLE_SYSTEM_COLUMN;
+ break;
+ case WebAccessibility::ROLE_COLUMN_HEADER:
+ ia_role_ = ROLE_SYSTEM_COLUMNHEADER;
+ break;
+ case WebAccessibility::ROLE_COMBO_BOX:
+ ia_role_ = ROLE_SYSTEM_COMBOBOX;
+ break;
+ case WebAccessibility::ROLE_DEFINITION_LIST_DEFINITION:
+ role_name_ = html_tag;
+ ia2_role_ = IA2_ROLE_PARAGRAPH;
+ break;
+ case WebAccessibility::ROLE_DEFINITION_LIST_TERM:
+ ia_role_ = ROLE_SYSTEM_LISTITEM;
+ break;
+ case WebAccessibility::ROLE_DIALOG:
+ ia_role_ = ROLE_SYSTEM_DIALOG;
+ break;
+ case WebAccessibility::ROLE_DISCLOSURE_TRIANGLE:
+ ia_role_ = ROLE_SYSTEM_OUTLINEBUTTON;
+ break;
+ case WebAccessibility::ROLE_DOCUMENT:
+ case WebAccessibility::ROLE_WEB_AREA:
+ ia_role_ = ROLE_SYSTEM_DOCUMENT;
+ ia_state_|= STATE_SYSTEM_READONLY;
+ ia_state_|= STATE_SYSTEM_FOCUSABLE;
+ break;
+ case WebAccessibility::ROLE_EDITABLE_TEXT:
+ ia_role_ = ROLE_SYSTEM_TEXT;
+ ia2_state_ |= IA2_STATE_SINGLE_LINE;
+ ia2_state_ |= IA2_STATE_EDITABLE;
+ break;
+ case WebAccessibility::ROLE_GRID:
+ ia_role_ = ROLE_SYSTEM_TABLE;
+ break;
+ case WebAccessibility::ROLE_GROUP:
+ if (html_tag == L"li") {
+ ia_role_ = ROLE_SYSTEM_LISTITEM;
+ } else {
+ if (html_tag.empty())
+ role_name_ = L"div";
+ else
+ role_name_ = html_tag;
+ ia2_role_ = IA2_ROLE_SECTION;
+ }
+ break;
+ case WebAccessibility::ROLE_GROW_AREA:
+ ia_role_ = ROLE_SYSTEM_GRIP;
+ break;
+ case WebAccessibility::ROLE_HEADING:
+ role_name_ = html_tag;
+ ia2_role_ = IA2_ROLE_HEADING;
+ break;
+ case WebAccessibility::ROLE_IMAGE:
+ ia_role_ = ROLE_SYSTEM_GRAPHIC;
+ break;
+ case WebAccessibility::ROLE_IMAGE_MAP:
+ role_name_ = html_tag;
+ ia2_role_ = IA2_ROLE_IMAGE_MAP;
+ break;
+ case WebAccessibility::ROLE_IMAGE_MAP_LINK:
+ ia_role_ = ROLE_SYSTEM_LINK;
+ ia_state_|= STATE_SYSTEM_LINKED;
+ break;
+ case WebAccessibility::ROLE_LANDMARK_APPLICATION:
+ case WebAccessibility::ROLE_LANDMARK_BANNER:
+ case WebAccessibility::ROLE_LANDMARK_COMPLEMENTARY:
+ case WebAccessibility::ROLE_LANDMARK_CONTENTINFO:
+ case WebAccessibility::ROLE_LANDMARK_MAIN:
+ case WebAccessibility::ROLE_LANDMARK_NAVIGATION:
+ case WebAccessibility::ROLE_LANDMARK_SEARCH:
+ ia_role_ = ROLE_SYSTEM_GROUPING;
+ ia2_role_ = IA2_ROLE_SECTION;
+ break;
+ case WebAccessibility::ROLE_LINK:
+ case WebAccessibility::ROLE_WEBCORE_LINK:
+ ia_role_ = ROLE_SYSTEM_LINK;
+ ia_state_|= STATE_SYSTEM_LINKED;
+ break;
+ case WebAccessibility::ROLE_LIST:
+ ia_role_ = ROLE_SYSTEM_LIST;
+ break;
+ case WebAccessibility::ROLE_LISTBOX:
+ ia_role_ = ROLE_SYSTEM_LIST;
+ break;
+ case WebAccessibility::ROLE_LISTBOX_OPTION:
+ case WebAccessibility::ROLE_LIST_ITEM:
+ case WebAccessibility::ROLE_LIST_MARKER:
+ ia_role_ = ROLE_SYSTEM_LISTITEM;
+ break;
+ case WebAccessibility::ROLE_MATH:
+ ia_role_ = ROLE_SYSTEM_EQUATION;
+ break;
+ case WebAccessibility::ROLE_MENU:
+ case WebAccessibility::ROLE_MENU_BUTTON:
+ ia_role_ = ROLE_SYSTEM_MENUPOPUP;
+ break;
+ case WebAccessibility::ROLE_MENU_BAR:
+ ia_role_ = ROLE_SYSTEM_MENUBAR;
+ break;
+ case WebAccessibility::ROLE_MENU_ITEM:
+ case WebAccessibility::ROLE_MENU_LIST_OPTION:
+ ia_role_ = ROLE_SYSTEM_MENUITEM;
+ break;
+ case WebAccessibility::ROLE_MENU_LIST_POPUP:
+ ia_role_ = ROLE_SYSTEM_MENUPOPUP;
+ break;
+ case WebAccessibility::ROLE_NOTE:
+ ia_role_ = ROLE_SYSTEM_GROUPING;
+ ia2_role_ = IA2_ROLE_NOTE;
+ break;
+ case WebAccessibility::ROLE_OUTLINE:
+ ia_role_ = ROLE_SYSTEM_OUTLINE;
+ break;
+ case WebAccessibility::ROLE_POPUP_BUTTON:
+ ia_role_ = ROLE_SYSTEM_COMBOBOX;
+ break;
+ case WebAccessibility::ROLE_PROGRESS_INDICATOR:
+ ia_role_ = ROLE_SYSTEM_PROGRESSBAR;
+ break;
+ case WebAccessibility::ROLE_RADIO_BUTTON:
+ ia_role_ = ROLE_SYSTEM_RADIOBUTTON;
+ break;
+ case WebAccessibility::ROLE_RADIO_GROUP:
+ ia_role_ = ROLE_SYSTEM_GROUPING;
+ ia2_role_ = IA2_ROLE_SECTION;
+ break;
+ case WebAccessibility::ROLE_REGION:
+ ia_role_ = ROLE_SYSTEM_GROUPING;
+ ia2_role_ = IA2_ROLE_SECTION;
+ break;
+ case WebAccessibility::ROLE_ROW:
+ ia_role_ = ROLE_SYSTEM_ROW;
+ break;
+ case WebAccessibility::ROLE_ROW_HEADER:
+ ia_role_ = ROLE_SYSTEM_ROWHEADER;
+ break;
+ case WebAccessibility::ROLE_RULER:
+ ia_role_ = ROLE_SYSTEM_CLIENT;
+ ia2_role_ = IA2_ROLE_RULER;
+ break;
+ case WebAccessibility::ROLE_SCROLLAREA:
+ ia_role_ = ROLE_SYSTEM_CLIENT;
+ ia2_role_ = IA2_ROLE_SCROLL_PANE;
+ break;
+ case WebAccessibility::ROLE_SCROLLBAR:
+ ia_role_ = ROLE_SYSTEM_SCROLLBAR;
+ break;
+ case WebAccessibility::ROLE_SLIDER:
+ ia_role_ = ROLE_SYSTEM_SLIDER;
+ break;
+ case WebAccessibility::ROLE_SPLIT_GROUP:
+ ia_role_ = ROLE_SYSTEM_CLIENT;
+ ia2_role_ = IA2_ROLE_SPLIT_PANE;
+ break;
+ case WebAccessibility::ROLE_ANNOTATION:
+ case WebAccessibility::ROLE_STATIC_TEXT:
+ ia_role_ = ROLE_SYSTEM_TEXT;
+ break;
+ case WebAccessibility::ROLE_STATUS:
+ ia_role_ = ROLE_SYSTEM_STATUSBAR;
+ break;
+ case WebAccessibility::ROLE_SPLITTER:
+ ia_role_ = ROLE_SYSTEM_SEPARATOR;
+ break;
+ case WebAccessibility::ROLE_TAB:
+ ia_role_ = ROLE_SYSTEM_PAGETAB;
+ break;
+ case WebAccessibility::ROLE_TABLE:
+ ia_role_ = ROLE_SYSTEM_TABLE;
+ break;
+ case WebAccessibility::ROLE_TABLE_HEADER_CONTAINER:
+ ia_role_ = ROLE_SYSTEM_GROUPING;
+ ia2_role_ = IA2_ROLE_SECTION;
+ break;
+ case WebAccessibility::ROLE_TAB_GROUP:
+ case WebAccessibility::ROLE_TAB_LIST:
+ case WebAccessibility::ROLE_TAB_PANEL:
+ ia_role_ = ROLE_SYSTEM_PAGETABLIST;
+ break;
+ case WebAccessibility::ROLE_TEXTAREA:
+ ia_role_ = ROLE_SYSTEM_TEXT;
+ ia2_state_ |= IA2_STATE_MULTI_LINE;
+ ia2_state_ |= IA2_STATE_EDITABLE;
+ ia2_state_ |= IA2_STATE_SELECTABLE_TEXT;
+ break;
+ case WebAccessibility::ROLE_TEXT_FIELD:
+ ia_role_ = ROLE_SYSTEM_TEXT;
+ ia2_state_ |= IA2_STATE_SINGLE_LINE;
+ ia2_state_ |= IA2_STATE_EDITABLE;
+ ia2_state_ |= IA2_STATE_SELECTABLE_TEXT;
+ break;
+ case WebAccessibility::ROLE_TIMER:
+ ia_role_ = ROLE_SYSTEM_CLOCK;
+ break;
+ case WebAccessibility::ROLE_TOOLBAR:
+ ia_role_ = ROLE_SYSTEM_TOOLBAR;
+ break;
+ case WebAccessibility::ROLE_TOOLTIP:
+ ia_role_ = ROLE_SYSTEM_TOOLTIP;
+ break;
+ case WebAccessibility::ROLE_TREE:
+ ia_role_ = ROLE_SYSTEM_OUTLINE;
+ break;
+ case WebAccessibility::ROLE_TREE_GRID:
+ ia_role_ = ROLE_SYSTEM_OUTLINE;
+ break;
+ case WebAccessibility::ROLE_TREE_ITEM:
+ ia_role_ = ROLE_SYSTEM_OUTLINEITEM;
+ break;
+ case WebAccessibility::ROLE_WINDOW:
+ ia_role_ = ROLE_SYSTEM_WINDOW;
+ break;
+
+ // TODO(dmazzoni): figure out the proper MSAA role for all of these.
+ case WebAccessibility::ROLE_BROWSER:
+ case WebAccessibility::ROLE_DIRECTORY:
+ case WebAccessibility::ROLE_DRAWER:
+ case WebAccessibility::ROLE_HELP_TAG:
+ case WebAccessibility::ROLE_IGNORED:
+ case WebAccessibility::ROLE_INCREMENTOR:
+ case WebAccessibility::ROLE_LOG:
+ case WebAccessibility::ROLE_MARQUEE:
+ case WebAccessibility::ROLE_MATTE:
+ case WebAccessibility::ROLE_RULER_MARKER:
+ case WebAccessibility::ROLE_SHEET:
+ case WebAccessibility::ROLE_SLIDER_THUMB:
+ case WebAccessibility::ROLE_SYSTEM_WIDE:
+ case WebAccessibility::ROLE_VALUE_INDICATOR:
+ default:
+ ia_role_ = ROLE_SYSTEM_CLIENT;
+ break;
+ }
+
+ // The role should always be set.
+ DCHECK(!role_name_.empty() || ia_role_);
+
+ // If we didn't explicitly set the IAccessible2 role, make it the same
+ // as the MSAA role.
+ if (!ia2_role_)
+ ia2_role_ = ia_role_;
+}
diff --git a/content/browser/accessibility/browser_accessibility_win.h b/content/browser/accessibility/browser_accessibility_win.h
new file mode 100644
index 0000000..fb8e014
--- /dev/null
+++ b/content/browser/accessibility/browser_accessibility_win.h
@@ -0,0 +1,499 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_ACCESSIBILITY_BROWSER_ACCESSIBILITY_WIN_H_
+#define CONTENT_BROWSER_ACCESSIBILITY_BROWSER_ACCESSIBILITY_WIN_H_
+#pragma once
+
+#include <atlbase.h>
+#include <atlcom.h>
+#include <oleacc.h>
+
+#include <vector>
+
+#include "content/browser/accessibility/browser_accessibility.h"
+#include "ia2_api_all.h" // Generated
+#include "ISimpleDOMDocument.h" // Generated
+#include "ISimpleDOMNode.h" // Generated
+#include "ISimpleDOMText.h" // Generated
+#include "webkit/glue/webaccessibility.h"
+
+class BrowserAccessibilityManagerWin;
+
+using webkit_glue::WebAccessibility;
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// BrowserAccessibilityWin
+//
+// Class implementing the windows accessible interface for the Browser-Renderer
+// communication of accessibility information, providing accessibility
+// to be used by screen readers and other assistive technology (AT).
+//
+////////////////////////////////////////////////////////////////////////////////
+class BrowserAccessibilityWin
+ : public BrowserAccessibility,
+ public CComObjectRootEx<CComMultiThreadModel>,
+ public IDispatchImpl<IAccessible2, &IID_IAccessible2,
+ &LIBID_IAccessible2Lib>,
+ public IAccessibleImage,
+ public IAccessibleText,
+ public IServiceProvider,
+ public ISimpleDOMDocument,
+ public ISimpleDOMNode,
+ public ISimpleDOMText {
+ public:
+ BEGIN_COM_MAP(BrowserAccessibilityWin)
+ COM_INTERFACE_ENTRY2(IDispatch, IAccessible2)
+ COM_INTERFACE_ENTRY2(IAccessible, IAccessible2)
+ COM_INTERFACE_ENTRY(IAccessible2)
+ COM_INTERFACE_ENTRY(IAccessibleImage)
+ COM_INTERFACE_ENTRY(IAccessibleText)
+ COM_INTERFACE_ENTRY(IServiceProvider)
+ COM_INTERFACE_ENTRY(ISimpleDOMDocument)
+ COM_INTERFACE_ENTRY(ISimpleDOMNode)
+ COM_INTERFACE_ENTRY(ISimpleDOMText)
+ END_COM_MAP()
+
+ BrowserAccessibilityWin();
+
+ virtual ~BrowserAccessibilityWin();
+
+ //
+ // BrowserAccessibility methods.
+ //
+ virtual void Initialize();
+ virtual void NativeAddReference();
+ virtual void NativeReleaseReference();
+
+ //
+ // IAccessible methods.
+ //
+
+ // Performs the default action on a given object.
+ STDMETHODIMP accDoDefaultAction(VARIANT var_id);
+
+ // Retrieves the child element or child object at a given point on the screen.
+ STDMETHODIMP accHitTest(LONG x_left, LONG y_top, VARIANT* child);
+
+ // Retrieves the specified object's current screen location.
+ STDMETHODIMP accLocation(LONG* x_left,
+ LONG* y_top,
+ LONG* width,
+ LONG* height,
+ VARIANT var_id);
+
+ // Traverses to another UI element and retrieves the object.
+ STDMETHODIMP accNavigate(LONG nav_dir, VARIANT start, VARIANT* end);
+
+ // Retrieves an IDispatch interface pointer for the specified child.
+ STDMETHODIMP get_accChild(VARIANT var_child, IDispatch** disp_child);
+
+ // Retrieves the number of accessible children.
+ STDMETHODIMP get_accChildCount(LONG* child_count);
+
+ // Retrieves a string that describes the object's default action.
+ STDMETHODIMP get_accDefaultAction(VARIANT var_id, BSTR* default_action);
+
+ // Retrieves the object's description.
+ STDMETHODIMP get_accDescription(VARIANT var_id, BSTR* desc);
+
+ // Retrieves the object that has the keyboard focus.
+ STDMETHODIMP get_accFocus(VARIANT* focus_child);
+
+ // Retrieves the help information associated with the object.
+ STDMETHODIMP get_accHelp(VARIANT var_id, BSTR* help);
+
+ // Retrieves the specified object's shortcut.
+ STDMETHODIMP get_accKeyboardShortcut(VARIANT var_id, BSTR* access_key);
+
+ // Retrieves the name of the specified object.
+ STDMETHODIMP get_accName(VARIANT var_id, BSTR* name);
+
+ // Retrieves the IDispatch interface of the object's parent.
+ STDMETHODIMP get_accParent(IDispatch** disp_parent);
+
+ // Retrieves information describing the role of the specified object.
+ STDMETHODIMP get_accRole(VARIANT var_id, VARIANT* role);
+
+ // Retrieves the current state of the specified object.
+ STDMETHODIMP get_accState(VARIANT var_id, VARIANT* state);
+
+ // Returns the value associated with the object.
+ STDMETHODIMP get_accValue(VARIANT var_id, BSTR* value);
+
+ // Make an object take focus or extend the selection.
+ STDMETHODIMP accSelect(LONG flags_sel, VARIANT var_id);
+
+ STDMETHODIMP get_accHelpTopic(BSTR* help_file,
+ VARIANT var_id,
+ LONG* topic_id);
+
+ STDMETHODIMP get_accSelection(VARIANT* selected);
+
+ // Deprecated methods, not implemented.
+ STDMETHODIMP put_accName(VARIANT var_id, BSTR put_name) {
+ return E_NOTIMPL;
+ }
+ STDMETHODIMP put_accValue(VARIANT var_id, BSTR put_val) {
+ return E_NOTIMPL;
+ }
+
+ //
+ // IAccessible2 methods.
+ //
+
+ // Returns role from a longer list of possible roles.
+ STDMETHODIMP role(LONG* role);
+
+ // Returns the state bitmask from a larger set of possible states.
+ STDMETHODIMP get_states(AccessibleStates* states);
+
+ // Returns the attributes specific to this IAccessible2 object,
+ // such as a cell's formula.
+ STDMETHODIMP get_attributes(BSTR* attributes);
+
+ // Get the unique ID of this object so that the client knows if it's
+ // been encountered previously.
+ STDMETHODIMP get_uniqueID(LONG* unique_id);
+
+ // Get the window handle of the enclosing window.
+ STDMETHODIMP get_windowHandle(HWND* window_handle);
+
+ // Get this object's index in its parent object.
+ STDMETHODIMP get_indexInParent(LONG* index_in_parent);
+
+ // IAccessible2 methods not implemented.
+ STDMETHODIMP get_extendedRole(BSTR* extended_role) {
+ return E_NOTIMPL;
+ }
+ STDMETHODIMP get_nRelations(LONG* n_relations) {
+ return E_NOTIMPL;
+ }
+ STDMETHODIMP get_relation(LONG relation_index,
+ IAccessibleRelation** relation) {
+ return E_NOTIMPL;
+ }
+ STDMETHODIMP get_relations(LONG max_relations,
+ IAccessibleRelation** relations,
+ LONG* n_relations) {
+ return E_NOTIMPL;
+ }
+ STDMETHODIMP scrollTo(enum IA2ScrollType scroll_type) {
+ return E_NOTIMPL;
+ }
+ STDMETHODIMP scrollToPoint(enum IA2CoordinateType coordinate_type,
+ LONG x,
+ LONG y) {
+ return E_NOTIMPL;
+ }
+ STDMETHODIMP get_groupPosition(LONG* group_level,
+ LONG* similar_items_in_group,
+ LONG* position_in_group) {
+ return E_NOTIMPL;
+ }
+ STDMETHODIMP get_localizedExtendedRole(BSTR* localized_extended_role) {
+ return E_NOTIMPL;
+ }
+ STDMETHODIMP get_nExtendedStates(LONG* n_extended_states) {
+ return E_NOTIMPL;
+ }
+ STDMETHODIMP get_extendedStates(LONG max_extended_states,
+ BSTR** extended_states,
+ LONG* n_extended_states) {
+ return E_NOTIMPL;
+ }
+ STDMETHODIMP get_localizedExtendedStates(LONG max_localized_extended_states,
+ BSTR** localized_extended_states,
+ LONG* n_localized_extended_states) {
+ return E_NOTIMPL;
+ }
+ STDMETHODIMP get_locale(IA2Locale* locale) {
+ return E_NOTIMPL;
+ }
+
+ //
+ // IAccessibleImage methods.
+ //
+
+ STDMETHODIMP get_description(BSTR* description);
+
+ STDMETHODIMP get_imagePosition(enum IA2CoordinateType coordinate_type,
+ LONG* x, LONG* y);
+
+ STDMETHODIMP get_imageSize(LONG* height, LONG* width);
+
+ //
+ // IAccessibleText methods.
+ //
+
+ STDMETHODIMP get_nCharacters(LONG* n_characters);
+
+ STDMETHODIMP get_caretOffset(LONG* offset);
+
+ STDMETHODIMP get_nSelections(LONG* n_selections);
+
+ STDMETHODIMP get_selection(LONG selection_index,
+ LONG* start_offset,
+ LONG* end_offset);
+
+ STDMETHODIMP get_text(LONG start_offset, LONG end_offset, BSTR* text);
+
+ STDMETHODIMP get_textAtOffset(LONG offset,
+ enum IA2TextBoundaryType boundary_type,
+ LONG* start_offset, LONG* end_offset,
+ BSTR* text);
+
+ STDMETHODIMP get_textBeforeOffset(LONG offset,
+ enum IA2TextBoundaryType boundary_type,
+ LONG* start_offset, LONG* end_offset,
+ BSTR* text);
+
+ STDMETHODIMP get_textAfterOffset(LONG offset,
+ enum IA2TextBoundaryType boundary_type,
+ LONG* start_offset, LONG* end_offset,
+ BSTR* text);
+
+ // IAccessibleText methods not implemented.
+ STDMETHODIMP addSelection(LONG start_offset, LONG end_offset) {
+ return E_NOTIMPL;
+ }
+ STDMETHODIMP get_attributes(LONG offset, LONG* start_offset, LONG* end_offset,
+ BSTR* text_attributes) {
+ return E_NOTIMPL;
+ }
+ STDMETHODIMP get_characterExtents(LONG offset,
+ enum IA2CoordinateType coord_type,
+ LONG* x, LONG* y,
+ LONG* width, LONG* height) {
+ return E_NOTIMPL;
+ }
+ STDMETHODIMP get_offsetAtPoint(LONG x, LONG y,
+ enum IA2CoordinateType coord_type,
+ LONG* offset) {
+ return E_NOTIMPL;
+ }
+ STDMETHODIMP removeSelection(LONG selection_index) {
+ return E_NOTIMPL;
+ }
+ STDMETHODIMP setCaretOffset(LONG offset) {
+ return E_NOTIMPL;
+ }
+ STDMETHODIMP setSelection(LONG selection_index,
+ LONG start_offset,
+ LONG end_offset) {
+ return E_NOTIMPL;
+ }
+ STDMETHODIMP scrollSubstringTo(LONG start_index,
+ LONG end_index,
+ enum IA2ScrollType scroll_type) {
+ return E_NOTIMPL;
+ }
+ STDMETHODIMP scrollSubstringToPoint(LONG start_index, LONG end_index,
+ enum IA2CoordinateType coordinate_type,
+ LONG x, LONG y) {
+ return E_NOTIMPL;
+ }
+ STDMETHODIMP get_newText(IA2TextSegment* new_text) {
+ return E_NOTIMPL;
+ }
+ STDMETHODIMP get_oldText(IA2TextSegment* old_text) {
+ return E_NOTIMPL;
+ }
+
+ //
+ // ISimpleDOMDocument methods.
+ //
+
+ STDMETHODIMP get_URL(BSTR* url);
+
+ STDMETHODIMP get_title(BSTR* title);
+
+ STDMETHODIMP get_mimeType(BSTR* mime_type);
+
+ STDMETHODIMP get_docType(BSTR* doc_type);
+
+ STDMETHODIMP get_nameSpaceURIForID(
+ short name_space_id, BSTR *name_space_uri) {
+ return E_NOTIMPL;
+ }
+ STDMETHODIMP put_alternateViewMediaTypes(
+ BSTR *comma_separated_media_types) {
+ return E_NOTIMPL;
+ }
+
+ //
+ // ISimpleDOMNode methods.
+ //
+
+ STDMETHODIMP get_nodeInfo(
+ BSTR* node_name,
+ short* name_space_id,
+ BSTR* node_value,
+ unsigned int* num_children,
+ unsigned int* unique_id,
+ unsigned short* node_type);
+
+ STDMETHODIMP get_attributes(
+ unsigned short max_attribs,
+ BSTR* attrib_names,
+ short* name_space_id,
+ BSTR* attrib_values,
+ unsigned short* num_attribs);
+
+ STDMETHODIMP get_attributesForNames(
+ unsigned short num_attribs,
+ BSTR* attrib_names,
+ short* name_space_id,
+ BSTR* attrib_values);
+
+ STDMETHODIMP get_computedStyle(
+ unsigned short max_style_properties,
+ boolean use_alternate_view,
+ BSTR *style_properties,
+ BSTR *style_values,
+ unsigned short *num_style_properties);
+
+ STDMETHODIMP get_computedStyleForProperties(
+ unsigned short num_style_properties,
+ boolean use_alternate_view,
+ BSTR* style_properties,
+ BSTR* style_values);
+
+ STDMETHODIMP scrollTo(boolean placeTopLeft);
+
+ STDMETHODIMP get_parentNode(ISimpleDOMNode** node);
+
+ STDMETHODIMP get_firstChild(ISimpleDOMNode** node);
+
+ STDMETHODIMP get_lastChild(ISimpleDOMNode** node);
+
+ STDMETHODIMP get_previousSibling(ISimpleDOMNode** node);
+
+ STDMETHODIMP get_nextSibling(ISimpleDOMNode** node);
+
+ STDMETHODIMP get_childAt(
+ unsigned int child_index,
+ ISimpleDOMNode** node);
+
+ STDMETHODIMP get_innerHTML(BSTR* innerHTML) {
+ return E_NOTIMPL;
+ }
+
+ STDMETHODIMP get_localInterface(void** local_interface) {
+ return E_NOTIMPL;
+ }
+
+ STDMETHODIMP get_language(BSTR* language) {
+ return E_NOTIMPL;
+ }
+
+ //
+ // ISimpleDOMText methods.
+ //
+
+ STDMETHODIMP get_domText(BSTR* dom_text);
+
+ STDMETHODIMP get_clippedSubstringBounds(
+ unsigned int start_index,
+ unsigned int end_index,
+ int* x,
+ int* y,
+ int* width,
+ int* height) {
+ return E_NOTIMPL;
+ }
+
+ STDMETHODIMP get_unclippedSubstringBounds(
+ unsigned int start_index,
+ unsigned int end_index,
+ int* x,
+ int* y,
+ int* width,
+ int* height) {
+ return E_NOTIMPL;
+ }
+
+ STDMETHODIMP scrollToSubstring(
+ unsigned int start_index,
+ unsigned int end_index) {
+ return E_NOTIMPL;
+ }
+
+ STDMETHODIMP get_fontFamily(BSTR *font_family) {
+ return E_NOTIMPL;
+ }
+
+ //
+ // IServiceProvider methods.
+ //
+
+ STDMETHODIMP QueryService(REFGUID guidService, REFIID riid, void** object);
+
+ //
+ // CComObjectRootEx methods.
+ //
+
+ HRESULT WINAPI InternalQueryInterface(void* this_ptr,
+ const _ATL_INTMAP_ENTRY* entries,
+ REFIID iid,
+ void** object);
+
+ private:
+ // Add one to the reference count and return the same object. Always
+ // use this method when returning a BrowserAccessibilityWin object as
+ // an output parameter to a COM interface, never use it otherwise.
+ BrowserAccessibilityWin* NewReference();
+
+ // Many MSAA methods take a var_id parameter indicating that the operation
+ // should be performed on a particular child ID, rather than this object.
+ // This method tries to figure out the target object from |var_id| and
+ // returns a pointer to the target object if it exists, otherwise NULL.
+ // Does not return a new reference.
+ BrowserAccessibilityWin* GetTargetFromChildID(const VARIANT& var_id);
+
+ // Initialize the role and state metadata from the role enum and state
+ // bitmasks defined in webkit/glue/webaccessibility.h.
+ void InitRoleAndState();
+
+ // Retrieve the string value of an attribute from the attribute map and
+ // if found and nonempty, allocate a new BSTR (with SysAllocString)
+ // and return S_OK. If not found or empty, return S_FALSE.
+ HRESULT GetAttributeAsBstr(
+ WebAccessibility::Attribute attribute, BSTR* value_bstr);
+
+ // Escape a string like it would be escaped for a URL or HTML form.
+ string16 Escape(const string16& str);
+
+ // Get the text of this node for the purposes of IAccessibleText - it may
+ // be the name, it may be the value, etc. depending on the role.
+ const string16& TextForIAccessibleText();
+
+ // If offset is a member of IA2TextSpecialOffsets this function updates the
+ // value of offset and returns, otherwise offset remains unchanged.
+ void HandleSpecialTextOffset(const string16& text, LONG* offset);
+
+ // Search forwards (direction == 1) or backwards (direction == -1) from
+ // the given offset until the given IAccessible2 boundary (like word,
+ // sentence) is found, and return its offset.
+ LONG FindBoundary(const string16& text,
+ IA2TextBoundaryType boundary,
+ LONG start_offset,
+ LONG direction);
+
+ // IAccessible role and state.
+ int32 ia_role_;
+ int32 ia_state_;
+
+ // IAccessible2 role and state.
+ int32 ia2_role_;
+ int32 ia2_state_;
+
+ // Give BrowserAccessibility::Create access to our constructor.
+ friend class BrowserAccessibility;
+
+ DISALLOW_COPY_AND_ASSIGN(BrowserAccessibilityWin);
+};
+
+#endif // CONTENT_BROWSER_ACCESSIBILITY_BROWSER_ACCESSIBILITY_WIN_H_
diff --git a/content/browser/renderer_host/render_widget_host.cc b/content/browser/renderer_host/render_widget_host.cc
index 1f98484..b962f6e 100644
--- a/content/browser/renderer_host/render_widget_host.cc
+++ b/content/browser/renderer_host/render_widget_host.cc
@@ -11,6 +11,7 @@
#include "base/message_loop.h"
#include "base/metrics/histogram.h"
#include "base/utf_string_conversions.h"
+#include "content/browser/accessibility/browser_accessibility_state.h"
#include "content/browser/gpu/gpu_process_host.h"
#include "content/browser/renderer_host/backing_store.h"
#include "content/browser/renderer_host/backing_store_manager.h"
@@ -90,7 +91,8 @@ RenderWidgetHost::RenderWidgetHost(RenderProcessHost* process,
process_->WidgetRestored();
if (CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kForceRendererAccessibility)) {
+ switches::kForceRendererAccessibility) ||
+ BrowserAccessibilityState::GetInstance()->IsAccessibleBrowser()) {
EnableRendererAccessibility();
}
}
diff --git a/content/content_browser.gypi b/content/content_browser.gypi
index e41827f..ec460e2 100644
--- a/content/content_browser.gypi
+++ b/content/content_browser.gypi
@@ -20,11 +20,29 @@
'../third_party/WebKit/Source/WebKit/chromium/WebKit.gyp:webkit',
'../third_party/zlib/zlib.gyp:zlib',
'../ui/ui.gyp:ui_base',
+ '../webkit/support/webkit_support.gyp:webkit_resources',
],
'include_dirs': [
'..',
],
'sources': [
+ 'browser/accessibility/browser_accessibility.cc',
+ 'browser/accessibility/browser_accessibility.h',
+ 'browser/accessibility/browser_accessibility_cocoa.h',
+ 'browser/accessibility/browser_accessibility_cocoa.mm',
+ 'browser/accessibility/browser_accessibility_delegate_mac.h',
+ 'browser/accessibility/browser_accessibility_mac.h',
+ 'browser/accessibility/browser_accessibility_mac.mm',
+ 'browser/accessibility/browser_accessibility_manager.cc',
+ 'browser/accessibility/browser_accessibility_manager.h',
+ 'browser/accessibility/browser_accessibility_manager_mac.h',
+ 'browser/accessibility/browser_accessibility_manager_mac.mm',
+ 'browser/accessibility/browser_accessibility_manager_win.cc',
+ 'browser/accessibility/browser_accessibility_manager_win.h',
+ 'browser/accessibility/browser_accessibility_state.cc',
+ 'browser/accessibility/browser_accessibility_state.h',
+ 'browser/accessibility/browser_accessibility_win.cc',
+ 'browser/accessibility/browser_accessibility_win.h',
'browser/appcache/appcache_dispatcher_host.cc',
'browser/appcache/appcache_dispatcher_host.h',
'browser/appcache/appcache_frontend_proxy.cc',
@@ -422,6 +440,12 @@
'browser/renderer_host/p2p/socket_dispatcher_host.h',
],
}],
+ ['OS=="win"', {
+ 'dependencies': [
+ '../third_party/iaccessible2/iaccessible2.gyp:iaccessible2',
+ '../third_party/isimpledom/isimpledom.gyp:isimpledom',
+ ]
+ }],
['toolkit_uses_gtk == 1', {
'dependencies': [
'../build/linux/system.gyp:dbus-glib',