OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "base/memory/ptr_util.h" | 5 #include "base/memory/ptr_util.h" |
6 #include "base/strings/utf_string_conversions.h" | 6 #include "base/strings/utf_string_conversions.h" |
7 #include "ui/accessibility/ax_node_data.h" | 7 #include "ui/accessibility/ax_node_data.h" |
8 #include "ui/gfx/geometry/rect_conversions.h" | 8 #include "ui/gfx/geometry/rect_conversions.h" |
9 #include "ui/views/accessibility/ax_aura_obj_cache.h" | 9 #include "ui/views/accessibility/ax_aura_obj_cache.h" |
10 #include "ui/views/accessibility/ax_aura_obj_wrapper.h" | 10 #include "ui/views/accessibility/ax_aura_obj_wrapper.h" |
11 #include "ui/views/accessibility/ax_widget_obj_wrapper.h" | 11 #include "ui/views/accessibility/ax_widget_obj_wrapper.h" |
12 #include "ui/views/accessibility/native_view_accessibility_base.h" | 12 #include "ui/views/accessibility/native_view_accessibility_base.h" |
13 #include "ui/views/controls/button/button.h" | 13 #include "ui/views/controls/button/button.h" |
14 #include "ui/views/controls/label.h" | 14 #include "ui/views/controls/label.h" |
15 #include "ui/views/test/views_test_base.h" | 15 #include "ui/views/test/views_test_base.h" |
| 16 #include "ui/views/widget/widget.h" |
16 | 17 |
17 namespace views { | 18 namespace views { |
18 namespace test { | 19 namespace test { |
19 | 20 |
20 class NativeViewAccessibilityTest; | |
21 | |
22 namespace { | 21 namespace { |
23 | 22 |
24 class TestButton : public Button { | 23 class TestButton : public Button { |
25 public: | 24 public: |
26 TestButton() : Button(NULL) {} | 25 TestButton() : Button(NULL) {} |
27 }; | 26 }; |
28 | 27 |
| 28 // Adds a View with given bounds and focusability to a parent. |
| 29 View* AddNewChildWithBoundsAndFocusability(View* parent, |
| 30 const gfx::Rect& bounds, |
| 31 bool focusable) { |
| 32 View* child = new View; |
| 33 child->SetBoundsRect(bounds); |
| 34 parent->AddChildView(child); |
| 35 child->SetFocusBehavior(focusable ? ClientView::FocusBehavior::ACCESSIBLE_ONLY |
| 36 : ClientView::FocusBehavior::NEVER); |
| 37 return child; |
| 38 } |
| 39 |
29 } // namespace | 40 } // namespace |
30 | 41 |
31 class NativeViewAccessibilityTest : public ViewsTestBase { | 42 class NativeViewAccessibilityTest : public ViewsTestBase { |
32 public: | 43 public: |
33 NativeViewAccessibilityTest() {} | 44 NativeViewAccessibilityTest() {} |
34 ~NativeViewAccessibilityTest() override {} | 45 ~NativeViewAccessibilityTest() override {} |
35 | 46 |
36 void SetUp() override { | 47 void SetUp() override { |
37 ViewsTestBase::SetUp(); | 48 ViewsTestBase::SetUp(); |
38 | 49 |
39 widget_ = new views::Widget; | 50 widget_ = new Widget; |
40 views::Widget::InitParams params = | 51 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW); |
41 CreateParams(views::Widget::InitParams::TYPE_WINDOW); | |
42 params.bounds = gfx::Rect(0, 0, 200, 200); | 52 params.bounds = gfx::Rect(0, 0, 200, 200); |
43 widget_->Init(params); | 53 widget_->Init(params); |
44 | 54 |
45 button_ = new TestButton(); | 55 button_ = new TestButton(); |
46 button_->SetSize(gfx::Size(20, 20)); | 56 button_->SetSize(gfx::Size(20, 20)); |
47 button_accessibility_ = NativeViewAccessibility::Create(button_); | 57 button_accessibility_ = NativeViewAccessibility::Create(button_); |
48 | 58 |
49 label_ = new Label(); | 59 label_ = new Label(); |
50 button_->AddChildView(label_); | 60 button_->AddChildView(label_); |
51 label_accessibility_ = NativeViewAccessibility::Create(label_); | 61 label_accessibility_ = NativeViewAccessibility::Create(label_); |
(...skipping 12 matching lines...) Expand all Loading... |
64 return static_cast<NativeViewAccessibilityBase*>( | 74 return static_cast<NativeViewAccessibilityBase*>( |
65 button_accessibility_.get()); | 75 button_accessibility_.get()); |
66 } | 76 } |
67 | 77 |
68 NativeViewAccessibilityBase* label_accessibility() { | 78 NativeViewAccessibilityBase* label_accessibility() { |
69 return static_cast<NativeViewAccessibilityBase*>( | 79 return static_cast<NativeViewAccessibilityBase*>( |
70 label_accessibility_.get()); | 80 label_accessibility_.get()); |
71 } | 81 } |
72 | 82 |
73 protected: | 83 protected: |
74 views::Widget* widget_; | 84 Widget* widget_; |
75 TestButton* button_; | 85 TestButton* button_; |
76 std::unique_ptr<NativeViewAccessibility> button_accessibility_; | 86 std::unique_ptr<NativeViewAccessibility> button_accessibility_; |
77 Label* label_; | 87 Label* label_; |
78 std::unique_ptr<NativeViewAccessibility> label_accessibility_; | 88 std::unique_ptr<NativeViewAccessibility> label_accessibility_; |
| 89 |
| 90 DISALLOW_COPY_AND_ASSIGN(NativeViewAccessibilityTest); |
79 }; | 91 }; |
80 | 92 |
81 TEST_F(NativeViewAccessibilityTest, RoleShouldMatch) { | 93 TEST_F(NativeViewAccessibilityTest, RoleShouldMatch) { |
82 EXPECT_EQ(ui::AX_ROLE_BUTTON, button_accessibility()->GetData().role); | 94 EXPECT_EQ(ui::AX_ROLE_BUTTON, button_accessibility()->GetData().role); |
| 95 // Since the label is a subview of |button_|, and the button is keyboard |
| 96 // focusable, the label is assumed to form part of the button and not have a |
| 97 // role of its own. |
| 98 EXPECT_EQ(ui::AX_ROLE_IGNORED, label_accessibility()->GetData().role); |
| 99 // This will happen for all potentially keyboard-focusable Views with |
| 100 // non-keyboard-focusable children, so if we make the button unfocusable, the |
| 101 // label will be allowed to have its own role again. |
| 102 button_->SetFocusBehavior(View::FocusBehavior::NEVER); |
83 EXPECT_EQ(ui::AX_ROLE_STATIC_TEXT, label_accessibility()->GetData().role); | 103 EXPECT_EQ(ui::AX_ROLE_STATIC_TEXT, label_accessibility()->GetData().role); |
84 } | 104 } |
85 | 105 |
86 TEST_F(NativeViewAccessibilityTest, BoundsShouldMatch) { | 106 TEST_F(NativeViewAccessibilityTest, BoundsShouldMatch) { |
87 gfx::Rect bounds = | 107 gfx::Rect bounds = |
88 gfx::ToEnclosingRect(button_accessibility()->GetData().location); | 108 gfx::ToEnclosingRect(button_accessibility()->GetData().location); |
89 bounds.Offset(button_accessibility()->GetGlobalCoordinateOffset()); | 109 bounds.Offset(button_accessibility()->GetGlobalCoordinateOffset()); |
90 EXPECT_EQ(button_->GetBoundsInScreen(), bounds); | 110 EXPECT_EQ(button_->GetBoundsInScreen(), bounds); |
91 } | 111 } |
92 | 112 |
93 TEST_F(NativeViewAccessibilityTest, LabelIsChildOfButton) { | 113 TEST_F(NativeViewAccessibilityTest, LabelIsChildOfButton) { |
| 114 EXPECT_EQ(0, button_accessibility()->GetChildCount()); |
| 115 EXPECT_EQ(nullptr, button_accessibility()->ChildAtIndex(0)); |
| 116 EXPECT_EQ(button_->GetNativeViewAccessible(), |
| 117 label_accessibility()->GetParent()); |
| 118 |
| 119 // If |button_| is no longer focusable, |label_| should show up again. |
| 120 button_->SetFocusBehavior(View::FocusBehavior::NEVER); |
94 EXPECT_EQ(1, button_accessibility()->GetChildCount()); | 121 EXPECT_EQ(1, button_accessibility()->GetChildCount()); |
95 EXPECT_EQ(label_->GetNativeViewAccessible(), | 122 EXPECT_EQ(label_->GetNativeViewAccessible(), |
96 button_accessibility()->ChildAtIndex(0)); | 123 button_accessibility()->ChildAtIndex(0)); |
97 EXPECT_EQ(button_->GetNativeViewAccessible(), | 124 EXPECT_EQ(button_->GetNativeViewAccessible(), |
98 label_accessibility()->GetParent()); | 125 label_accessibility()->GetParent()); |
99 } | 126 } |
100 | 127 |
101 // Verify Views with invisible ancestors have AX_STATE_INVISIBLE. | 128 // Verify Views with invisible ancestors have AX_STATE_INVISIBLE. |
102 TEST_F(NativeViewAccessibilityTest, InvisibleViews) { | 129 TEST_F(NativeViewAccessibilityTest, InvisibleViews) { |
103 EXPECT_TRUE(widget_->IsVisible()); | 130 EXPECT_TRUE(widget_->IsVisible()); |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
142 bool is_destroying_parent_widget = (parent_widget_ == widget); | 169 bool is_destroying_parent_widget = (parent_widget_ == widget); |
143 NativeViewAccessibilityBase::OnWidgetDestroying(widget); | 170 NativeViewAccessibilityBase::OnWidgetDestroying(widget); |
144 if (is_destroying_parent_widget) | 171 if (is_destroying_parent_widget) |
145 delete this; | 172 delete this; |
146 } | 173 } |
147 }; | 174 }; |
148 | 175 |
149 TEST_F(NativeViewAccessibilityTest, CrashOnWidgetDestroyed) { | 176 TEST_F(NativeViewAccessibilityTest, CrashOnWidgetDestroyed) { |
150 std::unique_ptr<Widget> parent_widget(new Widget); | 177 std::unique_ptr<Widget> parent_widget(new Widget); |
151 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP); | 178 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP); |
152 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; | 179 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; |
153 params.bounds = gfx::Rect(50, 50, 650, 650); | 180 params.bounds = gfx::Rect(50, 50, 650, 650); |
154 parent_widget->Init(params); | 181 parent_widget->Init(params); |
155 | 182 |
156 std::unique_ptr<Widget> child_widget(new Widget); | 183 std::unique_ptr<Widget> child_widget(new Widget); |
157 child_widget->Init(params); | 184 child_widget->Init(params); |
158 | 185 |
159 // Make sure that deleting the parent widget can't cause a crash | 186 // Make sure that deleting the parent widget can't cause a crash |
160 // due to NativeViewAccessibility not unregistering itself as a | 187 // due to NativeViewAccessibility not unregistering itself as a |
161 // WidgetObserver. Note that TestNativeViewAccessibility is a subclass | 188 // WidgetObserver. Note that TestNativeViewAccessibility is a subclass |
162 // defined above that destroys itself when its parent widget is destroyed. | 189 // defined above that destroys itself when its parent widget is destroyed. |
(...skipping 10 matching lines...) Expand all Loading... |
173 ~DerivedTestView() override {} | 200 ~DerivedTestView() override {} |
174 | 201 |
175 void OnBlur() override { SetVisible(false); } | 202 void OnBlur() override { SetVisible(false); } |
176 }; | 203 }; |
177 | 204 |
178 class AxTestViewsDelegate : public TestViewsDelegate { | 205 class AxTestViewsDelegate : public TestViewsDelegate { |
179 public: | 206 public: |
180 AxTestViewsDelegate() {} | 207 AxTestViewsDelegate() {} |
181 ~AxTestViewsDelegate() override {} | 208 ~AxTestViewsDelegate() override {} |
182 | 209 |
183 void NotifyAccessibilityEvent(views::View* view, | 210 void NotifyAccessibilityEvent(View* view, ui::AXEvent event_type) override { |
184 ui::AXEvent event_type) override { | |
185 AXAuraObjCache* ax = AXAuraObjCache::GetInstance(); | 211 AXAuraObjCache* ax = AXAuraObjCache::GetInstance(); |
186 std::vector<AXAuraObjWrapper*> out_children; | 212 std::vector<AXAuraObjWrapper*> out_children; |
187 AXAuraObjWrapper* ax_obj = ax->GetOrCreate(view->GetWidget()); | 213 AXAuraObjWrapper* ax_obj = ax->GetOrCreate(view->GetWidget()); |
188 ax_obj->GetChildren(&out_children); | 214 ax_obj->GetChildren(&out_children); |
189 } | 215 } |
190 | 216 |
191 private: | 217 private: |
192 DISALLOW_COPY_AND_ASSIGN(AxTestViewsDelegate); | 218 DISALLOW_COPY_AND_ASSIGN(AxTestViewsDelegate); |
193 }; | 219 }; |
194 | 220 |
195 class AXViewTest : public ViewsTestBase { | 221 class AXViewTest : public ViewsTestBase { |
196 public: | 222 public: |
197 AXViewTest() {} | 223 AXViewTest() {} |
198 ~AXViewTest() override {} | 224 ~AXViewTest() override {} |
199 void SetUp() override { | 225 void SetUp() override { |
200 std::unique_ptr<TestViewsDelegate> views_delegate( | 226 std::unique_ptr<TestViewsDelegate> views_delegate( |
201 new AxTestViewsDelegate()); | 227 new AxTestViewsDelegate()); |
202 set_views_delegate(std::move(views_delegate)); | 228 set_views_delegate(std::move(views_delegate)); |
203 views::ViewsTestBase::SetUp(); | 229 ViewsTestBase::SetUp(); |
204 } | 230 } |
205 }; | 231 }; |
206 | 232 |
207 // Check if the destruction of the widget ends successfully if |view|'s | 233 // Check if the destruction of the widget ends successfully if |view|'s |
208 // visibility changed during destruction. | 234 // visibility changed during destruction. |
209 TEST_F(AXViewTest, LayoutCalledInvalidateRootView) { | 235 TEST_F(AXViewTest, LayoutCalledInvalidateRootView) { |
210 std::unique_ptr<Widget> widget(new Widget); | 236 std::unique_ptr<Widget> widget(new Widget); |
211 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP); | 237 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP); |
212 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; | 238 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; |
213 widget->Init(params); | 239 widget->Init(params); |
214 widget->Show(); | 240 widget->Show(); |
215 | 241 |
216 View* root = widget->GetRootView(); | 242 View* root = widget->GetRootView(); |
217 DerivedTestView* parent = new DerivedTestView(); | 243 DerivedTestView* parent = new DerivedTestView(); |
218 DerivedTestView* child = new DerivedTestView(); | 244 DerivedTestView* child = new DerivedTestView(); |
219 root->AddChildView(parent); | 245 root->AddChildView(parent); |
220 parent->AddChildView(child); | 246 parent->AddChildView(child); |
221 child->SetFocusBehavior(DerivedTestView::FocusBehavior::ALWAYS); | 247 child->SetFocusBehavior(DerivedTestView::FocusBehavior::ALWAYS); |
222 parent->SetFocusBehavior(DerivedTestView::FocusBehavior::ALWAYS); | 248 parent->SetFocusBehavior(DerivedTestView::FocusBehavior::ALWAYS); |
223 root->SetFocusBehavior(DerivedTestView::FocusBehavior::ALWAYS); | 249 root->SetFocusBehavior(DerivedTestView::FocusBehavior::ALWAYS); |
224 parent->RequestFocus(); | 250 parent->RequestFocus(); |
225 // During the destruction of parent, OnBlur will be called and change the | 251 // During the destruction of parent, OnBlur will be called and change the |
226 // visibility to false. | 252 // visibility to false. |
227 parent->SetVisible(true); | 253 parent->SetVisible(true); |
228 AXAuraObjCache* ax = AXAuraObjCache::GetInstance(); | 254 AXAuraObjCache* ax = AXAuraObjCache::GetInstance(); |
229 ax->GetOrCreate(widget.get()); | 255 ax->GetOrCreate(widget.get()); |
230 } | 256 } |
231 #endif | 257 #endif |
232 | 258 |
| 259 // Separate test class for a complicated test case for ignored accessibility |
| 260 // elements which are excluded from the accessibility tree. |
| 261 class NativeViewAccessibilityBaseIgnoredElementsTest : public ViewsTestBase { |
| 262 public: |
| 263 NativeViewAccessibilityBaseIgnoredElementsTest() { |
| 264 a_root_ = new View; |
| 265 NativeViewAccessibilityBase::GetForView(a_root_); |
| 266 } |
| 267 |
| 268 void SetUp() override { |
| 269 ViewsTestBase::SetUp(); |
| 270 // Set up an accessibility tree where X-nodes should be ignored. A Views |
| 271 // hierarchy as shown on the left should expose the accessibility tree in |
| 272 // the middle, and respond to hit tests as shown on the right. This test |
| 273 // is here for completeness (in practice, it's unlikely a keyboard-focusable |
| 274 // View will be needed as a descendant of another keyboard-focusable View). |
| 275 // |
| 276 // A A |
| 277 // / \ / | \ +++---+---+---++---+---+---+++ |
| 278 // B X1 B F E ||| C | D | B || F | A | E ||| |
| 279 // / | \ / | \ / \ +++---+---+---++---+---+---+++ |
| 280 // C D X2 X3 X4 E C D |
| 281 // | | |
| 282 // X5 F |
| 283 // |
| 284 // Note: For hit tests, the parent's bounds will be divided equally amongst |
| 285 // its children (including ignored elements). This means all Views belonging |
| 286 // on the same level of the Views hierarchy will be the same size. |
| 287 a_root_ = new View; |
| 288 a_root_->SetSize(gfx::Size(400, 20)); |
| 289 a_root_->SetFocusBehavior(View::FocusBehavior::ACCESSIBLE_ONLY); |
| 290 |
| 291 // Create Views in the left subtree from |a_root_|. |
| 292 gfx::Rect new_bounds(0, 0, a_root_->width() / 2, a_root_->height()); |
| 293 View* b = AddNewChildWithBoundsAndFocusability(a_root_, new_bounds, true); |
| 294 // |a_root_| has 6 leaves, so divvy up space equally between them for hit |
| 295 // tests. |
| 296 new_bounds = gfx::Rect(0, 0, a_root_->width() / 6, a_root_->height()); |
| 297 View* c = AddNewChildWithBoundsAndFocusability(b, new_bounds, true); |
| 298 View* x5 = AddNewChildWithBoundsAndFocusability(c, new_bounds, false); |
| 299 // Update the |new_bounds| origin to position leaves next to each other. |
| 300 new_bounds.set_x(new_bounds.x() + a_root_->width() / 6); |
| 301 View* d = AddNewChildWithBoundsAndFocusability(b, new_bounds, true); |
| 302 new_bounds.set_x(new_bounds.x() + a_root_->width() / 6); |
| 303 View* x2 = AddNewChildWithBoundsAndFocusability(b, new_bounds, false); |
| 304 new_bounds.set_x(new_bounds.x() + a_root_->width() / 6); |
| 305 |
| 306 // Create Views in the right subtree from root |a_root_|. |
| 307 new_bounds.set_size(b->size()); |
| 308 View* x1 = AddNewChildWithBoundsAndFocusability(a_root_, new_bounds, false); |
| 309 new_bounds.set_origin(gfx::Point()); |
| 310 View* x3 = AddNewChildWithBoundsAndFocusability(x1, new_bounds, false); |
| 311 View* f = AddNewChildWithBoundsAndFocusability(x3, new_bounds, true); |
| 312 new_bounds.set_x(new_bounds.x() + a_root_->width() / 6); |
| 313 View* x4 = AddNewChildWithBoundsAndFocusability(x1, new_bounds, false); |
| 314 new_bounds.set_x(new_bounds.x() + a_root_->width() / 6); |
| 315 View* e = AddNewChildWithBoundsAndFocusability(x1, new_bounds, true); |
| 316 |
| 317 // Populate NPlatformativeViewAccessibility instances for convenience. |
| 318 a_root_nva_ = NativeViewAccessibilityBase::GetForView(a_root_); |
| 319 b_nva_ = NativeViewAccessibilityBase::GetForView(b); |
| 320 c_b_nva_ = NativeViewAccessibilityBase::GetForView(c); |
| 321 d_b_nva_ = NativeViewAccessibilityBase::GetForView(d); |
| 322 e_x1_nva_ = NativeViewAccessibilityBase::GetForView(e); |
| 323 f_x3_x1_nva_ = NativeViewAccessibilityBase::GetForView(f); |
| 324 x1_nva_ = NativeViewAccessibilityBase::GetForView(x1); |
| 325 x2_b_nva_ = NativeViewAccessibilityBase::GetForView(x2); |
| 326 x3_x1_nva_ = NativeViewAccessibilityBase::GetForView(x3); |
| 327 x4_x1_nva_ = NativeViewAccessibilityBase::GetForView(x4); |
| 328 x5_c_b_nva_ = NativeViewAccessibilityBase::GetForView(x5); |
| 329 |
| 330 // Add everything to a new widget, needed for hit testing and parent tests. |
| 331 widget_ = new Widget; |
| 332 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW); |
| 333 widget_->Init(params); |
| 334 widget_->GetContentsView()->AddChildView(a_root_); |
| 335 widget_->Show(); |
| 336 } |
| 337 |
| 338 void TearDown() override { |
| 339 widget_->Close(); |
| 340 ViewsTestBase::TearDown(); |
| 341 } |
| 342 |
| 343 protected: |
| 344 // Owned by |widget_|. |
| 345 View* a_root_; |
| 346 |
| 347 // Owned by their respective View, which are owned by |widget_|. |
| 348 // The following NativeViewAccessibilityBase objects are named after their |
| 349 // corresponding node as shown in the diagrams in SetUp(), then a list of |
| 350 // their ancestors (minus the root), separated by underscores. |
| 351 NativeViewAccessibilityBase* a_root_nva_; |
| 352 NativeViewAccessibilityBase* b_nva_; |
| 353 NativeViewAccessibilityBase* c_b_nva_; |
| 354 NativeViewAccessibilityBase* d_b_nva_; |
| 355 NativeViewAccessibilityBase* e_x1_nva_; |
| 356 NativeViewAccessibilityBase* f_x3_x1_nva_; |
| 357 NativeViewAccessibilityBase* x1_nva_; |
| 358 NativeViewAccessibilityBase* x2_b_nva_; |
| 359 NativeViewAccessibilityBase* x3_x1_nva_; |
| 360 NativeViewAccessibilityBase* x4_x1_nva_; |
| 361 NativeViewAccessibilityBase* x5_c_b_nva_; |
| 362 |
| 363 Widget* widget_ = nullptr; |
| 364 |
| 365 private: |
| 366 DISALLOW_COPY_AND_ASSIGN(NativeViewAccessibilityBaseIgnoredElementsTest); |
| 367 }; |
| 368 |
| 369 // Check the number of a11y children returned accounts for ignored elements. |
| 370 TEST_F(NativeViewAccessibilityBaseIgnoredElementsTest, GetChildCount) { |
| 371 EXPECT_EQ(3, a_root_nva_->GetChildCount()); |
| 372 EXPECT_EQ(2, b_nva_->GetChildCount()); |
| 373 // Leaf elements will return 0. |
| 374 EXPECT_EQ(0, c_b_nva_->GetChildCount()); |
| 375 EXPECT_EQ(0, x5_c_b_nva_->GetChildCount()); |
| 376 EXPECT_EQ(0, d_b_nva_->GetChildCount()); |
| 377 EXPECT_EQ(0, x2_b_nva_->GetChildCount()); |
| 378 EXPECT_EQ(2, x1_nva_->GetChildCount()); |
| 379 EXPECT_EQ(1, x3_x1_nva_->GetChildCount()); |
| 380 EXPECT_EQ(0, f_x3_x1_nva_->GetChildCount()); |
| 381 EXPECT_EQ(0, x4_x1_nva_->GetChildCount()); |
| 382 EXPECT_EQ(0, e_x1_nva_->GetChildCount()); |
| 383 } |
| 384 |
| 385 // Make sure the correct a11y child element is returned at its corresponding |
| 386 // index. Unignored children with ignored parents should move up in the tree. |
| 387 TEST_F(NativeViewAccessibilityBaseIgnoredElementsTest, ChildAtIndex) { |
| 388 EXPECT_EQ(b_nva_->GetNativeObject(), a_root_nva_->ChildAtIndex(0)); |
| 389 EXPECT_EQ(f_x3_x1_nva_->GetNativeObject(), a_root_nva_->ChildAtIndex(1)); |
| 390 EXPECT_EQ(e_x1_nva_->GetNativeObject(), a_root_nva_->ChildAtIndex(2)); |
| 391 EXPECT_EQ(nullptr, a_root_nva_->ChildAtIndex(3)); |
| 392 |
| 393 EXPECT_EQ(c_b_nva_->GetNativeObject(), b_nva_->ChildAtIndex(0)); |
| 394 EXPECT_EQ(d_b_nva_->GetNativeObject(), b_nva_->ChildAtIndex(1)); |
| 395 EXPECT_EQ(nullptr, b_nva_->ChildAtIndex(2)); |
| 396 |
| 397 EXPECT_EQ(f_x3_x1_nva_->GetNativeObject(), x1_nva_->ChildAtIndex(0)); |
| 398 EXPECT_EQ(e_x1_nva_->GetNativeObject(), x1_nva_->ChildAtIndex(1)); |
| 399 EXPECT_EQ(nullptr, x1_nva_->ChildAtIndex(2)); |
| 400 |
| 401 EXPECT_EQ(f_x3_x1_nva_->GetNativeObject(), x3_x1_nva_->ChildAtIndex(0)); |
| 402 |
| 403 // Node with ignored children. |
| 404 EXPECT_EQ(nullptr, c_b_nva_->ChildAtIndex(0)); |
| 405 // Node with 0 children. |
| 406 EXPECT_EQ(nullptr, d_b_nva_->ChildAtIndex(0)); |
| 407 // Ignored node with 0 children. |
| 408 EXPECT_EQ(nullptr, x2_b_nva_->ChildAtIndex(0)); |
| 409 } |
| 410 |
| 411 // Check the a11y parents returned correspond to their unignored children. |
| 412 TEST_F(NativeViewAccessibilityBaseIgnoredElementsTest, GetParent) { |
| 413 EXPECT_EQ(a_root_->parent()->GetNativeViewAccessible(), |
| 414 a_root_nva_->GetParent()); |
| 415 EXPECT_EQ(a_root_->GetNativeViewAccessible(), b_nva_->GetParent()); |
| 416 EXPECT_EQ(b_nva_->GetNativeObject(), c_b_nva_->GetParent()); |
| 417 EXPECT_EQ(c_b_nva_->GetNativeObject(), x5_c_b_nva_->GetParent()); |
| 418 EXPECT_EQ(b_nva_->GetNativeObject(), d_b_nva_->GetParent()); |
| 419 EXPECT_EQ(b_nva_->GetNativeObject(), x2_b_nva_->GetParent()); |
| 420 EXPECT_EQ(a_root_->GetNativeViewAccessible(), x1_nva_->GetParent()); |
| 421 |
| 422 // Skips X1. |
| 423 EXPECT_EQ(a_root_->GetNativeViewAccessible(), x3_x1_nva_->GetParent()); |
| 424 EXPECT_EQ(a_root_->GetNativeViewAccessible(), x4_x1_nva_->GetParent()); |
| 425 EXPECT_EQ(a_root_->GetNativeViewAccessible(), e_x1_nva_->GetParent()); |
| 426 |
| 427 // Skips X3 and X1. |
| 428 EXPECT_EQ(a_root_->GetNativeViewAccessible(), f_x3_x1_nva_->GetParent()); |
| 429 } |
| 430 |
| 431 // Test that a11y hit tests work correctly with ignored elements. A hit on a |
| 432 // ignored element should return its first unignored ancestor. |
| 433 TEST_F(NativeViewAccessibilityBaseIgnoredElementsTest, HitTestSync) { |
| 434 // Move the hit point horizontally, incrementing by the leaf View width. |
| 435 const int min_width = a_root_->GetBoundsInScreen().width() / 6; |
| 436 int curr_x = a_root_->GetBoundsInScreen().x() + min_width / 2; |
| 437 const int y = a_root_->GetBoundsInScreen().CenterPoint().y(); |
| 438 |
| 439 // HitTestSync isn't recursive, so manually do the recursion until arriving at |
| 440 // the correct answer. I.e., the last NativeViewAccessible being tested for |
| 441 // each |curr_x|, |y| pair below would be the correct return value if |
| 442 // HitTestSync were recursive. |
| 443 EXPECT_EQ(b_nva_->GetNativeObject(), a_root_nva_->HitTestSync(curr_x, y)); |
| 444 EXPECT_EQ(c_b_nva_->GetNativeObject(), b_nva_->HitTestSync(curr_x, y)); |
| 445 EXPECT_EQ(c_b_nva_->GetNativeObject(), c_b_nva_->HitTestSync(curr_x, y)); |
| 446 curr_x += min_width; |
| 447 EXPECT_EQ(b_nva_->GetNativeObject(), a_root_nva_->HitTestSync(curr_x, y)); |
| 448 EXPECT_EQ(d_b_nva_->GetNativeObject(), b_nva_->HitTestSync(curr_x, y)); |
| 449 curr_x += min_width; |
| 450 EXPECT_EQ(b_nva_->GetNativeObject(), a_root_nva_->HitTestSync(curr_x, y)); |
| 451 EXPECT_EQ(b_nva_->GetNativeObject(), b_nva_->HitTestSync(curr_x, y)); |
| 452 curr_x += min_width; |
| 453 EXPECT_EQ(x1_nva_->GetNativeObject(), a_root_nva_->HitTestSync(curr_x, y)); |
| 454 EXPECT_EQ(x3_x1_nva_->GetNativeObject(), x1_nva_->HitTestSync(curr_x, y)); |
| 455 EXPECT_EQ(f_x3_x1_nva_->GetNativeObject(), |
| 456 x3_x1_nva_->HitTestSync(curr_x, y)); |
| 457 curr_x += min_width; |
| 458 EXPECT_EQ(x1_nva_->GetNativeObject(), a_root_nva_->HitTestSync(curr_x, y)); |
| 459 EXPECT_EQ(a_root_nva_->GetNativeObject(), x1_nva_->HitTestSync(curr_x, y)); |
| 460 curr_x += min_width; |
| 461 EXPECT_EQ(x1_nva_->GetNativeObject(), a_root_nva_->HitTestSync(curr_x, y)); |
| 462 EXPECT_EQ(e_x1_nva_->GetNativeObject(), x1_nva_->HitTestSync(curr_x, y)); |
| 463 } |
| 464 |
233 } // namespace test | 465 } // namespace test |
234 } // namespace views | 466 } // namespace views |
OLD | NEW |