Torne (Richard Coles) | 53e740f | 2013-05-09 18:38:43 +0100 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 1999 Lars Knoll (knoll@kde.org) |
| 3 | * (C) 1999 Antti Koivisto (koivisto@kde.org) |
| 4 | * (C) 2001 Dirk Mueller (mueller@kde.org) |
| 5 | * (C) 2006 Alexey Proskuryakov (ap@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" |
Torne (Richard Coles) | 53e740f | 2013-05-09 18:38:43 +0100 | [diff] [blame] | 33 | #include "core/css/CSSStyleSheet.h" |
Torne (Richard Coles) | 53e740f | 2013-05-09 18:38:43 +0100 | [diff] [blame] | 34 | #include "core/css/StyleInvalidationAnalysis.h" |
Torne (Richard Coles) | 53e740f | 2013-05-09 18:38:43 +0100 | [diff] [blame] | 35 | #include "core/css/StyleSheetContents.h" |
Torne (Richard Coles) | 81a5157 | 2013-05-13 16:52:28 +0100 | [diff] [blame] | 36 | #include "core/css/resolver/StyleResolver.h" |
Torne (Richard Coles) | 53e740f | 2013-05-09 18:38:43 +0100 | [diff] [blame] | 37 | #include "core/dom/Document.h" |
| 38 | #include "core/dom/Element.h" |
| 39 | #include "core/dom/ProcessingInstruction.h" |
Torne (Richard Coles) | 53e740f | 2013-05-09 18:38:43 +0100 | [diff] [blame] | 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" |
Torne (Richard Coles) | 53e740f | 2013-05-09 18:38:43 +0100 | [diff] [blame] | 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) |
Torne (Richard Coles) | 53e740f | 2013-05-09 18:38:43 +0100 | [diff] [blame] | 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) |
Ben Murdoch | e69819b | 2013-07-17 14:56:49 +0100 | [diff] [blame] | 65 | , m_collectionForDocument(document) |
Torne (Richard Coles) | 53e740f | 2013-05-09 18:38:43 +0100 | [diff] [blame] | 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 | |
Ben Murdoch | e69819b | 2013-07-17 14:56:49 +0100 | [diff] [blame] | 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 | |
Ben Murdoch | 7757ec2 | 2013-07-23 11:17:36 +0100 | [diff] [blame] | 93 | void DocumentStyleSheetCollection::combineCSSFeatureFlags(const RuleFeatureSet& features) |
Torne (Richard Coles) | 53e740f | 2013-05-09 18:38:43 +0100 | [diff] [blame] | 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). |
Ben Murdoch | 7757ec2 | 2013-07-23 11:17:36 +0100 | [diff] [blame] | 96 | m_usesSiblingRules = m_usesSiblingRules || features.usesSiblingRules(); |
| 97 | m_usesFirstLineRules = m_usesFirstLineRules || features.usesFirstLineRules(); |
| 98 | m_usesBeforeAfterRules = m_usesBeforeAfterRules || features.usesBeforeAfterRules(); |
Torne (Richard Coles) | 53e740f | 2013-05-09 18:38:43 +0100 | [diff] [blame] | 99 | } |
| 100 | |
Ben Murdoch | 7757ec2 | 2013-07-23 11:17:36 +0100 | [diff] [blame] | 101 | void DocumentStyleSheetCollection::resetCSSFeatureFlags(const RuleFeatureSet& features) |
Torne (Richard Coles) | 53e740f | 2013-05-09 18:38:43 +0100 | [diff] [blame] | 102 | { |
Ben Murdoch | 7757ec2 | 2013-07-23 11:17:36 +0100 | [diff] [blame] | 103 | m_usesSiblingRules = features.usesSiblingRules(); |
| 104 | m_usesFirstLineRules = features.usesFirstLineRules(); |
| 105 | m_usesBeforeAfterRules = features.usesBeforeAfterRules(); |
Torne (Richard Coles) | 53e740f | 2013-05-09 18:38:43 +0100 | [diff] [blame] | 106 | } |
| 107 | |
| 108 | CSSStyleSheet* DocumentStyleSheetCollection::pageUserSheet() |
| 109 | { |
| 110 | if (m_pageUserSheet) |
| 111 | return m_pageUserSheet.get(); |
Ben Murdoch | 7757ec2 | 2013-07-23 11:17:36 +0100 | [diff] [blame] | 112 | |
Torne (Richard Coles) | 53e740f | 2013-05-09 18:38:43 +0100 | [diff] [blame] | 113 | Page* owningPage = m_document->page(); |
| 114 | if (!owningPage) |
| 115 | return 0; |
Ben Murdoch | 7757ec2 | 2013-07-23 11:17:36 +0100 | [diff] [blame] | 116 | |
Torne (Richard Coles) | 53e740f | 2013-05-09 18:38:43 +0100 | [diff] [blame] | 117 | String userSheetText = owningPage->userStyleSheet(); |
| 118 | if (userSheetText.isEmpty()) |
| 119 | return 0; |
Ben Murdoch | 7757ec2 | 2013-07-23 11:17:36 +0100 | [diff] [blame] | 120 | |
Torne (Richard Coles) | 53e740f | 2013-05-09 18:38:43 +0100 | [diff] [blame] | 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) { |
Ben Murdoch | e69819b | 2013-07-17 14:56:49 +0100 | [diff] [blame] | 131 | RefPtr<StyleSheet> removedSheet = m_pageUserSheet; |
Torne (Richard Coles) | 53e740f | 2013-05-09 18:38:43 +0100 | [diff] [blame] | 132 | m_pageUserSheet = 0; |
Ben Murdoch | e69819b | 2013-07-17 14:56:49 +0100 | [diff] [blame] | 133 | m_document->removedStyleSheet(removedSheet.get()); |
Torne (Richard Coles) | 53e740f | 2013-05-09 18:38:43 +0100 | [diff] [blame] | 134 | } |
| 135 | } |
| 136 | |
| 137 | void DocumentStyleSheetCollection::updatePageUserSheet() |
| 138 | { |
| 139 | clearPageUserSheet(); |
Ben Murdoch | e69819b | 2013-07-17 14:56:49 +0100 | [diff] [blame] | 140 | // FIXME: Why is this immediately and not defer? |
| 141 | if (StyleSheet* addedSheet = pageUserSheet()) |
| 142 | m_document->addedStyleSheet(addedSheet, RecalcStyleImmediately); |
Torne (Richard Coles) | 53e740f | 2013-05-09 18:38:43 +0100 | [diff] [blame] | 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; |
Ben Murdoch | e69819b | 2013-07-17 14:56:49 +0100 | [diff] [blame] | 191 | // FIXME: updateInjectedStyleSheetCache is called inside StyleSheetCollection::updateActiveStyleSheets |
| 192 | // and batch updates lots of sheets so we can't call addedStyleSheet() or removedStyleSheet(). |
Torne (Richard Coles) | 53e740f | 2013-05-09 18:38:43 +0100 | [diff] [blame] | 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)); |
Ben Murdoch | e69819b | 2013-07-17 14:56:49 +0100 | [diff] [blame] | 200 | m_document->addedStyleSheet(m_authorStyleSheets.last().get(), RecalcStyleImmediately); |
Torne (Richard Coles) | 53e740f | 2013-05-09 18:38:43 +0100 | [diff] [blame] | 201 | } |
| 202 | |
| 203 | void DocumentStyleSheetCollection::addUserSheet(PassRefPtr<StyleSheetContents> userSheet) |
| 204 | { |
| 205 | ASSERT(userSheet->isUserStyleSheet()); |
| 206 | m_userStyleSheets.append(CSSStyleSheet::create(userSheet, m_document)); |
Ben Murdoch | e69819b | 2013-07-17 14:56:49 +0100 | [diff] [blame] | 207 | m_document->addedStyleSheet(m_userStyleSheets.last().get(), RecalcStyleImmediately); |
Torne (Richard Coles) | 53e740f | 2013-05-09 18:38:43 +0100 | [diff] [blame] | 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--; |
Torne (Richard Coles) | 53e740f | 2013-05-09 18:38:43 +0100 | [diff] [blame] | 217 | |
| 218 | if (m_pendingStylesheets) |
| 219 | return; |
| 220 | |
| 221 | if (notification == RemovePendingSheetNotifyLater) { |
| 222 | m_document->setNeedsNotifyRemoveAllPendingStylesheet(); |
| 223 | return; |
| 224 | } |
Ben Murdoch | e69819b | 2013-07-17 14:56:49 +0100 | [diff] [blame] | 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. |
Torne (Richard Coles) | 53e740f | 2013-05-09 18:38:43 +0100 | [diff] [blame] | 228 | m_document->didRemoveAllPendingStylesheet(); |
| 229 | } |
| 230 | |
| 231 | void DocumentStyleSheetCollection::addStyleSheetCandidateNode(Node* node, bool createdByParser) |
| 232 | { |
Ben Murdoch | e69819b | 2013-07-17 14:56:49 +0100 | [diff] [blame] | 233 | m_collectionForDocument.addStyleSheetCandidateNode(node, createdByParser); |
Torne (Richard Coles) | 53e740f | 2013-05-09 18:38:43 +0100 | [diff] [blame] | 234 | } |
| 235 | |
Ben Murdoch | 02772c6 | 2013-07-26 10:21:05 +0100 | [diff] [blame] | 236 | void DocumentStyleSheetCollection::removeStyleSheetCandidateNode(Node* node, ContainerNode* scopingNode) |
Torne (Richard Coles) | 53e740f | 2013-05-09 18:38:43 +0100 | [diff] [blame] | 237 | { |
Ben Murdoch | 02772c6 | 2013-07-26 10:21:05 +0100 | [diff] [blame] | 238 | m_collectionForDocument.removeStyleSheetCandidateNode(node, scopingNode); |
Torne (Richard Coles) | 53e740f | 2013-05-09 18:38:43 +0100 | [diff] [blame] | 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 | |
Ben Murdoch | 591b958 | 2013-07-10 11:41:44 +0100 | [diff] [blame] | 250 | bool DocumentStyleSheetCollection::updateActiveStyleSheets(StyleResolverUpdateMode updateMode) |
Torne (Richard Coles) | 53e740f | 2013-05-09 18:38:43 +0100 | [diff] [blame] | 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; |
Torne (Richard Coles) | 53e740f | 2013-05-09 18:38:43 +0100 | [diff] [blame] | 257 | return false; |
| 258 | |
| 259 | } |
| 260 | if (!m_document->renderer() || !m_document->attached()) |
| 261 | return false; |
| 262 | |
Ben Murdoch | e69819b | 2013-07-17 14:56:49 +0100 | [diff] [blame] | 263 | StyleSheetCollection::StyleResolverUpdateType styleResolverUpdateType; |
| 264 | bool requiresFullStyleRecalc = m_collectionForDocument.updateActiveStyleSheets(this, updateMode, styleResolverUpdateType); |
Torne (Richard Coles) | 53e740f | 2013-05-09 18:38:43 +0100 | [diff] [blame] | 265 | m_needsUpdateActiveStylesheetsOnStyleRecalc = false; |
| 266 | |
Ben Murdoch | e69819b | 2013-07-17 14:56:49 +0100 | [diff] [blame] | 267 | if (styleResolverUpdateType != StyleSheetCollection::Reconstruct) |
Ben Murdoch | 7757ec2 | 2013-07-23 11:17:36 +0100 | [diff] [blame] | 268 | resetCSSFeatureFlags(m_document->styleResolver()->ruleFeatureSet()); |
Ben Murdoch | e69819b | 2013-07-17 14:56:49 +0100 | [diff] [blame] | 269 | |
| 270 | InspectorInstrumentation::activeStyleSheetsUpdated(m_document, m_collectionForDocument.styleSheetsForStyleSheetList()); |
| 271 | m_usesRemUnits = styleSheetsUseRemUnits(m_collectionForDocument.activeAuthorStyleSheets()); |
Torne (Richard Coles) | 53e740f | 2013-05-09 18:38:43 +0100 | [diff] [blame] | 272 | m_document->notifySeamlessChildDocumentsOfStylesheetUpdate(); |
| 273 | |
| 274 | return requiresFullStyleRecalc; |
| 275 | } |
| 276 | |
Torne (Richard Coles) | 53e740f | 2013-05-09 18:38:43 +0100 | [diff] [blame] | 277 | } |