1 /*
2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3 * (C) 1999 Antti Koivisto (koivisto@kde.org)
4 * (C) 2001 Dirk Mueller (mueller@kde.org)
5 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All
6 * rights reserved.
7 * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
8 * Copyright (C) 2009 Torch Mobile Inc. All rights reserved.
9 * (http://www.torchmobile.com/)
10 * Copyright (C) 2011 Google Inc. All rights reserved.
11 *
12 * This library is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Library General Public
14 * License as published by the Free Software Foundation; either
15 * version 2 of the License, or (at your option) any later version.
16 *
17 * This library is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Library General Public License for more details.
21 *
22 * You should have received a copy of the GNU Library General Public License
23 * along with this library; see the file COPYING.LIB. If not, write to
24 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
25 * Boston, MA 02110-1301, USA.
26 */
27 #include "third_party/blink/renderer/core/dom/tree_scope_adopter.h"
28
29 #include "third_party/blink/renderer/core/dom/attr.h"
30 #include "third_party/blink/renderer/core/dom/document.h"
31 #include "third_party/blink/renderer/core/dom/node.h"
32 #include "third_party/blink/renderer/core/dom/node_lists_node_data.h"
33 #include "third_party/blink/renderer/core/dom/node_rare_data.h"
34 #include "third_party/blink/renderer/core/dom/node_traversal.h"
35 #include "third_party/blink/renderer/core/dom/shadow_root.h"
36 #include "third_party/blink/renderer/core/html/custom/custom_element.h"
37
38 namespace blink {
39
Execute() const40 void TreeScopeAdopter::Execute() const {
41 MoveTreeToNewScope(*to_adopt_);
42 Document& old_document = OldScope().GetDocument();
43 if (old_document == NewScope().GetDocument())
44 return;
45 old_document.DidMoveTreeToNewDocument(*to_adopt_);
46 }
47
MoveTreeToNewScope(Node & root) const48 void TreeScopeAdopter::MoveTreeToNewScope(Node& root) const {
49 DCHECK(NeedsScopeChange());
50
51 // If an element is moved from a document and then eventually back again the
52 // collection cache for that element may contain stale data as changes made to
53 // it will have updated the DOMTreeVersion of the document it was moved to. By
54 // increasing the DOMTreeVersion of the donating document here we ensure that
55 // the collection cache will be invalidated as needed when the element is
56 // moved back.
57 Document& old_document = OldScope().GetDocument();
58 Document& new_document = NewScope().GetDocument();
59 bool will_move_to_new_document = old_document != new_document;
60
61 for (Node& node : NodeTraversal::InclusiveDescendantsOf(root)) {
62 UpdateTreeScope(node);
63
64 if (will_move_to_new_document) {
65 MoveNodeToNewDocument(node, old_document, new_document);
66 } else if (node.HasRareData()) {
67 NodeRareData* rare_data = node.RareData();
68 if (rare_data->NodeLists())
69 rare_data->NodeLists()->AdoptTreeScope();
70 }
71
72 auto* element = DynamicTo<Element>(node);
73 if (!element)
74 continue;
75
76 if (HeapVector<Member<Attr>>* attrs = element->GetAttrNodeList()) {
77 for (const auto& attr : *attrs)
78 MoveTreeToNewScope(*attr);
79 }
80
81 if (ShadowRoot* shadow = element->GetShadowRoot()) {
82 shadow->SetParentTreeScope(NewScope());
83 if (will_move_to_new_document)
84 MoveShadowTreeToNewDocument(*shadow, old_document, new_document);
85 }
86 }
87 }
88
MoveShadowTreeToNewDocument(ShadowRoot & shadow_root,Document & old_document,Document & new_document) const89 void TreeScopeAdopter::MoveShadowTreeToNewDocument(
90 ShadowRoot& shadow_root,
91 Document& old_document,
92 Document& new_document) const {
93 DCHECK_NE(old_document, new_document);
94 HeapVector<Member<CSSStyleSheet>> empty_vector;
95 shadow_root.SetAdoptedStyleSheets(empty_vector);
96
97 if (shadow_root.GetType() == ShadowRootType::V0) {
98 new_document.SetShadowCascadeOrder(ShadowCascadeOrder::kShadowCascadeV0);
99 } else if (shadow_root.IsV1() && !shadow_root.IsUserAgent()) {
100 new_document.SetShadowCascadeOrder(ShadowCascadeOrder::kShadowCascadeV1);
101 }
102 MoveTreeToNewDocument(shadow_root, old_document, new_document);
103 }
104
MoveTreeToNewDocument(Node & root,Document & old_document,Document & new_document) const105 void TreeScopeAdopter::MoveTreeToNewDocument(Node& root,
106 Document& old_document,
107 Document& new_document) const {
108 DCHECK_NE(old_document, new_document);
109 for (Node& node : NodeTraversal::InclusiveDescendantsOf(root)) {
110 MoveNodeToNewDocument(node, old_document, new_document);
111
112 auto* element = DynamicTo<Element>(node);
113 if (!element)
114 continue;
115
116 if (HeapVector<Member<Attr>>* attrs = element->GetAttrNodeList()) {
117 for (const auto& attr : *attrs)
118 MoveTreeToNewDocument(*attr, old_document, new_document);
119 }
120
121 if (ShadowRoot* shadow_root = element->GetShadowRoot())
122 MoveShadowTreeToNewDocument(*shadow_root, old_document, new_document);
123 }
124 }
125
126 #if DCHECK_IS_ON()
127 static bool g_did_move_to_new_document_was_called = false;
128 static Document* g_old_document_did_move_to_new_document_was_called_with =
129 nullptr;
130
EnsureDidMoveToNewDocumentWasCalled(Document & old_document)131 void TreeScopeAdopter::EnsureDidMoveToNewDocumentWasCalled(
132 Document& old_document) {
133 DCHECK(!g_did_move_to_new_document_was_called);
134 DCHECK_EQ(old_document,
135 g_old_document_did_move_to_new_document_was_called_with);
136 g_did_move_to_new_document_was_called = true;
137 }
138 #endif
139
UpdateTreeScope(Node & node) const140 inline void TreeScopeAdopter::UpdateTreeScope(Node& node) const {
141 DCHECK(!node.IsTreeScope());
142 DCHECK(node.GetTreeScope() == OldScope());
143 node.SetTreeScope(new_scope_);
144 }
145
MoveNodeToNewDocument(Node & node,Document & old_document,Document & new_document) const146 inline void TreeScopeAdopter::MoveNodeToNewDocument(
147 Node& node,
148 Document& old_document,
149 Document& new_document) const {
150 DCHECK_NE(old_document, new_document);
151 // Note: at the start of this function, node.document() may already have
152 // changed to match |newDocument|, which is why |oldDocument| is passed in.
153
154 if (node.HasRareData()) {
155 NodeRareData* rare_data = node.RareData();
156 if (rare_data->NodeLists())
157 rare_data->NodeLists()->AdoptDocument(old_document, new_document);
158 }
159
160 node.WillMoveToNewDocument(old_document, new_document);
161 old_document.MoveNodeIteratorsToNewDocument(node, new_document);
162
163 if (node.GetCustomElementState() == CustomElementState::kCustom) {
164 CustomElement::EnqueueAdoptedCallback(To<Element>(node), old_document,
165 new_document);
166 }
167
168 if (auto* shadow_root = DynamicTo<ShadowRoot>(node))
169 shadow_root->SetDocument(new_document);
170
171 #if DCHECK_IS_ON()
172 g_did_move_to_new_document_was_called = false;
173 g_old_document_did_move_to_new_document_was_called_with = &old_document;
174 #endif
175
176 node.DidMoveToNewDocument(old_document);
177 #if DCHECK_IS_ON()
178 DCHECK(g_did_move_to_new_document_was_called);
179 #endif
180 }
181
182 } // namespace blink
183