// 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_aura_obj_cache.h" #include "base/memory/singleton.h" #include "base/stl_util.h" #include "ui/aura/client/focus_client.h" #include "ui/aura/window.h" #include "ui/views/accessibility/ax_aura_obj_wrapper.h" #include "ui/views/accessibility/ax_view_obj_wrapper.h" #include "ui/views/accessibility/ax_widget_obj_wrapper.h" #include "ui/views/accessibility/ax_window_obj_wrapper.h" #include "ui/views/view.h" #include "ui/views/widget/widget.h" namespace views { // static AXAuraObjCache* AXAuraObjCache::GetInstance() { return base::Singleton::get(); } AXAuraObjWrapper* AXAuraObjCache::GetOrCreate(View* view) { return CreateInternal(view, view_to_id_map_); } AXAuraObjWrapper* AXAuraObjCache::GetOrCreate(Widget* widget) { return CreateInternal(widget, widget_to_id_map_); } AXAuraObjWrapper* AXAuraObjCache::GetOrCreate(aura::Window* window) { if (!focus_client_) { aura::Window* root_window = window->GetRootWindow(); if (root_window) { focus_client_ = aura::client::GetFocusClient(root_window); root_window->AddObserver(this); if (focus_client_) focus_client_->AddObserver(this); } } return CreateInternal(window, window_to_id_map_); } int32_t AXAuraObjCache::GetID(View* view) const { return GetIDInternal(view, view_to_id_map_); } int32_t AXAuraObjCache::GetID(Widget* widget) const { return GetIDInternal(widget, widget_to_id_map_); } int32_t AXAuraObjCache::GetID(aura::Window* window) const { return GetIDInternal(window, window_to_id_map_); } void AXAuraObjCache::Remove(View* view) { RemoveInternal(view, view_to_id_map_); } void AXAuraObjCache::RemoveViewSubtree(View* view) { Remove(view); for (int i = 0; i < view->child_count(); ++i) RemoveViewSubtree(view->child_at(i)); } void AXAuraObjCache::Remove(Widget* widget) { RemoveInternal(widget, widget_to_id_map_); // When an entire widget is deleted, it doesn't always send a notification // on each of its views, so we need to explore them recursively. if (widget->GetRootView()) RemoveViewSubtree(widget->GetRootView()); } void AXAuraObjCache::Remove(aura::Window* window) { RemoveInternal(window, window_to_id_map_); } AXAuraObjWrapper* AXAuraObjCache::Get(int32_t id) { std::map::iterator it = cache_.find(id); if (it == cache_.end()) return NULL; return it->second; } void AXAuraObjCache::Remove(int32_t id) { AXAuraObjWrapper* obj = Get(id); if (id == -1 || !obj) return; cache_.erase(id); delete obj; } void AXAuraObjCache::GetTopLevelWindows( std::vector* children) { for (std::map::iterator it = window_to_id_map_.begin(); it != window_to_id_map_.end(); ++it) { if (!it->first->parent()) children->push_back(GetOrCreate(it->first)); } } AXAuraObjWrapper* AXAuraObjCache::GetFocus() { View* focused_view = GetFocusedView(); if (focused_view) return GetOrCreate(focused_view); return nullptr; } AXAuraObjCache::AXAuraObjCache() : current_id_(1), focus_client_(nullptr), is_destroying_(false) { } AXAuraObjCache::~AXAuraObjCache() { is_destroying_ = true; STLDeleteContainerPairSecondPointers(cache_.begin(), cache_.end()); cache_.clear(); } View* AXAuraObjCache::GetFocusedView() { if (!focus_client_) return nullptr; aura::Window* focused_window = focus_client_->GetFocusedWindow(); if (!focused_window) return nullptr; Widget* focused_widget = Widget::GetWidgetForNativeView(focused_window); while (!focused_widget) { focused_window = focused_window->parent(); if (!focused_window) break; focused_widget = Widget::GetWidgetForNativeView(focused_window); } if (!focused_widget) return nullptr; FocusManager* focus_manager = focused_widget->GetFocusManager(); if (!focus_manager) return nullptr; return focus_manager->GetFocusedView(); } void AXAuraObjCache::OnWindowFocused(aura::Window* gained_focus, aura::Window* lost_focus) { View* view = GetFocusedView(); if (view) view->NotifyAccessibilityEvent(ui::AX_EVENT_FOCUS, true); } void AXAuraObjCache::OnWindowDestroying(aura::Window* window) { focus_client_ = nullptr; } template AXAuraObjWrapper* AXAuraObjCache::CreateInternal( AuraView* aura_view, std::map& aura_view_to_id_map) { if (!aura_view) return NULL; typename std::map::iterator it = aura_view_to_id_map.find(aura_view); if (it != aura_view_to_id_map.end()) return Get(it->second); AXAuraObjWrapper* wrapper = new AuraViewWrapper(aura_view); aura_view_to_id_map[aura_view] = current_id_; cache_[current_id_] = wrapper; current_id_++; return wrapper; } template int32_t AXAuraObjCache::GetIDInternal( AuraView* aura_view, const std::map& aura_view_to_id_map) const { if (!aura_view) return -1; auto it = aura_view_to_id_map.find(aura_view); if (it != aura_view_to_id_map.end()) return it->second; return -1; } template void AXAuraObjCache::RemoveInternal( AuraView* aura_view, std::map& aura_view_to_id_map) { int32_t id = GetID(aura_view); if (id == -1) return; aura_view_to_id_map.erase(aura_view); Remove(id); } } // namespace views