blob: 0f08a3c8434892d11c5071a577d14714744b795b [file] [log] [blame]
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/views/accessibility/ax_window_obj_wrapper.h"
#include <stddef.h>
#include "base/strings/utf_string_conversions.h"
#include "ui/accessibility/ax_node_data.h"
#include "ui/accessibility/platform/aura_window_properties.h"
#include "ui/aura/window.h"
#include "ui/views/accessibility/ax_aura_obj_cache.h"
#include "ui/views/widget/widget.h"
namespace views {
AXWindowObjWrapper::AXWindowObjWrapper(aura::Window* window)
: window_(window), is_alert_(false) {
window->AddObserver(this);
}
AXWindowObjWrapper::~AXWindowObjWrapper() {
window_->RemoveObserver(this);
window_ = NULL;
}
AXAuraObjWrapper* AXWindowObjWrapper::GetParent() {
if (!window_->parent())
return NULL;
return AXAuraObjCache::GetInstance()->GetOrCreate(window_->parent());
}
void AXWindowObjWrapper::GetChildren(
std::vector<AXAuraObjWrapper*>* out_children) {
aura::Window::Windows children = window_->children();
for (size_t i = 0; i < children.size(); ++i) {
if (!children[i]->IsVisible())
continue;
out_children->push_back(
AXAuraObjCache::GetInstance()->GetOrCreate(children[i]));
}
// Also consider any associated widgets as children.
Widget* widget = Widget::GetWidgetForNativeView(window_);
if (widget && widget->IsVisible())
out_children->push_back(AXAuraObjCache::GetInstance()->GetOrCreate(widget));
}
void AXWindowObjWrapper::Serialize(ui::AXNodeData* out_node_data) {
out_node_data->id = GetID();
out_node_data->role = is_alert_ ? ui::AX_ROLE_ALERT : ui::AX_ROLE_WINDOW;
out_node_data->AddStringAttribute(ui::AX_ATTR_NAME,
base::UTF16ToUTF8(window_->GetTitle()));
out_node_data->state = 0;
out_node_data->location = gfx::RectF(window_->GetBoundsInScreen());
ui::AXTreeIDRegistry::AXTreeID child_ax_tree_id =
window_->GetProperty(ui::kChildAXTreeID);
if (child_ax_tree_id != ui::AXTreeIDRegistry::kNoAXTreeID) {
// Most often, child AX trees are parented to Views. We need to handle
// the case where they're not here, but we don't want the same AX tree
// to be a child of two different parents.
//
// To avoid this double-parenting, only add the child tree ID of this
// window if the top-level window doesn't have an associated Widget.
if (!window_->GetToplevelWindow() ||
Widget::GetWidgetForNativeView(window_->GetToplevelWindow())) {
return;
}
out_node_data->AddIntAttribute(ui::AX_ATTR_CHILD_TREE_ID, child_ax_tree_id);
}
}
int32_t AXWindowObjWrapper::GetID() {
return AXAuraObjCache::GetInstance()->GetID(window_);
}
void AXWindowObjWrapper::OnWindowDestroyed(aura::Window* window) {
AXAuraObjCache::GetInstance()->Remove(window, nullptr);
}
void AXWindowObjWrapper::OnWindowDestroying(aura::Window* window) {
Widget* widget = Widget::GetWidgetForNativeView(window);
if (widget)
AXAuraObjCache::GetInstance()->Remove(widget);
}
void AXWindowObjWrapper::OnWindowHierarchyChanged(
const HierarchyChangeParams& params) {
if (params.phase == WindowObserver::HierarchyChangeParams::HIERARCHY_CHANGED)
AXAuraObjCache::GetInstance()->Remove(params.target, params.old_parent);
}
void AXWindowObjWrapper::OnWindowBoundsChanged(aura::Window* window,
const gfx::Rect& old_bounds,
const gfx::Rect& new_bounds) {
if (window != window_)
return;
AXAuraObjCache::GetInstance()->FireEvent(this, ui::AX_EVENT_LOCATION_CHANGED);
Widget* widget = Widget::GetWidgetForNativeView(window);
if (widget) {
widget->GetRootView()->NotifyAccessibilityEvent(
ui::AX_EVENT_LOCATION_CHANGED, true);
}
}
void AXWindowObjWrapper::OnWindowPropertyChanged(aura::Window* window,
const void* key,
intptr_t old) {
if (window == window_ && key == ui::kChildAXTreeID) {
AXAuraObjCache::GetInstance()->FireEvent(this,
ui::AX_EVENT_CHILDREN_CHANGED);
}
}
} // namespace views