1// Copyright 2014 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 "config.h"
6#include "core/frame/PlatformEventDispatcher.h"
7
8#include "core/frame/PlatformEventController.h"
9#include "wtf/TemporaryChange.h"
10
11namespace blink {
12
13PlatformEventDispatcher::PlatformEventDispatcher()
14    : m_needsPurge(false)
15    , m_isDispatching(false)
16{
17}
18
19PlatformEventDispatcher::~PlatformEventDispatcher()
20{
21}
22
23void PlatformEventDispatcher::addController(PlatformEventController* controller)
24{
25    bool wasEmpty = m_controllers.isEmpty();
26    if (!m_controllers.contains(controller))
27        m_controllers.append(controller);
28    if (wasEmpty)
29        startListening();
30}
31
32void PlatformEventDispatcher::removeController(PlatformEventController* controller)
33{
34    // Do not actually remove the controller from the vector, instead zero them out.
35    // The zeros are removed in these two cases:
36    // 1. either immediately if we are not dispatching any events,
37    // 2. or after events to all controllers have dispatched (see notifyControllers()).
38    // This is to correctly handle the re-entrancy case when a controller is destroyed
39    // while the events are still being dispatched.
40    size_t index = m_controllers.find(controller);
41    if (index == kNotFound)
42        return;
43
44    m_controllers[index] = 0;
45    m_needsPurge = true;
46
47    if (!m_isDispatching)
48        purgeControllers();
49}
50
51void PlatformEventDispatcher::purgeControllers()
52{
53    ASSERT(m_needsPurge);
54
55    size_t i = 0;
56    while (i < m_controllers.size()) {
57        if (!m_controllers[i]) {
58            m_controllers[i] = m_controllers.last();
59            m_controllers.removeLast();
60        } else {
61            ++i;
62        }
63    }
64
65    m_needsPurge = false;
66
67    if (m_controllers.isEmpty())
68        stopListening();
69}
70
71void PlatformEventDispatcher::notifyControllers()
72{
73    {
74        TemporaryChange<bool> changeIsDispatching(m_isDispatching, true);
75        // Don't notify controllers removed or added during event dispatch.
76        size_t size = m_controllers.size();
77        for (size_t i = 0; i < size; ++i) {
78            if (m_controllers[i])
79                m_controllers[i]->didUpdateData();
80        }
81    }
82
83    if (m_needsPurge)
84        purgeControllers();
85}
86
87} // namespace blink
88