| Index: Source/core/events/EventPath.cpp
|
| diff --git a/Source/core/events/EventPath.cpp b/Source/core/events/EventPath.cpp
|
| index 9e53e718837b7f4b98bb0c5d7645cbec6efd6614..7857bd0f35b306c48eb3b6863b08f4017462c885 100644
|
| --- a/Source/core/events/EventPath.cpp
|
| +++ b/Source/core/events/EventPath.cpp
|
| @@ -31,10 +31,12 @@
|
| #include "core/dom/Document.h"
|
| #include "core/dom/Touch.h"
|
| #include "core/dom/TouchList.h"
|
| +#include "core/dom/shadow/ElementShadow.h"
|
| #include "core/dom/shadow/InsertionPoint.h"
|
| #include "core/dom/shadow/ShadowRoot.h"
|
| #include "core/events/TouchEvent.h"
|
| #include "core/events/TouchEventContext.h"
|
| +#include "core/html/HTMLShadowElement.h"
|
|
|
| namespace blink {
|
|
|
| @@ -46,6 +48,8 @@ EventTarget* EventPath::eventTargetRespectingTargetRules(Node& referenceNode)
|
| return &referenceNode;
|
| }
|
|
|
| +#define W3C23887 3
|
| +#if !defined(W3C23887) || W3C23887 < 2
|
| static inline bool shouldStopAtShadowRoot(Event& event, ShadowRoot& shadowRoot, EventTarget& target)
|
| {
|
| // WebKit never allowed selectstart event to cross the the shadow DOM boundary.
|
| @@ -63,6 +67,24 @@ static inline bool shouldStopAtShadowRoot(Event& event, ShadowRoot& shadowRoot,
|
| || eventType == EventTypeNames::select
|
| || eventType == EventTypeNames::selectstart);
|
| }
|
| +#else
|
| +static inline bool shouldStopBeforeShadowHost(Event& event)
|
| +{
|
| + // WebKit never allowed selectstart event to cross the the shadow DOM boundary.
|
| + // Changing this breaks existing sites.
|
| + // See https://bugs.webkit.org/show_bug.cgi?id=52195 for details.
|
| + const AtomicString eventType = event.type();
|
| + return (eventType == EventTypeNames::abort
|
| + || eventType == EventTypeNames::change
|
| + || eventType == EventTypeNames::error
|
| + || eventType == EventTypeNames::load
|
| + || eventType == EventTypeNames::reset
|
| + || eventType == EventTypeNames::resize
|
| + || eventType == EventTypeNames::scroll
|
| + || eventType == EventTypeNames::select
|
| + || eventType == EventTypeNames::selectstart);
|
| +}
|
| +#endif
|
|
|
| EventPath::EventPath(Node& node, Event* event)
|
| : m_node(node)
|
| @@ -93,6 +115,46 @@ void EventPath::addNodeEventContext(Node& node)
|
| m_nodeEventContexts.append(NodeEventContext(&node, eventTargetRespectingTargetRules(node)));
|
| }
|
|
|
| +#if W3C23887 == 1
|
| +static bool isDistributedToShadowInsertionPoint(const ShadowRoot& shadowRoot)
|
| +{
|
| + // 5.2.3. If CURRENT is not the youngest shadow root hosted by SHADOW-POOL-HOST:
|
| + // https://www.w3.org/Bugs/Public/show_bug.cgi?id=23887#c163
|
| + // and CURRENT is distributed to a shadow insertion point
|
| + ElementShadow* owner = shadowRoot.owner();
|
| + if (!owner)
|
| + return false;
|
| + if (shadowRoot.firstChild())
|
| + return owner->finalDestinationInsertionPointFor(shadowRoot.firstChild());
|
| + // TODO(kojii): how can we determine if a shadow root is distributed?
|
| + return false;
|
| +}
|
| +
|
| +static ShadowRoot* shadowRootDistributedInto(InsertionPoint& insertionPoint)
|
| +{
|
| + // 5.4.4.1. Let PROJECTED-SHADOW be the shadow root projected into CURRENT.
|
| + // TODO(kojii): is this correct way to determine that?
|
| +#ifndef A1
|
| + return insertionPoint.containingShadowRoot()->olderShadowRoot();
|
| +#else
|
| + // TODO(kojii): should it be first() or last()?
|
| + Node* distributedNode = insertionPoint.first();
|
| + if (!distributedNode)
|
| + return nullptr;
|
| + return distributedNode->containingShadowRoot();
|
| +#endif
|
| +}
|
| +#endif
|
| +#if W3C23887 >= 2
|
| +static inline InsertionPoint* pop(WillBeHeapVector<RawPtrWillBeMember<InsertionPoint>, 8>& stack)
|
| +{
|
| + ASSERT(!stack.isEmpty());
|
| + InsertionPoint* last = stack.last();
|
| + stack.removeLast();
|
| + return last;
|
| +}
|
| +#endif
|
| +
|
| void EventPath::calculatePath()
|
| {
|
| ASSERT(m_node);
|
| @@ -100,6 +162,7 @@ void EventPath::calculatePath()
|
| m_node->updateDistribution();
|
|
|
| Node* current = m_node;
|
| +#ifndef W3C23887
|
| addNodeEventContext(*current);
|
| if (!m_node->inDocument())
|
| return;
|
| @@ -132,6 +195,182 @@ void EventPath::calculatePath()
|
| addNodeEventContext(*current);
|
| }
|
| }
|
| +#elif W3C23887 == 3
|
| + if (!m_node->inDocument()) {
|
| + addNodeEventContext(*current);
|
| + return;
|
| + }
|
| + Element* stopBefore = m_event && shouldStopBeforeShadowHost(*m_event) ? m_node->shadowHost() : nullptr;
|
| + WillBeHeapVector<RawPtrWillBeMember<InsertionPoint>, 8> insertionPointStack;
|
| + for (;;) {
|
| + ASSERT(current);
|
| + addNodeEventContext(*current);
|
| + if (m_event && current->keepEventInNode(m_event))
|
| + break;
|
| + WillBeHeapVector<RawPtrWillBeMember<InsertionPoint>, 8> insertionPoints;
|
| + collectDestinationInsertionPoints(*current, insertionPoints);
|
| + if (!insertionPoints.isEmpty()) {
|
| + insertionPointStack.appendVector(insertionPoints);
|
| + current = pop(insertionPointStack);
|
| + continue;
|
| + }
|
| + if (current->isShadowRoot()) {
|
| + ShadowRoot* shadowRoot = toShadowRoot(current);
|
| + Node* olderShadowRootOrShadowHost = shadowRoot->olderShadowRoot();
|
| + if (!olderShadowRootOrShadowHost)
|
| + olderShadowRootOrShadowHost = shadowRoot->host();
|
| + ASSERT(olderShadowRootOrShadowHost);
|
| + if (!insertionPointStack.isEmpty() && insertionPointStack.last()->treeScope() == olderShadowRootOrShadowHost->treeScope()) {
|
| + current = pop(insertionPointStack);
|
| + continue;
|
| + }
|
| + if (olderShadowRootOrShadowHost == stopBefore)
|
| + break;
|
| + current = olderShadowRootOrShadowHost;
|
| + continue;
|
| + }
|
| + current = current->parentNode();
|
| + if (!current)
|
| + break;
|
| + }
|
| + // ASSERT(insertionPointStack.isEmpty());
|
| +#elif W3C23887 == 2
|
| + if (!m_node->inDocument()) {
|
| + addNodeEventContext(*current);
|
| + return;
|
| + }
|
| + Element* stopBefore = m_event && shouldStopBeforeShadowHost(*m_event) ? m_node->shadowHost() : nullptr;
|
| + WillBeHeapVector<RawPtrWillBeMember<InsertionPoint>, 8> insertionPointStack;
|
| + for (;;) {
|
| + ASSERT(current);
|
| + addNodeEventContext(*current);
|
| + if (m_event && current->keepEventInNode(m_event))
|
| + break;
|
| + WillBeHeapVector<RawPtrWillBeMember<InsertionPoint>, 8> insertionPoints;
|
| + collectDestinationInsertionPoints(*current, insertionPoints);
|
| + if (!insertionPoints.isEmpty()) {
|
| + bool hasInsertionPoints = false;
|
| + for (const auto& insertionPoint : insertionPoints) {
|
| + if (insertionPoint->isShadowInsertionPoint() && !insertionPoint->containingShadowRoot()->isOldest())
|
| + continue;
|
| + insertionPointStack.append(insertionPoint);
|
| + hasInsertionPoints = true;
|
| + }
|
| + if (hasInsertionPoints) {
|
| + current = pop(insertionPointStack);
|
| + continue;
|
| + }
|
| + }
|
| + if (current->isShadowRoot()) {
|
| + ShadowRoot* shadowRoot = toShadowRoot(current);
|
| + Element* shadowHost = shadowRoot->host();
|
| + ASSERT(shadowHost);
|
| + if (!insertionPointStack.isEmpty() && insertionPointStack.last()->treeScope() == shadowHost->treeScope()) {
|
| + current = pop(insertionPointStack);
|
| + continue;
|
| + }
|
| + if (HTMLShadowElement* shadowInsertionPointOfYoungerShadowRoot = shadowRoot->shadowInsertionPointOfYoungerShadowRoot()) {
|
| + current = shadowInsertionPointOfYoungerShadowRoot;
|
| + continue;
|
| + }
|
| + if (shadowHost == stopBefore)
|
| + break;
|
| + current = shadowHost;
|
| + continue;
|
| + }
|
| + current = current->parentNode();
|
| + if (!current)
|
| + break;
|
| + }
|
| + ASSERT(insertionPointStack.isEmpty());
|
| +#elif W3C23887 == 1 // https://bugzilla.mozilla.org/show_bug.cgi?id=1059989#c10
|
| + addNodeEventContext(*current);
|
| + if (!m_node->inDocument())
|
| + return;
|
| + // 3. Let INSERTION-POINTS be an empty stack of nodes.
|
| + WillBeHeapVector<RawPtrWillBeMember<InsertionPoint>, 8> insertionPointStack;
|
| + while (current) {
|
| + if (m_event && current->keepEventInNode(m_event))
|
| + break;
|
| + // 5.1. If the destination insertion points of CURRENT is not empty:
|
| + WillBeHeapVector<RawPtrWillBeMember<InsertionPoint>, 8> insertionPoints;
|
| + collectDestinationInsertionPoints(*current, insertionPoints);
|
| + bool removeShadowInsertionPoint = true;
|
| + if (!insertionPoints.isEmpty()) {
|
| + // 5.1.1. Push the destination insertion points into INSERTION-POINTS in order of first destination to final destination.
|
| + insertionPointStack.appendVector(insertionPoints);
|
| + // 5.1.2. Pop INSERTION-POINTS and set CURRENT to be the popped node.
|
| + current = insertionPointStack.last();
|
| + insertionPointStack.removeLast();
|
| + // 5.2. Otherwise if CURRENT is a shadow root:
|
| + } else if (current->isShadowRoot()) {
|
| + // 5.2.2. If SHADOW-POOL-HOST hosts the node tree which NODE participates in and EVENT is one of the events which must be stopped:
|
| + ShadowRoot* currentShadowRoot = toShadowRoot(current);
|
| + // TODO(kojii): we should be able to check this once and determine where to stop for better performance
|
| + if (m_event && shouldStopAtShadowRoot(*m_event, *currentShadowRoot, *m_node)) {
|
| + // 5.2.2.1. Stop this algorithm
|
| + break;
|
| + }
|
| + // 5.2.1. Let SHADOW-POOL-HOST be the shadow host which hosts CURRENT
|
| + Element* shadowPoolHost = currentShadowRoot->host();
|
| + // 5.2.3. If CURRENT is not the youngest shadow root hosted by SHADOW-POOL-HOST:
|
| + // https://www.w3.org/Bugs/Public/show_bug.cgi?id=23887#c163
|
| + // and CURRENT is distributed to a shadow insertion point
|
| + if (!currentShadowRoot->isYoungest() && isDistributedToShadowInsertionPoint(*currentShadowRoot)) {
|
| + // 5.2.3.1. Let SHADOW-POOL-HOST be the shadow insertion point into which CURRENT shadow root is projected.
|
| + // https://www.w3.org/Bugs/Public/show_bug.cgi?id=23887#c122
|
| + // Let SHADOW-POOL-HOST be the shadow insertion point in the younger shadow tree relative to the shadow tree
|
| + // whose root is CURRENT shadow root.
|
| + shadowPoolHost = currentShadowRoot->shadowInsertionPointOfYoungerShadowRoot();
|
| + }
|
| + // 5.2.4. If INSERTION-POINTS is not empty and
|
| + // if the most recent node in the INSERTION-POINTS is in the same node tree as SHADOW-POOL-HOST:
|
| + if (!insertionPointStack.isEmpty() && insertionPointStack.last()->treeScope() == shadowPoolHost->treeScope()) {
|
| + // 5.2.4.1. Pop INSERTION-POINTS and set CURRENT to be the popped node.
|
| + current = insertionPointStack.last();
|
| + insertionPointStack.removeLast();
|
| + // 5.2.5. Otherwise:
|
| + } else {
|
| + // 5.2.5.1. Set CURRENT to SHADOW-POOL-HOST and skip step 4
|
| + current = shadowPoolHost;
|
| + removeShadowInsertionPoint = false;
|
| + }
|
| + // 5.3. Otherwise:
|
| + } else {
|
| + // 5.3.1. 1. Let CURRENT be the parent node of CURRENT.
|
| + current = current->parentNode();
|
| + }
|
| + if (removeShadowInsertionPoint) {
|
| + // 5.4.4. Repeat while CURRENT is a shadow insertion point.
|
| + // https://www.w3.org/Bugs/Public/show_bug.cgi?id=23887#c170
|
| + // and there is a shadow root distributed to it (see the "if" within the "while" below)
|
| + while (current && isActiveShadowInsertionPoint(*current)) {
|
| + // 5.4.4.1. Let PROJECTED-SHADOW be the shadow root projected into CURRENT.
|
| + ShadowRoot* distributedShadowRoot = shadowRootDistributedInto(toInsertionPoint(*current));
|
| + // https://www.w3.org/Bugs/Public/show_bug.cgi?id=23887#c170
|
| + // 5.4.4. and there is a shadow root distributed to it
|
| + if (!distributedShadowRoot)
|
| + break;
|
| + // 5.4.4.2. If INSERTION-POINTS is not empty and
|
| + // if the most recent node in the INSERTION-POINTS is in the same node tree as PROJECTED-SHADOW:
|
| + if (!insertionPointStack.isEmpty() && insertionPointStack.last()->treeScope() == distributedShadowRoot->treeScope()) {
|
| + // 5.4.4.2.1. Pop INSERTION-POINTS and set CURRENT to be the popped node.
|
| + current = insertionPointStack.last();
|
| + insertionPointStack.removeLast();
|
| + // 5.4.4.3. Otherwise:
|
| + } else {
|
| + // 5.4.4.3.1. Set CURRENT to PROJECTED-SHADOW.
|
| + current = distributedShadowRoot;
|
| + }
|
| + }
|
| + }
|
| + // 5.5. If CURRENT exists:
|
| + // 5.5.1. Add CURRENT to PATH.
|
| + if (current)
|
| + addNodeEventContext(*current);
|
| + }
|
| + ASSERT(insertionPointStack.isEmpty());
|
| +#endif
|
| }
|
|
|
| void EventPath::calculateTreeScopePrePostOrderNumbers()
|
|
|