1 | /* |
2 | * (C) 1999-2003 Lars Knoll (knoll@kde.org) |
3 | * Copyright (C) 2004-2017 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 "StyleSheetContents.h" |
23 | |
24 | #include "CSSImportRule.h" |
25 | #include "CSSParser.h" |
26 | #include "CSSStyleSheet.h" |
27 | #include "CachedCSSStyleSheet.h" |
28 | #include "ContentRuleListResults.h" |
29 | #include "Document.h" |
30 | #include "Frame.h" |
31 | #include "FrameLoader.h" |
32 | #include "MediaList.h" |
33 | #include "Node.h" |
34 | #include "Page.h" |
35 | #include "PageConsoleClient.h" |
36 | #include "ResourceLoadInfo.h" |
37 | #include "RuleSet.h" |
38 | #include "SecurityOrigin.h" |
39 | #include "StyleRule.h" |
40 | #include "StyleRuleImport.h" |
41 | #include <wtf/Deque.h> |
42 | #include <wtf/NeverDestroyed.h> |
43 | #include <wtf/Ref.h> |
44 | |
45 | #if ENABLE(CONTENT_EXTENSIONS) |
46 | #include "UserContentController.h" |
47 | #endif |
48 | |
49 | namespace WebCore { |
50 | |
51 | // Rough size estimate for the memory cache. |
52 | unsigned StyleSheetContents::estimatedSizeInBytes() const |
53 | { |
54 | // Note that this does not take into account size of the strings hanging from various objects. |
55 | // The assumption is that nearly all of of them are atomic and would exist anyway. |
56 | unsigned size = sizeof(*this); |
57 | |
58 | // FIXME: This ignores the children of media and region rules. |
59 | // Most rules are StyleRules. |
60 | size += ruleCount() * StyleRule::averageSizeInBytes(); |
61 | |
62 | for (unsigned i = 0; i < m_importRules.size(); ++i) { |
63 | if (StyleSheetContents* sheet = m_importRules[i]->styleSheet()) |
64 | size += sheet->estimatedSizeInBytes(); |
65 | } |
66 | return size; |
67 | } |
68 | |
69 | StyleSheetContents::StyleSheetContents(StyleRuleImport* ownerRule, const String& originalURL, const CSSParserContext& context) |
70 | : m_ownerRule(ownerRule) |
71 | , m_originalURL(originalURL) |
72 | , m_defaultNamespace(starAtom()) |
73 | , m_isUserStyleSheet(ownerRule && ownerRule->parentStyleSheet() && ownerRule->parentStyleSheet()->isUserStyleSheet()) |
74 | , m_parserContext(context) |
75 | { |
76 | } |
77 | |
78 | StyleSheetContents::StyleSheetContents(const StyleSheetContents& o) |
79 | : RefCounted<StyleSheetContents>() |
80 | , m_ownerRule(0) |
81 | , m_originalURL(o.m_originalURL) |
82 | , m_encodingFromCharsetRule(o.m_encodingFromCharsetRule) |
83 | , m_importRules(o.m_importRules.size()) |
84 | , m_namespaceRules(o.m_namespaceRules.size()) |
85 | , m_childRules(o.m_childRules.size()) |
86 | , m_namespaces(o.m_namespaces) |
87 | , m_defaultNamespace(o.m_defaultNamespace) |
88 | , m_isUserStyleSheet(o.m_isUserStyleSheet) |
89 | , m_loadCompleted(true) |
90 | , m_hasSyntacticallyValidCSSHeader(o.m_hasSyntacticallyValidCSSHeader) |
91 | , m_usesStyleBasedEditability(o.m_usesStyleBasedEditability) |
92 | , m_parserContext(o.m_parserContext) |
93 | { |
94 | ASSERT(o.isCacheable()); |
95 | |
96 | // FIXME: Copy import rules. |
97 | ASSERT(o.m_importRules.isEmpty()); |
98 | |
99 | for (unsigned i = 0; i < m_childRules.size(); ++i) |
100 | m_childRules[i] = o.m_childRules[i]->copy(); |
101 | } |
102 | |
103 | StyleSheetContents::~StyleSheetContents() |
104 | { |
105 | clearRules(); |
106 | } |
107 | |
108 | bool StyleSheetContents::isCacheable() const |
109 | { |
110 | // FIXME: Support copying import rules. |
111 | if (!m_importRules.isEmpty()) |
112 | return false; |
113 | // FIXME: Support cached stylesheets in import rules. |
114 | if (m_ownerRule) |
115 | return false; |
116 | // This would require dealing with multiple clients for load callbacks. |
117 | if (!m_loadCompleted) |
118 | return false; |
119 | if (m_didLoadErrorOccur) |
120 | return false; |
121 | // It is not the original sheet anymore. |
122 | if (m_isMutable) |
123 | return false; |
124 | // If the header is valid we are not going to need to check the SecurityOrigin. |
125 | // FIXME: Valid mime type avoids the check too. |
126 | if (!m_hasSyntacticallyValidCSSHeader) |
127 | return false; |
128 | return true; |
129 | } |
130 | |
131 | void StyleSheetContents::parserAppendRule(Ref<StyleRuleBase>&& rule) |
132 | { |
133 | ASSERT(!rule->isCharsetRule()); |
134 | |
135 | if (is<StyleRuleImport>(rule)) { |
136 | // Parser enforces that @import rules come before anything else except @charset. |
137 | ASSERT(m_childRules.isEmpty()); |
138 | m_importRules.append(downcast<StyleRuleImport>(rule.ptr())); |
139 | m_importRules.last()->setParentStyleSheet(this); |
140 | m_importRules.last()->requestStyleSheet(); |
141 | return; |
142 | } |
143 | |
144 | if (is<StyleRuleNamespace>(rule)) { |
145 | // Parser enforces that @namespace rules come before all rules other than |
146 | // import/charset rules |
147 | ASSERT(m_childRules.isEmpty()); |
148 | StyleRuleNamespace& namespaceRule = downcast<StyleRuleNamespace>(rule.get()); |
149 | parserAddNamespace(namespaceRule.prefix(), namespaceRule.uri()); |
150 | m_namespaceRules.append(downcast<StyleRuleNamespace>(rule.ptr())); |
151 | return; |
152 | } |
153 | |
154 | if (is<StyleRuleMedia>(rule)) |
155 | reportMediaQueryWarningIfNeeded(singleOwnerDocument(), downcast<StyleRuleMedia>(rule.get()).mediaQueries()); |
156 | |
157 | // NOTE: The selector list has to fit into RuleData. <http://webkit.org/b/118369> |
158 | // If we're adding a rule with a huge number of selectors, split it up into multiple rules |
159 | if (is<StyleRule>(rule) && downcast<StyleRule>(rule.get()).selectorList().componentCount() > RuleData::maximumSelectorComponentCount) { |
160 | m_childRules.appendVector(downcast<StyleRule>(rule.get()).splitIntoMultipleRulesWithMaximumSelectorComponentCount(RuleData::maximumSelectorComponentCount)); |
161 | return; |
162 | } |
163 | |
164 | m_childRules.append(WTFMove(rule)); |
165 | } |
166 | |
167 | StyleRuleBase* StyleSheetContents::ruleAt(unsigned index) const |
168 | { |
169 | ASSERT_WITH_SECURITY_IMPLICATION(index < ruleCount()); |
170 | |
171 | unsigned childVectorIndex = index; |
172 | if (childVectorIndex < m_importRules.size()) |
173 | return m_importRules[childVectorIndex].get(); |
174 | |
175 | childVectorIndex -= m_importRules.size(); |
176 | |
177 | if (childVectorIndex < m_namespaceRules.size()) |
178 | return m_namespaceRules[childVectorIndex].get(); |
179 | |
180 | childVectorIndex -= m_namespaceRules.size(); |
181 | |
182 | return m_childRules[childVectorIndex].get(); |
183 | } |
184 | |
185 | unsigned StyleSheetContents::ruleCount() const |
186 | { |
187 | unsigned result = 0; |
188 | result += m_importRules.size(); |
189 | result += m_namespaceRules.size(); |
190 | result += m_childRules.size(); |
191 | return result; |
192 | } |
193 | |
194 | void StyleSheetContents::clearCharsetRule() |
195 | { |
196 | m_encodingFromCharsetRule = String(); |
197 | } |
198 | |
199 | void StyleSheetContents::clearRules() |
200 | { |
201 | for (unsigned i = 0; i < m_importRules.size(); ++i) { |
202 | ASSERT(m_importRules.at(i)->parentStyleSheet() == this); |
203 | m_importRules[i]->clearParentStyleSheet(); |
204 | } |
205 | m_importRules.clear(); |
206 | m_namespaceRules.clear(); |
207 | m_childRules.clear(); |
208 | clearCharsetRule(); |
209 | } |
210 | |
211 | void StyleSheetContents::parserSetEncodingFromCharsetRule(const String& encoding) |
212 | { |
213 | // Parser enforces that there is ever only one @charset. |
214 | ASSERT(m_encodingFromCharsetRule.isNull()); |
215 | m_encodingFromCharsetRule = encoding; |
216 | } |
217 | |
218 | bool StyleSheetContents::wrapperInsertRule(Ref<StyleRuleBase>&& rule, unsigned index) |
219 | { |
220 | ASSERT(m_isMutable); |
221 | ASSERT_WITH_SECURITY_IMPLICATION(index <= ruleCount()); |
222 | // Parser::parseRule doesn't currently allow @charset so we don't need to deal with it. |
223 | ASSERT(!rule->isCharsetRule()); |
224 | |
225 | unsigned childVectorIndex = index; |
226 | if (childVectorIndex < m_importRules.size() || (childVectorIndex == m_importRules.size() && rule->isImportRule())) { |
227 | // Inserting non-import rule before @import is not allowed. |
228 | if (!is<StyleRuleImport>(rule)) |
229 | return false; |
230 | m_importRules.insert(childVectorIndex, downcast<StyleRuleImport>(rule.ptr())); |
231 | m_importRules[childVectorIndex]->setParentStyleSheet(this); |
232 | m_importRules[childVectorIndex]->requestStyleSheet(); |
233 | // FIXME: Stylesheet doesn't actually change meaningfully before the imported sheets are loaded. |
234 | return true; |
235 | } |
236 | // Inserting @import rule after a non-import rule is not allowed. |
237 | if (is<StyleRuleImport>(rule)) |
238 | return false; |
239 | childVectorIndex -= m_importRules.size(); |
240 | |
241 | |
242 | if (childVectorIndex < m_namespaceRules.size() || (childVectorIndex == m_namespaceRules.size() && rule->isNamespaceRule())) { |
243 | // Inserting non-namespace rules other than import rule before @namespace is |
244 | // not allowed. |
245 | if (!is<StyleRuleNamespace>(rule)) |
246 | return false; |
247 | // Inserting @namespace rule when rules other than import/namespace/charset |
248 | // are present is not allowed. |
249 | if (!m_childRules.isEmpty()) |
250 | return false; |
251 | |
252 | StyleRuleNamespace& namespaceRule = downcast<StyleRuleNamespace>(rule.get()); |
253 | m_namespaceRules.insert(index, downcast<StyleRuleNamespace>(rule.ptr())); |
254 | |
255 | // For now to be compatible with IE and Firefox if a namespace rule with the same |
256 | // prefix is added, it overwrites previous ones. |
257 | // FIXME: The eventual correct behavior would be to ensure that the last value in |
258 | // the list wins. |
259 | parserAddNamespace(namespaceRule.prefix(), namespaceRule.uri()); |
260 | return true; |
261 | } |
262 | if (is<StyleRuleNamespace>(rule)) |
263 | return false; |
264 | childVectorIndex -= m_namespaceRules.size(); |
265 | |
266 | // If the number of selectors would overflow RuleData, we drop the operation. |
267 | if (is<StyleRule>(rule) && downcast<StyleRule>(rule.get()).selectorList().componentCount() > RuleData::maximumSelectorComponentCount) |
268 | return false; |
269 | |
270 | m_childRules.insert(childVectorIndex, WTFMove(rule)); |
271 | return true; |
272 | } |
273 | |
274 | void StyleSheetContents::wrapperDeleteRule(unsigned index) |
275 | { |
276 | ASSERT(m_isMutable); |
277 | ASSERT_WITH_SECURITY_IMPLICATION(index < ruleCount()); |
278 | |
279 | unsigned childVectorIndex = index; |
280 | if (childVectorIndex < m_importRules.size()) { |
281 | m_importRules[childVectorIndex]->clearParentStyleSheet(); |
282 | m_importRules.remove(childVectorIndex); |
283 | return; |
284 | } |
285 | childVectorIndex -= m_importRules.size(); |
286 | |
287 | if (childVectorIndex < m_namespaceRules.size()) { |
288 | if (!m_childRules.isEmpty()) |
289 | return; |
290 | m_namespaceRules.remove(childVectorIndex); |
291 | return; |
292 | } |
293 | childVectorIndex -= m_namespaceRules.size(); |
294 | |
295 | m_childRules.remove(childVectorIndex); |
296 | } |
297 | |
298 | void StyleSheetContents::parserAddNamespace(const AtomicString& prefix, const AtomicString& uri) |
299 | { |
300 | ASSERT(!uri.isNull()); |
301 | if (prefix.isNull()) { |
302 | m_defaultNamespace = uri; |
303 | return; |
304 | } |
305 | PrefixNamespaceURIMap::AddResult result = m_namespaces.add(prefix, uri); |
306 | if (result.isNewEntry) |
307 | return; |
308 | result.iterator->value = uri; |
309 | } |
310 | |
311 | const AtomicString& StyleSheetContents::namespaceURIFromPrefix(const AtomicString& prefix) |
312 | { |
313 | PrefixNamespaceURIMap::const_iterator it = m_namespaces.find(prefix); |
314 | if (it == m_namespaces.end()) |
315 | return nullAtom(); |
316 | return it->value; |
317 | } |
318 | |
319 | void StyleSheetContents::parseAuthorStyleSheet(const CachedCSSStyleSheet* cachedStyleSheet, const SecurityOrigin* securityOrigin) |
320 | { |
321 | bool isSameOriginRequest = securityOrigin && securityOrigin->canRequest(baseURL()); |
322 | CachedCSSStyleSheet::MIMETypeCheckHint mimeTypeCheckHint = isStrictParserMode(m_parserContext.mode) || !isSameOriginRequest ? CachedCSSStyleSheet::MIMETypeCheckHint::Strict : CachedCSSStyleSheet::MIMETypeCheckHint::Lax; |
323 | bool hasValidMIMEType = true; |
324 | String sheetText = cachedStyleSheet->sheetText(mimeTypeCheckHint, &hasValidMIMEType); |
325 | |
326 | if (!hasValidMIMEType) { |
327 | ASSERT(sheetText.isNull()); |
328 | if (auto* document = singleOwnerDocument()) { |
329 | if (auto* page = document->page()) { |
330 | if (isStrictParserMode(m_parserContext.mode)) |
331 | page->console().addMessage(MessageSource::Security, MessageLevel::Error, makeString("Did not parse stylesheet at '" , cachedStyleSheet->url().stringCenterEllipsizedToLength(), "' because non CSS MIME types are not allowed in strict mode." )); |
332 | else if (!cachedStyleSheet->mimeTypeAllowedByNosniff()) |
333 | page->console().addMessage(MessageSource::Security, MessageLevel::Error, makeString("Did not parse stylesheet at '" , cachedStyleSheet->url().stringCenterEllipsizedToLength(), "' because non CSS MIME types are not allowed when 'X-Content-Type: nosniff' is given." )); |
334 | else |
335 | page->console().addMessage(MessageSource::Security, MessageLevel::Error, makeString("Did not parse stylesheet at '" , cachedStyleSheet->url().stringCenterEllipsizedToLength(), "' because non CSS MIME types are not allowed for cross-origin stylesheets." )); |
336 | } |
337 | } |
338 | return; |
339 | } |
340 | |
341 | CSSParser(parserContext()).parseSheet(this, sheetText, CSSParser::RuleParsing::Deferred); |
342 | } |
343 | |
344 | bool StyleSheetContents::parseString(const String& sheetText) |
345 | { |
346 | CSSParser p(parserContext()); |
347 | p.parseSheet(this, sheetText, parserContext().mode != UASheetMode ? CSSParser::RuleParsing::Deferred : CSSParser::RuleParsing::Normal); |
348 | return true; |
349 | } |
350 | |
351 | bool StyleSheetContents::isLoading() const |
352 | { |
353 | for (unsigned i = 0; i < m_importRules.size(); ++i) { |
354 | if (m_importRules[i]->isLoading()) |
355 | return true; |
356 | } |
357 | return false; |
358 | } |
359 | |
360 | void StyleSheetContents::checkLoaded() |
361 | { |
362 | if (isLoading()) |
363 | return; |
364 | |
365 | Ref<StyleSheetContents> protectedThis(*this); |
366 | StyleSheetContents* parentSheet = parentStyleSheet(); |
367 | if (parentSheet) { |
368 | parentSheet->checkLoaded(); |
369 | m_loadCompleted = true; |
370 | return; |
371 | } |
372 | RefPtr<Node> ownerNode = singleOwnerNode(); |
373 | if (!ownerNode) { |
374 | m_loadCompleted = true; |
375 | return; |
376 | } |
377 | m_loadCompleted = ownerNode->sheetLoaded(); |
378 | if (m_loadCompleted) |
379 | ownerNode->notifyLoadedSheetAndAllCriticalSubresources(m_didLoadErrorOccur); |
380 | } |
381 | |
382 | void StyleSheetContents::notifyLoadedSheet(const CachedCSSStyleSheet* sheet) |
383 | { |
384 | ASSERT(sheet); |
385 | m_didLoadErrorOccur |= sheet->errorOccurred(); |
386 | m_didLoadErrorOccur |= !sheet->mimeTypeAllowedByNosniff(); |
387 | } |
388 | |
389 | void StyleSheetContents::startLoadingDynamicSheet() |
390 | { |
391 | if (Node* owner = singleOwnerNode()) |
392 | owner->startLoadingDynamicSheet(); |
393 | } |
394 | |
395 | StyleSheetContents* StyleSheetContents::rootStyleSheet() const |
396 | { |
397 | const StyleSheetContents* root = this; |
398 | while (root->parentStyleSheet()) |
399 | root = root->parentStyleSheet(); |
400 | return const_cast<StyleSheetContents*>(root); |
401 | } |
402 | |
403 | Node* StyleSheetContents::singleOwnerNode() const |
404 | { |
405 | StyleSheetContents* root = rootStyleSheet(); |
406 | if (root->m_clients.isEmpty()) |
407 | return 0; |
408 | ASSERT(root->m_clients.size() == 1); |
409 | return root->m_clients[0]->ownerNode(); |
410 | } |
411 | |
412 | Document* StyleSheetContents::singleOwnerDocument() const |
413 | { |
414 | Node* ownerNode = singleOwnerNode(); |
415 | return ownerNode ? &ownerNode->document() : 0; |
416 | } |
417 | |
418 | URL StyleSheetContents::completeURL(const String& url) const |
419 | { |
420 | return m_parserContext.completeURL(url); |
421 | } |
422 | |
423 | static bool traverseRulesInVector(const Vector<RefPtr<StyleRuleBase>>& rules, const WTF::Function<bool (const StyleRuleBase&)>& handler) |
424 | { |
425 | for (auto& rule : rules) { |
426 | if (handler(*rule)) |
427 | return true; |
428 | switch (rule->type()) { |
429 | case StyleRuleBase::Media: { |
430 | auto* childRules = downcast<StyleRuleMedia>(*rule).childRulesWithoutDeferredParsing(); |
431 | if (childRules && traverseRulesInVector(*childRules, handler)) |
432 | return true; |
433 | break; |
434 | } |
435 | case StyleRuleBase::Import: |
436 | ASSERT_NOT_REACHED(); |
437 | break; |
438 | case StyleRuleBase::Style: |
439 | case StyleRuleBase::FontFace: |
440 | case StyleRuleBase::Page: |
441 | case StyleRuleBase::Keyframes: |
442 | case StyleRuleBase::Namespace: |
443 | case StyleRuleBase::Unknown: |
444 | case StyleRuleBase::Charset: |
445 | case StyleRuleBase::Keyframe: |
446 | case StyleRuleBase::Supports: |
447 | #if ENABLE(CSS_DEVICE_ADAPTATION) |
448 | case StyleRuleBase::Viewport: |
449 | #endif |
450 | break; |
451 | } |
452 | } |
453 | return false; |
454 | } |
455 | |
456 | bool StyleSheetContents::traverseRules(const WTF::Function<bool (const StyleRuleBase&)>& handler) const |
457 | { |
458 | for (auto& importRule : m_importRules) { |
459 | if (handler(*importRule)) |
460 | return true; |
461 | auto* importedStyleSheet = importRule->styleSheet(); |
462 | if (importedStyleSheet && importedStyleSheet->traverseRules(handler)) |
463 | return true; |
464 | } |
465 | return traverseRulesInVector(m_childRules, handler); |
466 | } |
467 | |
468 | bool StyleSheetContents::traverseSubresources(const WTF::Function<bool (const CachedResource&)>& handler) const |
469 | { |
470 | return traverseRules([&] (const StyleRuleBase& rule) { |
471 | switch (rule.type()) { |
472 | case StyleRuleBase::Style: { |
473 | auto* properties = downcast<StyleRule>(rule).propertiesWithoutDeferredParsing(); |
474 | return properties && properties->traverseSubresources(handler); |
475 | } |
476 | case StyleRuleBase::FontFace: |
477 | return downcast<StyleRuleFontFace>(rule).properties().traverseSubresources(handler); |
478 | case StyleRuleBase::Import: |
479 | if (auto* cachedResource = downcast<StyleRuleImport>(rule).cachedCSSStyleSheet()) |
480 | return handler(*cachedResource); |
481 | return false; |
482 | case StyleRuleBase::Media: |
483 | case StyleRuleBase::Page: |
484 | case StyleRuleBase::Keyframes: |
485 | case StyleRuleBase::Namespace: |
486 | case StyleRuleBase::Unknown: |
487 | case StyleRuleBase::Charset: |
488 | case StyleRuleBase::Keyframe: |
489 | case StyleRuleBase::Supports: |
490 | #if ENABLE(CSS_DEVICE_ADAPTATION) |
491 | case StyleRuleBase::Viewport: |
492 | #endif |
493 | return false; |
494 | }; |
495 | ASSERT_NOT_REACHED(); |
496 | return false; |
497 | }); |
498 | } |
499 | |
500 | bool StyleSheetContents::subresourcesAllowReuse(CachePolicy cachePolicy, FrameLoader& loader) const |
501 | { |
502 | bool hasFailedOrExpiredResources = traverseSubresources([cachePolicy, &loader](const CachedResource& resource) { |
503 | if (resource.loadFailedOrCanceled()) |
504 | return true; |
505 | // We can't revalidate subresources individually so don't use reuse the parsed sheet if they need revalidation. |
506 | if (resource.makeRevalidationDecision(cachePolicy) != CachedResource::RevalidationDecision::No) |
507 | return true; |
508 | |
509 | #if ENABLE(CONTENT_EXTENSIONS) |
510 | // If a cached subresource is blocked or made HTTPS by a content blocker, we cannot reuse the cached stylesheet. |
511 | auto* page = loader.frame().page(); |
512 | auto* documentLoader = loader.documentLoader(); |
513 | if (page && documentLoader) { |
514 | const auto& request = resource.resourceRequest(); |
515 | auto results = page->userContentProvider().processContentRuleListsForLoad(request.url(), ContentExtensions::toResourceType(resource.type()), *documentLoader); |
516 | if (results.summary.blockedLoad || results.summary.madeHTTPS) |
517 | return true; |
518 | } |
519 | #else |
520 | UNUSED_PARAM(loader); |
521 | #endif |
522 | |
523 | return false; |
524 | }); |
525 | return !hasFailedOrExpiredResources; |
526 | } |
527 | |
528 | bool StyleSheetContents::isLoadingSubresources() const |
529 | { |
530 | return traverseSubresources([](const CachedResource& resource) { |
531 | return resource.isLoading(); |
532 | }); |
533 | } |
534 | |
535 | StyleSheetContents* StyleSheetContents::parentStyleSheet() const |
536 | { |
537 | return m_ownerRule ? m_ownerRule->parentStyleSheet() : 0; |
538 | } |
539 | |
540 | void StyleSheetContents::registerClient(CSSStyleSheet* sheet) |
541 | { |
542 | ASSERT(!m_clients.contains(sheet)); |
543 | m_clients.append(sheet); |
544 | } |
545 | |
546 | void StyleSheetContents::unregisterClient(CSSStyleSheet* sheet) |
547 | { |
548 | bool removed = m_clients.removeFirst(sheet); |
549 | ASSERT_UNUSED(removed, removed); |
550 | } |
551 | |
552 | void StyleSheetContents::addedToMemoryCache() |
553 | { |
554 | ASSERT(isCacheable()); |
555 | ++m_inMemoryCacheCount; |
556 | } |
557 | |
558 | void StyleSheetContents::removedFromMemoryCache() |
559 | { |
560 | ASSERT(m_inMemoryCacheCount); |
561 | ASSERT(isCacheable()); |
562 | --m_inMemoryCacheCount; |
563 | } |
564 | |
565 | void StyleSheetContents::shrinkToFit() |
566 | { |
567 | m_importRules.shrinkToFit(); |
568 | m_childRules.shrinkToFit(); |
569 | } |
570 | |
571 | } |
572 | |