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/events/event_dispatcher.h"
6
7#include <algorithm>
8
9#include "ui/events/event_target.h"
10#include "ui/events/event_targeter.h"
11
12namespace ui {
13
14namespace {
15
16class ScopedDispatchHelper : public Event::DispatcherApi {
17 public:
18  explicit ScopedDispatchHelper(Event* event)
19      : Event::DispatcherApi(event) {
20    set_result(ui::ER_UNHANDLED);
21  }
22
23  virtual ~ScopedDispatchHelper() {
24    set_phase(EP_POSTDISPATCH);
25  }
26
27 private:
28  DISALLOW_COPY_AND_ASSIGN(ScopedDispatchHelper);
29};
30
31}  // namespace
32
33EventDispatcherDelegate::EventDispatcherDelegate()
34    : dispatcher_(NULL) {
35}
36
37EventDispatcherDelegate::~EventDispatcherDelegate() {
38  if (dispatcher_)
39    dispatcher_->OnDispatcherDelegateDestroyed();
40}
41
42Event* EventDispatcherDelegate::current_event() {
43  return dispatcher_ ? dispatcher_->current_event() : NULL;
44}
45
46EventDispatchDetails EventDispatcherDelegate::DispatchEvent(EventTarget* target,
47                                                            Event* event) {
48  CHECK(target);
49  Event::DispatcherApi dispatch_helper(event);
50  dispatch_helper.set_phase(EP_PREDISPATCH);
51  dispatch_helper.set_result(ER_UNHANDLED);
52
53  EventDispatchDetails details = PreDispatchEvent(target, event);
54  if (!event->handled() &&
55      !details.dispatcher_destroyed &&
56      !details.target_destroyed) {
57    details = DispatchEventToTarget(target, event);
58  }
59  bool target_destroyed_during_dispatch = details.target_destroyed;
60  if (!details.dispatcher_destroyed) {
61    details = PostDispatchEvent(target_destroyed_during_dispatch ?
62        NULL : target, *event);
63  }
64
65  details.target_destroyed |= target_destroyed_during_dispatch;
66  return details;
67}
68
69EventDispatchDetails EventDispatcherDelegate::PreDispatchEvent(
70    EventTarget* target, Event* event) {
71  return EventDispatchDetails();
72}
73
74EventDispatchDetails EventDispatcherDelegate::PostDispatchEvent(
75    EventTarget* target, const Event& event) {
76  return EventDispatchDetails();
77}
78
79EventDispatchDetails EventDispatcherDelegate::DispatchEventToTarget(
80    EventTarget* target,
81    Event* event) {
82  EventDispatcher* old_dispatcher = dispatcher_;
83  EventDispatcher dispatcher(this);
84  dispatcher_ = &dispatcher;
85  dispatcher.ProcessEvent(target, event);
86  if (!dispatcher.delegate_destroyed())
87    dispatcher_ = old_dispatcher;
88  else if (old_dispatcher)
89    old_dispatcher->OnDispatcherDelegateDestroyed();
90
91  EventDispatchDetails details;
92  details.dispatcher_destroyed = dispatcher.delegate_destroyed();
93  details.target_destroyed =
94      (!details.dispatcher_destroyed && !CanDispatchToTarget(target));
95  return details;
96}
97
98////////////////////////////////////////////////////////////////////////////////
99// EventDispatcher:
100
101EventDispatcher::EventDispatcher(EventDispatcherDelegate* delegate)
102    : delegate_(delegate),
103      current_event_(NULL) {
104}
105
106EventDispatcher::~EventDispatcher() {
107}
108
109void EventDispatcher::OnHandlerDestroyed(EventHandler* handler) {
110  handler_list_.erase(std::find(handler_list_.begin(),
111                                handler_list_.end(),
112                                handler));
113}
114
115void EventDispatcher::ProcessEvent(EventTarget* target, Event* event) {
116  if (!target || !target->CanAcceptEvent(*event))
117    return;
118
119  ScopedDispatchHelper dispatch_helper(event);
120  dispatch_helper.set_target(target);
121
122  handler_list_.clear();
123  target->GetPreTargetHandlers(&handler_list_);
124
125  dispatch_helper.set_phase(EP_PRETARGET);
126  DispatchEventToEventHandlers(&handler_list_, event);
127  if (event->handled())
128    return;
129
130  // If the event hasn't been consumed, trigger the default handler. Note that
131  // even if the event has already been handled (i.e. return result has
132  // ER_HANDLED set), that means that the event should still be processed at
133  // this layer, however it should not be processed in the next layer of
134  // abstraction.
135  if (delegate_ && delegate_->CanDispatchToTarget(target)) {
136    dispatch_helper.set_phase(EP_TARGET);
137    DispatchEvent(target, event);
138    if (event->handled())
139      return;
140  }
141
142  if (!delegate_ || !delegate_->CanDispatchToTarget(target))
143    return;
144
145  handler_list_.clear();
146  target->GetPostTargetHandlers(&handler_list_);
147  dispatch_helper.set_phase(EP_POSTTARGET);
148  DispatchEventToEventHandlers(&handler_list_, event);
149}
150
151void EventDispatcher::OnDispatcherDelegateDestroyed() {
152  delegate_ = NULL;
153}
154
155////////////////////////////////////////////////////////////////////////////////
156// EventDispatcher, private:
157
158void EventDispatcher::DispatchEventToEventHandlers(EventHandlerList* list,
159                                                   Event* event) {
160  for (EventHandlerList::const_iterator it = list->begin(),
161           end = list->end(); it != end; ++it) {
162    (*it)->dispatchers_.push(this);
163  }
164
165  while (!list->empty()) {
166    EventHandler* handler = (*list->begin());
167    if (delegate_ && !event->stopped_propagation())
168      DispatchEvent(handler, event);
169
170    if (!list->empty() && *list->begin() == handler) {
171      // The handler has not been destroyed (because if it were, then it would
172      // have been removed from the list).
173      CHECK(handler->dispatchers_.top() == this);
174      handler->dispatchers_.pop();
175      list->erase(list->begin());
176    }
177  }
178}
179
180void EventDispatcher::DispatchEvent(EventHandler* handler, Event* event) {
181  // If the target has been invalidated or deleted, don't dispatch the event.
182  if (!delegate_->CanDispatchToTarget(event->target())) {
183    if (event->cancelable())
184      event->StopPropagation();
185    return;
186  }
187
188  base::AutoReset<Event*> event_reset(&current_event_, event);
189  handler->OnEvent(event);
190  if (!delegate_ && event->cancelable())
191    event->StopPropagation();
192}
193
194}  // namespace ui
195