| Index: ui/views/accessibility/native_view_accessibility.cc
|
| diff --git a/ui/views/accessibility/native_view_accessibility.cc b/ui/views/accessibility/native_view_accessibility.cc
|
| index 6ca7676e6344d0b6339a33f10cea69cf5f19da91..aeb2c7071a2b9e46cd3d89dded5b6a2bfbc29973 100644
|
| --- a/ui/views/accessibility/native_view_accessibility.cc
|
| +++ b/ui/views/accessibility/native_view_accessibility.cc
|
| @@ -4,7 +4,10 @@
|
|
|
| #include "ui/views/accessibility/native_view_accessibility.h"
|
|
|
| +#include "base/strings/utf_string_conversions.h"
|
| #include "ui/accessibility/ax_view_state.h"
|
| +#include "ui/events/event_utils.h"
|
| +#include "ui/views/controls/native/native_view_host.h"
|
| #include "ui/views/view.h"
|
| #include "ui/views/widget/widget.h"
|
|
|
| @@ -13,77 +16,236 @@ namespace views {
|
| #if !defined(OS_WIN)
|
| // static
|
| NativeViewAccessibility* NativeViewAccessibility::Create(View* view) {
|
| - DCHECK(view);
|
| - NativeViewAccessibility* instance = new NativeViewAccessibility();
|
| - instance->set_view(view);
|
| - return instance;
|
| + return new NativeViewAccessibility(view);
|
| }
|
| #endif
|
|
|
| -NativeViewAccessibility::NativeViewAccessibility()
|
| - : view_(NULL), ax_node_(ui::AXPlatformNode::Create(this)) {
|
| +NativeViewAccessibility::NativeViewAccessibility(View* view)
|
| + : view_(view),
|
| + parent_widget_(nullptr),
|
| + ax_node_(ui::AXPlatformNode::Create(this)) {
|
| }
|
|
|
| NativeViewAccessibility::~NativeViewAccessibility() {
|
| if (ax_node_)
|
| ax_node_->Destroy();
|
| + if (parent_widget_)
|
| + parent_widget_->RemoveObserver(this);
|
| }
|
|
|
| gfx::NativeViewAccessible NativeViewAccessibility::GetNativeObject() {
|
| - return ax_node_ ? ax_node_->GetNativeViewAccessible() : NULL;
|
| + return ax_node_ ? ax_node_->GetNativeViewAccessible() : nullptr;
|
| }
|
|
|
| void NativeViewAccessibility::Destroy() {
|
| delete this;
|
| }
|
|
|
| -#if !defined(OS_WIN)
|
| -// static
|
| -void NativeViewAccessibility::RegisterWebView(View* web_view) {
|
| -}
|
| -
|
| -// static
|
| -void NativeViewAccessibility::UnregisterWebView(View* web_view) {
|
| +void NativeViewAccessibility::NotifyAccessibilityEvent(ui::AXEvent event_type) {
|
| + if (ax_node_)
|
| + ax_node_->NotifyAccessibilityEvent(event_type);
|
| }
|
| -#endif
|
|
|
| // ui::AXPlatformNodeDelegate
|
|
|
| -ui::AXNodeData* NativeViewAccessibility::GetData() {
|
| +const ui::AXNodeData& NativeViewAccessibility::GetData() {
|
| ui::AXViewState state;
|
| view_->GetAccessibleState(&state);
|
| + data_ = ui::AXNodeData();
|
| data_.role = state.role;
|
| + data_.state = state.state();
|
| data_.location = view_->GetBoundsInScreen();
|
| - return &data_;
|
| + data_.AddStringAttribute(ui::AX_ATTR_NAME, base::UTF16ToUTF8(state.name));
|
| + data_.AddStringAttribute(ui::AX_ATTR_VALUE, base::UTF16ToUTF8(state.value));
|
| + data_.AddStringAttribute(ui::AX_ATTR_ACTION,
|
| + base::UTF16ToUTF8(state.default_action));
|
| + data_.AddStringAttribute(ui::AX_ATTR_SHORTCUT,
|
| + base::UTF16ToUTF8(state.keyboard_shortcut));
|
| + data_.AddIntAttribute(ui::AX_ATTR_TEXT_SEL_START, state.selection_start);
|
| + data_.AddIntAttribute(ui::AX_ATTR_TEXT_SEL_END, state.selection_end);
|
| +
|
| + data_.state |= (1 << ui::AX_STATE_FOCUSABLE);
|
| +
|
| + if (!view_->enabled())
|
| + data_.state |= (1 << ui::AX_STATE_DISABLED);
|
| +
|
| + if (!view_->visible())
|
| + data_.state |= (1 << ui::AX_STATE_INVISIBLE);
|
| +
|
| + if (view_->HasFocus())
|
| + data_.state |= (1 << ui::AX_STATE_FOCUSED);
|
| +
|
| + return data_;
|
| }
|
|
|
| int NativeViewAccessibility::GetChildCount() {
|
| - return view_->child_count();
|
| + int child_count = view_->child_count();
|
| +
|
| + std::vector<Widget*> child_widgets;
|
| + PopulateChildWidgetVector(&child_widgets);
|
| + child_count += child_widgets.size();
|
| +
|
| + return child_count;
|
| }
|
|
|
| gfx::NativeViewAccessible NativeViewAccessibility::ChildAtIndex(int index) {
|
| - if (index < 0 || index >= view_->child_count())
|
| - return NULL;
|
| - return view_->child_at(index)->GetNativeViewAccessible();
|
| + // If this is a root view, our widget might have child widgets. Include
|
| + std::vector<Widget*> child_widgets;
|
| + PopulateChildWidgetVector(&child_widgets);
|
| + int child_widget_count = static_cast<int>(child_widgets.size());
|
| +
|
| + if (index < view_->child_count()) {
|
| + return view_->child_at(index)->GetNativeViewAccessible();
|
| + } else if (index < view_->child_count() + child_widget_count) {
|
| + Widget* child_widget = child_widgets[index - view_->child_count()];
|
| + return child_widget->GetRootView()->GetNativeViewAccessible();
|
| + }
|
| +
|
| + return nullptr;
|
| }
|
|
|
| gfx::NativeViewAccessible NativeViewAccessibility::GetParent() {
|
| if (view_->parent())
|
| return view_->parent()->GetNativeViewAccessible();
|
|
|
| + // TODO: move this to NativeViewAccessibilityMac.
|
| #if defined(OS_MACOSX)
|
| if (view_->GetWidget())
|
| return view_->GetWidget()->GetNativeView();
|
| #endif
|
|
|
| - return NULL;
|
| + if (parent_widget_)
|
| + return parent_widget_->GetRootView()->GetNativeViewAccessible();
|
| +
|
| + return nullptr;
|
| }
|
|
|
| gfx::Vector2d NativeViewAccessibility::GetGlobalCoordinateOffset() {
|
| return gfx::Vector2d(0, 0); // location is already in screen coordinates.
|
| }
|
|
|
| -void NativeViewAccessibility::NotifyAccessibilityEvent(ui::AXEvent event_type) {
|
| +gfx::NativeViewAccessible NativeViewAccessibility::HitTestSync(int x, int y) {
|
| + if (!view_ || !view_->GetWidget())
|
| + return nullptr;
|
| +
|
| + // Search child widgets first, since they're on top in the z-order.
|
| + std::vector<Widget*> child_widgets;
|
| + PopulateChildWidgetVector(&child_widgets);
|
| + for (Widget* child_widget : child_widgets) {
|
| + View* child_root_view = child_widget->GetRootView();
|
| + gfx::Point point(x, y);
|
| + View::ConvertPointFromScreen(child_root_view, &point);
|
| + if (child_root_view->HitTestPoint(point))
|
| + return child_root_view->GetNativeViewAccessible();
|
| + }
|
| +
|
| + gfx::Point point(x, y);
|
| + View::ConvertPointFromScreen(view_, &point);
|
| + if (!view_->HitTestPoint(point))
|
| + return nullptr;
|
| +
|
| + // Check if the point is within any of the immediate children of this
|
| + // view. We don't have to search further because AXPlatformNode will
|
| + // do a recursive hit test if we return anything other than |this| or NULL.
|
| + for (int i = view_->child_count() - 1; i >= 0; --i) {
|
| + View* child_view = view_->child_at(i);
|
| + if (!child_view->visible())
|
| + continue;
|
| +
|
| + gfx::Point point_in_child_coords(point);
|
| + view_->ConvertPointToTarget(view_, child_view, &point_in_child_coords);
|
| + if (child_view->HitTestPoint(point_in_child_coords))
|
| + return child_view->GetNativeViewAccessible();
|
| + }
|
| +
|
| + // If it's not inside any of our children, it's inside this view.
|
| + return GetNativeObject();
|
| +}
|
| +
|
| +gfx::NativeViewAccessible NativeViewAccessibility::GetFocus() {
|
| + FocusManager* focus_manager = view_->GetFocusManager();
|
| + View* focused_view =
|
| + focus_manager ? focus_manager->GetFocusedView() : nullptr;
|
| + return focused_view ? focused_view->GetNativeViewAccessible() : nullptr;
|
| +}
|
| +
|
| +gfx::AcceleratedWidget
|
| +NativeViewAccessibility::GetTargetForNativeAccessibilityEvent() {
|
| + return gfx::kNullAcceleratedWidget;
|
| +}
|
| +
|
| +void NativeViewAccessibility::DoDefaultAction() {
|
| + gfx::Point center = view_->GetLocalBounds().CenterPoint();
|
| + view_->OnMousePressed(ui::MouseEvent(ui::ET_MOUSE_PRESSED,
|
| + center,
|
| + center,
|
| + ui::EventTimeForNow(),
|
| + ui::EF_LEFT_MOUSE_BUTTON,
|
| + ui::EF_LEFT_MOUSE_BUTTON));
|
| + view_->OnMouseReleased(ui::MouseEvent(ui::ET_MOUSE_RELEASED,
|
| + center,
|
| + center,
|
| + ui::EventTimeForNow(),
|
| + ui::EF_LEFT_MOUSE_BUTTON,
|
| + ui::EF_LEFT_MOUSE_BUTTON));
|
| +}
|
| +
|
| +bool NativeViewAccessibility::SetStringValue(const base::string16& new_value) {
|
| + // Return an error if the view can't set the value.
|
| + ui::AXViewState state;
|
| + view_->GetAccessibleState(&state);
|
| + if (state.set_value_callback.is_null())
|
| + return false;
|
| +
|
| + state.set_value_callback.Run(new_value);
|
| + return true;
|
| +}
|
| +
|
| +void NativeViewAccessibility::OnWidgetDestroying(Widget* widget) {
|
| + if (parent_widget_ == widget)
|
| + parent_widget_ = nullptr;
|
| +}
|
| +
|
| +void NativeViewAccessibility::SetParentWidget(Widget* parent_widget) {
|
| + if (parent_widget_)
|
| + parent_widget_->RemoveObserver(this);
|
| + parent_widget_ = parent_widget;
|
| + parent_widget_->AddObserver(this);
|
| +}
|
| +
|
| +void NativeViewAccessibility::PopulateChildWidgetVector(
|
| + std::vector<Widget*>* result_child_widgets) {
|
| + // Only attach child widgets to the root view.
|
| + Widget* widget = view_->GetWidget();
|
| + if (!widget || widget->GetRootView() != view_)
|
| + return;
|
| +
|
| + std::set<Widget*> child_widgets;
|
| + Widget::GetAllOwnedWidgets(widget->GetNativeView(), &child_widgets);
|
| + for (auto iter = child_widgets.begin(); iter != child_widgets.end(); ++iter) {
|
| + Widget* child_widget = *iter;
|
| + DCHECK_NE(widget, child_widget);
|
| +
|
| + if (!child_widget->IsVisible())
|
| + continue;
|
| +
|
| + if (widget->GetNativeWindowProperty(kWidgetNativeViewHostKey))
|
| + continue;
|
| +
|
| + gfx::NativeViewAccessible child_widget_accessible =
|
| + child_widget->GetRootView()->GetNativeViewAccessible();
|
| + ui::AXPlatformNode* child_widget_platform_node =
|
| + ui::AXPlatformNode::FromNativeViewAccessible(child_widget_accessible);
|
| + if (child_widget_platform_node) {
|
| + NativeViewAccessibility* child_widget_view_accessibility =
|
| + static_cast<NativeViewAccessibility*>(
|
| + child_widget_platform_node->GetDelegate());
|
| + if (child_widget_view_accessibility->parent_widget() != widget)
|
| + child_widget_view_accessibility->SetParentWidget(widget);
|
| + }
|
| +
|
| + result_child_widgets->push_back(child_widget);
|
| + }
|
| }
|
|
|
| } // namespace views
|
|
|