Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / chromeos / ui / focus_ring_controller.cc
1 // Copyright 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.
4
5 #include "chrome/browser/chromeos/ui/focus_ring_controller.h"
6
7 #include "ash/system/tray/actionable_view.h"
8 #include "ash/system/tray/tray_background_view.h"
9 #include "ash/system/tray/tray_popup_header_button.h"
10 #include "ash/wm/window_util.h"
11 #include "chrome/browser/chromeos/ui/focus_ring_layer.h"
12 #include "ui/aura/window.h"
13 #include "ui/views/controls/button/label_button.h"
14 #include "ui/views/view.h"
15 #include "ui/views/widget/widget.h"
16
17 namespace chromeos {
18
19 FocusRingController::FocusRingController()
20     : visible_(false),
21       widget_(NULL) {
22 }
23
24 FocusRingController::~FocusRingController() {
25   SetVisible(false);
26 }
27
28 void FocusRingController::SetVisible(bool visible) {
29   if (visible_ == visible)
30     return;
31
32   visible_ = visible;
33
34   if (visible_) {
35     views::WidgetFocusManager::GetInstance()->AddFocusChangeListener(this);
36     aura::Window* active_window = ash::wm::GetActiveWindow();
37     if (active_window)
38       SetWidget(views::Widget::GetWidgetForNativeWindow(active_window));
39   } else {
40     views::WidgetFocusManager::GetInstance()->RemoveFocusChangeListener(this);
41     SetWidget(NULL);
42   }
43 }
44
45 void FocusRingController::UpdateFocusRing() {
46   views::View* view = NULL;
47   if (widget_ && widget_->GetFocusManager())
48     view = widget_->GetFocusManager()->GetFocusedView();
49
50   // No focus ring if no focused view or the focused view covers the whole
51   // widget content area (such as RenderWidgetHostWidgetAura).
52   if (!view ||
53       view->ConvertRectToWidget(view->bounds()) ==
54           widget_->GetContentsView()->bounds()) {
55     focus_ring_layer_.reset();
56     return;
57   }
58
59   gfx::Rect view_bounds = view->GetContentsBounds();
60
61   // Workarounds that attempts to pick a better bounds.
62   if (view->GetClassName() == views::LabelButton::kViewClassName) {
63     view_bounds = view->GetLocalBounds();
64     view_bounds.Inset(2, 2, 2, 2);
65   }
66
67   // Workarounds for system tray items that have customized focus borders.  The
68   // insets here must be consistent with the ones used by those classes.
69   if (view->GetClassName() == ash::ActionableView::kViewClassName) {
70     view_bounds = view->GetLocalBounds();
71     view_bounds.Inset(1, 1, 3, 3);
72   } else if (view->GetClassName() == ash::TrayBackgroundView::kViewClassName) {
73     view_bounds.Inset(1, 1, 3, 3);
74   } else if (view->GetClassName() ==
75              ash::TrayPopupHeaderButton::kViewClassName) {
76     view_bounds = view->GetLocalBounds();
77     view_bounds.Inset(2, 1, 2, 2);
78   }
79
80   // Convert view bounds to widget/window coordinates.
81   view_bounds = view->ConvertRectToWidget(view_bounds);
82
83   // Translate window coordinates to root window coordinates.
84   DCHECK(view->GetWidget());
85   aura::Window* window = view->GetWidget()->GetNativeWindow();
86   aura::Window* root_window = window->GetRootWindow();
87   gfx::Point origin = view_bounds.origin();
88   aura::Window::ConvertPointToTarget(window, root_window, &origin);
89   view_bounds.set_origin(origin);
90
91   // Update the focus ring layer.
92   if (!focus_ring_layer_)
93     focus_ring_layer_.reset(new FocusRingLayer(this));
94   focus_ring_layer_->Set(root_window, view_bounds);
95 }
96
97 void FocusRingController::OnDeviceScaleFactorChanged() {
98   UpdateFocusRing();
99 }
100
101 void FocusRingController::SetWidget(views::Widget* widget) {
102   if (widget_) {
103     widget_->RemoveObserver(this);
104     if (widget_->GetFocusManager())
105       widget_->GetFocusManager()->RemoveFocusChangeListener(this);
106   }
107
108   widget_ = widget;
109
110   if (widget_) {
111     widget_->AddObserver(this);
112     if (widget_->GetFocusManager())
113       widget_->GetFocusManager()->AddFocusChangeListener(this);
114   }
115
116   UpdateFocusRing();
117 }
118
119 void FocusRingController::OnWidgetDestroying(views::Widget* widget) {
120   DCHECK_EQ(widget_, widget);
121   SetWidget(NULL);
122 }
123
124 void FocusRingController::OnWidgetBoundsChanged(views::Widget* widget,
125                                                 const gfx::Rect& new_bounds) {
126   DCHECK_EQ(widget_, widget);
127   UpdateFocusRing();
128 }
129
130 void FocusRingController::OnNativeFocusChange(gfx::NativeView focused_before,
131                                               gfx::NativeView focused_now) {
132   views::Widget* widget =
133       focused_now ? views::Widget::GetWidgetForNativeWindow(focused_now) : NULL;
134   SetWidget(widget);
135 }
136
137 void FocusRingController::OnWillChangeFocus(views::View* focused_before,
138                                             views::View* focused_now) {
139 }
140
141 void FocusRingController::OnDidChangeFocus(views::View* focused_before,
142                                            views::View* focused_now) {
143   DCHECK_EQ(focused_now, widget_->GetFocusManager()->GetFocusedView());
144   UpdateFocusRing();
145 }
146
147 }  // namespace chromeos