• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * (C) 1999-2003 Lars Knoll (knoll@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.
estimatedSizeInBytes() const42 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 
StyleSheetContents(StyleRuleImport * ownerRule,const String & originalURL,const CSSParserContext & context)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 
StyleSheetContents(const StyleSheetContents & o)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 
~StyleSheetContents()100 StyleSheetContents::~StyleSheetContents()
101 {
102 #if !ENABLE(OILPAN)
103     clearRules();
104 #endif
105 }
106 
setHasSyntacticallyValidCSSHeader(bool isValidCss)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 
isCacheable() const116 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 
parserAppendRule(PassRefPtrWillBeRawPtr<StyleRuleBase> rule)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 
setHasMediaQueries()170 void StyleSheetContents::setHasMediaQueries()
171 {
172     m_hasMediaQueries = true;
173     if (parentStyleSheet())
174         parentStyleSheet()->setHasMediaQueries();
175 }
176 
ruleAt(unsigned index) const177 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 
ruleCount() const194 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 
clearCharsetRule()203 void StyleSheetContents::clearCharsetRule()
204 {
205     m_encodingFromCharsetRule = String();
206 }
207 
clearRules()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 
parserSetEncodingFromCharsetRule(const String & encoding)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 
wrapperInsertRule(PassRefPtrWillBeRawPtr<StyleRuleBase> rule,unsigned index)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 
wrapperDeleteRule(unsigned index)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 
parserAddNamespace(const AtomicString & prefix,const AtomicString & uri)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 
determineNamespace(const AtomicString & prefix)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 
parseAuthorStyleSheet(const CSSStyleSheetResource * cachedStyleSheet,const SecurityOrigin * securityOrigin)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 
parseString(const String & sheetText)344 bool StyleSheetContents::parseString(const String& sheetText)
345 {
346     return parseStringAtPosition(sheetText, TextPosition::minimumPosition(), false);
347 }
348 
parseStringAtPosition(const String & sheetText,const TextPosition & startPosition,bool createdByParser)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 
isLoading() const357 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 
loadCompleted() const366 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 
checkLoaded()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 
notifyLoadedSheet(const CSSStyleSheetResource * sheet)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 
startLoadingDynamicSheet()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 
rootStyleSheet() const445 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 
hasSingleOwnerNode() const453 bool StyleSheetContents::hasSingleOwnerNode() const
454 {
455     return rootStyleSheet()->hasOneClient();
456 }
457 
singleOwnerNode() const458 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 
singleOwnerDocument() const468 Document* StyleSheetContents::singleOwnerDocument() const
469 {
470     StyleSheetContents* root = rootStyleSheet();
471     return root->clientSingleOwnerDocument();
472 }
473 
completeURL(const String & url) const474 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 
childRulesHaveFailedOrCanceledSubresources(const WillBeHeapVector<RefPtrWillBeMember<StyleRuleBase>> & rules)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 
hasFailedOrCanceledSubresources() const513 bool StyleSheetContents::hasFailedOrCanceledSubresources() const
514 {
515     ASSERT(isCacheable());
516     return childRulesHaveFailedOrCanceledSubresources(m_childRules);
517 }
518 
clientSingleOwnerDocument() const519 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 
parentStyleSheet() const529 StyleSheetContents* StyleSheetContents::parentStyleSheet() const
530 {
531     return m_ownerRule ? m_ownerRule->parentStyleSheet() : 0;
532 }
533 
registerClient(CSSStyleSheet * sheet)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 
unregisterClient(CSSStyleSheet * sheet)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 
clientLoadCompleted(CSSStyleSheet * sheet)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 
clientLoadStarted(CSSStyleSheet * sheet)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 
removeSheetFromCache(Document * document)581 void StyleSheetContents::removeSheetFromCache(Document* document)
582 {
583     ASSERT(document);
584     document->styleEngine()->removeSheet(this);
585 }
586 
addedToMemoryCache()587 void StyleSheetContents::addedToMemoryCache()
588 {
589     ASSERT(!m_isInMemoryCache);
590     ASSERT(isCacheable());
591     m_isInMemoryCache = true;
592 }
593 
removedFromMemoryCache()594 void StyleSheetContents::removedFromMemoryCache()
595 {
596     ASSERT(m_isInMemoryCache);
597     ASSERT(isCacheable());
598     m_isInMemoryCache = false;
599 }
600 
shrinkToFit()601 void StyleSheetContents::shrinkToFit()
602 {
603     m_importRules.shrinkToFit();
604     m_childRules.shrinkToFit();
605 }
606 
ensureRuleSet(const MediaQueryEvaluator & medium,AddRuleFlags addRuleFlags)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 
clearResolvers(WillBeHeapHashSet<RawPtrWillBeWeakMember<CSSStyleSheet>> & clients)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 
clearRuleSet()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 
removeFontFaceRules(WillBeHeapHashSet<RawPtrWillBeWeakMember<CSSStyleSheet>> & clients,const StyleRuleFontFace * fontFaceRule)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 
notifyRemoveFontFaceRule(const StyleRuleFontFace * fontFaceRule)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 
findFontFaceRulesFromRules(const WillBeHeapVector<RefPtrWillBeMember<StyleRuleBase>> & rules,WillBeHeapVector<RawPtrWillBeMember<const StyleRuleFontFace>> & fontFaceRules)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 
findFontFaceRules(WillBeHeapVector<RawPtrWillBeMember<const StyleRuleFontFace>> & fontFaceRules)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 
trace(Visitor * visitor)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