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