1 /*
2 * (C) 1999-2003 Lars Knoll (knoll@kde.org)
3 * Copyright (C) 2004, 2006, 2007, 2012 Apple Inc. All rights reserved.
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public License
16 * along with this library; see the file COPYING.LIB. If not, write to
17 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
19 */
20
21 #include "third_party/blink/renderer/core/css/css_style_sheet.h"
22
23 #include "third_party/blink/renderer/bindings/core/v8/media_list_or_string.h"
24 #include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
25 #include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
26 #include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h"
27 #include "third_party/blink/renderer/bindings/core/v8/v8_css_style_sheet_init.h"
28 #include "third_party/blink/renderer/core/css/css_import_rule.h"
29 #include "third_party/blink/renderer/core/css/css_rule_list.h"
30 #include "third_party/blink/renderer/core/css/media_list.h"
31 #include "third_party/blink/renderer/core/css/parser/css_parser.h"
32 #include "third_party/blink/renderer/core/css/parser/css_parser_context.h"
33 #include "third_party/blink/renderer/core/css/parser/css_parser_impl.h"
34 #include "third_party/blink/renderer/core/css/style_engine.h"
35 #include "third_party/blink/renderer/core/css/style_rule.h"
36 #include "third_party/blink/renderer/core/css/style_sheet_contents.h"
37 #include "third_party/blink/renderer/core/dom/document.h"
38 #include "third_party/blink/renderer/core/dom/node.h"
39 #include "third_party/blink/renderer/core/frame/deprecation.h"
40 #include "third_party/blink/renderer/core/html/html_link_element.h"
41 #include "third_party/blink/renderer/core/html/html_style_element.h"
42 #include "third_party/blink/renderer/core/html_names.h"
43 #include "third_party/blink/renderer/core/inspector/console_message.h"
44 #include "third_party/blink/renderer/core/probe/core_probes.h"
45 #include "third_party/blink/renderer/core/svg/svg_style_element.h"
46 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
47 #include "third_party/blink/renderer/platform/bindings/script_state.h"
48 #include "third_party/blink/renderer/platform/bindings/v8_per_isolate_data.h"
49 #include "third_party/blink/renderer/platform/heap/heap.h"
50 #include "third_party/blink/renderer/platform/weborigin/security_origin.h"
51 #include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
52
53 namespace blink {
54
55 class StyleSheetCSSRuleList final : public CSSRuleList {
56 public:
StyleSheetCSSRuleList(CSSStyleSheet * sheet)57 StyleSheetCSSRuleList(CSSStyleSheet* sheet) : style_sheet_(sheet) {}
58
Trace(Visitor * visitor) const59 void Trace(Visitor* visitor) const override {
60 visitor->Trace(style_sheet_);
61 CSSRuleList::Trace(visitor);
62 }
63
64 private:
length() const65 unsigned length() const override { return style_sheet_->length(); }
item(unsigned index) const66 CSSRule* item(unsigned index) const override {
67 return style_sheet_->item(index);
68 }
69
GetStyleSheet() const70 CSSStyleSheet* GetStyleSheet() const override { return style_sheet_; }
71
72 Member<CSSStyleSheet> style_sheet_;
73 };
74
75 #if DCHECK_IS_ON()
IsAcceptableCSSStyleSheetParent(const Node & parent_node)76 static bool IsAcceptableCSSStyleSheetParent(const Node& parent_node) {
77 // Only these nodes can be parents of StyleSheets, and they need to call
78 // clearOwnerNode() when moved out of document. Note that destructor of
79 // the nodes don't call clearOwnerNode() with Oilpan.
80 return parent_node.IsDocumentNode() || IsA<HTMLLinkElement>(parent_node) ||
81 IsA<HTMLStyleElement>(parent_node) ||
82 IsA<SVGStyleElement>(parent_node) ||
83 parent_node.getNodeType() == Node::kProcessingInstructionNode;
84 }
85 #endif
86
87 // static
SingleOwnerDocument(const CSSStyleSheet * style_sheet)88 const Document* CSSStyleSheet::SingleOwnerDocument(
89 const CSSStyleSheet* style_sheet) {
90 if (style_sheet)
91 return StyleSheetContents::SingleOwnerDocument(style_sheet->Contents());
92 return nullptr;
93 }
94
Create(Document & document,const CSSStyleSheetInit * options,ExceptionState & exception_state)95 CSSStyleSheet* CSSStyleSheet::Create(Document& document,
96 const CSSStyleSheetInit* options,
97 ExceptionState& exception_state) {
98 auto* parser_context = MakeGarbageCollected<CSSParserContext>(document);
99 if (AdTracker::IsAdScriptExecutingInDocument(&document))
100 parser_context->SetIsAdRelated();
101
102 // Following steps at spec draft
103 // https://wicg.github.io/construct-stylesheets/#dom-cssstylesheet-cssstylesheet
104 auto* contents = MakeGarbageCollected<StyleSheetContents>(parser_context);
105 CSSStyleSheet* sheet = MakeGarbageCollected<CSSStyleSheet>(contents, nullptr);
106 sheet->SetConstructorDocument(document);
107 sheet->SetTitle(options->title());
108 sheet->ClearOwnerNode();
109 sheet->ClearOwnerRule();
110 contents->RegisterClient(sheet);
111 scoped_refptr<MediaQuerySet> media_query_set;
112 if (options->media().IsString()) {
113 media_query_set = MediaQuerySet::Create(options->media().GetAsString(),
114 document.GetExecutionContext());
115 } else {
116 media_query_set = options->media().GetAsMediaList()->Queries()->Copy();
117 }
118 auto* media_list = MakeGarbageCollected<MediaList>(
119 media_query_set, const_cast<CSSStyleSheet*>(sheet));
120 sheet->SetMedia(media_list);
121 if (options->alternate())
122 sheet->SetAlternateFromConstructor(true);
123 if (options->disabled())
124 sheet->setDisabled(true);
125 return sheet;
126 }
127
CreateInline(StyleSheetContents * sheet,Node & owner_node,const TextPosition & start_position)128 CSSStyleSheet* CSSStyleSheet::CreateInline(StyleSheetContents* sheet,
129 Node& owner_node,
130 const TextPosition& start_position) {
131 DCHECK(sheet);
132 return MakeGarbageCollected<CSSStyleSheet>(sheet, owner_node, true,
133 start_position);
134 }
135
CreateInline(Node & owner_node,const KURL & base_url,const TextPosition & start_position,const WTF::TextEncoding & encoding)136 CSSStyleSheet* CSSStyleSheet::CreateInline(Node& owner_node,
137 const KURL& base_url,
138 const TextPosition& start_position,
139 const WTF::TextEncoding& encoding) {
140 auto* parser_context = MakeGarbageCollected<CSSParserContext>(
141 owner_node.GetDocument(), owner_node.GetDocument().BaseURL(),
142 true /* origin_clean */, owner_node.GetDocument().GetReferrerPolicy(),
143 encoding);
144 if (AdTracker::IsAdScriptExecutingInDocument(&owner_node.GetDocument()))
145 parser_context->SetIsAdRelated();
146 auto* sheet = MakeGarbageCollected<StyleSheetContents>(parser_context,
147 base_url.GetString());
148 return MakeGarbageCollected<CSSStyleSheet>(sheet, owner_node, true,
149 start_position);
150 }
151
CSSStyleSheet(StyleSheetContents * contents,CSSImportRule * owner_rule)152 CSSStyleSheet::CSSStyleSheet(StyleSheetContents* contents,
153 CSSImportRule* owner_rule)
154 : contents_(contents),
155 owner_rule_(owner_rule),
156 start_position_(TextPosition::MinimumPosition()) {
157 contents_->RegisterClient(this);
158 }
159
CSSStyleSheet(StyleSheetContents * contents,Node & owner_node,bool is_inline_stylesheet,const TextPosition & start_position)160 CSSStyleSheet::CSSStyleSheet(StyleSheetContents* contents,
161 Node& owner_node,
162 bool is_inline_stylesheet,
163 const TextPosition& start_position)
164 : contents_(contents),
165 is_inline_stylesheet_(is_inline_stylesheet),
166 owner_node_(&owner_node),
167 start_position_(start_position) {
168 #if DCHECK_IS_ON()
169 DCHECK(IsAcceptableCSSStyleSheetParent(owner_node));
170 #endif
171 contents_->RegisterClient(this);
172 }
173
174 CSSStyleSheet::~CSSStyleSheet() = default;
175
WillMutateRules()176 void CSSStyleSheet::WillMutateRules() {
177 // If we are the only client it is safe to mutate.
178 if (!contents_->IsUsedFromTextCache() &&
179 !contents_->IsReferencedFromResource()) {
180 contents_->ClearRuleSet();
181 contents_->SetMutable();
182 return;
183 }
184 // Only cacheable stylesheets should have multiple clients.
185 DCHECK(contents_->IsCacheableForStyleElement() ||
186 contents_->IsCacheableForResource());
187
188 // Copy-on-write.
189 contents_->UnregisterClient(this);
190 contents_ = contents_->Copy();
191 contents_->RegisterClient(this);
192
193 contents_->SetMutable();
194
195 // Any existing CSSOM wrappers need to be connected to the copied child rules.
196 ReattachChildRuleCSSOMWrappers();
197 }
198
DidMutate(Mutation mutation)199 void CSSStyleSheet::DidMutate(Mutation mutation) {
200 if (mutation == Mutation::kRules) {
201 DCHECK(contents_->IsMutable());
202 DCHECK_LE(contents_->ClientSize(), 1u);
203 }
204 Document* document = OwnerDocument();
205 if (!document || !document->IsActive())
206 return;
207 if (!custom_element_tag_names_.IsEmpty()) {
208 document->GetStyleEngine().ScheduleCustomElementInvalidations(
209 custom_element_tag_names_);
210 }
211 bool invalidate_matched_properties_cache = false;
212 if (ownerNode() && ownerNode()->isConnected()) {
213 document->GetStyleEngine().SetNeedsActiveStyleUpdate(
214 ownerNode()->GetTreeScope());
215 invalidate_matched_properties_cache = true;
216 } else if (!adopted_tree_scopes_.IsEmpty()) {
217 for (auto tree_scope : adopted_tree_scopes_) {
218 // It is currently required that adopted sheets can not be moved between
219 // documents.
220 DCHECK(tree_scope->GetDocument() == document);
221 if (!tree_scope->RootNode().isConnected())
222 continue;
223 document->GetStyleEngine().SetNeedsActiveStyleUpdate(*tree_scope);
224 invalidate_matched_properties_cache = true;
225 }
226 }
227 if (mutation == Mutation::kRules) {
228 if (invalidate_matched_properties_cache)
229 document->GetStyleResolver().InvalidateMatchedPropertiesCache();
230 probe::DidMutateStyleSheet(document, this);
231 }
232 }
233
EnableRuleAccessForInspector()234 void CSSStyleSheet::EnableRuleAccessForInspector() {
235 enable_rule_access_for_inspector_ = true;
236 }
DisableRuleAccessForInspector()237 void CSSStyleSheet::DisableRuleAccessForInspector() {
238 enable_rule_access_for_inspector_ = false;
239 }
240
InspectorMutationScope(CSSStyleSheet * sheet)241 CSSStyleSheet::InspectorMutationScope::InspectorMutationScope(
242 CSSStyleSheet* sheet)
243 : style_sheet_(sheet) {
244 style_sheet_->EnableRuleAccessForInspector();
245 }
246
~InspectorMutationScope()247 CSSStyleSheet::InspectorMutationScope::~InspectorMutationScope() {
248 style_sheet_->DisableRuleAccessForInspector();
249 }
250
ReattachChildRuleCSSOMWrappers()251 void CSSStyleSheet::ReattachChildRuleCSSOMWrappers() {
252 for (unsigned i = 0; i < child_rule_cssom_wrappers_.size(); ++i) {
253 if (!child_rule_cssom_wrappers_[i])
254 continue;
255 child_rule_cssom_wrappers_[i]->Reattach(contents_->RuleAt(i));
256 }
257 }
258
setDisabled(bool disabled)259 void CSSStyleSheet::setDisabled(bool disabled) {
260 if (disabled == is_disabled_)
261 return;
262 is_disabled_ = disabled;
263
264 DidMutate(Mutation::kSheet);
265 }
266
SetMediaQueries(scoped_refptr<MediaQuerySet> media_queries)267 void CSSStyleSheet::SetMediaQueries(
268 scoped_refptr<MediaQuerySet> media_queries) {
269 media_queries_ = std::move(media_queries);
270 if (media_cssom_wrapper_ && media_queries_)
271 media_cssom_wrapper_->Reattach(media_queries_.get());
272 }
273
MatchesMediaQueries(const MediaQueryEvaluator & evaluator)274 bool CSSStyleSheet::MatchesMediaQueries(const MediaQueryEvaluator& evaluator) {
275 viewport_dependent_media_query_results_.clear();
276 device_dependent_media_query_results_.clear();
277
278 if (!media_queries_)
279 return true;
280 return evaluator.Eval(*media_queries_,
281 &viewport_dependent_media_query_results_,
282 &device_dependent_media_query_results_);
283 }
284
length() const285 unsigned CSSStyleSheet::length() const {
286 return contents_->RuleCount();
287 }
288
item(unsigned index)289 CSSRule* CSSStyleSheet::item(unsigned index) {
290 unsigned rule_count = length();
291 if (index >= rule_count)
292 return nullptr;
293
294 if (child_rule_cssom_wrappers_.IsEmpty())
295 child_rule_cssom_wrappers_.Grow(rule_count);
296 DCHECK_EQ(child_rule_cssom_wrappers_.size(), rule_count);
297
298 Member<CSSRule>& css_rule = child_rule_cssom_wrappers_[index];
299 if (!css_rule)
300 css_rule = contents_->RuleAt(index)->CreateCSSOMWrapper(this);
301 return css_rule.Get();
302 }
303
ClearOwnerNode()304 void CSSStyleSheet::ClearOwnerNode() {
305 DidMutate(Mutation::kSheet);
306 if (owner_node_)
307 contents_->UnregisterClient(this);
308 owner_node_ = nullptr;
309 }
310
CanAccessRules() const311 bool CSSStyleSheet::CanAccessRules() const {
312 return enable_rule_access_for_inspector_ || contents_->IsOriginClean();
313 }
314
rules(ExceptionState & exception_state)315 CSSRuleList* CSSStyleSheet::rules(ExceptionState& exception_state) {
316 return cssRules(exception_state);
317 }
318
insertRule(const String & rule_string,unsigned index,ExceptionState & exception_state)319 unsigned CSSStyleSheet::insertRule(const String& rule_string,
320 unsigned index,
321 ExceptionState& exception_state) {
322 if (!CanAccessRules()) {
323 exception_state.ThrowSecurityError(
324 "Cannot access StyleSheet to insertRule");
325 return 0;
326 }
327
328 DCHECK(child_rule_cssom_wrappers_.IsEmpty() ||
329 child_rule_cssom_wrappers_.size() == contents_->RuleCount());
330
331 if (index > length()) {
332 exception_state.ThrowDOMException(
333 DOMExceptionCode::kIndexSizeError,
334 "The index provided (" + String::Number(index) +
335 ") is larger than the maximum index (" + String::Number(length()) +
336 ").");
337 return 0;
338 }
339 const auto* context =
340 MakeGarbageCollected<CSSParserContext>(contents_->ParserContext(), this);
341 StyleRuleBase* rule =
342 CSSParser::ParseRule(context, contents_.Get(), rule_string);
343
344 if (!rule) {
345 exception_state.ThrowDOMException(
346 DOMExceptionCode::kSyntaxError,
347 "Failed to parse the rule '" + rule_string + "'.");
348 return 0;
349 }
350 RuleMutationScope mutation_scope(this);
351 if (rule->IsImportRule() && IsConstructed()) {
352 exception_state.ThrowDOMException(
353 DOMExceptionCode::kSyntaxError,
354 "Can't insert @import rules into a constructed stylesheet.");
355 return 0;
356 }
357 bool success = contents_->WrapperInsertRule(rule, index);
358 if (!success) {
359 if (rule->IsNamespaceRule())
360 exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
361 "Failed to insert the rule");
362 else
363 exception_state.ThrowDOMException(
364 DOMExceptionCode::kHierarchyRequestError,
365 "Failed to insert the rule.");
366 return 0;
367 }
368 if (!child_rule_cssom_wrappers_.IsEmpty())
369 child_rule_cssom_wrappers_.insert(index, Member<CSSRule>(nullptr));
370
371 return index;
372 }
373
deleteRule(unsigned index,ExceptionState & exception_state)374 void CSSStyleSheet::deleteRule(unsigned index,
375 ExceptionState& exception_state) {
376 if (!CanAccessRules()) {
377 exception_state.ThrowSecurityError(
378 "Cannot access StyleSheet to deleteRule");
379 return;
380 }
381
382 DCHECK(child_rule_cssom_wrappers_.IsEmpty() ||
383 child_rule_cssom_wrappers_.size() == contents_->RuleCount());
384
385 if (index >= length()) {
386 if (length()) {
387 exception_state.ThrowDOMException(
388 DOMExceptionCode::kIndexSizeError,
389 "The index provided (" + String::Number(index) +
390 ") is larger than the maximum index (" +
391 String::Number(length() - 1) + ").");
392 } else {
393 exception_state.ThrowDOMException(DOMExceptionCode::kIndexSizeError,
394 "Style sheet is empty (length 0).");
395 }
396 return;
397 }
398 RuleMutationScope mutation_scope(this);
399
400 bool success = contents_->WrapperDeleteRule(index);
401 if (!success) {
402 exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
403 "Failed to delete rule");
404 return;
405 }
406
407 if (!child_rule_cssom_wrappers_.IsEmpty()) {
408 if (child_rule_cssom_wrappers_[index])
409 child_rule_cssom_wrappers_[index]->SetParentStyleSheet(nullptr);
410 child_rule_cssom_wrappers_.EraseAt(index);
411 }
412 }
413
addRule(const String & selector,const String & style,int index,ExceptionState & exception_state)414 int CSSStyleSheet::addRule(const String& selector,
415 const String& style,
416 int index,
417 ExceptionState& exception_state) {
418 StringBuilder text;
419 text.Append(selector);
420 text.Append(" { ");
421 text.Append(style);
422 if (!style.IsEmpty())
423 text.Append(' ');
424 text.Append('}');
425 insertRule(text.ToString(), index, exception_state);
426
427 // As per Microsoft documentation, always return -1.
428 return -1;
429 }
430
addRule(const String & selector,const String & style,ExceptionState & exception_state)431 int CSSStyleSheet::addRule(const String& selector,
432 const String& style,
433 ExceptionState& exception_state) {
434 return addRule(selector, style, length(), exception_state);
435 }
436
replace(ScriptState * script_state,const String & text)437 ScriptPromise CSSStyleSheet::replace(ScriptState* script_state,
438 const String& text) {
439 if (!IsConstructed()) {
440 return ScriptPromise::RejectWithDOMException(
441 script_state,
442 MakeGarbageCollected<DOMException>(
443 DOMExceptionCode::kNotAllowedError,
444 "Can't call replace on non-constructed CSSStyleSheets."));
445 }
446 SetText(text, CSSImportRules::kIgnoreWithWarning);
447 // We currently parse synchronously, and since @import support was removed,
448 // nothing else happens asynchronously. This API is left as-is, so that future
449 // async parsing can still be supported here.
450 return ScriptPromise::Cast(script_state, ToV8(this, script_state));
451 }
452
replaceSync(const String & text,ExceptionState & exception_state)453 void CSSStyleSheet::replaceSync(const String& text,
454 ExceptionState& exception_state) {
455 if (!IsConstructed()) {
456 return exception_state.ThrowDOMException(
457 DOMExceptionCode::kNotAllowedError,
458 "Can't call replaceSync on non-constructed CSSStyleSheets.");
459 }
460 SetText(text, CSSImportRules::kIgnoreWithWarning);
461 }
462
cssRules(ExceptionState & exception_state)463 CSSRuleList* CSSStyleSheet::cssRules(ExceptionState& exception_state) {
464 if (!CanAccessRules()) {
465 exception_state.ThrowSecurityError("Cannot access rules");
466 return nullptr;
467 }
468 if (!rule_list_cssom_wrapper_) {
469 rule_list_cssom_wrapper_ =
470 MakeGarbageCollected<StyleSheetCSSRuleList>(this);
471 }
472 return rule_list_cssom_wrapper_.Get();
473 }
474
href() const475 String CSSStyleSheet::href() const {
476 return contents_->OriginalURL();
477 }
478
BaseURL() const479 KURL CSSStyleSheet::BaseURL() const {
480 return contents_->BaseURL();
481 }
482
IsLoading() const483 bool CSSStyleSheet::IsLoading() const {
484 return contents_->IsLoading();
485 }
486
media()487 MediaList* CSSStyleSheet::media() {
488 if (!media_queries_)
489 media_queries_ = MediaQuerySet::Create();
490
491 if (!media_cssom_wrapper_) {
492 media_cssom_wrapper_ = MakeGarbageCollected<MediaList>(
493 media_queries_.get(), const_cast<CSSStyleSheet*>(this));
494 }
495 return media_cssom_wrapper_.Get();
496 }
497
SetMedia(MediaList * media_list)498 void CSSStyleSheet::SetMedia(MediaList* media_list) {
499 media_cssom_wrapper_ = media_list;
500 }
501
parentStyleSheet() const502 CSSStyleSheet* CSSStyleSheet::parentStyleSheet() const {
503 return owner_rule_ ? owner_rule_->parentStyleSheet() : nullptr;
504 }
505
OwnerDocument() const506 Document* CSSStyleSheet::OwnerDocument() const {
507 if (CSSStyleSheet* parent = parentStyleSheet())
508 return parent->OwnerDocument();
509 if (IsConstructed()) {
510 DCHECK(!ownerNode());
511 return ConstructorDocument();
512 }
513 return ownerNode() ? &ownerNode()->GetDocument() : nullptr;
514 }
515
SheetLoaded()516 bool CSSStyleSheet::SheetLoaded() {
517 DCHECK(owner_node_);
518 SetLoadCompleted(owner_node_->SheetLoaded());
519 return load_completed_;
520 }
521
StartLoadingDynamicSheet()522 void CSSStyleSheet::StartLoadingDynamicSheet() {
523 SetLoadCompleted(false);
524 owner_node_->StartLoadingDynamicSheet();
525 }
526
SetLoadCompleted(bool completed)527 void CSSStyleSheet::SetLoadCompleted(bool completed) {
528 if (completed == load_completed_)
529 return;
530
531 load_completed_ = completed;
532
533 if (completed)
534 contents_->ClientLoadCompleted(this);
535 else
536 contents_->ClientLoadStarted(this);
537 }
538
SetText(const String & text,CSSImportRules import_rules)539 void CSSStyleSheet::SetText(const String& text, CSSImportRules import_rules) {
540 child_rule_cssom_wrappers_.clear();
541
542 CSSStyleSheet::RuleMutationScope mutation_scope(this);
543 contents_->ClearRules();
544 bool allow_imports = import_rules == CSSImportRules::kAllow;
545 if (contents_->ParseString(text, allow_imports) ==
546 ParseSheetResult::kHasUnallowedImportRule &&
547 import_rules == CSSImportRules::kIgnoreWithWarning) {
548 OwnerDocument()->AddConsoleMessage(MakeGarbageCollected<ConsoleMessage>(
549 mojom::blink::ConsoleMessageSource::kJavaScript,
550 mojom::blink::ConsoleMessageLevel::kWarning,
551 "@import rules are not allowed here. See "
552 "https://github.com/WICG/construct-stylesheets/issues/"
553 "119#issuecomment-588352418."));
554 }
555 }
556
SetAlternateFromConstructor(bool alternate_from_constructor)557 void CSSStyleSheet::SetAlternateFromConstructor(
558 bool alternate_from_constructor) {
559 alternate_from_constructor_ = alternate_from_constructor;
560 }
561
IsAlternate() const562 bool CSSStyleSheet::IsAlternate() const {
563 if (owner_node_) {
564 auto* owner_element = DynamicTo<Element>(owner_node_.Get());
565 return owner_element &&
566 owner_element->FastGetAttribute(html_names::kRelAttr)
567 .Contains("alternate");
568 }
569 return alternate_from_constructor_;
570 }
571
CanBeActivated(const String & current_preferrable_name) const572 bool CSSStyleSheet::CanBeActivated(
573 const String& current_preferrable_name) const {
574 if (disabled())
575 return false;
576
577 if (owner_node_ && owner_node_->IsInShadowTree()) {
578 if (IsA<HTMLStyleElement>(owner_node_.Get()) ||
579 IsA<SVGStyleElement>(owner_node_.Get()))
580 return true;
581 auto* html_link_element = DynamicTo<HTMLLinkElement>(owner_node_.Get());
582 if (html_link_element && html_link_element->IsImport())
583 return !IsAlternate();
584 }
585
586 auto* html_link_element = DynamicTo<HTMLLinkElement>(owner_node_.Get());
587 if (!owner_node_ ||
588 owner_node_->getNodeType() == Node::kProcessingInstructionNode ||
589 !html_link_element || !html_link_element->IsEnabledViaScript()) {
590 if (!title_.IsEmpty() && title_ != current_preferrable_name)
591 return false;
592 }
593
594 if (IsAlternate() && title_.IsEmpty())
595 return false;
596
597 return true;
598 }
599
Trace(Visitor * visitor) const600 void CSSStyleSheet::Trace(Visitor* visitor) const {
601 visitor->Trace(contents_);
602 visitor->Trace(owner_node_);
603 visitor->Trace(owner_rule_);
604 visitor->Trace(media_cssom_wrapper_);
605 visitor->Trace(child_rule_cssom_wrappers_);
606 visitor->Trace(rule_list_cssom_wrapper_);
607 visitor->Trace(adopted_tree_scopes_);
608 visitor->Trace(constructor_document_);
609 StyleSheet::Trace(visitor);
610 }
611
612 } // namespace blink
613