a11y: Enable accessibility on auralinux when API calls are made

This change introduces a mechanism to enable accessibility (on
auralinux) by creating the kApplication node and waiting until there
is a API query to enable accessibility fully. This is done to ensure
chromium will avoid performance overhead for users who don't need
accessibility, by not creating ATKObjects when they are not being
used.

Accessibility is enabled when one of two conditions are met:

1. A client queries an ATKObject API.
2. An AXMode is set on AccessibilityNotificationWaiter (used during
   testing).

This is implemented by using AXMode set on the AXPlatformNode, when
this is set it will allow for all ATK objects to be created. This
change does not remove the need to specify environmental variables and
the commandline flag.

The original author of this patch is Jessica Tallon<jtallon@igalia.com>

Bug: 977112
Change-Id: Ie5e46347296507d214df345320d3d58c9921c84d
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2060359
Reviewed-by: Scott Violet <sky@chromium.org>
Reviewed-by: Dominic Mazzoni <dmazzoni@chromium.org>
Commit-Queue: Julie Kim <jkim@igalia.com>
Cr-Commit-Position: refs/heads/master@{#744905}
diff --git a/chrome/browser/accessibility/accessibility_ui.cc b/chrome/browser/accessibility/accessibility_ui.cc
index c117f788..c77a24e89 100644
--- a/chrome/browser/accessibility/accessibility_ui.cc
+++ b/chrome/browser/accessibility/accessibility_ui.cc
@@ -555,6 +555,8 @@
   // because we are about to show the accessibility tree
   web_contents->SetAccessibilityMode(
       ui::AXMode(ui::AXMode::kNativeAPIs | ui::AXMode::kWebContents));
+  // Enable AXMode to access to AX objects.
+  ui::AXPlatformNode::NotifyAddAXModeFlags(ui::kAXModeComplete);
 
   std::vector<content::AccessibilityTreeFormatter::PropertyFilter>
       property_filters;
diff --git a/chrome/browser/autofill/autofill_browsertest.cc b/chrome/browser/autofill/autofill_browsertest.cc
index c03c109..58b4eff 100644
--- a/chrome/browser/autofill/autofill_browsertest.cc
+++ b/chrome/browser/autofill/autofill_browsertest.cc
@@ -39,6 +39,7 @@
 #include "components/autofill/core/browser/personal_data_manager_observer.h"
 #include "components/autofill/core/browser/validation.h"
 #include "components/autofill/core/common/autofill_features.h"
+#include "content/public/browser/browser_accessibility_state.h"
 #include "content/public/browser/navigation_controller.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/test/accessibility_notification_waiter.h"
@@ -589,6 +590,8 @@
 
 // Test that autofill available state is correctly set on accessibility node.
 IN_PROC_BROWSER_TEST_F(AutofillAccessibilityTest, TestAutofillState) {
+  content::BrowserAccessibilityState::GetInstance()->EnableAccessibility();
+
   // Navigate to url.
   GURL url =
       embedded_test_server()->GetURL("/autofill/duplicate_profiles_test.html");
@@ -596,10 +599,9 @@
   params.disposition = WindowOpenDisposition::NEW_FOREGROUND_TAB;
   ui_test_utils::NavigateToURL(&params);
 
-  // Enable accessibility.
-  content::EnableAccessibilityForWebContents(web_contents());
+  // Wait for accessibility notification.
   content::AccessibilityNotificationWaiter layout_waiter_one(
-      web_contents(), ui::kAXModeComplete, ax::mojom::Event::kLayoutComplete);
+      web_contents(), ui::kAXModeComplete, ax::mojom::Event::kLoadComplete);
   layout_waiter_one.WaitForNotification();
 
   // Focus target form field.
@@ -639,7 +641,7 @@
   // Reload page.
   ui_test_utils::NavigateToURL(&params);
   content::AccessibilityNotificationWaiter layout_waiter_two(
-      web_contents(), ui::kAXModeComplete, ax::mojom::Event::kLayoutComplete);
+      web_contents(), ui::kAXModeComplete, ax::mojom::Event::kLoadComplete);
   layout_waiter_two.WaitForNotification();
 
   // Focus target form field.
@@ -661,6 +663,7 @@
 // accessibility node. Test autocomplete in this file since it uses the same
 // infrastructure as autofill.
 IN_PROC_BROWSER_TEST_F(AutofillAccessibilityTest, TestAutocompleteState) {
+  content::BrowserAccessibilityState::GetInstance()->EnableAccessibility();
   // Navigate to url.
   GURL url =
       embedded_test_server()->GetURL("/autofill/duplicate_profiles_test.html");
@@ -668,10 +671,9 @@
   params.disposition = WindowOpenDisposition::NEW_FOREGROUND_TAB;
   ui_test_utils::NavigateToURL(&params);
 
-  // Enable accessibility.
-  content::EnableAccessibilityForWebContents(web_contents());
+  // Wait for accessibility notification.
   content::AccessibilityNotificationWaiter layout_waiter_one(
-      web_contents(), ui::kAXModeComplete, ax::mojom::Event::kLayoutComplete);
+      web_contents(), ui::kAXModeComplete, ax::mojom::Event::kLoadComplete);
   layout_waiter_one.WaitForNotification();
 
   // Focus target form field.
