Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / dom / StyleElement.cpp
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/dom/shadow/ShadowRoot.h"
33 #include "core/frame/LocalFrame.h"
34 #include "core/frame/csp/ContentSecurityPolicy.h"
35 #include "core/html/HTMLStyleElement.h"
36 #include "platform/TraceEvent.h"
37 #include "wtf/text/StringBuilder.h"
38
39 namespace blink {
40
41 static bool isCSS(Element* element, const AtomicString& type)
42 {
43     return type.isEmpty() || (element->isHTMLElement() ? equalIgnoringCase(type, "text/css") : (type == "text/css"));
44 }
45
46 StyleElement::StyleElement(Document* document, bool createdByParser)
47     : m_createdByParser(createdByParser)
48     , m_loading(false)
49     , m_registeredAsCandidate(false)
50     , m_startPosition(TextPosition::belowRangePosition())
51 {
52     if (createdByParser && document && document->scriptableDocumentParser() && !document->isInDocumentWrite())
53         m_startPosition = document->scriptableDocumentParser()->textPosition();
54 }
55
56 StyleElement::~StyleElement()
57 {
58 #if !ENABLE(OILPAN)
59     if (m_sheet)
60         clearSheet();
61 #endif
62 }
63
64 void StyleElement::processStyleSheet(Document& document, Element* element)
65 {
66     TRACE_EVENT0("blink", "StyleElement::processStyleSheet");
67     ASSERT(element);
68     ASSERT(element->inDocument());
69
70     m_registeredAsCandidate = true;
71     document.styleEngine()->addStyleSheetCandidateNode(element, m_createdByParser);
72     if (m_createdByParser)
73         return;
74
75     process(element);
76 }
77
78 void StyleElement::insertedInto(Element* element, ContainerNode* insertionPoint)
79 {
80     if (!insertionPoint->inDocument() || !element->isInShadowTree())
81         return;
82     if (ShadowRoot* scope = element->containingShadowRoot())
83         scope->registerScopedHTMLStyleChild();
84 }
85
86 void StyleElement::removedFrom(Element* element, ContainerNode* insertionPoint)
87 {
88     if (!insertionPoint->inDocument())
89         return;
90
91     ShadowRoot* shadowRoot = element->containingShadowRoot();
92     if (!shadowRoot)
93         shadowRoot = insertionPoint->containingShadowRoot();
94
95     if (shadowRoot)
96         shadowRoot->unregisterScopedHTMLStyleChild();
97
98     Document& document = element->document();
99     if (m_registeredAsCandidate) {
100         document.styleEngine()->removeStyleSheetCandidateNode(element, shadowRoot ? *toTreeScope(shadowRoot) : toTreeScope(document));
101         m_registeredAsCandidate = false;
102     }
103
104     RefPtrWillBeRawPtr<StyleSheet> removedSheet = m_sheet.get();
105
106     if (m_sheet)
107         clearSheet(element);
108     if (removedSheet)
109         document.removedStyleSheet(removedSheet.get(), AnalyzedStyleUpdate);
110 }
111
112 void StyleElement::clearDocumentData(Document& document, Element* element)
113 {
114     if (m_sheet)
115         m_sheet->clearOwnerNode();
116
117     if (element->inDocument()) {
118         // HTMLLinkElement in shadow tree is not supported.
119         TreeScope& treeScope = isHTMLStyleElement(element) || isSVGStyleElement(element) ? element->treeScope() : element->document();
120         document.styleEngine()->removeStyleSheetCandidateNode(element, treeScope);
121     }
122 }
123
124 void StyleElement::childrenChanged(Element* element)
125 {
126     ASSERT(element);
127     if (m_createdByParser)
128         return;
129
130     process(element);
131 }
132
133 void StyleElement::finishParsingChildren(Element* element)
134 {
135     ASSERT(element);
136     process(element);
137     m_createdByParser = false;
138 }
139
140 void StyleElement::process(Element* element)
141 {
142     if (!element || !element->inDocument())
143         return;
144     createSheet(element, element->textFromChildren());
145 }
146
147 void StyleElement::clearSheet(Element* ownerElement)
148 {
149     ASSERT(m_sheet);
150
151     if (ownerElement && m_sheet->isLoading())
152         ownerElement->document().styleEngine()->removePendingSheet(ownerElement);
153
154     m_sheet.release()->clearOwnerNode();
155 }
156
157 static bool shouldBypassMainWorldCSP(Element* element)
158 {
159     // Main world CSP is bypassed within an isolated world.
160     LocalFrame* frame = element->document().frame();
161     if (frame && frame->script().shouldBypassMainWorldCSP())
162         return true;
163
164     // Main world CSP is bypassed for style elements in user agent shadow DOM.
165     ShadowRoot* root = element->containingShadowRoot();
166     if (root && root->type() == ShadowRoot::UserAgentShadowRoot)
167         return true;
168
169     return false;
170 }
171
172 void StyleElement::createSheet(Element* e, const String& text)
173 {
174     ASSERT(e);
175     ASSERT(e->inDocument());
176     Document& document = e->document();
177     if (m_sheet)
178         clearSheet(e);
179
180     const ContentSecurityPolicy* csp = document.contentSecurityPolicy();
181     bool passesContentSecurityPolicyChecks = shouldBypassMainWorldCSP(e)
182         || csp->allowStyleWithHash(text)
183         || csp->allowStyleWithNonce(e->fastGetAttribute(HTMLNames::nonceAttr))
184         || csp->allowInlineStyle(e->document().url(), m_startPosition.m_line);
185
186     // If type is empty or CSS, this is a CSS style sheet.
187     const AtomicString& type = this->type();
188     if (isCSS(e, type) && passesContentSecurityPolicyChecks) {
189         RefPtrWillBeRawPtr<MediaQuerySet> mediaQueries = MediaQuerySet::create(media());
190
191         MediaQueryEvaluator screenEval("screen", true);
192         MediaQueryEvaluator printEval("print", true);
193         if (screenEval.eval(mediaQueries.get()) || printEval.eval(mediaQueries.get())) {
194             m_loading = true;
195             TextPosition startPosition = m_startPosition == TextPosition::belowRangePosition() ? TextPosition::minimumPosition() : m_startPosition;
196             m_sheet = document.styleEngine()->createSheet(e, text, startPosition, m_createdByParser);
197             m_sheet->setMediaQueries(mediaQueries.release());
198             m_loading = false;
199         }
200     }
201
202     if (m_sheet)
203         m_sheet->contents()->checkLoaded();
204 }
205
206 bool StyleElement::isLoading() const
207 {
208     if (m_loading)
209         return true;
210     return m_sheet ? m_sheet->isLoading() : false;
211 }
212
213 bool StyleElement::sheetLoaded(Document& document)
214 {
215     if (isLoading())
216         return false;
217
218     document.styleEngine()->removePendingSheet(m_sheet->ownerNode());
219     return true;
220 }
221
222 void StyleElement::startLoadingDynamicSheet(Document& document)
223 {
224     document.styleEngine()->addPendingSheet();
225 }
226
227 void StyleElement::trace(Visitor* visitor)
228 {
229     visitor->trace(m_sheet);
230 }
231
232 }