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