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, 2011, 2012 Apple Inc. All rights reserved. 7 * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/) 8 * Copyright (C) 2008, 2009, 2011, 2012 Google Inc. All rights reserved. 9 * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies) 10 * Copyright (C) Research In Motion Limited 2010-2011. All rights reserved. 11 * 12 * This library is free software; you can redistribute it and/or 13 * modify it under the terms of the GNU Library General Public 14 * License as published by the Free Software Foundation; either 15 * version 2 of the License, or (at your option) any later version. 16 * 17 * This library is distributed in the hope that it will be useful, 18 * but WITHOUT ANY WARRANTY; without even the implied warranty of 19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 20 * Library General Public License for more details. 21 * 22 * You should have received a copy of the GNU Library General Public License 23 * along with this library; see the file COPYING.LIB. If not, write to 24 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 25 * Boston, MA 02110-1301, USA. 26 */ 27 28 #include "config.h" 29 #include "core/dom/DocumentStyleSheetCollection.h" 30 31 #include "HTMLNames.h" 32 #include "SVGNames.h" 33 #include "core/css/CSSStyleSheet.h" 34 #include "core/css/StyleInvalidationAnalysis.h" 35 #include "core/css/StyleSheetContents.h" 36 #include "core/css/resolver/StyleResolver.h" 37 #include "core/dom/Document.h" 38 #include "core/dom/Element.h" 39 #include "core/dom/ProcessingInstruction.h" 40 #include "core/html/HTMLIFrameElement.h" 41 #include "core/html/HTMLLinkElement.h" 42 #include "core/html/HTMLStyleElement.h" 43 #include "core/page/Page.h" 44 #include "core/page/PageGroup.h" 45 #include "core/page/Settings.h" 46 #include "core/page/UserContentURLPattern.h" 47 #include "core/svg/SVGStyleElement.h" 48 49 namespace WebCore { 50 51 using namespace HTMLNames; 52 53 DocumentStyleSheetCollection::DocumentStyleSheetCollection(Document* document) 54 : m_document(document) 55 , m_pendingStylesheets(0) 56 , m_injectedStyleSheetCacheValid(false) 57 , m_needsUpdateActiveStylesheetsOnStyleRecalc(false) 58 , m_usesSiblingRules(false) 59 , m_usesSiblingRulesOverride(false) 60 , m_usesFirstLineRules(false) 61 , m_usesFirstLetterRules(false) 62 , m_usesBeforeAfterRules(false) 63 , m_usesBeforeAfterRulesOverride(false) 64 , m_usesRemUnits(false) 65 , m_collectionForDocument(document) 66 { 67 } 68 69 DocumentStyleSheetCollection::~DocumentStyleSheetCollection() 70 { 71 if (m_pageUserSheet) 72 m_pageUserSheet->clearOwnerNode(); 73 for (unsigned i = 0; i < m_injectedUserStyleSheets.size(); ++i) 74 m_injectedUserStyleSheets[i]->clearOwnerNode(); 75 for (unsigned i = 0; i < m_injectedAuthorStyleSheets.size(); ++i) 76 m_injectedAuthorStyleSheets[i]->clearOwnerNode(); 77 for (unsigned i = 0; i < m_userStyleSheets.size(); ++i) 78 m_userStyleSheets[i]->clearOwnerNode(); 79 for (unsigned i = 0; i < m_authorStyleSheets.size(); ++i) 80 m_authorStyleSheets[i]->clearOwnerNode(); 81 } 82 83 const Vector<RefPtr<StyleSheet> >& DocumentStyleSheetCollection::styleSheetsForStyleSheetList() 84 { 85 return m_collectionForDocument.styleSheetsForStyleSheetList(); 86 } 87 88 const Vector<RefPtr<CSSStyleSheet> >& DocumentStyleSheetCollection::activeAuthorStyleSheets() const 89 { 90 return m_collectionForDocument.activeAuthorStyleSheets(); 91 } 92 93 void DocumentStyleSheetCollection::combineCSSFeatureFlags(const RuleFeatureSet& features) 94 { 95 // Delay resetting the flags until after next style recalc since unapplying the style may not work without these set (this is true at least with before/after). 96 m_usesSiblingRules = m_usesSiblingRules || features.usesSiblingRules(); 97 m_usesFirstLineRules = m_usesFirstLineRules || features.usesFirstLineRules(); 98 m_usesBeforeAfterRules = m_usesBeforeAfterRules || features.usesBeforeAfterRules(); 99 } 100 101 void DocumentStyleSheetCollection::resetCSSFeatureFlags(const RuleFeatureSet& features) 102 { 103 m_usesSiblingRules = features.usesSiblingRules(); 104 m_usesFirstLineRules = features.usesFirstLineRules(); 105 m_usesBeforeAfterRules = features.usesBeforeAfterRules(); 106 } 107 108 CSSStyleSheet* DocumentStyleSheetCollection::pageUserSheet() 109 { 110 if (m_pageUserSheet) 111 return m_pageUserSheet.get(); 112 113 Page* owningPage = m_document->page(); 114 if (!owningPage) 115 return 0; 116 117 String userSheetText = owningPage->userStyleSheet(); 118 if (userSheetText.isEmpty()) 119 return 0; 120 121 // Parse the sheet and cache it. 122 m_pageUserSheet = CSSStyleSheet::createInline(m_document, m_document->settings()->userStyleSheetLocation()); 123 m_pageUserSheet->contents()->setIsUserStyleSheet(true); 124 m_pageUserSheet->contents()->parseString(userSheetText); 125 return m_pageUserSheet.get(); 126 } 127 128 void DocumentStyleSheetCollection::clearPageUserSheet() 129 { 130 if (m_pageUserSheet) { 131 RefPtr<StyleSheet> removedSheet = m_pageUserSheet; 132 m_pageUserSheet = 0; 133 m_document->removedStyleSheet(removedSheet.get()); 134 } 135 } 136 137 void DocumentStyleSheetCollection::updatePageUserSheet() 138 { 139 clearPageUserSheet(); 140 // FIXME: Why is this immediately and not defer? 141 if (StyleSheet* addedSheet = pageUserSheet()) 142 m_document->addedStyleSheet(addedSheet, RecalcStyleImmediately); 143 } 144 145 const Vector<RefPtr<CSSStyleSheet> >& DocumentStyleSheetCollection::injectedUserStyleSheets() const 146 { 147 updateInjectedStyleSheetCache(); 148 return m_injectedUserStyleSheets; 149 } 150 151 const Vector<RefPtr<CSSStyleSheet> >& DocumentStyleSheetCollection::injectedAuthorStyleSheets() const 152 { 153 updateInjectedStyleSheetCache(); 154 return m_injectedAuthorStyleSheets; 155 } 156 157 void DocumentStyleSheetCollection::updateInjectedStyleSheetCache() const 158 { 159 if (m_injectedStyleSheetCacheValid) 160 return; 161 m_injectedStyleSheetCacheValid = true; 162 m_injectedUserStyleSheets.clear(); 163 m_injectedAuthorStyleSheets.clear(); 164 165 Page* owningPage = m_document->page(); 166 if (!owningPage) 167 return; 168 169 const PageGroup& pageGroup = owningPage->group(); 170 const UserStyleSheetVector& sheets = pageGroup.userStyleSheets(); 171 for (unsigned i = 0; i < sheets.size(); ++i) { 172 const UserStyleSheet* sheet = sheets[i].get(); 173 if (sheet->injectedFrames() == InjectInTopFrameOnly && m_document->ownerElement()) 174 continue; 175 if (!UserContentURLPattern::matchesPatterns(m_document->url(), sheet->whitelist(), sheet->blacklist())) 176 continue; 177 RefPtr<CSSStyleSheet> groupSheet = CSSStyleSheet::createInline(const_cast<Document*>(m_document), sheet->url()); 178 bool isUserStyleSheet = sheet->level() == UserStyleUserLevel; 179 if (isUserStyleSheet) 180 m_injectedUserStyleSheets.append(groupSheet); 181 else 182 m_injectedAuthorStyleSheets.append(groupSheet); 183 groupSheet->contents()->setIsUserStyleSheet(isUserStyleSheet); 184 groupSheet->contents()->parseString(sheet->source()); 185 } 186 } 187 188 void DocumentStyleSheetCollection::invalidateInjectedStyleSheetCache() 189 { 190 m_injectedStyleSheetCacheValid = false; 191 // FIXME: updateInjectedStyleSheetCache is called inside StyleSheetCollection::updateActiveStyleSheets 192 // and batch updates lots of sheets so we can't call addedStyleSheet() or removedStyleSheet(). 193 m_document->styleResolverChanged(DeferRecalcStyle); 194 } 195 196 void DocumentStyleSheetCollection::addAuthorSheet(PassRefPtr<StyleSheetContents> authorSheet) 197 { 198 ASSERT(!authorSheet->isUserStyleSheet()); 199 m_authorStyleSheets.append(CSSStyleSheet::create(authorSheet, m_document)); 200 m_document->addedStyleSheet(m_authorStyleSheets.last().get(), RecalcStyleImmediately); 201 } 202 203 void DocumentStyleSheetCollection::addUserSheet(PassRefPtr<StyleSheetContents> userSheet) 204 { 205 ASSERT(userSheet->isUserStyleSheet()); 206 m_userStyleSheets.append(CSSStyleSheet::create(userSheet, m_document)); 207 m_document->addedStyleSheet(m_userStyleSheets.last().get(), RecalcStyleImmediately); 208 } 209 210 // This method is called whenever a top-level stylesheet has finished loading. 211 void DocumentStyleSheetCollection::removePendingSheet(RemovePendingSheetNotificationType notification) 212 { 213 // Make sure we knew this sheet was pending, and that our count isn't out of sync. 214 ASSERT(m_pendingStylesheets > 0); 215 216 m_pendingStylesheets--; 217 218 if (m_pendingStylesheets) 219 return; 220 221 if (notification == RemovePendingSheetNotifyLater) { 222 m_document->setNeedsNotifyRemoveAllPendingStylesheet(); 223 return; 224 } 225 226 // FIXME: We can't call addedStyleSheet or removedStyleSheet here because we don't know 227 // what's new. We should track that to tell the style system what changed. 228 m_document->didRemoveAllPendingStylesheet(); 229 } 230 231 void DocumentStyleSheetCollection::addStyleSheetCandidateNode(Node* node, bool createdByParser) 232 { 233 m_collectionForDocument.addStyleSheetCandidateNode(node, createdByParser); 234 } 235 236 void DocumentStyleSheetCollection::removeStyleSheetCandidateNode(Node* node, ContainerNode* scopingNode) 237 { 238 m_collectionForDocument.removeStyleSheetCandidateNode(node, scopingNode); 239 } 240 241 static bool styleSheetsUseRemUnits(const Vector<RefPtr<CSSStyleSheet> >& sheets) 242 { 243 for (unsigned i = 0; i < sheets.size(); ++i) { 244 if (sheets[i]->contents()->usesRemUnits()) 245 return true; 246 } 247 return false; 248 } 249 250 bool DocumentStyleSheetCollection::updateActiveStyleSheets(StyleResolverUpdateMode updateMode) 251 { 252 if (m_document->inStyleRecalc()) { 253 // SVG <use> element may manage to invalidate style selector in the middle of a style recalc. 254 // https://bugs.webkit.org/show_bug.cgi?id=54344 255 // FIXME: This should be fixed in SVG and the call site replaced by ASSERT(!m_inStyleRecalc). 256 m_needsUpdateActiveStylesheetsOnStyleRecalc = true; 257 return false; 258 259 } 260 if (!m_document->renderer() || !m_document->attached()) 261 return false; 262 263 StyleSheetCollection::StyleResolverUpdateType styleResolverUpdateType; 264 bool requiresFullStyleRecalc = m_collectionForDocument.updateActiveStyleSheets(this, updateMode, styleResolverUpdateType); 265 m_needsUpdateActiveStylesheetsOnStyleRecalc = false; 266 267 if (styleResolverUpdateType != StyleSheetCollection::Reconstruct) 268 resetCSSFeatureFlags(m_document->styleResolver()->ruleFeatureSet()); 269 270 InspectorInstrumentation::activeStyleSheetsUpdated(m_document, m_collectionForDocument.styleSheetsForStyleSheetList()); 271 m_usesRemUnits = styleSheetsUseRemUnits(m_collectionForDocument.activeAuthorStyleSheets()); 272 m_document->notifySeamlessChildDocumentsOfStylesheetUpdate(); 273 274 return requiresFullStyleRecalc; 275 } 276 277 } 278