1 /* 2 * (C) 1999-2003 Lars Knoll (knoll (at) kde.org) 3 * Copyright (C) 2004, 2006, 2007, 2012 Apple Inc. All rights reserved. 4 * 5 * This library is free software; you can redistribute it and/or 6 * modify it under the terms of the GNU Library General Public 7 * License as published by the Free Software Foundation; either 8 * version 2 of the License, or (at your option) any later version. 9 * 10 * This library is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 * Library General Public License for more details. 14 * 15 * You should have received a copy of the GNU Library General Public License 16 * along with this library; see the file COPYING.LIB. If not, write to 17 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 18 * Boston, MA 02110-1301, USA. 19 */ 20 21 #include "config.h" 22 #include "core/css/StyleSheetContents.h" 23 24 #include "core/css/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. 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("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 344 bool StyleSheetContents::parseString(const String& sheetText) 345 { 346 return parseStringAtPosition(sheetText, TextPosition::minimumPosition(), false); 347 } 348 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 357 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 366 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 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 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 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 445 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 453 bool StyleSheetContents::hasSingleOwnerNode() const 454 { 455 return rootStyleSheet()->hasOneClient(); 456 } 457 458 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 468 Document* StyleSheetContents::singleOwnerDocument() const 469 { 470 StyleSheetContents* root = rootStyleSheet(); 471 return root->clientSingleOwnerDocument(); 472 } 473 474 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 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 513 bool StyleSheetContents::hasFailedOrCanceledSubresources() const 514 { 515 ASSERT(isCacheable()); 516 return childRulesHaveFailedOrCanceledSubresources(m_childRules); 517 } 518 519 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 529 StyleSheetContents* StyleSheetContents::parentStyleSheet() const 530 { 531 return m_ownerRule ? m_ownerRule->parentStyleSheet() : 0; 532 } 533 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 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 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 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 581 void StyleSheetContents::removeSheetFromCache(Document* document) 582 { 583 ASSERT(document); 584 document->styleEngine()->removeSheet(this); 585 } 586 587 void StyleSheetContents::addedToMemoryCache() 588 { 589 ASSERT(!m_isInMemoryCache); 590 ASSERT(isCacheable()); 591 m_isInMemoryCache = true; 592 } 593 594 void StyleSheetContents::removedFromMemoryCache() 595 { 596 ASSERT(m_isInMemoryCache); 597 ASSERT(isCacheable()); 598 m_isInMemoryCache = false; 599 } 600 601 void StyleSheetContents::shrinkToFit() 602 { 603 m_importRules.shrinkToFit(); 604 m_childRules.shrinkToFit(); 605 } 606 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 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 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 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 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 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 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 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