OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "config.h" | 5 #include "config.h" |
6 #include "core/dom/EventHandlerRegistry.h" | 6 #include "core/page/EventHandlerRegistry.h" |
7 | 7 |
8 #include "core/dom/Document.h" | |
9 #include "core/events/ThreadLocalEventNames.h" | 8 #include "core/events/ThreadLocalEventNames.h" |
10 #include "core/events/WheelEvent.h" | 9 #include "core/html/HTMLFrameOwnerElement.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" | 10 #include "core/page/scrolling/ScrollingCoordinator.h" |
17 | 11 |
18 namespace WebCore { | 12 namespace WebCore { |
19 | 13 |
20 EventHandlerRegistry::HandlerState::HandlerState() | 14 EventHandlerRegistry::EventHandlerRegistry(Page& page) |
21 { | 15 : m_page(page) |
22 } | |
23 | |
24 EventHandlerRegistry::HandlerState::~HandlerState() | |
25 { | |
26 } | |
27 | |
28 EventHandlerRegistry::EventHandlerRegistry(Document& document) | |
29 : m_document(document) | |
30 { | 16 { |
31 } | 17 } |
32 | 18 |
33 EventHandlerRegistry::~EventHandlerRegistry() | 19 EventHandlerRegistry::~EventHandlerRegistry() |
34 { | 20 { |
| 21 checkConsistency(); |
35 } | 22 } |
36 | 23 |
37 const char* EventHandlerRegistry::supplementName() | 24 const char* EventHandlerRegistry::supplementName() |
38 { | 25 { |
39 return "EventHandlerRegistry"; | 26 return "EventHandlerRegistry"; |
40 } | 27 } |
41 | 28 |
42 EventHandlerRegistry* EventHandlerRegistry::from(Document& document) | 29 EventHandlerRegistry* EventHandlerRegistry::from(Page& page) |
43 { | 30 { |
44 EventHandlerRegistry* registry = static_cast<EventHandlerRegistry*>(Document
Supplement::from(document, supplementName())); | 31 EventHandlerRegistry* registry = static_cast<EventHandlerRegistry*>(WillBeHe
apSupplement<Page>::from(page, supplementName())); |
45 if (!registry) { | 32 if (!registry) { |
46 registry = new EventHandlerRegistry(document); | 33 registry = new EventHandlerRegistry(page); |
47 DocumentSupplement::provideTo(document, supplementName(), adoptPtrWillBe
Noop(registry)); | 34 Supplement<Page>::provideTo(page, supplementName(), adoptPtrWillBeNoop(r
egistry)); |
48 } | 35 } |
49 return registry; | 36 return registry; |
50 } | 37 } |
51 | 38 |
52 bool EventHandlerRegistry::eventTypeToClass(const AtomicString& eventType, Event
HandlerClass* result) | 39 bool EventHandlerRegistry::eventTypeToClass(const AtomicString& eventType, Event
HandlerClass* result) |
53 { | 40 { |
54 if (eventType == EventTypeNames::scroll) { | 41 if (eventType == EventTypeNames::scroll) { |
55 *result = ScrollEvent; | 42 *result = ScrollEvent; |
| 43 #if ASSERT_ENABLED |
| 44 } else if (eventType == EventTypeNames::load || eventType == EventTypeNames:
:mousemove || eventType == EventTypeNames::touchstart) { |
| 45 *result = EventsForTesting; |
| 46 #endif |
56 } else { | 47 } else { |
57 return false; | 48 return false; |
58 } | 49 } |
59 return true; | 50 return true; |
60 } | 51 } |
61 | 52 |
62 const EventTargetSet* EventHandlerRegistry::eventHandlerTargets(EventHandlerClas
s handlerClass) const | 53 const EventTargetSet* EventHandlerRegistry::eventHandlerTargets(EventHandlerClas
s handlerClass) const |
63 { | 54 { |
64 return m_eventHandlers[handlerClass].targets.get(); | 55 checkConsistency(); |
| 56 return &m_targets[handlerClass]; |
65 } | 57 } |
66 | 58 |
67 bool EventHandlerRegistry::hasEventHandlers(EventHandlerClass handlerClass) cons
t | 59 bool EventHandlerRegistry::hasEventHandlers(EventHandlerClass handlerClass) cons
t |
68 { | 60 { |
69 EventTargetSet* targets = m_eventHandlers[handlerClass].targets.get(); | 61 return m_targets[handlerClass].size(); |
70 return targets && targets->size(); | |
71 } | 62 } |
72 | 63 |
73 bool EventHandlerRegistry::updateEventHandlerTargets(ChangeOperation op, EventHa
ndlerClass handlerClass, EventTarget* target) | 64 bool EventHandlerRegistry::updateEventHandlerTargets(ChangeOperation op, EventHa
ndlerClass handlerClass, EventTarget* target) |
74 { | 65 { |
75 EventTargetSet* targets = m_eventHandlers[handlerClass].targets.get(); | 66 EventTargetSet* targets = &m_targets[handlerClass]; |
76 if (op == Add) { | 67 if (op == Add) { |
77 #if ASSERT_ENABLED | |
78 if (Node* node = target->toNode()) | |
79 ASSERT(&node->document() == &m_document); | |
80 #endif // ASSERT_ENABLED | |
81 | |
82 if (!targets) { | |
83 m_eventHandlers[handlerClass].targets = adoptPtr(new EventTargetSet)
; | |
84 targets = m_eventHandlers[handlerClass].targets.get(); | |
85 } | |
86 | |
87 if (!targets->add(target).isNewEntry) { | 68 if (!targets->add(target).isNewEntry) { |
88 // Just incremented refcount, no real change. | 69 // Just incremented refcount, no real change. |
89 return false; | 70 return false; |
90 } | 71 } |
91 } else { | 72 } else { |
92 // Note that we can't assert that |target| is in this document because | |
93 // it might be in the process of moving out of it. | |
94 ASSERT(op == Remove || op == RemoveAll); | 73 ASSERT(op == Remove || op == RemoveAll); |
95 ASSERT(op == RemoveAll || targets->contains(target)); | 74 ASSERT(op == RemoveAll || targets->contains(target)); |
96 if (!targets) | |
97 return false; | |
98 | 75 |
99 if (op == RemoveAll) { | 76 if (op == RemoveAll) { |
100 if (!targets->contains(target)) | 77 if (!targets->contains(target)) |
101 return false; | 78 return false; |
102 targets->removeAll(target); | 79 targets->removeAll(target); |
103 } else { | 80 } else { |
104 if (!targets->remove(target)) { | 81 if (!targets->remove(target)) { |
105 // Just decremented refcount, no real update. | 82 // Just decremented refcount, no real update. |
106 return false; | 83 return false; |
107 } | 84 } |
108 } | 85 } |
109 } | 86 } |
110 return true; | 87 return true; |
111 } | 88 } |
112 | 89 |
113 void EventHandlerRegistry::updateEventHandlerInternal(ChangeOperation op, EventH
andlerClass handlerClass, EventTarget* target) | 90 void EventHandlerRegistry::updateEventHandlerInternal(ChangeOperation op, EventH
andlerClass handlerClass, EventTarget* target) |
114 { | 91 { |
115 // After the document has stopped, all updates become no-ops. | |
116 if (!m_document.isActive()) { | |
117 return; | |
118 } | |
119 | |
120 bool hadHandlers = hasEventHandlers(handlerClass); | 92 bool hadHandlers = hasEventHandlers(handlerClass); |
121 updateEventHandlerTargets(op, handlerClass, target); | 93 updateEventHandlerTargets(op, handlerClass, target); |
122 bool hasHandlers = hasEventHandlers(handlerClass); | 94 bool hasHandlers = hasEventHandlers(handlerClass); |
123 | 95 |
124 // Notify the parent document's registry if we added the first or removed | 96 if (hadHandlers != hasHandlers) { |
125 // the last handler. | |
126 if (hadHandlers != hasHandlers && !m_document.parentDocument()) { | |
127 // This is the root registry; notify clients accordingly. | |
128 notifyHasHandlersChanged(handlerClass, hasHandlers); | 97 notifyHasHandlersChanged(handlerClass, hasHandlers); |
129 } | 98 } |
| 99 checkConsistency(); |
130 } | 100 } |
131 | 101 |
132 void EventHandlerRegistry::updateEventHandlerOfType(ChangeOperation op, const At
omicString& eventType, EventTarget* target) | 102 void EventHandlerRegistry::updateEventHandlerOfType(ChangeOperation op, const At
omicString& eventType, EventTarget* target) |
133 { | 103 { |
134 EventHandlerClass handlerClass; | 104 EventHandlerClass handlerClass; |
135 if (!eventTypeToClass(eventType, &handlerClass)) | 105 if (!eventTypeToClass(eventType, &handlerClass)) |
136 return; | 106 return; |
137 updateEventHandlerInternal(op, handlerClass, target); | 107 updateEventHandlerInternal(op, handlerClass, target); |
138 } | 108 } |
139 | 109 |
(...skipping 10 matching lines...) Expand all Loading... |
150 void EventHandlerRegistry::didAddEventHandler(EventTarget& target, EventHandlerC
lass handlerClass) | 120 void EventHandlerRegistry::didAddEventHandler(EventTarget& target, EventHandlerC
lass handlerClass) |
151 { | 121 { |
152 updateEventHandlerInternal(Add, handlerClass, &target); | 122 updateEventHandlerInternal(Add, handlerClass, &target); |
153 } | 123 } |
154 | 124 |
155 void EventHandlerRegistry::didRemoveEventHandler(EventTarget& target, EventHandl
erClass handlerClass) | 125 void EventHandlerRegistry::didRemoveEventHandler(EventTarget& target, EventHandl
erClass handlerClass) |
156 { | 126 { |
157 updateEventHandlerInternal(Remove, handlerClass, &target); | 127 updateEventHandlerInternal(Remove, handlerClass, &target); |
158 } | 128 } |
159 | 129 |
160 void EventHandlerRegistry::didMoveFromOtherDocument(EventTarget& target, Documen
t& oldDocument) | 130 void EventHandlerRegistry::didMoveIntoPage(EventTarget& target) |
161 { | 131 { |
162 EventHandlerRegistry* oldRegistry = EventHandlerRegistry::from(oldDocument); | 132 updateAllEventHandlers(Add, target); |
163 for (size_t i = 0; i < EventHandlerClassCount; ++i) { | 133 } |
164 EventHandlerClass handlerClass = static_cast<EventHandlerClass>(i); | 134 |
165 const EventTargetSet* targets = oldRegistry->eventHandlerTargets(handler
Class); | 135 void EventHandlerRegistry::didMoveOutOfPage(EventTarget& target) |
166 if (!targets) | 136 { |
167 continue; | 137 updateAllEventHandlers(RemoveAll, target); |
168 for (unsigned count = targets->count(&target); count > 0; --count) { | |
169 oldRegistry->updateEventHandlerInternal(Remove, handlerClass, &targe
t); | |
170 updateEventHandlerInternal(Add, handlerClass, &target); | |
171 } | |
172 } | |
173 } | 138 } |
174 | 139 |
175 void EventHandlerRegistry::didRemoveAllEventHandlers(EventTarget& target) | 140 void EventHandlerRegistry::didRemoveAllEventHandlers(EventTarget& target) |
176 { | 141 { |
177 for (size_t i = 0; i < EventHandlerClassCount; ++i) { | 142 for (size_t i = 0; i < EventHandlerClassCount; ++i) { |
178 EventHandlerClass handlerClass = static_cast<EventHandlerClass>(i); | 143 EventHandlerClass handlerClass = static_cast<EventHandlerClass>(i); |
179 const EventTargetSet* targets = eventHandlerTargets(handlerClass); | 144 updateEventHandlerInternal(RemoveAll, handlerClass, &target); |
180 if (!targets) | 145 } |
| 146 } |
| 147 |
| 148 void EventHandlerRegistry::updateAllEventHandlers(ChangeOperation op, EventTarge
t& target) |
| 149 { |
| 150 if (!target.hasEventListeners()) |
| 151 return; |
| 152 |
| 153 Vector<AtomicString> eventTypes = target.eventTypes(); |
| 154 for (size_t i = 0; i < eventTypes.size(); ++i) { |
| 155 EventHandlerClass handlerClass; |
| 156 if (!eventTypeToClass(eventTypes[i], &handlerClass)) |
181 continue; | 157 continue; |
182 updateEventHandlerInternal(RemoveAll, handlerClass, &target); | 158 if (op == RemoveAll) { |
| 159 updateEventHandlerInternal(op, handlerClass, &target); |
| 160 continue; |
| 161 } |
| 162 for (unsigned count = target.getEventListeners(eventTypes[i]).size(); co
unt > 0; --count) |
| 163 updateEventHandlerInternal(op, handlerClass, &target); |
183 } | 164 } |
184 } | 165 } |
185 | 166 |
186 void EventHandlerRegistry::notifyHasHandlersChanged(EventHandlerClass handlerCla
ss, bool hasActiveHandlers) | 167 void EventHandlerRegistry::notifyHasHandlersChanged(EventHandlerClass handlerCla
ss, bool hasActiveHandlers) |
187 { | 168 { |
188 Page* page = m_document.page(); | 169 ScrollingCoordinator* scrollingCoordinator = m_page.scrollingCoordinator(); |
189 ScrollingCoordinator* scrollingCoordinator = page ? page->scrollingCoordinat
or() : 0; | |
190 | 170 |
191 switch (handlerClass) { | 171 switch (handlerClass) { |
192 case ScrollEvent: | 172 case ScrollEvent: |
193 if (scrollingCoordinator) | 173 if (scrollingCoordinator) |
194 scrollingCoordinator->updateHaveScrollEventHandlers(); | 174 scrollingCoordinator->updateHaveScrollEventHandlers(); |
195 break; | 175 break; |
| 176 #if ASSERT_ENABLED |
| 177 case EventsForTesting: |
| 178 break; |
| 179 #endif |
196 default: | 180 default: |
197 ASSERT_NOT_REACHED(); | 181 ASSERT_NOT_REACHED(); |
198 break; | 182 break; |
199 } | 183 } |
200 } | 184 } |
201 | 185 |
202 void EventHandlerRegistry::trace(Visitor* visitor) | 186 void EventHandlerRegistry::trace(Visitor* visitor) |
203 { | 187 { |
204 visitor->registerWeakMembers<EventHandlerRegistry, &EventHandlerRegistry::cl
earWeakMembers>(this); | 188 visitor->registerWeakMembers<EventHandlerRegistry, &EventHandlerRegistry::cl
earWeakMembers>(this); |
205 } | 189 } |
206 | 190 |
207 void EventHandlerRegistry::clearWeakMembers(Visitor* visitor) | 191 void EventHandlerRegistry::clearWeakMembers(Visitor* visitor) |
208 { | 192 { |
209 // FIXME: Oilpan: This is pretty funky. The current code disables all modifi
cations of the | |
210 // EventHandlerRegistry when the document becomes inactive. To keep that beh
avior we only | |
211 // perform weak processing of the registry when the document is active. | |
212 if (!m_document.isActive()) | |
213 return; | |
214 Vector<EventTarget*> deadNodeTargets; | 193 Vector<EventTarget*> deadNodeTargets; |
215 for (size_t i = 0; i < EventHandlerClassCount; ++i) { | 194 for (size_t i = 0; i < EventHandlerClassCount; ++i) { |
216 EventHandlerClass handlerClass = static_cast<EventHandlerClass>(i); | 195 EventHandlerClass handlerClass = static_cast<EventHandlerClass>(i); |
217 const EventTargetSet* targets = eventHandlerTargets(handlerClass); | 196 const EventTargetSet* targets = &m_targets[handlerClass]; |
218 if (!targets) | |
219 continue; | |
220 for (EventTargetSet::const_iterator it = targets->begin(); it != targets
->end(); ++it) { | 197 for (EventTargetSet::const_iterator it = targets->begin(); it != targets
->end(); ++it) { |
221 Node* node = it->key->toNode(); | 198 Node* node = it->key->toNode(); |
222 if (node && !visitor->isAlive(node)) | 199 if (node && !visitor->isAlive(node)) |
223 deadNodeTargets.append(node); | 200 deadNodeTargets.append(node); |
224 } | 201 } |
225 } | 202 } |
226 for (size_t i = 0; i < deadNodeTargets.size(); ++i) | 203 for (size_t i = 0; i < deadNodeTargets.size(); ++i) |
227 didRemoveAllEventHandlers(*deadNodeTargets[i]); | 204 didRemoveAllEventHandlers(*deadNodeTargets[i]); |
228 } | 205 } |
229 | 206 |
| 207 void EventHandlerRegistry::documentDetached(Document& document) |
| 208 { |
| 209 // Remove all event targets under the detached document. |
| 210 for (size_t handlerClassIndex = 0; handlerClassIndex < EventHandlerClassCoun
t; ++handlerClassIndex) { |
| 211 EventHandlerClass handlerClass = static_cast<EventHandlerClass>(handlerC
lassIndex); |
| 212 Vector<EventTarget*> targetsToRemove; |
| 213 const EventTargetSet* targets = &m_targets[handlerClass]; |
| 214 for (EventTargetSet::const_iterator iter = targets->begin(); iter != tar
gets->end(); ++iter) { |
| 215 if (Node* node = iter->key->toNode()) { |
| 216 for (Document* doc = &node->document(); doc; doc = doc->ownerEle
ment() ? &doc->ownerElement()->document() : 0) { |
| 217 if (doc == &document) { |
| 218 targetsToRemove.append(iter->key); |
| 219 break; |
| 220 } |
| 221 } |
| 222 } |
| 223 } |
| 224 for (size_t i = 0; i < targetsToRemove.size(); ++i) |
| 225 updateEventHandlerInternal(RemoveAll, handlerClass, targetsToRemove[
i]); |
| 226 } |
| 227 } |
| 228 |
| 229 void EventHandlerRegistry::checkConsistency() const |
| 230 { |
| 231 #if ASSERT_ENABLED |
| 232 for (size_t i = 0; i < EventHandlerClassCount; ++i) { |
| 233 EventHandlerClass handlerClass = static_cast<EventHandlerClass>(i); |
| 234 const EventTargetSet* targets = &m_targets[handlerClass]; |
| 235 for (EventTargetSet::const_iterator iter = targets->begin(); iter != tar
gets->end(); ++iter) { |
| 236 if (Node* node = iter->key->toNode()) { |
| 237 // See the comment for |documentDetached| if either of these ass
ertions fails. |
| 238 ASSERT(node->document().page()); |
| 239 ASSERT(node->document().page() == &m_page); |
| 240 } |
| 241 } |
| 242 } |
| 243 #endif // ASSERT_ENABLED |
| 244 } |
| 245 |
230 } // namespace WebCore | 246 } // namespace WebCore |
OLD | NEW |