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.
4 
5 #include "ui/views/widget/root_view.h"
6 
7 #include <algorithm>
8 #include <memory>
9 
10 #include "base/logging.h"
11 #include "base/macros.h"
12 #include "build/build_config.h"
13 #include "ui/accessibility/ax_enums.mojom.h"
14 #include "ui/accessibility/ax_node_data.h"
15 #include "ui/base/cursor/cursor.h"
16 #include "ui/base/dragdrop/mojom/drag_drop_types.mojom-shared.h"
17 #include "ui/base/ui_base_switches_util.h"
18 #include "ui/compositor/layer.h"
19 #include "ui/events/event.h"
20 #include "ui/events/event_utils.h"
21 #include "ui/events/keycodes/keyboard_codes.h"
22 #include "ui/gfx/canvas.h"
23 #include "ui/views/drag_controller.h"
24 #include "ui/views/layout/fill_layout.h"
25 #include "ui/views/metadata/metadata_impl_macros.h"
26 #include "ui/views/view_targeter.h"
27 #include "ui/views/widget/root_view_targeter.h"
28 #include "ui/views/widget/widget.h"
29 #include "ui/views/widget/widget_delegate.h"
30 
31 using DispatchDetails = ui::EventDispatchDetails;
32 
33 namespace views {
34 namespace internal {
35 
36 namespace {
37 
38 class MouseEnterExitEvent : public ui::MouseEvent {
39  public:
MouseEnterExitEvent(const ui::MouseEvent & event,ui::EventType type)40   MouseEnterExitEvent(const ui::MouseEvent& event, ui::EventType type)
41       : ui::MouseEvent(event,
42                        static_cast<View*>(nullptr),
43                        static_cast<View*>(nullptr)) {
44     DCHECK(type == ui::ET_MOUSE_ENTERED || type == ui::ET_MOUSE_EXITED);
45     SetType(type);
46   }
47 
48   ~MouseEnterExitEvent() override = default;
49 };
50 
51 }  // namespace
52 
53 // Used by RootView to create a hidden child that can be used to make screen
54 // reader announcements on platforms that don't have a reliable system API call
55 // to do that.
56 //
57 // We use a separate view because the RootView itself supplies the widget's
58 // accessible name and cannot serve double-duty (the inability for views to make
59 // their own announcements without changing their accessible name or description
60 // is the reason this system exists at all).
61 class AnnounceTextView : public View {
62  public:
63   ~AnnounceTextView() override = default;
64 
Announce(const base::string16 & text)65   void Announce(const base::string16& text) {
66     // TODO(crbug.com/1024898): Use kLiveRegionChanged when supported across
67     // screen readers and platforms. See bug for details.
68     announce_text_ = text;
69     NotifyAccessibilityEvent(ax::mojom::Event::kAlert, true);
70   }
71 
72   // View:
GetAccessibleNodeData(ui::AXNodeData * node_data)73   void GetAccessibleNodeData(ui::AXNodeData* node_data) override {
74     // TODO(crbug.com/1024898): Use live regions (do not use alerts).
75     // May require setting kLiveStatus, kContainerLiveStatus to "polite".
76     node_data->role = ax::mojom::Role::kAlert;
77     node_data->SetName(announce_text_);
78   }
79 
80  private:
81   base::string16 announce_text_;
82 };
83 
84 // This event handler receives events in the pre-target phase and takes care of
85 // the following:
86 //   - Shows keyboard-triggered context menus.
87 class PreEventDispatchHandler : public ui::EventHandler {
88  public:
PreEventDispatchHandler(View * owner)89   explicit PreEventDispatchHandler(View* owner) : owner_(owner) {
90     owner_->AddPreTargetHandler(this);
91   }
~PreEventDispatchHandler()92   ~PreEventDispatchHandler() override { owner_->RemovePreTargetHandler(this); }
93 
94  private:
95   // ui::EventHandler:
OnKeyEvent(ui::KeyEvent * event)96   void OnKeyEvent(ui::KeyEvent* event) override {
97     CHECK_EQ(ui::EP_PRETARGET, event->phase());
98     if (event->handled())
99       return;
100 
101     View* v = nullptr;
102     if (owner_->GetFocusManager())  // Can be NULL in unittests.
103       v = owner_->GetFocusManager()->GetFocusedView();
104 // macOS doesn't have keyboard-triggered context menus.
105 #if !defined(OS_APPLE)
106     // Special case to handle keyboard-triggered context menus.
107     if (v && v->GetEnabled() &&
108         ((event->key_code() == ui::VKEY_APPS) ||
109          (event->key_code() == ui::VKEY_F10 && event->IsShiftDown()))) {
110       // Clamp the menu location within the visible bounds of each ancestor view
111       // to avoid showing the menu over a completely different view or window.
112       gfx::Point location = v->GetKeyboardContextMenuLocation();
113       for (View* parent = v->parent(); parent; parent = parent->parent()) {
114         const gfx::Rect& parent_bounds = parent->GetBoundsInScreen();
115         location.SetToMax(parent_bounds.origin());
116         location.SetToMin(parent_bounds.bottom_right());
117       }
118       v->ShowContextMenu(location, ui::MENU_SOURCE_KEYBOARD);
119       event->StopPropagation();
120     }
121 #endif
122   }
123 
124   View* owner_;
125 
126   DISALLOW_COPY_AND_ASSIGN(PreEventDispatchHandler);
127 };
128 
129 // This event handler receives events in the post-target phase and takes care of
130 // the following:
131 //   - Generates context menu, or initiates drag-and-drop, from gesture events.
132 class PostEventDispatchHandler : public ui::EventHandler {
133  public:
PostEventDispatchHandler()134   PostEventDispatchHandler()
135       : touch_dnd_enabled_(::switches::IsTouchDragDropEnabled()) {}
136   ~PostEventDispatchHandler() override = default;
137 
138  private:
139   // Overridden from ui::EventHandler:
OnGestureEvent(ui::GestureEvent * event)140   void OnGestureEvent(ui::GestureEvent* event) override {
141     DCHECK_EQ(ui::EP_POSTTARGET, event->phase());
142     if (event->handled())
143       return;
144 
145     View* target = static_cast<View*>(event->target());
146 
147     gfx::Point location = event->location();
148     if (touch_dnd_enabled_ && event->type() == ui::ET_GESTURE_LONG_PRESS &&
149         (!target->drag_controller() ||
150          target->drag_controller()->CanStartDragForView(target, location,
151                                                         location))) {
152       if (target->DoDrag(*event, location,
153                          ui::mojom::DragEventSource::kTouch)) {
154         event->StopPropagation();
155         return;
156       }
157     }
158 
159     if (target->context_menu_controller() &&
160         (event->type() == ui::ET_GESTURE_LONG_PRESS ||
161          event->type() == ui::ET_GESTURE_LONG_TAP ||
162          event->type() == ui::ET_GESTURE_TWO_FINGER_TAP)) {
163       gfx::Point screen_location(location);
164       View::ConvertPointToScreen(target, &screen_location);
165       target->ShowContextMenu(screen_location, ui::MENU_SOURCE_TOUCH);
166       event->StopPropagation();
167     }
168   }
169 
170   bool touch_dnd_enabled_;
171 
172   DISALLOW_COPY_AND_ASSIGN(PostEventDispatchHandler);
173 };
174 
175 ////////////////////////////////////////////////////////////////////////////////
176 // RootView, public:
177 
178 // Creation and lifetime -------------------------------------------------------
179 
RootView(Widget * widget)180 RootView::RootView(Widget* widget)
181     : widget_(widget),
182       mouse_pressed_handler_(nullptr),
183       mouse_move_handler_(nullptr),
184       last_click_handler_(nullptr),
185       explicit_mouse_handler_(false),
186       last_mouse_event_flags_(0),
187       last_mouse_event_x_(-1),
188       last_mouse_event_y_(-1),
189       gesture_handler_(nullptr),
190       gesture_handler_set_before_processing_(false),
191       pre_dispatch_handler_(new internal::PreEventDispatchHandler(this)),
192       post_dispatch_handler_(new internal::PostEventDispatchHandler),
193       focus_search_(this, false, false),
194       focus_traversable_parent_(nullptr),
195       focus_traversable_parent_view_(nullptr),
196       event_dispatch_target_(nullptr),
197       old_dispatch_target_(nullptr) {
198   AddPostTargetHandler(post_dispatch_handler_.get());
199   SetEventTargeter(
200       std::unique_ptr<ViewTargeter>(new RootViewTargeter(this, this)));
201 }
202 
~RootView()203 RootView::~RootView() {
204   // If we have children remove them explicitly so to make sure a remove
205   // notification is sent for each one of them.
206   RemoveAllChildViews(true);
207 }
208 
209 // Tree operations -------------------------------------------------------------
210 
SetContentsView(View * contents_view)211 void RootView::SetContentsView(View* contents_view) {
212   DCHECK(contents_view && GetWidget()->native_widget())
213       << "Can't be called until after the native widget is created!";
214   // The ContentsView must be set up _after_ the window is created so that its
215   // Widget pointer is valid.
216   SetLayoutManager(std::make_unique<FillLayout>());
217   if (!children().empty())
218     RemoveAllChildViews(true);
219   AddChildView(contents_view);
220 }
221 
GetContentsView()222 View* RootView::GetContentsView() {
223   return children().empty() ? nullptr : children().front();
224 }
225 
NotifyNativeViewHierarchyChanged()226 void RootView::NotifyNativeViewHierarchyChanged() {
227   PropagateNativeViewHierarchyChanged();
228 }
229 
230 // Focus -----------------------------------------------------------------------
231 
SetFocusTraversableParent(FocusTraversable * focus_traversable)232 void RootView::SetFocusTraversableParent(FocusTraversable* focus_traversable) {
233   DCHECK(focus_traversable != this);
234   focus_traversable_parent_ = focus_traversable;
235 }
236 
SetFocusTraversableParentView(View * view)237 void RootView::SetFocusTraversableParentView(View* view) {
238   focus_traversable_parent_view_ = view;
239 }
240 
241 // System events ---------------------------------------------------------------
242 
ThemeChanged()243 void RootView::ThemeChanged() {
244   View::PropagateThemeChanged();
245 }
246 
ResetEventHandlers()247 void RootView::ResetEventHandlers() {
248   explicit_mouse_handler_ = false;
249   mouse_pressed_handler_ = nullptr;
250   mouse_move_handler_ = nullptr;
251   gesture_handler_ = nullptr;
252   event_dispatch_target_ = nullptr;
253   old_dispatch_target_ = nullptr;
254 }
255 
DeviceScaleFactorChanged(float old_device_scale_factor,float new_device_scale_factor)256 void RootView::DeviceScaleFactorChanged(float old_device_scale_factor,
257                                         float new_device_scale_factor) {
258   View::PropagateDeviceScaleFactorChanged(old_device_scale_factor,
259                                           new_device_scale_factor);
260 }
261 
262 // Accessibility ---------------------------------------------------------------
263 
AnnounceText(const base::string16 & text)264 void RootView::AnnounceText(const base::string16& text) {
265 #if defined(OS_APPLE)
266   // MacOSX has its own API for making announcements; see AnnounceText()
267   // override in ax_platform_node_mac.[h|mm]
268   NOTREACHED();
269 #else
270   DCHECK(GetWidget());
271   DCHECK(GetContentsView());
272   if (!announce_view_) {
273     announce_view_ = AddChildView(std::make_unique<AnnounceTextView>());
274     static_cast<FillLayout*>(GetLayoutManager())
275         ->SetChildViewIgnoredByLayout(announce_view_, true);
276   }
277   announce_view_->Announce(text);
278 #endif
279 }
280 
281 ////////////////////////////////////////////////////////////////////////////////
282 // RootView, FocusTraversable implementation:
283 
GetFocusSearch()284 FocusSearch* RootView::GetFocusSearch() {
285   return &focus_search_;
286 }
287 
GetFocusTraversableParent()288 FocusTraversable* RootView::GetFocusTraversableParent() {
289   return focus_traversable_parent_;
290 }
291 
GetFocusTraversableParentView()292 View* RootView::GetFocusTraversableParentView() {
293   return focus_traversable_parent_view_;
294 }
295 
296 ////////////////////////////////////////////////////////////////////////////////
297 // RootView, ui::EventProcessor overrides:
298 
GetRootForEvent(ui::Event * event)299 ui::EventTarget* RootView::GetRootForEvent(ui::Event* event) {
300   return this;
301 }
302 
GetDefaultEventTargeter()303 ui::EventTargeter* RootView::GetDefaultEventTargeter() {
304   return this->GetEventTargeter();
305 }
306 
OnEventProcessingStarted(ui::Event * event)307 void RootView::OnEventProcessingStarted(ui::Event* event) {
308   if (!event->IsGestureEvent())
309     return;
310 
311   ui::GestureEvent* gesture_event = event->AsGestureEvent();
312 
313   // Do not process ui::ET_GESTURE_BEGIN events.
314   if (gesture_event->type() == ui::ET_GESTURE_BEGIN) {
315     event->SetHandled();
316     return;
317   }
318 
319   // Do not process ui::ET_GESTURE_END events if they do not correspond to the
320   // removal of the final touch point or if no gesture handler has already
321   // been set.
322   if (gesture_event->type() == ui::ET_GESTURE_END &&
323       (gesture_event->details().touch_points() > 1 || !gesture_handler_)) {
324     event->SetHandled();
325     return;
326   }
327 
328   // Do not process subsequent gesture scroll events if no handler was set for
329   // a ui::ET_GESTURE_SCROLL_BEGIN event.
330   if (!gesture_handler_ &&
331       (gesture_event->type() == ui::ET_GESTURE_SCROLL_UPDATE ||
332        gesture_event->type() == ui::ET_GESTURE_SCROLL_END ||
333        gesture_event->type() == ui::ET_SCROLL_FLING_START)) {
334     event->SetHandled();
335     return;
336   }
337 
338   gesture_handler_set_before_processing_ = !!gesture_handler_;
339 }
340 
OnEventProcessingFinished(ui::Event * event)341 void RootView::OnEventProcessingFinished(ui::Event* event) {
342   // If |event| was not handled and |gesture_handler_| was not set by the
343   // dispatch of a previous gesture event, then no default gesture handler
344   // should be set prior to the next gesture event being received.
345   if (event->IsGestureEvent() && !event->handled() &&
346       !gesture_handler_set_before_processing_) {
347     gesture_handler_ = nullptr;
348   }
349 }
350 
351 ////////////////////////////////////////////////////////////////////////////////
352 // RootView, View overrides:
353 
GetWidget() const354 const Widget* RootView::GetWidget() const {
355   return widget_;
356 }
357 
GetWidget()358 Widget* RootView::GetWidget() {
359   return const_cast<Widget*>(const_cast<const RootView*>(this)->GetWidget());
360 }
361 
IsDrawn() const362 bool RootView::IsDrawn() const {
363   return GetVisible();
364 }
365 
OnMousePressed(const ui::MouseEvent & event)366 bool RootView::OnMousePressed(const ui::MouseEvent& event) {
367   UpdateCursor(event);
368   SetMouseLocationAndFlags(event);
369 
370   // If mouse_pressed_handler_ is non null, we are currently processing
371   // a pressed -> drag -> released session. In that case we send the
372   // event to mouse_pressed_handler_
373   if (mouse_pressed_handler_) {
374     ui::MouseEvent mouse_pressed_event(event, static_cast<View*>(this),
375                                        mouse_pressed_handler_);
376     drag_info_.Reset();
377     ui::EventDispatchDetails dispatch_details =
378         DispatchEvent(mouse_pressed_handler_, &mouse_pressed_event);
379     if (dispatch_details.dispatcher_destroyed)
380       return true;
381     return true;
382   }
383   DCHECK(!explicit_mouse_handler_);
384 
385   // Walk up the tree from the target until we find a view that wants
386   // the mouse event.
387   for (mouse_pressed_handler_ = GetEventHandlerForPoint(event.location());
388        mouse_pressed_handler_ && (mouse_pressed_handler_ != this);
389        mouse_pressed_handler_ = mouse_pressed_handler_->parent()) {
390     DVLOG(1) << "OnMousePressed testing "
391              << mouse_pressed_handler_->GetClassName();
392     DCHECK(mouse_pressed_handler_->GetEnabled());
393 
394     // See if this view wants to handle the mouse press.
395     ui::MouseEvent mouse_pressed_event(event, static_cast<View*>(this),
396                                        mouse_pressed_handler_);
397 
398     // Remove the double-click flag if the handler is different than the
399     // one which got the first click part of the double-click.
400     if (mouse_pressed_handler_ != last_click_handler_)
401       mouse_pressed_event.set_flags(event.flags() & ~ui::EF_IS_DOUBLE_CLICK);
402 
403     drag_info_.Reset();
404     ui::EventDispatchDetails dispatch_details =
405         DispatchEvent(mouse_pressed_handler_, &mouse_pressed_event);
406     if (dispatch_details.dispatcher_destroyed)
407       return mouse_pressed_event.handled();
408 
409     // The view could have removed itself from the tree when handling
410     // OnMousePressed().  In this case, the removal notification will have
411     // reset mouse_pressed_handler_ to NULL out from under us.  Detect this
412     // case and stop.  (See comments in view.h.)
413     //
414     // NOTE: Don't return true here, because we don't want the frame to
415     // forward future events to us when there's no handler.
416     if (!mouse_pressed_handler_)
417       break;
418 
419     // If the view handled the event, leave mouse_pressed_handler_ set and
420     // return true, which will cause subsequent drag/release events to get
421     // forwarded to that view.
422     if (mouse_pressed_event.handled()) {
423       last_click_handler_ = mouse_pressed_handler_;
424       DVLOG(1) << "OnMousePressed handled by "
425                << mouse_pressed_handler_->GetClassName();
426       return true;
427     }
428   }
429 
430   // Reset mouse_pressed_handler_ to indicate that no processing is occurring.
431   mouse_pressed_handler_ = nullptr;
432 
433   const bool last_click_was_handled = (last_click_handler_ != nullptr);
434   last_click_handler_ = nullptr;
435 
436   // In the event that a double-click is not handled after traversing the
437   // entire hierarchy (even as a single-click when sent to a different view),
438   // it must be marked as handled to avoid anything happening from default
439   // processing if it the first click-part was handled by us.
440   return last_click_was_handled && (event.flags() & ui::EF_IS_DOUBLE_CLICK);
441 }
442 
OnMouseDragged(const ui::MouseEvent & event)443 bool RootView::OnMouseDragged(const ui::MouseEvent& event) {
444   if (mouse_pressed_handler_) {
445     SetMouseLocationAndFlags(event);
446 
447     ui::MouseEvent mouse_event(event, static_cast<View*>(this),
448                                mouse_pressed_handler_);
449     ui::EventDispatchDetails dispatch_details =
450         DispatchEvent(mouse_pressed_handler_, &mouse_event);
451     if (dispatch_details.dispatcher_destroyed)
452       return false;
453   }
454   return false;
455 }
456 
OnMouseReleased(const ui::MouseEvent & event)457 void RootView::OnMouseReleased(const ui::MouseEvent& event) {
458   UpdateCursor(event);
459 
460   if (mouse_pressed_handler_) {
461     ui::MouseEvent mouse_released(event, static_cast<View*>(this),
462                                   mouse_pressed_handler_);
463     // We allow the view to delete us from the event dispatch callback. As such,
464     // configure state such that we're done first, then call View.
465     View* mouse_pressed_handler = mouse_pressed_handler_;
466     SetMouseHandler(nullptr);
467     ui::EventDispatchDetails dispatch_details =
468         DispatchEvent(mouse_pressed_handler, &mouse_released);
469     if (dispatch_details.dispatcher_destroyed)
470       return;
471   }
472 }
473 
OnMouseCaptureLost()474 void RootView::OnMouseCaptureLost() {
475   if (mouse_pressed_handler_ || gesture_handler_) {
476     // Synthesize a release event for UpdateCursor.
477     if (mouse_pressed_handler_) {
478       gfx::Point last_point(last_mouse_event_x_, last_mouse_event_y_);
479       ui::MouseEvent release_event(ui::ET_MOUSE_RELEASED, last_point,
480                                    last_point, ui::EventTimeForNow(),
481                                    last_mouse_event_flags_, 0);
482       UpdateCursor(release_event);
483     }
484     // We allow the view to delete us from OnMouseCaptureLost. As such,
485     // configure state such that we're done first, then call View.
486     View* mouse_pressed_handler = mouse_pressed_handler_;
487     View* gesture_handler = gesture_handler_;
488     SetMouseHandler(nullptr);
489     if (mouse_pressed_handler)
490       mouse_pressed_handler->OnMouseCaptureLost();
491     else
492       gesture_handler->OnMouseCaptureLost();
493     // WARNING: we may have been deleted.
494   }
495 }
496 
OnMouseMoved(const ui::MouseEvent & event)497 void RootView::OnMouseMoved(const ui::MouseEvent& event) {
498   View* v = GetEventHandlerForPoint(event.location());
499   // Check for a disabled move handler. If the move handler became
500   // disabled while handling moves, it's wrong to suddenly send
501   // ET_MOUSE_EXITED and ET_MOUSE_ENTERED events, because the mouse
502   // hasn't actually exited yet.
503   if (mouse_move_handler_ && !mouse_move_handler_->GetEnabled() &&
504       v->Contains(mouse_move_handler_))
505     v = mouse_move_handler_;
506 
507   if (v && v != this) {
508     if (v != mouse_move_handler_) {
509       if (mouse_move_handler_ != nullptr &&
510           (!mouse_move_handler_->GetNotifyEnterExitOnChild() ||
511            !mouse_move_handler_->Contains(v))) {
512         MouseEnterExitEvent exit(event, ui::ET_MOUSE_EXITED);
513         exit.ConvertLocationToTarget(static_cast<View*>(this),
514                                      mouse_move_handler_);
515         ui::EventDispatchDetails dispatch_details =
516             DispatchEvent(mouse_move_handler_, &exit);
517         if (dispatch_details.dispatcher_destroyed)
518           return;
519         // The mouse_move_handler_ could have been destroyed in the context of
520         // the mouse exit event.
521         if (!dispatch_details.target_destroyed) {
522           // View was removed by ET_MOUSE_EXITED, or |mouse_move_handler_| was
523           // cleared, perhaps by a nested event handler, so return and wait for
524           // the next mouse move event.
525           if (!mouse_move_handler_)
526             return;
527           dispatch_details = NotifyEnterExitOfDescendant(
528               event, ui::ET_MOUSE_EXITED, mouse_move_handler_, v);
529           if (dispatch_details.dispatcher_destroyed)
530             return;
531         }
532       }
533       View* old_handler = mouse_move_handler_;
534       mouse_move_handler_ = v;
535       if (!mouse_move_handler_->GetNotifyEnterExitOnChild() ||
536           !mouse_move_handler_->Contains(old_handler)) {
537         MouseEnterExitEvent entered(event, ui::ET_MOUSE_ENTERED);
538         entered.ConvertLocationToTarget(static_cast<View*>(this),
539                                         mouse_move_handler_);
540         ui::EventDispatchDetails dispatch_details =
541             DispatchEvent(mouse_move_handler_, &entered);
542         if (dispatch_details.dispatcher_destroyed ||
543             dispatch_details.target_destroyed) {
544           return;
545         }
546         // View was removed by ET_MOUSE_ENTERED, or |mouse_move_handler_| was
547         // cleared, perhaps by a nested event handler, so return and wait for
548         // the next mouse move event.
549         if (!mouse_move_handler_)
550           return;
551         dispatch_details = NotifyEnterExitOfDescendant(
552             event, ui::ET_MOUSE_ENTERED, mouse_move_handler_, old_handler);
553         if (dispatch_details.dispatcher_destroyed ||
554             dispatch_details.target_destroyed) {
555           return;
556         }
557       }
558     }
559     ui::MouseEvent moved_event(event, static_cast<View*>(this),
560                                mouse_move_handler_);
561     mouse_move_handler_->OnMouseMoved(moved_event);
562     // TODO(tdanderson): It may be possible to avoid setting the cursor twice
563     //                   (once here and once from CompoundEventFilter) on a
564     //                   mousemove. See crbug.com/351469.
565     if (!(moved_event.flags() & ui::EF_IS_NON_CLIENT))
566       widget_->SetCursor(mouse_move_handler_->GetCursor(moved_event));
567   } else if (mouse_move_handler_ != nullptr) {
568     MouseEnterExitEvent exited(event, ui::ET_MOUSE_EXITED);
569     ui::EventDispatchDetails dispatch_details =
570         DispatchEvent(mouse_move_handler_, &exited);
571     if (dispatch_details.dispatcher_destroyed)
572       return;
573     // The mouse_move_handler_ could have been destroyed in the context of the
574     // mouse exit event.
575     if (!dispatch_details.target_destroyed) {
576       // View was removed by ET_MOUSE_EXITED, or |mouse_move_handler_| was
577       // cleared, perhaps by a nested event handler, so return and wait for
578       // the next mouse move event.
579       if (!mouse_move_handler_)
580         return;
581       dispatch_details = NotifyEnterExitOfDescendant(event, ui::ET_MOUSE_EXITED,
582                                                      mouse_move_handler_, v);
583       if (dispatch_details.dispatcher_destroyed)
584         return;
585     }
586     // On Aura the non-client area extends slightly outside the root view for
587     // some windows.  Let the non-client cursor handling code set the cursor
588     // as we do above.
589     if (!(event.flags() & ui::EF_IS_NON_CLIENT))
590       widget_->SetCursor(gfx::kNullCursor);
591     mouse_move_handler_ = nullptr;
592   }
593 }
594 
OnMouseExited(const ui::MouseEvent & event)595 void RootView::OnMouseExited(const ui::MouseEvent& event) {
596   if (mouse_move_handler_ != nullptr) {
597     MouseEnterExitEvent exited(event, ui::ET_MOUSE_EXITED);
598     ui::EventDispatchDetails dispatch_details =
599         DispatchEvent(mouse_move_handler_, &exited);
600     if (dispatch_details.dispatcher_destroyed)
601       return;
602     // The mouse_move_handler_ could have been destroyed in the context of the
603     // mouse exit event.
604     if (!dispatch_details.target_destroyed) {
605       CHECK(mouse_move_handler_);
606       dispatch_details = NotifyEnterExitOfDescendant(
607           event, ui::ET_MOUSE_EXITED, mouse_move_handler_, nullptr);
608       if (dispatch_details.dispatcher_destroyed)
609         return;
610     }
611     mouse_move_handler_ = nullptr;
612   }
613 }
614 
OnMouseWheel(const ui::MouseWheelEvent & event)615 bool RootView::OnMouseWheel(const ui::MouseWheelEvent& event) {
616   for (View* v = GetEventHandlerForPoint(event.location());
617        v && v != this && !event.handled(); v = v->parent()) {
618     ui::EventDispatchDetails dispatch_details =
619         DispatchEvent(v, const_cast<ui::MouseWheelEvent*>(&event));
620     if (dispatch_details.dispatcher_destroyed ||
621         dispatch_details.target_destroyed) {
622       return event.handled();
623     }
624   }
625   return event.handled();
626 }
627 
SetMouseHandler(View * new_mh)628 void RootView::SetMouseHandler(View* new_mh) {
629   // If we're clearing the mouse handler, clear explicit_mouse_handler_ as well.
630   explicit_mouse_handler_ = (new_mh != nullptr);
631   mouse_pressed_handler_ = new_mh;
632   gesture_handler_ = new_mh;
633   drag_info_.Reset();
634 }
635 
GetAccessibleNodeData(ui::AXNodeData * node_data)636 void RootView::GetAccessibleNodeData(ui::AXNodeData* node_data) {
637   DCHECK(GetWidget());
638   auto* widget_delegate = GetWidget()->widget_delegate();
639   if (!widget_delegate)
640     return;
641   node_data->SetName(widget_delegate->GetAccessibleWindowTitle());
642   node_data->role = widget_delegate->GetAccessibleWindowRole();
643 }
644 
UpdateParentLayer()645 void RootView::UpdateParentLayer() {
646   if (layer())
647     ReparentLayer(widget_->GetLayer());
648 }
649 
650 ////////////////////////////////////////////////////////////////////////////////
651 // RootView, protected:
652 
ViewHierarchyChanged(const ViewHierarchyChangedDetails & details)653 void RootView::ViewHierarchyChanged(
654     const ViewHierarchyChangedDetails& details) {
655   widget_->ViewHierarchyChanged(details);
656 
657   if (!details.is_add) {
658     if (!explicit_mouse_handler_ && mouse_pressed_handler_ == details.child)
659       mouse_pressed_handler_ = nullptr;
660     if (mouse_move_handler_ == details.child)
661       mouse_move_handler_ = nullptr;
662     if (gesture_handler_ == details.child)
663       gesture_handler_ = nullptr;
664     if (event_dispatch_target_ == details.child)
665       event_dispatch_target_ = nullptr;
666     if (old_dispatch_target_ == details.child)
667       old_dispatch_target_ = nullptr;
668   }
669 }
670 
VisibilityChanged(View *,bool is_visible)671 void RootView::VisibilityChanged(View* /*starting_from*/, bool is_visible) {
672   if (!is_visible) {
673     // When the root view is being hidden (e.g. when widget is minimized)
674     // handlers are reset, so that after it is reshown, events are not captured
675     // by old handlers.
676     ResetEventHandlers();
677   }
678 }
679 
OnDidSchedulePaint(const gfx::Rect & rect)680 void RootView::OnDidSchedulePaint(const gfx::Rect& rect) {
681   if (!layer()) {
682     gfx::Rect xrect = ConvertRectToParent(rect);
683     gfx::Rect invalid_rect = gfx::IntersectRects(GetLocalBounds(), xrect);
684     if (!invalid_rect.IsEmpty())
685       widget_->SchedulePaintInRect(invalid_rect);
686   }
687 }
688 
OnPaint(gfx::Canvas * canvas)689 void RootView::OnPaint(gfx::Canvas* canvas) {
690   if (!layer() || !layer()->fills_bounds_opaquely())
691     canvas->DrawColor(SK_ColorBLACK, SkBlendMode::kClear);
692 
693   View::OnPaint(canvas);
694 }
695 
CalculateOffsetToAncestorWithLayer(ui::Layer ** layer_parent)696 View::LayerOffsetData RootView::CalculateOffsetToAncestorWithLayer(
697     ui::Layer** layer_parent) {
698   if (layer() || !widget_->GetLayer())
699     return View::CalculateOffsetToAncestorWithLayer(layer_parent);
700   if (layer_parent)
701     *layer_parent = widget_->GetLayer();
702   return LayerOffsetData(widget_->GetLayer()->device_scale_factor());
703 }
704 
GetDragInfo()705 View::DragInfo* RootView::GetDragInfo() {
706   return &drag_info_;
707 }
708 
709 ////////////////////////////////////////////////////////////////////////////////
710 // RootView, private:
711 
UpdateCursor(const ui::MouseEvent & event)712 void RootView::UpdateCursor(const ui::MouseEvent& event) {
713   if (!(event.flags() & ui::EF_IS_NON_CLIENT)) {
714     View* v = GetEventHandlerForPoint(event.location());
715     ui::MouseEvent me(event, static_cast<View*>(this), v);
716     widget_->SetCursor(v->GetCursor(me));
717   }
718 }
719 
SetMouseLocationAndFlags(const ui::MouseEvent & event)720 void RootView::SetMouseLocationAndFlags(const ui::MouseEvent& event) {
721   last_mouse_event_flags_ = event.flags();
722   last_mouse_event_x_ = event.x();
723   last_mouse_event_y_ = event.y();
724 }
725 
NotifyEnterExitOfDescendant(const ui::MouseEvent & event,ui::EventType type,View * view,View * sibling)726 ui::EventDispatchDetails RootView::NotifyEnterExitOfDescendant(
727     const ui::MouseEvent& event,
728     ui::EventType type,
729     View* view,
730     View* sibling) {
731   for (View* p = view->parent(); p; p = p->parent()) {
732     if (!p->GetNotifyEnterExitOnChild())
733       continue;
734     if (sibling && p->Contains(sibling))
735       break;
736     // It is necessary to recreate the notify-event for each dispatch, since one
737     // of the callbacks can mark the event as handled, and that would cause
738     // incorrect event dispatch.
739     MouseEnterExitEvent notify_event(event, type);
740     ui::EventDispatchDetails dispatch_details = DispatchEvent(p, &notify_event);
741     if (dispatch_details.dispatcher_destroyed ||
742         dispatch_details.target_destroyed) {
743       return dispatch_details;
744     }
745   }
746   return ui::EventDispatchDetails();
747 }
748 
CanDispatchToTarget(ui::EventTarget * target)749 bool RootView::CanDispatchToTarget(ui::EventTarget* target) {
750   return event_dispatch_target_ == target;
751 }
752 
PreDispatchEvent(ui::EventTarget * target,ui::Event * event)753 ui::EventDispatchDetails RootView::PreDispatchEvent(ui::EventTarget* target,
754                                                     ui::Event* event) {
755   View* view = static_cast<View*>(target);
756   if (event->IsGestureEvent()) {
757     // Update |gesture_handler_| to indicate which View is currently handling
758     // gesture events.
759     // TODO(tdanderson): Look into moving this to PostDispatchEvent() and
760     //                   using |event_dispatch_target_| instead of
761     //                   |gesture_handler_| to detect if the view has been
762     //                   removed from the tree.
763     gesture_handler_ = view;
764   }
765 
766   old_dispatch_target_ = event_dispatch_target_;
767   event_dispatch_target_ = view;
768   return DispatchDetails();
769 }
770 
PostDispatchEvent(ui::EventTarget * target,const ui::Event & event)771 ui::EventDispatchDetails RootView::PostDispatchEvent(ui::EventTarget* target,
772                                                      const ui::Event& event) {
773   // The GESTURE_END event corresponding to the removal of the final touch
774   // point marks the end of a gesture sequence, so reset |gesture_handler_|
775   // to NULL.
776   if (event.type() == ui::ET_GESTURE_END) {
777     // In case a drag was in progress, reset all the handlers. Otherwise, just
778     // reset the gesture handler.
779     if (gesture_handler_ && gesture_handler_ == mouse_pressed_handler_)
780       SetMouseHandler(nullptr);
781     else
782       gesture_handler_ = nullptr;
783   }
784 
785   DispatchDetails details;
786   if (target != event_dispatch_target_)
787     details.target_destroyed = true;
788 
789   event_dispatch_target_ = old_dispatch_target_;
790   old_dispatch_target_ = nullptr;
791 
792 #ifndef NDEBUG
793   DCHECK(!event_dispatch_target_ || Contains(event_dispatch_target_));
794 #endif
795 
796   return details;
797 }
798 
799 BEGIN_METADATA(RootView, View)
800 END_METADATA
801 }  // namespace internal
802 }  // namespace views
803