OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org) | |
3 * (C) 1999 Antti Koivisto (koivisto@kde.org) | |
4 * (C) 2001 Dirk Mueller (mueller@kde.org) | |
5 * Copyright (C) 2004, 2005, 2006, 2007 Apple Inc. All rights reserved. | |
6 * Copyright (C) 2006 Alexey Proskuryakov (ap@webkit.org) | |
7 * (C) 2007, 2008 Nikolas Zimmermann <zimmermann@kde.org> | |
8 * | |
9 * Redistribution and use in source and binary forms, with or without | |
10 * modification, are permitted provided that the following conditions | |
11 * are met: | |
12 * 1. Redistributions of source code must retain the above copyright | |
13 * notice, this list of conditions and the following disclaimer. | |
14 * 2. Redistributions in binary form must reproduce the above copyright | |
15 * notice, this list of conditions and the following disclaimer in the | |
16 * documentation and/or other materials provided with the distribution. | |
17 * | |
18 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY | |
19 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |
21 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR | |
22 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | |
23 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |
24 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | |
25 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY | |
26 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
29 * | |
30 */ | |
31 | |
32 #include "config.h" | |
33 #include "core/events/EventTarget.h" | |
34 | |
35 #include "RuntimeEnabledFeatures.h" | |
36 #include "bindings/v8/DOMWrapperWorld.h" | |
37 #include "bindings/v8/ExceptionState.h" | |
38 #include "bindings/v8/ScriptController.h" | |
39 #include "core/events/Event.h" | |
40 #include "core/dom/ExceptionCode.h" | |
41 #include "core/inspector/InspectorInstrumentation.h" | |
42 #include "core/page/DOMWindow.h" | |
43 #include "wtf/StdLibExtras.h" | |
44 #include "wtf/Vector.h" | |
45 | |
46 using namespace WTF; | |
47 | |
48 namespace WebCore { | |
49 | |
50 EventTargetData::EventTargetData() | |
51 { | |
52 } | |
53 | |
54 EventTargetData::~EventTargetData() | |
55 { | |
56 } | |
57 | |
58 EventTarget::~EventTarget() | |
59 { | |
60 } | |
61 | |
62 Node* EventTarget::toNode() | |
63 { | |
64 return 0; | |
65 } | |
66 | |
67 DOMWindow* EventTarget::toDOMWindow() | |
68 { | |
69 return 0; | |
70 } | |
71 | |
72 MessagePort* EventTarget::toMessagePort() | |
73 { | |
74 return 0; | |
75 } | |
76 | |
77 inline DOMWindow* EventTarget::executingWindow() | |
78 { | |
79 if (ScriptExecutionContext* context = scriptExecutionContext()) | |
80 return context->executingWindow(); | |
81 return 0; | |
82 } | |
83 | |
84 bool EventTarget::addEventListener(const AtomicString& eventType, PassRefPtr<Eve
ntListener> listener, bool useCapture) | |
85 { | |
86 EventTargetData* d = ensureEventTargetData(); | |
87 return d->eventListenerMap.add(eventType, listener, useCapture); | |
88 } | |
89 | |
90 bool EventTarget::removeEventListener(const AtomicString& eventType, EventListen
er* listener, bool useCapture) | |
91 { | |
92 EventTargetData* d = eventTargetData(); | |
93 if (!d) | |
94 return false; | |
95 | |
96 size_t indexOfRemovedListener; | |
97 | |
98 if (!d->eventListenerMap.remove(eventType, listener, useCapture, indexOfRemo
vedListener)) | |
99 return false; | |
100 | |
101 // Notify firing events planning to invoke the listener at 'index' that | |
102 // they have one less listener to invoke. | |
103 if (!d->firingEventIterators) | |
104 return true; | |
105 for (size_t i = 0; i < d->firingEventIterators->size(); ++i) { | |
106 FiringEventIterator& firingIterator = d->firingEventIterators->at(i); | |
107 if (eventType != firingIterator.eventType) | |
108 continue; | |
109 | |
110 if (indexOfRemovedListener >= firingIterator.end) | |
111 continue; | |
112 | |
113 --firingIterator.end; | |
114 if (indexOfRemovedListener <= firingIterator.iterator) | |
115 --firingIterator.iterator; | |
116 } | |
117 | |
118 return true; | |
119 } | |
120 | |
121 bool EventTarget::setAttributeEventListener(const AtomicString& eventType, PassR
efPtr<EventListener> listener, DOMWrapperWorld* isolatedWorld) | |
122 { | |
123 clearAttributeEventListener(eventType, isolatedWorld); | |
124 if (!listener) | |
125 return false; | |
126 return addEventListener(eventType, listener, false); | |
127 } | |
128 | |
129 EventListener* EventTarget::getAttributeEventListener(const AtomicString& eventT
ype, DOMWrapperWorld* isolatedWorld) | |
130 { | |
131 const EventListenerVector& entry = getEventListeners(eventType); | |
132 for (size_t i = 0; i < entry.size(); ++i) { | |
133 EventListener* listener = entry[i].listener.get(); | |
134 if (listener->isAttribute()) { | |
135 DOMWrapperWorld* listenerWorld = listener->world(); | |
136 // Worker listener | |
137 if (!listenerWorld) { | |
138 ASSERT(!isolatedWorld); | |
139 return listener; | |
140 } | |
141 if (listenerWorld->isMainWorld() && !isolatedWorld) | |
142 return listener; | |
143 if (listenerWorld == isolatedWorld) | |
144 return listener; | |
145 } | |
146 } | |
147 return 0; | |
148 } | |
149 | |
150 bool EventTarget::clearAttributeEventListener(const AtomicString& eventType, DOM
WrapperWorld* isolatedWorld) | |
151 { | |
152 EventListener* listener = getAttributeEventListener(eventType, isolatedWorld
); | |
153 if (!listener) | |
154 return false; | |
155 return removeEventListener(eventType, listener, false); | |
156 } | |
157 | |
158 bool EventTarget::dispatchEvent(PassRefPtr<Event> event, ExceptionState& es) | |
159 { | |
160 if (!event || event->type().isEmpty() || event->isBeingDispatched()) { | |
161 es.throwDOMException(InvalidStateError); | |
162 return false; | |
163 } | |
164 | |
165 if (!scriptExecutionContext()) | |
166 return false; | |
167 | |
168 return dispatchEvent(event); | |
169 } | |
170 | |
171 bool EventTarget::dispatchEvent(PassRefPtr<Event> event) | |
172 { | |
173 event->setTarget(this); | |
174 event->setCurrentTarget(this); | |
175 event->setEventPhase(Event::AT_TARGET); | |
176 bool defaultPrevented = fireEventListeners(event.get()); | |
177 event->setEventPhase(0); | |
178 return defaultPrevented; | |
179 } | |
180 | |
181 void EventTarget::uncaughtExceptionInEventHandler() | |
182 { | |
183 } | |
184 | |
185 static AtomicString legacyType(const Event* event) | |
186 { | |
187 if (event->type() == eventNames().transitionendEvent) | |
188 return eventNames().webkitTransitionEndEvent; | |
189 | |
190 if (event->type() == eventNames().animationstartEvent) | |
191 return eventNames().webkitAnimationStartEvent; | |
192 | |
193 if (event->type() == eventNames().animationendEvent) | |
194 return eventNames().webkitAnimationEndEvent; | |
195 | |
196 if (event->type() == eventNames().animationiterationEvent) | |
197 return eventNames().webkitAnimationIterationEvent; | |
198 | |
199 if (event->type() == eventNames().wheelEvent) | |
200 return eventNames().mousewheelEvent; | |
201 | |
202 return emptyString(); | |
203 } | |
204 | |
205 void EventTarget::countLegacyEvents(const AtomicString& legacyTypeName, EventLis
tenerVector* listenersVector, EventListenerVector* legacyListenersVector) | |
206 { | |
207 UseCounter::Feature unprefixedFeature; | |
208 UseCounter::Feature prefixedFeature; | |
209 UseCounter::Feature prefixedAndUnprefixedFeature; | |
210 bool shouldCount = false; | |
211 | |
212 if (legacyTypeName == eventNames().webkitTransitionEndEvent) { | |
213 prefixedFeature = UseCounter::PrefixedTransitionEndEvent; | |
214 unprefixedFeature = UseCounter::UnprefixedTransitionEndEvent; | |
215 prefixedAndUnprefixedFeature = UseCounter::PrefixedAndUnprefixedTransiti
onEndEvent; | |
216 shouldCount = true; | |
217 } else if (legacyTypeName == eventNames().webkitAnimationEndEvent) { | |
218 prefixedFeature = UseCounter::PrefixedAnimationEndEvent; | |
219 unprefixedFeature = UseCounter::UnprefixedAnimationEndEvent; | |
220 prefixedAndUnprefixedFeature = UseCounter::PrefixedAndUnprefixedAnimatio
nEndEvent; | |
221 shouldCount = true; | |
222 } else if (legacyTypeName == eventNames().webkitAnimationStartEvent) { | |
223 prefixedFeature = UseCounter::PrefixedAnimationStartEvent; | |
224 unprefixedFeature = UseCounter::UnprefixedAnimationStartEvent; | |
225 prefixedAndUnprefixedFeature = UseCounter::PrefixedAndUnprefixedAnimatio
nStartEvent; | |
226 shouldCount = true; | |
227 } else if (legacyTypeName == eventNames().webkitAnimationIterationEvent) { | |
228 prefixedFeature = UseCounter::PrefixedAnimationIterationEvent; | |
229 unprefixedFeature = UseCounter::UnprefixedAnimationIterationEvent; | |
230 prefixedAndUnprefixedFeature = UseCounter::PrefixedAndUnprefixedAnimatio
nIterationEvent; | |
231 shouldCount = true; | |
232 } | |
233 | |
234 if (shouldCount) { | |
235 if (DOMWindow* executingWindow = this->executingWindow()) { | |
236 if (legacyListenersVector) { | |
237 if (listenersVector) | |
238 UseCounter::count(executingWindow, prefixedAndUnprefixedFeat
ure); | |
239 else | |
240 UseCounter::count(executingWindow, prefixedFeature); | |
241 } else if (listenersVector) { | |
242 UseCounter::count(executingWindow, unprefixedFeature); | |
243 } | |
244 } | |
245 } | |
246 } | |
247 | |
248 bool EventTarget::fireEventListeners(Event* event) | |
249 { | |
250 ASSERT(!NoEventDispatchAssertion::isEventDispatchForbidden()); | |
251 ASSERT(event && !event->type().isEmpty()); | |
252 | |
253 EventTargetData* d = eventTargetData(); | |
254 if (!d) | |
255 return true; | |
256 | |
257 EventListenerVector* legacyListenersVector = 0; | |
258 AtomicString legacyTypeName = legacyType(event); | |
259 if (!legacyTypeName.isEmpty()) | |
260 legacyListenersVector = d->eventListenerMap.find(legacyTypeName); | |
261 | |
262 EventListenerVector* listenersVector = d->eventListenerMap.find(event->type(
)); | |
263 if (!RuntimeEnabledFeatures::cssAnimationUnprefixedEnabled() && (event->type
() == eventNames().animationiterationEvent || event->type() == eventNames().anim
ationendEvent | |
264 || event->type() == eventNames().animationstartEvent)) | |
265 listenersVector = 0; | |
266 | |
267 if (listenersVector) { | |
268 fireEventListeners(event, d, *listenersVector); | |
269 } else if (legacyListenersVector) { | |
270 AtomicString unprefixedTypeName = event->type(); | |
271 event->setType(legacyTypeName); | |
272 fireEventListeners(event, d, *legacyListenersVector); | |
273 event->setType(unprefixedTypeName); | |
274 } | |
275 | |
276 countLegacyEvents(legacyTypeName, listenersVector, legacyListenersVector); | |
277 return !event->defaultPrevented(); | |
278 } | |
279 | |
280 void EventTarget::fireEventListeners(Event* event, EventTargetData* d, EventList
enerVector& entry) | |
281 { | |
282 RefPtr<EventTarget> protect = this; | |
283 | |
284 // Fire all listeners registered for this event. Don't fire listeners remove
d | |
285 // during event dispatch. Also, don't fire event listeners added during even
t | |
286 // dispatch. Conveniently, all new event listeners will be added after or at | |
287 // index |size|, so iterating up to (but not including) |size| naturally exc
ludes | |
288 // new event listeners. | |
289 | |
290 if (event->type() == eventNames().beforeunloadEvent) { | |
291 if (DOMWindow* executingWindow = this->executingWindow()) { | |
292 if (executingWindow->top()) | |
293 UseCounter::count(executingWindow, UseCounter::SubFrameBeforeUnl
oadFired); | |
294 } | |
295 } | |
296 | |
297 bool userEventWasHandled = false; | |
298 size_t i = 0; | |
299 size_t size = entry.size(); | |
300 if (!d->firingEventIterators) | |
301 d->firingEventIterators = adoptPtr(new FiringEventIteratorVector); | |
302 d->firingEventIterators->append(FiringEventIterator(event->type(), i, size))
; | |
303 for ( ; i < size; ++i) { | |
304 RegisteredEventListener& registeredListener = entry[i]; | |
305 if (event->eventPhase() == Event::CAPTURING_PHASE && !registeredListener
.useCapture) | |
306 continue; | |
307 if (event->eventPhase() == Event::BUBBLING_PHASE && registeredListener.u
seCapture) | |
308 continue; | |
309 | |
310 // If stopImmediatePropagation has been called, we just break out immedi
ately, without | |
311 // handling any more events on this target. | |
312 if (event->immediatePropagationStopped()) | |
313 break; | |
314 | |
315 ScriptExecutionContext* context = scriptExecutionContext(); | |
316 if (!context) | |
317 break; | |
318 | |
319 InspectorInstrumentationCookie cookie = InspectorInstrumentation::willHa
ndleEvent(context, event); | |
320 // To match Mozilla, the AT_TARGET phase fires both capturing and bubbli
ng | |
321 // event listeners, even though that violates some versions of the DOM s
pec. | |
322 registeredListener.listener->handleEvent(context, event); | |
323 if (!userEventWasHandled && ScriptController::processingUserGesture()) | |
324 userEventWasHandled = true; | |
325 InspectorInstrumentation::didHandleEvent(cookie); | |
326 } | |
327 d->firingEventIterators->removeLast(); | |
328 if (userEventWasHandled) { | |
329 if (ScriptExecutionContext* context = scriptExecutionContext()) | |
330 context->userEventWasHandled(); | |
331 } | |
332 } | |
333 | |
334 const EventListenerVector& EventTarget::getEventListeners(const AtomicString& ev
entType) | |
335 { | |
336 DEFINE_STATIC_LOCAL(EventListenerVector, emptyVector, ()); | |
337 | |
338 EventTargetData* d = eventTargetData(); | |
339 if (!d) | |
340 return emptyVector; | |
341 | |
342 EventListenerVector* listenerVector = d->eventListenerMap.find(eventType); | |
343 if (!listenerVector) | |
344 return emptyVector; | |
345 | |
346 return *listenerVector; | |
347 } | |
348 | |
349 void EventTarget::removeAllEventListeners() | |
350 { | |
351 EventTargetData* d = eventTargetData(); | |
352 if (!d) | |
353 return; | |
354 d->eventListenerMap.clear(); | |
355 | |
356 // Notify firing events planning to invoke the listener at 'index' that | |
357 // they have one less listener to invoke. | |
358 if (d->firingEventIterators) { | |
359 for (size_t i = 0; i < d->firingEventIterators->size(); ++i) { | |
360 d->firingEventIterators->at(i).iterator = 0; | |
361 d->firingEventIterators->at(i).end = 0; | |
362 } | |
363 } | |
364 } | |
365 | |
366 } // namespace WebCore | |
OLD | NEW |