summaryrefslogtreecommitdiffstats
path: root/chrome/browser/accessibility
diff options
context:
space:
mode:
authordtseng@chromium.org <dtseng@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-10-19 21:18:50 +0000
committerdtseng@chromium.org <dtseng@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-10-19 21:18:50 +0000
commit0d7dad6df2d9d6d9676ca7adb02e3c92beaa8a79 (patch)
treef646a38a4c8a43acdfea7addaf660bea0a02cbcc /chrome/browser/accessibility
parent027db59033125d49ab7cbf4a553e6be7c83b0960 (diff)
downloadchromium_src-0d7dad6df2d9d6d9676ca7adb02e3c92beaa8a79.zip
chromium_src-0d7dad6df2d9d6d9676ca7adb02e3c92beaa8a79.tar.gz
chromium_src-0d7dad6df2d9d6d9676ca7adb02e3c92beaa8a79.tar.bz2
Make the BrowserAccessibilityManagerMac own the management of the cocoa ax tree.
BUG=55657 TEST=passing unit tests. Review URL: http://codereview.chromium.org/3826002 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@63110 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/accessibility')
-rw-r--r--chrome/browser/accessibility/browser_accessibility.h20
-rw-r--r--chrome/browser/accessibility/browser_accessibility_cocoa.h52
-rw-r--r--chrome/browser/accessibility/browser_accessibility_cocoa.mm362
-rw-r--r--chrome/browser/accessibility/browser_accessibility_delegate_mac.h23
-rw-r--r--chrome/browser/accessibility/browser_accessibility_mac.h25
-rw-r--r--chrome/browser/accessibility/browser_accessibility_mac.mm35
-rw-r--r--chrome/browser/accessibility/browser_accessibility_mac_unittest.mm123
-rw-r--r--chrome/browser/accessibility/browser_accessibility_manager_mac.mm39
8 files changed, 619 insertions, 60 deletions
diff --git a/chrome/browser/accessibility/browser_accessibility.h b/chrome/browser/accessibility/browser_accessibility.h
index 62cffb5..6e6b8fb 100644
--- a/chrome/browser/accessibility/browser_accessibility.h
+++ b/chrome/browser/accessibility/browser_accessibility.h
@@ -15,8 +15,8 @@
#include "webkit/glue/webaccessibility.h"
class BrowserAccessibilityManager;
-#if defined(OS_MACOSX)
-class BrowserAccessibilityMac;
+#if defined(OS_MACOSX) && __OBJC__
+@class BrowserAccessibilityCocoa;
#elif defined(OS_WIN)
class BrowserAccessibilityWin;
#endif
@@ -91,16 +91,26 @@ class BrowserAccessibility {
BrowserAccessibility* new_acc);
// Accessors
+ const std::map<int32, string16>& attributes() const { return attributes_; }
int32 child_id() const { return child_id_; }
const std::vector<BrowserAccessibility*>& children() const {
return children_;
}
- int32 renderer_id() const { return renderer_id_; }
+ const std::vector<std::pair<string16, string16> >& html_attributes() const {
+ return html_attributes_;
+ }
int32 index_in_parent() const { return index_in_parent_; }
WebKit::WebRect 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_; }
-#if defined(OS_MACOSX)
- BrowserAccessibilityMac* toBrowserAccessibilityMac();
+#if defined(OS_MACOSX) && __OBJC__
+ BrowserAccessibilityCocoa* toBrowserAccessibilityCocoa();
#elif defined(OS_WIN)
BrowserAccessibilityWin* toBrowserAccessibilityWin();
#endif
diff --git a/chrome/browser/accessibility/browser_accessibility_cocoa.h b/chrome/browser/accessibility/browser_accessibility_cocoa.h
new file mode 100644
index 0000000..170c713
--- /dev/null
+++ b/chrome/browser/accessibility/browser_accessibility_cocoa.h
@@ -0,0 +1,52 @@
+// 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_COCOA_H_
+#define CHROME_BROWSER_ACCESSIBILITY_BROWSER_ACCESSIBILITY_COCOA_H_
+#pragma once
+
+#import <Cocoa/Cocoa.h>
+
+#import "base/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.
+@interface BrowserAccessibilityCocoa : NSObject {
+ @private
+ BrowserAccessibility* browserAccessibility_;
+ id<BrowserAccessibilityDelegateCocoa> delegate_;
+}
+
+// This creates a cocoa browser accessibility object around
+// the cross platform BrowserAccessibility object. The delegate is
+// used to communicate with the host renderer. None of these
+// parameters can be null.
+- (id)initWithObject:(BrowserAccessibility*)accessibility
+ delegate:(id<BrowserAccessibilityDelegateCocoa>)delegate;
+
+// Backing source of accessibility info.
+@property(nonatomic, assign) BrowserAccessibility* browserAccessibility;
+// Children is an array of BrowserAccessibility objects, representing
+// the accessibility children of this object.
+@property(nonatomic, readonly) NSArray* children;
+// 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;
+// A string indicating the role of this object as far as accessibility
+// is concerned.
+@property(nonatomic, readonly) NSString* role;
+// The size of this object.
+@property(nonatomic, readonly) NSSize size;
+
+@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
new file mode 100644
index 0000000..0a52a05
--- /dev/null
+++ b/chrome/browser/accessibility/browser_accessibility_cocoa.mm
@@ -0,0 +1,362 @@
+// 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 <execinfo.h>
+
+#import "chrome/browser/accessibility/browser_accessibility_cocoa.h"
+
+#include "app/l10n_util_mac.h"
+#include "base/string16.h"
+#include "base/sys_string_conversions.h"
+#include "chrome/browser/renderer_host/render_widget_host_view_mac.h"
+#include "grit/webkit_strings.h"
+#include "third_party/WebKit/WebKit/chromium/public/WebRect.h"
+
+namespace {
+
+// Returns an autoreleased copy of the WebAccessibility's attribute.
+NSString* NSStringForWebAccessibilityAttribute(
+ const std::map<int32, string16>& attributes,
+ WebAccessibility::Attribute attribute) {
+ std::map<int32, string16>::const_iterator iter =
+ attributes.find(attribute);
+ NSString* returnValue = @"";
+ if (iter != attributes.end()) {
+ returnValue = base::SysUTF16ToNSString(iter->second);
+ }
+ return returnValue;
+}
+
+struct RoleEntry {
+ WebAccessibility::Role value;
+ NSString* string;
+};
+
+static const RoleEntry roles[] = {
+ { WebAccessibility::ROLE_NONE, NSAccessibilityUnknownRole },
+ { WebAccessibility::ROLE_BUTTON, NSAccessibilityButtonRole },
+ { WebAccessibility::ROLE_RADIO_BUTTON, NSAccessibilityRadioButtonRole },
+ { WebAccessibility::ROLE_CHECKBOX, NSAccessibilityCheckBoxRole },
+ { WebAccessibility::ROLE_STATIC_TEXT, NSAccessibilityStaticTextRole},
+ { WebAccessibility::ROLE_IMAGE, NSAccessibilityImageRole},
+ { WebAccessibility::ROLE_TEXT_FIELD, NSAccessibilityTextFieldRole},
+ { WebAccessibility::ROLE_TEXTAREA, NSAccessibilityTextAreaRole},
+ { WebAccessibility::ROLE_LINK, NSAccessibilityLinkRole},
+ { WebAccessibility::ROLE_SCROLLAREA, NSAccessibilityScrollAreaRole},
+ { WebAccessibility::ROLE_SCROLLBAR, NSAccessibilityScrollBarRole},
+ { WebAccessibility::ROLE_RADIO_GROUP, NSAccessibilityRadioGroupRole},
+ { WebAccessibility::ROLE_TABLE, NSAccessibilityTableRole},
+ { WebAccessibility::ROLE_TAB_GROUP, NSAccessibilityTabGroupRole},
+ { WebAccessibility::ROLE_IGNORED, NSAccessibilityUnknownRole},
+ { WebAccessibility::ROLE_WEB_AREA, @"AXWebArea"},
+ { WebAccessibility::ROLE_GROUP, NSAccessibilityGroupRole},
+ { WebAccessibility::ROLE_GRID, NSAccessibilityGridRole},
+ { WebAccessibility::ROLE_WEBCORE_LINK, NSAccessibilityLinkRole},
+};
+
+// 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);
+}
+
+} // namespace
+
+@implementation BrowserAccessibilityCocoa
+
+@synthesize browserAccessibility = browserAccessibility_;
+
+- (id)initWithObject:(BrowserAccessibility*)accessibility
+ delegate:(id<BrowserAccessibilityDelegateCocoa>)delegate {
+ if ((self = [super init])) {
+ browserAccessibility_ = accessibility;
+ delegate_ = delegate;
+ }
+ return self;
+}
+
+// Deletes our associated BrowserAccessibilityMac.
+- (void)dealloc {
+ if (browserAccessibility_) {
+ delete browserAccessibility_;
+ browserAccessibility_ = NULL;
+ }
+
+ [super dealloc];
+}
+
+// Returns an array of BrowserAccessibilityCocoa objects, representing the
+// accessibility children of this object.
+- (NSArray*)children {
+ NSMutableArray* ret = [[[NSMutableArray alloc]
+ initWithCapacity:browserAccessibility_->GetChildCount()] autorelease];
+ for (uint32 index = 0;
+ index < browserAccessibility_->GetChildCount();
+ ++index) {
+ [ret addObject:
+ browserAccessibility_->GetChild(index)->toBrowserAccessibilityCocoa()];
+ }
+ return ret;
+}
+
+// Returns whether or not this node should be ignored in the
+// accessibility tree.
+- (BOOL)isIgnored {
+ return browserAccessibility_->role() == WebAccessibility::ROLE_IGNORED;
+}
+
+// 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);
+}
+
+// Returns a string indicating the role of this object.
+- (NSString*)role {
+ NSString* role = NSAccessibilityUnknownRole;
+ WebAccessibility::Role value =
+ static_cast<WebAccessibility::Role>( browserAccessibility_->role());
+ const size_t numRoles = sizeof(roles) / sizeof(roles[0]);
+ for (size_t i = 0; i < numRoles; ++i) {
+ if (roles[i].value == value) {
+ role = roles[i].string;
+ break;
+ }
+ }
+ return role;
+}
+
+// Returns a string indicating the role description of this object.
+- (NSString*)roleDescription {
+ // The following descriptions are specific to webkit.
+ if ([[self role] isEqualToString:@"AXWebArea"])
+ return l10n_util::GetNSString(IDS_AX_ROLE_WEB_AREA);
+
+ if ([[self role] isEqualToString:@"NSAccessibilityLinkRole"])
+ return l10n_util::GetNSString(IDS_AX_ROLE_LINK);
+
+ if ([[self role] isEqualToString:@"AXHeading"])
+ return l10n_util::GetNSString(IDS_AX_ROLE_HEADING);
+
+ return NSAccessibilityRoleDescription([self role], nil);
+}
+
+// Returns the size of this object.
+- (NSSize)size {
+ return NSMakeSize(browserAccessibility_->location().width,
+ browserAccessibility_->location().height);
+}
+
+// Returns the accessibility value for the given attribute. If the value isn't
+// supported this will return nil.
+- (id)accessibilityAttributeValue:(NSString*)attribute {
+ if ([attribute isEqualToString:NSAccessibilityRoleAttribute]) {
+ return [self role];
+ }
+ if ([attribute isEqualToString:NSAccessibilityDescriptionAttribute]) {
+ return NSStringForWebAccessibilityAttribute(
+ browserAccessibility_->attributes(),
+ WebAccessibility::ATTR_DESCRIPTION);
+ }
+ if ([attribute isEqualToString:NSAccessibilityPositionAttribute]) {
+ return [NSValue valueWithPoint:[delegate_ accessibilityPointInScreen:self]];
+ }
+ if ([attribute isEqualToString:NSAccessibilitySizeAttribute]) {
+ return [NSValue valueWithSize:[self size]];
+ }
+ if ([attribute isEqualToString:NSAccessibilityTopLevelUIElementAttribute] ||
+ [attribute isEqualToString:NSAccessibilityWindowAttribute]) {
+ return [delegate_ window];
+ }
+ if ([attribute isEqualToString:NSAccessibilityChildrenAttribute]) {
+ return [self children];
+ }
+ if ([attribute isEqualToString:NSAccessibilityParentAttribute]) {
+ // A nil parent means we're the root.
+ if (browserAccessibility_->GetParent()) {
+ return NSAccessibilityUnignoredAncestor(
+ browserAccessibility_->GetParent()->toBrowserAccessibilityCocoa());
+ } else {
+ // Hook back up to RenderWidgetHostViewCocoa.
+ return browserAccessibility_->manager()->GetParentView();
+ }
+ }
+ if ([attribute isEqualToString:NSAccessibilityTitleAttribute]) {
+ return base::SysUTF16ToNSString(browserAccessibility_->name());
+ }
+ if ([attribute isEqualToString:NSAccessibilityHelpAttribute]) {
+ return NSStringForWebAccessibilityAttribute(
+ browserAccessibility_->attributes(),
+ WebAccessibility::ATTR_HELP);
+ }
+ if ([attribute isEqualToString:NSAccessibilityValueAttribute]) {
+ return base::SysUTF16ToNSString(browserAccessibility_->value());
+ }
+ if ([attribute isEqualToString:NSAccessibilityRoleDescriptionAttribute]) {
+ return [self roleDescription];
+ }
+ if ([attribute isEqualToString:NSAccessibilityFocusedAttribute]) {
+ NSNumber* ret = [NSNumber numberWithBool:
+ GetState(browserAccessibility_, WebAccessibility::STATE_FOCUSED)];
+ return ret;
+ }
+ // TODO(dtseng): provide complete implementations for the following.
+ if ([attribute isEqualToString:NSAccessibilityEnabledAttribute] ||
+ [attribute isEqualToString:@"AXVisited"] ||
+ [attribute isEqualToString:@"AXLoaded"]) {
+ return [NSNumber numberWithBool:YES];
+ }
+ return nil;
+}
+
+// Returns an array of action names that this object will respond to.
+- (NSArray*)accessibilityActionNames {
+ return [NSArray arrayWithObjects:
+ NSAccessibilityPressAction, NSAccessibilityShowMenuAction, nil];
+}
+
+// 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 {
+ return [NSArray arrayWithObjects:
+ NSAccessibilityChildrenAttribute,
+ NSAccessibilityDescriptionAttribute,
+ NSAccessibilityEnabledAttribute,
+ NSAccessibilityFocusedAttribute,
+ NSAccessibilityHelpAttribute,
+ NSAccessibilityParentAttribute,
+ NSAccessibilityPositionAttribute,
+ NSAccessibilityRoleAttribute,
+ NSAccessibilityRoleDescriptionAttribute,
+ NSAccessibilitySizeAttribute,
+ NSAccessibilityTitleAttribute,
+ NSAccessibilityTopLevelUIElementAttribute,
+ NSAccessibilityValueAttribute,
+ NSAccessibilityWindowAttribute,
+ nil];
+}
+
+// Returns the index of the child in this objects array of children.
+- (NSUInteger)accessibilityIndexOfChild:(id)child {
+ NSUInteger index = 0;
+ for (BrowserAccessibilityCocoa* childToCheck in [self children]) {
+ if ([child isEqual:childToCheck])
+ return index;
+ if (![childToCheck isIgnored])
+ ++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.
+ [delegate_ doDefaultAction:browserAccessibility_->renderer_id()];
+}
+
+// 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 {
+ id hit = self;
+ for (id child in [self children]) {
+ NSPoint origin = [child origin];
+ NSSize size = [child size];
+ 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 {
+ 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
new file mode 100644
index 0000000..18eb49b
--- /dev/null
+++ b/chrome/browser/accessibility/browser_accessibility_delegate_mac.h
@@ -0,0 +1,23 @@
+// Copyright (c) 2006-2008 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)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
index 136be99..1e83fd8 100644
--- a/chrome/browser/accessibility/browser_accessibility_mac.h
+++ b/chrome/browser/accessibility/browser_accessibility_mac.h
@@ -10,6 +10,7 @@
#include <utility>
#include <vector>
+#include "base/scoped_nsobject.h"
#include "chrome/browser/accessibility/browser_accessibility.h"
@class BrowserAccessibilityCocoa;
@@ -20,29 +21,11 @@ class BrowserAccessibilityMac : public BrowserAccessibility {
virtual void Initialize();
virtual void ReleaseReference();
- // Accessers that allow the cocoa wrapper to read these values.
- const string16& name() const { return name_; }
- const string16& value() const { return value_; }
- const std::map<int32, string16>& attributes() const { return attributes_; }
-
- const std::vector<std::pair<string16, string16> >& html_attributes() const {
- return html_attributes_;
- }
-
- int32 role() const { return role_; }
- int32 state() const { return state_; }
- const string16& role_name() const { return role_name_; }
-
- // Accesser and setter for
- // the BrowserAccessibilityCocoa associated with us.
+ // The BrowserAccessibilityCocoa associated with us.
BrowserAccessibilityCocoa* native_view() const {
return browser_accessibility_cocoa_;
}
- void native_view(BrowserAccessibilityCocoa* v) {
- browser_accessibility_cocoa_ = v;
- }
-
private:
// This gives BrowserAccessibility::Create access to the class constructor.
friend class BrowserAccessibility;
@@ -50,8 +33,8 @@ class BrowserAccessibilityMac : public BrowserAccessibility {
BrowserAccessibilityMac();
// Allows access to the BrowserAccessibilityCocoa which wraps this.
- // BrowserAccessibility. We only initialize this member if the accessibility
- // API requests this object.
+ // BrowserAccessibility.
+ // We own this object.
BrowserAccessibilityCocoa* browser_accessibility_cocoa_;
DISALLOW_COPY_AND_ASSIGN(BrowserAccessibilityMac);
};
diff --git a/chrome/browser/accessibility/browser_accessibility_mac.mm b/chrome/browser/accessibility/browser_accessibility_mac.mm
index 1a6c1d4..4df23c6 100644
--- a/chrome/browser/accessibility/browser_accessibility_mac.mm
+++ b/chrome/browser/accessibility/browser_accessibility_mac.mm
@@ -2,26 +2,47 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#import <Cocoa/Cocoa.h>
+
#import "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() {
+BrowserAccessibilityMac::BrowserAccessibilityMac()
+ : browser_accessibility_cocoa_(NULL) {
}
-// TODO(dtseng): ensure we create BrowserAccessibilityCocoa here
-// (RenderWidgetHostViewCocoa to BrowserAccessibilityManagerMac refactoring).
void BrowserAccessibilityMac::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()];
}
-// TODO(dtseng): ensure we cleanup BrowserAccessibilityCocoa and this class.
-// (RenderWidgetHostViewCocoa to BrowserAccessibilityManagerMac refactoring).
void BrowserAccessibilityMac::ReleaseReference() {
+ if (browser_accessibility_cocoa_) {
+ // Relinquish ownership of the cocoa obj.
+ [browser_accessibility_cocoa_ release];
+ browser_accessibility_cocoa_ = nil;
+ // At this point, other processes may have a reference to
+ // browser_accessibility_cocoa_. When the retain count hits zero, it will
+ // destroy us in dealloc.
+ }
}
-BrowserAccessibilityMac* BrowserAccessibility::toBrowserAccessibilityMac() {
- return static_cast<BrowserAccessibilityMac*>(this);
+BrowserAccessibilityCocoa* BrowserAccessibility::toBrowserAccessibilityCocoa() {
+ return static_cast<BrowserAccessibilityMac*>(this)->
+ native_view();
}
diff --git a/chrome/browser/accessibility/browser_accessibility_mac_unittest.mm b/chrome/browser/accessibility/browser_accessibility_mac_unittest.mm
new file mode 100644
index 0000000..266182f
--- /dev/null
+++ b/chrome/browser/accessibility/browser_accessibility_mac_unittest.mm
@@ -0,0 +1,123 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import <Cocoa/Cocoa.h>
+
+#include "base/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/cocoa/cocoa_test_helper.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#import "testing/gtest_mac.h"
+
+@interface MockAccessibilityDelegate :
+ NSView<BrowserAccessibilityDelegateCocoa>
+
+- (NSPoint)accessibilityPointInScreen:(BrowserAccessibilityCocoa*)accessibility;
+- (void)doDefaultAction:(int32)accessibilityObjectId;
+- (void)setAccessibilityFocus:(BOOL)focus
+ accessibilityId:(int32)accessibilityObjectId;
+- (NSWindow*)window;
+
+@end
+
+@implementation MockAccessibilityDelegate
+
+- (NSPoint)accessibilityPointInScreen:
+ (BrowserAccessibilityCocoa*)accessibility {
+ return NSZeroPoint;
+}
+- (void)doDefaultAction:(int32)accessibilityObjectId {
+}
+- (void)setAccessibilityFocus:(BOOL)focus
+ accessibilityId:(int32)accessibilityObjectId {
+}
+- (NSWindow*)window {
+ return nil;
+}
+
+@end
+
+
+class BrowserAccessibilityTest : public CocoaTest {
+ public:
+ virtual void SetUp() {
+ CocoaTest::SetUp();
+ WebAccessibility root;
+ root.location.x = 0;
+ root.location.y = 0;
+ root.location.width = 500;
+ root.location.height = 100;
+ root.attributes[WebAccessibility::ATTR_HELP] = ASCIIToUTF16("HelpText");
+
+ WebAccessibility child1;
+ child1.name = ASCIIToUTF16("Child1");
+ child1.location.x = 0;
+ child1.location.y = 0;
+ child1.location.width = 250;
+ child1.location.height = 100;
+
+ WebAccessibility child2;
+ child2.location.x = 250;
+ child2.location.y = 0;
+ child2.location.width = 250;
+ child2.location.height = 100;
+
+ root.children.push_back(child1);
+ root.children.push_back(child2);
+
+ delegate_.reset([[MockAccessibilityDelegate alloc] init]);
+ manager_.reset(
+ BrowserAccessibilityManager::Create(delegate_, root, NULL));
+ // The manager still owns this object.
+ accessibility_ = manager_->GetRoot()->toBrowserAccessibilityCocoa();
+ }
+
+ protected:
+ scoped_nsobject<MockAccessibilityDelegate> delegate_;
+ // We do not own this object.
+ BrowserAccessibilityCocoa* accessibility_;
+ scoped_ptr<BrowserAccessibilityManager> manager_;
+};
+
+// Standard hit test.
+TEST_F(BrowserAccessibilityTest, HitTestTest) {
+ BrowserAccessibilityCocoa* firstChild =
+ [accessibility_ accessibilityHitTest:NSMakePoint(50, 50)];
+ EXPECT_NSEQ(@"Child1",
+ [firstChild accessibilityAttributeValue:NSAccessibilityTitleAttribute]);
+}
+
+// Test doing a hit test on the edge of a child.
+TEST_F(BrowserAccessibilityTest, EdgeHitTest) {
+ BrowserAccessibilityCocoa* firstChild =
+ [accessibility_ accessibilityHitTest:NSMakePoint(0, 0)];
+ EXPECT_NSEQ(@"Child1",
+ [firstChild accessibilityAttributeValue:NSAccessibilityTitleAttribute]);
+}
+
+// This will test a hit test with invalid coordinates. It is assumed that
+// the hit test has been narrowed down to this object or one of its children
+// so it should return itself since it has no better hit result.
+TEST_F(BrowserAccessibilityTest, InvalidHitTestCoordsTest) {
+ BrowserAccessibilityCocoa* hitTestResult =
+ [accessibility_ accessibilityHitTest:NSMakePoint(-50, 50)];
+ EXPECT_NSEQ(accessibility_, hitTestResult);
+}
+
+// Test to ensure querying standard attributes works.
+TEST_F(BrowserAccessibilityTest, BasicAttributeTest) {
+ NSString* helpText = [accessibility_
+ accessibilityAttributeValue:NSAccessibilityHelpAttribute];
+ EXPECT_NSEQ(@"HelpText", helpText);
+}
+
+// Test querying for an invalid attribute to ensure it doesn't crash.
+TEST_F(BrowserAccessibilityTest, InvalidAttributeTest) {
+ NSString* shouldBeNil = [accessibility_
+ accessibilityAttributeValue:@"NSAnInvalidAttribute"];
+ EXPECT_TRUE(shouldBeNil == nil);
+}
diff --git a/chrome/browser/accessibility/browser_accessibility_manager_mac.mm b/chrome/browser/accessibility/browser_accessibility_manager_mac.mm
index 8aadf8b..6e39cd1f 100644
--- a/chrome/browser/accessibility/browser_accessibility_manager_mac.mm
+++ b/chrome/browser/accessibility/browser_accessibility_manager_mac.mm
@@ -4,10 +4,7 @@
#include "chrome/browser/accessibility/browser_accessibility_manager_mac.h"
-#include "chrome/browser/accessibility/browser_accessibility_mac.h"
-#import "chrome/browser/cocoa/browser_accessibility.h"
-// TODO(dtseng): move to delegate?
-#import "chrome/browser/renderer_host/render_widget_host_view_mac.h"
+#import "chrome/browser/accessibility/browser_accessibility_cocoa.h"
// static
BrowserAccessibilityManager* BrowserAccessibilityManager::Create(
@@ -27,54 +24,42 @@ BrowserAccessibilityManagerMac::BrowserAccessibilityManagerMac(
gfx::NativeView parent_window,
const webkit_glue::WebAccessibility& src,
BrowserAccessibilityDelegate* delegate,
- BrowserAccessibilityFactory* factory)
+ BrowserAccessibilityFactory* factory)
: BrowserAccessibilityManager(parent_window, src, delegate, factory) {
}
void BrowserAccessibilityManagerMac::NotifyAccessibilityEvent(
ViewHostMsg_AccessibilityNotification_Params::NotificationType n,
BrowserAccessibility* node) {
- // TODO(dtseng): support all notifications.
+ // Refer to AXObjectCache.mm (webkit).
NSString* event_id = @"";
switch (n) {
case ViewHostMsg_AccessibilityNotification_Params::
NOTIFICATION_TYPE_CHECK_STATE_CHANGED:
+ // Does not exist on Mac.
return;
case ViewHostMsg_AccessibilityNotification_Params::
NOTIFICATION_TYPE_CHILDREN_CHANGED:
- event_id = NSAccessibilityValueChangedNotification;
- if (GetRoot() == node)
- [((RenderWidgetHostViewCocoa*)GetParentView())
- setAccessibilityTreeRoot:GetRoot()];
- else
- [node->GetParent()->toBrowserAccessibilityMac()->native_view()
- updateDescendants];
- break;
+ // TODO(dtseng): no clear equivalent on Mac.
+ return;
case ViewHostMsg_AccessibilityNotification_Params::
NOTIFICATION_TYPE_FOCUS_CHANGED:
event_id = NSAccessibilityFocusedUIElementChangedNotification;
- if (GetRoot() == node)
- [((RenderWidgetHostViewCocoa*)GetParentView())
- setAccessibilityTreeRoot:GetRoot()];
- else
- [node->GetParent()->toBrowserAccessibilityMac()->native_view()
- updateDescendants];
break;
case ViewHostMsg_AccessibilityNotification_Params::
NOTIFICATION_TYPE_LOAD_COMPLETE:
- [((RenderWidgetHostViewCocoa*)GetParentView())
- setAccessibilityTreeRoot:GetRoot()];
- return;
+ event_id = @"AXLoadComplete";
+ break;
case ViewHostMsg_AccessibilityNotification_Params::
NOTIFICATION_TYPE_VALUE_CHANGED:
event_id = NSAccessibilityValueChangedNotification;
break;
case ViewHostMsg_AccessibilityNotification_Params::
NOTIFICATION_TYPE_SELECTED_TEXT_CHANGED:
- return;
+ event_id = NSAccessibilitySelectedTextChangedNotification;
+ break;
}
- BrowserAccessibilityCocoa* native_node = node->toBrowserAccessibilityMac()->
- native_view();
+ BrowserAccessibilityCocoa* native_node = node->toBrowserAccessibilityCocoa();
DCHECK(native_node);
- NSAccessibilityPostNotification(native_node, event_id);
+ NSAccessibilityPostNotification(native_node, event_id);
}