Upstream version 8.37.180.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / frame / EventHandlerRegistry.cpp
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/EventHandlerRegistry.h"
7
8 #include "core/events/ThreadLocalEventNames.h"
9 #include "core/frame/LocalDOMWindow.h"
10 #include "core/frame/LocalFrame.h"
11 #include "core/html/HTMLFrameOwnerElement.h"
12 #include "core/page/Page.h"
13 #include "core/page/scrolling/ScrollingCoordinator.h"
14
15 namespace WebCore {
16
17 EventHandlerRegistry::EventHandlerRegistry(FrameHost& frameHost)
18     : m_frameHost(frameHost)
19 {
20 }
21
22 EventHandlerRegistry::~EventHandlerRegistry()
23 {
24     checkConsistency();
25 }
26
27 bool EventHandlerRegistry::eventTypeToClass(const AtomicString& eventType, EventHandlerClass* result)
28 {
29     if (eventType == EventTypeNames::scroll) {
30         *result = ScrollEvent;
31     } else if (eventType == EventTypeNames::wheel || eventType == EventTypeNames::mousewheel) {
32         *result = WheelEvent;
33 #if ASSERT_ENABLED
34     } else if (eventType == EventTypeNames::load || eventType == EventTypeNames::mousemove || eventType == EventTypeNames::touchstart) {
35         *result = EventsForTesting;
36 #endif
37     } else {
38         return false;
39     }
40     return true;
41 }
42
43 const EventTargetSet* EventHandlerRegistry::eventHandlerTargets(EventHandlerClass handlerClass) const
44 {
45     checkConsistency();
46     return &m_targets[handlerClass];
47 }
48
49 bool EventHandlerRegistry::hasEventHandlers(EventHandlerClass handlerClass) const
50 {
51     return m_targets[handlerClass].size();
52 }
53
54 bool EventHandlerRegistry::updateEventHandlerTargets(ChangeOperation op, EventHandlerClass handlerClass, EventTarget* target)
55 {
56     EventTargetSet* targets = &m_targets[handlerClass];
57     if (op == Add) {
58         if (!targets->add(target).isNewEntry) {
59             // Just incremented refcount, no real change.
60             return false;
61         }
62     } else {
63         ASSERT(op == Remove || op == RemoveAll);
64         ASSERT(op == RemoveAll || targets->contains(target));
65
66         if (op == RemoveAll) {
67             if (!targets->contains(target))
68                 return false;
69             targets->removeAll(target);
70         } else {
71             if (!targets->remove(target)) {
72                 // Just decremented refcount, no real update.
73                 return false;
74             }
75         }
76     }
77     return true;
78 }
79
80 void EventHandlerRegistry::updateEventHandlerInternal(ChangeOperation op, EventHandlerClass handlerClass, EventTarget* target)
81 {
82     bool hadHandlers = hasEventHandlers(handlerClass);
83     updateEventHandlerTargets(op, handlerClass, target);
84     bool hasHandlers = hasEventHandlers(handlerClass);
85
86     if (hadHandlers != hasHandlers) {
87         notifyHasHandlersChanged(handlerClass, hasHandlers);
88     }
89     checkConsistency();
90 }
91
92 void EventHandlerRegistry::updateEventHandlerOfType(ChangeOperation op, const AtomicString& eventType, EventTarget* target)
93 {
94     EventHandlerClass handlerClass;
95     if (!eventTypeToClass(eventType, &handlerClass))
96         return;
97     updateEventHandlerInternal(op, handlerClass, target);
98 }
99
100 void EventHandlerRegistry::didAddEventHandler(EventTarget& target, const AtomicString& eventType)
101 {
102     updateEventHandlerOfType(Add, eventType, &target);
103 }
104
105 void EventHandlerRegistry::didRemoveEventHandler(EventTarget& target, const AtomicString& eventType)
106 {
107     updateEventHandlerOfType(Remove, eventType, &target);
108 }
109
110 void EventHandlerRegistry::didAddEventHandler(EventTarget& target, EventHandlerClass handlerClass)
111 {
112     updateEventHandlerInternal(Add, handlerClass, &target);
113 }
114
115 void EventHandlerRegistry::didRemoveEventHandler(EventTarget& target, EventHandlerClass handlerClass)
116 {
117     updateEventHandlerInternal(Remove, handlerClass, &target);
118 }
119
120 void EventHandlerRegistry::didMoveIntoFrameHost(EventTarget& target)
121 {
122     updateAllEventHandlers(Add, target);
123 }
124
125 void EventHandlerRegistry::didMoveOutOfFrameHost(EventTarget& target)
126 {
127     updateAllEventHandlers(RemoveAll, target);
128 }
129
130 void EventHandlerRegistry::didRemoveAllEventHandlers(EventTarget& target)
131 {
132     for (size_t i = 0; i < EventHandlerClassCount; ++i) {
133         EventHandlerClass handlerClass = static_cast<EventHandlerClass>(i);
134         updateEventHandlerInternal(RemoveAll, handlerClass, &target);
135     }
136 }
137
138 void EventHandlerRegistry::updateAllEventHandlers(ChangeOperation op, EventTarget& target)
139 {
140     if (!target.hasEventListeners())
141         return;
142
143     Vector<AtomicString> eventTypes = target.eventTypes();
144     for (size_t i = 0; i < eventTypes.size(); ++i) {
145         EventHandlerClass handlerClass;
146         if (!eventTypeToClass(eventTypes[i], &handlerClass))
147             continue;
148         if (op == RemoveAll) {
149             updateEventHandlerInternal(op, handlerClass, &target);
150             continue;
151         }
152         for (unsigned count = target.getEventListeners(eventTypes[i]).size(); count > 0; --count)
153             updateEventHandlerInternal(op, handlerClass, &target);
154     }
155 }
156
157 void EventHandlerRegistry::notifyHasHandlersChanged(EventHandlerClass handlerClass, bool hasActiveHandlers)
158 {
159     ScrollingCoordinator* scrollingCoordinator = m_frameHost.page().scrollingCoordinator();
160
161     switch (handlerClass) {
162     case ScrollEvent:
163         if (scrollingCoordinator)
164             scrollingCoordinator->updateHaveScrollEventHandlers();
165         break;
166     case WheelEvent:
167         if (scrollingCoordinator)
168             scrollingCoordinator->updateHaveWheelEventHandlers();
169         break;
170 #if ASSERT_ENABLED
171     case EventsForTesting:
172         break;
173 #endif
174     default:
175         ASSERT_NOT_REACHED();
176         break;
177     }
178 }
179
180 void EventHandlerRegistry::trace(Visitor* visitor)
181 {
182     visitor->registerWeakMembers<EventHandlerRegistry, &EventHandlerRegistry::clearWeakMembers>(this);
183 }
184
185 void EventHandlerRegistry::clearWeakMembers(Visitor* visitor)
186 {
187     Vector<EventTarget*> deadTargets;
188     for (size_t i = 0; i < EventHandlerClassCount; ++i) {
189         EventHandlerClass handlerClass = static_cast<EventHandlerClass>(i);
190         const EventTargetSet* targets = &m_targets[handlerClass];
191         for (EventTargetSet::const_iterator it = targets->begin(); it != targets->end(); ++it) {
192             Node* node = it->key->toNode();
193             LocalDOMWindow* window = it->key->toDOMWindow();
194             if (node && !visitor->isAlive(node)) {
195                 deadTargets.append(node);
196             } else if (window && !visitor->isAlive(window)) {
197                 deadTargets.append(window);
198             }
199         }
200     }
201     for (size_t i = 0; i < deadTargets.size(); ++i)
202         didRemoveAllEventHandlers(*deadTargets[i]);
203 }
204
205 void EventHandlerRegistry::documentDetached(Document& document)
206 {
207     // Remove all event targets under the detached document.
208     for (size_t handlerClassIndex = 0; handlerClassIndex < EventHandlerClassCount; ++handlerClassIndex) {
209         EventHandlerClass handlerClass = static_cast<EventHandlerClass>(handlerClassIndex);
210         Vector<EventTarget*> targetsToRemove;
211         const EventTargetSet* targets = &m_targets[handlerClass];
212         for (EventTargetSet::const_iterator iter = targets->begin(); iter != targets->end(); ++iter) {
213             if (Node* node = iter->key->toNode()) {
214                 for (Document* doc = &node->document(); doc; doc = doc->ownerElement() ? &doc->ownerElement()->document() : 0) {
215                     if (doc == &document) {
216                         targetsToRemove.append(iter->key);
217                         break;
218                     }
219                 }
220             } else if (iter->key->toDOMWindow()) {
221                 // DOMWindows may outlive their documents, so we shouldn't remove their handlers
222                 // here.
223             } else {
224                 ASSERT_NOT_REACHED();
225             }
226         }
227         for (size_t i = 0; i < targetsToRemove.size(); ++i)
228             updateEventHandlerInternal(RemoveAll, handlerClass, targetsToRemove[i]);
229     }
230 }
231
232 void EventHandlerRegistry::checkConsistency() const
233 {
234 #if ASSERT_ENABLED
235     for (size_t i = 0; i < EventHandlerClassCount; ++i) {
236         EventHandlerClass handlerClass = static_cast<EventHandlerClass>(i);
237         const EventTargetSet* targets = &m_targets[handlerClass];
238         for (EventTargetSet::const_iterator iter = targets->begin(); iter != targets->end(); ++iter) {
239             if (Node* node = iter->key->toNode()) {
240                 // See the comment for |documentDetached| if either of these assertions fails.
241                 ASSERT(node->document().frameHost());
242                 ASSERT(node->document().frameHost() == &m_frameHost);
243             } else if (LocalDOMWindow* window = iter->key->toDOMWindow()) {
244                 // If any of these assertions fail, LocalDOMWindow failed to unregister its handlers
245                 // properly.
246                 ASSERT(window->frame());
247                 ASSERT(window->frame()->host());
248                 ASSERT(window->frame()->host() == &m_frameHost);
249             }
250         }
251     }
252 #endif // ASSERT_ENABLED
253 }
254
255 } // namespace WebCore