Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / css / StyleSheetContents.cpp
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/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 (RefPtr<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 }