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

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: Discard handlers in detached docs. Moar tests. 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
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*>(Suppleme nt<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(), adoptPtr(regis try)); 34 Supplement<Page>::provideTo(page, supplementName(), adoptPtr(registry));
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
186 void EventHandlerRegistry::documentDetached(Document& document)
187 {
188 // Remove all event targets under the detached document.
189 for (size_t handlerClassIndex = 0; handlerClassIndex < EventHandlerClassCoun t; ++handlerClassIndex) {
190 EventHandlerClass handlerClass = static_cast<EventHandlerClass>(handlerC lassIndex);
191 Vector<EventTarget*> targetsToRemove;
192 const EventTargetSet* targets = &m_targets[handlerClass];
193 for (EventTargetSet::const_iterator iter = targets->begin(); iter != tar gets->end(); ++iter) {
194 if (Node* node = iter->key->toNode()) {
195 for (Document* doc = &node->document(); doc; doc = doc->ownerEle ment() ? &doc->ownerElement()->document() : 0) {
196 if (doc == &document) {
197 targetsToRemove.append(iter->key);
198 break;
199 }
200 }
201 }
202 }
203 for (size_t i = 0; i < targetsToRemove.size(); ++i)
204 updateEventHandlerInternal(RemoveAll, handlerClass, targetsToRemove[ i]);
205 }
206 }
207
208 void EventHandlerRegistry::checkConsistency() const
209 {
210 #if ASSERT_ENABLED
211 for (size_t i = 0; i < EventHandlerClassCount; ++i) {
212 EventHandlerClass handlerClass = static_cast<EventHandlerClass>(i);
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 ASSERT(node->document().page());
217 ASSERT(node->document().page() == &m_page);
218 }
219 }
220 }
221 #endif // ASSERT_ENABLED
222 }
223
202 } // namespace WebCore 224 } // namespace WebCore
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698