• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "config.h"
22 #include "core/dom/StyleElement.h"
23 
24 #include "bindings/core/v8/ScriptController.h"
25 #include "core/css/MediaList.h"
26 #include "core/css/MediaQueryEvaluator.h"
27 #include "core/css/StyleSheetContents.h"
28 #include "core/dom/Document.h"
29 #include "core/dom/Element.h"
30 #include "core/dom/ScriptableDocumentParser.h"
31 #include "core/dom/StyleEngine.h"
32 #include "core/frame/LocalFrame.h"
33 #include "core/frame/csp/ContentSecurityPolicy.h"
34 #include "core/html/HTMLStyleElement.h"
35 #include "platform/TraceEvent.h"
36 #include "wtf/text/StringBuilder.h"
37 
38 namespace blink {
39 
isCSS(Element * element,const AtomicString & type)40 static bool isCSS(Element* element, const AtomicString& type)
41 {
42     return type.isEmpty() || (element->isHTMLElement() ? equalIgnoringCase(type, "text/css") : (type == "text/css"));
43 }
44 
StyleElement(Document * document,bool createdByParser)45 StyleElement::StyleElement(Document* document, bool createdByParser)
46     : m_createdByParser(createdByParser)
47     , m_loading(false)
48     , m_registeredAsCandidate(false)
49     , m_startPosition(TextPosition::belowRangePosition())
50 {
51     if (createdByParser && document && document->scriptableDocumentParser() && !document->isInDocumentWrite())
52         m_startPosition = document->scriptableDocumentParser()->textPosition();
53 }
54 
~StyleElement()55 StyleElement::~StyleElement()
56 {
57 #if !ENABLE(OILPAN)
58     if (m_sheet)
59         clearSheet();
60 #endif
61 }
62 
processStyleSheet(Document & document,Element * element)63 void StyleElement::processStyleSheet(Document& document, Element* element)
64 {
65     TRACE_EVENT0("blink", "StyleElement::processStyleSheet");
66     ASSERT(element);
67     ASSERT(element->inDocument());
68 
69     m_registeredAsCandidate = true;
70     document.styleEngine()->addStyleSheetCandidateNode(element, m_createdByParser);
71     if (m_createdByParser)
72         return;
73 
74     process(element);
75 }
76 
removedFromDocument(Document & document,Element * element)77 void StyleElement::removedFromDocument(Document& document, Element* element)
78 {
79     removedFromDocument(document, element, 0, document);
80 }
81 
removedFromDocument(Document & document,Element * element,ContainerNode * scopingNode,TreeScope & treeScope)82 void StyleElement::removedFromDocument(Document& document, Element* element, ContainerNode* scopingNode, TreeScope& treeScope)
83 {
84     ASSERT(element);
85 
86     if (m_registeredAsCandidate) {
87         document.styleEngine()->removeStyleSheetCandidateNode(element, scopingNode, treeScope);
88         m_registeredAsCandidate = false;
89     }
90 
91     RefPtrWillBeRawPtr<StyleSheet> removedSheet = m_sheet.get();
92 
93     if (m_sheet)
94         clearSheet(element);
95     if (removedSheet)
96         document.removedStyleSheet(removedSheet.get(), AnalyzedStyleUpdate);
97 }
98 
clearDocumentData(Document & document,Element * element)99 void StyleElement::clearDocumentData(Document& document, Element* element)
100 {
101     if (m_sheet)
102         m_sheet->clearOwnerNode();
103 
104     if (element->inDocument()) {
105         ContainerNode* scopingNode = isHTMLStyleElement(element) ? toHTMLStyleElement(element)->scopingNode() :  0;
106         TreeScope& treeScope = scopingNode ? scopingNode->treeScope() : element->treeScope();
107         document.styleEngine()->removeStyleSheetCandidateNode(element, scopingNode, treeScope);
108     }
109 }
110 
childrenChanged(Element * element)111 void StyleElement::childrenChanged(Element* element)
112 {
113     ASSERT(element);
114     if (m_createdByParser)
115         return;
116 
117     process(element);
118 }
119 
finishParsingChildren(Element * element)120 void StyleElement::finishParsingChildren(Element* element)
121 {
122     ASSERT(element);
123     process(element);
124     m_createdByParser = false;
125 }
126 
process(Element * element)127 void StyleElement::process(Element* element)
128 {
129     if (!element || !element->inDocument())
130         return;
131     createSheet(element, element->textFromChildren());
132 }
133 
clearSheet(Element * ownerElement)134 void StyleElement::clearSheet(Element* ownerElement)
135 {
136     ASSERT(m_sheet);
137 
138     if (ownerElement && m_sheet->isLoading())
139         ownerElement->document().styleEngine()->removePendingSheet(ownerElement);
140 
141     m_sheet.release()->clearOwnerNode();
142 }
143 
createSheet(Element * e,const String & text)144 void StyleElement::createSheet(Element* e, const String& text)
145 {
146     ASSERT(e);
147     ASSERT(e->inDocument());
148     Document& document = e->document();
149     if (m_sheet)
150         clearSheet(e);
151 
152     // Inline style added from an isolated world should bypass the main world's
153     // CSP just as an inline script would.
154     LocalFrame* frame = document.frame();
155     bool shouldBypassMainWorldCSP = frame && frame->script().shouldBypassMainWorldCSP();
156 
157     const ContentSecurityPolicy* csp = document.contentSecurityPolicy();
158     bool passesContentSecurityPolicyChecks = shouldBypassMainWorldCSP
159         || csp->allowStyleWithHash(text)
160         || csp->allowStyleWithNonce(e->fastGetAttribute(HTMLNames::nonceAttr))
161         || csp->allowInlineStyle(e->document().url(), m_startPosition.m_line);
162 
163     // If type is empty or CSS, this is a CSS style sheet.
164     const AtomicString& type = this->type();
165     if (isCSS(e, type) && passesContentSecurityPolicyChecks) {
166         RefPtrWillBeRawPtr<MediaQuerySet> mediaQueries = MediaQuerySet::create(media());
167 
168         MediaQueryEvaluator screenEval("screen", true);
169         MediaQueryEvaluator printEval("print", true);
170         if (screenEval.eval(mediaQueries.get()) || printEval.eval(mediaQueries.get())) {
171             m_loading = true;
172             TextPosition startPosition = m_startPosition == TextPosition::belowRangePosition() ? TextPosition::minimumPosition() : m_startPosition;
173             m_sheet = document.styleEngine()->createSheet(e, text, startPosition, m_createdByParser);
174             m_sheet->setMediaQueries(mediaQueries.release());
175             m_loading = false;
176         }
177     }
178 
179     if (m_sheet)
180         m_sheet->contents()->checkLoaded();
181 }
182 
isLoading() const183 bool StyleElement::isLoading() const
184 {
185     if (m_loading)
186         return true;
187     return m_sheet ? m_sheet->isLoading() : false;
188 }
189 
sheetLoaded(Document & document)190 bool StyleElement::sheetLoaded(Document& document)
191 {
192     if (isLoading())
193         return false;
194 
195     document.styleEngine()->removePendingSheet(m_sheet->ownerNode());
196     return true;
197 }
198 
startLoadingDynamicSheet(Document & document)199 void StyleElement::startLoadingDynamicSheet(Document& document)
200 {
201     document.styleEngine()->addPendingSheet();
202 }
203 
trace(Visitor * visitor)204 void StyleElement::trace(Visitor* visitor)
205 {
206     visitor->trace(m_sheet);
207 }
208 
209 }
210