Home | History | Annotate | Download | only in dom
      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/dom/DocumentEventQueue.h"
     29 
     30 #include "core/dom/Document.h"
     31 #include "core/dom/Event.h"
     32 #include "core/dom/EventNames.h"
     33 #include "core/page/DOMWindow.h"
     34 #include "core/page/SuspendableTimer.h"
     35 
     36 namespace WebCore {
     37 
     38 class DocumentEventQueueTimer : public SuspendableTimer {
     39     WTF_MAKE_NONCOPYABLE(DocumentEventQueueTimer);
     40 public:
     41     DocumentEventQueueTimer(DocumentEventQueue* eventQueue, ScriptExecutionContext* context)
     42         : SuspendableTimer(context)
     43         , m_eventQueue(eventQueue) { }
     44 
     45 private:
     46     virtual void fired() { m_eventQueue->pendingEventTimerFired(); }
     47     DocumentEventQueue* m_eventQueue;
     48 };
     49 
     50 PassRefPtr<DocumentEventQueue> DocumentEventQueue::create(ScriptExecutionContext* context)
     51 {
     52     return adoptRef(new DocumentEventQueue(context));
     53 }
     54 
     55 DocumentEventQueue::DocumentEventQueue(ScriptExecutionContext* context)
     56     : m_pendingEventTimer(adoptPtr(new DocumentEventQueueTimer(this, context)))
     57     , m_isClosed(false)
     58 {
     59     m_pendingEventTimer->suspendIfNeeded();
     60 }
     61 
     62 DocumentEventQueue::~DocumentEventQueue()
     63 {
     64 }
     65 
     66 bool DocumentEventQueue::enqueueEvent(PassRefPtr<Event> event)
     67 {
     68     if (m_isClosed)
     69         return false;
     70 
     71     ASSERT(event->target());
     72     bool wasAdded = m_queuedEvents.add(event).isNewEntry;
     73     ASSERT_UNUSED(wasAdded, wasAdded); // It should not have already been in the list.
     74 
     75     if (!m_pendingEventTimer->isActive())
     76         m_pendingEventTimer->startOneShot(0);
     77 
     78     return true;
     79 }
     80 
     81 void DocumentEventQueue::enqueueOrDispatchScrollEvent(PassRefPtr<Node> target, ScrollEventTargetType targetType)
     82 {
     83     if (!target->document()->hasListenerType(Document::SCROLL_LISTENER))
     84         return;
     85 
     86     // Per the W3C CSSOM View Module, scroll events fired at the document should bubble, others should not.
     87     bool canBubble = targetType == ScrollEventDocumentTarget;
     88     RefPtr<Event> scrollEvent = Event::create(eventNames().scrollEvent, canBubble, false /* non cancelleable */);
     89 
     90     if (!m_nodesWithQueuedScrollEvents.add(target.get()).isNewEntry)
     91         return;
     92 
     93     scrollEvent->setTarget(target);
     94     enqueueEvent(scrollEvent.release());
     95 }
     96 
     97 bool DocumentEventQueue::cancelEvent(Event* event)
     98 {
     99     ListHashSet<RefPtr<Event>, 16>::iterator it = m_queuedEvents.find(event);
    100     bool found = it != m_queuedEvents.end();
    101     if (found)
    102         m_queuedEvents.remove(it);
    103     if (m_queuedEvents.isEmpty())
    104         m_pendingEventTimer->stop();
    105     return found;
    106 }
    107 
    108 void DocumentEventQueue::close()
    109 {
    110     m_isClosed = true;
    111     m_pendingEventTimer->stop();
    112     m_queuedEvents.clear();
    113 }
    114 
    115 void DocumentEventQueue::pendingEventTimerFired()
    116 {
    117     ASSERT(!m_pendingEventTimer->isActive());
    118     ASSERT(!m_queuedEvents.isEmpty());
    119 
    120     m_nodesWithQueuedScrollEvents.clear();
    121 
    122     // Insert a marker for where we should stop.
    123     ASSERT(!m_queuedEvents.contains(0));
    124     bool wasAdded = m_queuedEvents.add(0).isNewEntry;
    125     ASSERT_UNUSED(wasAdded, wasAdded); // It should not have already been in the list.
    126 
    127     RefPtr<DocumentEventQueue> protector(this);
    128 
    129     while (!m_queuedEvents.isEmpty()) {
    130         ListHashSet<RefPtr<Event>, 16>::iterator iter = m_queuedEvents.begin();
    131         RefPtr<Event> event = *iter;
    132         m_queuedEvents.remove(iter);
    133         if (!event)
    134             break;
    135         dispatchEvent(event.get());
    136     }
    137 }
    138 
    139 void DocumentEventQueue::dispatchEvent(PassRefPtr<Event> event)
    140 {
    141     EventTarget* eventTarget = event->target();
    142     if (eventTarget->toDOMWindow())
    143         eventTarget->toDOMWindow()->dispatchEvent(event, 0);
    144     else
    145         eventTarget->dispatchEvent(event);
    146 }
    147 
    148 }
    149