summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authornektar <nektar@chromium.org>2016-03-24 13:44:25 -0700
committerCommit bot <commit-bot@chromium.org>2016-03-24 20:46:35 +0000
commit5ca8b4fa7b1f9d53be5f5f1a30b4cecf1c1c4fa5 (patch)
tree31d3728633b9ac8c6d3c896e424352299504331f
parent75eab41568b41bde52a213b53ce31e164cd3ab2d (diff)
downloadchromium_src-5ca8b4fa7b1f9d53be5f5f1a30b4cecf1c1c4fa5.zip
chromium_src-5ca8b4fa7b1f9d53be5f5f1a30b4cecf1c1c4fa5.tar.gz
chromium_src-5ca8b4fa7b1f9d53be5f5f1a30b4cecf1c1c4fa5.tar.bz2
Fixes typing and deleting text in simple text fields on Mac OS X 10.11.
BUG=530826 TESTED=VoiceOver on Mac OS X 10.11 R=dmazzoni@chromium.org, avi@chromium.org, mark@chromium.org Review URL: https://codereview.chromium.org/1814163003 Cr-Commit-Position: refs/heads/master@{#383141}
-rw-r--r--content/browser/accessibility/browser_accessibility_manager.h2
-rw-r--r--content/browser/accessibility/browser_accessibility_manager_mac.h27
-rw-r--r--content/browser/accessibility/browser_accessibility_manager_mac.mm161
-rw-r--r--content/browser/accessibility/browser_accessibility_manager_win.h2
4 files changed, 172 insertions, 20 deletions
diff --git a/content/browser/accessibility/browser_accessibility_manager.h b/content/browser/accessibility/browser_accessibility_manager.h
index 908029b..9b5c381 100644
--- a/content/browser/accessibility/browser_accessibility_manager.h
+++ b/content/browser/accessibility/browser_accessibility_manager.h
@@ -226,7 +226,7 @@ class CONTENT_EXPORT BrowserAccessibilityManager : public ui::AXTreeDelegate {
void ActivateFindInPageResult(int request_id, int match_index);
// Called when the renderer process has notified us of about tree changes.
- void OnAccessibilityEvents(
+ virtual void OnAccessibilityEvents(
const std::vector<AXEventNotificationDetails>& details);
// Called when the renderer process updates the location of accessibility
diff --git a/content/browser/accessibility/browser_accessibility_manager_mac.h b/content/browser/accessibility/browser_accessibility_manager_mac.h
index f659059..7150819 100644
--- a/content/browser/accessibility/browser_accessibility_manager_mac.h
+++ b/content/browser/accessibility/browser_accessibility_manager_mac.h
@@ -6,9 +6,16 @@
#define CONTENT_BROWSER_ACCESSIBILITY_BROWSER_ACCESSIBILITY_MANAGER_MAC_H_
#import <Cocoa/Cocoa.h>
+#include <stdint.h>
+
+#include <map>
+#include <vector>
#include "base/macros.h"
+#include "base/strings/string16.h"
+#import "content/browser/accessibility/browser_accessibility_cocoa.h"
#include "content/browser/accessibility/browser_accessibility_manager.h"
+#include "content/public/browser/ax_event_notification_details.h"
namespace content {
@@ -21,6 +28,8 @@ class CONTENT_EXPORT BrowserAccessibilityManagerMac
BrowserAccessibilityDelegate* delegate,
BrowserAccessibilityFactory* factory = new BrowserAccessibilityFactory());
+ ~BrowserAccessibilityManagerMac() override;
+
static ui::AXTreeUpdate GetEmptyDocument();
BrowserAccessibility* GetFocus() override;
@@ -29,9 +38,16 @@ class CONTENT_EXPORT BrowserAccessibilityManagerMac
void NotifyAccessibilityEvent(ui::AXEvent event_type,
BrowserAccessibility* node) override;
+ void OnAccessibilityEvents(
+ const std::vector<AXEventNotificationDetails>& details) override;
+
NSView* parent_view() { return parent_view_; }
private:
+ // AXTreeDelegate methods.
+ void OnNodeDataWillChange(ui::AXTree* tree,
+ const ui::AXNodeData& old_node_data,
+ const ui::AXNodeData& new_node_data) override;
void OnAtomicUpdateFinished(
ui::AXTree* tree,
bool root_changed,
@@ -40,12 +56,23 @@ class CONTENT_EXPORT BrowserAccessibilityManagerMac
// Returns an autoreleased object.
NSDictionary* GetUserInfoForSelectedTextChangedNotification();
+ // Returns an autoreleased object.
+ NSDictionary* GetUserInfoForValueChangedNotification(
+ const BrowserAccessibilityCocoa* native_node,
+ const base::string16& deleted_text,
+ const base::string16& inserted_text) const;
+
// This gives BrowserAccessibilityManager::Create access to the class
// constructor.
friend class BrowserAccessibilityManager;
NSView* parent_view_;
+ // Keeps track of any edits that have been made by the user during a tree
+ // update. Used by NSAccessibilityValueChangedNotification.
+ // Maps AXNode IDs to name or value attribute changes.
+ std::map<int32_t, base::string16> text_edits_;
+
DISALLOW_COPY_AND_ASSIGN(BrowserAccessibilityManagerMac);
};
diff --git a/content/browser/accessibility/browser_accessibility_manager_mac.mm b/content/browser/accessibility/browser_accessibility_manager_mac.mm
index 0df142e..48f8023 100644
--- a/content/browser/accessibility/browser_accessibility_manager_mac.mm
+++ b/content/browser/accessibility/browser_accessibility_manager_mac.mm
@@ -4,19 +4,19 @@
#include "content/browser/accessibility/browser_accessibility_manager_mac.h"
-#include <stddef.h>
-
#import "base/mac/mac_util.h"
#import "base/mac/sdk_forward_declarations.h"
#include "base/logging.h"
+#include "base/strings/sys_string_conversions.h"
+#include "base/strings/utf_string_conversions.h"
#import "content/browser/accessibility/browser_accessibility_cocoa.h"
#import "content/browser/accessibility/browser_accessibility_mac.h"
#include "content/common/accessibility_messages.h"
-
namespace {
-// Declare accessibility constants and enums only present in WebKit.
+// Declare undocumented accessibility constants and enums only present in
+// WebKit.
enum AXTextStateChangeType {
AXTextStateChangeTypeUnknown,
@@ -46,6 +46,17 @@ enum AXTextSelectionGranularity {
AXTextSelectionGranularityAll
};
+enum AXTextEditType {
+ AXTextEditTypeUnknown,
+ AXTextEditTypeDelete,
+ AXTextEditTypeInsert,
+ AXTextEditTypeTyping,
+ AXTextEditTypeDictation,
+ AXTextEditTypeCut,
+ AXTextEditTypePaste,
+ AXTextEditTypeAttributesChange
+};
+
NSString* const NSAccessibilityAutocorrectionOccurredNotification =
@"AXAutocorrectionOccurred";
NSString* const NSAccessibilityLayoutCompleteNotification =
@@ -59,7 +70,8 @@ NSString* const NSAccessibilityLiveRegionChangedNotification =
NSString* const NSAccessibilityMenuItemSelectedNotification =
@"AXMenuItemSelected";
-// Attributes used for NSAccessibilitySelectedTextChangedNotification.
+// Attributes used for NSAccessibilitySelectedTextChangedNotification and
+// NSAccessibilityValueChangedNotification.
NSString* const NSAccessibilityTextStateChangeTypeKey =
@"AXTextStateChangeType";
NSString* const NSAccessibilityTextStateSyncKey = @"AXTextStateSync";
@@ -72,6 +84,11 @@ NSString* const NSAccessibilityTextSelectionChangedFocus =
NSString* const NSAccessibilitySelectedTextMarkerRangeAttribute =
@"AXSelectedTextMarkerRange";
NSString* const NSAccessibilityTextChangeElement = @"AXTextChangeElement";
+NSString* const NSAccessibilityTextEditType = @"AXTextEditType";
+NSString* const NSAccessibilityTextChangeValue = @"AXTextChangeValue";
+NSString* const NSAccessibilityTextChangeValueLength =
+ @"AXTextChangeValueLength";
+NSString* const NSAccessibilityTextChangeValues = @"AXTextChangeValues";
} // namespace
@@ -96,6 +113,8 @@ BrowserAccessibilityManagerMac::BrowserAccessibilityManagerMac(
Initialize(initial_tree);
}
+BrowserAccessibilityManagerMac::~BrowserAccessibilityManagerMac() {}
+
// static
ui::AXTreeUpdate
BrowserAccessibilityManagerMac::GetEmptyDocument() {
@@ -186,7 +205,7 @@ void BrowserAccessibilityManagerMac::NotifyAccessibilityEvent(
// WebKit fires a notification both on the focused object and the root.
BrowserAccessibility* focus = GetFocus();
if (!focus)
- break;
+ break; // Just fire a notification on the root.
NSAccessibilityPostNotification(ToBrowserAccessibilityCocoa(focus),
mac_notification);
@@ -211,8 +230,32 @@ void BrowserAccessibilityManagerMac::NotifyAccessibilityEvent(
break;
}
case ui::AX_EVENT_CHECKED_STATE_CHANGED:
+ mac_notification = NSAccessibilityValueChangedNotification;
+ break;
case ui::AX_EVENT_VALUE_CHANGED:
mac_notification = NSAccessibilityValueChangedNotification;
+ if (base::mac::IsOSElCapitanOrLater() && text_edits_.size()) {
+ // It seems that we don't need to distinguish between deleted and
+ // inserted text for now.
+ base::string16 deleted_text;
+ base::string16 inserted_text;
+ int32_t id = node->GetId();
+ const auto iterator = text_edits_.find(id);
+ if (iterator != text_edits_.end())
+ inserted_text = iterator->second;
+ NSDictionary* user_info = GetUserInfoForValueChangedNotification(
+ native_node, deleted_text, inserted_text);
+
+ BrowserAccessibility* root = GetRoot();
+ if (!root)
+ return;
+
+ NSAccessibilityPostNotificationWithUserInfo(
+ native_node, mac_notification, user_info);
+ NSAccessibilityPostNotificationWithUserInfo(
+ ToBrowserAccessibilityCocoa(root), mac_notification, user_info);
+ return;
+ }
break;
// TODO(nektar): Need to add an event for live region created.
case ui::AX_EVENT_LIVE_REGION_CHANGED:
@@ -259,6 +302,61 @@ void BrowserAccessibilityManagerMac::NotifyAccessibilityEvent(
NSAccessibilityPostNotification(native_node, mac_notification);
}
+void BrowserAccessibilityManagerMac::OnAccessibilityEvents(
+ const std::vector<AXEventNotificationDetails>& details) {
+ BrowserAccessibilityManager::OnAccessibilityEvents(details);
+ text_edits_.clear();
+}
+
+void BrowserAccessibilityManagerMac::OnNodeDataWillChange(
+ ui::AXTree* tree,
+ const ui::AXNodeData& old_node_data,
+ const ui::AXNodeData& new_node_data) {
+ BrowserAccessibilityManager::OnNodeDataWillChange(tree, old_node_data,
+ new_node_data);
+
+ // Starting from OS X 10.11, if the user has edited some text we need to
+ // dispatch the actual text that changed on the value changed notification.
+ // We run this code on all OS X versions to get the highest test coverage.
+ base::string16 old_text, new_text;
+ ui::AXRole role = new_node_data.role;
+ if (role == ui::AX_ROLE_COMBO_BOX || role == ui::AX_ROLE_SEARCH_BOX ||
+ role == ui::AX_ROLE_TEXT_FIELD) {
+ old_text = old_node_data.GetString16Attribute(ui::AX_ATTR_VALUE);
+ new_text = new_node_data.GetString16Attribute(ui::AX_ATTR_VALUE);
+ } else if (new_node_data.state & (1 << ui::AX_STATE_EDITABLE)) {
+ old_text = old_node_data.GetString16Attribute(ui::AX_ATTR_NAME);
+ new_text = new_node_data.GetString16Attribute(ui::AX_ATTR_NAME);
+ }
+
+ if ((old_text.empty() && new_text.empty()) ||
+ old_text.length() == new_text.length()) {
+ return;
+ }
+
+ if (old_text.length() < new_text.length()) {
+ // Insertion.
+ size_t i = 0;
+ while (i < old_text.length() && i < new_text.length() &&
+ old_text[i] == new_text[i]) {
+ ++i;
+ }
+ size_t length = (new_text.length() - i) - (old_text.length() - i);
+ base::string16 inserted_text = new_text.substr(i, length);
+ text_edits_[new_node_data.id] = inserted_text;
+ } else {
+ // Deletion.
+ size_t i = 0;
+ while (i < old_text.length() && i < new_text.length() &&
+ old_text[i] == new_text[i]) {
+ ++i;
+ }
+ size_t length = (old_text.length() - i) - (new_text.length() - i);
+ base::string16 deleted_text = old_text.substr(i, length);
+ text_edits_[new_node_data.id] = deleted_text;
+ }
+}
+
void BrowserAccessibilityManagerMac::OnAtomicUpdateFinished(
ui::AXTree* tree,
bool root_changed,
@@ -296,23 +394,18 @@ void BrowserAccessibilityManagerMac::OnAtomicUpdateFinished(
}
}
-// Returns an autoreleased object.
NSDictionary* BrowserAccessibilityManagerMac::
GetUserInfoForSelectedTextChangedNotification() {
NSMutableDictionary* user_info = [[[NSMutableDictionary alloc] init]
autorelease];
- [user_info setObject:[NSNumber numberWithBool:YES]
- forKey:NSAccessibilityTextStateSyncKey];
- [user_info setObject:[NSNumber numberWithInt:AXTextStateChangeTypeUnknown]
+ [user_info setObject:@YES forKey:NSAccessibilityTextStateSyncKey];
+ [user_info setObject:@(AXTextStateChangeTypeUnknown)
forKey:NSAccessibilityTextStateChangeTypeKey];
- [user_info
- setObject:[NSNumber numberWithInt:AXTextSelectionDirectionUnknown]
- forKey:NSAccessibilityTextSelectionDirection];
- [user_info
- setObject:[NSNumber numberWithInt:AXTextSelectionGranularityUnknown]
- forKey:NSAccessibilityTextSelectionGranularity];
- [user_info setObject:[NSNumber numberWithBool:YES]
- forKey:NSAccessibilityTextSelectionChangedFocus];
+ [user_info setObject:@(AXTextSelectionDirectionUnknown)
+ forKey:NSAccessibilityTextSelectionDirection];
+ [user_info setObject:@(AXTextSelectionGranularityUnknown)
+ forKey:NSAccessibilityTextSelectionGranularity];
+ [user_info setObject:@YES forKey:NSAccessibilityTextSelectionChangedFocus];
int32_t focus_id = GetTreeData().sel_focus_object_id;
BrowserAccessibility* focus_object = GetFromID(focus_id);
@@ -330,4 +423,36 @@ NSDictionary* BrowserAccessibilityManagerMac::
return user_info;
}
+NSDictionary*
+BrowserAccessibilityManagerMac::GetUserInfoForValueChangedNotification(
+ const BrowserAccessibilityCocoa* native_node,
+ const base::string16& deleted_text,
+ const base::string16& inserted_text) const {
+ DCHECK(native_node);
+ if (deleted_text.empty() && inserted_text.empty())
+ return nil;
+
+ NSMutableArray* changes = [[[NSMutableArray alloc] init] autorelease];
+ if (!deleted_text.empty()) {
+ [changes addObject:@{
+ NSAccessibilityTextEditType : @(AXTextEditTypeUnknown),
+ NSAccessibilityTextChangeValueLength : @(deleted_text.length()),
+ NSAccessibilityTextChangeValue : base::SysUTF16ToNSString(deleted_text)
+ }];
+ }
+ if (!inserted_text.empty()) {
+ [changes addObject:@{
+ NSAccessibilityTextEditType : @(AXTextEditTypeUnknown),
+ NSAccessibilityTextChangeValueLength : @(inserted_text.length()),
+ NSAccessibilityTextChangeValue : base::SysUTF16ToNSString(inserted_text)
+ }];
+ }
+
+ return @{
+ NSAccessibilityTextStateChangeTypeKey : @(AXTextStateChangeTypeEdit),
+ NSAccessibilityTextChangeValues : changes,
+ NSAccessibilityTextChangeElement : native_node
+ };
+}
+
} // namespace content
diff --git a/content/browser/accessibility/browser_accessibility_manager_win.h b/content/browser/accessibility/browser_accessibility_manager_win.h
index 42c7da8..04b8aa2 100644
--- a/content/browser/accessibility/browser_accessibility_manager_win.h
+++ b/content/browser/accessibility/browser_accessibility_manager_win.h
@@ -58,7 +58,7 @@ class CONTENT_EXPORT BrowserAccessibilityManagerWin
void OnAccessibleHwndDeleted();
protected:
- // AXTree methods.
+ // AXTreeDelegate methods.
void OnNodeWillBeDeleted(ui::AXTree* tree, ui::AXNode* node) override;
void OnNodeCreated(ui::AXTree* tree, ui::AXNode* node) override;
void OnAtomicUpdateFinished(