1 /*
2 * Copyright (C) 2006, 2007 Rob Buis
3 * Copyright (C) 2008 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/style_element.h"
22
23 #include "third_party/blink/renderer/bindings/core/v8/script_controller.h"
24 #include "third_party/blink/renderer/core/css/media_list.h"
25 #include "third_party/blink/renderer/core/css/media_query_evaluator.h"
26 #include "third_party/blink/renderer/core/css/style_engine.h"
27 #include "third_party/blink/renderer/core/css/style_sheet_contents.h"
28 #include "third_party/blink/renderer/core/dom/document.h"
29 #include "third_party/blink/renderer/core/dom/element.h"
30 #include "third_party/blink/renderer/core/dom/scriptable_document_parser.h"
31 #include "third_party/blink/renderer/core/dom/shadow_root.h"
32 #include "third_party/blink/renderer/core/frame/csp/content_security_policy.h"
33 #include "third_party/blink/renderer/core/frame/local_frame.h"
34 #include "third_party/blink/renderer/core/html/html_style_element.h"
35 #include "third_party/blink/renderer/core/probe/core_probes.h"
36 #include "third_party/blink/renderer/core/svg/svg_style_element.h"
37 #include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h"
38 #include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
39
40 namespace blink {
41
IsCSS(const Element & element,const AtomicString & type)42 static bool IsCSS(const Element& element, const AtomicString& type) {
43 return type.IsEmpty() ||
44 (element.IsHTMLElement() ? EqualIgnoringASCIICase(type, "text/css")
45 : (type == "text/css"));
46 }
47
StyleElement(Document * document,bool created_by_parser)48 StyleElement::StyleElement(Document* document, bool created_by_parser)
49 : created_by_parser_(created_by_parser),
50 loading_(false),
51 registered_as_candidate_(false),
52 start_position_(TextPosition::BelowRangePosition()) {
53 if (created_by_parser && document &&
54 document->GetScriptableDocumentParser() &&
55 !document->IsInDocumentWrite()) {
56 start_position_ =
57 document->GetScriptableDocumentParser()->GetTextPosition();
58 }
59 }
60
61 StyleElement::~StyleElement() = default;
62
ProcessStyleSheet(Document & document,Element & element)63 StyleElement::ProcessingResult StyleElement::ProcessStyleSheet(
64 Document& document,
65 Element& element) {
66 TRACE_EVENT0("blink", "StyleElement::processStyleSheet");
67 DCHECK(element.isConnected());
68
69 registered_as_candidate_ = true;
70 document.GetStyleEngine().AddStyleSheetCandidateNode(element);
71 if (created_by_parser_)
72 return kProcessingSuccessful;
73
74 return Process(element);
75 }
76
RemovedFrom(Element & element,ContainerNode & insertion_point)77 void StyleElement::RemovedFrom(Element& element,
78 ContainerNode& insertion_point) {
79 if (!insertion_point.isConnected())
80 return;
81
82 Document& document = element.GetDocument();
83 if (registered_as_candidate_) {
84 document.GetStyleEngine().RemoveStyleSheetCandidateNode(element,
85 insertion_point);
86 registered_as_candidate_ = false;
87 }
88
89 if (sheet_)
90 ClearSheet(element);
91 }
92
ChildrenChanged(Element & element)93 StyleElement::ProcessingResult StyleElement::ChildrenChanged(Element& element) {
94 if (created_by_parser_)
95 return kProcessingSuccessful;
96 probe::WillChangeStyleElement(&element);
97 return Process(element);
98 }
99
FinishParsingChildren(Element & element)100 StyleElement::ProcessingResult StyleElement::FinishParsingChildren(
101 Element& element) {
102 ProcessingResult result = Process(element);
103 created_by_parser_ = false;
104 return result;
105 }
106
Process(Element & element)107 StyleElement::ProcessingResult StyleElement::Process(Element& element) {
108 if (!element.isConnected())
109 return kProcessingSuccessful;
110 return CreateSheet(element, element.TextFromChildren());
111 }
112
ClearSheet(Element & owner_element)113 void StyleElement::ClearSheet(Element& owner_element) {
114 DCHECK(sheet_);
115
116 if (sheet_->IsLoading()) {
117 owner_element.GetDocument().GetStyleEngine().RemovePendingSheet(
118 owner_element, style_engine_context_);
119 }
120
121 sheet_.Release()->ClearOwnerNode();
122 }
123
IsInUserAgentShadowDOM(const Element & element)124 static bool IsInUserAgentShadowDOM(const Element& element) {
125 ShadowRoot* root = element.ContainingShadowRoot();
126 return root && root->IsUserAgent();
127 }
128
CreateSheet(Element & element,const String & text)129 StyleElement::ProcessingResult StyleElement::CreateSheet(Element& element,
130 const String& text) {
131 DCHECK(element.isConnected());
132 Document& document = element.GetDocument();
133
134 const ContentSecurityPolicy* csp =
135 document.GetContentSecurityPolicyForWorld();
136
137 // CSP is bypassed for style elements in user agent shadow DOM.
138 bool passes_content_security_policy_checks =
139 IsInUserAgentShadowDOM(element) ||
140 csp->AllowInline(ContentSecurityPolicy::InlineType::kStyle, &element,
141 text, element.nonce(), document.Url(),
142 start_position_.line_);
143
144 // Clearing the current sheet may remove the cache entry so create the new
145 // sheet first
146 CSSStyleSheet* new_sheet = nullptr;
147
148 // If type is empty or CSS, this is a CSS style sheet.
149 const AtomicString& type = this->type();
150 if (IsCSS(element, type) && passes_content_security_policy_checks) {
151 scoped_refptr<MediaQuerySet> media_queries;
152 const AtomicString& media_string = media();
153 if (!media_string.IsEmpty()) {
154 media_queries =
155 MediaQuerySet::Create(media_string, element.GetExecutionContext());
156 }
157 loading_ = true;
158 TextPosition start_position =
159 start_position_ == TextPosition::BelowRangePosition()
160 ? TextPosition::MinimumPosition()
161 : start_position_;
162 new_sheet = document.GetStyleEngine().CreateSheet(
163 element, text, start_position, style_engine_context_);
164 new_sheet->SetMediaQueries(media_queries);
165 loading_ = false;
166 }
167
168 if (sheet_)
169 ClearSheet(element);
170
171 sheet_ = new_sheet;
172 if (sheet_)
173 sheet_->Contents()->CheckLoaded();
174
175 return passes_content_security_policy_checks ? kProcessingSuccessful
176 : kProcessingFatalError;
177 }
178
IsLoading() const179 bool StyleElement::IsLoading() const {
180 if (loading_)
181 return true;
182 return sheet_ ? sheet_->IsLoading() : false;
183 }
184
SheetLoaded(Document & document)185 bool StyleElement::SheetLoaded(Document& document) {
186 if (IsLoading())
187 return false;
188
189 document.GetStyleEngine().RemovePendingSheet(*sheet_->ownerNode(),
190 style_engine_context_);
191 return true;
192 }
193
StartLoadingDynamicSheet(Document & document)194 void StyleElement::StartLoadingDynamicSheet(Document& document) {
195 document.GetStyleEngine().AddPendingSheet(style_engine_context_);
196 }
197
Trace(Visitor * visitor)198 void StyleElement::Trace(Visitor* visitor) {
199 visitor->Trace(sheet_);
200 }
201
202 } // namespace blink
203