Home | History | Annotate | Download | only in frame
      1 // Copyright 2014 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "config.h"
      6 #include "core/frame/EventHandlerRegistry.h"
      7 
      8 #include "core/events/ThreadLocalEventNames.h"
      9 #include "core/frame/LocalDOMWindow.h"
     10 #include "core/frame/LocalFrame.h"
     11 #include "core/html/HTMLFrameOwnerElement.h"
     12 #include "core/page/Page.h"
     13 #include "core/page/scrolling/ScrollingCoordinator.h"
     14 
     15 namespace WebCore {
     16 
     17 EventHandlerRegistry::EventHandlerRegistry(FrameHost& frameHost)
     18     : m_frameHost(frameHost)
     19 {
     20 }
     21 
     22 EventHandlerRegistry::~EventHandlerRegistry()
     23 {
     24     checkConsistency();
     25 }
     26 
     27 bool EventHandlerRegistry::eventTypeToClass(const AtomicString& eventType, EventHandlerClass* result)
     28 {
     29     if (eventType == EventTypeNames::scroll) {
     30         *result = ScrollEvent;
     31     } else if (eventType == EventTypeNames::wheel || eventType == EventTypeNames::mousewheel) {
     32         *result = WheelEvent;
     33 #if ASSERT_ENABLED
     34     } else if (eventType == EventTypeNames::load || eventType == EventTypeNames::mousemove || eventType == EventTypeNames::touchstart) {
     35         *result = EventsForTesting;
     36 #endif
     37     } else {
     38         return false;
     39     }
     40     return true;
     41 }
     42 
     43 const EventTargetSet* EventHandlerRegistry::eventHandlerTargets(EventHandlerClass handlerClass) const
     44 {
     45     checkConsistency();
     46     return &m_targets[handlerClass];
     47 }
     48 
     49 bool EventHandlerRegistry::hasEventHandlers(EventHandlerClass handlerClass) const
     50 {
     51     return m_targets[handlerClass].size();
     52 }
     53 
     54 bool EventHandlerRegistry::updateEventHandlerTargets(ChangeOperation op, EventHandlerClass handlerClass, EventTarget* target)
     55 {
     56     EventTargetSet* targets = &m_targets[handlerClass];
     57     if (op == Add) {
     58         if (!targets->add(target).isNewEntry) {
     59             // Just incremented refcount, no real change.
     60             return false;
     61         }
     62     } else {
     63         ASSERT(op == Remove || op == RemoveAll);
     64         ASSERT(op == RemoveAll || targets->contains(target));
     65 
     66         if (op == RemoveAll) {
     67             if (!targets->contains(target))
     68                 return false;
     69             targets->removeAll(target);
     70         } else {
     71             if (!targets->remove(target)) {
     72                 // Just decremented refcount, no real update.
     73                 return false;
     74             }
     75         }
     76     }
     77     return true;
     78 }
     79 
     80 void EventHandlerRegistry::updateEventHandlerInternal(ChangeOperation op, EventHandlerClass handlerClass, EventTarget* target)
     81 {
     82     bool hadHandlers = hasEventHandlers(handlerClass);
     83     updateEventHandlerTargets(op, handlerClass, target);
     84     bool hasHandlers = hasEventHandlers(handlerClass);
     85 
     86     if (hadHandlers != hasHandlers) {
     87         notifyHasHandlersChanged(handlerClass, hasHandlers);
     88     }
     89     checkConsistency();
     90 }
     91 
     92 void EventHandlerRegistry::updateEventHandlerOfType(ChangeOperation op, const AtomicString& eventType, EventTarget* target)
     93 {
     94     EventHandlerClass handlerClass;
     95     if (!eventTypeToClass(eventType, &handlerClass))
     96         return;
     97     updateEventHandlerInternal(op, handlerClass, target);
     98 }
     99 
    100 void EventHandlerRegistry::didAddEventHandler(EventTarget& target, const AtomicString& eventType)
    101 {
    102     updateEventHandlerOfType(Add, eventType, &target);
    103 }
    104 
    105 void EventHandlerRegistry::didRemoveEventHandler(EventTarget& target, const AtomicString& eventType)
    106 {
    107     updateEventHandlerOfType(Remove, eventType, &target);
    108 }
    109 
    110 void EventHandlerRegistry::didAddEventHandler(EventTarget& target, EventHandlerClass handlerClass)
    111 {
    112     updateEventHandlerInternal(Add, handlerClass, &target);
    113 }
    114 
    115 void EventHandlerRegistry::didRemoveEventHandler(EventTarget& target, EventHandlerClass handlerClass)
    116 {
    117     updateEventHandlerInternal(Remove, handlerClass, &target);
    118 }
    119 
    120 void EventHandlerRegistry::didMoveIntoFrameHost(EventTarget& target)
    121 {
    122     updateAllEventHandlers(Add, target);
    123 }
    124 
    125 void EventHandlerRegistry::didMoveOutOfFrameHost(EventTarget& target)
    126 {
    127     updateAllEventHandlers(RemoveAll, target);
    128 }
    129 
    130 void EventHandlerRegistry::didRemoveAllEventHandlers(EventTarget& target)
    131 {
    132     for (size_t i = 0; i < EventHandlerClassCount; ++i) {
    133         EventHandlerClass handlerClass = static_cast<EventHandlerClass>(i);
    134         updateEventHandlerInternal(RemoveAll, handlerClass, &target);
    135     }
    136 }
    137 
    138 void EventHandlerRegistry::updateAllEventHandlers(ChangeOperation op, EventTarget& target)
    139 {
    140     if (!target.hasEventListeners())
    141         return;
    142 
    143     Vector<AtomicString> eventTypes = target.eventTypes();
    144     for (size_t i = 0; i < eventTypes.size(); ++i) {
    145         EventHandlerClass handlerClass;
    146         if (!eventTypeToClass(eventTypes[i], &handlerClass))
    147             continue;
    148         if (op == RemoveAll) {
    149             updateEventHandlerInternal(op, handlerClass, &target);
    150             continue;
    151         }
    152         for (unsigned count = target.getEventListeners(eventTypes[i]).size(); count > 0; --count)
    153             updateEventHandlerInternal(op, handlerClass, &target);
    154     }
    155 }
    156 
    157 void EventHandlerRegistry::notifyHasHandlersChanged(EventHandlerClass handlerClass, bool hasActiveHandlers)
    158 {
    159     ScrollingCoordinator* scrollingCoordinator = m_frameHost.page().scrollingCoordinator();
    160 
    161     switch (handlerClass) {
    162     case ScrollEvent:
    163         if (scrollingCoordinator)
    164             scrollingCoordinator->updateHaveScrollEventHandlers();
    165         break;
    166     case WheelEvent:
    167         if (scrollingCoordinator)
    168             scrollingCoordinator->updateHaveWheelEventHandlers();
    169         break;
    170 #if ASSERT_ENABLED
    171     case EventsForTesting:
    172         break;
    173 #endif
    174     default:
    175         ASSERT_NOT_REACHED();
    176         break;
    177     }
    178 }
    179 
    180 void EventHandlerRegistry::trace(Visitor* visitor)
    181 {
    182     visitor->registerWeakMembers<EventHandlerRegistry, &EventHandlerRegistry::clearWeakMembers>(this);
    183 }
    184 
    185 void EventHandlerRegistry::clearWeakMembers(Visitor* visitor)
    186 {
    187     Vector<EventTarget*> deadTargets;
    188     for (size_t i = 0; i < EventHandlerClassCount; ++i) {
    189         EventHandlerClass handlerClass = static_cast<EventHandlerClass>(i);
    190         const EventTargetSet* targets = &m_targets[handlerClass];
    191         for (EventTargetSet::const_iterator it = targets->begin(); it != targets->end(); ++it) {
    192             Node* node = it->key->toNode();
    193             LocalDOMWindow* window = it->key->toDOMWindow();
    194             if (node && !visitor->isAlive(node)) {
    195                 deadTargets.append(node);
    196             } else if (window && !visitor->isAlive(window)) {
    197                 deadTargets.append(window);
    198             }
    199         }
    200     }
    201     for (size_t i = 0; i < deadTargets.size(); ++i)
    202         didRemoveAllEventHandlers(*deadTargets[i]);
    203 }
    204 
    205 void EventHandlerRegistry::documentDetached(Document& document)
    206 {
    207     // Remove all event targets under the detached document.
    208     for (size_t handlerClassIndex = 0; handlerClassIndex < EventHandlerClassCount; ++handlerClassIndex) {
    209         EventHandlerClass handlerClass = static_cast<EventHandlerClass>(handlerClassIndex);
    210         Vector<EventTarget*> targetsToRemove;
    211         const EventTargetSet* targets = &m_targets[handlerClass];
    212         for (EventTargetSet::const_iterator iter = targets->begin(); iter != targets->end(); ++iter) {
    213             if (Node* node = iter->key->toNode()) {
    214                 for (Document* doc = &node->document(); doc; doc = doc->ownerElement() ? &doc->ownerElement()->document() : 0) {
    215                     if (doc == &document) {
    216                         targetsToRemove.append(iter->key);
    217                         break;
    218                     }
    219                 }
    220             } else if (iter->key->toDOMWindow()) {
    221                 // DOMWindows may outlive their documents, so we shouldn't remove their handlers
    222                 // here.
    223             } else {
    224                 ASSERT_NOT_REACHED();
    225             }
    226         }
    227         for (size_t i = 0; i < targetsToRemove.size(); ++i)
    228             updateEventHandlerInternal(RemoveAll, handlerClass, targetsToRemove[i]);
    229     }
    230 }
    231 
    232 void EventHandlerRegistry::checkConsistency() const
    233 {
    234 #if ASSERT_ENABLED
    235     for (size_t i = 0; i < EventHandlerClassCount; ++i) {
    236         EventHandlerClass handlerClass = static_cast<EventHandlerClass>(i);
    237         const EventTargetSet* targets = &m_targets[handlerClass];
    238         for (EventTargetSet::const_iterator iter = targets->begin(); iter != targets->end(); ++iter) {
    239             if (Node* node = iter->key->toNode()) {
    240                 // See the comment for |documentDetached| if either of these assertions fails.
    241                 ASSERT(node->document().frameHost());
    242                 ASSERT(node->document().frameHost() == &m_frameHost);
    243             } else if (LocalDOMWindow* window = iter->key->toDOMWindow()) {
    244                 // If any of these assertions fail, LocalDOMWindow failed to unregister its handlers
    245                 // properly.
    246                 ASSERT(window->frame());
    247                 ASSERT(window->frame()->host());
    248                 ASSERT(window->frame()->host() == &m_frameHost);
    249             }
    250         }
    251     }
    252 #endif // ASSERT_ENABLED
    253 }
    254 
    255 } // namespace WebCore
    256