Commit 55a42461 authored by dglazkov@chromium.org's avatar dglazkov@chromium.org

2010-10-30 Dimitri Glazkov <dglazkov@chromium.org>

        Reviewed by Darin Adler.

        Implement shadow DOM-aware event targeting and introduce EventContext to track the context of each event dispatch.
        https://bugs.webkit.org/show_bug.cgi?id=46015

        Tuned the test to better reflect its point: the event should indeed fire (it used to be swallowed),
        but its target should be a non-shadow node.

        * fast/events/shadow-boundary-crossing.html: Modified the test.
2010-10-30  Dimitri Glazkov  <dglazkov@chromium.org>

        Reviewed by Darin Adler.

        Implement shadow DOM-aware event targeting and introduce EventContext to track the context of each event dispatch.
        https://bugs.webkit.org/show_bug.cgi?id=46015

        This patch adds the notion of EventContext (and a very similar-acting WindowEventContext, specifically
        for DOMWindow), an abstraction that carries information around dispatching an event for any given Node.

        This abstraction is necessary to ensure that events, fired from shadow DOM nodes are properly retargeted to
        appear as if they are coming from their host, thus never exposing the shadow DOM nodes to the world outside.

        * Android.mk: Added EventContext, WindowEventContext files.
        * CMakeLists.txt: Ditto.
        * GNUmakefile.am: Ditto.
        * WebCore.gypi: Ditto.
        * WebCore.pro: Ditto.
        * WebCore.xcodeproj/project.pbxproj: Ditto.
        * dom/ContainerNode.cpp:
        (WebCore::notifyChildInserted): Changed to be shadow DOM-aware.
        * dom/EventContext.cpp: Added.
        * dom/EventContext.h: Added.
        * dom/Node.cpp:
        (WebCore::Node::markAncestorsWithChildNeedsStyleRecalc): Changed to be shadow DOM-aware.
        (WebCore::Node::createRendererIfNeeded): Ditto.
        (WebCore::Node::parentOrHostNode): Added new helper method.
        (WebCore::Node::enclosingLinkEventParentOrSelf): Changed to be shadow DOM-aware.
        (WebCore::eventTargetRespectingSVGTargetRules): Collapsed two helper methods into one.
        (WebCore::Node::eventAncestors): Refactored to collect a vector of EventContexts.
        (WebCore::Node::topEventContext): Added.
        (WebCore::eventHasListeners): Changed to use EventContexts.
        (WebCore::Node::dispatchGenericEvent): Ditto.
        * dom/Node.h: Removed eventParentNode that's no longer needed, added parentOrHostNode decl,
            and changed signature of eventAncestors to use EventContexts.
        * dom/Text.cpp:
        (WebCore::Text::createRenderer): Changed to be shadow DOM-aware.
        * inspector/InspectorDOMAgent.cpp:
        (WebCore::InspectorDOMAgent::getEventListenersForNode): Changed to use EventContexts.
        * page/EventHandler.cpp:
        (WebCore::EventHandler::updateMouseEventTargetNode): Removed code that's no longer necessary.
        * svg/SVGElement.cpp: Removed eventParentNode that's no longer needed.
        * svg/SVGElement.h: Ditto.
        * dom/WindowEventContext.cpp: Added.
        * dom/WindowEventContext.h: Added.

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@70984 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent 87b1ca5d
2010-10-30 Dimitri Glazkov <dglazkov@chromium.org>
Reviewed by Darin Adler.
Implement shadow DOM-aware event targeting and introduce EventContext to track the context of each event dispatch.
https://bugs.webkit.org/show_bug.cgi?id=46015
Tuned the test to better reflect its point: the event should indeed fire (it used to be swallowed),
but its target should be a non-shadow node.
* fast/events/shadow-boundary-crossing.html: Modified the test.
2010-10-30 Nikolas Zimmermann <nzimmermann@rim.com>
Reviewed by Rob Buis.
......@@ -2,11 +2,12 @@
<head>
<title></title>
<script type="text/javascript">
var fired = false;
var success;
var target;
function selectStart(event)
{
fired = true;
success = event.target == target;
}
function test()
......@@ -15,7 +16,7 @@
return;
layoutTestController.dumpAsText();
var target = document.getElementById("target");
target = document.getElementById("target");
var x = target.offsetLeft + target.offsetWidth / 2;
var y = target.offsetTop + target.offsetHeight / 2;
......@@ -23,7 +24,7 @@
eventSender.mouseDown();
eventSender.mouseUp();
document.getElementById("result").innerText = fired ? "FAIL" : "PASS";
document.getElementById("result").innerText = !success ? "FAIL" : "PASS";
}
addEventListener("selectstart", selectStart, true);
......
......@@ -132,6 +132,7 @@ LOCAL_SRC_FILES := $(LOCAL_SRC_FILES) \
dom/EntityReference.cpp \
dom/ErrorEvent.cpp \
dom/Event.cpp \
dom/EventContext.cpp \
dom/EventNames.cpp \
dom/EventTarget.cpp \
dom/ExceptionBase.cpp \
......@@ -192,6 +193,7 @@ LOCAL_SRC_FILES := $(LOCAL_SRC_FILES) \
dom/WebKitAnimationEvent.cpp \
dom/WebKitTransitionEvent.cpp \
dom/WheelEvent.cpp \
dom/WindowEventContext.cpp \
dom/XMLDocumentParser.cpp \
dom/XMLDocumentParserLibxml2.cpp \
dom/XMLDocumentParserScope.cpp \
......
......@@ -824,6 +824,7 @@ SET(WebCore_SOURCES
dom/EntityReference.cpp
dom/ErrorEvent.cpp
dom/Event.cpp
dom/EventContext.cpp
dom/EventNames.cpp
dom/EventTarget.cpp
dom/ExceptionBase.cpp
......@@ -881,6 +882,7 @@ SET(WebCore_SOURCES
dom/WebKitAnimationEvent.cpp
dom/WebKitTransitionEvent.cpp
dom/WheelEvent.cpp
dom/WindowEventContext.cpp
dom/XMLDocumentParser.cpp
dom/XMLDocumentParserLibxml2.cpp
dom/XMLDocumentParserScope.cpp
......
2010-10-30 Dimitri Glazkov <dglazkov@chromium.org>
Reviewed by Darin Adler.
Implement shadow DOM-aware event targeting and introduce EventContext to track the context of each event dispatch.
https://bugs.webkit.org/show_bug.cgi?id=46015
This patch adds the notion of EventContext (and a very similar-acting WindowEventContext, specifically
for DOMWindow), an abstraction that carries information around dispatching an event for any given Node.
This abstraction is necessary to ensure that events, fired from shadow DOM nodes are properly retargeted to
appear as if they are coming from their host, thus never exposing the shadow DOM nodes to the world outside.
* Android.mk: Added EventContext, WindowEventContext files.
* CMakeLists.txt: Ditto.
* GNUmakefile.am: Ditto.
* WebCore.gypi: Ditto.
* WebCore.pro: Ditto.
* WebCore.xcodeproj/project.pbxproj: Ditto.
* dom/ContainerNode.cpp:
(WebCore::notifyChildInserted): Changed to be shadow DOM-aware.
* dom/EventContext.cpp: Added.
* dom/EventContext.h: Added.
* dom/Node.cpp:
(WebCore::Node::markAncestorsWithChildNeedsStyleRecalc): Changed to be shadow DOM-aware.
(WebCore::Node::createRendererIfNeeded): Ditto.
(WebCore::Node::parentOrHostNode): Added new helper method.
(WebCore::Node::enclosingLinkEventParentOrSelf): Changed to be shadow DOM-aware.
(WebCore::eventTargetRespectingSVGTargetRules): Collapsed two helper methods into one.
(WebCore::Node::eventAncestors): Refactored to collect a vector of EventContexts.
(WebCore::Node::topEventContext): Added.
(WebCore::eventHasListeners): Changed to use EventContexts.
(WebCore::Node::dispatchGenericEvent): Ditto.
* dom/Node.h: Removed eventParentNode that's no longer needed, added parentOrHostNode decl,
and changed signature of eventAncestors to use EventContexts.
* dom/Text.cpp:
(WebCore::Text::createRenderer): Changed to be shadow DOM-aware.
* inspector/InspectorDOMAgent.cpp:
(WebCore::InspectorDOMAgent::getEventListenersForNode): Changed to use EventContexts.
* page/EventHandler.cpp:
(WebCore::EventHandler::updateMouseEventTargetNode): Removed code that's no longer necessary.
* svg/SVGElement.cpp: Removed eventParentNode that's no longer needed.
* svg/SVGElement.h: Ditto.
* dom/WindowEventContext.cpp: Added.
* dom/WindowEventContext.h: Added.
2010-10-30 Nikolas Zimmermann <nzimmermann@rim.com>
Reviewed by Rob Buis.
......@@ -1132,8 +1132,10 @@ webcore_sources += \
WebCore/dom/ErrorEvent.cpp \
WebCore/dom/ErrorEvent.h \
WebCore/dom/Event.cpp \
WebCore/dom/EventException.h \
WebCore/dom/Event.h \
WebCore/dom/EventContext.cpp \
WebCore/dom/EventContext.h \
WebCore/dom/EventException.h \
WebCore/dom/EventListener.h \
WebCore/dom/EventNames.cpp \
WebCore/dom/EventNames.h \
......@@ -1261,6 +1263,8 @@ webcore_sources += \
WebCore/dom/WebKitTransitionEvent.h \
WebCore/dom/WheelEvent.cpp \
WebCore/dom/WheelEvent.h \
WebCore/dom/WindowEventContext.cpp \
WebCore/dom/WindowEventContext.h \
WebCore/dom/XMLDocumentParser.cpp \
WebCore/dom/XMLDocumentParser.h \
WebCore/dom/XMLDocumentParserLibxml2.cpp \
......
......@@ -1204,6 +1204,8 @@
'dom/ErrorEvent.h',
'dom/Event.cpp',
'dom/Event.h',
'dom/EventContext.cpp',
'dom/EventContext.h',
'dom/EventException.h',
'dom/EventListener.h',
'dom/EventNames.cpp',
......@@ -1339,6 +1341,8 @@
'dom/WebKitTransitionEvent.h',
'dom/WheelEvent.cpp',
'dom/WheelEvent.h',
'dom/WindowEventContext.cpp',
'dom/WindowEventContext.h',
'dom/XMLDocumentParser.cpp',
'dom/XMLDocumentParser.h',
'dom/XMLDocumentParserLibxml2.cpp',
......
......@@ -713,6 +713,7 @@ SOURCES += \
dom/EntityReference.cpp \
dom/ErrorEvent.cpp \
dom/Event.cpp \
dom/EventContext.cpp \
dom/EventNames.cpp \
dom/EventTarget.cpp \
dom/ExceptionBase.cpp \
......@@ -773,6 +774,7 @@ SOURCES += \
dom/WebKitAnimationEvent.cpp \
dom/WebKitTransitionEvent.cpp \
dom/WheelEvent.cpp \
dom/WindowEventContext.cpp \
dom/XMLDocumentParser.cpp \
dom/XMLDocumentParserQt.cpp \
dom/default/PlatformMessagePortChannel.cpp \
......
......@@ -891,7 +891,11 @@
410B7E721045FAB000D8224F /* JSMessageEventCustom.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 410B7E711045FAB000D8224F /* JSMessageEventCustom.cpp */; };
411046410FA222A600BA436A /* ScriptEventListener.h in Headers */ = {isa = PBXBuildFile; fileRef = 4110463F0FA222A600BA436A /* ScriptEventListener.h */; };
411046420FA222A600BA436A /* ScriptEventListener.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 411046400FA222A600BA436A /* ScriptEventListener.cpp */; };
4123E569127B3041000FEEA7 /* WindowEventContext.h in Headers */ = {isa = PBXBuildFile; fileRef = 4123E567127B3041000FEEA7 /* WindowEventContext.h */; };
4123E56A127B3041000FEEA7 /* WindowEventContext.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4123E568127B3041000FEEA7 /* WindowEventContext.cpp */; };
4127D5370F8AAB1D00E424F5 /* ScriptState.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4127D5360F8AAB1D00E424F5 /* ScriptState.cpp */; };
4138D3351244054800323D33 /* EventContext.h in Headers */ = {isa = PBXBuildFile; fileRef = 4138D3331244054800323D33 /* EventContext.h */; };
4138D3361244054800323D33 /* EventContext.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4138D3341244054800323D33 /* EventContext.cpp */; };
4162A450101145AE00DFF3ED /* DedicatedWorkerContext.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4162A44D101145AE00DFF3ED /* DedicatedWorkerContext.cpp */; };
4162A451101145AE00DFF3ED /* DedicatedWorkerContext.h in Headers */ = {isa = PBXBuildFile; fileRef = 4162A44E101145AE00DFF3ED /* DedicatedWorkerContext.h */; };
4162A454101145E300DFF3ED /* JSDedicatedWorkerContextCustom.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4162A453101145E300DFF3ED /* JSDedicatedWorkerContextCustom.cpp */; };
......@@ -6955,7 +6959,11 @@
410B7E711045FAB000D8224F /* JSMessageEventCustom.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSMessageEventCustom.cpp; sourceTree = "<group>"; };
4110463F0FA222A600BA436A /* ScriptEventListener.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ScriptEventListener.h; sourceTree = "<group>"; };
411046400FA222A600BA436A /* ScriptEventListener.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ScriptEventListener.cpp; sourceTree = "<group>"; };
4123E567127B3041000FEEA7 /* WindowEventContext.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WindowEventContext.h; sourceTree = "<group>"; };
4123E568127B3041000FEEA7 /* WindowEventContext.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WindowEventContext.cpp; sourceTree = "<group>"; };
4127D5360F8AAB1D00E424F5 /* ScriptState.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ScriptState.cpp; sourceTree = "<group>"; };
4138D3331244054800323D33 /* EventContext.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EventContext.h; sourceTree = "<group>"; };
4138D3341244054800323D33 /* EventContext.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = EventContext.cpp; sourceTree = "<group>"; };
4162A44D101145AE00DFF3ED /* DedicatedWorkerContext.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DedicatedWorkerContext.cpp; path = workers/DedicatedWorkerContext.cpp; sourceTree = "<group>"; };
4162A44E101145AE00DFF3ED /* DedicatedWorkerContext.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DedicatedWorkerContext.h; path = workers/DedicatedWorkerContext.h; sourceTree = "<group>"; };
4162A44F101145AE00DFF3ED /* DedicatedWorkerContext.idl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = DedicatedWorkerContext.idl; path = workers/DedicatedWorkerContext.idl; sourceTree = "<group>"; };
......@@ -18163,6 +18171,8 @@
85031B2B0A44EFC700F992E0 /* Event.cpp */,
85031B2C0A44EFC700F992E0 /* Event.h */,
14E836D209F8512000B85AE4 /* Event.idl */,
4138D3341244054800323D33 /* EventContext.cpp */,
4138D3331244054800323D33 /* EventContext.h */,
BC60D9090D2A17CE00B9918F /* EventException.h */,
BC60D90A0D2A17CE00B9918F /* EventException.idl */,
935FBC4409BA00B900E230B1 /* EventListener.h */,
......@@ -18323,6 +18333,8 @@
85031B3A0A44EFC700F992E0 /* WheelEvent.cpp */,
85031B3B0A44EFC700F992E0 /* WheelEvent.h */,
93EEC1F709C2877700C515D1 /* WheelEvent.idl */,
4123E568127B3041000FEEA7 /* WindowEventContext.cpp */,
4123E567127B3041000FEEA7 /* WindowEventContext.h */,
F523D30902DE4476018635CA /* XMLDocumentParser.cpp */,
F523D30A02DE4476018635CA /* XMLDocumentParser.h */,
54C50F7A0E801DF3009832A0 /* XMLDocumentParserLibxml2.cpp */,
......@@ -19486,6 +19498,7 @@
89878560122CA064003AABDA /* ErrorCallback.h in Headers */,
2ECF7AE210162B5800427DE7 /* ErrorEvent.h in Headers */,
85031B420A44EFC700F992E0 /* Event.h in Headers */,
4138D3351244054800323D33 /* EventContext.h in Headers */,
BC60D90C0D2A17CE00B9918F /* EventException.h in Headers */,
93C09A530B064DB3005ABD4D /* EventHandler.h in Headers */,
935FBC4509BA00B900E230B1 /* EventListener.h in Headers */,
......@@ -21141,6 +21154,7 @@
85031B510A44EFC700F992E0 /* WheelEvent.h in Headers */,
9380F47409A11AB4001FDB34 /* Widget.h in Headers */,
939B02EF0EA2DBC400C54570 /* WidthIterator.h in Headers */,
4123E569127B3041000FEEA7 /* WindowEventContext.h in Headers */,
BC8243E90D0CFD7500460C8F /* WindowFeatures.h in Headers */,
E1E1BF00115FF6FB006F52CA /* WindowsKeyboardCodes.h in Headers */,
08203AA00ED8C35300B8B61A /* WMLAccessElement.h in Headers */,
......@@ -22116,6 +22130,7 @@
893C480C1248BD3A002B3D86 /* EntrySync.cpp in Sources */,
2ECF7AE110162B5800427DE7 /* ErrorEvent.cpp in Sources */,
85031B410A44EFC700F992E0 /* Event.cpp in Sources */,
4138D3361244054800323D33 /* EventContext.cpp in Sources */,
93C09A810B064F00005ABD4D /* EventHandler.cpp in Sources */,
93C09A7F0B064EEF005ABD4D /* EventHandlerMac.mm in Sources */,
1CA19E050DC255950065A994 /* EventLoopMac.mm in Sources */,
......@@ -23715,6 +23730,7 @@
9380F47309A11AB4001FDB34 /* Widget.cpp in Sources */,
9380F47809A11ACC001FDB34 /* WidgetMac.mm in Sources */,
939B02EE0EA2DBC400C54570 /* WidthIterator.cpp in Sources */,
4123E56A127B3041000FEEA7 /* WindowEventContext.cpp in Sources */,
BC8243E80D0CFD7500460C8F /* WindowFeatures.cpp in Sources */,
08203A9F0ED8C35300B8B61A /* WMLAccessElement.cpp in Sources */,
088C97510ECB6E28000534BA /* WMLAElement.cpp in Sources */,
......@@ -1005,7 +1005,8 @@ static void notifyChildInserted(Node* child)
RefPtr<Node> c = child;
RefPtr<Document> document = child->document();
if (c->parentNode() && c->parentNode()->inDocument())
Node* parentOrHostNode = c->parentOrHostNode();
if (parentOrHostNode && parentOrHostNode->inDocument())
c->insertedIntoDocument();
else
c->insertedIntoTree(true);
......
/*
* Copyright (C) 2010 Google Inc. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "config.h"
#include "EventContext.h"
#include "DOMWindow.h"
#include "Document.h"
#include "Event.h"
#include "Node.h"
namespace WebCore {
EventContext::EventContext(PassRefPtr<Node> node, PassRefPtr<EventTarget> currentTarget, PassRefPtr<EventTarget> target)
: m_node(node)
, m_currentTarget(currentTarget)
, m_target(target)
{
}
void EventContext::handleLocalEvents(Event* event) const
{
event->setTarget(m_target.get());
event->setCurrentTarget(m_currentTarget.get());
m_node->handleLocalEvents(event);
}
}
/*
* Copyright (C) 2010 Google Inc. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef EventContext_h
#define EventContext_h
#include <wtf/RefPtr.h>
namespace WebCore {
class EventTarget;
class Event;
class Node;
class EventContext {
public:
// FIXME: Use ContainerNode instead of Node.
EventContext(PassRefPtr<Node>, PassRefPtr<EventTarget> currentTarget, PassRefPtr<EventTarget> target);
Node* node() const;
EventTarget* target() const;
void handleLocalEvents(Event*) const;
private:
RefPtr<Node> m_node;
RefPtr<EventTarget> m_currentTarget;
RefPtr<EventTarget> m_target;
};
inline Node* EventContext::node() const
{
return m_node.get();
}
inline EventTarget* EventContext::target() const
{
return m_target.get();
}
}
#endif // EventContext_h
......@@ -45,6 +45,7 @@
#include "DynamicNodeList.h"
#include "Element.h"
#include "Event.h"
#include "EventContext.h"
#include "EventException.h"
#include "EventHandler.h"
#include "EventListener.h"
......@@ -80,6 +81,7 @@
#include "WebKitAnimationEvent.h"
#include "WebKitTransitionEvent.h"
#include "WheelEvent.h"
#include "WindowEventContext.h"
#include "XMLNames.h"
#include "htmlediting.h"
#include <wtf/HashSet.h>
......@@ -734,9 +736,9 @@ inline void Node::setStyleChange(StyleChangeType changeType)
inline void Node::markAncestorsWithChildNeedsStyleRecalc()
{
for (ContainerNode* p = parentNode(); p && !p->childNeedsStyleRecalc(); p = p->parentNode())
for (ContainerNode* p = parentOrHostNode(); p && !p->childNeedsStyleRecalc(); p = p->parentOrHostNode())
p->setChildNeedsStyleRecalc();
if (document()->childNeedsStyleRecalc())
document()->scheduleStyleRecalc();
}
......@@ -1321,7 +1323,7 @@ void Node::createRendererIfNeeded()
ASSERT(!renderer());
ContainerNode* parent = parentNode();
ContainerNode* parent = parentOrHostNode();
ASSERT(parent);
RenderObject* parentRenderer = parent->renderer();
......@@ -2239,14 +2241,9 @@ void Node::getSubresourceURLs(ListHashSet<KURL>& urls) const
addSubresourceAttributeURLs(urls);
}
ContainerNode* Node::eventParentNode()
{
return parentNode();
}
Node* Node::enclosingLinkEventParentOrSelf()
{
for (Node* node = this; node; node = node->eventParentNode()) {
for (Node* node = this; node; node = node->parentOrHostNode()) {
// For imagemaps, the enclosing link node is the associated area element not the image itself.
// So we don't let images be the enclosingLinkNode, even though isLink sometimes returns true
// for them.
......@@ -2484,12 +2481,13 @@ void Node::handleLocalEvents(Event* event)
fireEventListeners(event);
}
#if ENABLE(SVG)
static inline SVGElementInstance* eventTargetAsSVGElementInstance(Node* referenceNode)
static inline EventTarget* eventTargetRespectingSVGTargetRules(Node* referenceNode)
{
ASSERT(referenceNode);
#if ENABLE(SVG)
if (!referenceNode->isSVGElement())
return 0;
return referenceNode;
// Spec: The event handling for the non-exposed tree works as if the referenced element had been textually included
// as a deeply cloned child of the 'use' element, except that events are dispatched to the SVGElementInstance objects
......@@ -2503,36 +2501,39 @@ static inline SVGElementInstance* eventTargetAsSVGElementInstance(Node* referenc
if (SVGElementInstance* instance = static_cast<SVGUseElement*>(shadowTreeParentElement)->instanceForShadowTreeElement(referenceNode))
return instance;
}
return 0;
}
#endif
static inline EventTarget* eventTargetRespectingSVGTargetRules(Node* referenceNode)
{
ASSERT(referenceNode);
#if ENABLE(SVG)
if (SVGElementInstance* instance = eventTargetAsSVGElementInstance(referenceNode)) {
ASSERT(instance->shadowTreeElement() == referenceNode);
return instance;
}
#endif
return referenceNode;
}
void Node::eventAncestors(Vector<RefPtr<ContainerNode> > &ancestors)
void Node::getEventAncestors(Vector<EventContext>& ancestors, EventTarget* originalTarget)
{
if (inDocument()) {
for (ContainerNode* ancestor = eventParentNode(); ancestor; ancestor = ancestor->eventParentNode()) {
if (!inDocument())
return;
EventTarget* target = originalTarget;
Node* ancestor = this;
bool shouldSkipNextAncestor = false;
while (true) {
if (ancestor->isShadowNode()) {
ancestor = ancestor->shadowParentNode();
if (!shouldSkipNextAncestor)
target = ancestor;
} else
ancestor = ancestor->parentNode();
if (!ancestor)
return;
#if ENABLE(SVG)
// Skip <use> shadow tree elements.
if (ancestor->isSVGElement() && ancestor->isShadowNode())
continue;
// Skip SVGShadowTreeRootElement.
shouldSkipNextAncestor = ancestor->isSVGElement() && ancestor->isShadowNode();
if (shouldSkipNextAncestor)
continue;
#endif
ancestors.append(ancestor);
}
// FIXME: Unroll the extra loop inside eventTargetRespectingSVGTargetRules into this loop.
ancestors.append(EventContext(ancestor, eventTargetRespectingSVGTargetRules(ancestor), target));
}
}
......@@ -2547,6 +2548,11 @@ bool Node::dispatchEvent(PassRefPtr<Event> prpEvent)
return dispatchGenericEvent(event.release());
}
static const EventContext* topEventContext(const Vector<EventContext>& ancestors)
{
return ancestors.isEmpty() ? 0 : &(ancestors.last());
}
bool Node::dispatchGenericEvent(PassRefPtr<Event> prpEvent)
{
RefPtr<Event> event(prpEvent);
......@@ -2559,20 +2565,13 @@ bool Node::dispatchGenericEvent(PassRefPtr<Event> prpEvent)
// If the node is not in a document just send the event to it.
// Be sure to ref all of nodes since event handlers could result in the last reference going away.
RefPtr<Node> thisNode(this);
Vector<RefPtr<ContainerNode> > ancestors;
eventAncestors(ancestors);
RefPtr<EventTarget> originalTarget = event->target();
Vector<EventContext> ancestors;
getEventAncestors(ancestors, originalTarget.get());
// Set up a pointer to indicate whether / where to dispatch window events.
// We don't dispatch load events to the window. That quirk was originally
// added because Mozilla doesn't propagate load events to the window object.
DOMWindow* targetForWindowEvents = 0;
if (event->type() != eventNames().loadEvent) {
Node* topLevelContainer = ancestors.isEmpty() ? this : ancestors.last().get();
if (topLevelContainer->isDocumentNode())
targetForWindowEvents = static_cast<Document*>(topLevelContainer)->domWindow();
}
WindowEventContext windowContext(event.get(), this, topEventContext(ancestors));
InspectorInstrumentationCookie cookie = InspectorInstrumentation::willDispatchEvent(document(), *event, targetForWindowEvents, this, ancestors);
InspectorInstrumentationCookie cookie = InspectorInstrumentation::willDispatchEvent(document(), *event, windowContext.window(), this, ancestors);
// Give the target node a chance to do some work before DOM event handlers get a crack.
void* data = preDispatchEventHandler(event.get());
......@@ -2582,22 +2581,17 @@ bool Node::dispatchGenericEvent(PassRefPtr<Event> prpEvent)
// Trigger capturing event handlers, starting at the top and working our way down.
event->setEventPhase(Event::CAPTURING_PHASE);
if (targetForWindowEvents) {
event->setCurrentTarget(targetForWindowEvents);
targetForWindowEvents->fireEventListeners(event.get());
if (event->propagationStopped())
goto doneDispatching;
}
if (windowContext.handleLocalEvents(event.get()) && event->propagationStopped())
goto doneDispatching;
for (size_t i = ancestors.size(); i; --i) {
ContainerNode* ancestor = ancestors[i - 1].get();
event->setCurrentTarget(eventTargetRespectingSVGTargetRules(ancestor));
ancestor->handleLocalEvents(event.get());
ancestors[i - 1].handleLocalEvents(event.get());
if (event->propagationStopped())
goto doneDispatching;
}
event->setEventPhase(Event::AT_TARGET);
event->setTarget(originalTarget.get());
event->setCurrentTarget(eventTargetRespectingSVGTargetRules(this));
handleLocalEvents(event.get());
if (event->propagationStopped())
......@@ -2609,21 +2603,15 @@ bool Node::dispatchGenericEvent(PassRefPtr<Event> prpEvent)
size_t size = ancestors.size();
for (size_t i = 0; i < size; ++i) {
ContainerNode* ancestor = ancestors[i].get();
event->setCurrentTarget(eventTargetRespectingSVGTargetRules(ancestor));
ancestor->handleLocalEvents(event.get());
if (event->propagationStopped() || event->cancelBubble())
goto doneDispatching;
}
if (targetForWindowEvents) {
event->setCurrentTarget(targetForWindowEvents);
targetForWindowEvents->fireEventListeners(event.get());
ancestors[i].handleLocalEvents(event.get());
if (event->propagationStopped() || event->cancelBubble())
goto doneDispatching;
}
windowContext.handleLocalEvents(event.get());
}
doneDispatching:
event->setTarget(originalTarget.get());
event->setCurrentTarget(0);
event->setEventPhase(0);
......@@ -2644,8 +2632,7 @@ doneDispatching:
if (event->bubbles()) {
size_t size = ancestors.size();
for (size_t i = 0; i < size; ++i) {
ContainerNode* ancestor = ancestors[i].get();
ancestor->defaultEventHandler(event.get());
ancestors[i].node()->defaultEventHandler(event.get());
ASSERT(!event->defaultPrevented());
if (event->defaultHandled())
goto doneWithDefault;
......
......@@ -49,6 +49,7 @@ class Document;
class DynamicNodeList;
class Element;
class Event;
class EventContext;
class EventListener;
class FloatPoint;
class Frame;
......@@ -204,16 +205,14 @@ public:
Node* shadowAncestorNode();
Node* shadowTreeRootNode();
bool isInShadowTree();
// The node's parent for the purpose of event capture and bubbling.
virtual ContainerNode* eventParentNode();
// Node's parent or shadow tree host.
ContainerNode* parentOrHostNode();
// Returns the enclosing event parent node (or self) that, when clicked, would trigger a navigation.
Node* enclosingLinkEventParentOrSelf();
// Node ancestors when concerned about event flow.
// FIXME: Should be named getEventAncestors.
void eventAncestors(Vector<RefPtr<ContainerNode> > &ancestors);
void getEventAncestors(Vector<EventContext>& ancestors, EventTarget*);
bool isBlockFlow() const;
bool isBlockFlowOrBlockTable() const;
......@@ -693,6 +692,13 @@ inline void addSubresourceURL(ListHashSet<KURL>& urls, const KURL& url)
urls.add(url);