OLD | NEW |
---|---|
(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 | |
OLD | NEW |