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/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 (RefPtrWillBeRawPtr<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 } 697