Browse Source

chore: cherry-pick bc4df9dd11e609e from chromium (#24084)

* chore: cherry-pick bc4df9dd11e609e from chromium

* chore: update patches

Co-authored-by: deepak1556 <[email protected]>
trop[bot] 4 years ago
parent
commit
0b846b2f13

+ 1 - 0
patches/chromium/.patches

@@ -107,3 +107,4 @@ fix_swap_global_proxies_before_initializing_the_windows_proxies.patch
 fix_default_to_ntlm_v2_in_network_service.patch
 a11y_allows_klistboxoption_as_an_item_to_kgroup.patch
 fix_handling_non_client_pointer_events_from_pen_on_windows_10.patch
+a11y_iterate_all_descendants_for_getselectioncount.patch

+ 393 - 0
patches/chromium/a11y_iterate_all_descendants_for_getselectioncount.patch

@@ -0,0 +1,393 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Julie Jeongeun Kim <[email protected]>
+Date: Fri, 10 Apr 2020 05:50:17 +0000
+Subject: a11y: Iterate all descendants for GetSelectionCount
+
+This CL iterates all descendants for GetSelectionCount and
+GetSelectedChild. When listbox has group children, it should
+iterates their children as well to check the select state.
+
+Bug: 1058961
+Change-Id: Ib6459bf6f47023d4258ef4c2f2dc545739d7a61b
+Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2115211
+Commit-Queue: Julie Kim <[email protected]>
+Reviewed-by: Nektarios Paisios <[email protected]>
+Reviewed-by: Aaron Leventhal <[email protected]>
+Reviewed-by: Joanmarie Diggs <[email protected]>
+Cr-Commit-Position: refs/heads/master@{#758140}
+
+diff --git a/ui/accessibility/platform/ax_platform_node_auralinux.cc b/ui/accessibility/platform/ax_platform_node_auralinux.cc
+index 86ce9de34a5286b1c3990c4aab614450e1d6fb63..88528364e148284b7e45958451a65497c295f256 100644
+--- a/ui/accessibility/platform/ax_platform_node_auralinux.cc
++++ b/ui/accessibility/platform/ax_platform_node_auralinux.cc
+@@ -1435,19 +1435,10 @@ AtkObject* RefSelection(AtkSelection* selection, gint requested_child_index) {
+   if (!obj)
+     return nullptr;
+ 
+-  int child_count = obj->GetChildCount();
+-  gint selected_count = 0;
+-  for (int i = 0; i < child_count; ++i) {
+-    AtkObject* child = obj->ChildAtIndex(i);
+-    AXPlatformNodeAuraLinux* child_ax_node =
+-        AtkObjectToAXPlatformNodeAuraLinux(child);
+-    if (!child_ax_node)
+-      continue;
+-
+-    if (child_ax_node->GetBoolAttribute(ax::mojom::BoolAttribute::kSelected)) {
+-      if (selected_count == requested_child_index)
+-        return static_cast<AtkObject*>(g_object_ref(child));
+-      ++selected_count;
++  if (auto* selected_child = obj->GetSelectedItem(requested_child_index)) {
++    if (AtkObject* atk_object = selected_child->GetNativeViewAccessible()) {
++      g_object_ref(atk_object);
++      return atk_object;
+     }
+   }
+ 
+@@ -1460,19 +1451,7 @@ gint GetSelectionCount(AtkSelection* selection) {
+   if (!obj)
+     return 0;
+ 
+-  int child_count = obj->GetChildCount();
+-  gint selected_count = 0;
+-  for (int i = 0; i < child_count; ++i) {
+-    AXPlatformNodeAuraLinux* child =
+-        AtkObjectToAXPlatformNodeAuraLinux(obj->ChildAtIndex(i));
+-    if (!child)
+-      continue;
+-
+-    if (child->GetBoolAttribute(ax::mojom::BoolAttribute::kSelected))
+-      ++selected_count;
+-  }
+-
+-  return selected_count;
++  return obj->GetSelectionCount();
+ }
+ 
+ gboolean IsChildSelected(AtkSelection* selection, gint index) {
+diff --git a/ui/accessibility/platform/ax_platform_node_auralinux_unittest.cc b/ui/accessibility/platform/ax_platform_node_auralinux_unittest.cc
+index f17dbeda08917ef636f1f4342011394f076cee35..eb61fc1c1224e8a2ca94929e07f24bfa7dc41691 100644
+--- a/ui/accessibility/platform/ax_platform_node_auralinux_unittest.cc
++++ b/ui/accessibility/platform/ax_platform_node_auralinux_unittest.cc
+@@ -1853,6 +1853,8 @@ TEST_F(AXPlatformNodeAuraLinuxTest, TestAtkSelectionInterface) {
+   AXNodeData root;
+   root.id = 1;
+   root.role = ax::mojom::Role::kListBox;
++  root.AddState(ax::mojom::State::kFocusable);
++  root.AddState(ax::mojom::State::kMultiselectable);
+   root.child_ids.push_back(2);
+   root.child_ids.push_back(3);
+   root.child_ids.push_back(4);
+diff --git a/ui/accessibility/platform/ax_platform_node_base.cc b/ui/accessibility/platform/ax_platform_node_base.cc
+index d705cd927ed816208b22106e5beb30c550c55ca3..bf9dc27604ff5ae7f88c8fd734ec26c699e7bc04 100644
+--- a/ui/accessibility/platform/ax_platform_node_base.cc
++++ b/ui/accessibility/platform/ax_platform_node_base.cc
+@@ -92,7 +92,7 @@ int AXPlatformNodeBase::GetChildCount() const {
+   return 0;
+ }
+ 
+-gfx::NativeViewAccessible AXPlatformNodeBase::ChildAtIndex(int index) {
++gfx::NativeViewAccessible AXPlatformNodeBase::ChildAtIndex(int index) const {
+   if (delegate_)
+     return delegate_->ChildAtIndex(index);
+   return nullptr;
+@@ -701,8 +701,8 @@ bool AXPlatformNodeBase::HasCaret() {
+   return focus_object->IsDescendantOf(this);
+ }
+ 
+-bool AXPlatformNodeBase::IsLeaf() {
+-  if (GetChildCount() == 0)
++bool AXPlatformNodeBase::IsLeaf() const {
++  if (!GetChildCount())
+     return true;
+ 
+   // These types of objects may have children that we use as internal
+@@ -1868,9 +1868,73 @@ ui::TextAttributeList AXPlatformNodeBase::ComputeTextAttributes() const {
+   return attributes;
+ }
+ 
++int AXPlatformNodeBase::GetSelectionCount() const {
++  int max_items = GetMaxSelectableItems();
++  if (!max_items)
++    return 0;
++  return GetSelectedItems(max_items);
++}
++
++AXPlatformNodeBase* AXPlatformNodeBase::GetSelectedItem(
++    int selected_index) const {
++  DCHECK_GE(selected_index, 0);
++  int max_items = GetMaxSelectableItems();
++  if (max_items == 0)
++    return nullptr;
++  if (selected_index >= max_items)
++    return nullptr;
++
++  std::vector<AXPlatformNodeBase*> selected_children;
++  int requested_count = selected_index + 1;
++  int returned_count = GetSelectedItems(requested_count, &selected_children);
++
++  if (returned_count <= selected_index)
++    return nullptr;
++
++  DCHECK(!selected_children.empty());
++  DCHECK_LT(selected_index, static_cast<int>(selected_children.size()));
++  return selected_children[selected_index];
++}
++
++int AXPlatformNodeBase::GetSelectedItems(
++    int max_items,
++    std::vector<AXPlatformNodeBase*>* out_selected_items) const {
++  int selected_count = 0;
++  // TODO(Nektar): Remove const_cast by making all tree traversal methods const.
++  for (AXPlatformNodeBase* child =
++           const_cast<AXPlatformNodeBase*>(this)->GetFirstChild();
++       child && selected_count < max_items; child = child->GetNextSibling()) {
++    if (!IsItemLike(child->GetData().role)) {
++      selected_count += child->GetSelectedItems(max_items - selected_count,
++                                                out_selected_items);
++    } else if (child->GetBoolAttribute(ax::mojom::BoolAttribute::kSelected)) {
++      selected_count++;
++      if (out_selected_items)
++        out_selected_items->emplace_back(child);
++    }
++  }
++  return selected_count;
++}
++
+ void AXPlatformNodeBase::SanitizeTextAttributeValue(const std::string& input,
+                                                     std::string* output) const {
+   DCHECK(output);
+ }
+ 
++int AXPlatformNodeBase::GetMaxSelectableItems() const {
++  if (!GetData().HasState(ax::mojom::State::kFocusable))
++    return 0;
++
++  if (IsLeaf())
++    return 0;
++
++  if (!IsContainerWithSelectableChildren(GetData().role))
++    return 0;
++
++  int max_items = 1;
++  if (GetData().HasState(ax::mojom::State::kMultiselectable))
++    max_items = std::numeric_limits<int>::max();
++  return max_items;
++}
++
+ }  // namespace ui
+diff --git a/ui/accessibility/platform/ax_platform_node_base.h b/ui/accessibility/platform/ax_platform_node_base.h
+index 2bee9a7e3108963847486139d40a087428323fbb..98a72c6be316803618f74ae0766e1fd24515509a 100644
+--- a/ui/accessibility/platform/ax_platform_node_base.h
++++ b/ui/accessibility/platform/ax_platform_node_base.h
+@@ -57,7 +57,7 @@ class AX_EXPORT AXPlatformNodeBase : public AXPlatformNode {
+   gfx::NativeViewAccessible GetFocus();
+   gfx::NativeViewAccessible GetParent() const;
+   int GetChildCount() const;
+-  gfx::NativeViewAccessible ChildAtIndex(int index);
++  gfx::NativeViewAccessible ChildAtIndex(int index) const;
+ 
+   // This needs to be implemented for each platform.
+   virtual int GetIndexInParent();
+@@ -202,7 +202,7 @@ class AX_EXPORT AXPlatformNodeBase : public AXPlatformNode {
+   // The definition of a leaf may vary depending on the platform,
+   // but a leaf node should never have children that are focusable or
+   // that might send notifications.
+-  bool IsLeaf();
++  bool IsLeaf() const;
+ 
+   bool IsInvisibleOrIgnored() const;
+ 
+@@ -275,6 +275,24 @@ class AX_EXPORT AXPlatformNodeBase : public AXPlatformNode {
+ 
+   ui::TextAttributeList ComputeTextAttributes() const;
+ 
++  // Get the number of items selected. It checks kMultiselectable and
++  // kFocusable. and uses GetSelectedItems to get the selected number.
++  int GetSelectionCount() const;
++
++  // If this object is a container that supports selectable children, returns
++  // the selected item at the provided index.
++  AXPlatformNodeBase* GetSelectedItem(int selected_index) const;
++
++  // If this object is a container that supports selectable children,
++  // returns the number of selected items in this container.
++  // |out_selected_items| could be set to nullptr if the caller just
++  // needs to know the number of items selected.
++  // |max_items| represents the number that the caller expects as a
++  // maximum. For a single selection list box, it will be 1.
++  int GetSelectedItems(
++      int max_items,
++      std::vector<AXPlatformNodeBase*>* out_selected_items = nullptr) const;
++
+   //
+   // Delegate.  This is a weak reference which owns |this|.
+   //
+@@ -412,6 +430,11 @@ class AX_EXPORT AXPlatformNodeBase : public AXPlatformNode {
+ 
+   std::string GetInvalidValue() const;
+ 
++  // Based on the characteristics of this object, such as its role and the
++  // presence of a multiselectable attribute, returns the maximum number of
++  // selectable children that this object could potentially contain.
++  int GetMaxSelectableItems() const;
++
+   AXHypertext hypertext_;
+ 
+  private:
+diff --git a/ui/accessibility/platform/ax_platform_node_unittest.cc b/ui/accessibility/platform/ax_platform_node_unittest.cc
+index 9950894e9fbb30b79b392ffe782dd31f75bd7f52..d8bfc0ed9c2b20c64dd15f3c6c2ef8cfaa87c510 100644
+--- a/ui/accessibility/platform/ax_platform_node_unittest.cc
++++ b/ui/accessibility/platform/ax_platform_node_unittest.cc
+@@ -379,13 +379,13 @@ AXTreeUpdate AXPlatformNodeTest::BuildListBox(
+     bool option_1_is_selected,
+     bool option_2_is_selected,
+     bool option_3_is_selected,
+-    ax::mojom::State additional_state /* ax::mojom::State::kNone */) {
++    const std::vector<ax::mojom::State>& additional_state) {
+   AXNodeData listbox;
+   listbox.id = 1;
+   listbox.SetName("ListBox");
+   listbox.role = ax::mojom::Role::kListBox;
+-  if (additional_state != ax::mojom::State::kNone)
+-    listbox.AddState(additional_state);
++  for (auto state : additional_state)
++    listbox.AddState(state);
+ 
+   AXNodeData option_1;
+   option_1.id = 2;
+diff --git a/ui/accessibility/platform/ax_platform_node_unittest.h b/ui/accessibility/platform/ax_platform_node_unittest.h
+index b512b5a79f103bf4524a7467f4ae60d8036054b6..2b5392f589b26795cc3971be297257b1c2ece615 100644
+--- a/ui/accessibility/platform/ax_platform_node_unittest.h
++++ b/ui/accessibility/platform/ax_platform_node_unittest.h
+@@ -58,10 +58,11 @@ class AXPlatformNodeTest : public testing::Test, public AXTreeManager {
+   AXTreeUpdate Build3X3Table();
+   AXTreeUpdate BuildAriaColumnAndRowCountGrids();
+ 
+-  AXTreeUpdate BuildListBox(bool option_1_is_selected,
+-                            bool option_2_is_selected,
+-                            bool option_3_is_selected,
+-                            ax::mojom::State additional_state);
++  AXTreeUpdate BuildListBox(
++      bool option_1_is_selected,
++      bool option_2_is_selected,
++      bool option_3_is_selected,
++      const std::vector<ax::mojom::State>& additional_state);
+ 
+   std::unique_ptr<AXTree> tree_;
+ };
+diff --git a/ui/accessibility/platform/ax_platform_node_win.cc b/ui/accessibility/platform/ax_platform_node_win.cc
+index 6b70f5eed20290141adc659b71900536ef052bb2..232eff3c4af371eaa7026f2a14953c947b2bda7a 100644
+--- a/ui/accessibility/platform/ax_platform_node_win.cc
++++ b/ui/accessibility/platform/ax_platform_node_win.cc
+@@ -2148,15 +2148,10 @@ IFACEMETHODIMP AXPlatformNodeWin::GetSelection(SAFEARRAY** result) {
+   WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_SELECTION_GETSELECTION);
+   UIA_VALIDATE_CALL_1_ARG(result);
+ 
+-  std::vector<AXPlatformNodeWin*> selected_children;
+-  LONG child_count = GetDelegate()->GetChildCount();
+-  for (LONG i = 0; i < child_count; ++i) {
+-    auto* child = static_cast<AXPlatformNodeWin*>(
+-        FromNativeViewAccessible(GetDelegate()->ChildAtIndex(i)));
+-    DCHECK(child);
+-    if (child->GetData().GetBoolAttribute(ax::mojom::BoolAttribute::kSelected))
+-      selected_children.push_back(child);
+-  }
++  std::vector<AXPlatformNodeBase*> selected_children;
++  int max_items = GetMaxSelectableItems();
++  if (max_items)
++    GetSelectedItems(max_items, &selected_children);
+ 
+   LONG selected_children_count = selected_children.size();
+   *result = SafeArrayCreateVector(VT_UNKNOWN, 0, selected_children_count);
+@@ -2164,9 +2159,10 @@ IFACEMETHODIMP AXPlatformNodeWin::GetSelection(SAFEARRAY** result) {
+     return E_OUTOFMEMORY;
+ 
+   for (LONG i = 0; i < selected_children_count; ++i) {
++    AXPlatformNodeWin* children =
++        static_cast<AXPlatformNodeWin*>(selected_children[i]);
+     HRESULT hr = SafeArrayPutElement(
+-        *result, &i,
+-        static_cast<IRawElementProviderSimple*>(selected_children[i]));
++        *result, &i, static_cast<IRawElementProviderSimple*>(children));
+     if (FAILED(hr)) {
+       SafeArrayDestroy(*result);
+       *result = nullptr;
+diff --git a/ui/accessibility/platform/ax_platform_node_win_unittest.cc b/ui/accessibility/platform/ax_platform_node_win_unittest.cc
+index 31ebeaaae3ea801add4e7f8a609649de425ead04..e64aa75a2dd98ce2968ba314f78423058488cbd7 100644
+--- a/ui/accessibility/platform/ax_platform_node_win_unittest.cc
++++ b/ui/accessibility/platform/ax_platform_node_win_unittest.cc
+@@ -4532,8 +4532,7 @@ TEST_F(AXPlatformNodeWinTest, TestUIANavigate) {
+ TEST_F(AXPlatformNodeWinTest, TestISelectionProviderCanSelectMultipleDefault) {
+   Init(BuildListBox(/*option_1_is_selected*/ false,
+                     /*option_2_is_selected*/ false,
+-                    /*option_3_is_selected*/ false,
+-                    /*additional_state*/ ax::mojom::State::kNone));
++                    /*option_3_is_selected*/ false, {}));
+ 
+   ComPtr<ISelectionProvider> selection_provider(
+       QueryInterfaceFromNode<ISelectionProvider>(GetRootNode()));
+@@ -4545,10 +4544,12 @@ TEST_F(AXPlatformNodeWinTest, TestISelectionProviderCanSelectMultipleDefault) {
+ }
+ 
+ TEST_F(AXPlatformNodeWinTest, TestISelectionProviderCanSelectMultipleTrue) {
++  const std::vector<ax::mojom::State> state = {
++      ax::mojom::State::kMultiselectable, ax::mojom::State::kFocusable};
+   Init(BuildListBox(/*option_1_is_selected*/ false,
+                     /*option_2_is_selected*/ false,
+                     /*option_3_is_selected*/ false,
+-                    /*additional_state*/ ax::mojom::State::kMultiselectable));
++                    /*additional_state*/ state));
+ 
+   ComPtr<ISelectionProvider> selection_provider(
+       QueryInterfaceFromNode<ISelectionProvider>(GetRootNode()));
+@@ -4564,7 +4565,7 @@ TEST_F(AXPlatformNodeWinTest,
+   Init(BuildListBox(/*option_1_is_selected*/ false,
+                     /*option_2_is_selected*/ false,
+                     /*option_3_is_selected*/ false,
+-                    /*additional_state*/ ax::mojom::State::kNone));
++                    /*additional_state*/ {}));
+ 
+   ComPtr<ISelectionProvider> selection_provider(
+       QueryInterfaceFromNode<ISelectionProvider>(GetRootNode()));
+@@ -4579,7 +4580,7 @@ TEST_F(AXPlatformNodeWinTest, TestISelectionProviderIsSelectionRequiredTrue) {
+   Init(BuildListBox(/*option_1_is_selected*/ false,
+                     /*option_2_is_selected*/ false,
+                     /*option_3_is_selected*/ false,
+-                    /*additional_state*/ ax::mojom::State::kRequired));
++                    /*additional_state*/ {ax::mojom::State::kRequired}));
+ 
+   ComPtr<ISelectionProvider> selection_provider(
+       QueryInterfaceFromNode<ISelectionProvider>(GetRootNode()));
+@@ -4594,7 +4595,7 @@ TEST_F(AXPlatformNodeWinTest, TestISelectionProviderGetSelectionNoneSelected) {
+   Init(BuildListBox(/*option_1_is_selected*/ false,
+                     /*option_2_is_selected*/ false,
+                     /*option_3_is_selected*/ false,
+-                    /*additional_state*/ ax::mojom::State::kNone));
++                    /*additional_state*/ {ax::mojom::State::kFocusable}));
+ 
+   ComPtr<ISelectionProvider> selection_provider(
+       QueryInterfaceFromNode<ISelectionProvider>(GetRootNode()));
+@@ -4620,7 +4621,7 @@ TEST_F(AXPlatformNodeWinTest,
+   Init(BuildListBox(/*option_1_is_selected*/ false,
+                     /*option_2_is_selected*/ true,
+                     /*option_3_is_selected*/ false,
+-                    /*additional_state*/ ax::mojom::State::kNone));
++                    /*additional_state*/ {ax::mojom::State::kFocusable}));
+ 
+   ComPtr<ISelectionProvider> selection_provider(
+       QueryInterfaceFromNode<ISelectionProvider>(GetRootNode()));
+@@ -4652,10 +4653,12 @@ TEST_F(AXPlatformNodeWinTest,
+ 
+ TEST_F(AXPlatformNodeWinTest,
+        TestISelectionProviderGetSelectionMultipleItemsSelected) {
++  const std::vector<ax::mojom::State> state = {
++      ax::mojom::State::kMultiselectable, ax::mojom::State::kFocusable};
+   Init(BuildListBox(/*option_1_is_selected*/ true,
+                     /*option_2_is_selected*/ true,
+                     /*option_3_is_selected*/ true,
+-                    /*additional_state*/ ax::mojom::State::kNone));
++                    /*additional_state*/ state));
+ 
+   ComPtr<ISelectionProvider> selection_provider(
+       QueryInterfaceFromNode<ISelectionProvider>(GetRootNode()));