• 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 "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