Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(596)

Side by Side Diff: Source/core/dom/EventHandlerRegistry.cpp

Issue 206603002: Add EventHandlerRegistry (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: Tests now seem to pass. Created 6 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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 #include "config.h"
5 #include "core/dom/EventHandlerRegistry.h"
6
7 #include "core/dom/Document.h"
8 #include "core/events/ThreadLocalEventNames.h"
9 #include "core/events/WheelEvent.h"
10 #include "core/frame/FrameHost.h"
11 #include "core/frame/LocalFrame.h"
12 #include "core/page/Chrome.h"
13 #include "core/page/ChromeClient.h"
14 #include "core/page/Page.h"
15 #include "core/page/scrolling/ScrollingCoordinator.h"
16
17 namespace WebCore {
18
19 EventHandlerRegistry::HandlerState::HandlerState()
20 : handlerCount(0)
21 , externalHandlerCount(0)
22 {
23 }
24
25 EventHandlerRegistry::HandlerState::~HandlerState()
26 {
27 }
28
29 EventHandlerRegistry::EventHandlerRegistry(Document& document)
30 : DOMWindowLifecycleObserver(document.domWindow())
31 , DocumentLifecycleObserver(&document)
32 {
33 }
34
35 EventHandlerRegistry::~EventHandlerRegistry()
36 {
37 }
38
39 const char* EventHandlerRegistry::supplementName()
40 {
41 return "EventHandlerRegistry";
42 }
43
44 EventHandlerRegistry* EventHandlerRegistry::from(Document& document)
45 {
46 EventHandlerRegistry* registry = static_cast<EventHandlerRegistry*>(Document Supplement::from(document, supplementName()));
47 if (!registry) {
48 registry = new EventHandlerRegistry(document);
49 DocumentSupplement::provideTo(document, supplementName(), adoptPtr(regis try));
50 }
51 return registry;
52 }
53
54 bool EventHandlerRegistry::eventTypeToClass(const AtomicString& eventType, Event HandlerClass* result)
55 {
56 if (eventType == EventTypeNames::wheel || eventType == EventTypeNames::mouse wheel) {
57 *result = WheelEvent;
58 } else if (eventType == EventTypeNames::scroll) {
59 *result = ScrollEvent;
60 } else if (isTouchEventType(eventType)) {
61 *result = TouchEvent;
62 } else {
63 return false;
64 }
65 return true;
66 }
67
68 unsigned EventHandlerRegistry::eventHandlerCount(EventHandlerClass handlerClass) const
69 {
70 return m_eventHandlers[handlerClass].handlerCount + m_eventHandlers[handlerC lass].externalHandlerCount;
71 }
72
73 const EventTargetSet* EventHandlerRegistry::eventHandlerTargets(EventHandlerClas s handlerClass) const
74 {
75 return m_eventHandlers[handlerClass].targets.get();
76 }
77
78 void EventHandlerRegistry::updateExternalHandlerCount(ChangeOperation op, EventH andlerClass handlerClass)
79 {
80 if (op == Add) {
81 m_eventHandlers[handlerClass].externalHandlerCount++;
82 } else {
83 ASSERT(op == Remove);
84 ASSERT(m_eventHandlers[handlerClass].externalHandlerCount > 0);
85 m_eventHandlers[handlerClass].externalHandlerCount--;
86 }
87 }
88
89 bool EventHandlerRegistry::updateEventHandlerTargets(ChangeOperation op, EventHa ndlerClass handlerClass, Document& document, EventTarget* target)
90 {
91 EventTargetSet* targets = m_eventHandlers[handlerClass].targets.get();
92 if (op == Add) {
93 if (Node* node = target->toNode()) {
94 // The node should either be in the document, or be the Document nod e of a child
Rick Byers 2014/03/27 16:43:31 I like this assert, but again, but what if 'docume
Sami 2014/04/02 19:58:05 Agreed. This is now cleared up too.
95 // of the document.
96 ASSERT(&node->document() == &document
97 || (node->isDocumentNode() && toDocument(node)->parentDocument() == &document));
98 } else if (DOMWindow* window = target->toDOMWindow()) {
99 // The window should belong to this document.
100 ASSERT(window->document() == &document);
101 }
102
103 if (!targets) {
104 m_eventHandlers[handlerClass].targets = adoptPtr(new EventTargetSet) ;
105 targets = m_eventHandlers[handlerClass].targets.get();
106 }
107
108 m_eventHandlers[handlerClass].handlerCount++;
109 if (!targets->add(target).isNewEntry) {
110 // Just incremented refcount, no real change.
111 // If this is a child document node, then the count should never go above 1.
112 if (Node* node = target->toNode())
113 ASSERT(!node->isDocumentNode() || &node->document() == &document );
114 return false;
115 }
116 } else {
117 // Note that we can't assert that |target| is in this document because
118 // it might be in the process of moving out of it.
119 ASSERT(op == Remove || op == RemoveAll);
120 ASSERT(op == RemoveAll || targets->contains(target));
121 if (!targets)
122 return false;
123
124 if (op == RemoveAll) {
125 if (!targets->contains(target))
126 return false;
127 m_eventHandlers[handlerClass].handlerCount -= targets->count(target) ;
128 targets->removeAll(target);
129 } else {
130 m_eventHandlers[handlerClass].handlerCount--;
131 if (!targets->remove(target)) {
132 // Just decremented refcount, no real update.
133 return false;
134 }
135 }
136 }
137 return true;
138 }
139
140 void EventHandlerRegistry::checkEventHandlerConsistency(EventHandlerClass handle rClass) const
141 {
142 #ifndef NDEBUG
143 EventTargetSet* targets = m_eventHandlers[handlerClass].targets.get();
144 if (!targets) {
145 ASSERT(!m_eventHandlers[handlerClass].handlerCount);
146 return;
147 }
148
149 unsigned count = 0;
150 for (EventTargetSet::const_iterator iter = targets->begin(); iter != targets ->end(); ++iter)
151 count += iter->value;
152 ASSERT(count == m_eventHandlers[handlerClass].handlerCount);
153 #endif // NDEBUG
154 }
155
156 void EventHandlerRegistry::updateEventHandlerInternal(ChangeOperation op, Docume nt& document, EventHandlerClass handlerClass, EventTarget* target)
157 {
158 bool hadHandlers = eventHandlerCount(handlerClass);
159 bool targetSetChanged;
160 if (target) {
161 targetSetChanged = updateEventHandlerTargets(op, handlerClass, document, target);
162 checkEventHandlerConsistency(handlerClass);
163 } else {
164 updateExternalHandlerCount(op, handlerClass);
165 targetSetChanged = true;
166 }
167 bool haveHandlers = eventHandlerCount(handlerClass);
168
169 // Notify the parent document's registry if we added the first or removed
170 // the last handler.
171 bool addedFirstHandler = !hadHandlers && haveHandlers;
172 bool removedLastHandler = hadHandlers && !haveHandlers;
173 if (addedFirstHandler || removedLastHandler) {
Rick Byers 2014/03/27 16:43:31 simpler just to check if(hadHandlers != haveHandle
Sami 2014/04/02 19:58:05 D'oh, done.
174 if (Document* parent = document.parentDocument()) {
175 // Report change to parent with our Document as the target.
176 EventHandlerRegistry::from(*parent)->updateEventHandlerInternal(op, *parent, handlerClass, &document);
Rick Byers 2014/03/27 16:43:31 It's calls like this that make me think the Docume
Sami 2014/04/02 19:58:05 Done.
177 } else {
178 // This is the root registry; notify clients accordingly.
179 notifyDidAddFirstOrRemoveLastEventHandler(document, handlerClass, ha veHandlers);
180 }
181 }
182
183 // Only notify the client when something actually changed, and then only if
184 // this wasn't a notification that was sent by a sub-registry.
185 if (!targetSetChanged)
186 return;
187 Node* node = target ? target->toNode() : nullptr;
188 if (!node || !node->isDocumentNode() || node == &document)
189 notifyDidAddOrRemoveEventHandlerTarget(handlerClass, document);
190 }
191
192 void EventHandlerRegistry::updateEventHandlerOfClass(ChangeOperation op, EventHa ndlerClass handlerClass, EventTarget& target)
193 {
Rick Byers 2014/03/27 16:43:31 this function should collapse to nothing if you ca
Sami 2014/04/02 19:58:05 Done.
194 if (Node* node = target.toNode())
195 updateEventHandlerInternal(op, node->document(), handlerClass, node);
196 else if (DOMWindow* window = target.toDOMWindow())
197 updateEventHandlerInternal(op, *window->document(), handlerClass, window );
198 else
199 ASSERT_NOT_REACHED();
200 }
201
202 void EventHandlerRegistry::updateEventHandlerOfType(ChangeOperation op, const At omicString& eventType, EventTarget& target)
203 {
204 EventHandlerClass handlerClass;
205 if (!eventTypeToClass(eventType, &handlerClass))
206 return;
207 updateEventHandlerOfClass(op, handlerClass, target);
208 }
209
210 void EventHandlerRegistry::didAddExternalEventHandler(Document& document, const AtomicString& eventType)
211 {
212 EventHandlerClass handlerClass;
213 if (!eventTypeToClass(eventType, &handlerClass))
214 return;
215 updateEventHandlerInternal(Add, document, handlerClass, nullptr);
216 }
217
218 void EventHandlerRegistry::didRemoveExternalEventHandler(Document& document, con st AtomicString& eventType)
219 {
220 EventHandlerClass handlerClass;
221 if (!eventTypeToClass(eventType, &handlerClass))
222 return;
223 updateEventHandlerInternal(Remove, document, handlerClass, nullptr);
224 }
225
226 void EventHandlerRegistry::willDetachDocument()
227 {
228 Document* document = DocumentLifecycleObserver::lifecycleContext();
229 Document* parentDocument = document->parentDocument();
230 if (!parentDocument)
231 return;
232 // Unregister our Document node from the parent for all event classes that
233 // have handlers.
234 EventHandlerRegistry* parentRegistry = EventHandlerRegistry::from(*parentDoc ument);
235 updateAllEventHandlersForTarget(RemoveAll, *document, *parentRegistry);
236 }
237
238 void EventHandlerRegistry::documentWasAttached()
239 {
240 Document* document = DocumentLifecycleObserver::lifecycleContext();
241 if (document->parentDocument())
242 return;
243 for (size_t i = 0; i < EventHandlerClassCount; ++i) {
244 EventHandlerClass handlerClass = static_cast<EventHandlerClass>(i);
245 if (eventHandlerCount(handlerClass))
246 notifyDidAddFirstOrRemoveLastEventHandler(*document, handlerClass, t rue);
247 }
248 }
249
250 void EventHandlerRegistry::didAddEventHandler(EventTarget& target, const AtomicS tring& eventType)
251 {
252 updateEventHandlerOfType(Add, eventType, target);
253 }
254
255 void EventHandlerRegistry::didRemoveEventHandler(EventTarget& target, const Atom icString& eventType)
256 {
257 updateEventHandlerOfType(Remove, eventType, target);
258 }
259
260 void EventHandlerRegistry::didAddEventListener(DOMWindow* window, const AtomicSt ring& eventType)
261 {
262 updateEventHandlerOfType(Add, eventType, *window);
263 }
264
265 void EventHandlerRegistry::didRemoveEventListener(DOMWindow* window, const Atomi cString& eventType)
266 {
267 updateEventHandlerOfType(Remove, eventType, *window);
268 }
269
270 void EventHandlerRegistry::didRemoveAllEventListeners(DOMWindow* window)
271 {
272 updateAllEventHandlersForTarget(RemoveAll, *window, *this);
273 }
274
275 void EventHandlerRegistry::didMoveToNewDocument(EventTarget& target, Document& o ldDocument)
276 {
277 EventHandlerRegistry* oldRegistry = EventHandlerRegistry::from(oldDocument);
278 oldRegistry->updateAllEventHandlersForTarget(Add, target, *this);
279 oldRegistry->updateAllEventHandlersForTarget(Remove, target, *oldRegistry);
280 }
281
282 void EventHandlerRegistry::didRemoveAllEventHandlers(EventTarget& target)
283 {
284 updateAllEventHandlersForTarget(RemoveAll, target, *this);
285 }
286
287 void EventHandlerRegistry::updateAllEventHandlersForTarget(ChangeOperation op, E ventTarget& target, EventHandlerRegistry& targetRegistry) const
Rick Byers 2014/03/27 16:43:31 I find this function confusing. Perhaps there's r
Sami 2014/04/02 19:58:05 Right, I tried a little too hard to reuse code and
288 {
289 for (size_t i = 0; i < EventHandlerClassCount; ++i) {
290 EventHandlerClass handlerClass = static_cast<EventHandlerClass>(i);
291 const EventTargetSet* targets = eventHandlerTargets(handlerClass);
292 if (!targets)
293 continue;
294 for (unsigned count = targets->count(&target); count > 0; --count)
Rick Byers 2014/03/27 16:43:31 This loop doesn't seem to make sense when the op i
Sami 2014/04/02 19:58:05 Done.
295 targetRegistry.updateEventHandlerOfClass(op, handlerClass, target);
296 }
297 }
298
299 void EventHandlerRegistry::notifyDidAddFirstOrRemoveLastEventHandler(Document& d ocument, EventHandlerClass handlerClass, bool hasActiveHandlers)
300 {
301 Page* page = document.page();
302 LocalFrame* mainFrame = page ? page->mainFrame() : nullptr;
303 ScrollingCoordinator* scrollingCoordinator = page ? page->scrollingCoordinat or() : nullptr;
304 FrameView* frameView = document.view();
305
306 switch (handlerClass) {
307 case WheelEvent:
308 if (mainFrame) {
309 // TODO(skyostil): This notification is wired up to a black hole, so remove it.
310 mainFrame->notifyChromeClientWheelEventHandlerCountChanged();
311 }
312 if (scrollingCoordinator && frameView)
313 scrollingCoordinator->frameViewWheelEventHandlerCountChanged(frameVi ew);
Rick Byers 2014/03/27 16:43:31 This function and the below say they're supposed t
Sami 2014/04/02 19:58:05 Yes, especially now that ScrollingCoordinator no l
314 break;
315 case ScrollEvent:
316 if (scrollingCoordinator && frameView)
317 scrollingCoordinator->frameViewScrollEventHandlerCountChanged(frameV iew);
318 break;
319 case TouchEvent:
320 if (FrameHost* frameHost = document.frameHost())
321 frameHost->chrome().client().needTouchEvents(hasActiveHandlers);
322 break;
323 default:
324 ASSERT_NOT_REACHED();
325 break;
326 }
327 }
328
329 void EventHandlerRegistry::notifyDidAddOrRemoveEventHandlerTarget(EventHandlerCl ass handlerClass, Document& document)
330 {
331 Page* page = document.page();
332 if (!page)
333 return;
334
335 ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator();
336 if (!scrollingCoordinator)
337 return;
338
339 if (handlerClass == TouchEvent)
340 scrollingCoordinator->touchEventTargetRectsDidChange();
341 }
342
343 } // namespace WebCore
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698