Forward BrowserAccessibility get_accState to AXPlatformNode.

This is another migration from BrowserAccessibility to AXPlatformNodeWin.
In this installment, we're converting get_accState. This one is mostly
straightforward. The one gotcha is that there are some types that need
to be explictly marked as focusable if they are selectable.

BUG=703369

Review-Url: https://codereview.chromium.org/2913553002
Cr-Commit-Position: refs/heads/master@{#478110}
diff --git a/content/browser/accessibility/browser_accessibility.cc b/content/browser/accessibility/browser_accessibility.cc
index 5587511..3fb2659 100644
--- a/content/browser/accessibility/browser_accessibility.cc
+++ b/content/browser/accessibility/browser_accessibility.cc
@@ -13,6 +13,7 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
 #include "content/browser/accessibility/browser_accessibility_manager.h"
+#include "content/browser/accessibility/browser_accessibility_state_impl.h"
 #include "content/common/accessibility_messages.h"
 #include "ui/accessibility/ax_role_properties.h"
 #include "ui/accessibility/ax_text_utils.h"
@@ -1201,4 +1202,10 @@
   return false;
 }
 
+bool BrowserAccessibility::ShouldIgnoreHoveredStateForTesting() {
+  BrowserAccessibilityStateImpl* accessibility_state =
+      BrowserAccessibilityStateImpl::GetInstance();
+  return accessibility_state->disable_hot_tracking_for_testing();
+}
+
 }  // namespace content
diff --git a/content/browser/accessibility/browser_accessibility.h b/content/browser/accessibility/browser_accessibility.h
index e9df24c..b4a6f2c 100644
--- a/content/browser/accessibility/browser_accessibility.h
+++ b/content/browser/accessibility/browser_accessibility.h
@@ -391,6 +391,7 @@
   gfx::NativeViewAccessible GetFocus() override;
   gfx::AcceleratedWidget GetTargetForNativeAccessibilityEvent() override;
   bool AccessibilityPerformAction(const ui::AXActionData& data) override;
+  bool ShouldIgnoreHoveredStateForTesting() override;
 
  protected:
   using AXPlatformPositionInstance = AXPlatformPosition::AXPositionInstance;
diff --git a/content/browser/accessibility/browser_accessibility_com_win.cc b/content/browser/accessibility/browser_accessibility_com_win.cc
index 46b1cd1..c20cff8 100644
--- a/content/browser/accessibility/browser_accessibility_com_win.cc
+++ b/content/browser/accessibility/browser_accessibility_com_win.cc
@@ -642,23 +642,7 @@
   if (!owner())
     return E_FAIL;
 
-  auto* manager = Manager();
-  if (!manager)
-    return E_FAIL;
-
-  if (!state)
-    return E_INVALIDARG;
-
-  BrowserAccessibilityComWin* target = GetTargetFromChildID(var_id);
-  if (!target)
-    return E_INVALIDARG;
-
-  state->vt = VT_I4;
-  state->lVal = target->ia_state();
-  if (manager->GetFocus() == owner())
-    state->lVal |= STATE_SYSTEM_FOCUSED;
-
-  return S_OK;
+  return AXPlatformNodeWin::get_accState(var_id, state);
 }
 
 bool BrowserAccessibilityComWin::IsRangeValueSupported() {
diff --git a/ui/accessibility/platform/ax_fake_caret_win.cc b/ui/accessibility/platform/ax_fake_caret_win.cc
index 8b645dc..d15b180 100644
--- a/ui/accessibility/platform/ax_fake_caret_win.cc
+++ b/ui/accessibility/platform/ax_fake_caret_win.cc
@@ -99,4 +99,8 @@
   return false;
 }
 
+bool AXFakeCaretWin::ShouldIgnoreHoveredStateForTesting() {
+  return true;
+}
+
 }  // namespace ui
diff --git a/ui/accessibility/platform/ax_fake_caret_win.h b/ui/accessibility/platform/ax_fake_caret_win.h
index d2a5bba..a23f376 100644
--- a/ui/accessibility/platform/ax_fake_caret_win.h
+++ b/ui/accessibility/platform/ax_fake_caret_win.h
@@ -43,6 +43,7 @@
   gfx::NativeViewAccessible GetFocus() override;
   gfx::AcceleratedWidget GetTargetForNativeAccessibilityEvent() override;
   bool AccessibilityPerformAction(const ui::AXActionData& data) override;
+  bool ShouldIgnoreHoveredStateForTesting() override;
 
   AXPlatformNodeWin* caret_;
   gfx::AcceleratedWidget event_target_;
diff --git a/ui/accessibility/platform/ax_platform_node_delegate.h b/ui/accessibility/platform/ax_platform_node_delegate.h
index 6960a44..7629ea5 100644
--- a/ui/accessibility/platform/ax_platform_node_delegate.h
+++ b/ui/accessibility/platform/ax_platform_node_delegate.h
@@ -84,6 +84,16 @@
   // Perform an accessibility action, switching on the ui::AXAction
   // provided in |data|.
   virtual bool AccessibilityPerformAction(const ui::AXActionData& data) = 0;
