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/parser/BisonCSSParser.h"
     25 #include "core/css/CSSStyleSheet.h"
     26 #include "core/css/MediaList.h"
     27 #include "core/css/StylePropertySet.h"
     28 #include "core/css/StyleRule.h"
     29 #include "core/css/StyleRuleImport.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 WebCore {
     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("webkit", "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     BisonCSSParser p(context);
    331     p.parseSheet(this, sheetText, TextPosition::minimumPosition(), 0, true);
    332 
    333     // If we're loading a stylesheet cross-origin, and the MIME type is not standard, require the CSS
    334     // to at least start with a syntactically valid CSS rule.
    335     // This prevents an attacker playing games by injecting CSS strings into HTML, XML, JSON, etc. etc.
    336     if (!hasValidMIMEType && !hasSyntacticallyValidCSSHeader()) {
    337         bool isCrossOriginCSS = !securityOrigin || !securityOrigin->canRequest(baseURL());
    338         if (isCrossOriginCSS) {
    339             clearRules();
    340             return;
    341         }
    342     }
    343 }
    344 
    345 bool StyleSheetContents::parseString(const String& sheetText)
    346 {
    347     return parseStringAtPosition(sheetText, TextPosition::minimumPosition(), false);
    348 }
    349 
    350 bool StyleSheetContents::parseStringAtPosition(const String& sheetText, const TextPosition& startPosition, bool createdByParser)
    351 {
    352     CSSParserContext context(parserContext(), UseCounter::getFrom(this));
    353     BisonCSSParser p(context);
    354     p.parseSheet(this, sheetText, startPosition, 0, createdByParser);
    355 
    356     return true;
    357 }
    358 
    359 bool StyleSheetContents::isLoading() const
    360 {
    361     for (unsigned i = 0; i < m_importRules.size(); ++i) {
    362         if (m_importRules[i]->isLoading())
    363             return true;
    364     }
    365     return false;
    366 }
    367 
    368 bool StyleSheetContents::loadCompleted() const
    369 {
    370     StyleSheetContents* parentSheet = parentStyleSheet();
    371     if (parentSheet)
    372         return parentSheet->loadCompleted();
    373 
    374     StyleSheetContents* root = rootStyleSheet();
    375     return root->m_loadingClients.isEmpty();
    376 }
    377 
    378 void StyleSheetContents::checkLoaded()
    379 {
    380     if (isLoading())
    381         return;
    382 
    383     // Avoid |this| being deleted by scripts that run via
    384     // ScriptableDocumentParser::executeScriptsWaitingForResources().
    385     // See https://bugs.webkit.org/show_bug.cgi?id=95106
    386     RefPtrWillBeRawPtr<StyleSheetContents> protect(this);
    387 
    388     StyleSheetContents* parentSheet = parentStyleSheet();
    389     if (parentSheet) {
    390         parentSheet->checkLoaded();
    391         return;
    392     }
    393 
    394     StyleSheetContents* root = rootStyleSheet();
    395     if (root->m_loadingClients.isEmpty())
    396         return;
    397 
    398     // Avoid |CSSSStyleSheet| and |ownerNode| being deleted by scripts that run via
    399     // ScriptableDocumentParser::executeScriptsWaitingForResources(). Also protect
    400     // the |CSSStyleSheet| from being deleted during iteration via the |sheetLoaded|
    401     // method.
    402     //
    403     // When a sheet is loaded it is moved from the set of loading clients
    404     // to the set of completed clients. We therefore need the copy in order to
    405     // not modify the set while iterating it.
    406     WillBeHeapVector<RefPtrWillBeMember<CSSStyleSheet> > loadingClients;
    407     copyToVector(m_loadingClients, loadingClients);
    408 
    409     for (unsigned i = 0; i < loadingClients.size(); ++i) {
    410         if (loadingClients[i]->loadCompleted())
    411             continue;
    412 
    413         // sheetLoaded might be invoked after its owner node is removed from document.
    414         if (RefPtrWillBeRawPtr<Node> ownerNode = loadingClients[i]->ownerNode()) {
    415             if (loadingClients[i]->sheetLoaded())
    416                 ownerNode->notifyLoadedSheetAndAllCriticalSubresources(m_didLoadErrorOccur);
    417         }
    418     }
    419 }
    420 
    421 void StyleSheetContents::notifyLoadedSheet(const CSSStyleSheetResource* sheet)
    422 {
    423     ASSERT(sheet);
    424     m_didLoadErrorOccur |= sheet->errorOccurred();
    425     // updateLayoutIgnorePendingStyleSheets can cause us to create the RuleSet on this
    426     // sheet before its imports have loaded. So clear the RuleSet when the imports
    427     // load since the import's subrules are flattened into its parent sheet's RuleSet.
    428     clearRuleSet();
    429 }
    430 
    431 void StyleSheetContents::startLoadingDynamicSheet()
    432 {
    433     StyleSheetContents* root = rootStyleSheet();
    434     for (ClientsIterator it = root->m_loadingClients.begin(); it != root->m_loadingClients.end(); ++it)
    435         (*it)->startLoadingDynamicSheet();
    436     // Copy the completed clients to a vector for iteration.
    437     // startLoadingDynamicSheet will move the style sheet from the
    438     // completed state to the loading state which modifies the set of
    439     // completed clients. We therefore need the copy in order to not
    440     // modify the set of completed clients while iterating it.
    441     WillBeHeapVector<RawPtrWillBeMember<CSSStyleSheet> > completedClients;
    442     copyToVector(root->m_completedClients, completedClients);
    443     for (unsigned i = 0; i < completedClients.size(); ++i)
    444         completedClients[i]->startLoadingDynamicSheet();
    445 }
    446 
    447 StyleSheetContents* StyleSheetContents::rootStyleSheet() const
    448 {
    449     const StyleSheetContents* root = this;
    450     while (root->parentStyleSheet())
    451         root = root->parentStyleSheet();
    452     return const_cast<StyleSheetContents*>(root);
    453 }
    454 
    455 bool StyleSheetContents::hasSingleOwnerNode() const
    456 {
    457     return rootStyleSheet()->hasOneClient();
    458 }
    459 
    460 Node* StyleSheetContents::singleOwnerNode() const
    461 {
    462     StyleSheetContents* root = rootStyleSheet();
    463     if (!root->hasOneClient())
    464         return 0;
    465     if (root->m_loadingClients.size())
    466         return (*root->m_loadingClients.begin())->ownerNode();
    467     return (*root->m_completedClients.begin())->ownerNode();
    468 }
    469 
    470 Document* StyleSheetContents::singleOwnerDocument() const
    471 {
    472     StyleSheetContents* root = rootStyleSheet();
    473     return root->clientSingleOwnerDocument();
    474 }
    475 
    476 KURL StyleSheetContents::completeURL(const String& url) const
    477 {
    478     // FIXME: This is only OK when we have a singleOwnerNode, right?
    479     return m_parserContext.completeURL(url);
    480 }
    481 
    482 static bool childRulesHaveFailedOrCanceledSubresources(const WillBeHeapVector<RefPtrWillBeMember<StyleRuleBase> >& rules)
    483 {
    484     for (unsigned i = 0; i < rules.size(); ++i) {
    485         const StyleRuleBase* rule = rules[i].get();
    486         switch (rule->type()) {
    487         case StyleRuleBase::Style:
    488             if (toStyleRule(rule)->properties().hasFailedOrCanceledSubresources())
    489                 return true;
    490             break;
    491         case StyleRuleBase::FontFace:
    492             if (toStyleRuleFontFace(rule)->properties().hasFailedOrCanceledSubresources())
    493                 return true;
    494             break;
    495         case StyleRuleBase::Media:
    496             if (childRulesHaveFailedOrCanceledSubresources(toStyleRuleMedia(rule)->childRules()))
    497                 return true;
    498             break;
    499         case StyleRuleBase::Import:
    500             ASSERT_NOT_REACHED();
    501         case StyleRuleBase::Page:
    502         case StyleRuleBase::Keyframes:
    503         case StyleRuleBase::Unknown:
    504         case StyleRuleBase::Charset:
    505         case StyleRuleBase::Keyframe:
    506         case StyleRuleBase::Supports:
    507         case StyleRuleBase::Viewport:
    508         case StyleRuleBase::Filter:
    509             break;
    510         }
    511     }
    512     return false;
    513 }
    514 
    515 bool StyleSheetContents::hasFailedOrCanceledSubresources() const
    516 {
    517     ASSERT(isCacheable());
    518     return childRulesHaveFailedOrCanceledSubresources(m_childRules);
    519 }
    520 
    521 Document* StyleSheetContents::clientSingleOwnerDocument() const
    522 {
    523     if (!m_hasSingleOwnerDocument || clientSize() <= 0)
    524         return 0;
    525 
    526     if (m_loadingClients.size())
    527         return (*m_loadingClients.begin())->ownerDocument();
    528     return (*m_completedClients.begin())->ownerDocument();
    529 }
    530 
    531 StyleSheetContents* StyleSheetContents::parentStyleSheet() const
    532 {
    533     return m_ownerRule ? m_ownerRule->parentStyleSheet() : 0;
    534 }
    535 
    536 void StyleSheetContents::registerClient(CSSStyleSheet* sheet)
    537 {
    538     ASSERT(!m_loadingClients.contains(sheet) && !m_completedClients.contains(sheet));
    539 
    540     // InspectorCSSAgent::buildObjectForRule creates CSSStyleSheet without any owner node.
    541     if (!sheet->ownerDocument())
    542         return;
    543 
    544     if (Document* document = clientSingleOwnerDocument()) {
    545         if (sheet->ownerDocument() != document)
    546             m_hasSingleOwnerDocument = false;
    547     }
    548     m_loadingClients.add(sheet);
    549 }
    550 
    551 void StyleSheetContents::unregisterClient(CSSStyleSheet* sheet)
    552 {
    553     m_loadingClients.remove(sheet);
    554     m_completedClients.remove(sheet);
    555 
    556     if (!sheet->ownerDocument() || !m_loadingClients.isEmpty() || !m_completedClients.isEmpty())
    557         return;
    558 
    559     if (m_hasSingleOwnerDocument)
    560         removeSheetFromCache(sheet->ownerDocument());
    561     m_hasSingleOwnerDocument = true;
    562 }
    563 
    564 void StyleSheetContents::clientLoadCompleted(CSSStyleSheet* sheet)
    565 {
    566     ASSERT(m_loadingClients.contains(sheet) || !sheet->ownerDocument());
    567     m_loadingClients.remove(sheet);
    568     // In m_ownerNode->sheetLoaded, the CSSStyleSheet might be detached.
    569     // (i.e. clearOwnerNode was invoked.)
    570     // In this case, we don't need to add the stylesheet to completed clients.
    571     if (!sheet->ownerDocument())
    572         return;
    573     m_completedClients.add(sheet);
    574 }
    575 
    576 void StyleSheetContents::clientLoadStarted(CSSStyleSheet* sheet)
    577 {
    578     ASSERT(m_completedClients.contains(sheet));
    579     m_completedClients.remove(sheet);
    580     m_loadingClients.add(sheet);
    581 }
    582 
    583 void StyleSheetContents::removeSheetFromCache(Document* document)
    584 {
    585     ASSERT(document);
    586     document->styleEngine()->removeSheet(this);
    587 }
    588 
    589 void StyleSheetContents::addedToMemoryCache()
    590 {
    591     ASSERT(!m_isInMemoryCache);
    592     ASSERT(isCacheable());
    593     m_isInMemoryCache = true;
    594 }
    595 
    596 void StyleSheetContents::removedFromMemoryCache()
    597 {
    598     ASSERT(m_isInMemoryCache);
    599     ASSERT(isCacheable());
    600     m_isInMemoryCache = false;
    601 }
    602 
    603 void StyleSheetContents::shrinkToFit()
    604 {
    605     m_importRules.shrinkToFit();
    606     m_childRules.shrinkToFit();
    607 }
    608 
    609 RuleSet& StyleSheetContents::ensureRuleSet(const MediaQueryEvaluator& medium, AddRuleFlags addRuleFlags)
    610 {
    611     if (!m_ruleSet) {
    612         m_ruleSet = RuleSet::create();
    613         m_ruleSet->addRulesFromSheet(this, medium, addRuleFlags);
    614     }
    615     return *m_ruleSet.get();
    616 }
    617 
    618 static void clearResolvers(WillBeHeapHashSet<RawPtrWillBeWeakMember<CSSStyleSheet> >& clients)
    619 {
    620     for (WillBeHeapHashSet<RawPtrWillBeWeakMember<CSSStyleSheet> >::iterator it = clients.begin(); it != clients.end(); ++it) {
    621         if (Document* document = (*it)->ownerDocument())
    622             document->styleEngine()->clearResolver();
    623     }
    624 }
    625 
    626 void StyleSheetContents::clearRuleSet()
    627 {
    628     if (StyleSheetContents* parentSheet = parentStyleSheet())
    629         parentSheet->clearRuleSet();
    630 
    631     // Don't want to clear the StyleResolver if the RuleSet hasn't been created
    632     // since we only clear the StyleResolver so that it's members are properly
    633     // updated in ScopedStyleResolver::addRulesFromSheet.
    634     if (!m_ruleSet)
    635         return;
    636 
    637     // Clearing the ruleSet means we need to recreate the styleResolver data structures.
    638     // See the StyleResolver calls in ScopedStyleResolver::addRulesFromSheet.
    639     clearResolvers(m_loadingClients);
    640     clearResolvers(m_completedClients);
    641     m_ruleSet.clear();
    642 }
    643 
    644 static void removeFontFaceRules(WillBeHeapHashSet<RawPtrWillBeWeakMember<CSSStyleSheet> >& clients, const StyleRuleFontFace* fontFaceRule)
    645 {
    646     for (WillBeHeapHashSet<RawPtrWillBeWeakMember<CSSStyleSheet> >::iterator it = clients.begin(); it != clients.end(); ++it) {
    647         if (Node* ownerNode = (*it)->ownerNode())
    648             ownerNode->document().styleEngine()->removeFontFaceRules(WillBeHeapVector<RawPtrWillBeMember<const StyleRuleFontFace> >(1, fontFaceRule));
    649     }
    650 }
    651 
    652 void StyleSheetContents::notifyRemoveFontFaceRule(const StyleRuleFontFace* fontFaceRule)
    653 {
    654     StyleSheetContents* root = rootStyleSheet();
    655     removeFontFaceRules(root->m_loadingClients, fontFaceRule);
    656     removeFontFaceRules(root->m_completedClients, fontFaceRule);
    657 }
    658 
    659 static void findFontFaceRulesFromRules(const WillBeHeapVector<RefPtrWillBeMember<StyleRuleBase> >& rules, WillBeHeapVector<RawPtrWillBeMember<const StyleRuleFontFace> >& fontFaceRules)
    660 {
    661     for (unsigned i = 0; i < rules.size(); ++i) {
    662         StyleRuleBase* rule = rules[i].get();
    663 
    664         if (rule->isFontFaceRule()) {
    665             fontFaceRules.append(toStyleRuleFontFace(rule));
    666         } else if (rule->isMediaRule()) {
    667             StyleRuleMedia* mediaRule = toStyleRuleMedia(rule);
    668             // We cannot know whether the media rule matches or not, but
    669             // for safety, remove @font-face in the media rule (if exists).
    670             findFontFaceRulesFromRules(mediaRule->childRules(), fontFaceRules);
    671         }
    672     }
    673 }
    674 
    675 void StyleSheetContents::findFontFaceRules(WillBeHeapVector<RawPtrWillBeMember<const StyleRuleFontFace> >& fontFaceRules)
    676 {
    677     for (unsigned i = 0; i < m_importRules.size(); ++i) {
    678         if (!m_importRules[i]->styleSheet())
    679             continue;
    680         m_importRules[i]->styleSheet()->findFontFaceRules(fontFaceRules);
    681     }
    682 
    683     findFontFaceRulesFromRules(childRules(), fontFaceRules);
    684 }
    685 
    686 void StyleSheetContents::trace(Visitor* visitor)
    687 {
    688     visitor->trace(m_ownerRule);
    689     visitor->trace(m_importRules);
    690     visitor->trace(m_childRules);
    691     visitor->trace(m_loadingClients);
    692     visitor->trace(m_completedClients);
    693     visitor->trace(m_ruleSet);
    694 }
    695 
    696 }
    697