From fc1926184af3507865502a92b5102e12680b7c21 Mon Sep 17 00:00:00 2001 From: "dmazzoni@chromium.org" Date: Thu, 23 Jun 2011 21:07:33 +0000 Subject: 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 --- .../browser/accessibility/browser_accessibility.cc | 204 --- .../browser/accessibility/browser_accessibility.h | 227 --- .../accessibility/browser_accessibility_cocoa.h | 76 - .../accessibility/browser_accessibility_cocoa.mm | 822 ---------- .../browser_accessibility_delegate_mac.h | 24 - .../accessibility/browser_accessibility_mac.h | 46 - .../accessibility/browser_accessibility_mac.mm | 59 - .../browser_accessibility_mac_unittest.mm | 4 +- .../accessibility/browser_accessibility_manager.cc | 373 ----- .../accessibility/browser_accessibility_manager.h | 177 --- .../browser_accessibility_manager_mac.h | 31 - .../browser_accessibility_manager_mac.mm | 63 - .../browser_accessibility_manager_unittest.cc | 4 +- .../browser_accessibility_manager_win.cc | 90 -- .../browser_accessibility_manager_win.h | 48 - .../accessibility/browser_accessibility_state.cc | 27 - .../accessibility/browser_accessibility_state.h | 53 - .../accessibility/browser_accessibility_win.cc | 1634 -------------------- .../accessibility/browser_accessibility_win.h | 499 ------ .../browser_accessibility_win_unittest.cc | 4 +- chrome/browser/chrome_browser_application_mac.mm | 2 +- chrome/browser/chrome_content_browser_client.cc | 4 - .../renderer_host/render_widget_host_view_mac.h | 4 +- .../renderer_host/render_widget_host_view_mac.mm | 2 +- .../renderer_host/render_widget_host_view_win.cc | 6 +- .../renderer_host/render_widget_host_view_win.h | 2 +- chrome/browser/ui/views/frame/browser_frame_win.cc | 3 +- chrome/browser/ui/views/toolbar_view.cc | 2 +- chrome/chrome_browser.gypi | 17 - content/browser/accessibility/OWNERS | 3 + .../browser/accessibility/browser_accessibility.cc | 204 +++ .../browser/accessibility/browser_accessibility.h | 227 +++ .../accessibility/browser_accessibility_cocoa.h | 76 + .../accessibility/browser_accessibility_cocoa.mm | 822 ++++++++++ .../browser_accessibility_delegate_mac.h | 24 + .../accessibility/browser_accessibility_mac.h | 46 + .../accessibility/browser_accessibility_mac.mm | 59 + .../accessibility/browser_accessibility_manager.cc | 373 +++++ .../accessibility/browser_accessibility_manager.h | 177 +++ .../browser_accessibility_manager_mac.h | 31 + .../browser_accessibility_manager_mac.mm | 63 + .../browser_accessibility_manager_win.cc | 90 ++ .../browser_accessibility_manager_win.h | 48 + .../accessibility/browser_accessibility_state.cc | 27 + .../accessibility/browser_accessibility_state.h | 53 + .../accessibility/browser_accessibility_win.cc | 1634 ++++++++++++++++++++ .../accessibility/browser_accessibility_win.h | 499 ++++++ .../browser/renderer_host/render_widget_host.cc | 4 +- content/content_browser.gypi | 24 + 49 files changed, 4499 insertions(+), 4492 deletions(-) delete mode 100644 chrome/browser/accessibility/browser_accessibility.cc delete mode 100644 chrome/browser/accessibility/browser_accessibility.h delete mode 100644 chrome/browser/accessibility/browser_accessibility_cocoa.h delete mode 100644 chrome/browser/accessibility/browser_accessibility_cocoa.mm delete mode 100644 chrome/browser/accessibility/browser_accessibility_delegate_mac.h delete mode 100644 chrome/browser/accessibility/browser_accessibility_mac.h delete mode 100644 chrome/browser/accessibility/browser_accessibility_mac.mm delete mode 100644 chrome/browser/accessibility/browser_accessibility_manager.cc delete mode 100644 chrome/browser/accessibility/browser_accessibility_manager.h delete mode 100644 chrome/browser/accessibility/browser_accessibility_manager_mac.h delete mode 100644 chrome/browser/accessibility/browser_accessibility_manager_mac.mm delete mode 100644 chrome/browser/accessibility/browser_accessibility_manager_win.cc delete mode 100644 chrome/browser/accessibility/browser_accessibility_manager_win.h delete mode 100644 chrome/browser/accessibility/browser_accessibility_state.cc delete mode 100644 chrome/browser/accessibility/browser_accessibility_state.h delete mode 100644 chrome/browser/accessibility/browser_accessibility_win.cc delete mode 100644 chrome/browser/accessibility/browser_accessibility_win.h create mode 100644 content/browser/accessibility/OWNERS create mode 100644 content/browser/accessibility/browser_accessibility.cc create mode 100644 content/browser/accessibility/browser_accessibility.h create mode 100644 content/browser/accessibility/browser_accessibility_cocoa.h create mode 100644 content/browser/accessibility/browser_accessibility_cocoa.mm create mode 100644 content/browser/accessibility/browser_accessibility_delegate_mac.h create mode 100644 content/browser/accessibility/browser_accessibility_mac.h create mode 100644 content/browser/accessibility/browser_accessibility_mac.mm create mode 100644 content/browser/accessibility/browser_accessibility_manager.cc create mode 100644 content/browser/accessibility/browser_accessibility_manager.h create mode 100644 content/browser/accessibility/browser_accessibility_manager_mac.h create mode 100644 content/browser/accessibility/browser_accessibility_manager_mac.mm create mode 100644 content/browser/accessibility/browser_accessibility_manager_win.cc create mode 100644 content/browser/accessibility/browser_accessibility_manager_win.h create mode 100644 content/browser/accessibility/browser_accessibility_state.cc create mode 100644 content/browser/accessibility/browser_accessibility_state.h create mode 100644 content/browser/accessibility/browser_accessibility_win.cc create mode 100644 content/browser/accessibility/browser_accessibility_win.h diff --git a/chrome/browser/accessibility/browser_accessibility.cc b/chrome/browser/accessibility/browser_accessibility.cc deleted file mode 100644 index 92a4819..0000000 --- a/chrome/browser/accessibility/browser_accessibility.cc +++ /dev/null @@ -1,204 +0,0 @@ -// 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 "chrome/browser/accessibility/browser_accessibility.h" - -#include "base/logging.h" -#include "base/string_number_conversions.h" -#include "chrome/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* 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(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::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::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/chrome/browser/accessibility/browser_accessibility.h b/chrome/browser/accessibility/browser_accessibility.h deleted file mode 100644 index 3234372..0000000 --- a/chrome/browser/accessibility/browser_accessibility.h +++ /dev/null @@ -1,227 +0,0 @@ -// 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 CHROME_BROWSER_ACCESSIBILITY_BROWSER_ACCESSIBILITY_H_ -#define CHROME_BROWSER_ACCESSIBILITY_BROWSER_ACCESSIBILITY_H_ -#pragma once - -#include -#include -#include - -#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* 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& attributes() const { return attributes_; } - int32 child_id() const { return child_id_; } - const std::vector& children() const { - return children_; - } - const std::vector >& html_attributes() const { - return html_attributes_; - } - int32 index_in_parent() const { return index_in_parent_; } - const std::vector& indirect_child_ids() const { - return indirect_child_ids_; - } - const std::vector& 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 children_; - - // The number of internal references to this object. - int32 ref_count_; - - // Accessibility metadata from the renderer - string16 name_; - string16 value_; - std::map attributes_; - std::vector > html_attributes_; - int32 role_; - int32 state_; - string16 role_name_; - gfx::Rect location_; - std::vector indirect_child_ids_; - std::vector 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 // CHROME_BROWSER_ACCESSIBILITY_BROWSER_ACCESSIBILITY_H_ diff --git a/chrome/browser/accessibility/browser_accessibility_cocoa.h b/chrome/browser/accessibility/browser_accessibility_cocoa.h deleted file mode 100644 index db224e0..0000000 --- a/chrome/browser/accessibility/browser_accessibility_cocoa.h +++ /dev/null @@ -1,76 +0,0 @@ -// 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 CHROME_BROWSER_ACCESSIBILITY_BROWSER_ACCESSIBILITY_COCOA_H_ -#define CHROME_BROWSER_ACCESSIBILITY_BROWSER_ACCESSIBILITY_COCOA_H_ -#pragma once - -#import - -#import "base/memory/scoped_nsobject.h" -#import "chrome/browser/accessibility/browser_accessibility_delegate_mac.h" -#include "chrome/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 children_; - id 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)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 // CHROME_BROWSER_ACCESSIBILITY_BROWSER_ACCESSIBILITY_COCOA_H_ diff --git a/chrome/browser/accessibility/browser_accessibility_cocoa.mm b/chrome/browser/accessibility/browser_accessibility_cocoa.mm deleted file mode 100644 index f4ed2e4..0000000 --- a/chrome/browser/accessibility/browser_accessibility_cocoa.mm +++ /dev/null @@ -1,822 +0,0 @@ -// 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 - -#import "chrome/browser/accessibility/browser_accessibility_cocoa.h" - -#include - -#include "base/string16.h" -#include "base/sys_string_conversions.h" -#include "base/utf_string_conversions.h" -#include "chrome/browser/renderer_host/render_widget_host_view_mac.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& attributes, - WebAccessibility::Attribute attribute) { - std::map::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 webAccessibilityToNativeRole; -// A mapping of webkit roles to native subroles. -std::map 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)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( browserAccessibility_->role()); - - // Roles that we only determine at runtime. - if (browserAccessibilityRole == WebAccessibility::ROLE_TEXT_FIELD && - GetState(browserAccessibility_, WebAccessibility::STATE_PROTECTED)) { - return @"AXSecureTextField"; - } - - std::map::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 >& htmlAttributes = - browserAccessibility_->html_attributes(); - WebAccessibility::Role browserAccessibilityRole = - static_cast(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& 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( browserAccessibility_->role()); - - std::map::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& line_breaks = - browserAccessibility_->line_breaks(); - for (int i = 0; i < static_cast(line_breaks.size()); ++i) { - if (line_breaks[i] > selStart) - return [NSNumber numberWithInt:i]; - } - return [NSNumber numberWithInt:static_cast(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& line_breaks = browserAccessibility_->line_breaks(); - int len = static_cast(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(line_breaks.size()); ++i) { - if (line_breaks[i] > index) - return [NSNumber numberWithInt:i]; - } - return [NSNumber numberWithInt:static_cast(line_breaks.size())]; - } - - if ([attribute isEqualToString: - NSAccessibilityRangeForLineParameterizedAttribute]) { - int line_index = [(NSNumber*)parameter intValue]; - int line_count = static_cast(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/chrome/browser/accessibility/browser_accessibility_delegate_mac.h b/chrome/browser/accessibility/browser_accessibility_delegate_mac.h deleted file mode 100644 index 1fd27c1..0000000 --- a/chrome/browser/accessibility/browser_accessibility_delegate_mac.h +++ /dev/null @@ -1,24 +0,0 @@ -// 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 CHROME_BROWSER_ACCESSIBILITY_BROWSER_ACCESSIBILITY_DELEGATE_MAC_H_ -#define CHROME_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 // CHROME_BROWSER_ACCESSIBILITY_BROWSER_ACCESSIBILITY_DELEGATE_MAC_H_ diff --git a/chrome/browser/accessibility/browser_accessibility_mac.h b/chrome/browser/accessibility/browser_accessibility_mac.h deleted file mode 100644 index 027ab94..0000000 --- a/chrome/browser/accessibility/browser_accessibility_mac.h +++ /dev/null @@ -1,46 +0,0 @@ -// 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 CHROME_BROWSER_ACCESSIBILITY_BROWSER_ACCESSIBILITY_MAC_H_ -#define CHROME_BROWSER_ACCESSIBILITY_BROWSER_ACCESSIBILITY_MAC_H_ -#pragma once - -#include -#include -#include - -#include "base/memory/scoped_nsobject.h" -#include "chrome/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* 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 // CHROME_BROWSER_ACCESSIBILITY_BROWSER_ACCESSIBILITY_MAC_H_ diff --git a/chrome/browser/accessibility/browser_accessibility_mac.mm b/chrome/browser/accessibility/browser_accessibility_mac.mm deleted file mode 100644 index 6594c7e..0000000 --- a/chrome/browser/accessibility/browser_accessibility_mac.mm +++ /dev/null @@ -1,59 +0,0 @@ -// 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 - -#import "chrome/browser/accessibility/browser_accessibility_mac.h" - -#import "chrome/browser/accessibility/browser_accessibility_cocoa.h" -#import "chrome/browser/accessibility/browser_accessibility_delegate_mac.h" -#include "chrome/browser/accessibility/browser_accessibility_manager.h" -#import "chrome/browser/renderer_host/render_widget_host_view_mac.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:(RenderWidgetHostViewCocoa*)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* nodes) { - [browser_accessibility_cocoa_ childrenChanged]; - BrowserAccessibility::DetachTree(nodes); -} - -BrowserAccessibilityCocoa* BrowserAccessibility::toBrowserAccessibilityCocoa() { - return static_cast(this)-> - native_view(); -} diff --git a/chrome/browser/accessibility/browser_accessibility_mac_unittest.mm b/chrome/browser/accessibility/browser_accessibility_mac_unittest.mm index 09fb41f1..595fb33 100644 --- a/chrome/browser/accessibility/browser_accessibility_mac_unittest.mm +++ b/chrome/browser/accessibility/browser_accessibility_mac_unittest.mm @@ -7,9 +7,9 @@ #include "base/memory/scoped_ptr.h" #include "base/string_util.h" #include "base/utf_string_conversions.h" -#include "chrome/browser/accessibility/browser_accessibility_cocoa.h" -#include "chrome/browser/accessibility/browser_accessibility_manager.h" #include "chrome/browser/ui/cocoa/cocoa_test_helper.h" +#include "content/browser/accessibility/browser_accessibility_cocoa.h" +#include "content/browser/accessibility/browser_accessibility_manager.h" #include "testing/gtest/include/gtest/gtest.h" #import "testing/gtest_mac.h" diff --git a/chrome/browser/accessibility/browser_accessibility_manager.cc b/chrome/browser/accessibility/browser_accessibility_manager.cc deleted file mode 100644 index 4c58228..0000000 --- a/chrome/browser/accessibility/browser_accessibility_manager.cc +++ /dev/null @@ -1,373 +0,0 @@ -// 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 "chrome/browser/accessibility/browser_accessibility_manager.h" - -#include "base/logging.h" -#include "chrome/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::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::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& 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::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 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(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::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(src.children.size()); ++i) { - BrowserAccessibility* child = CreateAccessibilityTree( - instance, src.children[i], i); - instance->AddChild(child); - } - - return instance; -} diff --git a/chrome/browser/accessibility/browser_accessibility_manager.h b/chrome/browser/accessibility/browser_accessibility_manager.h deleted file mode 100644 index 1014f33..0000000 --- a/chrome/browser/accessibility/browser_accessibility_manager.h +++ /dev/null @@ -1,177 +0,0 @@ -// 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 CHROME_BROWSER_ACCESSIBILITY_BROWSER_ACCESSIBILITY_MANAGER_H_ -#define CHROME_BROWSER_ACCESSIBILITY_BROWSER_ACCESSIBILITY_MANAGER_H_ -#pragma once - -#include - -#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& 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 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 renderer_id_to_child_id_map_; - - // A mapping from child IDs to BrowserAccessibility objects. - base::hash_map child_id_map_; - - DISALLOW_COPY_AND_ASSIGN(BrowserAccessibilityManager); -}; - -#endif // CHROME_BROWSER_ACCESSIBILITY_BROWSER_ACCESSIBILITY_MANAGER_H_ diff --git a/chrome/browser/accessibility/browser_accessibility_manager_mac.h b/chrome/browser/accessibility/browser_accessibility_manager_mac.h deleted file mode 100644 index dc35d6f..0000000 --- a/chrome/browser/accessibility/browser_accessibility_manager_mac.h +++ /dev/null @@ -1,31 +0,0 @@ -// 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 CHROME_BROWSER_ACCESSIBILITY_BROWSER_ACCESSIBILITY_MANAGER_MAC_H_ -#define CHROME_BROWSER_ACCESSIBILITY_BROWSER_ACCESSIBILITY_MANAGER_MAC_H_ -#pragma once - -#import - -#include "chrome/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 // CHROME_BROWSER_ACCESSIBILITY_BROWSER_ACCESSIBILITY_MANAGER_MAC_H_ diff --git a/chrome/browser/accessibility/browser_accessibility_manager_mac.mm b/chrome/browser/accessibility/browser_accessibility_manager_mac.mm deleted file mode 100644 index 5c876e3..0000000 --- a/chrome/browser/accessibility/browser_accessibility_manager_mac.mm +++ /dev/null @@ -1,63 +0,0 @@ -// 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 "chrome/browser/accessibility/browser_accessibility_manager_mac.h" - -#import "base/logging.h" -#import "chrome/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/chrome/browser/accessibility/browser_accessibility_manager_unittest.cc b/chrome/browser/accessibility/browser_accessibility_manager_unittest.cc index 4d8bb15..79f96b8 100644 --- a/chrome/browser/accessibility/browser_accessibility_manager_unittest.cc +++ b/chrome/browser/accessibility/browser_accessibility_manager_unittest.cc @@ -4,8 +4,8 @@ #include "base/string16.h" #include "base/utf_string_conversions.h" -#include "chrome/browser/accessibility/browser_accessibility.h" -#include "chrome/browser/accessibility/browser_accessibility_manager.h" +#include "content/browser/accessibility/browser_accessibility.h" +#include "content/browser/accessibility/browser_accessibility_manager.h" #include "content/common/view_messages.h" #include "testing/gtest/include/gtest/gtest.h" #include "webkit/glue/webaccessibility.h" diff --git a/chrome/browser/accessibility/browser_accessibility_manager_win.cc b/chrome/browser/accessibility/browser_accessibility_manager_win.cc deleted file mode 100644 index 92a290c..0000000 --- a/chrome/browser/accessibility/browser_accessibility_manager_win.cc +++ /dev/null @@ -1,90 +0,0 @@ -// 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 "chrome/browser/accessibility/browser_accessibility_manager_win.h" - -#include "chrome/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(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(&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/chrome/browser/accessibility/browser_accessibility_manager_win.h b/chrome/browser/accessibility/browser_accessibility_manager_win.h deleted file mode 100644 index 59af0a2..0000000 --- a/chrome/browser/accessibility/browser_accessibility_manager_win.h +++ /dev/null @@ -1,48 +0,0 @@ -// 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 CHROME_BROWSER_ACCESSIBILITY_BROWSER_ACCESSIBILITY_MANAGER_WIN_H_ -#define CHROME_BROWSER_ACCESSIBILITY_BROWSER_ACCESSIBILITY_MANAGER_WIN_H_ -#pragma once - -#include - -#include "base/win/scoped_comptr.h" -#include "chrome/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 window_iaccessible_; - - // Give BrowserAccessibilityManager::Create access to our constructor. - friend class BrowserAccessibilityManager; - - DISALLOW_COPY_AND_ASSIGN(BrowserAccessibilityManagerWin); -}; - -#endif // CHROME_BROWSER_ACCESSIBILITY_BROWSER_ACCESSIBILITY_MANAGER_WIN_H_ diff --git a/chrome/browser/accessibility/browser_accessibility_state.cc b/chrome/browser/accessibility/browser_accessibility_state.cc deleted file mode 100644 index bc818d3..0000000 --- a/chrome/browser/accessibility/browser_accessibility_state.cc +++ /dev/null @@ -1,27 +0,0 @@ -// 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 "chrome/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::get(); -} - -void BrowserAccessibilityState::OnScreenReaderDetected() { - screen_reader_active_ = true; -} - -bool BrowserAccessibilityState::IsAccessibleBrowser() { - return screen_reader_active_; -} diff --git a/chrome/browser/accessibility/browser_accessibility_state.h b/chrome/browser/accessibility/browser_accessibility_state.h deleted file mode 100644 index 710f18a..0000000 --- a/chrome/browser/accessibility/browser_accessibility_state.h +++ /dev/null @@ -1,53 +0,0 @@ -// 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 CHROME_BROWSER_ACCESSIBILITY_BROWSER_ACCESSIBILITY_STATE_H_ -#define CHROME_BROWSER_ACCESSIBILITY_BROWSER_ACCESSIBILITY_STATE_H_ -#pragma once - -#include "base/basictypes.h" - -template 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 Chrome browser should be customized for accessibility. - bool IsAccessibleBrowser(); - - private: - BrowserAccessibilityState(); - friend struct DefaultSingletonTraits; - - // Set to true when a screen reader client is detected. - bool screen_reader_active_; - - DISALLOW_COPY_AND_ASSIGN(BrowserAccessibilityState); -}; - -#endif // CHROME_BROWSER_ACCESSIBILITY_BROWSER_ACCESSIBILITY_STATE_H_ diff --git a/chrome/browser/accessibility/browser_accessibility_win.cc b/chrome/browser/accessibility/browser_accessibility_win.cc deleted file mode 100644 index a543c12..0000000 --- a/chrome/browser/accessibility/browser_accessibility_win.cc +++ /dev/null @@ -1,1634 +0,0 @@ -// 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 "chrome/browser/accessibility/browser_accessibility_win.h" - -#include "base/string_number_conversions.h" -#include "base/string_util.h" -#include "base/utf_string_conversions.h" -#include "chrome/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* instance; - HRESULT hr = CComObject::CreateInstance(&instance); - DCHECK(SUCCEEDED(hr)); - return instance->NewReference(); -} - -BrowserAccessibilityWin* BrowserAccessibility::toBrowserAccessibilityWin() { - return static_cast(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( - 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(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(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(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(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(line_breaks_.size()); j++) { - if (line_breaks_[j] > start_offset) - return line_breaks_[j]; - } - return text_size; - } else { - for (int j = static_cast(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/chrome/browser/accessibility/browser_accessibility_win.h b/chrome/browser/accessibility/browser_accessibility_win.h deleted file mode 100644 index 78d0ecd..0000000 --- a/chrome/browser/accessibility/browser_accessibility_win.h +++ /dev/null @@ -1,499 +0,0 @@ -// 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 CHROME_BROWSER_ACCESSIBILITY_BROWSER_ACCESSIBILITY_WIN_H_ -#define CHROME_BROWSER_ACCESSIBILITY_BROWSER_ACCESSIBILITY_WIN_H_ -#pragma once - -#include -#include -#include - -#include - -#include "chrome/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, - public IDispatchImpl, - 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 // CHROME_BROWSER_ACCESSIBILITY_BROWSER_ACCESSIBILITY_WIN_H_ diff --git a/chrome/browser/accessibility/browser_accessibility_win_unittest.cc b/chrome/browser/accessibility/browser_accessibility_win_unittest.cc index 66cf70d..f34b11c 100644 --- a/chrome/browser/accessibility/browser_accessibility_win_unittest.cc +++ b/chrome/browser/accessibility/browser_accessibility_win_unittest.cc @@ -4,8 +4,8 @@ #include "base/memory/scoped_ptr.h" #include "base/win/scoped_comptr.h" -#include "chrome/browser/accessibility/browser_accessibility_manager.h" -#include "chrome/browser/accessibility/browser_accessibility_win.h" +#include "content/browser/accessibility/browser_accessibility_manager.h" +#include "content/browser/accessibility/browser_accessibility_win.h" #include "content/common/view_messages.h" #include "testing/gtest/include/gtest/gtest.h" diff --git a/chrome/browser/chrome_browser_application_mac.mm b/chrome/browser/chrome_browser_application_mac.mm index ebb37f5..8c212cf 100644 --- a/chrome/browser/chrome_browser_application_mac.mm +++ b/chrome/browser/chrome_browser_application_mac.mm @@ -10,12 +10,12 @@ #import "base/memory/scoped_nsobject.h" #import "base/sys_string_conversions.h" #import "chrome/app/breakpad_mac.h" -#include "chrome/browser/accessibility/browser_accessibility_state.h" #import "chrome/browser/app_controller_mac.h" #include "chrome/browser/ui/browser_list.h" #import "chrome/browser/ui/cocoa/objc_method_swizzle.h" #import "chrome/browser/ui/cocoa/objc_zombie.h" #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h" +#include "content/browser/accessibility/browser_accessibility_state.h" #include "content/browser/renderer_host/render_view_host.h" // The implementation of NSExceptions break various assumptions in the diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc index 8d72958..f491b14 100644 --- a/chrome/browser/chrome_content_browser_client.cc +++ b/chrome/browser/chrome_content_browser_client.cc @@ -6,7 +6,6 @@ #include "base/command_line.h" #include "chrome/app/breakpad_mac.h" -#include "chrome/browser/accessibility/browser_accessibility_state.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/character_encoding.h" #include "chrome/browser/chrome_plugin_message_filter.h" @@ -140,9 +139,6 @@ void ChromeContentBrowserClient::RenderViewHostCreated( new DevToolsHandler(render_view_host); new ExtensionMessageHandler(render_view_host); - if (BrowserAccessibilityState::GetInstance()->IsAccessibleBrowser()) - render_view_host->EnableRendererAccessibility(); - InitRenderViewHostForExtensions(render_view_host); } diff --git a/chrome/browser/renderer_host/render_widget_host_view_mac.h b/chrome/browser/renderer_host/render_widget_host_view_mac.h index 923e401..1d032e7 100644 --- a/chrome/browser/renderer_host/render_widget_host_view_mac.h +++ b/chrome/browser/renderer_host/render_widget_host_view_mac.h @@ -12,9 +12,9 @@ #include "base/memory/scoped_ptr.h" #include "base/task.h" #include "base/time.h" -#include "chrome/browser/accessibility/browser_accessibility_delegate_mac.h" -#include "chrome/browser/accessibility/browser_accessibility_manager.h" #include "chrome/browser/ui/cocoa/base_view.h" +#include "content/browser/accessibility/browser_accessibility_delegate_mac.h" +#include "content/browser/accessibility/browser_accessibility_manager.h" #include "content/browser/renderer_host/accelerated_surface_container_manager_mac.h" #include "content/browser/renderer_host/render_widget_host_view.h" #include "content/common/edit_command.h" diff --git a/chrome/browser/renderer_host/render_widget_host_view_mac.mm b/chrome/browser/renderer_host/render_widget_host_view_mac.mm index b344f08..64aa8c0 100644 --- a/chrome/browser/renderer_host/render_widget_host_view_mac.mm +++ b/chrome/browser/renderer_host/render_widget_host_view_mac.mm @@ -16,7 +16,6 @@ #include "base/sys_info.h" #include "base/sys_string_conversions.h" #import "chrome/app/breakpad_mac.h" -#import "chrome/browser/accessibility/browser_accessibility_cocoa.h" #include "chrome/browser/browser_trial.h" #import "chrome/browser/renderer_host/accelerated_plugin_view_mac.h" #import "chrome/browser/renderer_host/text_input_client_mac.h" @@ -25,6 +24,7 @@ #import "chrome/browser/ui/cocoa/view_id_util.h" #include "chrome/common/render_messages.h" #include "chrome/common/spellcheck_messages.h" +#import "content/browser/accessibility/browser_accessibility_cocoa.h" #include "content/browser/browser_thread.h" #include "content/browser/gpu/gpu_process_host.h" #include "content/browser/gpu/gpu_process_host_ui_shim.h" diff --git a/chrome/browser/renderer_host/render_widget_host_view_win.cc b/chrome/browser/renderer_host/render_widget_host_view_win.cc index fc28ed1..fdb5d85 100644 --- a/chrome/browser/renderer_host/render_widget_host_view_win.cc +++ b/chrome/browser/renderer_host/render_widget_host_view_win.cc @@ -14,14 +14,14 @@ #include "base/win/scoped_comptr.h" #include "base/win/scoped_gdi_object.h" #include "base/win/wrapped_window_proc.h" -#include "chrome/browser/accessibility/browser_accessibility_manager.h" -#include "chrome/browser/accessibility/browser_accessibility_state.h" -#include "chrome/browser/accessibility/browser_accessibility_win.h" #include "chrome/browser/browser_trial.h" #include "chrome/browser/renderer_host/render_widget_host_view_views.h" #include "chrome/common/chrome_constants.h" #include "chrome/common/chrome_switches.h" #include "chrome/common/render_messages.h" +#include "content/browser/accessibility/browser_accessibility_manager.h" +#include "content/browser/accessibility/browser_accessibility_state.h" +#include "content/browser/accessibility/browser_accessibility_win.h" #include "content/browser/browser_thread.h" #include "content/browser/plugin_process_host.h" #include "content/browser/renderer_host/backing_store.h" diff --git a/chrome/browser/renderer_host/render_widget_host_view_win.h b/chrome/browser/renderer_host/render_widget_host_view_win.h index b72d853..70e126c 100644 --- a/chrome/browser/renderer_host/render_widget_host_view_win.h +++ b/chrome/browser/renderer_host/render_widget_host_view_win.h @@ -17,7 +17,7 @@ #include "base/memory/scoped_vector.h" #include "base/task.h" #include "base/win/scoped_comptr.h" -#include "chrome/browser/accessibility/browser_accessibility_manager.h" +#include "content/browser/accessibility/browser_accessibility_manager.h" #include "content/browser/renderer_host/render_widget_host_view.h" #include "content/common/notification_observer.h" #include "content/common/notification_registrar.h" diff --git a/chrome/browser/ui/views/frame/browser_frame_win.cc b/chrome/browser/ui/views/frame/browser_frame_win.cc index e3f5cdc..2b344c6 100644 --- a/chrome/browser/ui/views/frame/browser_frame_win.cc +++ b/chrome/browser/ui/views/frame/browser_frame_win.cc @@ -9,10 +9,10 @@ #include -#include "chrome/browser/accessibility/browser_accessibility_state.h" #include "chrome/browser/ui/browser_list.h" #include "chrome/browser/ui/views/frame/browser_frame_views.h" #include "chrome/browser/ui/views/frame/browser_view.h" +#include "content/browser/accessibility/browser_accessibility_state.h" #include "grit/theme_resources.h" #include "ui/base/theme_provider.h" #include "ui/gfx/font.h" @@ -221,4 +221,3 @@ NativeBrowserFrame* NativeBrowserFrame::CreateNativeBrowserFrame( return new BrowserFrameViews(browser_frame, browser_view); return new BrowserFrameWin(browser_frame, browser_view); } - diff --git a/chrome/browser/ui/views/toolbar_view.cc b/chrome/browser/ui/views/toolbar_view.cc index c9908f4..d9c1958 100644 --- a/chrome/browser/ui/views/toolbar_view.cc +++ b/chrome/browser/ui/views/toolbar_view.cc @@ -7,7 +7,6 @@ #include "base/i18n/number_formatting.h" #include "base/utf_string_conversions.h" #include "chrome/app/chrome_command_ids.h" -#include "chrome/browser/accessibility/browser_accessibility_state.h" #include "chrome/browser/prefs/pref_service.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/browser.h" @@ -19,6 +18,7 @@ #include "chrome/browser/ui/views/wrench_menu.h" #include "chrome/browser/upgrade_detector.h" #include "chrome/common/pref_names.h" +#include "content/browser/accessibility/browser_accessibility_state.h" #include "content/browser/user_metrics.h" #include "content/common/notification_service.h" #include "grit/chromium_strings.h" diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi index 2d85a16..817eaef 100644 --- a/chrome/chrome_browser.gypi +++ b/chrome/chrome_browser.gypi @@ -75,23 +75,6 @@ # mocks. 'browser/about_flags.cc', 'browser/about_flags.h', - '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/accessibility_events.cc', 'browser/accessibility_events.h', 'browser/aeropeek_manager.cc', 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* 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(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::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::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 +#include +#include + +#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* 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& attributes() const { return attributes_; } + int32 child_id() const { return child_id_; } + const std::vector& children() const { + return children_; + } + const std::vector >& html_attributes() const { + return html_attributes_; + } + int32 index_in_parent() const { return index_in_parent_; } + const std::vector& indirect_child_ids() const { + return indirect_child_ids_; + } + const std::vector& 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 children_; + + // The number of internal references to this object. + int32 ref_count_; + + // Accessibility metadata from the renderer + string16 name_; + string16 value_; + std::map attributes_; + std::vector > html_attributes_; + int32 role_; + int32 state_; + string16 role_name_; + gfx::Rect location_; + std::vector indirect_child_ids_; + std::vector 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 + +#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 children_; + id 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)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 + +#import "content/browser/accessibility/browser_accessibility_cocoa.h" + +#include + +#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& attributes, + WebAccessibility::Attribute attribute) { + std::map::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 webAccessibilityToNativeRole; +// A mapping of webkit roles to native subroles. +std::map 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)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( browserAccessibility_->role()); + + // Roles that we only determine at runtime. + if (browserAccessibilityRole == WebAccessibility::ROLE_TEXT_FIELD && + GetState(browserAccessibility_, WebAccessibility::STATE_PROTECTED)) { + return @"AXSecureTextField"; + } + + std::map::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 >& htmlAttributes = + browserAccessibility_->html_attributes(); + WebAccessibility::Role browserAccessibilityRole = + static_cast(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& 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( browserAccessibility_->role()); + + std::map::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& line_breaks = + browserAccessibility_->line_breaks(); + for (int i = 0; i < static_cast(line_breaks.size()); ++i) { + if (line_breaks[i] > selStart) + return [NSNumber numberWithInt:i]; + } + return [NSNumber numberWithInt:static_cast(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& line_breaks = browserAccessibility_->line_breaks(); + int len = static_cast(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(line_breaks.size()); ++i) { + if (line_breaks[i] > index) + return [NSNumber numberWithInt:i]; + } + return [NSNumber numberWithInt:static_cast(line_breaks.size())]; + } + + if ([attribute isEqualToString: + NSAccessibilityRangeForLineParameterizedAttribute]) { + int line_index = [(NSNumber*)parameter intValue]; + int line_count = static_cast(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 +#include +#include + +#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* 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 + +#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)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* nodes) { + [browser_accessibility_cocoa_ childrenChanged]; + BrowserAccessibility::DetachTree(nodes); +} + +BrowserAccessibilityCocoa* BrowserAccessibility::toBrowserAccessibilityCocoa() { + return static_cast(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::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::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& 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::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 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(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::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(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 + +#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& 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 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 renderer_id_to_child_id_map_; + + // A mapping from child IDs to BrowserAccessibility objects. + base::hash_map 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 + +#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(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(&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 + +#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 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::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 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; + + // 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* instance; + HRESULT hr = CComObject::CreateInstance(&instance); + DCHECK(SUCCEEDED(hr)); + return instance->NewReference(); +} + +BrowserAccessibilityWin* BrowserAccessibility::toBrowserAccessibilityWin() { + return static_cast(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( + 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(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(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(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(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(line_breaks_.size()); j++) { + if (line_breaks_[j] > start_offset) + return line_breaks_[j]; + } + return text_size; + } else { + for (int j = static_cast(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 +#include +#include + +#include + +#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, + public IDispatchImpl, + 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', -- cgit v1.1