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, 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