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

Side by Side Diff: Source/core/page/EventHandlerRegistry.cpp

Issue 237963014: Track scroll event handlers in nested documents (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Oilpan build fix. Created 6 years, 7 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 | Annotate | Revision Log
« no previous file with comments | « Source/core/page/EventHandlerRegistry.h ('k') | Source/core/page/Page.cpp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
OLDNEW
« no previous file with comments | « Source/core/page/EventHandlerRegistry.h ('k') | Source/core/page/Page.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698