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 "StyleElement.h"
23
24 #include "Attribute.h"
25 #include "Document.h"
26 #include "Element.h"
27 #include "MediaList.h"
28 #include "MediaQueryEvaluator.h"
29 #include "ScriptableDocumentParser.h"
30
31 namespace WebCore {
32
isValidStyleChild(Node * node)33 static bool isValidStyleChild(Node* node)
34 {
35 ASSERT(node);
36 Node::NodeType nodeType = node->nodeType();
37 return nodeType == Node::TEXT_NODE || nodeType == Node::CDATA_SECTION_NODE;
38 }
39
StyleElement(Document * document,bool createdByParser)40 StyleElement::StyleElement(Document* document, bool createdByParser)
41 : m_createdByParser(createdByParser)
42 , m_loading(false)
43 , m_startLineNumber(0)
44 {
45 if (createdByParser && document && document->scriptableDocumentParser())
46 m_startLineNumber = document->scriptableDocumentParser()->lineNumber();
47 }
48
~StyleElement()49 StyleElement::~StyleElement()
50 {
51 }
52
insertedIntoDocument(Document * document,Element * element)53 void StyleElement::insertedIntoDocument(Document* document, Element* element)
54 {
55 ASSERT(document);
56 ASSERT(element);
57 document->addStyleSheetCandidateNode(element, m_createdByParser);
58 if (m_createdByParser)
59 return;
60
61 process(element);
62 }
63
removedFromDocument(Document * document,Element * element)64 void StyleElement::removedFromDocument(Document* document, Element* element)
65 {
66 ASSERT(document);
67 ASSERT(element);
68 document->removeStyleSheetCandidateNode(element);
69
70 if (m_sheet) {
71 ASSERT(m_sheet->ownerNode() == element);
72 m_sheet->clearOwnerNode();
73 m_sheet = 0;
74 }
75
76 // If we're in document teardown, then we don't need to do any notification of our sheet's removal.
77 if (document->renderer())
78 document->styleSelectorChanged(DeferRecalcStyle);
79 }
80
childrenChanged(Element * element)81 void StyleElement::childrenChanged(Element* element)
82 {
83 ASSERT(element);
84 if (m_createdByParser)
85 return;
86
87 process(element);
88 }
89
finishParsingChildren(Element * element)90 void StyleElement::finishParsingChildren(Element* element)
91 {
92 ASSERT(element);
93 process(element);
94 m_createdByParser = false;
95 }
96
process(Element * e)97 void StyleElement::process(Element* e)
98 {
99 if (!e || !e->inDocument())
100 return;
101
102 unsigned resultLength = 0;
103 for (Node* c = e->firstChild(); c; c = c->nextSibling()) {
104 if (isValidStyleChild(c)) {
105 unsigned length = c->nodeValue().length();
106 if (length > std::numeric_limits<unsigned>::max() - resultLength) {
107 createSheet(e, m_startLineNumber, "");
108 return;
109 }
110 resultLength += length;
111 }
112 }
113 UChar* text;
114 String sheetText = String::createUninitialized(resultLength, text);
115
116 UChar* p = text;
117 for (Node* c = e->firstChild(); c; c = c->nextSibling()) {
118 if (isValidStyleChild(c)) {
119 String nodeValue = c->nodeValue();
120 unsigned nodeLength = nodeValue.length();
121 memcpy(p, nodeValue.characters(), nodeLength * sizeof(UChar));
122 p += nodeLength;
123 }
124 }
125 ASSERT(p == text + resultLength);
126
127 createSheet(e, m_startLineNumber, sheetText);
128 }
129
createSheet(Element * e,int startLineNumber,const String & text)130 void StyleElement::createSheet(Element* e, int startLineNumber, const String& text)
131 {
132 ASSERT(e);
133 ASSERT(e->inDocument());
134 Document* document = e->document();
135 if (m_sheet) {
136 if (m_sheet->isLoading())
137 document->removePendingSheet();
138 m_sheet = 0;
139 }
140
141 // If type is empty or CSS, this is a CSS style sheet.
142 const AtomicString& type = this->type();
143 if (type.isEmpty() || (e->isHTMLElement() ? equalIgnoringCase(type, "text/css") : (type == "text/css"))) {
144 RefPtr<MediaList> mediaList = MediaList::create(media(), e->isHTMLElement());
145 MediaQueryEvaluator screenEval("screen", true);
146 MediaQueryEvaluator printEval("print", true);
147 if (screenEval.eval(mediaList.get()) || printEval.eval(mediaList.get())) {
148 document->addPendingSheet();
149 m_loading = true;
150 m_sheet = CSSStyleSheet::create(e, String(), KURL(), document->inputEncoding());
151 m_sheet->parseStringAtLine(text, !document->inQuirksMode(), startLineNumber);
152 m_sheet->setMedia(mediaList.get());
153 m_sheet->setTitle(e->title());
154 m_loading = false;
155 }
156 }
157
158 if (m_sheet)
159 m_sheet->checkLoaded();
160 }
161
isLoading() const162 bool StyleElement::isLoading() const
163 {
164 if (m_loading)
165 return true;
166 return m_sheet ? m_sheet->isLoading() : false;
167 }
168
sheetLoaded(Document * document)169 bool StyleElement::sheetLoaded(Document* document)
170 {
171 ASSERT(document);
172 if (isLoading())
173 return false;
174
175 document->removePendingSheet();
176 return true;
177 }
178
179 }
180