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.
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("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
parseString(const String & sheetText)345 bool StyleSheetContents::parseString(const String& sheetText)
346 {
347 return parseStringAtPosition(sheetText, TextPosition::minimumPosition(), false);
348 }
349
parseStringAtPosition(const String & sheetText,const TextPosition & startPosition,bool createdByParser)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
isLoading() const359 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
loadCompleted() const368 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
checkLoaded()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
notifyLoadedSheet(const CSSStyleSheetResource * sheet)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
startLoadingDynamicSheet()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
rootStyleSheet() const447 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
hasSingleOwnerNode() const455 bool StyleSheetContents::hasSingleOwnerNode() const
456 {
457 return rootStyleSheet()->hasOneClient();
458 }
459
singleOwnerNode() const460 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
singleOwnerDocument() const470 Document* StyleSheetContents::singleOwnerDocument() const
471 {
472 StyleSheetContents* root = rootStyleSheet();
473 return root->clientSingleOwnerDocument();
474 }
475
completeURL(const String & url) const476 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
childRulesHaveFailedOrCanceledSubresources(const WillBeHeapVector<RefPtrWillBeMember<StyleRuleBase>> & rules)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
hasFailedOrCanceledSubresources() const515 bool StyleSheetContents::hasFailedOrCanceledSubresources() const
516 {
517 ASSERT(isCacheable());
518 return childRulesHaveFailedOrCanceledSubresources(m_childRules);
519 }
520
clientSingleOwnerDocument() const521 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
parentStyleSheet() const531 StyleSheetContents* StyleSheetContents::parentStyleSheet() const
532 {
533 return m_ownerRule ? m_ownerRule->parentStyleSheet() : 0;
534 }
535
registerClient(CSSStyleSheet * sheet)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
unregisterClient(CSSStyleSheet * sheet)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
clientLoadCompleted(CSSStyleSheet * sheet)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
clientLoadStarted(CSSStyleSheet * sheet)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
removeSheetFromCache(Document * document)583 void StyleSheetContents::removeSheetFromCache(Document* document)
584 {
585 ASSERT(document);
586 document->styleEngine()->removeSheet(this);
587 }
588
addedToMemoryCache()589 void StyleSheetContents::addedToMemoryCache()
590 {
591 ASSERT(!m_isInMemoryCache);
592 ASSERT(isCacheable());
593 m_isInMemoryCache = true;
594 }
595
removedFromMemoryCache()596 void StyleSheetContents::removedFromMemoryCache()
597 {
598 ASSERT(m_isInMemoryCache);
599 ASSERT(isCacheable());
600 m_isInMemoryCache = false;
601 }
602
shrinkToFit()603 void StyleSheetContents::shrinkToFit()
604 {
605 m_importRules.shrinkToFit();
606 m_childRules.shrinkToFit();
607 }
608
ensureRuleSet(const MediaQueryEvaluator & medium,AddRuleFlags addRuleFlags)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
clearResolvers(WillBeHeapHashSet<RawPtrWillBeWeakMember<CSSStyleSheet>> & clients)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
clearRuleSet()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
removeFontFaceRules(WillBeHeapHashSet<RawPtrWillBeWeakMember<CSSStyleSheet>> & clients,const StyleRuleFontFace * fontFaceRule)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
notifyRemoveFontFaceRule(const StyleRuleFontFace * fontFaceRule)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
findFontFaceRulesFromRules(const WillBeHeapVector<RefPtrWillBeMember<StyleRuleBase>> & rules,WillBeHeapVector<RawPtrWillBeMember<const StyleRuleFontFace>> & fontFaceRules)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
findFontFaceRules(WillBeHeapVector<RawPtrWillBeMember<const StyleRuleFontFace>> & fontFaceRules)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
trace(Visitor * visitor)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