| 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 class NativeViewAccessibilityTest; |
| 21 | 22 |
| 22 namespace { | 23 namespace { |
| 23 | 24 |
| 24 class TestButton : public Button { | 25 class TestButton : public Button { |
| 25 public: | 26 public: |
| 26 TestButton() : Button(NULL) {} | 27 TestButton() : Button(NULL) {} |
| 27 }; | 28 }; |
| 28 | 29 |
| 29 } // namespace | 30 } // namespace |
| 30 | 31 |
| 31 class NativeViewAccessibilityTest : public ViewsTestBase { | 32 class NativeViewAccessibilityTest : public ViewsTestBase { |
| 32 public: | 33 public: |
| 33 NativeViewAccessibilityTest() {} | 34 NativeViewAccessibilityTest() {} |
| 34 ~NativeViewAccessibilityTest() override {} | 35 ~NativeViewAccessibilityTest() override {} |
| 35 | 36 |
| 36 void SetUp() override { | 37 void SetUp() override { |
| 37 ViewsTestBase::SetUp(); | 38 ViewsTestBase::SetUp(); |
| 38 | 39 |
| 39 widget_ = new views::Widget; | 40 widget_ = new Widget; |
| 40 views::Widget::InitParams params = | 41 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW); |
| 41 CreateParams(views::Widget::InitParams::TYPE_WINDOW); | |
| 42 params.bounds = gfx::Rect(0, 0, 200, 200); | 42 params.bounds = gfx::Rect(0, 0, 200, 200); |
| 43 widget_->Init(params); | 43 widget_->Init(params); |
| 44 | 44 |
| 45 button_ = new TestButton(); | 45 button_ = new TestButton(); |
| 46 button_->SetSize(gfx::Size(20, 20)); | 46 button_->SetSize(gfx::Size(20, 20)); |
| 47 button_accessibility_ = NativeViewAccessibility::Create(button_); | 47 button_accessibility_ = NativeViewAccessibility::Create(button_); |
| 48 | 48 |
| 49 label_ = new Label(); | 49 label_ = new Label(); |
| 50 button_->AddChildView(label_); | 50 button_->AddChildView(label_); |
| 51 label_accessibility_ = NativeViewAccessibility::Create(label_); | 51 label_accessibility_ = NativeViewAccessibility::Create(label_); |
| (...skipping 19 matching lines...) Expand all Loading... |
| 71 } | 71 } |
| 72 | 72 |
| 73 bool SetFocused(NativeViewAccessibilityBase* view_accessibility, | 73 bool SetFocused(NativeViewAccessibilityBase* view_accessibility, |
| 74 bool focused) { | 74 bool focused) { |
| 75 ui::AXActionData data; | 75 ui::AXActionData data; |
| 76 data.action = focused ? ui::AX_ACTION_FOCUS : ui::AX_ACTION_BLUR; | 76 data.action = focused ? ui::AX_ACTION_FOCUS : ui::AX_ACTION_BLUR; |
| 77 return view_accessibility->AccessibilityPerformAction(data); | 77 return view_accessibility->AccessibilityPerformAction(data); |
| 78 } | 78 } |
| 79 | 79 |
| 80 protected: | 80 protected: |
| 81 views::Widget* widget_; | 81 Widget* widget_; |
| 82 TestButton* button_; | 82 TestButton* button_; |
| 83 std::unique_ptr<NativeViewAccessibility> button_accessibility_; | 83 std::unique_ptr<NativeViewAccessibility> button_accessibility_; |
| 84 Label* label_; | 84 Label* label_; |
| 85 std::unique_ptr<NativeViewAccessibility> label_accessibility_; | 85 std::unique_ptr<NativeViewAccessibility> label_accessibility_; |
| 86 |
| 87 DISALLOW_COPY_AND_ASSIGN(NativeViewAccessibilityTest); |
| 86 }; | 88 }; |
| 87 | 89 |
| 88 TEST_F(NativeViewAccessibilityTest, RoleShouldMatch) { | 90 TEST_F(NativeViewAccessibilityTest, RoleShouldMatch) { |
| 89 EXPECT_EQ(ui::AX_ROLE_BUTTON, button_accessibility()->GetData().role); | 91 EXPECT_EQ(ui::AX_ROLE_BUTTON, button_accessibility()->GetData().role); |
| 92 // Since the label is a subview of |button_|, and the button is keyboard |
| 93 // focusable, the label is assumed to form part of the button and not have a |
| 94 // role of its own. |
| 95 EXPECT_EQ(ui::AX_ROLE_IGNORED, label_accessibility()->GetData().role); |
| 96 // This will happen for all potentially keyboard-focusable Views with |
| 97 // non-keyboard-focusable children, so if we make the button unfocusable, the |
| 98 // label will be allowed to have its own role again. |
| 99 button_->SetFocusBehavior(View::FocusBehavior::NEVER); |
| 90 EXPECT_EQ(ui::AX_ROLE_STATIC_TEXT, label_accessibility()->GetData().role); | 100 EXPECT_EQ(ui::AX_ROLE_STATIC_TEXT, label_accessibility()->GetData().role); |
| 91 } | 101 } |
| 92 | 102 |
| 93 TEST_F(NativeViewAccessibilityTest, BoundsShouldMatch) { | 103 TEST_F(NativeViewAccessibilityTest, BoundsShouldMatch) { |
| 94 gfx::Rect bounds = | 104 gfx::Rect bounds = |
| 95 gfx::ToEnclosingRect(button_accessibility()->GetData().location); | 105 gfx::ToEnclosingRect(button_accessibility()->GetData().location); |
| 96 gfx::Rect screen_bounds = button_accessibility()->GetScreenBoundsRect(); | 106 gfx::Rect screen_bounds = button_accessibility()->GetScreenBoundsRect(); |
| 97 | 107 |
| 98 EXPECT_EQ(button_->GetBoundsInScreen(), bounds); | 108 EXPECT_EQ(button_->GetBoundsInScreen(), bounds); |
| 99 EXPECT_EQ(screen_bounds, bounds); | 109 EXPECT_EQ(screen_bounds, bounds); |
| 100 } | 110 } |
| 101 | 111 |
| 102 TEST_F(NativeViewAccessibilityTest, LabelIsChildOfButton) { | 112 TEST_F(NativeViewAccessibilityTest, LabelIsChildOfButton) { |
| 113 // |button_| is focusable, so |label_| (as its child) should be ignored. |
| 114 EXPECT_EQ(View::FocusBehavior::ACCESSIBLE_ONLY, button_->focus_behavior()); |
| 115 EXPECT_EQ(1, button_accessibility()->GetChildCount()); |
| 116 EXPECT_EQ(button_->GetNativeViewAccessible(), |
| 117 label_accessibility()->GetParent()); |
| 118 EXPECT_EQ(ui::AX_ROLE_IGNORED, label_accessibility()->GetData().role); |
| 119 |
| 120 // If |button_| is no longer focusable, |label_| should show up again. |
| 121 button_->SetFocusBehavior(View::FocusBehavior::NEVER); |
| 103 EXPECT_EQ(1, button_accessibility()->GetChildCount()); | 122 EXPECT_EQ(1, button_accessibility()->GetChildCount()); |
| 104 EXPECT_EQ(label_->GetNativeViewAccessible(), | 123 EXPECT_EQ(label_->GetNativeViewAccessible(), |
| 105 button_accessibility()->ChildAtIndex(0)); | 124 button_accessibility()->ChildAtIndex(0)); |
| 106 EXPECT_EQ(button_->GetNativeViewAccessible(), | 125 EXPECT_EQ(button_->GetNativeViewAccessible(), |
| 107 label_accessibility()->GetParent()); | 126 label_accessibility()->GetParent()); |
| 127 EXPECT_NE(ui::AX_ROLE_IGNORED, label_accessibility()->GetData().role); |
| 108 } | 128 } |
| 109 | 129 |
| 110 // Verify Views with invisible ancestors have AX_STATE_INVISIBLE. | 130 // Verify Views with invisible ancestors have AX_STATE_INVISIBLE. |
| 111 TEST_F(NativeViewAccessibilityTest, InvisibleViews) { | 131 TEST_F(NativeViewAccessibilityTest, InvisibleViews) { |
| 112 EXPECT_TRUE(widget_->IsVisible()); | 132 EXPECT_TRUE(widget_->IsVisible()); |
| 113 EXPECT_FALSE( | 133 EXPECT_FALSE( |
| 114 button_accessibility()->GetData().HasState(ui::AX_STATE_INVISIBLE)); | 134 button_accessibility()->GetData().HasState(ui::AX_STATE_INVISIBLE)); |
| 115 EXPECT_FALSE( | 135 EXPECT_FALSE( |
| 116 label_accessibility()->GetData().HasState(ui::AX_STATE_INVISIBLE)); | 136 label_accessibility()->GetData().HasState(ui::AX_STATE_INVISIBLE)); |
| 117 button_->SetVisible(false); | 137 button_->SetVisible(false); |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 151 bool is_destroying_parent_widget = (parent_widget_ == widget); | 171 bool is_destroying_parent_widget = (parent_widget_ == widget); |
| 152 NativeViewAccessibilityBase::OnWidgetDestroying(widget); | 172 NativeViewAccessibilityBase::OnWidgetDestroying(widget); |
| 153 if (is_destroying_parent_widget) | 173 if (is_destroying_parent_widget) |
| 154 delete this; | 174 delete this; |
| 155 } | 175 } |
| 156 }; | 176 }; |
| 157 | 177 |
| 158 TEST_F(NativeViewAccessibilityTest, CrashOnWidgetDestroyed) { | 178 TEST_F(NativeViewAccessibilityTest, CrashOnWidgetDestroyed) { |
| 159 std::unique_ptr<Widget> parent_widget(new Widget); | 179 std::unique_ptr<Widget> parent_widget(new Widget); |
| 160 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP); | 180 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP); |
| 161 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; | 181 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; |
| 162 params.bounds = gfx::Rect(50, 50, 650, 650); | 182 params.bounds = gfx::Rect(50, 50, 650, 650); |
| 163 parent_widget->Init(params); | 183 parent_widget->Init(params); |
| 164 | 184 |
| 165 std::unique_ptr<Widget> child_widget(new Widget); | 185 std::unique_ptr<Widget> child_widget(new Widget); |
| 166 child_widget->Init(params); | 186 child_widget->Init(params); |
| 167 | 187 |
| 168 // Make sure that deleting the parent widget can't cause a crash | 188 // Make sure that deleting the parent widget can't cause a crash |
| 169 // due to NativeViewAccessibility not unregistering itself as a | 189 // due to NativeViewAccessibility not unregistering itself as a |
| 170 // WidgetObserver. Note that TestNativeViewAccessibility is a subclass | 190 // WidgetObserver. Note that TestNativeViewAccessibility is a subclass |
| 171 // defined above that destroys itself when its parent widget is destroyed. | 191 // defined above that destroys itself when its parent widget is destroyed. |
| (...skipping 10 matching lines...) Expand all Loading... |
| 182 ~DerivedTestView() override {} | 202 ~DerivedTestView() override {} |
| 183 | 203 |
| 184 void OnBlur() override { SetVisible(false); } | 204 void OnBlur() override { SetVisible(false); } |
| 185 }; | 205 }; |
| 186 | 206 |
| 187 class AxTestViewsDelegate : public TestViewsDelegate { | 207 class AxTestViewsDelegate : public TestViewsDelegate { |
| 188 public: | 208 public: |
| 189 AxTestViewsDelegate() {} | 209 AxTestViewsDelegate() {} |
| 190 ~AxTestViewsDelegate() override {} | 210 ~AxTestViewsDelegate() override {} |
| 191 | 211 |
| 192 void NotifyAccessibilityEvent(views::View* view, | 212 void NotifyAccessibilityEvent(View* view, ui::AXEvent event_type) override { |
| 193 ui::AXEvent event_type) override { | |
| 194 AXAuraObjCache* ax = AXAuraObjCache::GetInstance(); | 213 AXAuraObjCache* ax = AXAuraObjCache::GetInstance(); |
| 195 std::vector<AXAuraObjWrapper*> out_children; | 214 std::vector<AXAuraObjWrapper*> out_children; |
| 196 AXAuraObjWrapper* ax_obj = ax->GetOrCreate(view->GetWidget()); | 215 AXAuraObjWrapper* ax_obj = ax->GetOrCreate(view->GetWidget()); |
| 197 ax_obj->GetChildren(&out_children); | 216 ax_obj->GetChildren(&out_children); |
| 198 } | 217 } |
| 199 | 218 |
| 200 private: | 219 private: |
| 201 DISALLOW_COPY_AND_ASSIGN(AxTestViewsDelegate); | 220 DISALLOW_COPY_AND_ASSIGN(AxTestViewsDelegate); |
| 202 }; | 221 }; |
| 203 | 222 |
| 204 class AXViewTest : public ViewsTestBase { | 223 class AXViewTest : public ViewsTestBase { |
| 205 public: | 224 public: |
| 206 AXViewTest() {} | 225 AXViewTest() {} |
| 207 ~AXViewTest() override {} | 226 ~AXViewTest() override {} |
| 208 void SetUp() override { | 227 void SetUp() override { |
| 209 std::unique_ptr<TestViewsDelegate> views_delegate( | 228 std::unique_ptr<TestViewsDelegate> views_delegate( |
| 210 new AxTestViewsDelegate()); | 229 new AxTestViewsDelegate()); |
| 211 set_views_delegate(std::move(views_delegate)); | 230 set_views_delegate(std::move(views_delegate)); |
| 212 views::ViewsTestBase::SetUp(); | 231 ViewsTestBase::SetUp(); |
| 213 } | 232 } |
| 214 }; | 233 }; |
| 215 | 234 |
| 216 // Check if the destruction of the widget ends successfully if |view|'s | 235 // Check if the destruction of the widget ends successfully if |view|'s |
| 217 // visibility changed during destruction. | 236 // visibility changed during destruction. |
| 218 TEST_F(AXViewTest, LayoutCalledInvalidateRootView) { | 237 TEST_F(AXViewTest, LayoutCalledInvalidateRootView) { |
| 219 std::unique_ptr<Widget> widget(new Widget); | 238 std::unique_ptr<Widget> widget(new Widget); |
| 220 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP); | 239 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP); |
| 221 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; | 240 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; |
| 222 widget->Init(params); | 241 widget->Init(params); |
| 223 widget->Show(); | 242 widget->Show(); |
| 224 | 243 |
| 225 View* root = widget->GetRootView(); | 244 View* root = widget->GetRootView(); |
| 226 DerivedTestView* parent = new DerivedTestView(); | 245 DerivedTestView* parent = new DerivedTestView(); |
| 227 DerivedTestView* child = new DerivedTestView(); | 246 DerivedTestView* child = new DerivedTestView(); |
| 228 root->AddChildView(parent); | 247 root->AddChildView(parent); |
| 229 parent->AddChildView(child); | 248 parent->AddChildView(child); |
| 230 child->SetFocusBehavior(DerivedTestView::FocusBehavior::ALWAYS); | 249 child->SetFocusBehavior(DerivedTestView::FocusBehavior::ALWAYS); |
| 231 parent->SetFocusBehavior(DerivedTestView::FocusBehavior::ALWAYS); | 250 parent->SetFocusBehavior(DerivedTestView::FocusBehavior::ALWAYS); |
| 232 root->SetFocusBehavior(DerivedTestView::FocusBehavior::ALWAYS); | 251 root->SetFocusBehavior(DerivedTestView::FocusBehavior::ALWAYS); |
| 233 parent->RequestFocus(); | 252 parent->RequestFocus(); |
| 234 // During the destruction of parent, OnBlur will be called and change the | 253 // During the destruction of parent, OnBlur will be called and change the |
| 235 // visibility to false. | 254 // visibility to false. |
| 236 parent->SetVisible(true); | 255 parent->SetVisible(true); |
| 237 AXAuraObjCache* ax = AXAuraObjCache::GetInstance(); | 256 AXAuraObjCache* ax = AXAuraObjCache::GetInstance(); |
| 238 ax->GetOrCreate(widget.get()); | 257 ax->GetOrCreate(widget.get()); |
| 239 } | 258 } |
| 240 #endif | 259 #endif |
| 241 | 260 |
| 242 } // namespace test | 261 } // namespace test |
| 243 } // namespace views | 262 } // namespace views |
| OLD | NEW |