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/events/Event.h" 31 #include "core/frame/LocalDOMWindow.h" 32 #include "core/frame/SuspendableTimer.h" 33 #include "core/inspector/InspectorInstrumentation.h" 34 35 namespace blink { 36 37 class DOMWindowEventQueueTimer : public NoBaseWillBeGarbageCollectedFinalized<DOMWindowEventQueueTimer>, public SuspendableTimer { 38 WTF_MAKE_NONCOPYABLE(DOMWindowEventQueueTimer); 39 public: 40 DOMWindowEventQueueTimer(DOMWindowEventQueue* eventQueue, ExecutionContext* context) 41 : SuspendableTimer(context) 42 , m_eventQueue(eventQueue) { } 43 void trace(Visitor* visitor) { visitor->trace(m_eventQueue); } 44 45 private: 46 virtual void fired() { m_eventQueue->pendingEventTimerFired(); } 47 48 RawPtrWillBeMember<DOMWindowEventQueue> m_eventQueue; 49 }; 50 51 PassRefPtrWillBeRawPtr<DOMWindowEventQueue> DOMWindowEventQueue::create(ExecutionContext* context) 52 { 53 return adoptRefWillBeNoop(new DOMWindowEventQueue(context)); 54 } 55 56 DOMWindowEventQueue::DOMWindowEventQueue(ExecutionContext* context) 57 : m_pendingEventTimer(adoptPtrWillBeNoop(new DOMWindowEventQueueTimer(this, context))) 58 , m_isClosed(false) 59 { 60 m_pendingEventTimer->suspendIfNeeded(); 61 } 62 63 DOMWindowEventQueue::~DOMWindowEventQueue() 64 { 65 } 66 67 void DOMWindowEventQueue::trace(Visitor* visitor) 68 { 69 #if ENABLE(OILPAN) 70 visitor->trace(m_pendingEventTimer); 71 visitor->trace(m_queuedEvents); 72 #endif 73 EventQueue::trace(visitor); 74 } 75 76 bool DOMWindowEventQueue::enqueueEvent(PassRefPtrWillBeRawPtr<Event> event) 77 { 78 if (m_isClosed) 79 return false; 80 81 ASSERT(event->target()); 82 InspectorInstrumentation::didEnqueueEvent(event->target(), event.get()); 83 84 bool wasAdded = m_queuedEvents.add(event).isNewEntry; 85 ASSERT_UNUSED(wasAdded, wasAdded); // It should not have already been in the list. 86 87 if (!m_pendingEventTimer->isActive()) 88 m_pendingEventTimer->startOneShot(0, FROM_HERE); 89 90 return true; 91 } 92 93 bool DOMWindowEventQueue::cancelEvent(Event* event) 94 { 95 WillBeHeapListHashSet<RefPtrWillBeMember<Event>, 16>::iterator it = m_queuedEvents.find(event); 96 bool found = it != m_queuedEvents.end(); 97 if (found) { 98 InspectorInstrumentation::didRemoveEvent(event->target(), event); 99 m_queuedEvents.remove(it); 100 } 101 if (m_queuedEvents.isEmpty()) 102 m_pendingEventTimer->stop(); 103 return found; 104 } 105 106 void DOMWindowEventQueue::close() 107 { 108 m_isClosed = true; 109 m_pendingEventTimer->stop(); 110 if (InspectorInstrumentation::hasFrontends()) { 111 WillBeHeapListHashSet<RefPtrWillBeMember<Event>, 16>::iterator it = m_queuedEvents.begin(); 112 for (; it != m_queuedEvents.end(); ++it) { 113 RefPtrWillBeRawPtr<Event> event = *it; 114 if (event) 115 InspectorInstrumentation::didRemoveEvent(event->target(), event.get()); 116 } 117 } 118 m_queuedEvents.clear(); 119 } 120 121 void DOMWindowEventQueue::pendingEventTimerFired() 122 { 123 ASSERT(!m_pendingEventTimer->isActive()); 124 ASSERT(!m_queuedEvents.isEmpty()); 125 126 // Insert a marker for where we should stop. 127 ASSERT(!m_queuedEvents.contains(nullptr)); 128 bool wasAdded = m_queuedEvents.add(nullptr).isNewEntry; 129 ASSERT_UNUSED(wasAdded, wasAdded); // It should not have already been in the list. 130 131 RefPtrWillBeRawPtr<DOMWindowEventQueue> protector(this); 132 133 while (!m_queuedEvents.isEmpty()) { 134 WillBeHeapListHashSet<RefPtrWillBeMember<Event>, 16>::iterator iter = m_queuedEvents.begin(); 135 RefPtrWillBeRawPtr<Event> event = *iter; 136 m_queuedEvents.remove(iter); 137 if (!event) 138 break; 139 dispatchEvent(event.get()); 140 InspectorInstrumentation::didRemoveEvent(event->target(), event.get()); 141 } 142 } 143 144 void DOMWindowEventQueue::dispatchEvent(PassRefPtrWillBeRawPtr<Event> event) 145 { 146 EventTarget* eventTarget = event->target(); 147 if (eventTarget->toDOMWindow()) 148 eventTarget->toDOMWindow()->dispatchEvent(event, nullptr); 149 else 150 eventTarget->dispatchEvent(event); 151 } 152 153 } 154