text: // Copyright (c) 2012 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/events/event_dispatcher.h"
  
  #include <algorithm>
  
  namespace ui {
  
  namespace {
  
  class ScopedDispatchHelper : public Event::DispatcherApi {
   public:
    explicit ScopedDispatchHelper(Event* event)
        : Event::DispatcherApi(event) {
      set_result(ui::ER_UNHANDLED);
    }
  
    virtual ~ScopedDispatchHelper() {
      set_phase(EP_POSTDISPATCH);
    }
  
   private:
    DISALLOW_COPY_AND_ASSIGN(ScopedDispatchHelper);
  };
  
  }  // namespace
  
  EventDispatcherDelegate::EventDispatcherDelegate()
      : dispatcher_(NULL) {
  }
  
  EventDispatcherDelegate::~EventDispatcherDelegate() {
    if (dispatcher_)
      dispatcher_->OnDispatcherDelegateDestroyed();
  }
  
  Event* EventDispatcherDelegate::current_event() {
    return dispatcher_ ? dispatcher_->current_event() : NULL;
  }
  
  EventDispatchDetails EventDispatcherDelegate::DispatchEvent(EventTarget* target,
                                                              Event* event) {
    EventDispatcher* old_dispatcher = dispatcher_;
    EventDispatcher dispatcher(this);
    dispatcher_ = &dispatcher;
    dispatcher.ProcessEvent(target, event);
    if (!dispatcher.delegate_destroyed())
      dispatcher_ = old_dispatcher;
    else if (old_dispatcher)
      old_dispatcher->OnDispatcherDelegateDestroyed();
  
    return dispatcher.details();
  }
  
  EventDispatcher::EventDispatcher(EventDispatcherDelegate* delegate)
      : delegate_(delegate),
        current_event_(NULL) {
  }
  
  EventDispatcher::~EventDispatcher() {
  }
  
  void EventDispatcher::OnHandlerDestroyed(EventHandler* handler) {
    handler_list_.erase(std::find(handler_list_.begin(),
                                  handler_list_.end(),
                                  handler));
  }
  
  void EventDispatcher::ProcessEvent(EventTarget* target, Event* event) {
    if (!target || !target->CanAcceptEvent(*event))
      return;
  
    ScopedDispatchHelper dispatch_helper(event);
    dispatch_helper.set_target(target);
  
    handler_list_.clear();
    target->GetPreTargetHandlers(&handler_list_);
  
    dispatch_helper.set_phase(EP_PRETARGET);
    DispatchEventToEventHandlers(&handler_list_, event);
    if (event->handled())
      return;
  
    // If the event hasn't been consumed, trigger the default handler. Note that
    // even if the event has already been handled (i.e. return result has
    // ER_HANDLED set), that means that the event should still be processed at
    // this layer, however it should not be processed in the next layer of
    // abstraction.
    if (delegate_ && delegate_->CanDispatchToTarget(target)) {
      dispatch_helper.set_phase(EP_TARGET);
      DispatchEvent(target, event);
      if (event->handled())
        return;
    }
  
    if (!delegate_)
      return;
  
    if (!delegate_->CanDispatchToTarget(target)) {
      details_.target_destroyed = true;
      return;
    }
  
    handler_list_.clear();
    target->GetPostTargetHandlers(&handler_list_);
    dispatch_helper.set_phase(EP_POSTTARGET);
    DispatchEventToEventHandlers(&handler_list_, event);
  }
  
  void EventDispatcher::OnDispatcherDelegateDestroyed() {
    details_.dispatcher_destroyed = true;
    delegate_ = NULL;
  }
  
  ////////////////////////////////////////////////////////////////////////////////
  // EventDispatcher, private:
  
  void EventDispatcher::DispatchEventToEventHandlers(EventHandlerList* list,
                                                     Event* event) {
    for (EventHandlerList::const_iterator it = list->begin(),
             end = list->end(); it != end; ++it) {
      (*it)->dispatchers_.push(this);
    }
  
    while (!list->empty()) {
      EventHandler* handler = (*list->begin());
      if (delegate_ && !event->stopped_propagation())
        DispatchEvent(handler, event);
  
      if (!list->empty() && *list->begin() == handler) {
        // The handler has not been destroyed (because if it were, then it would
        // have been removed from the list).
        CHECK(handler->dispatchers_.top() == this);
        handler->dispatchers_.pop();
        list->erase(list->begin());
      }
    }
  }
  
  void EventDispatcher::DispatchEvent(EventHandler* handler, Event* event) {
    // If the target has been invalidated or deleted, don't dispatch the event.
    if (!delegate_->CanDispatchToTarget(event->target())) {
      details_.target_destroyed = true;
      if (event->cancelable())
        event->StopPropagation();
      return;
    }
  
    base::AutoReset<Event*> event_reset(&current_event_, event);
    handler->OnEvent(event);
    if (!delegate_ && event->cancelable())
      event->StopPropagation();
  }
  
  }  // namespace ui
  