1 /* 2 * Copyright (C) 1999 Lars Knoll (knoll (at) kde.org) 3 * (C) 1999 Antti Koivisto (koivisto (at) kde.org) 4 * (C) 2001 Dirk Mueller (mueller (at) kde.org) 5 * (C) 2006 Alexey Proskuryakov (ap (at) webkit.org) 6 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2012 Apple Inc. All rights reserved. 7 * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/) 8 * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies) 9 * Copyright (C) 2013 Google Inc. All rights reserved. 10 * 11 * This library is free software; you can redistribute it and/or 12 * modify it under the terms of the GNU Library General Public 13 * License as published by the Free Software Foundation; either 14 * version 2 of the License, or (at your option) any later version. 15 * 16 * This library is distributed in the hope that it will be useful, 17 * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 19 * Library General Public License for more details. 20 * 21 * You should have received a copy of the GNU Library General Public License 22 * along with this library; see the file COPYING.LIB. If not, write to 23 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 24 * Boston, MA 02110-1301, USA. 25 */ 26 27 #include "config.h" 28 #include "core/dom/DocumentStyleSheetCollection.h" 29 30 #include "HTMLNames.h" 31 #include "RuntimeEnabledFeatures.h" 32 #include "SVGNames.h" 33 #include "core/css/CSSStyleSheet.h" 34 #include "core/css/resolver/StyleResolver.h" 35 #include "core/dom/Document.h" 36 #include "core/dom/Element.h" 37 #include "core/dom/ProcessingInstruction.h" 38 #include "core/dom/StyleEngine.h" 39 #include "core/html/HTMLIFrameElement.h" 40 #include "core/html/HTMLLinkElement.h" 41 #include "core/html/HTMLStyleElement.h" 42 #include "core/frame/Settings.h" 43 #include "core/svg/SVGStyleElement.h" 44 45 namespace WebCore { 46 47 using namespace HTMLNames; 48 49 DocumentStyleSheetCollection::DocumentStyleSheetCollection(TreeScope& treeScope) 50 : StyleSheetCollection(treeScope) 51 { 52 ASSERT(treeScope.rootNode() == treeScope.rootNode()->document()); 53 } 54 55 void DocumentStyleSheetCollection::collectStyleSheetsFromCandidates(StyleEngine* engine, StyleSheetCollectionBase& collection, DocumentStyleSheetCollection::CollectFor collectFor) 56 { 57 DocumentOrderedList::iterator begin = m_styleSheetCandidateNodes.begin(); 58 DocumentOrderedList::iterator end = m_styleSheetCandidateNodes.end(); 59 for (DocumentOrderedList::iterator it = begin; it != end; ++it) { 60 Node* n = *it; 61 StyleSheet* sheet = 0; 62 CSSStyleSheet* activeSheet = 0; 63 if (n->nodeType() == Node::PROCESSING_INSTRUCTION_NODE && !document()->isHTMLDocument()) { 64 // Processing instruction (XML documents only). 65 // We don't support linking to embedded CSS stylesheets, see <https://bugs.webkit.org/show_bug.cgi?id=49281> for discussion. 66 ProcessingInstruction* pi = toProcessingInstruction(n); 67 // Don't apply XSL transforms to already transformed documents -- <rdar://problem/4132806> 68 if (RuntimeEnabledFeatures::xsltEnabled() && pi->isXSL() && !document()->transformSourceDocument()) { 69 // Don't apply XSL transforms until loading is finished. 70 if (!document()->parsing() && !pi->isLoading()) 71 document()->applyXSLTransform(pi); 72 return; 73 } 74 sheet = pi->sheet(); 75 if (sheet && !sheet->disabled() && sheet->isCSSStyleSheet()) 76 activeSheet = toCSSStyleSheet(sheet); 77 } else if ((n->isHTMLElement() && (n->hasTagName(linkTag) || n->hasTagName(styleTag))) || (n->isSVGElement() && n->hasTagName(SVGNames::styleTag))) { 78 Element* e = toElement(n); 79 AtomicString title = e->getAttribute(titleAttr); 80 bool enabledViaScript = false; 81 if (e->hasLocalName(linkTag)) { 82 // <LINK> element 83 HTMLLinkElement* linkElement = toHTMLLinkElement(n); 84 enabledViaScript = linkElement->isEnabledViaScript(); 85 if (!linkElement->isDisabled() && linkElement->styleSheetIsLoading()) { 86 // it is loading but we should still decide which style sheet set to use 87 if (!enabledViaScript && !title.isEmpty() && engine->preferredStylesheetSetName().isEmpty()) { 88 const AtomicString& rel = e->getAttribute(relAttr); 89 if (!rel.contains("alternate")) { 90 engine->setPreferredStylesheetSetName(title); 91 engine->setSelectedStylesheetSetName(title); 92 } 93 } 94 95 continue; 96 } 97 sheet = linkElement->sheet(); 98 if (!sheet) 99 title = nullAtom; 100 } else if (n->isSVGElement() && n->hasTagName(SVGNames::styleTag)) { 101 sheet = toSVGStyleElement(n)->sheet(); 102 } else { 103 sheet = toHTMLStyleElement(n)->sheet(); 104 } 105 106 if (sheet && !sheet->disabled() && sheet->isCSSStyleSheet()) 107 activeSheet = toCSSStyleSheet(sheet); 108 109 // Check to see if this sheet belongs to a styleset 110 // (thus making it PREFERRED or ALTERNATE rather than 111 // PERSISTENT). 112 AtomicString rel = e->getAttribute(relAttr); 113 if (!enabledViaScript && sheet && !title.isEmpty()) { 114 // Yes, we have a title. 115 if (engine->preferredStylesheetSetName().isEmpty()) { 116 // No preferred set has been established. If 117 // we are NOT an alternate sheet, then establish 118 // us as the preferred set. Otherwise, just ignore 119 // this sheet. 120 if (e->hasLocalName(styleTag) || !rel.contains("alternate")) { 121 engine->setPreferredStylesheetSetName(title); 122 engine->setSelectedStylesheetSetName(title); 123 } 124 } 125 if (title != engine->preferredStylesheetSetName()) 126 activeSheet = 0; 127 } 128 129 if (rel.contains("alternate") && title.isEmpty()) 130 activeSheet = 0; 131 } 132 133 if (sheet && collectFor == CollectForList) 134 collection.appendSheetForList(sheet); 135 if (activeSheet) 136 collection.appendActiveStyleSheet(activeSheet); 137 } 138 } 139 140 static void collectActiveCSSStyleSheetsFromSeamlessParents(StyleSheetCollectionBase& collection, Document* document) 141 { 142 HTMLIFrameElement* seamlessParentIFrame = document->seamlessParentIFrame(); 143 if (!seamlessParentIFrame) 144 return; 145 collection.appendActiveStyleSheets(seamlessParentIFrame->document().styleEngine()->activeAuthorStyleSheets()); 146 } 147 148 void DocumentStyleSheetCollection::collectStyleSheets(StyleEngine* engine, StyleSheetCollectionBase& collection, DocumentStyleSheetCollection::CollectFor colletFor) 149 { 150 ASSERT(document()->styleEngine() == engine); 151 collection.appendActiveStyleSheets(engine->injectedAuthorStyleSheets()); 152 collection.appendActiveStyleSheets(engine->documentAuthorStyleSheets()); 153 collectActiveCSSStyleSheetsFromSeamlessParents(collection, document()); 154 collectStyleSheetsFromCandidates(engine, collection, colletFor); 155 } 156 157 bool DocumentStyleSheetCollection::updateActiveStyleSheets(StyleEngine* engine, StyleResolverUpdateMode updateMode) 158 { 159 StyleSheetCollectionBase collection; 160 engine->collectDocumentActiveStyleSheets(collection); 161 162 StyleSheetChange change; 163 analyzeStyleSheetChange(updateMode, collection, change); 164 165 if (change.styleResolverUpdateType == Reconstruct) { 166 engine->clearMasterResolver(); 167 engine->resetFontSelector(); 168 } else if (StyleResolver* styleResolver = engine->resolver()) { 169 // FIXME: We might have already had styles in child treescope. In this case, we cannot use buildScopedStyleTreeInDocumentOrder. 170 // Need to change "false" to some valid condition. 171 styleResolver->setBuildScopedStyleTreeInDocumentOrder(false); 172 if (change.styleResolverUpdateType != Additive) { 173 ASSERT(change.styleResolverUpdateType == Reset || change.styleResolverUpdateType == ResetStyleResolverAndFontSelector); 174 resetAllRuleSetsInTreeScope(styleResolver); 175 if (change.styleResolverUpdateType == ResetStyleResolverAndFontSelector) 176 engine->resetFontSelector(); 177 styleResolver->removePendingAuthorStyleSheets(m_activeAuthorStyleSheets); 178 styleResolver->lazyAppendAuthorStyleSheets(0, collection.activeAuthorStyleSheets()); 179 } else { 180 styleResolver->lazyAppendAuthorStyleSheets(m_activeAuthorStyleSheets.size(), collection.activeAuthorStyleSheets()); 181 } 182 } else if (change.styleResolverUpdateType == ResetStyleResolverAndFontSelector) { 183 engine->resetFontSelector(); 184 } 185 m_scopingNodesForStyleScoped.didRemoveScopingNodes(); 186 collection.swap(*this); 187 updateUsesRemUnits(); 188 189 return change.requiresFullStyleRecalc; 190 } 191 192 } 193