1 /* 2 * Copyright (C) 1999 Lars Knoll (knoll (at) kde.org) 3 * (C) 1999 Antti Koivisto (koivisto (at) kde.org) 4 * (C) 2001 Dirk Mueller (mueller (at) kde.org) 5 * (C) 2006 Alexey Proskuryakov (ap (at) webkit.org) 6 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2011, 2012 Apple Inc. All rights reserved. 7 * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/) 8 * Copyright (C) 2008, 2009, 2011, 2012 Google Inc. All rights reserved. 9 * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies) 10 * Copyright (C) Research In Motion Limited 2010-2011. All rights reserved. 11 * 12 * This library is free software; you can redistribute it and/or 13 * modify it under the terms of the GNU Library General Public 14 * License as published by the Free Software Foundation; either 15 * version 2 of the License, or (at your option) any later version. 16 * 17 * This library is distributed in the hope that it will be useful, 18 * but WITHOUT ANY WARRANTY; without even the implied warranty of 19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 20 * Library General Public License for more details. 21 * 22 * You should have received a copy of the GNU Library General Public License 23 * along with this library; see the file COPYING.LIB. If not, write to 24 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 25 * Boston, MA 02110-1301, USA. 26 */ 27 28 #include "config.h" 29 #include "core/dom/StyleEngine.h" 30 31 #include "core/HTMLNames.h" 32 #include "core/css/CSSFontSelector.h" 33 #include "core/css/CSSStyleSheet.h" 34 #include "core/css/FontFaceCache.h" 35 #include "core/css/StyleSheetContents.h" 36 #include "core/dom/DocumentStyleSheetCollector.h" 37 #include "core/dom/Element.h" 38 #include "core/dom/ProcessingInstruction.h" 39 #include "core/dom/ShadowTreeStyleSheetCollection.h" 40 #include "core/dom/shadow/ShadowRoot.h" 41 #include "core/html/HTMLIFrameElement.h" 42 #include "core/html/HTMLLinkElement.h" 43 #include "core/html/imports/HTMLImportsController.h" 44 #include "core/inspector/InspectorInstrumentation.h" 45 #include "core/page/InjectedStyleSheets.h" 46 #include "core/page/Page.h" 47 #include "core/frame/Settings.h" 48 #include "platform/URLPatternMatcher.h" 49 50 namespace WebCore { 51 52 using namespace HTMLNames; 53 54 StyleEngine::StyleEngine(Document& document) 55 : m_document(&document) 56 , m_isMaster(!document.importsController() || document.importsController()->master() == &document) 57 , m_pendingStylesheets(0) 58 , m_injectedStyleSheetCacheValid(false) 59 #if ENABLE(OILPAN) 60 , m_documentStyleSheetCollection(new DocumentStyleSheetCollection(document)) 61 #else 62 , m_documentStyleSheetCollection(document) 63 #endif 64 , m_documentScopeDirty(true) 65 , m_usesSiblingRules(false) 66 , m_usesSiblingRulesOverride(false) 67 , m_usesFirstLineRules(false) 68 , m_usesFirstLetterRules(false) 69 , m_usesRemUnits(false) 70 , m_maxDirectAdjacentSelectors(0) 71 , m_ignorePendingStylesheets(false) 72 , m_didCalculateResolver(false) 73 // We don't need to create CSSFontSelector for imported document or 74 // HTMLTemplateElement's document, because those documents have no frame. 75 , m_fontSelector(document.frame() ? CSSFontSelector::create(&document) : nullptr) 76 , m_xslStyleSheet(nullptr) 77 { 78 if (m_fontSelector) 79 m_fontSelector->registerForInvalidationCallbacks(this); 80 } 81 82 StyleEngine::~StyleEngine() 83 { 84 } 85 86 #if !ENABLE(OILPAN) 87 void StyleEngine::detachFromDocument() 88 { 89 // Cleanup is performed eagerly when the StyleEngine is removed from the 90 // document. The StyleEngine is unreachable after this, since only the 91 // document has a reference to it. 92 for (unsigned i = 0; i < m_injectedAuthorStyleSheets.size(); ++i) 93 m_injectedAuthorStyleSheets[i]->clearOwnerNode(); 94 for (unsigned i = 0; i < m_authorStyleSheets.size(); ++i) 95 m_authorStyleSheets[i]->clearOwnerNode(); 96 97 if (m_fontSelector) { 98 m_fontSelector->clearDocument(); 99 m_fontSelector->unregisterForInvalidationCallbacks(this); 100 } 101 102 // Decrement reference counts for things we could be keeping alive. 103 m_fontSelector.clear(); 104 m_resolver.clear(); 105 m_styleSheetCollectionMap.clear(); 106 } 107 #endif 108 109 inline Document* StyleEngine::master() 110 { 111 if (isMaster()) 112 return m_document; 113 HTMLImportsController* import = document().importsController(); 114 if (!import) // Document::import() can return null while executing its destructor. 115 return 0; 116 return import->master(); 117 } 118 119 void StyleEngine::insertTreeScopeInDocumentOrder(TreeScopeSet& treeScopes, TreeScope* treeScope) 120 { 121 if (treeScopes.isEmpty()) { 122 treeScopes.add(treeScope); 123 return; 124 } 125 if (treeScopes.contains(treeScope)) 126 return; 127 128 TreeScopeSet::iterator begin = treeScopes.begin(); 129 TreeScopeSet::iterator end = treeScopes.end(); 130 TreeScopeSet::iterator it = end; 131 TreeScope* followingTreeScope = 0; 132 do { 133 --it; 134 TreeScope* n = *it; 135 unsigned short position = n->comparePosition(*treeScope); 136 if (position & Node::DOCUMENT_POSITION_FOLLOWING) { 137 treeScopes.insertBefore(followingTreeScope, treeScope); 138 return; 139 } 140 followingTreeScope = n; 141 } while (it != begin); 142 143 treeScopes.insertBefore(followingTreeScope, treeScope); 144 } 145 146 TreeScopeStyleSheetCollection* StyleEngine::ensureStyleSheetCollectionFor(TreeScope& treeScope) 147 { 148 if (treeScope == m_document) 149 return documentStyleSheetCollection(); 150 151 StyleSheetCollectionMap::AddResult result = m_styleSheetCollectionMap.add(&treeScope, nullptr); 152 if (result.isNewEntry) 153 result.storedValue->value = adoptPtrWillBeNoop(new ShadowTreeStyleSheetCollection(toShadowRoot(treeScope))); 154 return result.storedValue->value.get(); 155 } 156 157 TreeScopeStyleSheetCollection* StyleEngine::styleSheetCollectionFor(TreeScope& treeScope) 158 { 159 if (treeScope == m_document) 160 return documentStyleSheetCollection(); 161 162 StyleSheetCollectionMap::iterator it = m_styleSheetCollectionMap.find(&treeScope); 163 if (it == m_styleSheetCollectionMap.end()) 164 return 0; 165 return it->value.get(); 166 } 167 168 const WillBeHeapVector<RefPtrWillBeMember<StyleSheet> >& StyleEngine::styleSheetsForStyleSheetList(TreeScope& treeScope) 169 { 170 if (treeScope == m_document) 171 return documentStyleSheetCollection()->styleSheetsForStyleSheetList(); 172 173 return ensureStyleSheetCollectionFor(treeScope)->styleSheetsForStyleSheetList(); 174 } 175 176 const WillBeHeapVector<RefPtrWillBeMember<CSSStyleSheet> >& StyleEngine::activeAuthorStyleSheets() const 177 { 178 return documentStyleSheetCollection()->activeAuthorStyleSheets(); 179 } 180 181 void StyleEngine::combineCSSFeatureFlags(const RuleFeatureSet& features) 182 { 183 // Delay resetting the flags until after next style recalc since unapplying the style may not work without these set (this is true at least with before/after). 184 m_usesSiblingRules = m_usesSiblingRules || features.usesSiblingRules(); 185 m_usesFirstLineRules = m_usesFirstLineRules || features.usesFirstLineRules(); 186 m_maxDirectAdjacentSelectors = max(m_maxDirectAdjacentSelectors, features.maxDirectAdjacentSelectors()); 187 } 188 189 void StyleEngine::resetCSSFeatureFlags(const RuleFeatureSet& features) 190 { 191 m_usesSiblingRules = features.usesSiblingRules(); 192 m_usesFirstLineRules = features.usesFirstLineRules(); 193 m_maxDirectAdjacentSelectors = features.maxDirectAdjacentSelectors(); 194 } 195 196 const WillBeHeapVector<RefPtrWillBeMember<CSSStyleSheet> >& StyleEngine::injectedAuthorStyleSheets() const 197 { 198 updateInjectedStyleSheetCache(); 199 return m_injectedAuthorStyleSheets; 200 } 201 202 void StyleEngine::updateInjectedStyleSheetCache() const 203 { 204 if (m_injectedStyleSheetCacheValid) 205 return; 206 m_injectedStyleSheetCacheValid = true; 207 m_injectedAuthorStyleSheets.clear(); 208 209 Page* owningPage = document().page(); 210 if (!owningPage) 211 return; 212 213 const InjectedStyleSheetEntryVector& entries = InjectedStyleSheets::instance().entries(); 214 for (unsigned i = 0; i < entries.size(); ++i) { 215 const InjectedStyleSheetEntry* entry = entries[i].get(); 216 if (entry->injectedFrames() == InjectStyleInTopFrameOnly && document().ownerElement()) 217 continue; 218 if (!URLPatternMatcher::matchesPatterns(document().url(), entry->whitelist())) 219 continue; 220 RefPtrWillBeRawPtr<CSSStyleSheet> groupSheet = CSSStyleSheet::createInline(m_document, KURL()); 221 m_injectedAuthorStyleSheets.append(groupSheet); 222 groupSheet->contents()->parseString(entry->source()); 223 } 224 } 225 226 void StyleEngine::invalidateInjectedStyleSheetCache() 227 { 228 m_injectedStyleSheetCacheValid = false; 229 markDocumentDirty(); 230 // FIXME: updateInjectedStyleSheetCache is called inside StyleSheetCollection::updateActiveStyleSheets 231 // and batch updates lots of sheets so we can't call addedStyleSheet() or removedStyleSheet(). 232 document().styleResolverChanged(); 233 } 234 235 void StyleEngine::addAuthorSheet(PassRefPtrWillBeRawPtr<StyleSheetContents> authorSheet) 236 { 237 m_authorStyleSheets.append(CSSStyleSheet::create(authorSheet, m_document)); 238 document().addedStyleSheet(m_authorStyleSheets.last().get()); 239 markDocumentDirty(); 240 } 241 242 void StyleEngine::addPendingSheet() 243 { 244 m_pendingStylesheets++; 245 } 246 247 // This method is called whenever a top-level stylesheet has finished loading. 248 void StyleEngine::removePendingSheet(Node* styleSheetCandidateNode) 249 { 250 ASSERT(styleSheetCandidateNode); 251 TreeScope* treeScope = isHTMLStyleElement(*styleSheetCandidateNode) ? &styleSheetCandidateNode->treeScope() : m_document.get(); 252 markTreeScopeDirty(*treeScope); 253 254 // Make sure we knew this sheet was pending, and that our count isn't out of sync. 255 ASSERT(m_pendingStylesheets > 0); 256 257 m_pendingStylesheets--; 258 if (m_pendingStylesheets) 259 return; 260 261 // FIXME: We can't call addedStyleSheet or removedStyleSheet here because we don't know 262 // what's new. We should track that to tell the style system what changed. 263 document().didRemoveAllPendingStylesheet(); 264 } 265 266 void StyleEngine::modifiedStyleSheet(StyleSheet* sheet) 267 { 268 if (!sheet) 269 return; 270 271 Node* node = sheet->ownerNode(); 272 if (!node || !node->inDocument()) 273 return; 274 275 TreeScope& treeScope = isHTMLStyleElement(*node) ? node->treeScope() : *m_document; 276 ASSERT(isHTMLStyleElement(node) || treeScope == m_document); 277 278 markTreeScopeDirty(treeScope); 279 } 280 281 void StyleEngine::addStyleSheetCandidateNode(Node* node, bool createdByParser) 282 { 283 if (!node->inDocument()) 284 return; 285 286 TreeScope& treeScope = isHTMLStyleElement(*node) ? node->treeScope() : *m_document; 287 ASSERT(isHTMLStyleElement(node) || treeScope == m_document); 288 ASSERT(!isXSLStyleSheet(*node)); 289 TreeScopeStyleSheetCollection* collection = ensureStyleSheetCollectionFor(treeScope); 290 ASSERT(collection); 291 collection->addStyleSheetCandidateNode(node, createdByParser); 292 293 markTreeScopeDirty(treeScope); 294 if (treeScope != m_document) 295 insertTreeScopeInDocumentOrder(m_activeTreeScopes, &treeScope); 296 } 297 298 void StyleEngine::removeStyleSheetCandidateNode(Node* node) 299 { 300 removeStyleSheetCandidateNode(node, 0, *m_document); 301 } 302 303 void StyleEngine::removeStyleSheetCandidateNode(Node* node, ContainerNode* scopingNode, TreeScope& treeScope) 304 { 305 ASSERT(isHTMLStyleElement(node) || treeScope == m_document); 306 ASSERT(!isXSLStyleSheet(*node)); 307 308 TreeScopeStyleSheetCollection* collection = styleSheetCollectionFor(treeScope); 309 ASSERT(collection); 310 collection->removeStyleSheetCandidateNode(node, scopingNode); 311 312 markTreeScopeDirty(treeScope); 313 m_activeTreeScopes.remove(&treeScope); 314 } 315 316 void StyleEngine::addXSLStyleSheet(ProcessingInstruction* node, bool createdByParser) 317 { 318 if (!node->inDocument()) 319 return; 320 321 ASSERT(isXSLStyleSheet(*node)); 322 bool needToUpdate = false; 323 if (createdByParser || !m_xslStyleSheet) { 324 needToUpdate = !m_xslStyleSheet; 325 } else { 326 unsigned position = m_xslStyleSheet->compareDocumentPositionInternal(node, Node::TreatShadowTreesAsDisconnected); 327 needToUpdate = position & Node::DOCUMENT_POSITION_FOLLOWING; 328 } 329 330 if (!needToUpdate) 331 return; 332 333 markTreeScopeDirty(*m_document); 334 m_xslStyleSheet = node; 335 } 336 337 void StyleEngine::removeXSLStyleSheet(ProcessingInstruction* node) 338 { 339 ASSERT(isXSLStyleSheet(*node)); 340 if (m_xslStyleSheet != node) 341 return; 342 343 markTreeScopeDirty(*m_document); 344 m_xslStyleSheet = nullptr; 345 } 346 347 void StyleEngine::modifiedStyleSheetCandidateNode(Node* node) 348 { 349 if (!node->inDocument()) 350 return; 351 352 TreeScope& treeScope = isHTMLStyleElement(*node) ? node->treeScope() : *m_document; 353 ASSERT(isHTMLStyleElement(node) || treeScope == m_document); 354 markTreeScopeDirty(treeScope); 355 } 356 357 void StyleEngine::enableExitTransitionStylesheets() 358 { 359 TreeScopeStyleSheetCollection* collection = ensureStyleSheetCollectionFor(*m_document); 360 collection->enableExitTransitionStylesheets(); 361 } 362 363 bool StyleEngine::shouldUpdateDocumentStyleSheetCollection(StyleResolverUpdateMode updateMode) const 364 { 365 return m_documentScopeDirty || updateMode == FullStyleUpdate; 366 } 367 368 bool StyleEngine::shouldUpdateShadowTreeStyleSheetCollection(StyleResolverUpdateMode updateMode) const 369 { 370 return !m_dirtyTreeScopes.isEmpty() || updateMode == FullStyleUpdate; 371 } 372 373 void StyleEngine::clearMediaQueryRuleSetOnTreeScopeStyleSheets(TreeScopeSet treeScopes) 374 { 375 for (TreeScopeSet::iterator it = treeScopes.begin(); it != treeScopes.end(); ++it) { 376 TreeScope& treeScope = **it; 377 ASSERT(treeScope != m_document); 378 ShadowTreeStyleSheetCollection* collection = static_cast<ShadowTreeStyleSheetCollection*>(styleSheetCollectionFor(treeScope)); 379 ASSERT(collection); 380 collection->clearMediaQueryRuleSetStyleSheets(); 381 } 382 } 383 384 void StyleEngine::clearMediaQueryRuleSetStyleSheets() 385 { 386 documentStyleSheetCollection()->clearMediaQueryRuleSetStyleSheets(); 387 clearMediaQueryRuleSetOnTreeScopeStyleSheets(m_activeTreeScopes); 388 clearMediaQueryRuleSetOnTreeScopeStyleSheets(m_dirtyTreeScopes); 389 } 390 391 void StyleEngine::updateStyleSheetsInImport(DocumentStyleSheetCollector& parentCollector) 392 { 393 ASSERT(!isMaster()); 394 WillBeHeapVector<RefPtrWillBeMember<StyleSheet> > sheetsForList; 395 ImportedDocumentStyleSheetCollector subcollector(parentCollector, sheetsForList); 396 documentStyleSheetCollection()->collectStyleSheets(this, subcollector); 397 documentStyleSheetCollection()->swapSheetsForSheetList(sheetsForList); 398 } 399 400 void StyleEngine::updateActiveStyleSheets(StyleResolverUpdateMode updateMode) 401 { 402 ASSERT(isMaster()); 403 ASSERT(!document().inStyleRecalc()); 404 405 if (!document().isActive()) 406 return; 407 408 if (shouldUpdateDocumentStyleSheetCollection(updateMode)) 409 documentStyleSheetCollection()->updateActiveStyleSheets(this, updateMode); 410 411 if (shouldUpdateShadowTreeStyleSheetCollection(updateMode)) { 412 TreeScopeSet treeScopes = updateMode == FullStyleUpdate ? m_activeTreeScopes : m_dirtyTreeScopes; 413 HashSet<TreeScope*> treeScopesRemoved; 414 415 for (TreeScopeSet::iterator it = treeScopes.begin(); it != treeScopes.end(); ++it) { 416 TreeScope* treeScope = *it; 417 ASSERT(treeScope != m_document); 418 ShadowTreeStyleSheetCollection* collection = static_cast<ShadowTreeStyleSheetCollection*>(styleSheetCollectionFor(*treeScope)); 419 ASSERT(collection); 420 collection->updateActiveStyleSheets(this, updateMode); 421 if (!collection->hasStyleSheetCandidateNodes()) 422 treeScopesRemoved.add(treeScope); 423 } 424 m_activeTreeScopes.removeAll(treeScopesRemoved); 425 } 426 427 InspectorInstrumentation::activeStyleSheetsUpdated(m_document); 428 m_usesRemUnits = documentStyleSheetCollection()->usesRemUnits(); 429 430 m_dirtyTreeScopes.clear(); 431 m_documentScopeDirty = false; 432 } 433 434 const WillBeHeapVector<RefPtrWillBeMember<CSSStyleSheet> > StyleEngine::activeStyleSheetsForInspector() const 435 { 436 if (m_activeTreeScopes.isEmpty()) 437 return documentStyleSheetCollection()->activeAuthorStyleSheets(); 438 439 WillBeHeapVector<RefPtrWillBeMember<CSSStyleSheet> > activeStyleSheets; 440 441 activeStyleSheets.appendVector(documentStyleSheetCollection()->activeAuthorStyleSheets()); 442 443 TreeScopeSet::const_iterator begin = m_activeTreeScopes.begin(); 444 TreeScopeSet::const_iterator end = m_activeTreeScopes.end(); 445 for (TreeScopeSet::const_iterator it = begin; it != end; ++it) { 446 if (TreeScopeStyleSheetCollection* collection = m_styleSheetCollectionMap.get(*it)) 447 activeStyleSheets.appendVector(collection->activeAuthorStyleSheets()); 448 } 449 450 // FIXME: Inspector needs a vector which has all active stylesheets. 451 // However, creating such a large vector might cause performance regression. 452 // Need to implement some smarter solution. 453 return activeStyleSheets; 454 } 455 456 void StyleEngine::didRemoveShadowRoot(ShadowRoot* shadowRoot) 457 { 458 m_styleSheetCollectionMap.remove(shadowRoot); 459 } 460 461 void StyleEngine::appendActiveAuthorStyleSheets() 462 { 463 ASSERT(isMaster()); 464 465 m_resolver->setBuildScopedStyleTreeInDocumentOrder(true); 466 m_resolver->appendAuthorStyleSheets(documentStyleSheetCollection()->activeAuthorStyleSheets()); 467 468 TreeScopeSet::iterator begin = m_activeTreeScopes.begin(); 469 TreeScopeSet::iterator end = m_activeTreeScopes.end(); 470 for (TreeScopeSet::iterator it = begin; it != end; ++it) { 471 if (TreeScopeStyleSheetCollection* collection = m_styleSheetCollectionMap.get(*it)) { 472 m_resolver->setBuildScopedStyleTreeInDocumentOrder(!collection->scopingNodesForStyleScoped()); 473 m_resolver->appendAuthorStyleSheets(collection->activeAuthorStyleSheets()); 474 } 475 } 476 m_resolver->finishAppendAuthorStyleSheets(); 477 m_resolver->setBuildScopedStyleTreeInDocumentOrder(false); 478 } 479 480 void StyleEngine::createResolver() 481 { 482 // It is a programming error to attempt to resolve style on a Document 483 // which is not in a frame. Code which hits this should have checked 484 // Document::isActive() before calling into code which could get here. 485 486 ASSERT(document().frame()); 487 488 m_resolver = adoptPtrWillBeNoop(new StyleResolver(*m_document)); 489 appendActiveAuthorStyleSheets(); 490 combineCSSFeatureFlags(m_resolver->ensureUpdatedRuleFeatureSet()); 491 } 492 493 void StyleEngine::clearResolver() 494 { 495 ASSERT(!document().inStyleRecalc()); 496 ASSERT(isMaster() || !m_resolver); 497 if (m_resolver) 498 document().updateStyleInvalidationIfNeeded(); 499 m_resolver.clear(); 500 } 501 502 void StyleEngine::clearMasterResolver() 503 { 504 if (Document* master = this->master()) 505 master->styleEngine()->clearResolver(); 506 } 507 508 unsigned StyleEngine::resolverAccessCount() const 509 { 510 return m_resolver ? m_resolver->accessCount() : 0; 511 } 512 513 void StyleEngine::didDetach() 514 { 515 clearResolver(); 516 } 517 518 bool StyleEngine::shouldClearResolver() const 519 { 520 return !m_didCalculateResolver && !haveStylesheetsLoaded(); 521 } 522 523 bool StyleEngine::shouldApplyXSLTransform() const 524 { 525 if (!RuntimeEnabledFeatures::xsltEnabled()) 526 return false; 527 return m_xslStyleSheet && !m_document->transformSourceDocument(); 528 } 529 530 void StyleEngine::resolverChanged(StyleResolverUpdateMode mode) 531 { 532 if (!isMaster()) { 533 if (Document* master = this->master()) 534 master->styleResolverChanged(mode); 535 return; 536 } 537 538 // Don't bother updating, since we haven't loaded all our style info yet 539 // and haven't calculated the style selector for the first time. 540 if (!document().isActive() || shouldClearResolver()) { 541 clearResolver(); 542 return; 543 } 544 545 if (shouldApplyXSLTransform()) { 546 // Processing instruction (XML documents only). 547 // We don't support linking to embedded CSS stylesheets, see <https://bugs.webkit.org/show_bug.cgi?id=49281> for discussion. 548 // Don't apply XSL transforms to already transformed documents -- <rdar://problem/4132806> 549 if (!m_document->parsing() && !m_xslStyleSheet->isLoading()) 550 m_document->applyXSLTransform(m_xslStyleSheet.get()); 551 return; 552 } 553 554 m_didCalculateResolver = true; 555 updateActiveStyleSheets(mode); 556 } 557 558 void StyleEngine::clearFontCache() 559 { 560 // We should not recreate FontSelector. Instead, clear fontFaceCache. 561 if (m_fontSelector) 562 m_fontSelector->fontFaceCache()->clear(); 563 if (m_resolver) 564 m_resolver->invalidateMatchedPropertiesCache(); 565 } 566 567 void StyleEngine::updateGenericFontFamilySettings() 568 { 569 // FIXME: we should not update generic font family settings when 570 // document is inactive. 571 ASSERT(document().isActive()); 572 573 if (!m_fontSelector) 574 return; 575 576 m_fontSelector->updateGenericFontFamilySettings(*m_document); 577 if (m_resolver) 578 m_resolver->invalidateMatchedPropertiesCache(); 579 } 580 581 void StyleEngine::removeFontFaceRules(const WillBeHeapVector<RawPtrWillBeMember<const StyleRuleFontFace> >& fontFaceRules) 582 { 583 if (!m_fontSelector) 584 return; 585 586 FontFaceCache* cache = m_fontSelector->fontFaceCache(); 587 for (unsigned i = 0; i < fontFaceRules.size(); ++i) 588 cache->remove(fontFaceRules[i]); 589 if (m_resolver) 590 m_resolver->invalidateMatchedPropertiesCache(); 591 } 592 593 void StyleEngine::markTreeScopeDirty(TreeScope& scope) 594 { 595 if (scope == m_document) { 596 markDocumentDirty(); 597 return; 598 } 599 600 m_dirtyTreeScopes.add(&scope); 601 } 602 603 void StyleEngine::markDocumentDirty() 604 { 605 m_documentScopeDirty = true; 606 if (document().importLoader()) 607 document().importsController()->master()->styleEngine()->markDocumentDirty(); 608 } 609 610 static bool isCacheableForStyleElement(const StyleSheetContents& contents) 611 { 612 // FIXME: Support copying import rules. 613 if (!contents.importRules().isEmpty()) 614 return false; 615 // Until import rules are supported in cached sheets it's not possible for loading to fail. 616 ASSERT(!contents.didLoadErrorOccur()); 617 // It is not the original sheet anymore. 618 if (contents.isMutable()) 619 return false; 620 if (!contents.hasSyntacticallyValidCSSHeader()) 621 return false; 622 return true; 623 } 624 625 PassRefPtrWillBeRawPtr<CSSStyleSheet> StyleEngine::createSheet(Element* e, const String& text, TextPosition startPosition, bool createdByParser) 626 { 627 RefPtrWillBeRawPtr<CSSStyleSheet> styleSheet = nullptr; 628 629 e->document().styleEngine()->addPendingSheet(); 630 631 if (!e->document().inQuirksMode()) { 632 AtomicString textContent(text); 633 634 WillBeHeapHashMap<AtomicString, RawPtrWillBeMember<StyleSheetContents> >::AddResult result = m_textToSheetCache.add(textContent, nullptr); 635 if (result.isNewEntry || !result.storedValue->value) { 636 styleSheet = StyleEngine::parseSheet(e, text, startPosition, createdByParser); 637 if (result.isNewEntry && isCacheableForStyleElement(*styleSheet->contents())) { 638 result.storedValue->value = styleSheet->contents(); 639 m_sheetToTextCache.add(styleSheet->contents(), textContent); 640 } 641 } else { 642 StyleSheetContents* contents = result.storedValue->value; 643 ASSERT(contents); 644 ASSERT(isCacheableForStyleElement(*contents)); 645 ASSERT(contents->singleOwnerDocument() == e->document()); 646 styleSheet = CSSStyleSheet::createInline(contents, e, startPosition); 647 } 648 } else { 649 // FIXME: currently we don't cache StyleSheetContents inQuirksMode. 650 styleSheet = StyleEngine::parseSheet(e, text, startPosition, createdByParser); 651 } 652 653 ASSERT(styleSheet); 654 styleSheet->setTitle(e->title()); 655 return styleSheet; 656 } 657 658 PassRefPtrWillBeRawPtr<CSSStyleSheet> StyleEngine::parseSheet(Element* e, const String& text, TextPosition startPosition, bool createdByParser) 659 { 660 RefPtrWillBeRawPtr<CSSStyleSheet> styleSheet = nullptr; 661 styleSheet = CSSStyleSheet::createInline(e, KURL(), startPosition, e->document().inputEncoding()); 662 styleSheet->contents()->parseStringAtPosition(text, startPosition, createdByParser); 663 return styleSheet; 664 } 665 666 void StyleEngine::removeSheet(StyleSheetContents* contents) 667 { 668 WillBeHeapHashMap<RawPtrWillBeMember<StyleSheetContents>, AtomicString>::iterator it = m_sheetToTextCache.find(contents); 669 if (it == m_sheetToTextCache.end()) 670 return; 671 672 m_textToSheetCache.remove(it->value); 673 m_sheetToTextCache.remove(contents); 674 } 675 676 void StyleEngine::fontsNeedUpdate(CSSFontSelector*) 677 { 678 if (!document().isActive()) 679 return; 680 681 if (m_resolver) 682 m_resolver->invalidateMatchedPropertiesCache(); 683 document().setNeedsStyleRecalc(SubtreeStyleChange); 684 } 685 686 void StyleEngine::trace(Visitor* visitor) 687 { 688 visitor->trace(m_document); 689 visitor->trace(m_injectedAuthorStyleSheets); 690 visitor->trace(m_authorStyleSheets); 691 visitor->trace(m_documentStyleSheetCollection); 692 visitor->trace(m_styleSheetCollectionMap); 693 visitor->trace(m_resolver); 694 visitor->trace(m_fontSelector); 695 visitor->trace(m_textToSheetCache); 696 visitor->trace(m_sheetToTextCache); 697 visitor->trace(m_xslStyleSheet); 698 CSSFontSelectorClient::trace(visitor); 699 } 700 701 } 702