Home | History | Annotate | Download | only in dom
      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