1 /*
2 * Copyright (C) 2011 Google Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 *
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.
13 *
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.
25 */
26
27 #include "third_party/blink/renderer/core/dom/shadow_root.h"
28
29 #include "third_party/blink/public/platform/platform.h"
30 #include "third_party/blink/renderer/bindings/core/v8/v8_set_inner_html_options.h"
31 #include "third_party/blink/renderer/core/css/resolver/style_resolver.h"
32 #include "third_party/blink/renderer/core/css/style_change_reason.h"
33 #include "third_party/blink/renderer/core/css/style_engine.h"
34 #include "third_party/blink/renderer/core/css/style_sheet_list.h"
35 #include "third_party/blink/renderer/core/dom/element_traversal.h"
36 #include "third_party/blink/renderer/core/dom/events/event_dispatch_forbidden_scope.h"
37 #include "third_party/blink/renderer/core/dom/shadow_root_v0.h"
38 #include "third_party/blink/renderer/core/dom/slot_assignment.h"
39 #include "third_party/blink/renderer/core/dom/slot_assignment_engine.h"
40 #include "third_party/blink/renderer/core/dom/text.h"
41 #include "third_party/blink/renderer/core/dom/v0_insertion_point.h"
42 #include "third_party/blink/renderer/core/dom/whitespace_attacher.h"
43 #include "third_party/blink/renderer/core/editing/serializers/serialization.h"
44 #include "third_party/blink/renderer/core/html/html_content_element.h"
45 #include "third_party/blink/renderer/core/html/html_shadow_element.h"
46 #include "third_party/blink/renderer/core/html/html_slot_element.h"
47 #include "third_party/blink/renderer/core/layout/layout_object.h"
48 #include "third_party/blink/renderer/core/trustedtypes/trusted_types_util.h"
49 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
50 #include "third_party/blink/renderer/platform/wtf/size_assertions.h"
51
52 namespace blink {
53
Distribute()54 void ShadowRoot::Distribute() {
55 if (!IsV1())
56 V0().Distribute();
57 }
58
59 struct SameSizeAsShadowRoot : public DocumentFragment, public TreeScope {
60 Member<void*> member[3];
61 unsigned flags[1];
62 };
63
64 ASSERT_SIZE(ShadowRoot, SameSizeAsShadowRoot);
65
ShadowRoot(Document & document,ShadowRootType type)66 ShadowRoot::ShadowRoot(Document& document, ShadowRootType type)
67 : DocumentFragment(nullptr, kCreateShadowRoot),
68 TreeScope(*this, document),
69 style_sheet_list_(nullptr),
70 child_shadow_root_count_(0),
71 type_(static_cast<unsigned>(type)),
72 registered_with_parent_shadow_root_(false),
73 delegates_focus_(false),
74 slot_assignment_mode_(static_cast<unsigned>(SlotAssignmentMode::kAuto)),
75 needs_distribution_recalc_(false),
76 unused_(0) {
77 if (IsV0())
78 shadow_root_v0_ = MakeGarbageCollected<ShadowRootV0>(*this);
79 }
80
81 ShadowRoot::~ShadowRoot() = default;
82
EnsureSlotAssignment()83 SlotAssignment& ShadowRoot::EnsureSlotAssignment() {
84 if (!slot_assignment_)
85 slot_assignment_ = MakeGarbageCollected<SlotAssignment>(*this);
86 return *slot_assignment_;
87 }
88
AssignedSlotFor(const Node & node)89 HTMLSlotElement* ShadowRoot::AssignedSlotFor(const Node& node) {
90 if (!slot_assignment_)
91 return nullptr;
92 return slot_assignment_->FindSlot(node);
93 }
94
DidAddSlot(HTMLSlotElement & slot)95 void ShadowRoot::DidAddSlot(HTMLSlotElement& slot) {
96 DCHECK(IsV1());
97 EnsureSlotAssignment().DidAddSlot(slot);
98 }
99
DidChangeHostChildSlotName(const AtomicString & old_value,const AtomicString & new_value)100 void ShadowRoot::DidChangeHostChildSlotName(const AtomicString& old_value,
101 const AtomicString& new_value) {
102 if (!slot_assignment_)
103 return;
104 slot_assignment_->DidChangeHostChildSlotName(old_value, new_value);
105 }
106
Clone(Document &,CloneChildrenFlag) const107 Node* ShadowRoot::Clone(Document&, CloneChildrenFlag) const {
108 NOTREACHED() << "ShadowRoot nodes are not clonable.";
109 return nullptr;
110 }
111
SetSlotAssignmentMode(SlotAssignmentMode assignment_mode)112 void ShadowRoot::SetSlotAssignmentMode(SlotAssignmentMode assignment_mode) {
113 slot_assignment_mode_ = static_cast<unsigned>(assignment_mode);
114 }
115
innerHTML() const116 String ShadowRoot::innerHTML() const {
117 return CreateMarkup(this, kChildrenOnly);
118 }
119
SetInnerHTMLInternal(const String & html,const SetInnerHTMLOptions * options,ExceptionState & exception_state)120 void ShadowRoot::SetInnerHTMLInternal(const String& html,
121 const SetInnerHTMLOptions* options,
122 ExceptionState& exception_state) {
123 bool allow_shadow_root =
124 options->hasAllowShadowRoot() && options->allowShadowRoot();
125 if (DocumentFragment* fragment = CreateFragmentForInnerOuterHTML(
126 html, &host(), kAllowScriptingContent, "innerHTML", allow_shadow_root,
127 exception_state)) {
128 ReplaceChildrenWithFragment(this, fragment, exception_state);
129 }
130 }
131
setInnerHTML(const String & html,ExceptionState & exception_state)132 void ShadowRoot::setInnerHTML(const String& html,
133 ExceptionState& exception_state) {
134 const SetInnerHTMLOptions options;
135 SetInnerHTMLInternal(html, &options, exception_state);
136 }
137
setInnerHTMLWithOptions(const String & html,const SetInnerHTMLOptions * options,ExceptionState & exception_state)138 void ShadowRoot::setInnerHTMLWithOptions(const String& html,
139 const SetInnerHTMLOptions* options,
140 ExceptionState& exception_state) {
141 DCHECK(RuntimeEnabledFeatures::DeclarativeShadowDOMEnabled(
142 GetExecutionContext()));
143 SetInnerHTMLInternal(html, options, exception_state);
144 }
145
RebuildLayoutTree(WhitespaceAttacher & whitespace_attacher)146 void ShadowRoot::RebuildLayoutTree(WhitespaceAttacher& whitespace_attacher) {
147 DCHECK(!NeedsReattachLayoutTree());
148 DCHECK(!ChildNeedsReattachLayoutTree());
149 RebuildChildrenLayoutTrees(whitespace_attacher);
150 }
151
InsertedInto(ContainerNode & insertion_point)152 Node::InsertionNotificationRequest ShadowRoot::InsertedInto(
153 ContainerNode& insertion_point) {
154 DocumentFragment::InsertedInto(insertion_point);
155
156 if (!insertion_point.isConnected())
157 return kInsertionDone;
158
159 GetDocument().GetStyleEngine().ShadowRootInsertedToDocument(*this);
160
161 GetDocument().GetSlotAssignmentEngine().Connected(*this);
162
163 // FIXME: When parsing <video controls>, InsertedInto() is called many times
164 // without invoking RemovedFrom(). For now, we check
165 // registered_with_parent_shadow_root. We would like to
166 // DCHECK(!registered_with_parent_shadow_root) here.
167 // https://bugs.webkit.org/show_bug.cig?id=101316
168 if (registered_with_parent_shadow_root_)
169 return kInsertionDone;
170
171 if (ShadowRoot* root = host().ContainingShadowRoot()) {
172 root->AddChildShadowRoot();
173 registered_with_parent_shadow_root_ = true;
174 }
175
176 return kInsertionDone;
177 }
178
RemovedFrom(ContainerNode & insertion_point)179 void ShadowRoot::RemovedFrom(ContainerNode& insertion_point) {
180 if (insertion_point.isConnected()) {
181 if (NeedsSlotAssignmentRecalc())
182 GetDocument().GetSlotAssignmentEngine().Disconnected(*this);
183 GetDocument().GetStyleEngine().ShadowRootRemovedFromDocument(this);
184 if (registered_with_parent_shadow_root_) {
185 ShadowRoot* root = host().ContainingShadowRoot();
186 if (!root)
187 root = insertion_point.ContainingShadowRoot();
188 if (root)
189 root->RemoveChildShadowRoot();
190 registered_with_parent_shadow_root_ = false;
191 }
192 }
193
194 DocumentFragment::RemovedFrom(insertion_point);
195 }
196
SetNeedsAssignmentRecalc()197 void ShadowRoot::SetNeedsAssignmentRecalc() {
198 DCHECK(IsV1());
199 if (!slot_assignment_)
200 return;
201 return slot_assignment_->SetNeedsAssignmentRecalc();
202 }
203
NeedsSlotAssignmentRecalc() const204 bool ShadowRoot::NeedsSlotAssignmentRecalc() const {
205 return slot_assignment_ && slot_assignment_->NeedsAssignmentRecalc();
206 }
207
ChildrenChanged(const ChildrenChange & change)208 void ShadowRoot::ChildrenChanged(const ChildrenChange& change) {
209 ContainerNode::ChildrenChanged(change);
210
211 if (change.IsChildElementChange()) {
212 CheckForSiblingStyleChanges(
213 change.type == ChildrenChangeType::kElementRemoved
214 ? kSiblingElementRemoved
215 : kSiblingElementInserted,
216 To<Element>(change.sibling_changed), change.sibling_before_change,
217 change.sibling_after_change);
218 }
219 }
220
StyleSheets()221 StyleSheetList& ShadowRoot::StyleSheets() {
222 if (!style_sheet_list_)
223 SetStyleSheets(MakeGarbageCollected<StyleSheetList>(this));
224 return *style_sheet_list_;
225 }
226
SetNeedsDistributionRecalcWillBeSetNeedsAssignmentRecalc()227 void ShadowRoot::SetNeedsDistributionRecalcWillBeSetNeedsAssignmentRecalc() {
228 if (IsV1())
229 SetNeedsAssignmentRecalc();
230 else
231 SetNeedsDistributionRecalc();
232 }
233
SetNeedsDistributionRecalc()234 void ShadowRoot::SetNeedsDistributionRecalc() {
235 DCHECK(!IsV1());
236 if (needs_distribution_recalc_)
237 return;
238 needs_distribution_recalc_ = true;
239 host().MarkAncestorsWithChildNeedsDistributionRecalc();
240 }
241
Trace(Visitor * visitor) const242 void ShadowRoot::Trace(Visitor* visitor) const {
243 visitor->Trace(style_sheet_list_);
244 visitor->Trace(slot_assignment_);
245 visitor->Trace(shadow_root_v0_);
246 TreeScope::Trace(visitor);
247 DocumentFragment::Trace(visitor);
248 }
249
operator <<(std::ostream & ostream,const ShadowRootType & type)250 std::ostream& operator<<(std::ostream& ostream, const ShadowRootType& type) {
251 switch (type) {
252 case ShadowRootType::kUserAgent:
253 ostream << "UserAgent";
254 break;
255 case ShadowRootType::V0:
256 ostream << "V0";
257 break;
258 case ShadowRootType::kOpen:
259 ostream << "Open";
260 break;
261 case ShadowRootType::kClosed:
262 ostream << "Closed";
263 break;
264 }
265 return ostream;
266 }
267
268 } // namespace blink
269