Index: Source/core/dom/EventHandlerRegistry.cpp |
diff --git a/Source/core/dom/EventHandlerRegistry.cpp b/Source/core/dom/EventHandlerRegistry.cpp |
new file mode 100644 |
index 0000000000000000000000000000000000000000..9760626631a10fa304862da8c1e805e5fbb80909 |
--- /dev/null |
+++ b/Source/core/dom/EventHandlerRegistry.cpp |
@@ -0,0 +1,242 @@ |
+// Copyright 2014 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+#include "config.h" |
+#include "core/dom/EventHandlerRegistry.h" |
+ |
+#include "core/dom/Document.h" |
+#include "core/events/ThreadLocalEventNames.h" |
+#include "core/events/WheelEvent.h" |
+#include "core/frame/FrameHost.h" |
+#include "core/frame/LocalFrame.h" |
+#include "core/page/Chrome.h" |
+#include "core/page/ChromeClient.h" |
+#include "core/page/Page.h" |
+#include "core/page/scrolling/ScrollingCoordinator.h" |
+ |
+namespace WebCore { |
+ |
+EventHandlerRegistry::EventHandlerRegistry(Document& document) |
+ : DOMWindowLifecycleObserver(document.domWindow()) |
+ , m_scrollEventHandlerCount(0) |
+ , m_wheelEventHandlerCount(0) |
+{ |
+} |
+ |
+EventHandlerRegistry::~EventHandlerRegistry() |
+{ |
+} |
+ |
+const char* EventHandlerRegistry::supplementName() |
+{ |
+ return "EventHandlerRegistry"; |
+} |
+ |
+EventHandlerRegistry* EventHandlerRegistry::from(Document& document) |
+{ |
+ EventHandlerRegistry* controller = static_cast<EventHandlerRegistry*>(DocumentSupplement::from(document, supplementName())); |
+ if (!controller) { |
+ controller = new EventHandlerRegistry(document); |
+ DocumentSupplement::provideTo(document, supplementName(), adoptPtr(controller)); |
+ } |
+ return controller; |
+} |
+ |
+void EventHandlerRegistry::didChangeWheelEventHandlerCount(Document& document, int delta) |
+{ |
+ if (delta < 0) |
+ ASSERT(m_wheelEventHandlerCount > 0); |
+ m_wheelEventHandlerCount += delta; |
+ |
+ Page* page = document.page(); |
+ if (!page) |
+ return; |
+ |
+ LocalFrame* mainFrame = page->mainFrame(); |
+ if (mainFrame) |
+ mainFrame->notifyChromeClientWheelEventHandlerCountChanged(); |
+ |
+ ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator(); |
+ if (!scrollingCoordinator) |
+ return; |
+ |
+ FrameView* frameView = document.view(); |
+ if (!frameView) |
+ return; |
+ |
+ scrollingCoordinator->frameViewWheelEventHandlerCountChanged(frameView); |
+} |
+ |
+void EventHandlerRegistry::didChangeScrollEventHandlerCount(Document& document, int delta) |
+{ |
+ if (delta < 0) |
+ ASSERT(m_scrollEventHandlerCount > 0); |
+ m_scrollEventHandlerCount += delta; |
+ |
+ Page* page = document.page(); |
+ if (!page) |
+ return; |
+ |
+ ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator(); |
+ if (!scrollingCoordinator) |
+ return; |
+ |
+ FrameView* frameView = document.view(); |
+ if (!frameView) |
+ return; |
+ |
+ scrollingCoordinator->frameViewScrollEventHandlerCountChanged(frameView); |
+} |
+ |
+static void notifyTouchRectsChanged(Document& document) |
+{ |
+ Page* page = document.page(); |
+ if (!page) |
+ return; |
+ |
+ ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator(); |
+ if (!scrollingCoordinator) |
+ return; |
+ |
+ scrollingCoordinator->touchEventTargetRectsDidChange(); |
+} |
+ |
+void EventHandlerRegistry::didAddTouchEventHandler(Document& document, Node& handler) |
+{ |
+ // The node should either be in the document, or be the Document node of a child |
+ // of the document. |
+ ASSERT(&handler.document() == &document |
+ || (handler.isDocumentNode() && toDocument(&handler)->parentDocument() == &document)); |
+ |
+ if (!m_touchEventTargets.get()) |
+ m_touchEventTargets = adoptPtr(new TouchEventTargetSet); |
+ bool isFirstHandler = m_touchEventTargets->isEmpty(); |
+ |
+ if (!m_touchEventTargets->add(&handler).isNewEntry) { |
+ // Just incremented refcount, no real change. |
+ // If this is a child document node, then the count should never go above 1. |
+ ASSERT(!handler.isDocumentNode() || &handler->document() == &document); |
+ return; |
+ } |
+ |
+ if (isFirstHandler) { |
+ if (Document* parent = document.parentDocument()) { |
+ didAddTouchEventHandler(*parent, document); |
+ } else { |
+ // This is the first touch handler on the whole page. |
+ if (FrameHost* frameHost = document.frameHost()) |
+ frameHost->chrome().client().needTouchEvents(true); |
+ } |
+ } |
+ |
+ // When we're all done with all frames, ensure touch hit rects are marked as dirty. |
+ if (!handler.isDocumentNode() || &handler == &document) |
+ notifyTouchRectsChanged(document); |
+} |
+ |
+void EventHandlerRegistry::didRemoveTouchEventHandler(Document& document, Node& handler, bool clearAll) |
+{ |
+ // Note that we can't assert that |handler| is in this document because it might be in |
+ // the process of moving out of it. |
+ ASSERT(clearAll || m_touchEventTargets->contains(&handler)); |
+ if (!m_touchEventTargets.get()) |
+ return; |
+ |
+ if (clearAll) { |
+ if (!m_touchEventTargets->contains(&handler)) |
+ return; |
+ m_touchEventTargets->removeAll(&handler); |
+ } else { |
+ if (!m_touchEventTargets->remove(&handler)) { |
+ // Just decremented refcount, no real update. |
+ return; |
+ } |
+ } |
+ |
+ if (m_touchEventTargets->isEmpty()) { |
+ if (Document* parent = document.parentDocument()) { |
+ // This was the last handler in the document, update the parent document too. |
+ didRemoveTouchEventHandler(*parent, document, clearAll); |
+ } else { |
+ // We just removed the last touch handler on the whole page. |
+ if (FrameHost* frameHost = document.frameHost()) |
+ frameHost->chrome().client().needTouchEvents(false); |
+ } |
+ } |
+ |
+ // When we're all done with all frames, ensure touch hit rects are marked as dirty. |
+ if (!handler.isDocumentNode() || &handler == &document) |
+ notifyTouchRectsChanged(document); |
+} |
+ |
+void EventHandlerRegistry::didAddEventHandler(Document& document, const AtomicString& eventType, Node* targetNode) |
+{ |
+ if (eventType == EventTypeNames::wheel || eventType == EventTypeNames::mousewheel) |
+ didChangeWheelEventHandlerCount(document, 1); |
+ else if (eventType == EventTypeNames::scroll) |
+ didChangeScrollEventHandlerCount(document, 1); |
+ else if (isTouchEventType(eventType)) |
+ didAddTouchEventHandler(document, *targetNode); |
+} |
+ |
+void EventHandlerRegistry::didRemoveEventHandler(Document& document, const AtomicString& eventType, Node* targetNode) |
+{ |
+ if (eventType == EventTypeNames::wheel || eventType == EventTypeNames::mousewheel) |
+ didChangeWheelEventHandlerCount(document, -1); |
+ else if (eventType == EventTypeNames::scroll) |
+ didChangeScrollEventHandlerCount(document, -1); |
+ else if (isTouchEventType(eventType)) |
+ didRemoveTouchEventHandler(document, *targetNode, false); |
+} |
+ |
+void EventHandlerRegistry::didAddEventListener(DOMWindow* window, const AtomicString& eventType) |
+{ |
+ didAddEventHandler(*window->document(), eventType, window->document()); |
+} |
+ |
+void EventHandlerRegistry::didRemoveEventListener(DOMWindow* window, const AtomicString& eventType) |
+{ |
+ didRemoveEventHandler(*window->document(), eventType, window->document()); |
+} |
+ |
+void EventHandlerRegistry::didMoveNodeToNewDocument(Node& targetNode, Document& oldDocument) |
+{ |
+ didChangeAllEventHandlers(targetNode, oldDocument, Removed); |
+ didChangeAllEventHandlers(targetNode, targetNode.document(), Added); |
+} |
+ |
+void EventHandlerRegistry::didRemoveAllEventHandlers(Node& targetNode) |
+{ |
+ didChangeAllEventHandlers(targetNode, targetNode.document(), RemovedAll); |
+} |
+ |
+void EventHandlerRegistry::didChangeAllEventHandlers(Node& targetNode, Document& document, ChangeOperation op) |
+{ |
+ if (!targetNode.hasEventListeners()) |
+ return; |
+ EventHandlerRegistry* registry = EventHandlerRegistry::from(document); |
+ int wheelHandlerCount = targetNode.getEventListeners(EventTypeNames::wheel).size() + |
+ targetNode.getEventListeners(EventTypeNames::mousewheel).size(); |
+ registry->didChangeWheelEventHandlerCount( |
+ document, (op == Added) ? wheelHandlerCount : -wheelHandlerCount); |
+ |
+ int scrollHandlerCount = targetNode.getEventListeners(EventTypeNames::scroll).size(); |
+ registry->didChangeScrollEventHandlerCount( |
+ document, (op == Added) ? scrollHandlerCount : -scrollHandlerCount); |
+ |
+ const Vector<AtomicString> eventTypes = targetNode.eventTypes(); |
+ for (size_t i = 0; i < eventTypes.size(); ++i) { |
+ if (!isTouchEventType(eventTypes[i])) |
+ continue; |
+ const EventListenerVector& eventListeners = |
+ targetNode.getEventListeners(eventTypes[i]); |
+ for (size_t j = 0; j < eventListeners.size(); ++j) { |
+ if (op == Added) |
+ registry->didAddTouchEventHandler(document, targetNode); |
+ else |
+ registry->didRemoveTouchEventHandler(document, targetNode, op == RemovedAll); |
+ } |
+ } |
+} |
+ |
+} // namespace WebCore |