Home | History | Annotate | Download | only in css
      1 /*
      2  * (C) 1999-2003 Lars Knoll (knoll (at) kde.org)
      3  * Copyright (C) 2004, 2006, 2007, 2012 Apple Inc. All rights reserved.
      4  *
      5  * This library is free software; you can redistribute it and/or
      6  * modify it under the terms of the GNU Library General Public
      7  * License as published by the Free Software Foundation; either
      8  * version 2 of the License, or (at your option) any later version.
      9  *
     10  * This library is distributed in the hope that it will be useful,
     11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     13  * Library General Public License for more details.
     14  *
     15  * You should have received a copy of the GNU Library General Public License
     16  * along with this library; see the file COPYING.LIB.  If not, write to
     17  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
     18  * Boston, MA 02110-1301, USA.
     19  */
     20 
     21 #include "config.h"
     22 #include "core/css/StyleSheetContents.h"
     23 
     24 #include "core/css/CSSStyleSheet.h"
     25 #include "core/css/MediaList.h"
     26 #include "core/css/StylePropertySet.h"
     27 #include "core/css/StyleRule.h"
     28 #include "core/css/StyleRuleImport.h"
     29 #include "core/css/parser/CSSParser.h"
     30 #include "core/dom/Document.h"
     31 #include "core/dom/Node.h"
     32 #include "core/dom/StyleEngine.h"
     33 #include "core/fetch/CSSStyleSheetResource.h"
     34 #include "core/frame/UseCounter.h"
     35 #include "platform/TraceEvent.h"
     36 #include "platform/weborigin/SecurityOrigin.h"
     37 #include "wtf/Deque.h"
     38 
     39 namespace blink {
     40 
     41 // Rough size estimate for the memory cache.
     42 unsigned StyleSheetContents::estimatedSizeInBytes() const
     43 {
     44     // Note that this does not take into account size of the strings hanging from various objects.
     45     // The assumption is that nearly all of of them are atomic and would exist anyway.
     46     unsigned size = sizeof(*this);
     47 
     48     // FIXME: This ignores the children of media rules.
     49     // Most rules are StyleRules.
     50     size += ruleCount() * StyleRule::averageSizeInBytes();
     51 
     52     for (unsigned i = 0; i < m_importRules.size(); ++i) {
     53         if (StyleSheetContents* sheet = m_importRules[i]->styleSheet())
     54             size += sheet->estimatedSizeInBytes();
     55     }
     56     return size;
     57 }
     58 
     59 StyleSheetContents::StyleSheetContents(StyleRuleImport* ownerRule, const String& originalURL, const CSSParserContext& context)
     60     : m_ownerRule(ownerRule)
     61     , m_originalURL(originalURL)
     62     , m_hasSyntacticallyValidCSSHeader(true)
     63     , m_didLoadErrorOccur(false)
     64     , m_usesRemUnits(false)
     65     , m_isMutable(false)
     66     , m_isInMemoryCache(false)
     67     , m_hasFontFaceRule(false)
     68     , m_hasMediaQueries(false)
     69     , m_hasSingleOwnerDocument(true)
     70     , m_parserContext(context)
     71 {
     72 }
     73 
     74 StyleSheetContents::StyleSheetContents(const StyleSheetContents& o)
     75     : m_ownerRule(nullptr)
     76     , m_originalURL(o.m_originalURL)
     77     , m_encodingFromCharsetRule(o.m_encodingFromCharsetRule)
     78     , m_importRules(o.m_importRules.size())
     79     , m_childRules(o.m_childRules.size())
     80     , m_namespaces(o.m_namespaces)
     81     , m_hasSyntacticallyValidCSSHeader(o.m_hasSyntacticallyValidCSSHeader)
     82     , m_didLoadErrorOccur(false)
     83     , m_usesRemUnits(o.m_usesRemUnits)
     84     , m_isMutable(false)
     85     , m_isInMemoryCache(false)
     86     , m_hasFontFaceRule(o.m_hasFontFaceRule)
     87     , m_hasMediaQueries(o.m_hasMediaQueries)
     88     , m_hasSingleOwnerDocument(true)
     89     , m_parserContext(o.m_parserContext)
     90 {
     91     ASSERT(o.isCacheable());
     92 
     93     // FIXME: Copy import rules.
     94     ASSERT(o.m_importRules.isEmpty());
     95 
     96     for (unsigned i = 0; i < m_childRules.size(); ++i)
     97         m_childRules[i] = o.m_childRules[i]->copy();
     98 }
     99 
    100 StyleSheetContents::~StyleSheetContents()
    101 {
    102 #if !ENABLE(OILPAN)
    103     clearRules();
    104 #endif
    105 }
    106 
    107 void StyleSheetContents::setHasSyntacticallyValidCSSHeader(bool isValidCss)
    108 {
    109     if (!isValidCss) {
    110         if (Document* document = clientSingleOwnerDocument())
    111             removeSheetFromCache(document);
    112     }
    113     m_hasSyntacticallyValidCSSHeader = isValidCss;
    114 }
    115 
    116 bool StyleSheetContents::isCacheable() const
    117 {
    118     // This would require dealing with multiple clients for load callbacks.
    119     if (!loadCompleted())
    120         return false;
    121     // FIXME: StyleSheets with media queries can't be cached because their RuleSet
    122     // is processed differently based off the media queries, which might resolve
    123     // differently depending on the context of the parent CSSStyleSheet (e.g.
    124     // if they are in differently sized iframes). Once RuleSets are media query
    125     // agnostic, we can restore sharing of StyleSheetContents with medea queries.
    126     if (m_hasMediaQueries)
    127         return false;
    128     // FIXME: Support copying import rules.
    129     if (!m_importRules.isEmpty())
    130         return false;
    131     // FIXME: Support cached stylesheets in import rules.
    132     if (m_ownerRule)
    133         return false;
    134     if (m_didLoadErrorOccur)
    135         return false;
    136     // It is not the original sheet anymore.
    137     if (m_isMutable)
    138         return false;
    139     // If the header is valid we are not going to need to check the SecurityOrigin.
    140     // FIXME: Valid mime type avoids the check too.
    141     if (!m_hasSyntacticallyValidCSSHeader)
    142         return false;
    143     return true;
    144 }
    145 
    146 void StyleSheetContents::parserAppendRule(PassRefPtrWillBeRawPtr<StyleRuleBase> rule)
    147 {
    148     ASSERT(!rule->isCharsetRule());
    149     if (rule->isImportRule()) {
    150         // Parser enforces that @import rules come before anything else except @charset.
    151         ASSERT(m_childRules.isEmpty());
    152         StyleRuleImport* importRule = toStyleRuleImport(rule.get());
    153         if (importRule->mediaQueries())
    154             setHasMediaQueries();
    155         m_importRules.append(importRule);
    156         m_importRules.last()->setParentStyleSheet(this);
    157         m_importRules.last()->requestStyleSheet();
    158         return;
    159     }
    160 
    161     // Add warning message to inspector if dpi/dpcm values are used for screen media.
    162     if (rule->isMediaRule()) {
    163         setHasMediaQueries();
    164         reportMediaQueryWarningIfNeeded(singleOwnerDocument(), toStyleRuleMedia(rule.get())->mediaQueries());
    165     }
    166 
    167     m_childRules.append(rule);
    168 }
    169 
    170 void StyleSheetContents::setHasMediaQueries()
    171 {
    172     m_hasMediaQueries = true;
    173     if (parentStyleSheet())
    174         parentStyleSheet()->setHasMediaQueries();
    175 }
    176 
    177 StyleRuleBase* StyleSheetContents::ruleAt(unsigned index) const
    178 {
    179     ASSERT_WITH_SECURITY_IMPLICATION(index < ruleCount());
    180 
    181     unsigned childVectorIndex = index;
    182     if (hasCharsetRule()) {
    183         if (index == 0)
    184             return 0;
    185         --childVectorIndex;
    186     }
    187     if (childVectorIndex < m_importRules.size())
    188         return m_importRules[childVectorIndex].get();
    189 
    190     childVectorIndex -= m_importRules.size();
    191     return m_childRules[childVectorIndex].get();
    192 }
    193 
    194 unsigned StyleSheetContents::ruleCount() const
    195 {
    196     unsigned result = 0;
    197     result += hasCharsetRule() ? 1 : 0;
    198     result += m_importRules.size();
    199     result += m_childRules.size();
    200     return result;
    201 }
    202 
    203 void StyleSheetContents::clearCharsetRule()
    204 {
    205     m_encodingFromCharsetRule = String();
    206 }
    207 
    208 void StyleSheetContents::clearRules()
    209 {
    210     for (unsigned i = 0; i < m_importRules.size(); ++i) {
    211         ASSERT(m_importRules.at(i)->parentStyleSheet() == this);
    212         m_importRules[i]->clearParentStyleSheet();
    213     }
    214     m_importRules.clear();
    215     m_childRules.clear();
    216     clearCharsetRule();
    217 }
    218 
    219 void StyleSheetContents::parserSetEncodingFromCharsetRule(const String& encoding)
    220 {
    221     // Parser enforces that there is ever only one @charset.
    222     ASSERT(m_encodingFromCharsetRule.isNull());
    223     m_encodingFromCharsetRule = encoding;
    224 }
    225 
    226 bool StyleSheetContents::wrapperInsertRule(PassRefPtrWillBeRawPtr<StyleRuleBase> rule, unsigned index)
    227 {
    228     ASSERT(m_isMutable);
    229     ASSERT_WITH_SECURITY_IMPLICATION(index <= ruleCount());
    230     // Parser::parseRule doesn't currently allow @charset so we don't need to deal with it.
    231     ASSERT(!rule->isCharsetRule());
    232 
    233     unsigned childVectorIndex = index;
    234     // m_childRules does not contain @charset which is always in index 0 if it exists.
    235     if (hasCharsetRule()) {
    236         if (childVectorIndex == 0) {
    237             // Nothing can be inserted before @charset.
    238             return false;
    239         }
    240         --childVectorIndex;
    241     }
    242 
    243     if (childVectorIndex < m_importRules.size() || (childVectorIndex == m_importRules.size() && rule->isImportRule())) {
    244         // Inserting non-import rule before @import is not allowed.
    245         if (!rule->isImportRule())
    246             return false;
    247 
    248         StyleRuleImport* importRule = toStyleRuleImport(rule.get());
    249         if (importRule->mediaQueries())
    250             setHasMediaQueries();
    251 
    252         m_importRules.insert(childVectorIndex, importRule);
    253         m_importRules[childVectorIndex]->setParentStyleSheet(this);
    254         m_importRules[childVectorIndex]->requestStyleSheet();
    255         // FIXME: Stylesheet doesn't actually change meaningfully before the imported sheets are loaded.
    256         return true;
    257     }
    258     // Inserting @import rule after a non-import rule is not allowed.
    259     if (rule->isImportRule())
    260         return false;
    261 
    262     if (rule->isMediaRule())
    263         setHasMediaQueries();
    264 
    265     childVectorIndex -= m_importRules.size();
    266 
    267     if (rule->isFontFaceRule())
    268         setHasFontFaceRule(true);
    269     m_childRules.insert(childVectorIndex, rule);
    270     return true;
    271 }
    272 
    273 void StyleSheetContents::wrapperDeleteRule(unsigned index)
    274 {
    275     ASSERT(m_isMutable);
    276     ASSERT_WITH_SECURITY_IMPLICATION(index < ruleCount());
    277 
    278     unsigned childVectorIndex = index;
    279     if (hasCharsetRule()) {
    280         if (childVectorIndex == 0) {
    281             clearCharsetRule();
    282             return;
    283         }
    284         --childVectorIndex;
    285     }
    286     if (childVectorIndex < m_importRules.size()) {
    287         m_importRules[childVectorIndex]->clearParentStyleSheet();
    288         if (m_importRules[childVectorIndex]->isFontFaceRule())
    289             notifyRemoveFontFaceRule(toStyleRuleFontFace(m_importRules[childVectorIndex].get()));
    290         m_importRules.remove(childVectorIndex);
    291         return;
    292     }
    293     childVectorIndex -= m_importRules.size();
    294 
    295     if (m_childRules[childVectorIndex]->isFontFaceRule())
    296         notifyRemoveFontFaceRule(toStyleRuleFontFace(m_childRules[childVectorIndex].get()));
    297     m_childRules.remove(childVectorIndex);
    298 }
    299 
    300 void StyleSheetContents::parserAddNamespace(const AtomicString& prefix, const AtomicString& uri)
    301 {
    302     if (uri.isNull() || prefix.isNull())
    303         return;
    304     PrefixNamespaceURIMap::AddResult result = m_namespaces.add(prefix, uri);
    305     if (result.isNewEntry)
    306         return;
    307     result.storedValue->value = uri;
    308 }
    309 
    310 const AtomicString& StyleSheetContents::determineNamespace(const AtomicString& prefix)
    311 {
    312     if (prefix.isNull())
    313         return nullAtom; // No namespace. If an element/attribute has a namespace, we won't match it.
    314     if (prefix == starAtom)
    315         return starAtom; // We'll match any namespace.
    316     return m_namespaces.get(prefix);
    317 }
    318 
    319 void StyleSheetContents::parseAuthorStyleSheet(const CSSStyleSheetResource* cachedStyleSheet, const SecurityOrigin* securityOrigin)
    320 {
    321     TRACE_EVENT0("blink", "StyleSheetContents::parseAuthorStyleSheet");
    322 
    323     bool quirksMode = isQuirksModeBehavior(m_parserContext.mode());
    324 
    325     bool enforceMIMEType = !quirksMode;
    326     bool hasValidMIMEType = false;
    327     String sheetText = cachedStyleSheet->sheetText(enforceMIMEType, &hasValidMIMEType);
    328 
    329     CSSParserContext context(parserContext(), UseCounter::getFrom(this));
    330     CSSParser::parseSheet(context, this, sheetText, TextPosition::minimumPosition(), 0, true);
    331 
    332     // If we're loading a stylesheet cross-origin, and the MIME type is not standard, require the CSS
    333     // to at least start with a syntactically valid CSS rule.
    334     // This prevents an attacker playing games by injecting CSS strings into HTML, XML, JSON, etc. etc.
    335     if (!hasValidMIMEType && !hasSyntacticallyValidCSSHeader()) {
    336         bool isCrossOriginCSS = !securityOrigin || !securityOrigin->canRequest(baseURL());
    337         if (isCrossOriginCSS) {
    338             clearRules();
    339             return;
    340         }
    341     }
    342 }
    343 
    344 bool StyleSheetContents::parseString(const String& sheetText)
    345 {
    346     return parseStringAtPosition(sheetText, TextPosition::minimumPosition(), false);
    347 }
    348 
    349 bool StyleSheetContents::parseStringAtPosition(const String& sheetText, const TextPosition& startPosition, bool createdByParser)
    350 {
    351     CSSParserContext context(parserContext(), UseCounter::getFrom(this));
    352     CSSParser::parseSheet(context, this, sheetText, startPosition, 0, createdByParser);
    353 
    354     return true;
    355 }
    356 
    357 bool StyleSheetContents::isLoading() const
    358 {
    359     for (unsigned i = 0; i < m_importRules.size(); ++i) {
    360         if (m_importRules[i]->isLoading())
    361             return true;
    362     }
    363     return false;
    364 }
    365 
    366 bool StyleSheetContents::loadCompleted() const
    367 {
    368     StyleSheetContents* parentSheet = parentStyleSheet();
    369     if (parentSheet)
    370         return parentSheet->loadCompleted();
    371 
    372     StyleSheetContents* root = rootStyleSheet();
    373     return root->m_loadingClients.isEmpty();
    374 }
    375 
    376 void StyleSheetContents::checkLoaded()
    377 {
    378     if (isLoading())
    379         return;
    380 
    381     // Avoid |this| being deleted by scripts that run via
    382     // ScriptableDocumentParser::executeScriptsWaitingForResources().
    383     // See https://bugs.webkit.org/show_bug.cgi?id=95106
    384     RefPtrWillBeRawPtr<StyleSheetContents> protect(this);
    385 
    386     StyleSheetContents* parentSheet = parentStyleSheet();
    387     if (parentSheet) {
    388         parentSheet->checkLoaded();
    389         return;
    390     }
    391 
    392     ASSERT(this == rootStyleSheet());
    393     if (m_loadingClients.isEmpty())
    394         return;
    395 
    396     // Avoid |CSSSStyleSheet| and |ownerNode| being deleted by scripts that run via
    397     // ScriptableDocumentParser::executeScriptsWaitingForResources(). Also protect
    398     // the |CSSStyleSheet| from being deleted during iteration via the |sheetLoaded|
    399     // method.
    400     //
    401     // When a sheet is loaded it is moved from the set of loading clients
    402     // to the set of completed clients. We therefore need the copy in order to
    403     // not modify the set while iterating it.
    404     WillBeHeapVector<RefPtrWillBeMember<CSSStyleSheet> > loadingClients;
    405     copyToVector(m_loadingClients, loadingClients);
    406 
    407     for (unsigned i = 0; i < loadingClients.size(); ++i) {
    408         if (loadingClients[i]->loadCompleted())
    409             continue;
    410 
    411         // sheetLoaded might be invoked after its owner node is removed from document.
    412         if (RefPtrWillBeRawPtr<Node> ownerNode = loadingClients[i]->ownerNode()) {
    413             if (loadingClients[i]->sheetLoaded())
    414                 ownerNode->notifyLoadedSheetAndAllCriticalSubresources(m_didLoadErrorOccur);
    415         }
    416     }
    417 }
    418 
    419 void StyleSheetContents::notifyLoadedSheet(const CSSStyleSheetResource* sheet)
    420 {
    421     ASSERT(sheet);
    422     m_didLoadErrorOccur |= sheet->errorOccurred();
    423     // updateLayoutIgnorePendingStyleSheets can cause us to create the RuleSet on this
    424     // sheet before its imports have loaded. So clear the RuleSet when the imports
    425     // load since the import's subrules are flattened into its parent sheet's RuleSet.
    426     clearRuleSet();
    427 }
    428 
    429 void StyleSheetContents::startLoadingDynamicSheet()
    430 {
    431     StyleSheetContents* root = rootStyleSheet();
    432     for (ClientsIterator it = root->m_loadingClients.begin(); it != root->m_loadingClients.end(); ++it)
    433         (*it)->startLoadingDynamicSheet();
    434     // Copy the completed clients to a vector for iteration.
    435     // startLoadingDynamicSheet will move the style sheet from the
    436     // completed state to the loading state which modifies the set of
    437     // completed clients. We therefore need the copy in order to not
    438     // modify the set of completed clients while iterating it.
    439     WillBeHeapVector<RawPtrWillBeMember<CSSStyleSheet> > completedClients;
    440     copyToVector(root->m_completedClients, completedClients);
    441     for (unsigned i = 0; i < completedClients.size(); ++i)
    442         completedClients[i]->startLoadingDynamicSheet();
    443 }
    444 
    445 StyleSheetContents* StyleSheetContents::rootStyleSheet() const
    446 {
    447     const StyleSheetContents* root = this;
    448     while (root->parentStyleSheet())
    449         root = root->parentStyleSheet();
    450     return const_cast<StyleSheetContents*>(root);
    451 }
    452 
    453 bool StyleSheetContents::hasSingleOwnerNode() const
    454 {
    455     return rootStyleSheet()->hasOneClient();
    456 }
    457 
    458 Node* StyleSheetContents::singleOwnerNode() const
    459 {
    460     StyleSheetContents* root = rootStyleSheet();
    461     if (!root->hasOneClient())
    462         return 0;
    463     if (root->m_loadingClients.size())
    464         return (*root->m_loadingClients.begin())->ownerNode();
    465     return (*root->m_completedClients.begin())->ownerNode();
    466 }
    467 
    468 Document* StyleSheetContents::singleOwnerDocument() const
    469 {
    470     StyleSheetContents* root = rootStyleSheet();
    471     return root->clientSingleOwnerDocument();
    472 }
    473 
    474 KURL StyleSheetContents::completeURL(const String& url) const
    475 {
    476     // FIXME: This is only OK when we have a singleOwnerNode, right?
    477     return m_parserContext.completeURL(url);
    478 }
    479 
    480 static bool childRulesHaveFailedOrCanceledSubresources(const WillBeHeapVector<RefPtrWillBeMember<StyleRuleBase> >& rules)
    481 {
    482     for (unsigned i = 0; i < rules.size(); ++i) {
    483         const StyleRuleBase* rule = rules[i].get();
    484         switch (rule->type()) {
    485         case StyleRuleBase::Style:
    486             if (toStyleRule(rule)->properties().hasFailedOrCanceledSubresources())
    487                 return true;
    488             break;
    489         case StyleRuleBase::FontFace:
    490             if (toStyleRuleFontFace(rule)->properties().hasFailedOrCanceledSubresources())
    491                 return true;
    492             break;
    493         case StyleRuleBase::Media:
    494             if (childRulesHaveFailedOrCanceledSubresources(toStyleRuleMedia(rule)->childRules()))
    495                 return true;
    496             break;
    497         case StyleRuleBase::Import:
    498             ASSERT_NOT_REACHED();
    499         case StyleRuleBase::Page:
    500         case StyleRuleBase::Keyframes:
    501         case StyleRuleBase::Unknown:
    502         case StyleRuleBase::Charset:
    503         case StyleRuleBase::Keyframe:
    504         case StyleRuleBase::Supports:
    505         case StyleRuleBase::Viewport:
    506         case StyleRuleBase::Filter:
    507             break;
    508         }
    509     }
    510     return false;
    511 }
    512 
    513 bool StyleSheetContents::hasFailedOrCanceledSubresources() const
    514 {
    515     ASSERT(isCacheable());
    516     return childRulesHaveFailedOrCanceledSubresources(m_childRules);
    517 }
    518 
    519 Document* StyleSheetContents::clientSingleOwnerDocument() const
    520 {
    521     if (!m_hasSingleOwnerDocument || clientSize() <= 0)
    522         return 0;
    523 
    524     if (m_loadingClients.size())
    525         return (*m_loadingClients.begin())->ownerDocument();
    526     return (*m_completedClients.begin())->ownerDocument();
    527 }
    528 
    529 StyleSheetContents* StyleSheetContents::parentStyleSheet() const
    530 {
    531     return m_ownerRule ? m_ownerRule->parentStyleSheet() : 0;
    532 }
    533 
    534 void StyleSheetContents::registerClient(CSSStyleSheet* sheet)
    535 {
    536     ASSERT(!m_loadingClients.contains(sheet) && !m_completedClients.contains(sheet));
    537 
    538     // InspectorCSSAgent::buildObjectForRule creates CSSStyleSheet without any owner node.
    539     if (!sheet->ownerDocument())
    540         return;
    541 
    542     if (Document* document = clientSingleOwnerDocument()) {
    543         if (sheet->ownerDocument() != document)
    544             m_hasSingleOwnerDocument = false;
    545     }
    546     m_loadingClients.add(sheet);
    547 }
    548 
    549 void StyleSheetContents::unregisterClient(CSSStyleSheet* sheet)
    550 {
    551     m_loadingClients.remove(sheet);
    552     m_completedClients.remove(sheet);
    553 
    554     if (!sheet->ownerDocument() || !m_loadingClients.isEmpty() || !m_completedClients.isEmpty())
    555         return;
    556 
    557     if (m_hasSingleOwnerDocument)
    558         removeSheetFromCache(sheet->ownerDocument());
    559     m_hasSingleOwnerDocument = true;
    560 }
    561 
    562 void StyleSheetContents::clientLoadCompleted(CSSStyleSheet* sheet)
    563 {
    564     ASSERT(m_loadingClients.contains(sheet) || !sheet->ownerDocument());
    565     m_loadingClients.remove(sheet);
    566     // In m_ownerNode->sheetLoaded, the CSSStyleSheet might be detached.
    567     // (i.e. clearOwnerNode was invoked.)
    568     // In this case, we don't need to add the stylesheet to completed clients.
    569     if (!sheet->ownerDocument())
    570         return;
    571     m_completedClients.add(sheet);
    572 }
    573 
    574 void StyleSheetContents::clientLoadStarted(CSSStyleSheet* sheet)
    575 {
    576     ASSERT(m_completedClients.contains(sheet));
    577     m_completedClients.remove(sheet);
    578     m_loadingClients.add(sheet);
    579 }
    580 
    581 void StyleSheetContents::removeSheetFromCache(Document* document)
    582 {
    583     ASSERT(document);
    584     document->styleEngine()->removeSheet(this);
    585 }
    586 
    587 void StyleSheetContents::addedToMemoryCache()
    588 {
    589     ASSERT(!m_isInMemoryCache);
    590     ASSERT(isCacheable());
    591     m_isInMemoryCache = true;
    592 }
    593 
    594 void StyleSheetContents::removedFromMemoryCache()
    595 {
    596     ASSERT(m_isInMemoryCache);
    597     ASSERT(isCacheable());
    598     m_isInMemoryCache = false;
    599 }
    600 
    601 void StyleSheetContents::shrinkToFit()
    602 {
    603     m_importRules.shrinkToFit();
    604     m_childRules.shrinkToFit();
    605 }
    606 
    607 RuleSet& StyleSheetContents::ensureRuleSet(const MediaQueryEvaluator& medium, AddRuleFlags addRuleFlags)
    608 {
    609     if (!m_ruleSet) {
    610         m_ruleSet = RuleSet::create();
    611         m_ruleSet->addRulesFromSheet(this, medium, addRuleFlags);
    612     }
    613     return *m_ruleSet.get();
    614 }
    615 
    616 static void clearResolvers(WillBeHeapHashSet<RawPtrWillBeWeakMember<CSSStyleSheet> >& clients)
    617 {
    618     for (WillBeHeapHashSet<RawPtrWillBeWeakMember<CSSStyleSheet> >::iterator it = clients.begin(); it != clients.end(); ++it) {
    619         if (Document* document = (*it)->ownerDocument())
    620             document->styleEngine()->clearResolver();
    621     }
    622 }
    623 
    624 void StyleSheetContents::clearRuleSet()
    625 {
    626     if (StyleSheetContents* parentSheet = parentStyleSheet())
    627         parentSheet->clearRuleSet();
    628 
    629     // Don't want to clear the StyleResolver if the RuleSet hasn't been created
    630     // since we only clear the StyleResolver so that it's members are properly
    631     // updated in ScopedStyleResolver::addRulesFromSheet.
    632     if (!m_ruleSet)
    633         return;
    634 
    635     // Clearing the ruleSet means we need to recreate the styleResolver data structures.
    636     // See the StyleResolver calls in ScopedStyleResolver::addRulesFromSheet.
    637     clearResolvers(m_loadingClients);
    638     clearResolvers(m_completedClients);
    639     m_ruleSet.clear();
    640 }
    641 
    642 static void removeFontFaceRules(WillBeHeapHashSet<RawPtrWillBeWeakMember<CSSStyleSheet> >& clients, const StyleRuleFontFace* fontFaceRule)
    643 {
    644     for (WillBeHeapHashSet<RawPtrWillBeWeakMember<CSSStyleSheet> >::iterator it = clients.begin(); it != clients.end(); ++it) {
    645         if (Node* ownerNode = (*it)->ownerNode())
    646             ownerNode->document().styleEngine()->removeFontFaceRules(WillBeHeapVector<RawPtrWillBeMember<const StyleRuleFontFace> >(1, fontFaceRule));
    647     }
    648 }
    649 
    650 void StyleSheetContents::notifyRemoveFontFaceRule(const StyleRuleFontFace* fontFaceRule)
    651 {
    652     StyleSheetContents* root = rootStyleSheet();
    653     removeFontFaceRules(root->m_loadingClients, fontFaceRule);
    654     removeFontFaceRules(root->m_completedClients, fontFaceRule);
    655 }
    656 
    657 static void findFontFaceRulesFromRules(const WillBeHeapVector<RefPtrWillBeMember<StyleRuleBase> >& rules, WillBeHeapVector<RawPtrWillBeMember<const StyleRuleFontFace> >& fontFaceRules)
    658 {
    659     for (unsigned i = 0; i < rules.size(); ++i) {
    660         StyleRuleBase* rule = rules[i].get();
    661 
    662         if (rule->isFontFaceRule()) {
    663             fontFaceRules.append(toStyleRuleFontFace(rule));
    664         } else if (rule->isMediaRule()) {
    665             StyleRuleMedia* mediaRule = toStyleRuleMedia(rule);
    666             // We cannot know whether the media rule matches or not, but
    667             // for safety, remove @font-face in the media rule (if exists).
    668             findFontFaceRulesFromRules(mediaRule->childRules(), fontFaceRules);
    669         }
    670     }
    671 }
    672 
    673 void StyleSheetContents::findFontFaceRules(WillBeHeapVector<RawPtrWillBeMember<const StyleRuleFontFace> >& fontFaceRules)
    674 {
    675     for (unsigned i = 0; i < m_importRules.size(); ++i) {
    676         if (!m_importRules[i]->styleSheet())
    677             continue;
    678         m_importRules[i]->styleSheet()->findFontFaceRules(fontFaceRules);
    679     }
    680 
    681     findFontFaceRulesFromRules(childRules(), fontFaceRules);
    682 }
    683 
    684 void StyleSheetContents::trace(Visitor* visitor)
    685 {
    686 #if ENABLE(OILPAN)
    687     visitor->trace(m_ownerRule);
    688     visitor->trace(m_importRules);
    689     visitor->trace(m_childRules);
    690     visitor->trace(m_loadingClients);
    691     visitor->trace(m_completedClients);
    692     visitor->trace(m_ruleSet);
    693 #endif
    694 }
    695 
    696 }
    697