Move parseFontFaceDescriptor to CSSPropertyParser.cpp
[chromium-blink-merge.git] / third_party / WebKit / Source / core / events / EventPath.cpp
blob1c601b4c9c0f05f69099d863c985390875fcfe2c
1 /*
2 * Copyright (C) 2013 Google Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Neither the name of Google Inc. nor the names of its
11 * contributors may be used to endorse or promote products derived from
12 * this software without specific prior written permission.
14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
15 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
16 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
17 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
18 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
19 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
20 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 #include "config.h"
28 #include "core/events/EventPath.h"
30 #include "core/EventNames.h"
31 #include "core/dom/Document.h"
32 #include "core/dom/Touch.h"
33 #include "core/dom/TouchList.h"
34 #include "core/dom/shadow/InsertionPoint.h"
35 #include "core/dom/shadow/ShadowRoot.h"
36 #include "core/events/TouchEvent.h"
37 #include "core/events/TouchEventContext.h"
39 namespace blink {
41 EventTarget* EventPath::eventTargetRespectingTargetRules(Node& referenceNode)
43 if (referenceNode.isPseudoElement()) {
44 ASSERT(referenceNode.parentNode());
45 return referenceNode.parentNode();
48 return &referenceNode;
51 static inline bool shouldStopAtShadowRoot(Event& event, ShadowRoot& shadowRoot, EventTarget& target)
53 // WebKit never allowed selectstart event to cross the the shadow DOM boundary.
54 // Changing this breaks existing sites.
55 // See https://bugs.webkit.org/show_bug.cgi?id=52195 for details.
56 const AtomicString eventType = event.type();
57 return target.toNode() && target.toNode()->shadowHost() == shadowRoot.host()
58 && (eventType == EventTypeNames::abort
59 || eventType == EventTypeNames::change
60 || eventType == EventTypeNames::error
61 || eventType == EventTypeNames::load
62 || eventType == EventTypeNames::reset
63 || eventType == EventTypeNames::resize
64 || eventType == EventTypeNames::scroll
65 || eventType == EventTypeNames::select
66 || eventType == EventTypeNames::selectstart);
69 EventPath::EventPath(Node& node, Event* event)
70 : m_node(node)
71 , m_event(event)
73 initialize();
76 void EventPath::initializeWith(Node& node, Event* event)
78 m_node = &node;
79 m_event = event;
80 m_windowEventContext = nullptr;
81 m_nodeEventContexts.clear();
82 m_treeScopeEventContexts.clear();
83 initialize();
86 static inline bool eventPathShouldBeEmptyFor(Node& node)
88 return node.isPseudoElement() && !node.parentElement();
91 void EventPath::initialize()
93 if (eventPathShouldBeEmptyFor(*m_node))
94 return;
95 calculatePath();
96 calculateAdjustedTargets();
97 calculateTreeOrderAndSetNearestAncestorClosedTree();
100 void EventPath::calculatePath()
102 ASSERT(m_node);
103 ASSERT(m_nodeEventContexts.isEmpty());
104 m_node->updateDistribution();
106 // For performance and memory usage reasons we want to store the
107 // path using as few bytes as possible and with as few allocations
108 // as possible which is why we gather the data on the stack before
109 // storing it in a perfectly sized m_nodeEventContexts Vector.
110 WillBeHeapVector<RawPtrWillBeMember<Node>, 64> nodesInPath;
111 Node* current = m_node;
112 nodesInPath.append(current);
113 while (current) {
114 if (m_event && current->keepEventInNode(m_event))
115 break;
116 WillBeHeapVector<RawPtrWillBeMember<InsertionPoint>, 8> insertionPoints;
117 collectDestinationInsertionPoints(*current, insertionPoints);
118 if (!insertionPoints.isEmpty()) {
119 for (const auto& insertionPoint : insertionPoints) {
120 if (insertionPoint->isShadowInsertionPoint()) {
121 ShadowRoot* containingShadowRoot = insertionPoint->containingShadowRoot();
122 ASSERT(containingShadowRoot);
123 if (!containingShadowRoot->isOldest())
124 nodesInPath.append(containingShadowRoot->olderShadowRoot());
126 nodesInPath.append(insertionPoint);
128 current = insertionPoints.last();
129 continue;
131 if (current->isShadowRoot()) {
132 if (m_event && shouldStopAtShadowRoot(*m_event, *toShadowRoot(current), *m_node))
133 break;
134 current = current->shadowHost();
135 #if !ENABLE(OILPAN)
136 // TODO(kochi): crbug.com/507413 This check is necessary when some asynchronous event
137 // is queued while its shadow host is removed and the shadow root gets the event
138 // immediately after it. When Oilpan is enabled, this situation does not happen.
139 // Except this case, shadow root's host is assumed to be non-null.
140 if (current)
141 nodesInPath.append(current);
142 #else
143 nodesInPath.append(current);
144 #endif
145 } else {
146 current = current->parentNode();
147 if (current)
148 nodesInPath.append(current);
152 m_nodeEventContexts.reserveCapacity(nodesInPath.size());
153 for (Node* nodeInPath : nodesInPath) {
154 m_nodeEventContexts.append(NodeEventContext(nodeInPath, eventTargetRespectingTargetRules(*nodeInPath)));
158 void EventPath::calculateTreeOrderAndSetNearestAncestorClosedTree()
160 // Precondition:
161 // - TreeScopes in m_treeScopeEventContexts must be *connected* in the same tree of trees.
162 // - The root tree must be included.
163 WillBeHeapHashMap<RawPtrWillBeMember<const TreeScope>, RawPtrWillBeMember<TreeScopeEventContext>> treeScopeEventContextMap;
164 for (const auto& treeScopeEventContext : m_treeScopeEventContexts)
165 treeScopeEventContextMap.add(&treeScopeEventContext->treeScope(), treeScopeEventContext.get());
166 TreeScopeEventContext* rootTree = nullptr;
167 for (const auto& treeScopeEventContext : m_treeScopeEventContexts) {
168 // Use olderShadowRootOrParentTreeScope here for parent-child relationships.
169 // See the definition of trees of trees in the Shadow DOM spec:
170 // http://w3c.github.io/webcomponents/spec/shadow/
171 TreeScope* parent = treeScopeEventContext.get()->treeScope().olderShadowRootOrParentTreeScope();
172 if (!parent) {
173 ASSERT(!rootTree);
174 rootTree = treeScopeEventContext.get();
175 continue;
177 ASSERT(treeScopeEventContextMap.find(parent) != treeScopeEventContextMap.end());
178 treeScopeEventContextMap.find(parent)->value->addChild(*treeScopeEventContext.get());
180 ASSERT(rootTree);
181 rootTree->calculateTreeOrderAndSetNearestAncestorClosedTree(0, nullptr);
184 TreeScopeEventContext* EventPath::ensureTreeScopeEventContext(Node* currentTarget, TreeScope* treeScope, TreeScopeEventContextMap& treeScopeEventContextMap)
186 if (!treeScope)
187 return nullptr;
188 TreeScopeEventContext* treeScopeEventContext;
189 bool isNewEntry;
191 TreeScopeEventContextMap::AddResult addResult = treeScopeEventContextMap.add(treeScope, nullptr);
192 isNewEntry = addResult.isNewEntry;
193 if (isNewEntry)
194 addResult.storedValue->value = TreeScopeEventContext::create(*treeScope);
195 treeScopeEventContext = addResult.storedValue->value.get();
197 if (isNewEntry) {
198 TreeScopeEventContext* parentTreeScopeEventContext = ensureTreeScopeEventContext(0, treeScope->olderShadowRootOrParentTreeScope(), treeScopeEventContextMap);
199 if (parentTreeScopeEventContext && parentTreeScopeEventContext->target()) {
200 treeScopeEventContext->setTarget(parentTreeScopeEventContext->target());
201 } else if (currentTarget) {
202 treeScopeEventContext->setTarget(eventTargetRespectingTargetRules(*currentTarget));
204 } else if (!treeScopeEventContext->target() && currentTarget) {
205 treeScopeEventContext->setTarget(eventTargetRespectingTargetRules(*currentTarget));
207 return treeScopeEventContext;
210 void EventPath::calculateAdjustedTargets()
212 const TreeScope* lastTreeScope = nullptr;
214 TreeScopeEventContextMap treeScopeEventContextMap;
215 TreeScopeEventContext* lastTreeScopeEventContext = nullptr;
217 for (size_t i = 0; i < size(); ++i) {
218 Node* currentNode = at(i).node();
219 TreeScope& currentTreeScope = currentNode->treeScope();
220 if (lastTreeScope != &currentTreeScope) {
221 lastTreeScopeEventContext = ensureTreeScopeEventContext(currentNode, &currentTreeScope, treeScopeEventContextMap);
223 ASSERT(lastTreeScopeEventContext);
224 at(i).setTreeScopeEventContext(lastTreeScopeEventContext);
225 lastTreeScope = &currentTreeScope;
227 m_treeScopeEventContexts.appendRange(treeScopeEventContextMap.values().begin(), treeScopeEventContextMap.values().end());
230 void EventPath::buildRelatedNodeMap(const Node& relatedNode, RelatedTargetMap& relatedTargetMap)
232 OwnPtrWillBeRawPtr<EventPath> relatedTargetEventPath = adoptPtrWillBeNoop(new EventPath(const_cast<Node&>(relatedNode)));
233 for (size_t i = 0; i < relatedTargetEventPath->m_treeScopeEventContexts.size(); ++i) {
234 TreeScopeEventContext* treeScopeEventContext = relatedTargetEventPath->m_treeScopeEventContexts[i].get();
235 relatedTargetMap.add(&treeScopeEventContext->treeScope(), treeScopeEventContext->target());
237 #if ENABLE(OILPAN)
238 // Oilpan: It is important to explicitly clear the vectors to reuse
239 // the memory in subsequent event dispatchings.
240 relatedTargetEventPath->clear();
241 #endif
244 EventTarget* EventPath::findRelatedNode(TreeScope& scope, RelatedTargetMap& relatedTargetMap)
246 WillBeHeapVector<RawPtrWillBeMember<TreeScope>, 32> parentTreeScopes;
247 EventTarget* relatedNode = nullptr;
248 for (TreeScope* current = &scope; current; current = current->olderShadowRootOrParentTreeScope()) {
249 parentTreeScopes.append(current);
250 RelatedTargetMap::const_iterator iter = relatedTargetMap.find(current);
251 if (iter != relatedTargetMap.end() && iter->value) {
252 relatedNode = iter->value;
253 break;
256 ASSERT(relatedNode);
257 for (const auto& entry : parentTreeScopes)
258 relatedTargetMap.add(entry, relatedNode);
260 return relatedNode;
263 void EventPath::adjustForRelatedTarget(Node& target, EventTarget* relatedTarget)
265 if (!relatedTarget)
266 return;
267 Node* relatedNode = relatedTarget->toNode();
268 if (!relatedNode)
269 return;
270 if (target.document() != relatedNode->document())
271 return;
272 if (!target.inDocument() || !relatedNode->inDocument())
273 return;
275 RelatedTargetMap relatedNodeMap;
276 buildRelatedNodeMap(*relatedNode, relatedNodeMap);
278 for (const auto& treeScopeEventContext : m_treeScopeEventContexts) {
279 EventTarget* adjustedRelatedTarget = findRelatedNode(treeScopeEventContext->treeScope(), relatedNodeMap);
280 ASSERT(adjustedRelatedTarget);
281 treeScopeEventContext.get()->setRelatedTarget(adjustedRelatedTarget);
284 shrinkIfNeeded(target, *relatedTarget);
287 void EventPath::shrinkIfNeeded(const Node& target, const EventTarget& relatedTarget)
289 // Synthetic mouse events can have a relatedTarget which is identical to the target.
290 bool targetIsIdenticalToToRelatedTarget = (&target == &relatedTarget);
292 for (size_t i = 0; i < size(); ++i) {
293 if (targetIsIdenticalToToRelatedTarget) {
294 if (target.treeScope().rootNode() == at(i).node()) {
295 shrink(i + 1);
296 break;
298 } else if (at(i).target() == at(i).relatedTarget()) {
299 // Event dispatching should be stopped here.
300 shrink(i);
301 break;
306 void EventPath::adjustForTouchEvent(TouchEvent& touchEvent)
308 WillBeHeapVector<RawPtrWillBeMember<TouchList>> adjustedTouches;
309 WillBeHeapVector<RawPtrWillBeMember<TouchList>> adjustedTargetTouches;
310 WillBeHeapVector<RawPtrWillBeMember<TouchList>> adjustedChangedTouches;
311 WillBeHeapVector<RawPtrWillBeMember<TreeScope>> treeScopes;
313 for (const auto& treeScopeEventContext : m_treeScopeEventContexts) {
314 TouchEventContext* touchEventContext = treeScopeEventContext->ensureTouchEventContext();
315 adjustedTouches.append(&touchEventContext->touches());
316 adjustedTargetTouches.append(&touchEventContext->targetTouches());
317 adjustedChangedTouches.append(&touchEventContext->changedTouches());
318 treeScopes.append(&treeScopeEventContext->treeScope());
321 adjustTouchList(touchEvent.touches(), adjustedTouches, treeScopes);
322 adjustTouchList(touchEvent.targetTouches(), adjustedTargetTouches, treeScopes);
323 adjustTouchList(touchEvent.changedTouches(), adjustedChangedTouches, treeScopes);
325 #if ENABLE(ASSERT)
326 for (const auto& treeScopeEventContext : m_treeScopeEventContexts) {
327 TreeScope& treeScope = treeScopeEventContext->treeScope();
328 TouchEventContext* touchEventContext = treeScopeEventContext->touchEventContext();
329 checkReachability(treeScope, touchEventContext->touches());
330 checkReachability(treeScope, touchEventContext->targetTouches());
331 checkReachability(treeScope, touchEventContext->changedTouches());
333 #endif
336 void EventPath::adjustTouchList(const TouchList* touchList, WillBeHeapVector<RawPtrWillBeMember<TouchList>> adjustedTouchList, const WillBeHeapVector<RawPtrWillBeMember<TreeScope>>& treeScopes)
338 if (!touchList)
339 return;
340 for (size_t i = 0; i < touchList->length(); ++i) {
341 const Touch& touch = *touchList->item(i);
342 if (!touch.target())
343 continue;
345 Node* targetNode = touch.target()->toNode();
346 if (!targetNode)
347 continue;
349 RelatedTargetMap relatedNodeMap;
350 buildRelatedNodeMap(*targetNode, relatedNodeMap);
351 for (size_t j = 0; j < treeScopes.size(); ++j) {
352 adjustedTouchList[j]->append(touch.cloneWithNewTarget(findRelatedNode(*treeScopes[j], relatedNodeMap)));
357 const NodeEventContext& EventPath::topNodeEventContext()
359 ASSERT(!isEmpty());
360 return last();
363 void EventPath::ensureWindowEventContext()
365 ASSERT(m_event);
366 if (!m_windowEventContext)
367 m_windowEventContext = adoptPtrWillBeNoop(new WindowEventContext(*m_event, topNodeEventContext()));
370 #if ENABLE(ASSERT)
371 void EventPath::checkReachability(TreeScope& treeScope, TouchList& touchList)
373 for (size_t i = 0; i < touchList.length(); ++i)
374 ASSERT(touchList.item(i)->target()->toNode()->treeScope().isInclusiveOlderSiblingShadowRootOrAncestorTreeScopeOf(treeScope));
376 #endif
378 DEFINE_TRACE(EventPath)
380 #if ENABLE(OILPAN)
381 visitor->trace(m_nodeEventContexts);
382 visitor->trace(m_node);
383 visitor->trace(m_event);
384 visitor->trace(m_treeScopeEventContexts);
385 visitor->trace(m_windowEventContext);
386 #endif
389 } // namespace