+
+  //
+  // Testing.
+  //
+
+  // Accessibility objects can have the "hot tracked" state set when
+  // the mouse is hovering over them, but this makes tests flaky because
+  // the test behaves differently when the mouse happens to be over an
+  // element. The default value should be falses if not in testing mode.
+  virtual bool ShouldIgnoreHoveredStateForTesting() = 0;
 };
 
 }  // namespace ui
diff --git a/ui/accessibility/platform/ax_platform_node_win.cc b/ui/accessibility/platform/ax_platform_node_win.cc
index 1a54321..7d385a6 100644
--- a/ui/accessibility/platform/ax_platform_node_win.cc
+++ b/ui/accessibility/platform/ax_platform_node_win.cc
@@ -1438,8 +1438,7 @@
     msaa_state |= STATE_SYSTEM_FOCUSABLE;
   if (state & (1 << ui::AX_STATE_HASPOPUP))
     msaa_state |= STATE_SYSTEM_HASPOPUP;
-  if (state & (1 << ui::AX_STATE_HOVERED))
-    msaa_state |= STATE_SYSTEM_HOTTRACKED;
+
   if (state & (1 << ui::AX_STATE_INVISIBLE) ||
       GetData().role == ui::AX_ROLE_IGNORED) {
     msaa_state |= STATE_SYSTEM_INVISIBLE;
@@ -1458,6 +1457,23 @@
     msaa_state |= STATE_SYSTEM_SELECTED;
   if (state & (1 << ui::AX_STATE_DISABLED))
     msaa_state |= STATE_SYSTEM_UNAVAILABLE;
+  if (state & (1 << ui::AX_STATE_BUSY))
+    msaa_state |= STATE_SYSTEM_BUSY;
+  if (state & (1 << ui::AX_STATE_VISITED))
+    msaa_state |= STATE_SYSTEM_TRAVERSED;
+
+  if (state & (1 << ui::AX_STATE_MULTISELECTABLE)) {
+    msaa_state |= STATE_SYSTEM_EXTSELECTABLE;
+    msaa_state |= STATE_SYSTEM_MULTISELECTABLE;
+  }
+
+  // Expose whether or not the mouse is over an element, but suppress
+  // this for tests because it can make the test results flaky depending
+  // on the position of the mouse.
+  if (delegate_->ShouldIgnoreHoveredStateForTesting()) {
+    if (state & (1 << ui::AX_STATE_HOVERED))
+      msaa_state |= STATE_SYSTEM_HOTTRACKED;
+  }
 
   // Checked state
   const auto checked_state = static_cast<ui::AXCheckedState>(
@@ -1490,6 +1506,89 @@
     msaa_state |= STATE_SYSTEM_FOCUSED;
   }
 
+  switch (GetData().role) {
+    case ui::AX_ROLE_ARTICLE:
+    case ui::AX_ROLE_BUSY_INDICATOR:
+    case ui::AX_ROLE_DEFINITION:
+    case ui::AX_ROLE_DESCRIPTION_LIST:
+    case ui::AX_ROLE_DESCRIPTION_LIST_TERM:
+    case ui::AX_ROLE_IFRAME:
+    case ui::AX_ROLE_IMAGE:
+    case ui::AX_ROLE_IMAGE_MAP:
+    case ui::AX_ROLE_LIST:
+    case ui::AX_ROLE_LIST_ITEM:
+    case ui::AX_ROLE_PROGRESS_INDICATOR:
+    case ui::AX_ROLE_RULER:
+    case ui::AX_ROLE_SCROLL_AREA:
+    case ui::AX_ROLE_TABLE_HEADER_CONTAINER:
+    case ui::AX_ROLE_TERM:
+    case ui::AX_ROLE_TIMER:
+    case ui::AX_ROLE_TOOLBAR:
+    case ui::AX_ROLE_TOOLTIP:
+      msaa_state |= STATE_SYSTEM_READONLY;
+      break;
+
+    case ui::AX_ROLE_DOCUMENT:
+    case ui::AX_ROLE_ROOT_WEB_AREA:
+    case ui::AX_ROLE_WEB_AREA:
+      msaa_state |= STATE_SYSTEM_READONLY;
+      msaa_state |= STATE_SYSTEM_FOCUSABLE;
+      break;
+
+    case ui::AX_ROLE_GRID:
+      // TODO(aleventhal) this changed between ARIA 1.0 and 1.1,
+      // need to determine whether grids/treegrids should really be readonly
+      // or editable by default
+      // msaa_state |= STATE_SYSTEM_READONLY;
+      break;
+
+    case ui::AX_ROLE_IMAGE_MAP_LINK:
+      msaa_state |= STATE_SYSTEM_LINKED;
+      msaa_state |= STATE_SYSTEM_READONLY;
+      break;
+
+    case ui::AX_ROLE_LINK:
+      msaa_state |= STATE_SYSTEM_LINKED;
+      break;
+
+    case ui::AX_ROLE_LIST_BOX_OPTION:
+      if (msaa_state & STATE_SYSTEM_SELECTABLE) {
+        msaa_state |= STATE_SYSTEM_FOCUSABLE;
+      }
+      break;
+
+    case ui::AX_ROLE_MENU_LIST_OPTION:
+      if (msaa_state & STATE_SYSTEM_SELECTABLE) {
+        msaa_state |= STATE_SYSTEM_FOCUSABLE;
+      }
+      break;
+
+    case ui::AX_ROLE_TEXT_FIELD:
+    case ui::AX_ROLE_SEARCH_BOX:
+      if (state & (1 << ui::AX_STATE_READ_ONLY))
+        msaa_state |= STATE_SYSTEM_READONLY;
+      break;
+    default:
+      break;
+  }
+
+  // Compute the final value of READONLY for MSAA.
+  //
+  // We always set the READONLY state for elements that have the
+  // aria-readonly attribute and for a few roles (in the switch above),
+  // including read-only text fields.
+  // The majority of focusable controls should not have the read-only state set.
+  if (state & (1 << ui::AX_STATE_FOCUSABLE) &&
+      GetData().role != ROLE_SYSTEM_DOCUMENT &&
+      GetData().role != ROLE_SYSTEM_TEXT) {
+    msaa_state &= ~(STATE_SYSTEM_READONLY);
+  }
+  if (!(state & (1 << ui::AX_STATE_READ_ONLY)))
+    msaa_state &= ~(STATE_SYSTEM_READONLY);
+
+  if (GetData().GetBoolAttribute(ui::AX_ATTR_ARIA_READONLY))
+    msaa_state |= STATE_SYSTEM_READONLY;
+
   return msaa_state;
 }
 