@@ -707,7 +709,7 @@
   // Reload page.
   ui_test_utils::NavigateToURL(&params);
   content::AccessibilityNotificationWaiter layout_waiter_two(
-      web_contents(), ui::kAXModeComplete, ax::mojom::Event::kLayoutComplete);
+      web_contents(), ui::kAXModeComplete, ax::mojom::Event::kLoadComplete);
   layout_waiter_two.WaitForNotification();
 
   // Focus target form field.
diff --git a/chrome/browser/ui/views/accessibility/browser_accessibility_uitest_auralinux.cc b/chrome/browser/ui/views/accessibility/browser_accessibility_uitest_auralinux.cc
index b588061..78f9c7a5 100644
--- a/chrome/browser/ui/views/accessibility/browser_accessibility_uitest_auralinux.cc
+++ b/chrome/browser/ui/views/accessibility/browser_accessibility_uitest_auralinux.cc
@@ -11,10 +11,17 @@
 #include "chrome/browser/ui/views/frame/browser_view.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "content/public/browser/render_widget_host_view.h"
+#include "ui/accessibility/platform/ax_platform_node.h"
 
 class AuraLinuxAccessibilityInProcessBrowserTest : public InProcessBrowserTest {
+ public:
+  void SetUp() override {
+    ui::AXPlatformNode::NotifyAddAXModeFlags(ui::kAXModeComplete);
+    InProcessBrowserTest::SetUp();
+  }
+
  protected:
-  AuraLinuxAccessibilityInProcessBrowserTest() {}
+  AuraLinuxAccessibilityInProcessBrowserTest() = default;
 
   void VerifyEmbedRelationships();
 
diff --git a/content/browser/accessibility/browser_accessibility_auralinux_unittest.cc b/content/browser/accessibility/browser_accessibility_auralinux_unittest.cc
index 0979395..6ba656b 100644
--- a/content/browser/accessibility/browser_accessibility_auralinux_unittest.cc
+++ b/content/browser/accessibility/browser_accessibility_auralinux_unittest.cc
@@ -34,11 +34,14 @@
   DISALLOW_COPY_AND_ASSIGN(BrowserAccessibilityAuraLinuxTest);
 };
 
-BrowserAccessibilityAuraLinuxTest::BrowserAccessibilityAuraLinuxTest() {}
+BrowserAccessibilityAuraLinuxTest::BrowserAccessibilityAuraLinuxTest() =
+    default;
 
-BrowserAccessibilityAuraLinuxTest::~BrowserAccessibilityAuraLinuxTest() {}
+BrowserAccessibilityAuraLinuxTest::~BrowserAccessibilityAuraLinuxTest() =
+    default;
 
 void BrowserAccessibilityAuraLinuxTest::SetUp() {
+  ui::AXPlatformNode::NotifyAddAXModeFlags(ui::kAXModeComplete);
   test_browser_accessibility_delegate_ =
       std::make_unique<TestBrowserAccessibilityDelegate>();
 }
diff --git a/content/browser/accessibility/browser_accessibility_state_impl.cc b/content/browser/accessibility/browser_accessibility_state_impl.cc
index 8f778dfc..04f8b8d 100644
--- a/content/browser/accessibility/browser_accessibility_state_impl.cc
+++ b/content/browser/accessibility/browser_accessibility_state_impl.cc
@@ -215,6 +215,9 @@
   if (accessibility_mode_ == previous_mode)
     return;
 
+  // Proxy the AXMode to AXPlatformNode to enable accessibility.
+  ui::AXPlatformNode::NotifyAddAXModeFlags(accessibility_mode_);
+
   // Retrieve only newly added modes for the purposes of logging.
   int new_mode_flags = mode.mode() & (~previous_mode.mode());
   if (new_mode_flags & ui::AXMode::kNativeAPIs)
diff --git a/content/browser/accessibility/browser_accessibility_unittest.cc b/content/browser/accessibility/browser_accessibility_unittest.cc
index a744955..584f424 100644
--- a/content/browser/accessibility/browser_accessibility_unittest.cc
+++ b/content/browser/accessibility/browser_accessibility_unittest.cc
@@ -28,11 +28,12 @@
   DISALLOW_COPY_AND_ASSIGN(BrowserAccessibilityTest);
 };
 
-BrowserAccessibilityTest::BrowserAccessibilityTest() {}
+BrowserAccessibilityTest::BrowserAccessibilityTest() = default;
 
-BrowserAccessibilityTest::~BrowserAccessibilityTest() {}
+BrowserAccessibilityTest::~BrowserAccessibilityTest() = default;
 
 void BrowserAccessibilityTest::SetUp() {
+  ui::AXPlatformNode::NotifyAddAXModeFlags(ui::kAXModeComplete);
   test_browser_accessibility_delegate_ =
       std::make_unique<TestBrowserAccessibilityDelegate>();
 }
diff --git a/content/public/test/accessibility_notification_waiter.cc b/content/public/test/accessibility_notification_waiter.cc
index ea0700ed..50bad44 100644
--- a/content/public/test/accessibility_notification_waiter.cc
+++ b/content/public/test/accessibility_notification_waiter.cc
@@ -15,6 +15,7 @@
 #include "content/browser/frame_host/render_frame_host_impl.h"
 #include "content/browser/renderer_host/render_widget_host_view_base.h"
 #include "content/browser/web_contents/web_contents_impl.h"
+#include "content/public/browser/browser_accessibility_state.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/browser_plugin_guest_manager.h"
 #include "content/public/browser/web_contents.h"
