1 /* 2 * Copyright (C) 2010 Google Inc. All Rights Reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 * 25 */ 26 27 #include "config.h" 28 #include "core/events/DOMWindowEventQueue.h" 29 30 #include "core/dom/Document.h" 31 #include "core/events/Event.h" 32 #include "core/frame/LocalDOMWindow.h" 33 #include "core/frame/SuspendableTimer.h" 34 #include "core/inspector/InspectorInstrumentation.h" 35 36 namespace WebCore { 37 38 class DOMWindowEventQueueTimer : public NoBaseWillBeGarbageCollectedFinalized<DOMWindowEventQueueTimer>, public SuspendableTimer { 39 WTF_MAKE_NONCOPYABLE(DOMWindowEventQueueTimer); 40 public: 41 DOMWindowEventQueueTimer(DOMWindowEventQueue* eventQueue, ExecutionContext* context) 42 : SuspendableTimer(context) 43 , m_eventQueue(eventQueue) { } 44 void trace(Visitor* visitor) { visitor->trace(m_eventQueue); } 45 46 private: 47 virtual void fired() { m_eventQueue->pendingEventTimerFired(); } 48 49 RawPtrWillBeMember<DOMWindowEventQueue> m_eventQueue; 50 }; 51 52 PassRefPtrWillBeRawPtr<DOMWindowEventQueue> DOMWindowEventQueue::create(ExecutionContext* context) 53 { 54 return adoptRefWillBeNoop(new DOMWindowEventQueue(context)); 55 } 56 57 DOMWindowEventQueue::DOMWindowEventQueue(ExecutionContext* context) 58 : m_pendingEventTimer(adoptPtrWillBeNoop(new DOMWindowEventQueueTimer(this, context))) 59 , m_isClosed(false) 60 { 61 m_pendingEventTimer->suspendIfNeeded(); 62 } 63 64 DOMWindowEventQueue::~DOMWindowEventQueue() 65 { 66 } 67 68 void DOMWindowEventQueue::trace(Visitor* visitor) 69 { 70 visitor->trace(m_pendingEventTimer); 71 visitor->trace(m_queuedEvents); 72 EventQueue::trace(visitor); 73 } 74 75 bool DOMWindowEventQueue::enqueueEvent(PassRefPtrWillBeRawPtr<Event> event) 76 { 77 if (m_isClosed) 78 return false; 79 80 ASSERT(event->target()); 81 InspectorInstrumentation::didEnqueueEvent(event->target(), event.get()); 82 83 bool wasAdded = m_queuedEvents.add(event).isNewEntry; 84 ASSERT_UNUSED(wasAdded, wasAdded); // It should not have already been in the list. 85 86 if (!m_pendingEventTimer->isActive()) 87 m_pendingEventTimer->startOneShot(0, FROM_HERE); 88 89 return true; 90 } 91 92 bool DOMWindowEventQueue::cancelEvent(Event* event) 93 { 94 WillBeHeapListHashSet<RefPtrWillBeMember<Event>, 16>::iterator it = m_queuedEvents.find(event); 95 bool found = it != m_queuedEvents.end(); 96 if (found) { 97 InspectorInstrumentation::didRemoveEvent(event->target(), event); 98 m_queuedEvents.remove(it); 99 } 100 if (m_queuedEvents.isEmpty()) 101 m_pendingEventTimer->stop(); 102 return found; 103 } 104 105 void DOMWindowEventQueue::close() 106 { 107 m_isClosed = true; 108 m_pendingEventTimer->stop(); 109 if (InspectorInstrumentation::hasFrontends()) { 110 WillBeHeapListHashSet<RefPtrWillBeMember<Event>, 16>::iterator it = m_queuedEvents.begin(); 111 for (; it != m_queuedEvents.end(); ++it) 112 InspectorInstrumentation::didRemoveEvent((*it)->target(), it->get()); 113 } 114 m_queuedEvents.clear(); 115 } 116 117 void DOMWindowEventQueue::pendingEventTimerFired() 118 { 119 ASSERT(!m_pendingEventTimer->isActive()); 120 ASSERT(!m_queuedEvents.isEmpty()); 121 122 // Insert a marker for where we should stop. 123 ASSERT(!m_queuedEvents.contains(nullptr)); 124 bool wasAdded = m_queuedEvents.add(nullptr).isNewEntry; 125 ASSERT_UNUSED(wasAdded, wasAdded); // It should not have already been in the list. 126 127 RefPtrWillBeRawPtr<DOMWindowEventQueue> protector(this); 128 129 while (!m_queuedEvents.isEmpty()) { 130 WillBeHeapListHashSet<RefPtrWillBeMember<Event>, 16>::iterator iter = m_queuedEvents.begin(); 131 RefPtrWillBeRawPtr<Event> event = *iter; 132 m_queuedEvents.remove(iter); 133 if (!event) 134 break; 135 dispatchEvent(event.get()); 136 InspectorInstrumentation::didRemoveEvent(event->target(), event.get()); 137 } 138 } 139 140 void DOMWindowEventQueue::dispatchEvent(PassRefPtrWillBeRawPtr<Event> event) 141 { 142 EventTarget* eventTarget = event->target(); 143 if (eventTarget->toDOMWindow()) 144 eventTarget->toDOMWindow()->dispatchEvent(event, nullptr); 145 else 146 eventTarget->dispatchEvent(event); 147 } 148 149 } 150