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

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

Powered by Google App Engine
This is Rietveld 408576698