1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "ui/views/accessibility/native_view_accessibility.h"
7 #include "base/strings/utf_string_conversions.h"
8 #include "ui/accessibility/ax_view_state.h"
9 #include "ui/events/event_utils.h"
10 #include "ui/views/controls/native/native_view_host.h"
11 #include "ui/views/view.h"
12 #include "ui/views/widget/widget.h"
16 #if !defined(OS_WIN) && !(defined(OS_LINUX) && !defined(OS_CHROMEOS))
18 NativeViewAccessibility
* NativeViewAccessibility::Create(View
* view
) {
19 return new NativeViewAccessibility(view
);
23 NativeViewAccessibility::NativeViewAccessibility(View
* view
)
25 parent_widget_(nullptr),
27 ax_node_
= ui::AXPlatformNode::Create(this);
30 NativeViewAccessibility::~NativeViewAccessibility() {
34 parent_widget_
->RemoveObserver(this);
37 gfx::NativeViewAccessible
NativeViewAccessibility::GetNativeObject() {
38 return ax_node_
? ax_node_
->GetNativeViewAccessible() : nullptr;
41 void NativeViewAccessibility::Destroy() {
45 void NativeViewAccessibility::NotifyAccessibilityEvent(ui::AXEvent event_type
) {
47 ax_node_
->NotifyAccessibilityEvent(event_type
);
50 // ui::AXPlatformNodeDelegate
52 const ui::AXNodeData
& NativeViewAccessibility::GetData() {
53 ui::AXViewState state
;
54 view_
->GetAccessibleState(&state
);
55 data_
= ui::AXNodeData();
56 data_
.role
= state
.role
;
57 data_
.state
= state
.state();
58 data_
.location
= view_
->GetBoundsInScreen();
59 data_
.AddStringAttribute(ui::AX_ATTR_NAME
, base::UTF16ToUTF8(state
.name
));
60 data_
.AddStringAttribute(ui::AX_ATTR_VALUE
, base::UTF16ToUTF8(state
.value
));
61 data_
.AddStringAttribute(ui::AX_ATTR_ACTION
,
62 base::UTF16ToUTF8(state
.default_action
));
63 data_
.AddStringAttribute(ui::AX_ATTR_SHORTCUT
,
64 base::UTF16ToUTF8(state
.keyboard_shortcut
));
65 data_
.AddIntAttribute(ui::AX_ATTR_TEXT_SEL_START
, state
.selection_start
);
66 data_
.AddIntAttribute(ui::AX_ATTR_TEXT_SEL_END
, state
.selection_end
);
68 data_
.state
|= (1 << ui::AX_STATE_FOCUSABLE
);
70 if (!view_
->enabled())
71 data_
.state
|= (1 << ui::AX_STATE_DISABLED
);
73 if (!view_
->visible())
74 data_
.state
|= (1 << ui::AX_STATE_INVISIBLE
);
76 if (view_
->HasFocus())
77 data_
.state
|= (1 << ui::AX_STATE_FOCUSED
);
82 int NativeViewAccessibility::GetChildCount() {
83 int child_count
= view_
->child_count();
85 std::vector
<Widget
*> child_widgets
;
86 PopulateChildWidgetVector(&child_widgets
);
87 child_count
+= child_widgets
.size();
92 gfx::NativeViewAccessible
NativeViewAccessibility::ChildAtIndex(int index
) {
93 // If this is a root view, our widget might have child widgets. Include
94 std::vector
<Widget
*> child_widgets
;
95 PopulateChildWidgetVector(&child_widgets
);
96 int child_widget_count
= static_cast<int>(child_widgets
.size());
98 if (index
< view_
->child_count()) {
99 return view_
->child_at(index
)->GetNativeViewAccessible();
100 } else if (index
< view_
->child_count() + child_widget_count
) {
101 Widget
* child_widget
= child_widgets
[index
- view_
->child_count()];
102 return child_widget
->GetRootView()->GetNativeViewAccessible();
108 gfx::NativeViewAccessible
NativeViewAccessibility::GetParent() {
110 return view_
->parent()->GetNativeViewAccessible();
112 // TODO: move this to NativeViewAccessibilityMac.
113 #if defined(OS_MACOSX)
114 if (view_
->GetWidget())
115 return view_
->GetWidget()->GetNativeView();
119 return parent_widget_
->GetRootView()->GetNativeViewAccessible();
124 gfx::Vector2d
NativeViewAccessibility::GetGlobalCoordinateOffset() {
125 return gfx::Vector2d(0, 0); // location is already in screen coordinates.
128 gfx::NativeViewAccessible
NativeViewAccessibility::HitTestSync(int x
, int y
) {
129 if (!view_
|| !view_
->GetWidget())
132 // Search child widgets first, since they're on top in the z-order.
133 std::vector
<Widget
*> child_widgets
;
134 PopulateChildWidgetVector(&child_widgets
);
135 for (Widget
* child_widget
: child_widgets
) {
136 View
* child_root_view
= child_widget
->GetRootView();
137 gfx::Point
point(x
, y
);
138 View::ConvertPointFromScreen(child_root_view
, &point
);
139 if (child_root_view
->HitTestPoint(point
))
140 return child_root_view
->GetNativeViewAccessible();
143 gfx::Point
point(x
, y
);
144 View::ConvertPointFromScreen(view_
, &point
);
145 if (!view_
->HitTestPoint(point
))
148 // Check if the point is within any of the immediate children of this
149 // view. We don't have to search further because AXPlatformNode will
150 // do a recursive hit test if we return anything other than |this| or NULL.
151 for (int i
= view_
->child_count() - 1; i
>= 0; --i
) {
152 View
* child_view
= view_
->child_at(i
);
153 if (!child_view
->visible())
156 gfx::Point
point_in_child_coords(point
);
157 view_
->ConvertPointToTarget(view_
, child_view
, &point_in_child_coords
);
158 if (child_view
->HitTestPoint(point_in_child_coords
))
159 return child_view
->GetNativeViewAccessible();
162 // If it's not inside any of our children, it's inside this view.
163 return GetNativeObject();
166 gfx::NativeViewAccessible
NativeViewAccessibility::GetFocus() {
167 FocusManager
* focus_manager
= view_
->GetFocusManager();
169 focus_manager
? focus_manager
->GetFocusedView() : nullptr;
170 return focused_view
? focused_view
->GetNativeViewAccessible() : nullptr;
173 gfx::AcceleratedWidget
174 NativeViewAccessibility::GetTargetForNativeAccessibilityEvent() {
175 return gfx::kNullAcceleratedWidget
;
178 void NativeViewAccessibility::DoDefaultAction() {
179 gfx::Point center
= view_
->GetLocalBounds().CenterPoint();
180 view_
->OnMousePressed(ui::MouseEvent(ui::ET_MOUSE_PRESSED
,
183 ui::EventTimeForNow(),
184 ui::EF_LEFT_MOUSE_BUTTON
,
185 ui::EF_LEFT_MOUSE_BUTTON
));
186 view_
->OnMouseReleased(ui::MouseEvent(ui::ET_MOUSE_RELEASED
,
189 ui::EventTimeForNow(),
190 ui::EF_LEFT_MOUSE_BUTTON
,
191 ui::EF_LEFT_MOUSE_BUTTON
));
194 bool NativeViewAccessibility::SetStringValue(const base::string16
& new_value
) {
195 // Return an error if the view can't set the value.
196 ui::AXViewState state
;
197 view_
->GetAccessibleState(&state
);
198 if (state
.set_value_callback
.is_null())
201 state
.set_value_callback
.Run(new_value
);
205 void NativeViewAccessibility::OnWidgetDestroying(Widget
* widget
) {
206 if (parent_widget_
== widget
)
207 parent_widget_
= nullptr;
210 void NativeViewAccessibility::SetParentWidget(Widget
* parent_widget
) {
212 parent_widget_
->RemoveObserver(this);
213 parent_widget_
= parent_widget
;
214 parent_widget_
->AddObserver(this);
217 void NativeViewAccessibility::PopulateChildWidgetVector(
218 std::vector
<Widget
*>* result_child_widgets
) {
219 // Only attach child widgets to the root view.
220 Widget
* widget
= view_
->GetWidget();
221 if (!widget
|| widget
->GetRootView() != view_
)
224 std::set
<Widget
*> child_widgets
;
225 Widget::GetAllOwnedWidgets(widget
->GetNativeView(), &child_widgets
);
226 for (auto iter
= child_widgets
.begin(); iter
!= child_widgets
.end(); ++iter
) {
227 Widget
* child_widget
= *iter
;
228 DCHECK_NE(widget
, child_widget
);
230 if (!child_widget
->IsVisible())
233 if (widget
->GetNativeWindowProperty(kWidgetNativeViewHostKey
))
236 gfx::NativeViewAccessible child_widget_accessible
=
237 child_widget
->GetRootView()->GetNativeViewAccessible();
238 ui::AXPlatformNode
* child_widget_platform_node
=
239 ui::AXPlatformNode::FromNativeViewAccessible(child_widget_accessible
);
240 if (child_widget_platform_node
) {
241 NativeViewAccessibility
* child_widget_view_accessibility
=
242 static_cast<NativeViewAccessibility
*>(
243 child_widget_platform_node
->GetDelegate());
244 if (child_widget_view_accessibility
->parent_widget() != widget
)
245 child_widget_view_accessibility
->SetParentWidget(widget
);
248 result_child_widgets
->push_back(child_widget
);