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