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