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

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

Powered by Google App Engine
This is Rietveld 408576698