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

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

Powered by Google App Engine
This is Rietveld 408576698