@@ -44,6 +45,11 @@
   ListenToAllFrames(web_contents);
   static_cast<WebContentsImpl*>(web_contents)
       ->AddAccessibilityMode(accessibility_mode);
+  // Add the the accessibility mode on BrowserAccessibilityState so it can be
+  // also be added to AXPlatformNode, auralinux uses this to determine if it
+  // should enable accessibility or not.
+  BrowserAccessibilityState::GetInstance()->AddAccessibilityModeFlags(
+      accessibility_mode);
 }
 
 AccessibilityNotificationWaiter::AccessibilityNotificationWaiter(
@@ -57,9 +63,14 @@
   ListenToAllFrames(web_contents);
   static_cast<WebContentsImpl*>(web_contents)
       ->AddAccessibilityMode(accessibility_mode);
+  // Add the the accessibility mode on BrowserAccessibilityState so it can be
+  // also be added to AXPlatformNode, auralinux uses this to determine if it
+  // should enable accessibility or not.
+  BrowserAccessibilityState::GetInstance()->AddAccessibilityModeFlags(
+      accessibility_mode);
 }
 
-AccessibilityNotificationWaiter::~AccessibilityNotificationWaiter() {}
+AccessibilityNotificationWaiter::~AccessibilityNotificationWaiter() = default;
 
 void AccessibilityNotificationWaiter::ListenToAllFrames(
     WebContents* web_contents) {
diff --git a/ui/accessibility/platform/ax_platform_node_auralinux.cc b/ui/accessibility/platform/ax_platform_node_auralinux.cc
index c121d88..16c31de 100644
--- a/ui/accessibility/platform/ax_platform_node_auralinux.cc
+++ b/ui/accessibility/platform/ax_platform_node_auralinux.cc
@@ -195,20 +195,24 @@
 }
 
 AtkObject* FindAtkObjectParentFrame(AtkObject* atk_object) {
-  while (atk_object) {
-    if (atk_object_get_role(atk_object) == ATK_ROLE_FRAME)
-      return atk_object;
-    atk_object = atk_object_get_parent(atk_object);
+  AXPlatformNodeAuraLinux* node =
+      AtkObjectToAXPlatformNodeAuraLinux(atk_object);
+  while (node) {
+    if (node->GetAtkRole() == ATK_ROLE_FRAME)
+      return node->GetNativeViewAccessible();
+    node = AtkObjectToAXPlatformNodeAuraLinux(node->GetParent());
   }
   return nullptr;
 }
 
 AtkObject* FindAtkObjectToplevelParentDocument(AtkObject* atk_object) {
+  AXPlatformNodeAuraLinux* node =
+      AtkObjectToAXPlatformNodeAuraLinux(atk_object);
   AtkObject* toplevel_document = nullptr;
-  while (atk_object) {
-    if (atk_object_get_role(atk_object) == ATK_ROLE_DOCUMENT_WEB)
-      toplevel_document = atk_object;
-    atk_object = atk_object_get_parent(atk_object);
+  while (node) {
+    if (node->GetAtkRole() == ATK_ROLE_DOCUMENT_WEB)
+      toplevel_document = node->GetNativeViewAccessible();
+    node = AtkObjectToAXPlatformNodeAuraLinux(node->GetParent());
   }
   return toplevel_document;
 }
@@ -218,8 +222,9 @@
   while (current_frame) {
     if (current_frame == frame)
       return true;
-    current_frame =
-        FindAtkObjectParentFrame(atk_object_get_parent(current_frame));
+    AXPlatformNodeAuraLinux* frame_node =
+        AtkObjectToAXPlatformNodeAuraLinux(current_frame);
+    current_frame = FindAtkObjectParentFrame(frame_node->GetParent());
   }
   return false;
 }
@@ -324,14 +329,16 @@
   if (!atk_object)
     return gfx::Point(0, 0);
 
-  if (atk_object_get_role(atk_object) == ATK_ROLE_FRAME) {
+  AXPlatformNodeAuraLinux* node =
+      AtkObjectToAXPlatformNodeAuraLinux(atk_object);
+  if (node->GetAtkRole() == ATK_ROLE_FRAME) {
     int x, y;
     atk_component_get_extents(ATK_COMPONENT(atk_object), &x, &y, nullptr,
                               nullptr, ATK_XY_WINDOW);
     gfx::Point window_coords(x, y);
     return window_coords;
   }
-  atk_object = atk_object_get_parent(atk_object);
+  atk_object = node->GetParent();
 
   return FindAtkObjectParentCoords(atk_object);
 }
@@ -1762,16 +1769,16 @@
 GPtrArray* GetColumnHeaderCells(AtkTableCell* cell) {
   GPtrArray* array = g_ptr_array_new_with_free_func(g_object_unref);
 
+  auto* obj = AtkObjectToAXPlatformNodeAuraLinux(ATK_OBJECT(cell));
+  if (!obj)
+    return array;
+
   // AtkTableCell is implemented on cells, row headers, and column headers.
   // Calling GetColHeaderNodeIds() on a column header cell will include that
   // column header, along with any other column headers in the column which
   // may or may not describe the header cell in question. Therefore, just return
   // headers for non-header cells.
-  if (atk_object_get_role(ATK_OBJECT(cell)) != ATK_ROLE_TABLE_CELL)
-    return array;
-
-  auto* obj = AtkObjectToAXPlatformNodeAuraLinux(ATK_OBJECT(cell));
-  if (!obj)
+  if (obj->GetAtkRole() != ATK_ROLE_TABLE_CELL)
     return array;
 
   base::Optional<int> col_index = obj->GetTableColumn();
@@ -1818,16 +1825,16 @@
 GPtrArray* GetRowHeaderCells(AtkTableCell* cell) {
   GPtrArray* array = g_ptr_array_new_with_free_func(g_object_unref);
 
+  auto* obj = AtkObjectToAXPlatformNodeAuraLinux(ATK_OBJECT(cell));
+  if (!obj)
+    return array;
+
   // AtkTableCell is implemented on cells, row headers, and column headers.
   // Calling GetRowHeaderNodeIds() on a row header cell will include that
   // row header, along with any other row headers in the row which may or
   // may not describe the header cell in question. Therefore, just return
   // headers for non-header cells.
-  if (atk_object_get_role(ATK_OBJECT(cell)) != ATK_ROLE_TABLE_CELL)
-    return array;
-
-  auto* obj = AtkObjectToAXPlatformNodeAuraLinux(ATK_OBJECT(cell));
-  if (!obj)
+  if (obj->GetAtkRole() != ATK_ROLE_TABLE_CELL)
     return array;
 
   base::Optional<int> row_index = obj->GetTableRow();
@@ -1896,6 +1903,11 @@
   return obj->accessible_name_.c_str();
 }
 
+const gchar* AtkGetName(AtkObject* atk_object) {
+  AXPlatformNode::NotifyAddAXModeFlags(kAXModeComplete);
+  return GetName(atk_object);
+}
+
 const gchar* GetDescription(AtkObject* atk_object) {
   AXPlatformNodeAuraLinux* obj = AtkObjectToAXPlatformNodeAuraLinux(atk_object);
   if (!obj)
@@ -1905,44 +1917,9 @@
       .c_str();
 }
 
-gint GetIndexInParent(AtkObject* atk_object) {
-  AtkObject* parent = atk_object_get_parent(atk_object);
-  if (!parent)
-    return -1;
-
-  AXPlatformNodeAuraLinux* obj = AtkObjectToAXPlatformNodeAuraLinux(atk_object);
-  if (!obj)
-    return -1;
-
-  int n_children = atk_object_get_n_accessible_children(parent);
-
-  // Ask the delegate for the index in parent, and return it if it's plausible.
-  //
-  // Delegates are allowed to not implement this (AXPlatformNodeDelegateBase
-  // returns -1). Also, delegates may not know the correct answer if this
-  // node is the root of a tree that's embedded in another tree, in which
-  // case the delegate should return -1 and we'll compute it.
-  int index_in_parent = obj->GetDelegate()->GetIndexInParent();
-  if (index_in_parent >= 0 && index_in_parent < n_children)
-    return index_in_parent;
-
-  // Otherwise, search the parent's children.
-  for (int i = 0; i < n_children; i++) {
-    AtkObject* child = atk_object_ref_accessible_child(parent, i);
-    g_object_unref(child);
-    if (child == atk_object)
-      return i;
-  }
-
-  return -1;
-}
-
-AtkObject* GetParent(AtkObject* atk_object) {
-  AXPlatformNodeAuraLinux* obj = AtkObjectToAXPlatformNodeAuraLinux(atk_object);
-  if (!obj)
-    return nullptr;
-
-  return obj->GetParent();
+const gchar* AtkGetDescription(AtkObject* atk_object) {
+  AXPlatformNode::NotifyAddAXModeFlags(kAXModeComplete);
+  return GetDescription(atk_object);
 }
 
 gint GetNChildren(AtkObject* atk_object) {
@@ -1953,6 +1930,11 @@
   return obj->GetChildCount();
 }
 
+gint AtkGetNChildren(AtkObject* atk_object) {
+  AXPlatformNode::NotifyAddAXModeFlags(kAXModeComplete);
+  return GetNChildren(atk_object);
+}
+
 AtkObject* RefChild(AtkObject* atk_object, gint index) {
   AXPlatformNodeAuraLinux* obj = AtkObjectToAXPlatformNodeAuraLinux(atk_object);
   if (!obj)
@@ -1967,6 +1949,61 @@
   return result;
 }
 
+AtkObject* AtkRefChild(AtkObject* atk_object, gint index) {
+  AXPlatformNode::NotifyAddAXModeFlags(kAXModeComplete);
+  return RefChild(atk_object, index);
+}
+
+gint GetIndexInParent(AtkObject* atk_object) {
+  AXPlatformNodeAuraLinux* obj = AtkObjectToAXPlatformNodeAuraLinux(atk_object);
+  if (!obj)
+    return -1;
+
+  AtkObject* parent = obj->GetParent();
+  if (!parent)
+    return -1;
+
+  int n_children = GetNChildren(parent);
+
+  // Ask the delegate for the index in parent, and return it if it's plausible.
+  //
+  // Delegates are allowed to not implement this (AXPlatformNodeDelegateBase
+  // returns -1). Also, delegates may not know the correct answer if this
+  // node is the root of a tree that's embedded in another tree, in which
+  // case the delegate should return -1 and we'll compute it.
+  int index_in_parent = obj->GetDelegate()->GetIndexInParent();
+  if (index_in_parent >= 0 && index_in_parent < n_children)
+    return index_in_parent;
+
+  // Otherwise, search the parent's children.
+  for (int i = 0; i < n_children; i++) {
+    AtkObject* child = RefChild(parent, i);
+    g_object_unref(child);
+    if (child == atk_object)
+      return i;
+  }
+
+  return -1;
+}
+
+gint AtkGetIndexInParent(AtkObject* atk_object) {
+  AXPlatformNode::NotifyAddAXModeFlags(kAXModeComplete);
+  return GetIndexInParent(atk_object);
+}
+
+AtkObject* GetParent(AtkObject* atk_object) {
+  AXPlatformNodeAuraLinux* obj = AtkObjectToAXPlatformNodeAuraLinux(atk_object);
+  if (!obj)
+    return nullptr;
+
+  return obj->GetParent();
+}
+
+AtkObject* AtkGetParent(AtkObject* atk_object) {
+  AXPlatformNode::NotifyAddAXModeFlags(kAXModeComplete);
+  return GetParent(atk_object);
+}
+
 AtkRelationSet* RefRelationSet(AtkObject* atk_object) {
   AXPlatformNodeAuraLinux* obj = AtkObjectToAXPlatformNodeAuraLinux(atk_object);
   if (!obj)
@@ -1974,6 +2011,11 @@
   return obj->GetAtkRelations();
 }
 
+AtkRelationSet* AtkRefRelationSet(AtkObject* atk_object) {
+  AXPlatformNode::NotifyAddAXModeFlags(kAXModeComplete);
+  return RefRelationSet(atk_object);
+}
+
 AtkAttributeSet* GetAttributes(AtkObject* atk_object) {
   AXPlatformNodeAuraLinux* obj = AtkObjectToAXPlatformNodeAuraLinux(atk_object);
   if (!obj)
@@ -1982,6 +2024,11 @@
   return obj->GetAtkAttributes();
 }
 
+AtkAttributeSet* AtkGetAttributes(AtkObject* atk_object) {
+  AXPlatformNode::NotifyAddAXModeFlags(kAXModeComplete);
+  return GetAttributes(atk_object);
+}
+
 AtkRole GetRole(AtkObject* atk_object) {
   AXPlatformNodeAuraLinux* obj = AtkObjectToAXPlatformNodeAuraLinux(atk_object);
   if (!obj)
@@ -1989,6 +2036,11 @@
   return obj->GetAtkRole();
 }
 
+AtkRole AtkGetRole(AtkObject* atk_object) {
+  AXPlatformNode::NotifyAddAXModeFlags(kAXModeComplete);
+  return GetRole(atk_object);
+}
+
 AtkStateSet* RefStateSet(AtkObject* atk_object) {
   AtkStateSet* atk_state_set =
       ATK_OBJECT_CLASS(kAXPlatformNodeAuraLinuxParentClass)
@@ -2002,6 +2054,12 @@
   }
   return atk_state_set;
 }
+
+AtkStateSet* AtkRefStateSet(AtkObject* atk_object) {
+  AXPlatformNode::NotifyAddAXModeFlags(kAXModeComplete);
+  return RefStateSet(atk_object);
+}
+
 void Initialize(AtkObject* atk_object, gpointer data) {
   if (ATK_OBJECT_CLASS(kAXPlatformNodeAuraLinuxParentClass)->initialize) {
     ATK_OBJECT_CLASS(kAXPlatformNodeAuraLinuxParentClass)
@@ -2023,16 +2081,16 @@
 
   AtkObjectClass* atk_object_class = ATK_OBJECT_CLASS(gobject_class);
   atk_object_class->initialize = Initialize;
-  atk_object_class->get_name = GetName;
-  atk_object_class->get_description = GetDescription;
-  atk_object_class->get_parent = GetParent;
-  atk_object_class->get_n_children = GetNChildren;
-  atk_object_class->ref_child = RefChild;
-  atk_object_class->get_role = GetRole;
-  atk_object_class->ref_state_set = RefStateSet;
-  atk_object_class->get_index_in_parent = GetIndexInParent;
-  atk_object_class->ref_relation_set = RefRelationSet;
-  atk_object_class->get_attributes = GetAttributes;
+  atk_object_class->get_name = AtkGetName;
+  atk_object_class->get_description = AtkGetDescription;
+  atk_object_class->get_parent = AtkGetParent;
+  atk_object_class->get_n_children = AtkGetNChildren;
+  atk_object_class->ref_child = AtkRefChild;
+  atk_object_class->get_role = AtkGetRole;
+  atk_object_class->ref_state_set = AtkRefStateSet;
+  atk_object_class->get_index_in_parent = AtkGetIndexInParent;
+  atk_object_class->ref_relation_set = AtkRefRelationSet;
+  atk_object_class->get_attributes = AtkGetAttributes;
 }
 
 GType GetType() {
@@ -2297,6 +2355,9 @@
 }
 
 AtkObject* AXPlatformNodeAuraLinux::CreateAtkObject() {
+  if (GetData().role != ax::mojom::Role::kApplication &&
+      !GetAccessibilityMode().has_mode(AXMode::kWebContents))
+    return nullptr;
   EnsureGTypeInit();
   interface_mask_ = GetGTypeInterfaceMask(GetData());
   GType type = GetAccessibilityGType();
@@ -2855,6 +2916,7 @@
     }
   }
 
+  DCHECK(GetOrCreateAtkObject());
   if (delegate_->GetFocus() == GetOrCreateAtkObject())
     atk_state_set_add_state(atk_state_set, ATK_STATE_FOCUSED);
 
@@ -2933,6 +2995,7 @@
 }
 
 AtkRelationSet* AXPlatformNodeAuraLinux::GetAtkRelations() {
+  DCHECK(GetOrCreateAtkObject());
   AtkRelationSet* relation_set = atk_relation_set_new();
 
   if (GetDelegate()->IsWebContent() && GetAtkRole() == ATK_ROLE_DOCUMENT_WEB) {
@@ -3235,7 +3298,7 @@
 void AXPlatformNodeAuraLinux::OnWindowVisibilityChanged() {
   AtkObject* atk_object = GetOrCreateAtkObject();
 
-  if (atk_object_get_role(atk_object) != ATK_ROLE_FRAME)
+  if (GetAtkRole() != ATK_ROLE_FRAME)
     return;
 
   bool minimized = delegate_->IsMinimized();
@@ -3263,11 +3326,11 @@
   AtkObject* parent = GetOrCreateAtkObject();
   if (!GetDelegate()->IsWebContent()) {
     while (parent) {
-      if (atk_object_get_role(parent) == ATK_ROLE_DIALOG) {
+      if (atk_object::GetRole(parent) == ATK_ROLE_DIALOG) {
         new_views_dialog = parent;
         break;
       }
-      parent = atk_object_get_parent(parent);
+      parent = atk_object::GetParent(parent);
     }
   }
 
@@ -3284,7 +3347,7 @@
 void AXPlatformNodeAuraLinux::OnFocused() {
   AtkObject* atk_object = GetOrCreateAtkObject();
 
-  if (atk_object_get_role(atk_object) == ATK_ROLE_FRAME) {
+  if (atk_object::GetRole(atk_object) == ATK_ROLE_FRAME) {
     OnWindowActivated();
     return;
   }
@@ -3434,6 +3497,8 @@
   }
 
   AtkObject* atk_object = GetOrCreateAtkObject();
+  if (!atk_object)
+    return;
   DCHECK(ATK_IS_TEXT(atk_object));
 
   // ATK does not consider a collapsed selection a selection, so
@@ -3542,7 +3607,7 @@
   AtkObject* atk_object = GetOrCreateAtkObject();
   std::string previous_accessible_name = accessible_name_;
   // Calling atk_object_get_name will update the value of accessible_name_.
-  if (!g_strcmp0(atk_object_get_name(atk_object),
+  if (!g_strcmp0(atk_object::GetName(atk_object),
                  previous_accessible_name.c_str()))
     return;
 
@@ -3602,6 +3667,8 @@
 
 void AXPlatformNodeAuraLinux::NotifyAccessibilityEvent(
     ax::mojom::Event event_type) {
+  if (!GetOrCreateAtkObject())
+    return;
   AXPlatformNodeBase::NotifyAccessibilityEvent(event_type);
   switch (event_type) {
     // There are three types of messages that we receive for popup menus. Each
@@ -3707,6 +3774,9 @@
 }
 
 void AXPlatformNodeAuraLinux::UpdateHypertext() {
+  if (!GetOrCreateAtkObject())
+    return;
+
   EnsureAtkObjectIsValid();
   AXHypertext old_hypertext = hypertext_;
   base::OffsetAdjuster::Adjustments old_adjustments = GetHypertextAdjustments();
@@ -3884,7 +3954,8 @@
     *height = extents.height();
 }
 
-void AXPlatformNodeAuraLinux::GetPosition(gint* x, gint* y,
+void AXPlatformNodeAuraLinux::GetPosition(gint* x,
+                                          gint* y,
                                           AtkCoordType coord_type) {
   gfx::Rect extents = GetExtentsRelativeToAtkCoordinateType(coord_type);
   if (x)
@@ -4143,6 +4214,7 @@
 }
 
 bool AXPlatformNodeAuraLinux::SetCaretOffset(int offset) {
+  DCHECK(GetOrCreateAtkObject());
   int character_count =
       atk_text_get_character_count(ATK_TEXT(GetOrCreateAtkObject()));
   if (offset < 0 || offset > character_count)
@@ -4230,6 +4302,7 @@
   GetSelectionExtents(&selection_start, &selection_end);
 
   AtkObject* atk_object = GetOrCreateAtkObject();
+  DCHECK(atk_object);
   if (selection_start < 0 || selection_end < 0 ||
       selection_start == selection_end) {
     base::Optional<FindInPageResultInfo> find_in_page_result =
@@ -4543,6 +4616,7 @@
 
 void AXPlatformNodeAuraLinux::ForgetCurrentFindInPageResult() {
   AtkObject* atk_object = GetOrCreateAtkObject();
+  DCHECK(atk_object);
   AtkObject* parent_doc = FindAtkObjectToplevelParentDocument(atk_object);
   if (parent_doc)
     GetActiveFindInPageResults().erase(parent_doc);
@@ -4551,6 +4625,7 @@
 base::Optional<FindInPageResultInfo>
 AXPlatformNodeAuraLinux::GetSelectionOffsetsFromFindInPage() {
   AtkObject* atk_object = GetOrCreateAtkObject();
+  DCHECK(atk_object);
   AtkObject* parent_doc = FindAtkObjectToplevelParentDocument(atk_object);
   if (!parent_doc)
     return base::nullopt;
diff --git a/ui/accessibility/platform/ax_platform_node_auralinux_unittest.cc b/ui/accessibility/platform/ax_platform_node_auralinux_unittest.cc
index a314fea..fdae097 100644
--- a/ui/accessibility/platform/ax_platform_node_auralinux_unittest.cc
+++ b/ui/accessibility/platform/ax_platform_node_auralinux_unittest.cc
@@ -22,6 +22,10 @@
   AXPlatformNodeAuraLinuxTest& operator=(const AXPlatformNodeAuraLinuxTest&) =
       delete;
 
+  void SetUp() override {
+    AXPlatformNode::NotifyAddAXModeFlags(kAXModeComplete);
+  }
+
  protected:
   AXPlatformNodeAuraLinux* GetPlatformNode(AXNode* node) {
     TestAXNodeWrapper* wrapper =
diff --git a/ui/accessibility/platform/ax_platform_node_base_unittest.cc b/ui/accessibility/platform/ax_platform_node_base_unittest.cc
index c68584d..b231a59 100644
--- a/ui/accessibility/platform/ax_platform_node_base_unittest.cc
+++ b/ui/accessibility/platform/ax_platform_node_base_unittest.cc
@@ -63,6 +63,10 @@
   auto* root = static_cast<AXPlatformNodeBase*>(
       TestAXNodeWrapper::GetOrCreate(&tree, tree.root())->ax_platform_node());
 
+  // Set an AXMode on the AXPlatformNode as some platforms (auralinux) use it to
+  // determine if it should enable accessibility.
+  AXPlatformNodeBase::NotifyAddAXModeFlags(kAXModeComplete);
+
   EXPECT_EQ(root->GetInnerText(), base::UTF8ToUTF16("abde"));
 
   // Setting invisible or ignored on a static text node causes it to be included
diff --git a/ui/views/accessibility/ax_virtual_view_unittest.cc b/ui/views/accessibility/ax_virtual_view_unittest.cc
index 34a60e5..7e221487 100644
--- a/ui/views/accessibility/ax_virtual_view_unittest.cc
+++ b/ui/views/accessibility/ax_virtual_view_unittest.cc
@@ -13,6 +13,7 @@
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/accessibility/ax_enums.mojom.h"
 #include "ui/accessibility/ax_node_data.h"
+#include "ui/accessibility/platform/ax_platform_node.h"
 #include "ui/accessibility/platform/ax_platform_node_delegate.h"
 #include "ui/gfx/geometry/rect.h"
 #include "ui/gfx/geometry/size.h"
@@ -51,6 +52,7 @@
 
   void SetUp() override {
     ViewsTestBase::SetUp();
+    ui::AXPlatformNode::NotifyAddAXModeFlags(ui::kAXModeComplete);
 
     widget_ = new Widget;
     Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW);
diff --git a/ui/views/accessibility/view_ax_platform_node_delegate_auralinux.cc b/ui/views/accessibility/view_ax_platform_node_delegate_auralinux.cc
index b16fd4b..46eb655 100644
--- a/ui/views/accessibility/view_ax_platform_node_delegate_auralinux.cc
+++ b/ui/views/accessibility/view_ax_platform_node_delegate_auralinux.cc
@@ -175,9 +175,6 @@
   view->AddObserver(this);
 }
 
-ViewAXPlatformNodeDelegateAuraLinux::~ViewAXPlatformNodeDelegateAuraLinux() =
-    default;
-
 gfx::NativeViewAccessible ViewAXPlatformNodeDelegateAuraLinux::GetParent() {
   if (gfx::NativeViewAccessible parent =
           ViewAXPlatformNodeDelegate::GetParent())
diff --git a/ui/views/accessibility/view_ax_platform_node_delegate_auralinux.h b/ui/views/accessibility/view_ax_platform_node_delegate_auralinux.h
index 72052ec..cc5cbf17 100644
--- a/ui/views/accessibility/view_ax_platform_node_delegate_auralinux.h
+++ b/ui/views/accessibility/view_ax_platform_node_delegate_auralinux.h
@@ -20,7 +20,6 @@
       const ViewAXPlatformNodeDelegateAuraLinux&) = delete;
   ViewAXPlatformNodeDelegateAuraLinux& operator=(
       const ViewAXPlatformNodeDelegateAuraLinux&) = delete;
-  ~ViewAXPlatformNodeDelegateAuraLinux() override;
 
   // |ViewAXPlatformNodeDelegate| overrides:
   gfx::NativeViewAccessible GetParent() override;
diff --git a/ui/views/accessibility/view_ax_platform_node_delegate_auralinux_unittest.cc b/ui/views/accessibility/view_ax_platform_node_delegate_auralinux_unittest.cc
index 4fa37a9..f9c0de73 100644
--- a/ui/views/accessibility/view_ax_platform_node_delegate_auralinux_unittest.cc
+++ b/ui/views/accessibility/view_ax_platform_node_delegate_auralinux_unittest.cc
@@ -6,6 +6,7 @@
 
 #include <atk/atk.h>
 
+#include "ui/accessibility/platform/ax_platform_node.h"
 #include "ui/views/controls/textfield/textfield.h"
 #include "ui/views/test/views_test_base.h"
 
@@ -16,6 +17,10 @@
  public:
   ViewAXPlatformNodeDelegateAuraLinuxTest() = default;
   ~ViewAXPlatformNodeDelegateAuraLinuxTest() override = default;
+  void SetUp() override {
+    ViewsTestBase::SetUp();
+    ui::AXPlatformNode::NotifyAddAXModeFlags(ui::kAXModeComplete);
+  }
 };
 
 TEST_F(ViewAXPlatformNodeDelegateAuraLinuxTest, TextfieldAccessibility) {
diff --git a/ui/views/accessibility/view_ax_platform_node_delegate_unittest.cc b/ui/views/accessibility/view_ax_platform_node_delegate_unittest.cc
index 56d1cb1..9152402 100644
--- a/ui/views/accessibility/view_ax_platform_node_delegate_unittest.cc
+++ b/ui/views/accessibility/view_ax_platform_node_delegate_unittest.cc
@@ -8,6 +8,7 @@
 #include "ui/accessibility/ax_action_data.h"
 #include "ui/accessibility/ax_enums.mojom.h"
 #include "ui/accessibility/ax_node_data.h"
+#include "ui/accessibility/platform/ax_platform_node.h"
 #include "ui/accessibility/platform/ax_platform_node_base.h"
 #include "ui/gfx/geometry/rect.h"
 #include "ui/gfx/geometry/rect_conversions.h"
@@ -48,6 +49,7 @@
 
   void SetUp() override {
     ViewsTestBase::SetUp();
+    ui::AXPlatformNode::NotifyAddAXModeFlags(ui::kAXModeComplete);
 
     widget_ = new Widget;
     Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW);
diff --git a/ui/views/controls/webview/webview.cc b/ui/views/controls/webview/webview.cc
index c265f6c..9a9f250 100644
--- a/ui/views/controls/webview/webview.cc
+++ b/ui/views/controls/webview/webview.cc
@@ -18,6 +18,7 @@
 #include "ipc/ipc_message.h"
 #include "ui/accessibility/ax_enums.mojom.h"
 #include "ui/accessibility/ax_node_data.h"
+#include "ui/accessibility/platform/ax_platform_node.h"
 #include "ui/events/event.h"
 #include "ui/views/focus/focus_manager.h"
 #include "ui/views/views_delegate.h"
@@ -32,6 +33,16 @@
   return creator.get();
 }
 
+// Updates the parent accessible object on the NativeView. As WebView overrides
+// GetNativeViewAccessible() to return the accessible from the WebContents, it
+// needs to ensure the accessible from the parent is set on the NativeView.
+void UpdateNativeViewHostAccessibleParent(NativeViewHost* holder,
+                                          View* parent) {
+  if (!parent)
+    return;
+  holder->SetParentAccessible(parent->GetNativeViewAccessible());
+}
+
 }  // namespace
 
 WebView::ScopedWebContentsCreatorForTesting::ScopedWebContentsCreatorForTesting(
@@ -49,9 +60,12 @@
 // WebView, public:
 
 WebView::WebView(content::BrowserContext* browser_context)
-    : browser_context_(browser_context) {}
+    : browser_context_(browser_context) {
+  ui::AXPlatformNode::AddAXModeObserver(this);
+}
 
 WebView::~WebView() {
+  ui::AXPlatformNode::RemoveAXModeObserver(this);
   SetWebContents(nullptr);  // Make sure all necessary tear-down takes place.
 }
 
@@ -251,6 +265,17 @@
   return View::GetNativeViewAccessible();
 }
 
+void WebView::OnAXModeAdded(ui::AXMode mode) {
+  if (!web_contents())
+    return;
+
+  // Normally, it is set during AttachWebContentsNativeView when the WebView is
+  // created but this may not happen on some platforms as the accessible object
+  // may not have been present when this WebView was created. So, update it when
+  // AX mode is added.
+  UpdateNativeViewHostAccessibleParent(holder(), parent());
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 // WebView, content::WebContentsDelegate implementation:
 
@@ -363,8 +388,7 @@
     holder_->Layout();
 
   // We set the parent accessible of the native view to be our parent.
-  if (parent())
-    holder_->SetParentAccessible(parent()->GetNativeViewAccessible());
+  UpdateNativeViewHostAccessibleParent(holder(), parent());
 
   // The WebContents is not focused automatically when attached, so we need to
   // tell the WebContents it has focus if this has focus.
diff --git a/ui/views/controls/webview/webview.h b/ui/views/controls/webview/webview.h
index 9872ad3..84d5cd5 100644
--- a/ui/views/controls/webview/webview.h
+++ b/ui/views/controls/webview/webview.h
@@ -13,6 +13,7 @@
 #include "base/macros.h"
 #include "content/public/browser/web_contents_delegate.h"
 #include "content/public/browser/web_contents_observer.h"
+#include "ui/accessibility/ax_mode_observer.h"
 #include "ui/gfx/native_widget_types.h"
 #include "ui/views/controls/native/native_view_host.h"
 #include "ui/views/controls/webview/webview_export.h"
@@ -36,7 +37,8 @@
 // whenever possible.
 class WEBVIEW_EXPORT WebView : public View,
                                public content::WebContentsDelegate,
-                               public content::WebContentsObserver {
+                               public content::WebContentsObserver,
+                               public ui::AXModeObserver {
  public:
   METADATA_HEADER(WebView);
 
@@ -158,6 +160,9 @@
       content::RenderWidgetHost* render_widget_host) override;
   void RenderProcessGone(base::TerminationStatus status) override;
 
+  // Override from ui::AXModeObserver
+  void OnAXModeAdded(ui::AXMode mode) override;
+
  private:
   friend class WebViewUnitTest;