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

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: Added comments. Replaced nullptr with 0 to fix build. Created 6 years, 8 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.
abarth-chromium 2014/04/10 21:25:58 blank line after this line pls
Sami 2014/04/11 16:46:53 Done.
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::WindowObserver::WindowObserver(EventHandlerRegistry& regis try, DOMWindow& window)
20 : DOMWindowLifecycleObserver(&window)
21 , m_registry(registry)
22 {
23 }
24
25 EventHandlerRegistry::WindowObserver::~WindowObserver()
26 {
27 }
28
29 void EventHandlerRegistry::WindowObserver::didAddEventListener(DOMWindow* window , const AtomicString& eventType)
30 {
31 m_registry.didAddEventHandler(*window, eventType);
32 }
33
34 void EventHandlerRegistry::WindowObserver::didRemoveEventListener(DOMWindow* win dow, const AtomicString& eventType)
35 {
36 m_registry.didRemoveEventHandler(*window, eventType);
37 }
38
39 void EventHandlerRegistry::WindowObserver::didRemoveAllEventListeners(DOMWindow* window)
40 {
41 m_registry.didRemoveAllEventHandlers(*window);
42 }
43
44 EventHandlerRegistry::DocumentObserver::DocumentObserver(Document& document)
45 : DocumentLifecycleObserver(&document) { }
46
47 EventHandlerRegistry::DocumentObserver::~DocumentObserver()
48 {
49 }
50
51 void EventHandlerRegistry::DocumentObserver::documentWasAttached()
52 {
53 Document* document = lifecycleContext();
54 if (document->parentDocument())
55 return;
56 EventHandlerRegistry* registry = EventHandlerRegistry::from(*document);
57
58 // Make sure we are tracking handlers on the window.
59 if (!registry->m_windowObserver && document->domWindow()) {
60 ASSERT(!document->domWindow()->hasEventListeners());
abarth-chromium 2014/04/10 21:25:58 I don't think this ASSERT is valid. I think it's
Sami 2014/04/11 16:46:53 Ok, I wasn't sure if that was the case so I added
61 registry->m_windowObserver = adoptPtr(new WindowObserver(*registry, *doc ument->domWindow()));
62 }
63
64 // When the root document is attached, notify clients of any handlers it has .
65 for (size_t i = 0; i < EventHandlerClassCount; ++i) {
66 EventHandlerClass handlerClass = static_cast<EventHandlerClass>(i);
67 if (registry->hasEventHandlers(handlerClass)) {
68 registry->notifyHasHandlersChanged(handlerClass, true);
69 registry->notifyDidAddOrRemoveEventHandlerTarget(handlerClass);
70 }
71 }
abarth-chromium 2014/04/10 21:25:58 Why are we delaying this processing until attachme
Sami 2014/04/11 16:46:53 This is something I cargo culted from DOMWindow::i
72 }
73
74 void EventHandlerRegistry::DocumentObserver::willDetachDocument()
75 {
76 Document* document = lifecycleContext();
77
78 // The detached document should no longer track handlers on its window.
79 EventHandlerRegistry* registry = EventHandlerRegistry::from(*document);
80 if (document->domWindow())
81 registry->didRemoveAllEventHandlers(*document->domWindow());
82 registry->m_windowObserver.clear();
83
84 // Unregister our Document node from the parent for all event classes that
85 // have handlers.
86 Document* parentDocument = document->parentDocument();
87 if (!parentDocument)
88 return;
89 EventHandlerRegistry* parentRegistry = EventHandlerRegistry::from(*parentDoc ument);
90 parentRegistry->didRemoveAllEventHandlers(*document);
91 }
92
93 EventHandlerRegistry::HandlerState::HandlerState()
94 : externalHandlerCount(0)
95 {
96 }
97
98 EventHandlerRegistry::HandlerState::~HandlerState()
99 {
100 }
101
102 EventHandlerRegistry::EventHandlerRegistry(Document& document)
103 : m_document(document)
104 , m_documentObserver(DocumentObserver(document))
105 , m_windowObserver(adoptPtr(new WindowObserver(*this, *document.domWindow()) ))
106 {
107 }
108
109 EventHandlerRegistry::~EventHandlerRegistry()
110 {
111 }
112
113 const char* EventHandlerRegistry::supplementName()
114 {
115 return "EventHandlerRegistry";
116 }
117
118 EventHandlerRegistry* EventHandlerRegistry::from(Document& document)
119 {
120 EventHandlerRegistry* registry = static_cast<EventHandlerRegistry*>(Document Supplement::from(document, supplementName()));
121 if (!registry) {
122 registry = new EventHandlerRegistry(document);
123 DocumentSupplement::provideTo(document, supplementName(), adoptPtr(regis try));
124 }
125 return registry;
126 }
127
128 bool EventHandlerRegistry::eventTypeToClass(const AtomicString& eventType, Event HandlerClass* result)
129 {
130 if (eventType == EventTypeNames::wheel || eventType == EventTypeNames::mouse wheel) {
131 *result = WheelEvent;
132 } else if (eventType == EventTypeNames::scroll) {
133 *result = ScrollEvent;
134 } else if (isTouchEventType(eventType)) {
135 *result = TouchEvent;
136 } else {
137 return false;
138 }
139 return true;
140 }
141
142 const EventTargetSet* EventHandlerRegistry::eventHandlerTargets(EventHandlerClas s handlerClass) const
143 {
144 return m_eventHandlers[handlerClass].targets.get();
145 }
146
147 bool EventHandlerRegistry::hasEventHandlers(EventHandlerClass handlerClass) cons t
148 {
149 EventTargetSet* targets = m_eventHandlers[handlerClass].targets.get();
150 return m_eventHandlers[handlerClass].externalHandlerCount || (targets && tar gets->size());
151 }
152
153 unsigned EventHandlerRegistry::externalEventHandlerCount(EventHandlerClass handl erClass) const
154 {
155 return m_eventHandlers[handlerClass].externalHandlerCount;
156 }
157
158 void EventHandlerRegistry::updateExternalHandlerCount(ChangeOperation op, EventH andlerClass handlerClass)
159 {
160 if (op == Add) {
161 m_eventHandlers[handlerClass].externalHandlerCount++;
162 } else {
163 ASSERT(op == Remove);
164 ASSERT(m_eventHandlers[handlerClass].externalHandlerCount > 0);
165 m_eventHandlers[handlerClass].externalHandlerCount--;
166 }
167 }
168
169 bool EventHandlerRegistry::updateEventHandlerTargets(ChangeOperation op, EventHa ndlerClass handlerClass, EventTarget* target)
170 {
171 EventTargetSet* targets = m_eventHandlers[handlerClass].targets.get();
172 if (op == Add) {
173 #ifndef NDEBUG
174 if (Node* node = target->toNode()) {
175 // The node should either be in the document, or be the Document nod e of a child
176 // of the document.
177 ASSERT(&node->document() == &m_document
178 || (node->isDocumentNode() && toDocument(node)->parentDocument() == &m_document));
179 } else if (DOMWindow* window = target->toDOMWindow()) {
180 // The window should belong to this document.
181 ASSERT(window->document() == &m_document);
182 }
183 #endif // NDEBUG
184
185 if (!targets) {
186 m_eventHandlers[handlerClass].targets = adoptPtr(new EventTargetSet) ;
187 targets = m_eventHandlers[handlerClass].targets.get();
188 }
189
190 if (!targets->add(target).isNewEntry) {
191 // Just incremented refcount, no real change.
192 // If this is a child document node, then the count should never go above 1.
193 #ifndef NDEBUG
194 if (Node* node = target->toNode())
195 ASSERT(!node->isDocumentNode() || &node->document() == &m_docume nt);
196 #endif // NDEBUG
197 return false;
198 }
199 } else {
200 // Note that we can't assert that |target| is in this document because
201 // it might be in the process of moving out of it.
202 ASSERT(op == Remove || op == RemoveAll);
203 ASSERT(op == RemoveAll || targets->contains(target));
204 if (!targets)
205 return false;
206
207 if (op == RemoveAll) {
208 if (!targets->contains(target))
209 return false;
210 targets->removeAll(target);
211 } else {
212 if (!targets->remove(target)) {
213 // Just decremented refcount, no real update.
214 return false;
215 }
216 }
217 }
218 return true;
219 }
220
221 void EventHandlerRegistry::updateEventHandlerInternal(ChangeOperation op, EventH andlerClass handlerClass, EventTarget* target)
222 {
223 bool hadHandlers = hasEventHandlers(handlerClass);
224 bool targetSetChanged;
225 if (target) {
226 targetSetChanged = updateEventHandlerTargets(op, handlerClass, target);
227 } else {
228 updateExternalHandlerCount(op, handlerClass);
229 targetSetChanged = true;
230 }
231 bool hasHandlers = hasEventHandlers(handlerClass);
232
233 // Notify the parent document's registry if we added the first or removed
234 // the last handler.
235 if (hadHandlers != hasHandlers) {
236 if (Document* parent = m_document.parentDocument()) {
237 // Report change to parent with our Document as the target.
238 EventHandlerRegistry::from(*parent)->updateEventHandlerInternal(op, handlerClass, &m_document);
239 } else {
240 // This is the root registry; notify clients accordingly.
241 notifyHasHandlersChanged(handlerClass, hasHandlers);
242 }
243 }
244
245 // Only notify the client when something actually changed, and then only if
246 // this wasn't a notification that was sent by a sub-registry.
247 if (!targetSetChanged)
248 return;
249 Node* node = target ? target->toNode() : 0;
250 if (!node || !node->isDocumentNode() || node == &m_document)
251 notifyDidAddOrRemoveEventHandlerTarget(handlerClass);
252 }
253
254 void EventHandlerRegistry::updateEventHandlerOfType(ChangeOperation op, const At omicString& eventType, EventTarget* target)
255 {
256 EventHandlerClass handlerClass;
257 if (!eventTypeToClass(eventType, &handlerClass))
258 return;
259 updateEventHandlerInternal(op, handlerClass, target);
260 }
261
262 void EventHandlerRegistry::didAddExternalEventHandler(const AtomicString& eventT ype)
263 {
264 updateEventHandlerOfType(Add, eventType, 0);
265 }
266
267 void EventHandlerRegistry::didRemoveExternalEventHandler(const AtomicString& eve ntType)
268 {
269 updateEventHandlerOfType(Remove, eventType, 0);
270 }
271
272 void EventHandlerRegistry::didAddEventHandler(EventTarget& target, const AtomicS tring& eventType)
273 {
274 updateEventHandlerOfType(Add, eventType, &target);
275 }
276
277 void EventHandlerRegistry::didRemoveEventHandler(EventTarget& target, const Atom icString& eventType)
278 {
279 updateEventHandlerOfType(Remove, eventType, &target);
280 }
281
282 void EventHandlerRegistry::didAddEventHandler(EventTarget& target, EventHandlerC lass handlerClass)
283 {
284 updateEventHandlerInternal(Add, handlerClass, &target);
285 }
286
287 void EventHandlerRegistry::didRemoveEventHandler(EventTarget& target, EventHandl erClass handlerClass)
288 {
289 updateEventHandlerInternal(Remove, handlerClass, &target);
290 }
291
292 void EventHandlerRegistry::didMoveFromOtherDocument(EventTarget& target, Documen t& oldDocument)
293 {
294 EventHandlerRegistry* oldRegistry = EventHandlerRegistry::from(oldDocument);
295 for (size_t i = 0; i < EventHandlerClassCount; ++i) {
296 EventHandlerClass handlerClass = static_cast<EventHandlerClass>(i);
297 const EventTargetSet* targets = oldRegistry->eventHandlerTargets(handler Class);
298 if (!targets)
299 continue;
300 for (unsigned count = targets->count(&target); count > 0; --count) {
301 oldRegistry->updateEventHandlerInternal(Remove, handlerClass, &targe t);
302 updateEventHandlerInternal(Add, handlerClass, &target);
303 }
304 }
305 }
306
307 void EventHandlerRegistry::didRemoveAllEventHandlers(EventTarget& target)
308 {
309 for (size_t i = 0; i < EventHandlerClassCount; ++i) {
310 EventHandlerClass handlerClass = static_cast<EventHandlerClass>(i);
311 const EventTargetSet* targets = eventHandlerTargets(handlerClass);
312 if (!targets)
313 continue;
314 updateEventHandlerInternal(RemoveAll, handlerClass, &target);
315 }
316 }
317
318 void EventHandlerRegistry::notifyHasHandlersChanged(EventHandlerClass handlerCla ss, bool hasActiveHandlers)
319 {
320 Page* page = m_document.page();
321 LocalFrame* mainFrame = page ? page->mainFrame() : 0;
322 ScrollingCoordinator* scrollingCoordinator = page ? page->scrollingCoordinat or() : 0;
323
324 switch (handlerClass) {
325 case WheelEvent:
326 if (mainFrame) {
327 // TODO(skyostil): This notification is wired up to a black hole, so remove it.
328 mainFrame->notifyChromeClientWheelEventHandlerCountChanged();
329 }
330 if (scrollingCoordinator)
331 scrollingCoordinator->haveWheelEventHandlersChangedForPage();
332 break;
333 case ScrollEvent:
334 if (scrollingCoordinator)
335 scrollingCoordinator->haveScrollEventHandlersChangedForPage();
336 break;
337 case TouchEvent:
338 if (FrameHost* frameHost = m_document.frameHost())
339 frameHost->chrome().client().needTouchEvents(hasActiveHandlers);
340 break;
341 default:
342 ASSERT_NOT_REACHED();
343 break;
344 }
345 }
346
347 void EventHandlerRegistry::notifyDidAddOrRemoveEventHandlerTarget(EventHandlerCl ass handlerClass)
348 {
349 Page* page = m_document.page();
350 if (!page)
351 return;
352
353 ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator();
354 if (!scrollingCoordinator)
355 return;
356
357 if (handlerClass == TouchEvent)
358 scrollingCoordinator->touchEventTargetRectsDidChange();
359 }
360
361 } // namespace WebCore
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698