summaryrefslogtreecommitdiff
path: root/chromium/ui/accessibility/platform
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@theqtcompany.com>2016-05-09 14:22:11 +0200
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2016-05-09 15:11:45 +0000
commit2ddb2d3e14eef3de7dbd0cef553d669b9ac2361c (patch)
treee75f511546c5fd1a173e87c1f9fb11d7ac8d1af3 /chromium/ui/accessibility/platform
parenta4f3d46271c57e8155ba912df46a05559d14726e (diff)
downloadqtwebengine-chromium-2ddb2d3e14eef3de7dbd0cef553d669b9ac2361c.tar.gz
BASELINE: Update Chromium to 51.0.2704.41
Also adds in all smaller components by reversing logic for exclusion. Change-Id: Ibf90b506e7da088ea2f65dcf23f2b0992c504422 Reviewed-by: Joerg Bornemann <joerg.bornemann@theqtcompany.com>
Diffstat (limited to 'chromium/ui/accessibility/platform')
-rw-r--r--chromium/ui/accessibility/platform/atk_util_auralinux.cc137
-rw-r--r--chromium/ui/accessibility/platform/atk_util_auralinux.h8
-rw-r--r--chromium/ui/accessibility/platform/ax_platform_node.cc42
-rw-r--r--chromium/ui/accessibility/platform/ax_platform_node.h14
-rw-r--r--chromium/ui/accessibility/platform/ax_platform_node_auralinux.cc5
-rw-r--r--chromium/ui/accessibility/platform/ax_platform_node_base.cc6
-rw-r--r--chromium/ui/accessibility/platform/ax_platform_node_mac.mm2
-rw-r--r--chromium/ui/accessibility/platform/ax_platform_node_win.cc94
-rw-r--r--chromium/ui/accessibility/platform/ax_platform_node_win.h28
-rw-r--r--chromium/ui/accessibility/platform/ax_platform_node_win_unittest.cc17
-rw-r--r--chromium/ui/accessibility/platform/test_ax_node_wrapper.cc3
11 files changed, 264 insertions, 92 deletions
diff --git a/chromium/ui/accessibility/platform/atk_util_auralinux.cc b/chromium/ui/accessibility/platform/atk_util_auralinux.cc
index 02563199409..46ad3be53be 100644
--- a/chromium/ui/accessibility/platform/atk_util_auralinux.cc
+++ b/chromium/ui/accessibility/platform/atk_util_auralinux.cc
@@ -8,7 +8,9 @@
#endif
#include <glib-2.0/gmodule.h>
+#include "base/bind.h"
#include "base/files/file_path.h"
+#include "base/location.h"
#include "base/logging.h"
#include "base/memory/singleton.h"
#include "ui/accessibility/platform/atk_util_auralinux.h"
@@ -16,41 +18,42 @@
namespace {
-#if defined(USE_GCONF)
+typedef void (*gnome_accessibility_module_init)();
-const char kGnomeAccessibilityEnabledKey[] =
- "/desktop/gnome/interface/accessibility";
+const char kAtkBridgePath[] = "gtk-2.0/modules/libatk-bridge.so";
+const char kAtkBridgeSymbolName[] = "gnome_accessibility_module_init";
-bool ShouldEnableAccessibility() {
- GConfClient* client = gconf_client_get_default();
- if (!client) {
- LOG(ERROR) << "gconf_client_get_default failed";
+gnome_accessibility_module_init g_accessibility_module_init = nullptr;
+
+bool AccessibilityModuleInitOnFileThread() {
+ // Try to load libatk-bridge.so.
+ base::FilePath atk_bridge_path(ATK_LIB_DIR);
+ atk_bridge_path = atk_bridge_path.Append(kAtkBridgePath);
+ GModule* bridge = g_module_open(atk_bridge_path.value().c_str(),
+ static_cast<GModuleFlags>(0));
+ if (!bridge) {
+ VLOG(1) << "Unable to open module " << atk_bridge_path.value();
return false;
}
- GError* error = nullptr;
- gboolean value = gconf_client_get_bool(client,
- kGnomeAccessibilityEnabledKey,
- &error);
- if (error) {
- VLOG(1) << "gconf_client_get_bool failed";
- g_error_free(error);
- g_object_unref(client);
+ if (!g_module_symbol(bridge, kAtkBridgeSymbolName,
+ (gpointer *)&g_accessibility_module_init)) {
+ VLOG(1) << "Unable to get symbol pointer from " << atk_bridge_path.value();
+ // Just to make sure it's null;
+ g_accessibility_module_init = nullptr;
return false;
}
- g_object_unref(client);
- return value;
+ return true;
}
-#else // !defined(USE_GCONF)
+#if defined(USE_GCONF)
-bool ShouldEnableAccessibility() {
- // TODO(k.czech): implement this for non-GNOME desktops.
- return false;
-}
+const char kAccessibilityEnabled[] = "ACCESSIBILITY_ENABLED";
+const char kGnomeAccessibilityEnabledKey[] =
+ "/desktop/gnome/interface/accessibility";
-#endif // defined(USE_GCONF)
+#endif
} // namespace
@@ -139,44 +142,88 @@ AtkUtilAuraLinux* AtkUtilAuraLinux::GetInstance() {
return base::Singleton<AtkUtilAuraLinux>::get();
}
+#if defined(USE_GCONF)
+
+AtkUtilAuraLinux::AtkUtilAuraLinux()
+ : is_enabled_(false) {
+}
+
+#else
+
AtkUtilAuraLinux::AtkUtilAuraLinux() {
}
+#endif // defined(USE_GCONF)
+
void AtkUtilAuraLinux::Initialize(
- scoped_refptr<base::TaskRunner> /* init_task_runner */) {
- // TODO(k.czech): use |init_task_runner| to post a task to do the
- // initialization rather than doing it on this thread.
- // http://crbug.com/468112
+ scoped_refptr<base::TaskRunner> init_task_runner) {
// Register our util class.
g_type_class_unref(g_type_class_ref(ATK_UTIL_AURALINUX_TYPE));
- if (!ShouldEnableAccessibility()) {
- VLOG(1) << "Will not enable ATK accessibility support.";
- return;
+ init_task_runner->PostTaskAndReply(
+ FROM_HERE,
+ base::Bind(
+ &AtkUtilAuraLinux::CheckIfAccessibilityIsEnabledOnFileThread,
+ base::Unretained(this)),
+ base::Bind(
+ &AtkUtilAuraLinux::FinishAccessibilityInitOnUIThread,
+ base::Unretained(this)));
+}
+
+AtkUtilAuraLinux::~AtkUtilAuraLinux() {
+}
+
+#if defined(USE_GCONF)
+
+void AtkUtilAuraLinux::CheckIfAccessibilityIsEnabledOnFileThread() {
+ char* enable_accessibility = getenv(kAccessibilityEnabled);
+ if ((enable_accessibility && atoi(enable_accessibility) == 1) ||
+ CheckPlatformAccessibilitySupportOnFileThread())
+ is_enabled_ = AccessibilityModuleInitOnFileThread();
+}
+
+bool AtkUtilAuraLinux::CheckPlatformAccessibilitySupportOnFileThread() {
+ GConfClient* client = gconf_client_get_default();
+ if (!client) {
+ LOG(ERROR) << "gconf_client_get_default failed";
+ return false;
}
- VLOG(1) << "Enabling ATK accessibility support.";
+ GError* error = nullptr;
+ bool is_enabled = gconf_client_get_bool(client,
+ kGnomeAccessibilityEnabledKey,
+ &error);
- // Try to load libatk-bridge.so.
- base::FilePath atk_bridge_path(ATK_LIB_DIR);
- atk_bridge_path = atk_bridge_path.Append("gtk-2.0/modules/libatk-bridge.so");
- GModule* bridge = g_module_open(atk_bridge_path.value().c_str(),
- static_cast<GModuleFlags>(0));
- if (!bridge) {
- VLOG(1) << "Unable to open module " << atk_bridge_path.value();
- return;
+ g_object_unref(client);
+
+ if (error) {
+ VLOG(1) << "gconf_client_get_bool failed";
+ g_error_free(error);
+ return false;
}
- // Try to call gnome_accessibility_module_init from libatk-bridge.so.
- void (*gnome_accessibility_module_init)();
- if (g_module_symbol(bridge, "gnome_accessibility_module_init",
- (gpointer *)&gnome_accessibility_module_init)) {
- (*gnome_accessibility_module_init)();
+ return is_enabled;
+}
+
+void AtkUtilAuraLinux::FinishAccessibilityInitOnUIThread() {
+ if (!is_enabled_) {
+ VLOG(1) << "Will not enable ATK accessibility support.";
+ return;
}
+
+ DCHECK(g_accessibility_module_init);
+ g_accessibility_module_init();
}
-AtkUtilAuraLinux::~AtkUtilAuraLinux() {
+#else
+
+void AtkUtilAuraLinux::CheckIfAccessibilityIsEnabledOnFileThread() {
+}
+
+void AtkUtilAuraLinux::FinishAccessibilityInitOnUIThread() {
}
+#endif // defined(USE_GCONF)
+
} // namespace ui
diff --git a/chromium/ui/accessibility/platform/atk_util_auralinux.h b/chromium/ui/accessibility/platform/atk_util_auralinux.h
index a5bc75d9311..8342a1299c7 100644
--- a/chromium/ui/accessibility/platform/atk_util_auralinux.h
+++ b/chromium/ui/accessibility/platform/atk_util_auralinux.h
@@ -29,6 +29,14 @@ class AtkUtilAuraLinux {
private:
friend struct base::DefaultSingletonTraits<AtkUtilAuraLinux>;
+
+ void CheckIfAccessibilityIsEnabledOnFileThread();
+ bool CheckPlatformAccessibilitySupportOnFileThread();
+ void FinishAccessibilityInitOnUIThread();
+
+#if defined(USE_GCONF)
+ bool is_enabled_;
+#endif
};
} // namespace ui
diff --git a/chromium/ui/accessibility/platform/ax_platform_node.cc b/chromium/ui/accessibility/platform/ax_platform_node.cc
index 8f889458ddb..adfcc1e2ad2 100644
--- a/chromium/ui/accessibility/platform/ax_platform_node.cc
+++ b/chromium/ui/accessibility/platform/ax_platform_node.cc
@@ -4,12 +4,23 @@
#include "ui/accessibility/platform/ax_platform_node.h"
+#include "base/containers/hash_tables.h"
+#include "base/lazy_instance.h"
#include "build/build_config.h"
#include "ui/accessibility/ax_node_data.h"
#include "ui/accessibility/platform/ax_platform_node_delegate.h"
namespace ui {
+namespace {
+
+using UniqueIdMap = base::hash_map<int32_t, AXPlatformNode*>;
+// Map from each AXPlatformNode's unique id to its instance.
+base::LazyInstance<UniqueIdMap> g_unique_id_map =
+ LAZY_INSTANCE_INITIALIZER;
+
+}
+
#if !defined(PLATFORM_HAS_AX_PLATFORM_NODE_IMPL)
// static
AXPlatformNode* AXPlatformNode::Create(AXPlatformNodeDelegate* delegate) {
@@ -28,10 +39,39 @@ AXPlatformNode* AXPlatformNode::FromNativeViewAccessible(
}
#endif
-AXPlatformNode::AXPlatformNode() {
+// static
+int32_t AXPlatformNode::GetNextUniqueId() {
+ static int32_t next_unique_id = 1;
+ int32_t unique_id = next_unique_id;
+ if (next_unique_id == INT32_MAX)
+ next_unique_id = 1;
+ else
+ next_unique_id++;
+
+ return unique_id;
+}
+
+AXPlatformNode::AXPlatformNode() : unique_id_(GetNextUniqueId()) {
+ g_unique_id_map.Get()[unique_id_] = this;
}
AXPlatformNode::~AXPlatformNode() {
+ if (unique_id_)
+ g_unique_id_map.Get().erase(unique_id_);
+}
+
+void AXPlatformNode::Destroy() {
+ g_unique_id_map.Get().erase(unique_id_);
+ unique_id_ = 0;
+}
+
+AXPlatformNode* AXPlatformNode::GetFromUniqueId(int32_t unique_id) {
+ UniqueIdMap* unique_ids = g_unique_id_map.Pointer();
+ auto iter = unique_ids->find(unique_id);
+ if (iter != unique_ids->end())
+ return iter->second;
+
+ return nullptr;
}
} // namespace ui
diff --git a/chromium/ui/accessibility/platform/ax_platform_node.h b/chromium/ui/accessibility/platform/ax_platform_node.h
index 1d0ed510b38..c9df25947dd 100644
--- a/chromium/ui/accessibility/platform/ax_platform_node.h
+++ b/chromium/ui/accessibility/platform/ax_platform_node.h
@@ -46,9 +46,17 @@ class AX_EXPORT AXPlatformNode {
static AXPlatformNode* FromNativeViewAccessible(
gfx::NativeViewAccessible accessible);
+ // Each platform accessibility object has a unique id that's guaranteed
+ // to be a positive number. (It's stored in an int32_t as opposed to
+ // uint32_t because some platforms want to negate it, so we want to ensure
+ // the range is below the signed int max.) This can be used when the
+ // id has to be unique across multiple frames, since node ids are
+ // only unique within one tree.
+ static int32_t GetNextUniqueId();
+
// Call Destroy rather than deleting this, because the subclass may
// use reference counting.
- virtual void Destroy() = 0;
+ virtual void Destroy();
// Get the platform-specific accessible object type for this instance.
// On some platforms this is just a type cast, on others it may be a
@@ -65,6 +73,10 @@ class AX_EXPORT AXPlatformNode {
protected:
AXPlatformNode();
virtual ~AXPlatformNode();
+
+ AXPlatformNode* GetFromUniqueId(int32_t unique_id);
+
+ int32_t unique_id_;
};
} // namespace ui
diff --git a/chromium/ui/accessibility/platform/ax_platform_node_auralinux.cc b/chromium/ui/accessibility/platform/ax_platform_node_auralinux.cc
index 801c3473e66..04e96c02ba5 100644
--- a/chromium/ui/accessibility/platform/ax_platform_node_auralinux.cc
+++ b/chromium/ui/accessibility/platform/ax_platform_node_auralinux.cc
@@ -448,14 +448,15 @@ void AXPlatformNodeAuraLinux::GetAtkState(AtkStateSet* atk_state_set) {
atk_state_set_add_state(atk_state_set, ATK_STATE_EXPANDED);
if (state & (1 << ui::AX_STATE_FOCUSABLE))
atk_state_set_add_state(atk_state_set, ATK_STATE_FOCUSABLE);
- if (state & (1 << ui::AX_STATE_FOCUSED))
- atk_state_set_add_state(atk_state_set, ATK_STATE_FOCUSED);
if (state & (1 << ui::AX_STATE_PRESSED))
atk_state_set_add_state(atk_state_set, ATK_STATE_PRESSED);
if (state & (1 << ui::AX_STATE_SELECTABLE))
atk_state_set_add_state(atk_state_set, ATK_STATE_SELECTABLE);
if (state & (1 << ui::AX_STATE_SELECTED))
atk_state_set_add_state(atk_state_set, ATK_STATE_SELECTED);
+
+ if (delegate_->GetFocus() == GetNativeViewAccessible())
+ atk_state_set_add_state(atk_state_set, ATK_STATE_FOCUSED);
}
void AXPlatformNodeAuraLinux::GetAtkRelations(AtkRelationSet* atk_relation_set)
diff --git a/chromium/ui/accessibility/platform/ax_platform_node_base.cc b/chromium/ui/accessibility/platform/ax_platform_node_base.cc
index 2c1bf90507d..4937e4d3178 100644
--- a/chromium/ui/accessibility/platform/ax_platform_node_base.cc
+++ b/chromium/ui/accessibility/platform/ax_platform_node_base.cc
@@ -44,6 +44,7 @@ gfx::NativeViewAccessible AXPlatformNodeBase::ChildAtIndex(int index) {
// AXPlatformNode overrides.
void AXPlatformNodeBase::Destroy() {
+ AXPlatformNode::Destroy();
delegate_ = nullptr;
delete this;
}
@@ -92,7 +93,10 @@ bool AXPlatformNodeBase::IsDescendant(AXPlatformNodeBase* node) {
return false;
if (node == this)
return true;
- AXPlatformNodeBase* parent = FromNativeViewAccessible(node->GetParent());
+ gfx::NativeViewAccessible native_parent = node->GetParent();
+ if (!native_parent)
+ return false;
+ AXPlatformNodeBase* parent = FromNativeViewAccessible(native_parent);
return IsDescendant(parent);
}
diff --git a/chromium/ui/accessibility/platform/ax_platform_node_mac.mm b/chromium/ui/accessibility/platform/ax_platform_node_mac.mm
index a4384f9ac77..c4b54d421bd 100644
--- a/chromium/ui/accessibility/platform/ax_platform_node_mac.mm
+++ b/chromium/ui/accessibility/platform/ax_platform_node_mac.mm
@@ -24,6 +24,7 @@ typedef std::map<ui::AXRole, NSString*> RoleMap;
RoleMap BuildRoleMap() {
const MapEntry roles[] = {
+ {ui::AX_ROLE_ABBR, NSAccessibilityGroupRole},
{ui::AX_ROLE_ALERT, NSAccessibilityGroupRole},
{ui::AX_ROLE_ALERT_DIALOG, NSAccessibilityGroupRole},
{ui::AX_ROLE_ANNOTATION, NSAccessibilityUnknownRole},
@@ -55,6 +56,7 @@ RoleMap BuildRoleMap() {
{ui::AX_ROLE_DISCLOSURE_TRIANGLE, NSAccessibilityDisclosureTriangleRole},
{ui::AX_ROLE_DIV, NSAccessibilityGroupRole},
{ui::AX_ROLE_DOCUMENT, NSAccessibilityGroupRole},
+ {ui::AX_ROLE_EMBEDDED_OBJECT, NSAccessibilityGroupRole},
{ui::AX_ROLE_FIGCAPTION, NSAccessibilityGroupRole},
{ui::AX_ROLE_FIGURE, NSAccessibilityGroupRole},
{ui::AX_ROLE_FOOTER, NSAccessibilityGroupRole},
diff --git a/chromium/ui/accessibility/platform/ax_platform_node_win.cc b/chromium/ui/accessibility/platform/ax_platform_node_win.cc
index ee7a4f9f8c6..c8f7d5445c3 100644
--- a/chromium/ui/accessibility/platform/ax_platform_node_win.cc
+++ b/chromium/ui/accessibility/platform/ax_platform_node_win.cc
@@ -78,35 +78,36 @@ namespace ui {
namespace {
-typedef base::hash_map<LONG, AXPlatformNodeWin*> UniqueIdWinMap;
-// Map from each AXPlatformNodeWin's unique id to its instance.
-base::LazyInstance<UniqueIdWinMap> g_unique_id_win_map =
- LAZY_INSTANCE_INITIALIZER;
-
typedef base::hash_set<AXPlatformNodeWin*> AXPlatformNodeWinSet;
// Set of all AXPlatformNodeWin objects that were the target of an
// alert event.
base::LazyInstance<AXPlatformNodeWinSet> g_alert_targets =
LAZY_INSTANCE_INITIALIZER;
-LONG GetNextNegativeUniqueIdForWinAccessibility(AXPlatformNodeWin* obj) {
- static LONG next_unique_id = -1;
- LONG unique_id = next_unique_id;
- if (next_unique_id == LONG_MIN)
- next_unique_id = -1;
- else
- next_unique_id--;
+base::LazyInstance<base::ObserverList<IAccessible2UsageObserver>>
+ g_iaccessible2_usage_observer_list = LAZY_INSTANCE_INITIALIZER;
+
+} // namespace
- g_unique_id_win_map.Get().insert(std::make_pair(unique_id, obj));
+//
+// IAccessible2UsageObserver
+//
- return unique_id;
+IAccessible2UsageObserver::IAccessible2UsageObserver() {
}
-void UnregisterNegativeUniqueId(LONG unique_id) {
- g_unique_id_win_map.Get().erase(unique_id);
+IAccessible2UsageObserver::~IAccessible2UsageObserver() {
}
-} // namespace
+// static
+base::ObserverList<IAccessible2UsageObserver>&
+ GetIAccessible2UsageObserverList() {
+ return g_iaccessible2_usage_observer_list.Get();
+}
+
+//
+// AXPlatformNode::Create
+//
// static
AXPlatformNode* AXPlatformNode::Create(AXPlatformNodeDelegate* delegate) {
@@ -129,8 +130,11 @@ AXPlatformNode* AXPlatformNode::FromNativeViewAccessible(
return ax_platform_node.get();
}
-AXPlatformNodeWin::AXPlatformNodeWin()
- : unique_id_win_(GetNextNegativeUniqueIdForWinAccessibility(this)) {
+//
+// AXPlatformNodeWin
+//
+
+AXPlatformNodeWin::AXPlatformNodeWin() {
}
AXPlatformNodeWin::~AXPlatformNodeWin() {
@@ -143,7 +147,6 @@ AXPlatformNodeWin::~AXPlatformNodeWin() {
void AXPlatformNodeWin::Destroy() {
delegate_ = nullptr;
- UnregisterNegativeUniqueId(unique_id_win_);
RemoveAlertTarget();
Release();
}
@@ -157,11 +160,17 @@ void AXPlatformNodeWin::NotifyAccessibilityEvent(ui::AXEvent event_type) {
if (!hwnd)
return;
+ // Menu items fire selection events but Windows screen readers work reliably
+ // with focus events. Remap here.
+ if (event_type == ui::AX_EVENT_SELECTION &&
+ GetData().role == ui::AX_ROLE_MENU_ITEM)
+ event_type = ui::AX_EVENT_FOCUS;
+
int native_event = MSAAEvent(event_type);
if (native_event < EVENT_MIN)
return;
- ::NotifyWinEvent(native_event, hwnd, OBJID_CLIENT, unique_id_win_);
+ ::NotifyWinEvent(native_event, hwnd, OBJID_CLIENT, -unique_id_);
// Keep track of objects that are a target of an alert event.
if (event_type == ui::AX_EVENT_ALERT)
@@ -324,25 +333,28 @@ STDMETHODIMP AXPlatformNodeWin::get_accChild(VARIANT var_child,
// that want to enumerate all immediate children.
*disp_child = delegate_->ChildAtIndex(child_id - 1);
if (!(*disp_child))
- return E_FAIL;
+ return E_INVALIDARG;
(*disp_child)->AddRef();
return S_OK;
}
if (child_id >= 0)
- return E_FAIL;
+ return E_INVALIDARG;
// Negative child ids can be used to map to any descendant.
- UniqueIdWinMap* unique_ids = g_unique_id_win_map.Pointer();
- auto iter = unique_ids->find(child_id);
- if (iter != unique_ids->end()) {
- *disp_child = iter->second;
+ AXPlatformNodeWin* child = static_cast<AXPlatformNodeWin*>(
+ GetFromUniqueId(-child_id));
+ if (child && !IsDescendant(child))
+ child = nullptr;
+
+ if (child) {
+ *disp_child = child;
(*disp_child)->AddRef();
return S_OK;
}
*disp_child = nullptr;
- return E_FAIL;
+ return E_INVALIDARG;
}
STDMETHODIMP AXPlatformNodeWin::get_accChildCount(LONG* child_count) {
@@ -498,7 +510,7 @@ STDMETHODIMP AXPlatformNodeWin::get_states(AccessibleStates* states) {
STDMETHODIMP AXPlatformNodeWin::get_uniqueID(LONG* unique_id) {
COM_OBJECT_VALIDATE_1_ARG(unique_id);
- *unique_id = unique_id_win_;
+ *unique_id = -unique_id_;
return S_OK;
}
@@ -876,6 +888,13 @@ STDMETHODIMP AXPlatformNodeWin::scrollSubstringToPoint(
STDMETHODIMP AXPlatformNodeWin::QueryService(
REFGUID guidService, REFIID riid, void** object) {
COM_OBJECT_VALIDATE_1_ARG(object);
+
+ if (riid == IID_IAccessible2) {
+ FOR_EACH_OBSERVER(IAccessible2UsageObserver,
+ GetIAccessible2UsageObserverList(),
+ OnIAccessible2Used());
+ }
+
if (guidService == IID_IAccessible ||
guidService == IID_IAccessible2 ||
guidService == IID_IAccessible2_2 ||
@@ -982,8 +1001,6 @@ int AXPlatformNodeWin::MSAAState() {
msaa_state |= STATE_SYSTEM_EXPANDED;
if (state & (1 << ui::AX_STATE_FOCUSABLE))
msaa_state |= STATE_SYSTEM_FOCUSABLE;
- if (state & (1 << ui::AX_STATE_FOCUSED))
- msaa_state |= STATE_SYSTEM_FOCUSED;
if (state & (1 << ui::AX_STATE_HASPOPUP))
msaa_state |= STATE_SYSTEM_HASPOPUP;
if (state & (1 << ui::AX_STATE_HOVERED))
@@ -1007,6 +1024,21 @@ int AXPlatformNodeWin::MSAAState() {
if (state & (1 << ui::AX_STATE_DISABLED))
msaa_state |= STATE_SYSTEM_UNAVAILABLE;
+ gfx::NativeViewAccessible focus = delegate_->GetFocus();
+ if (focus == GetNativeViewAccessible())
+ msaa_state |= STATE_SYSTEM_FOCUSED;
+
+ // On Windows, the "focus" bit should be set on certain containers, like
+ // menu bars, when visible.
+ //
+ // TODO(dmazzoni): this should probably check if focus is actually inside
+ // the menu bar, but we don't currently track focus inside menu pop-ups,
+ // and Chrome only has one menu visible at a time so this works for now.
+ if (GetData().role == ui::AX_ROLE_MENU_BAR &&
+ !(state & (1 << ui::AX_STATE_INVISIBLE))) {
+ msaa_state |= STATE_SYSTEM_FOCUSED;
+ }
+
return msaa_state;
}
diff --git a/chromium/ui/accessibility/platform/ax_platform_node_win.h b/chromium/ui/accessibility/platform/ax_platform_node_win.h
index 5d264211b34..eb747ed4d0b 100644
--- a/chromium/ui/accessibility/platform/ax_platform_node_win.h
+++ b/chromium/ui/accessibility/platform/ax_platform_node_win.h
@@ -9,11 +9,29 @@
#include <atlcom.h>
#include <oleacc.h>
+#include "base/observer_list.h"
#include "third_party/iaccessible2/ia2_api_all.h"
+#include "ui/accessibility/ax_export.h"
+#include "ui/accessibility/ax_text_utils.h"
#include "ui/accessibility/platform/ax_platform_node_base.h"
namespace ui {
+// A simple interface for a class that wants to be notified when IAccessible2
+// is used by a client, a strong indication that full accessibility support
+// should be enabled.
+class AX_EXPORT IAccessible2UsageObserver {
+ public:
+ IAccessible2UsageObserver();
+ virtual ~IAccessible2UsageObserver();
+ virtual void OnIAccessible2Used() = 0;
+};
+
+// Get an observer list that allows modules across the codebase to
+// listen to when usage of IAccessible2 is detected.
+extern AX_EXPORT base::ObserverList<IAccessible2UsageObserver>&
+ GetIAccessible2UsageObserverList();
+
class __declspec(uuid("26f5641a-246d-457b-a96d-07f3fae6acf2"))
AXPlatformNodeWin
: public CComObjectRootEx<CComMultiThreadModel>,
@@ -279,16 +297,6 @@ AXPlatformNodeWin
IA2TextBoundaryType ia2_boundary,
LONG start_offset,
ui::TextBoundaryDirection direction);
-
- // A windows-specific unique ID for this object. It's returned in
- // IAccessible2::get_uniqueID, but more importantly it's used for
- // firing events. On Windows, we fire events on the nearest parent HWND
- // and pass the unique ID as the child id parameter. When the client
- // wants to retrieve the object the event was fired on, it calls
- // get_accChild and passes the child ID. We use negative IDs for the unique
- // ID so we can distinguish a request for an arbitrary child from a request
- // for an immediate child of an object by its 0-based index.
- LONG unique_id_win_;
};
} // namespace ui
diff --git a/chromium/ui/accessibility/platform/ax_platform_node_win_unittest.cc b/chromium/ui/accessibility/platform/ax_platform_node_win_unittest.cc
index 08be59b21f1..d5a4f81e501 100644
--- a/chromium/ui/accessibility/platform/ax_platform_node_win_unittest.cc
+++ b/chromium/ui/accessibility/platform/ax_platform_node_win_unittest.cc
@@ -315,7 +315,8 @@ TEST_F(AXPlatformNodeWinTest, TestIAccessibleChildAndParent) {
// Asking for child id 3 should fail.
ScopedComPtr<IDispatch> result;
ScopedVariant child3(3);
- ASSERT_EQ(E_FAIL, root_iaccessible->get_accChild(child3, result.Receive()));
+ ASSERT_EQ(E_INVALIDARG,
+ root_iaccessible->get_accChild(child3, result.Receive()));
}
// We should be able to ask for the button by its unique id too.
@@ -332,6 +333,20 @@ TEST_F(AXPlatformNodeWinTest, TestIAccessibleChildAndParent) {
ASSERT_EQ(result.get(), button_iaccessible);
}
+ // We shouldn't be able to ask for the root node by its unique ID
+ // from one of its children, though.
+ LONG root_unique_id;
+ ScopedComPtr<IAccessible2> root_iaccessible2 =
+ ToIAccessible2(root_iaccessible);
+ root_iaccessible2->get_uniqueID(&root_unique_id);
+ ASSERT_LT(root_unique_id, 0);
+ {
+ ScopedComPtr<IDispatch> result;
+ ScopedVariant root_id_variant(root_unique_id);
+ ASSERT_EQ(E_INVALIDARG, button_iaccessible->get_accChild(root_id_variant,
+ result.Receive()));
+ }
+
// Now check parents.
{
ScopedComPtr<IDispatch> result;
diff --git a/chromium/ui/accessibility/platform/test_ax_node_wrapper.cc b/chromium/ui/accessibility/platform/test_ax_node_wrapper.cc
index fbb76ca13be..f2b91731aa4 100644
--- a/chromium/ui/accessibility/platform/test_ax_node_wrapper.cc
+++ b/chromium/ui/accessibility/platform/test_ax_node_wrapper.cc
@@ -18,6 +18,9 @@ gfx::Vector2d g_offset;
// A simple implementation of AXTreeDelegate to catch when AXNodes are
// deleted so we can delete their wrappers.
class TestAXTreeDelegate : public AXTreeDelegate {
+ void OnNodeDataWillChange(AXTree* tree,
+ const AXNodeData& old_node_data,
+ const AXNodeData& new_node_data) override {}
void OnTreeDataChanged(AXTree* tree) override {}
void OnNodeWillBeDeleted(AXTree* tree, AXNode* node) override {
auto iter = g_node_to_wrapper_map.find(node);