Home | History | Annotate | Download | only in events
      1 /*
      2  * Copyright (C) 1999 Lars Knoll (knoll (at) kde.org)
      3  *           (C) 1999 Antti Koivisto (koivisto (at) kde.org)
      4  *           (C) 2001 Dirk Mueller (mueller (at) kde.org)
      5  * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
      6  * Copyright (C) 2006 Alexey Proskuryakov (ap (at) webkit.org)
      7  *           (C) 2007, 2008 Nikolas Zimmermann <zimmermann (at) 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 #ifndef EventTarget_h
     33 #define EventTarget_h
     34 
     35 #include "bindings/core/v8/ScriptWrappable.h"
     36 #include "core/events/EventListenerMap.h"
     37 #include "core/events/ThreadLocalEventNames.h"
     38 #include "platform/heap/Handle.h"
     39 
     40 namespace blink {
     41 
     42 class LocalDOMWindow;
     43 class Event;
     44 class ExceptionState;
     45 class MessagePort;
     46 class Node;
     47 class TextTrack;
     48 class TextTrackCue;
     49 class XMLHttpRequest;
     50 class XMLHttpRequestUpload;
     51 
     52 struct FiringEventIterator {
     53     FiringEventIterator(const AtomicString& eventType, size_t& iterator, size_t& end)
     54         : eventType(eventType)
     55         , iterator(iterator)
     56         , end(end)
     57     {
     58     }
     59 
     60     const AtomicString& eventType;
     61     size_t& iterator;
     62     size_t& end;
     63 };
     64 typedef Vector<FiringEventIterator, 1> FiringEventIteratorVector;
     65 
     66 struct EventTargetData {
     67     WTF_MAKE_NONCOPYABLE(EventTargetData); WTF_MAKE_FAST_ALLOCATED;
     68 public:
     69     EventTargetData();
     70     ~EventTargetData();
     71 
     72     EventListenerMap eventListenerMap;
     73     OwnPtr<FiringEventIteratorVector> firingEventIterators;
     74 };
     75 
     76 // This is the base class for all DOM event targets. To make your class an
     77 // EventTarget, follow these steps:
     78 // - Make your IDL interface inherit from EventTarget.
     79 //   Optionally add "attribute EventHandler onfoo;" attributes.
     80 // - Inherit from EventTargetWithInlineData (only in rare cases should you use
     81 //   EventTarget directly).
     82 // - Figure out if you now need to inherit from ActiveDOMObject as well.
     83 // - In your class declaration, you will typically use
     84 //   REFCOUNTED_EVENT_TARGET(YourClassName) and
     85 //   WILL_BE_USING_GARBAGE_COLLECTED_MIXIN(YourClassName). Make sure to include
     86 //   this header file in your .h file, or you will get very strange compiler
     87 //   errors.
     88 // - If you added an onfoo attribute, use DEFINE_ATTRIBUTE_EVENT_LISTENER(foo)
     89 //   in your class declaration.
     90 // - Override EventTarget::interfaceName() and executionContext(). The former
     91 //   will typically return EventTargetNames::YourClassName. The latter will
     92 //   return ActiveDOMObject::executionContext (if you are an ActiveDOMObject)
     93 //   or the document you're in.
     94 // - Your trace() method will need to call EventTargetWithInlineData::trace.
     95 //
     96 // Optionally, add a FooEvent.idl class, but that's outside the scope of this
     97 // comment (and much more straightforward).
     98 class EventTarget : public WillBeGarbageCollectedMixin, public ScriptWrappable {
     99     DEFINE_WRAPPERTYPEINFO();
    100 public:
    101 #if !ENABLE(OILPAN)
    102     void ref() { refEventTarget(); }
    103     void deref() { derefEventTarget(); }
    104 #endif
    105 
    106     virtual const AtomicString& interfaceName() const = 0;
    107     virtual ExecutionContext* executionContext() const = 0;
    108 
    109     virtual Node* toNode();
    110     virtual LocalDOMWindow* toDOMWindow();
    111     virtual MessagePort* toMessagePort();
    112 
    113     // FIXME: first 2 args to addEventListener and removeEventListener should
    114     // be required (per spec), but throwing TypeError breaks legacy content.
    115     // http://crbug.com/353484
    116     bool addEventListener() { return false; }
    117     bool addEventListener(const AtomicString& eventType) { return false; }
    118     virtual bool addEventListener(const AtomicString& eventType, PassRefPtr<EventListener>, bool useCapture = false);
    119     bool removeEventListener() { return false; }
    120     bool removeEventListener(const AtomicString& eventType) { return false; }
    121     virtual bool removeEventListener(const AtomicString& eventType, PassRefPtr<EventListener>, bool useCapture = false);
    122     virtual void removeAllEventListeners();
    123     virtual bool dispatchEvent(PassRefPtrWillBeRawPtr<Event>);
    124     bool dispatchEvent(PassRefPtrWillBeRawPtr<Event>, ExceptionState&); // DOM API
    125     virtual void uncaughtExceptionInEventHandler();
    126 
    127     // Used for legacy "onEvent" attribute APIs.
    128     bool setAttributeEventListener(const AtomicString& eventType, PassRefPtr<EventListener>);
    129     EventListener* getAttributeEventListener(const AtomicString& eventType);
    130 
    131     bool hasEventListeners() const;
    132     bool hasEventListeners(const AtomicString& eventType) const;
    133     bool hasCapturingEventListeners(const AtomicString& eventType);
    134     const EventListenerVector& getEventListeners(const AtomicString& eventType);
    135     Vector<AtomicString> eventTypes();
    136 
    137     bool fireEventListeners(Event*);
    138 
    139     virtual void trace(Visitor*) { }
    140 
    141     virtual bool keepEventInNode(Event*) { return false; };
    142 
    143 protected:
    144     EventTarget();
    145     virtual ~EventTarget();
    146 
    147     // Subclasses should likely not override these themselves; instead, they should subclass EventTargetWithInlineData.
    148     virtual EventTargetData* eventTargetData() = 0;
    149     virtual EventTargetData& ensureEventTargetData() = 0;
    150 
    151 private:
    152 #if !ENABLE(OILPAN)
    153     // Subclasses should likely not override these themselves; instead, they should use the REFCOUNTED_EVENT_TARGET() macro.
    154     virtual void refEventTarget() = 0;
    155     virtual void derefEventTarget() = 0;
    156 #endif
    157 
    158     LocalDOMWindow* executingWindow();
    159     void fireEventListeners(Event*, EventTargetData*, EventListenerVector&);
    160     void countLegacyEvents(const AtomicString& legacyTypeName, EventListenerVector*, EventListenerVector*);
    161 
    162     bool clearAttributeEventListener(const AtomicString& eventType);
    163 
    164     friend class EventListenerIterator;
    165 };
    166 
    167 class EventTargetWithInlineData : public EventTarget {
    168 protected:
    169     virtual EventTargetData* eventTargetData() OVERRIDE FINAL { return &m_eventTargetData; }
    170     virtual EventTargetData& ensureEventTargetData() OVERRIDE FINAL { return m_eventTargetData; }
    171 private:
    172     EventTargetData m_eventTargetData;
    173 };
    174 
    175 // FIXME: These macros should be split into separate DEFINE and DECLARE
    176 // macros to avoid causing so many header includes.
    177 #define DEFINE_ATTRIBUTE_EVENT_LISTENER(attribute) \
    178     EventListener* on##attribute() { return getAttributeEventListener(EventTypeNames::attribute); } \
    179     void setOn##attribute(PassRefPtr<EventListener> listener) { setAttributeEventListener(EventTypeNames::attribute, listener); } \
    180 
    181 #define DEFINE_STATIC_ATTRIBUTE_EVENT_LISTENER(attribute) \
    182     static EventListener* on##attribute(EventTarget& eventTarget) { return eventTarget.getAttributeEventListener(EventTypeNames::attribute); } \
    183     static void setOn##attribute(EventTarget& eventTarget, PassRefPtr<EventListener> listener) { eventTarget.setAttributeEventListener(EventTypeNames::attribute, listener); } \
    184 
    185 #define DEFINE_WINDOW_ATTRIBUTE_EVENT_LISTENER(attribute) \
    186     EventListener* on##attribute() { return document().getWindowAttributeEventListener(EventTypeNames::attribute); } \
    187     void setOn##attribute(PassRefPtr<EventListener> listener) { document().setWindowAttributeEventListener(EventTypeNames::attribute, listener); } \
    188 
    189 #define DEFINE_STATIC_WINDOW_ATTRIBUTE_EVENT_LISTENER(attribute) \
    190     static EventListener* on##attribute(EventTarget& eventTarget) { \
    191         if (Node* node = eventTarget.toNode()) \
    192             return node->document().getWindowAttributeEventListener(EventTypeNames::attribute); \
    193         ASSERT(eventTarget.toDOMWindow()); \
    194         return eventTarget.getAttributeEventListener(EventTypeNames::attribute); \
    195     } \
    196     static void setOn##attribute(EventTarget& eventTarget, PassRefPtr<EventListener> listener) { \
    197         if (Node* node = eventTarget.toNode()) \
    198             node->document().setWindowAttributeEventListener(EventTypeNames::attribute, listener); \
    199         else { \
    200             ASSERT(eventTarget.toDOMWindow()); \
    201             eventTarget.setAttributeEventListener(EventTypeNames::attribute, listener); \
    202         } \
    203     }
    204 
    205 #define DEFINE_MAPPED_ATTRIBUTE_EVENT_LISTENER(attribute, eventName) \
    206     EventListener* on##attribute() { return getAttributeEventListener(EventTypeNames::eventName); } \
    207     void setOn##attribute(PassRefPtr<EventListener> listener) { setAttributeEventListener(EventTypeNames::eventName, listener); } \
    208 
    209 #define DECLARE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(recipient, attribute) \
    210     EventListener* on##attribute(); \
    211     void setOn##attribute(PassRefPtr<EventListener> listener);
    212 
    213 #define DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(type, recipient, attribute) \
    214     EventListener* type::on##attribute() { return recipient ? recipient->getAttributeEventListener(EventTypeNames::attribute) : 0; } \
    215     void type::setOn##attribute(PassRefPtr<EventListener> listener) \
    216     { \
    217         if (recipient) \
    218             recipient->setAttributeEventListener(EventTypeNames::attribute, listener); \
    219     }
    220 
    221 inline bool EventTarget::hasEventListeners() const
    222 {
    223     // FIXME: We should have a const version of eventTargetData.
    224     if (const EventTargetData* d = const_cast<EventTarget*>(this)->eventTargetData())
    225         return !d->eventListenerMap.isEmpty();
    226     return false;
    227 }
    228 
    229 inline bool EventTarget::hasEventListeners(const AtomicString& eventType) const
    230 {
    231     // FIXME: We should have const version of eventTargetData.
    232     if (const EventTargetData* d = const_cast<EventTarget*>(this)->eventTargetData())
    233         return d->eventListenerMap.contains(eventType);
    234     return false;
    235 }
    236 
    237 inline bool EventTarget::hasCapturingEventListeners(const AtomicString& eventType)
    238 {
    239     EventTargetData* d = eventTargetData();
    240     if (!d)
    241         return false;
    242     return d->eventListenerMap.containsCapturing(eventType);
    243 }
    244 
    245 } // namespace blink
    246 
    247 #if ENABLE(OILPAN)
    248 #define DEFINE_EVENT_TARGET_REFCOUNTING(baseClass) \
    249 public: \
    250     using baseClass::ref; \
    251     using baseClass::deref; \
    252 private: \
    253     typedef int thisIsHereToForceASemiColonAfterThisEventTargetMacro
    254 #define DEFINE_EVENT_TARGET_REFCOUNTING_WILL_BE_REMOVED(baseClass)
    255 #else
    256 #define DEFINE_EVENT_TARGET_REFCOUNTING(baseClass) \
    257 public: \
    258     using baseClass::ref; \
    259     using baseClass::deref; \
    260 private: \
    261     virtual void refEventTarget() OVERRIDE FINAL { ref(); } \
    262     virtual void derefEventTarget() OVERRIDE FINAL { deref(); } \
    263     typedef int thisIsHereToForceASemiColonAfterThisEventTargetMacro
    264 #define DEFINE_EVENT_TARGET_REFCOUNTING_WILL_BE_REMOVED(baseClass) DEFINE_EVENT_TARGET_REFCOUNTING(baseClass)
    265 #endif
    266 
    267 // Use this macro if your EventTarget subclass is also a subclass of WTF::RefCounted.
    268 // A ref-counted class that uses a different method of refcounting should use DEFINE_EVENT_TARGET_REFCOUNTING directly.
    269 // Both of these macros are meant to be placed just before the "public:" section of the class declaration.
    270 #define REFCOUNTED_EVENT_TARGET(className) DEFINE_EVENT_TARGET_REFCOUNTING_WILL_BE_REMOVED(RefCounted<className>)
    271 
    272 #endif // EventTarget_h
    273