Make castv2 performance test work.
[chromium-blink-merge.git] / ui / views / focus / focus_manager.cc
blobed12e4d0956af9e9d09e4ff31c6708adc3b4b37b
1 // Copyright (c) 2012 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/focus/focus_manager.h"
7 #include <algorithm>
8 #include <vector>
10 #include "base/auto_reset.h"
11 #include "base/logging.h"
12 #include "build/build_config.h"
13 #include "ui/base/accelerators/accelerator.h"
14 #include "ui/base/ime/input_method.h"
15 #include "ui/base/ime/text_input_client.h"
16 #include "ui/base/ime/text_input_focus_manager.h"
17 #include "ui/base/ui_base_switches_util.h"
18 #include "ui/events/event.h"
19 #include "ui/events/keycodes/keyboard_codes.h"
20 #include "ui/views/focus/focus_manager_delegate.h"
21 #include "ui/views/focus/focus_search.h"
22 #include "ui/views/focus/view_storage.h"
23 #include "ui/views/focus/widget_focus_manager.h"
24 #include "ui/views/view.h"
25 #include "ui/views/widget/root_view.h"
26 #include "ui/views/widget/widget.h"
27 #include "ui/views/widget/widget_delegate.h"
29 namespace views {
31 namespace {
33 #if defined(OS_MACOSX) || defined(OS_CHROMEOS)
34 static const int kEventFlagsMask = ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN |
35 ui::EF_ALT_DOWN | ui::EF_COMMAND_DOWN;
36 #else
37 static const int kEventFlagsMask = ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN |
38 ui::EF_ALT_DOWN;
39 #endif
41 static inline int CalculateModifiers(const ui::KeyEvent& event) {
42 return event.flags() & kEventFlagsMask;
45 } // namespace
47 bool FocusManager::arrow_key_traversal_enabled_ = false;
49 FocusManager::FocusManager(Widget* widget, FocusManagerDelegate* delegate)
50 : widget_(widget),
51 delegate_(delegate),
52 focused_view_(NULL),
53 accelerator_manager_(new ui::AcceleratorManager),
54 shortcut_handling_suspended_(false),
55 focus_change_reason_(kReasonDirectFocusChange),
56 is_changing_focus_(false) {
57 DCHECK(widget_);
58 stored_focused_view_storage_id_ =
59 ViewStorage::GetInstance()->CreateStorageID();
62 FocusManager::~FocusManager() {
65 bool FocusManager::OnKeyEvent(const ui::KeyEvent& event) {
66 const int key_code = event.key_code();
68 if (event.type() != ui::ET_KEY_PRESSED && event.type() != ui::ET_KEY_RELEASED)
69 return false;
71 if (shortcut_handling_suspended())
72 return true;
74 int modifiers = CalculateModifiers(event);
75 ui::Accelerator accelerator(event.key_code(), modifiers);
76 accelerator.set_type(event.type());
77 accelerator.set_is_repeat(event.IsRepeat());
79 if (event.type() == ui::ET_KEY_PRESSED) {
80 // If the focused view wants to process the key event as is, let it be.
81 if (focused_view_ && focused_view_->SkipDefaultKeyEventProcessing(event) &&
82 !accelerator_manager_->HasPriorityHandler(accelerator))
83 return true;
85 // Intercept Tab related messages for focus traversal.
86 // Note that we don't do focus traversal if the root window is not part of
87 // the active window hierarchy as this would mean we have no focused view
88 // and would focus the first focusable view.
89 if (IsTabTraversalKeyEvent(event)) {
90 AdvanceFocus(event.IsShiftDown());
91 return false;
94 if (arrow_key_traversal_enabled_ && ProcessArrowKeyTraversal(event))
95 return false;
97 // Intercept arrow key messages to switch between grouped views.
98 if (focused_view_ && focused_view_->GetGroup() != -1 &&
99 (key_code == ui::VKEY_UP || key_code == ui::VKEY_DOWN ||
100 key_code == ui::VKEY_LEFT || key_code == ui::VKEY_RIGHT)) {
101 bool next = (key_code == ui::VKEY_RIGHT || key_code == ui::VKEY_DOWN);
102 View::Views views;
103 focused_view_->parent()->GetViewsInGroup(focused_view_->GetGroup(),
104 &views);
105 View::Views::const_iterator i(
106 std::find(views.begin(), views.end(), focused_view_));
107 DCHECK(i != views.end());
108 int index = static_cast<int>(i - views.begin());
109 index += next ? 1 : -1;
110 if (index < 0) {
111 index = static_cast<int>(views.size()) - 1;
112 } else if (index >= static_cast<int>(views.size())) {
113 index = 0;
115 SetFocusedViewWithReason(views[index], kReasonFocusTraversal);
116 return false;
120 // Process keyboard accelerators.
121 // If the key combination matches an accelerator, the accelerator is
122 // triggered, otherwise the key event is processed as usual.
123 if (ProcessAccelerator(accelerator)) {
124 // If a shortcut was activated for this keydown message, do not propagate
125 // the event further.
126 return false;
128 return true;
131 void FocusManager::ValidateFocusedView() {
132 if (focused_view_ && !ContainsView(focused_view_))
133 ClearFocus();
136 // Tests whether a view is valid, whether it still belongs to the window
137 // hierarchy of the FocusManager.
138 bool FocusManager::ContainsView(View* view) {
139 Widget* widget = view->GetWidget();
140 return widget ? widget->GetFocusManager() == this : false;
143 void FocusManager::AdvanceFocus(bool reverse) {
144 View* v = GetNextFocusableView(focused_view_, NULL, reverse, false);
145 // Note: Do not skip this next block when v == focused_view_. If the user
146 // tabs past the last focusable element in a webpage, we'll get here, and if
147 // the TabContentsContainerView is the only focusable view (possible in
148 // fullscreen mode), we need to run this block in order to cycle around to the
149 // first element on the page.
150 if (v) {
151 views::View* focused_view = focused_view_;
152 v->AboutToRequestFocusFromTabTraversal(reverse);
153 // AboutToRequestFocusFromTabTraversal() may have changed focus. If it did,
154 // don't change focus again.
155 if (focused_view == focused_view_)
156 SetFocusedViewWithReason(v, kReasonFocusTraversal);
160 void FocusManager::ClearNativeFocus() {
161 // Keep the top root window focused so we get keyboard events.
162 widget_->ClearNativeFocus();
165 bool FocusManager::RotatePaneFocus(Direction direction,
166 FocusCycleWrappingBehavior wrap) {
167 // Get the list of all accessible panes.
168 std::vector<View*> panes;
169 widget_->widget_delegate()->GetAccessiblePanes(&panes);
171 // Count the number of panes and set the default index if no pane
172 // is initially focused.
173 int count = static_cast<int>(panes.size());
174 if (count == 0)
175 return false;
177 // Initialize |index| to an appropriate starting index if nothing is
178 // focused initially.
179 int index = direction == kBackward ? 0 : count - 1;
181 // Check to see if a pane already has focus and update the index accordingly.
182 const views::View* focused_view = GetFocusedView();
183 if (focused_view) {
184 for (int i = 0; i < count; i++) {
185 if (panes[i] && panes[i]->Contains(focused_view)) {
186 index = i;
187 break;
192 // Rotate focus.
193 int start_index = index;
194 for (;;) {
195 if (direction == kBackward)
196 index--;
197 else
198 index++;
200 if (wrap == kNoWrap && (index >= count || index < 0))
201 return false;
202 index = (index + count) % count;
204 // Ensure that we don't loop more than once.
205 if (index == start_index)
206 break;
208 views::View* pane = panes[index];
209 DCHECK(pane);
211 if (!pane->visible())
212 continue;
214 pane->RequestFocus();
215 focused_view = GetFocusedView();
216 if (pane == focused_view || pane->Contains(focused_view))
217 return true;
220 return false;
223 View* FocusManager::GetNextFocusableView(View* original_starting_view,
224 Widget* starting_widget,
225 bool reverse,
226 bool dont_loop) {
227 FocusTraversable* focus_traversable = NULL;
229 // Let's revalidate the focused view.
230 ValidateFocusedView();
232 View* starting_view = NULL;
233 if (original_starting_view) {
234 // Search up the containment hierarchy to see if a view is acting as
235 // a pane, and wants to implement its own focus traversable to keep
236 // the focus trapped within that pane.
237 View* pane_search = original_starting_view;
238 while (pane_search) {
239 focus_traversable = pane_search->GetPaneFocusTraversable();
240 if (focus_traversable) {
241 starting_view = original_starting_view;
242 break;
244 pane_search = pane_search->parent();
247 if (!focus_traversable) {
248 if (!reverse) {
249 // If the starting view has a focus traversable, use it.
250 // This is the case with NativeWidgetWins for example.
251 focus_traversable = original_starting_view->GetFocusTraversable();
253 // Otherwise default to the root view.
254 if (!focus_traversable) {
255 focus_traversable =
256 original_starting_view->GetWidget()->GetFocusTraversable();
257 starting_view = original_starting_view;
259 } else {
260 // When you are going back, starting view's FocusTraversable
261 // should not be used.
262 focus_traversable =
263 original_starting_view->GetWidget()->GetFocusTraversable();
264 starting_view = original_starting_view;
267 } else {
268 Widget* widget = starting_widget ? starting_widget : widget_;
269 focus_traversable = widget->GetFocusTraversable();
272 // Traverse the FocusTraversable tree down to find the focusable view.
273 View* v = FindFocusableView(focus_traversable, starting_view, reverse);
274 if (v) {
275 return v;
276 } else {
277 // Let's go up in the FocusTraversable tree.
278 FocusTraversable* parent_focus_traversable =
279 focus_traversable->GetFocusTraversableParent();
280 starting_view = focus_traversable->GetFocusTraversableParentView();
281 while (parent_focus_traversable) {
282 FocusTraversable* new_focus_traversable = NULL;
283 View* new_starting_view = NULL;
284 // When we are going backward, the parent view might gain the next focus.
285 bool check_starting_view = reverse;
286 v = parent_focus_traversable->GetFocusSearch()->FindNextFocusableView(
287 starting_view, reverse, FocusSearch::UP,
288 check_starting_view, &new_focus_traversable, &new_starting_view);
290 if (new_focus_traversable) {
291 DCHECK(!v);
293 // There is a FocusTraversable, traverse it down.
294 v = FindFocusableView(new_focus_traversable, NULL, reverse);
297 if (v)
298 return v;
300 starting_view = focus_traversable->GetFocusTraversableParentView();
301 parent_focus_traversable =
302 parent_focus_traversable->GetFocusTraversableParent();
305 // If we get here, we have reached the end of the focus hierarchy, let's
306 // loop. Make sure there was at least a view to start with, to prevent
307 // infinitely looping in empty windows.
308 if (!dont_loop && original_starting_view) {
309 // Easy, just clear the selection and press tab again.
310 // By calling with NULL as the starting view, we'll start from either
311 // the starting views widget or |widget_|.
312 Widget* widget = original_starting_view->GetWidget();
313 if (widget->widget_delegate()->ShouldAdvanceFocusToTopLevelWidget())
314 widget = widget_;
315 return GetNextFocusableView(NULL, widget, reverse, true);
318 return NULL;
321 void FocusManager::SetFocusedViewWithReason(
322 View* view, FocusChangeReason reason) {
323 if (focused_view_ == view) {
324 // In the case that the widget lost the focus and gained it back without
325 // changing the focused view, we have to make the text input client focused.
326 // TODO(yukishiino): Remove this hack once we fix http://crbug.com/383236
327 FocusTextInputClient(focused_view_);
328 return;
331 base::AutoReset<bool> auto_changing_focus(&is_changing_focus_, true);
332 // Update the reason for the focus change (since this is checked by
333 // some listeners), then notify all listeners.
334 focus_change_reason_ = reason;
335 FOR_EACH_OBSERVER(FocusChangeListener, focus_change_listeners_,
336 OnWillChangeFocus(focused_view_, view));
338 View* old_focused_view = focused_view_;
339 focused_view_ = view;
340 if (old_focused_view) {
341 old_focused_view->Blur();
342 BlurTextInputClient(old_focused_view);
344 // Also make |focused_view_| the stored focus view. This way the stored focus
345 // view is remembered if focus changes are requested prior to a show or while
346 // hidden.
347 SetStoredFocusView(focused_view_);
348 if (focused_view_) {
349 FocusTextInputClient(focused_view_);
350 focused_view_->Focus();
353 FOR_EACH_OBSERVER(FocusChangeListener, focus_change_listeners_,
354 OnDidChangeFocus(old_focused_view, focused_view_));
357 void FocusManager::ClearFocus() {
358 // SetFocusedView(NULL) is going to clear out the stored view to. We need to
359 // persist it in this case.
360 views::View* focused_view = GetStoredFocusView();
361 SetFocusedView(NULL);
362 ClearNativeFocus();
363 SetStoredFocusView(focused_view);
366 void FocusManager::AdvanceFocusIfNecessary() {
367 // If widget is inactive, there is no focused view to check. The stored view
368 // will also be checked for focusability when it is being restored.
369 if (!widget_->IsActive())
370 return;
372 // If widget is active and focused view is not focusable, advance focus or,
373 // if not possible, clear focus.
374 if (focused_view_ && !focused_view_->IsAccessibilityFocusable()) {
375 AdvanceFocus(false);
376 if (focused_view_ && !focused_view_->IsAccessibilityFocusable())
377 ClearFocus();
381 void FocusManager::StoreFocusedView(bool clear_native_focus) {
382 View* focused_view = focused_view_;
383 // Don't do anything if no focused view. Storing the view (which is NULL), in
384 // this case, would clobber the view that was previously saved.
385 if (!focused_view_)
386 return;
388 View* v = focused_view_;
390 if (clear_native_focus) {
391 // Temporarily disable notification. ClearFocus() will set the focus to the
392 // main browser window. This extra focus bounce which happens during
393 // deactivation can confuse registered WidgetFocusListeners, as the focus
394 // is not changing due to a user-initiated event.
395 AutoNativeNotificationDisabler local_notification_disabler;
396 // ClearFocus() also stores the focused view.
397 ClearFocus();
398 } else {
399 SetFocusedView(NULL);
400 SetStoredFocusView(focused_view);
403 if (v)
404 v->SchedulePaint(); // Remove focus border.
407 bool FocusManager::RestoreFocusedView() {
408 View* view = GetStoredFocusView();
409 if (view) {
410 if (ContainsView(view)) {
411 if (!view->IsFocusable() && view->IsAccessibilityFocusable()) {
412 // RequestFocus would fail, but we want to restore focus to controls
413 // that had focus in accessibility mode.
414 SetFocusedViewWithReason(view, kReasonFocusRestore);
415 } else {
416 // This usually just sets the focus if this view is focusable, but
417 // let the view override RequestFocus if necessary.
418 view->RequestFocus();
420 // If it succeeded, the reason would be incorrect; set it to
421 // focus restore.
422 if (focused_view_ == view)
423 focus_change_reason_ = kReasonFocusRestore;
426 return true;
428 return false;
431 void FocusManager::SetStoredFocusView(View* focus_view) {
432 ViewStorage* view_storage = ViewStorage::GetInstance();
433 if (!view_storage) {
434 // This should never happen but bug 981648 seems to indicate it could.
435 NOTREACHED();
436 return;
439 // TODO(jcivelli): when a TabContents containing a popup is closed, the focus
440 // is stored twice causing an assert. We should find a better alternative than
441 // removing the view from the storage explicitly.
442 view_storage->RemoveView(stored_focused_view_storage_id_);
444 if (!focus_view)
445 return;
447 view_storage->StoreView(stored_focused_view_storage_id_, focus_view);
450 View* FocusManager::GetStoredFocusView() {
451 ViewStorage* view_storage = ViewStorage::GetInstance();
452 if (!view_storage) {
453 // This should never happen but bug 981648 seems to indicate it could.
454 NOTREACHED();
455 return NULL;
458 return view_storage->RetrieveView(stored_focused_view_storage_id_);
461 void FocusManager::ClearStoredFocusedView() {
462 SetStoredFocusView(NULL);
465 void FocusManager::OnTextInputClientChanged(View* view) {
466 if (view == focused_view_)
467 FocusTextInputClient(view);
470 void FocusManager::FocusTextInputClient(View* view) {
471 if (!switches::IsTextInputFocusManagerEnabled())
472 return;
474 // If the widget is not active, do not steal the text input focus.
475 if (!widget_->IsActive())
476 return;
478 ui::TextInputClient* text_input_client =
479 view ? view->GetTextInputClient() : NULL;
480 ui::TextInputFocusManager::GetInstance()->
481 FocusTextInputClient(text_input_client);
482 ui::InputMethod* input_method = widget_->GetHostInputMethod();
483 if (input_method) {
484 input_method->OnTextInputTypeChanged(text_input_client);
485 input_method->OnCaretBoundsChanged(text_input_client);
489 void FocusManager::BlurTextInputClient(View* view) {
490 if (!switches::IsTextInputFocusManagerEnabled())
491 return;
493 ui::TextInputClient* text_input_client =
494 view ? view->GetTextInputClient() : NULL;
495 if (text_input_client && text_input_client->HasCompositionText()) {
496 text_input_client->ConfirmCompositionText();
497 ui::InputMethod* input_method = widget_->GetHostInputMethod();
498 if (input_method && input_method->GetTextInputClient() == text_input_client)
499 input_method->CancelComposition(text_input_client);
501 ui::TextInputFocusManager::GetInstance()->
502 BlurTextInputClient(text_input_client);
505 // Find the next (previous if reverse is true) focusable view for the specified
506 // FocusTraversable, starting at the specified view, traversing down the
507 // FocusTraversable hierarchy.
508 View* FocusManager::FindFocusableView(FocusTraversable* focus_traversable,
509 View* starting_view,
510 bool reverse) {
511 FocusTraversable* new_focus_traversable = NULL;
512 View* new_starting_view = NULL;
513 View* v = focus_traversable->GetFocusSearch()->FindNextFocusableView(
514 starting_view,
515 reverse,
516 FocusSearch::DOWN,
517 false,
518 &new_focus_traversable,
519 &new_starting_view);
521 // Let's go down the FocusTraversable tree as much as we can.
522 while (new_focus_traversable) {
523 DCHECK(!v);
524 focus_traversable = new_focus_traversable;
525 new_focus_traversable = NULL;
526 starting_view = NULL;
527 v = focus_traversable->GetFocusSearch()->FindNextFocusableView(
528 starting_view,
529 reverse,
530 FocusSearch::DOWN,
531 false,
532 &new_focus_traversable,
533 &new_starting_view);
535 return v;
538 void FocusManager::RegisterAccelerator(
539 const ui::Accelerator& accelerator,
540 ui::AcceleratorManager::HandlerPriority priority,
541 ui::AcceleratorTarget* target) {
542 accelerator_manager_->Register(accelerator, priority, target);
545 void FocusManager::UnregisterAccelerator(const ui::Accelerator& accelerator,
546 ui::AcceleratorTarget* target) {
547 accelerator_manager_->Unregister(accelerator, target);
550 void FocusManager::UnregisterAccelerators(ui::AcceleratorTarget* target) {
551 accelerator_manager_->UnregisterAll(target);
554 bool FocusManager::ProcessAccelerator(const ui::Accelerator& accelerator) {
555 if (accelerator_manager_->Process(accelerator))
556 return true;
557 if (delegate_.get())
558 return delegate_->ProcessAccelerator(accelerator);
559 return false;
562 ui::AcceleratorTarget* FocusManager::GetCurrentTargetForAccelerator(
563 const ui::Accelerator& accelerator) const {
564 ui::AcceleratorTarget* target =
565 accelerator_manager_->GetCurrentTarget(accelerator);
566 if (!target && delegate_.get())
567 target = delegate_->GetCurrentTargetForAccelerator(accelerator);
568 return target;
571 bool FocusManager::HasPriorityHandler(
572 const ui::Accelerator& accelerator) const {
573 return accelerator_manager_->HasPriorityHandler(accelerator);
576 // static
577 bool FocusManager::IsTabTraversalKeyEvent(const ui::KeyEvent& key_event) {
578 return key_event.key_code() == ui::VKEY_TAB && !key_event.IsControlDown();
581 void FocusManager::ViewRemoved(View* removed) {
582 // If the view being removed contains (or is) the focused view,
583 // clear the focus. However, it's not safe to call ClearFocus()
584 // (and in turn ClearNativeFocus()) here because ViewRemoved() can
585 // be called while the top level widget is being destroyed.
586 if (focused_view_ && removed->Contains(focused_view_))
587 SetFocusedView(NULL);
590 void FocusManager::AddFocusChangeListener(FocusChangeListener* listener) {
591 focus_change_listeners_.AddObserver(listener);
594 void FocusManager::RemoveFocusChangeListener(FocusChangeListener* listener) {
595 focus_change_listeners_.RemoveObserver(listener);
598 bool FocusManager::ProcessArrowKeyTraversal(const ui::KeyEvent& event) {
599 if (event.IsShiftDown() || event.IsControlDown() || event.IsAltDown())
600 return false;
602 const int key_code = event.key_code();
603 if (key_code == ui::VKEY_LEFT || key_code == ui::VKEY_UP) {
604 AdvanceFocus(true);
605 return true;
607 if (key_code == ui::VKEY_RIGHT || key_code == ui::VKEY_DOWN) {
608 AdvanceFocus(false);
609 return true;
612 return false;
615 } // namespace views