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 "Document.h" 25 #include "Element.h" 26 #include "MappedAttribute.h" 27 #include "MediaList.h" 28 #include "MediaQueryEvaluator.h" 29 30 namespace WebCore { 31 32 StyleElement::StyleElement() 33 { 34 } 35 36 StyleSheet* StyleElement::sheet(Element* e) 37 { 38 if (!m_sheet) 39 createSheet(e); 40 return m_sheet.get(); 41 } 42 43 void StyleElement::insertedIntoDocument(Document*, Element* element) 44 { 45 process(element); 46 } 47 48 void StyleElement::removedFromDocument(Document* document) 49 { 50 // If we're in document teardown, then we don't need to do any notification of our sheet's removal. 51 if (!document->renderer()) 52 return; 53 54 // FIXME: It's terrible to do a synchronous update of the style selector just because a <style> or <link> element got removed. 55 if (m_sheet) 56 document->updateStyleSelector(); 57 } 58 59 void StyleElement::process(Element* e) 60 { 61 if (!e || !e->inDocument()) 62 return; 63 64 unsigned resultLength = 0; 65 for (Node* c = e->firstChild(); c; c = c->nextSibling()) { 66 Node::NodeType nodeType = c->nodeType(); 67 if (nodeType == Node::TEXT_NODE || nodeType == Node::CDATA_SECTION_NODE || nodeType == Node::COMMENT_NODE) { 68 unsigned length = c->nodeValue().length(); 69 if (length > std::numeric_limits<unsigned>::max() - resultLength) 70 CRASH(); 71 resultLength += length; 72 } 73 } 74 UChar* text; 75 String sheetText = String::createUninitialized(resultLength, text); 76 77 UChar* p = text; 78 for (Node* c = e->firstChild(); c; c = c->nextSibling()) { 79 Node::NodeType nodeType = c->nodeType(); 80 if (nodeType == Node::TEXT_NODE || nodeType == Node::CDATA_SECTION_NODE || nodeType == Node::COMMENT_NODE) { 81 String nodeValue = c->nodeValue(); 82 unsigned nodeLength = nodeValue.length(); 83 memcpy(p, nodeValue.characters(), nodeLength * sizeof(UChar)); 84 p += nodeLength; 85 } 86 } 87 ASSERT(p == text + resultLength); 88 89 createSheet(e, sheetText); 90 } 91 92 void StyleElement::createSheet(Element* e, const String& text) 93 { 94 Document* document = e->document(); 95 if (m_sheet) { 96 if (static_cast<CSSStyleSheet*>(m_sheet.get())->isLoading()) 97 document->removePendingSheet(); 98 m_sheet = 0; 99 } 100 101 // If type is empty or CSS, this is a CSS style sheet. 102 const AtomicString& type = this->type(); 103 if (type.isEmpty() || (e->isHTMLElement() ? equalIgnoringCase(type, "text/css") : (type == "text/css"))) { 104 RefPtr<MediaList> mediaList = MediaList::create(media(), e->isHTMLElement()); 105 MediaQueryEvaluator screenEval("screen", true); 106 MediaQueryEvaluator printEval("print", true); 107 if (screenEval.eval(mediaList.get()) || printEval.eval(mediaList.get())) { 108 document->addPendingSheet(); 109 setLoading(true); 110 m_sheet = CSSStyleSheet::create(e, String(), KURL(), document->inputEncoding()); 111 m_sheet->parseString(text, !document->inCompatMode()); 112 m_sheet->setMedia(mediaList.get()); 113 m_sheet->setTitle(e->title()); 114 setLoading(false); 115 } 116 } 117 118 if (m_sheet) 119 m_sheet->checkLoaded(); 120 } 121 122 } 123