diff --git a/ui/accessibility/platform/test_ax_node_wrapper.cc b/ui/accessibility/platform/test_ax_node_wrapper.cc
index 10ab594..94ddc84 100644
--- a/ui/accessibility/platform/test_ax_node_wrapper.cc
+++ b/ui/accessibility/platform/test_ax_node_wrapper.cc
@@ -125,6 +125,10 @@
   return true;
 }
 
+bool TestAXNodeWrapper::ShouldIgnoreHoveredStateForTesting() {
+  return true;
+}
+
 TestAXNodeWrapper::TestAXNodeWrapper(AXTree* tree, AXNode* node)
     : tree_(tree),
       node_(node),
diff --git a/ui/accessibility/platform/test_ax_node_wrapper.h b/ui/accessibility/platform/test_ax_node_wrapper.h
index 4d3f2b9..a0c5440 100644
--- a/ui/accessibility/platform/test_ax_node_wrapper.h
+++ b/ui/accessibility/platform/test_ax_node_wrapper.h
@@ -39,6 +39,7 @@
   gfx::NativeViewAccessible GetFocus() override;
   gfx::AcceleratedWidget GetTargetForNativeAccessibilityEvent() override;
   bool AccessibilityPerformAction(const ui::AXActionData& data) override;
+  bool ShouldIgnoreHoveredStateForTesting() override;
 
  private:
   TestAXNodeWrapper(AXTree* tree, AXNode* node);
diff --git a/ui/views/accessibility/native_view_accessibility_auralinux.cc b/ui/views/accessibility/native_view_accessibility_auralinux.cc
index 89b42737..316bd4f 100644
--- a/ui/views/accessibility/native_view_accessibility_auralinux.cc
+++ b/ui/views/accessibility/native_view_accessibility_auralinux.cc
@@ -109,6 +109,8 @@
     return false;
   }
 
+  bool ShouldIgnoreHoveredStateForTesting() override { return false; }
+
  private:
   friend struct base::DefaultSingletonTraits<AuraLinuxApplication>;
 
diff --git a/ui/views/accessibility/native_view_accessibility_base.cc b/ui/views/accessibility/native_view_accessibility_base.cc
index 300e86a0..3eca6e3 100644
--- a/ui/views/accessibility/native_view_accessibility_base.cc
+++ b/ui/views/accessibility/native_view_accessibility_base.cc
@@ -199,6 +199,10 @@
   return view_->HandleAccessibleAction(data);
 }
 
+bool NativeViewAccessibilityBase::ShouldIgnoreHoveredStateForTesting() {
+  return false;
+}
+
 void NativeViewAccessibilityBase::OnWidgetDestroying(Widget* widget) {
   if (parent_widget_ == widget) {
     parent_widget_->RemoveObserver(this);
diff --git a/ui/views/accessibility/native_view_accessibility_base.h b/ui/views/accessibility/native_view_accessibility_base.h
index fb0d0fe..cc8acfb 100644
--- a/ui/views/accessibility/native_view_accessibility_base.h
+++ b/ui/views/accessibility/native_view_accessibility_base.h
@@ -47,6 +47,7 @@
   gfx::NativeViewAccessible GetFocus() override;
   gfx::AcceleratedWidget GetTargetForNativeAccessibilityEvent() override;
   bool AccessibilityPerformAction(const ui::AXActionData& data) override;
+  bool ShouldIgnoreHoveredStateForTesting() override;
 
   // WidgetObserver
   void OnWidgetDestroying(Widget* widget) override;