Move parseFontFaceDescriptor to CSSPropertyParser.cpp
[chromium-blink-merge.git] / third_party / WebKit / Source / core / dom / StyleEngine.cpp
blob8f61504461b5ddd1396365e116888792f32fd843
1 /*
2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3 * (C) 1999 Antti Koivisto (koivisto@kde.org)
4 * (C) 2001 Dirk Mueller (mueller@kde.org)
5 * (C) 2006 Alexey Proskuryakov (ap@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.
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.
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.
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.
28 #include "config.h"
29 #include "core/dom/StyleEngine.h"
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/css/resolver/ScopedStyleResolver.h"
37 #include "core/dom/DocumentStyleSheetCollector.h"
38 #include "core/dom/Element.h"
39 #include "core/dom/ProcessingInstruction.h"
40 #include "core/dom/ShadowTreeStyleSheetCollection.h"
41 #include "core/dom/shadow/ShadowRoot.h"
42 #include "core/frame/Settings.h"
43 #include "core/html/HTMLIFrameElement.h"
44 #include "core/html/HTMLLinkElement.h"
45 #include "core/html/imports/HTMLImportsController.h"
46 #include "core/inspector/InspectorInstrumentation.h"
47 #include "core/page/Page.h"
48 #include "core/svg/SVGStyleElement.h"
49 #include "platform/TraceEvent.h"
51 namespace blink {
53 using namespace HTMLNames;
55 StyleEngine::StyleEngine(Document& document)
56 : m_document(&document)
57 , m_isMaster(!document.importsController() || document.importsController()->master() == &document)
58 , m_pendingStylesheets(0)
59 , m_documentStyleSheetCollection(DocumentStyleSheetCollection::create(document))
60 , m_documentScopeDirty(true)
61 , m_usesSiblingRules(false)
62 , m_usesFirstLineRules(false)
63 , m_usesWindowInactiveSelector(false)
64 , m_usesRemUnits(false)
65 , m_maxDirectAdjacentSelectors(0)
66 , m_ignorePendingStylesheets(false)
67 , m_didCalculateResolver(false)
68 // We don't need to create CSSFontSelector for imported document or
69 // HTMLTemplateElement's document, because those documents have no frame.
70 , m_fontSelector(document.frame() ? CSSFontSelector::create(&document) : nullptr)
72 if (m_fontSelector)
73 m_fontSelector->registerForInvalidationCallbacks(this);
76 StyleEngine::~StyleEngine()
80 static bool isStyleElement(Node& node)
82 return isHTMLStyleElement(node) || isSVGStyleElement(node);
85 #if !ENABLE(OILPAN)
86 void StyleEngine::detachFromDocument()
88 // Cleanup is performed eagerly when the StyleEngine is removed from the
89 // document. The StyleEngine is unreachable after this, since only the
90 // document has a reference to it.
91 for (unsigned i = 0; i < m_authorStyleSheets.size(); ++i)
92 m_authorStyleSheets[i]->clearOwnerNode();
94 if (m_fontSelector) {
95 m_fontSelector->clearDocument();
96 m_fontSelector->unregisterForInvalidationCallbacks(this);
99 // Decrement reference counts for things we could be keeping alive.
100 m_fontSelector.clear();
101 m_resolver.clear();
102 m_styleSheetCollectionMap.clear();
103 m_activeTreeScopes.clear();
105 #endif
107 inline Document* StyleEngine::master()
109 if (isMaster())
110 return m_document;
111 HTMLImportsController* import = document().importsController();
112 if (!import) // Document::import() can return null while executing its destructor.
113 return 0;
114 return import->master();
117 TreeScopeStyleSheetCollection* StyleEngine::ensureStyleSheetCollectionFor(TreeScope& treeScope)
119 if (treeScope == m_document)
120 return documentStyleSheetCollection();
122 StyleSheetCollectionMap::AddResult result = m_styleSheetCollectionMap.add(&treeScope, nullptr);
123 if (result.isNewEntry)
124 result.storedValue->value = adoptPtrWillBeNoop(new ShadowTreeStyleSheetCollection(toShadowRoot(treeScope)));
125 return result.storedValue->value.get();
128 TreeScopeStyleSheetCollection* StyleEngine::styleSheetCollectionFor(TreeScope& treeScope)
130 if (treeScope == m_document)
131 return documentStyleSheetCollection();
133 StyleSheetCollectionMap::iterator it = m_styleSheetCollectionMap.find(&treeScope);
134 if (it == m_styleSheetCollectionMap.end())
135 return 0;
136 return it->value.get();
139 const WillBeHeapVector<RefPtrWillBeMember<StyleSheet>>& StyleEngine::styleSheetsForStyleSheetList(TreeScope& treeScope)
141 if (treeScope == m_document)
142 return documentStyleSheetCollection()->styleSheetsForStyleSheetList();
144 return ensureStyleSheetCollectionFor(treeScope)->styleSheetsForStyleSheetList();
147 const WillBeHeapVector<RefPtrWillBeMember<CSSStyleSheet>>& StyleEngine::activeAuthorStyleSheets() const
149 return documentStyleSheetCollection()->activeAuthorStyleSheets();
152 void StyleEngine::combineCSSFeatureFlags(const RuleFeatureSet& features)
154 // 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).
155 m_usesSiblingRules = m_usesSiblingRules || features.usesSiblingRules();
156 m_usesFirstLineRules = m_usesFirstLineRules || features.usesFirstLineRules();
157 m_usesWindowInactiveSelector = m_usesWindowInactiveSelector || features.usesWindowInactiveSelector();
158 m_maxDirectAdjacentSelectors = max(m_maxDirectAdjacentSelectors, features.maxDirectAdjacentSelectors());
161 void StyleEngine::resetCSSFeatureFlags(const RuleFeatureSet& features)
163 m_usesSiblingRules = features.usesSiblingRules();
164 m_usesFirstLineRules = features.usesFirstLineRules();
165 m_usesWindowInactiveSelector = features.usesWindowInactiveSelector();
166 m_maxDirectAdjacentSelectors = features.maxDirectAdjacentSelectors();
169 void StyleEngine::addAuthorSheet(PassRefPtrWillBeRawPtr<StyleSheetContents> authorSheet)
171 m_authorStyleSheets.append(CSSStyleSheet::create(authorSheet, m_document));
172 document().addedStyleSheet(m_authorStyleSheets.last().get());
173 markDocumentDirty();
176 void StyleEngine::addPendingSheet()
178 m_pendingStylesheets++;
181 // This method is called whenever a top-level stylesheet has finished loading.
182 void StyleEngine::removePendingSheet(Node* styleSheetCandidateNode)
184 ASSERT(styleSheetCandidateNode);
185 TreeScope* treeScope = isStyleElement(*styleSheetCandidateNode) ? &styleSheetCandidateNode->treeScope() : m_document.get();
186 if (styleSheetCandidateNode->inDocument())
187 markTreeScopeDirty(*treeScope);
189 // Make sure we knew this sheet was pending, and that our count isn't out of sync.
190 ASSERT(m_pendingStylesheets > 0);
192 m_pendingStylesheets--;
193 if (m_pendingStylesheets)
194 return;
196 // FIXME: We can't call addedStyleSheet or removedStyleSheet here because we don't know
197 // what's new. We should track that to tell the style system what changed.
198 document().didRemoveAllPendingStylesheet();
201 void StyleEngine::modifiedStyleSheet(StyleSheet* sheet)
203 if (!sheet)
204 return;
206 Node* node = sheet->ownerNode();
207 if (!node || !node->inDocument())
208 return;
210 TreeScope& treeScope = isStyleElement(*node) ? node->treeScope() : *m_document;
211 ASSERT(isStyleElement(*node) || treeScope == m_document);
213 markTreeScopeDirty(treeScope);
216 void StyleEngine::addStyleSheetCandidateNode(Node* node, bool createdByParser)
218 if (!node->inDocument() || document().isDetached())
219 return;
221 TreeScope& treeScope = isStyleElement(*node) ? node->treeScope() : *m_document;
222 ASSERT(isStyleElement(*node) || treeScope == m_document);
223 ASSERT(!isXSLStyleSheet(*node));
224 TreeScopeStyleSheetCollection* collection = ensureStyleSheetCollectionFor(treeScope);
225 ASSERT(collection);
226 collection->addStyleSheetCandidateNode(node, createdByParser);
228 markTreeScopeDirty(treeScope);
229 if (treeScope != m_document)
230 m_activeTreeScopes.add(&treeScope);
233 void StyleEngine::removeStyleSheetCandidateNode(Node* node)
235 removeStyleSheetCandidateNode(node, *m_document);
238 void StyleEngine::removeStyleSheetCandidateNode(Node* node, TreeScope& treeScope)
240 ASSERT(isStyleElement(*node) || treeScope == m_document);
241 ASSERT(!isXSLStyleSheet(*node));
243 TreeScopeStyleSheetCollection* collection = styleSheetCollectionFor(treeScope);
244 // After detaching document, collection could be null. In the case,
245 // we should not update anything. Instead, just return.
246 if (!collection)
247 return;
248 collection->removeStyleSheetCandidateNode(node);
250 markTreeScopeDirty(treeScope);
253 void StyleEngine::modifiedStyleSheetCandidateNode(Node* node)
255 if (!node->inDocument())
256 return;
258 TreeScope& treeScope = isStyleElement(*node) ? node->treeScope() : *m_document;
259 ASSERT(isStyleElement(*node) || treeScope == m_document);
260 markTreeScopeDirty(treeScope);
263 bool StyleEngine::shouldUpdateDocumentStyleSheetCollection(StyleResolverUpdateMode updateMode) const
265 return m_documentScopeDirty || updateMode == FullStyleUpdate;
268 bool StyleEngine::shouldUpdateShadowTreeStyleSheetCollection(StyleResolverUpdateMode updateMode) const
270 return !m_dirtyTreeScopes.isEmpty() || updateMode == FullStyleUpdate;
273 void StyleEngine::clearMediaQueryRuleSetOnTreeScopeStyleSheets(UnorderedTreeScopeSet& treeScopes)
275 for (TreeScope* treeScope : treeScopes) {
276 ASSERT(treeScope != m_document);
277 ShadowTreeStyleSheetCollection* collection = static_cast<ShadowTreeStyleSheetCollection*>(styleSheetCollectionFor(*treeScope));
278 ASSERT(collection);
279 collection->clearMediaQueryRuleSetStyleSheets();
283 void StyleEngine::clearMediaQueryRuleSetStyleSheets()
285 documentStyleSheetCollection()->clearMediaQueryRuleSetStyleSheets();
286 clearMediaQueryRuleSetOnTreeScopeStyleSheets(m_activeTreeScopes);
287 clearMediaQueryRuleSetOnTreeScopeStyleSheets(m_dirtyTreeScopes);
290 void StyleEngine::updateStyleSheetsInImport(DocumentStyleSheetCollector& parentCollector)
292 ASSERT(!isMaster());
293 WillBeHeapVector<RefPtrWillBeMember<StyleSheet>> sheetsForList;
294 ImportedDocumentStyleSheetCollector subcollector(parentCollector, sheetsForList);
295 documentStyleSheetCollection()->collectStyleSheets(*this, subcollector);
296 documentStyleSheetCollection()->swapSheetsForSheetList(sheetsForList);
299 void StyleEngine::updateActiveStyleSheetsInShadow(StyleResolverUpdateMode updateMode, TreeScope* treeScope, UnorderedTreeScopeSet& treeScopesRemoved)
301 ASSERT(treeScope != m_document);
302 ShadowTreeStyleSheetCollection* collection = static_cast<ShadowTreeStyleSheetCollection*>(styleSheetCollectionFor(*treeScope));
303 ASSERT(collection);
304 collection->updateActiveStyleSheets(*this, updateMode);
305 if (!collection->hasStyleSheetCandidateNodes()) {
306 treeScopesRemoved.add(treeScope);
307 // When removing TreeScope from ActiveTreeScopes,
308 // its resolver should be destroyed by invoking resetAuthorStyle.
309 ASSERT(!treeScope->scopedStyleResolver());
313 void StyleEngine::updateActiveStyleSheets(StyleResolverUpdateMode updateMode)
315 ASSERT(isMaster());
316 ASSERT(!document().inStyleRecalc());
318 if (!document().isActive())
319 return;
321 if (shouldUpdateDocumentStyleSheetCollection(updateMode))
322 documentStyleSheetCollection()->updateActiveStyleSheets(*this, updateMode);
324 if (shouldUpdateShadowTreeStyleSheetCollection(updateMode)) {
325 UnorderedTreeScopeSet treeScopesRemoved;
327 if (updateMode == FullStyleUpdate) {
328 for (TreeScope* treeScope : m_activeTreeScopes)
329 updateActiveStyleSheetsInShadow(updateMode, treeScope, treeScopesRemoved);
330 } else {
331 for (TreeScope* treeScope : m_dirtyTreeScopes)
332 updateActiveStyleSheetsInShadow(updateMode, treeScope, treeScopesRemoved);
334 for (TreeScope* treeScope : treeScopesRemoved)
335 m_activeTreeScopes.remove(treeScope);
338 InspectorInstrumentation::activeStyleSheetsUpdated(m_document);
340 m_dirtyTreeScopes.clear();
341 m_documentScopeDirty = false;
344 const WillBeHeapVector<RefPtrWillBeMember<CSSStyleSheet>> StyleEngine::activeStyleSheetsForInspector() const
346 if (m_activeTreeScopes.isEmpty())
347 return documentStyleSheetCollection()->activeAuthorStyleSheets();
349 WillBeHeapVector<RefPtrWillBeMember<CSSStyleSheet>> activeStyleSheets;
351 activeStyleSheets.appendVector(documentStyleSheetCollection()->activeAuthorStyleSheets());
352 for (TreeScope* treeScope : m_activeTreeScopes) {
353 if (TreeScopeStyleSheetCollection* collection = m_styleSheetCollectionMap.get(treeScope))
354 activeStyleSheets.appendVector(collection->activeAuthorStyleSheets());
357 // FIXME: Inspector needs a vector which has all active stylesheets.
358 // However, creating such a large vector might cause performance regression.
359 // Need to implement some smarter solution.
360 return activeStyleSheets;
363 void StyleEngine::didRemoveShadowRoot(ShadowRoot* shadowRoot)
365 m_styleSheetCollectionMap.remove(shadowRoot);
366 m_activeTreeScopes.remove(shadowRoot);
367 m_dirtyTreeScopes.remove(shadowRoot);
370 void StyleEngine::shadowRootRemovedFromDocument(ShadowRoot* shadowRoot)
372 if (StyleResolver* styleResolver = resolver()) {
373 styleResolver->resetAuthorStyle(*shadowRoot);
375 if (TreeScopeStyleSheetCollection* collection = styleSheetCollectionFor(*shadowRoot))
376 styleResolver->removePendingAuthorStyleSheets(collection->activeAuthorStyleSheets());
378 m_styleSheetCollectionMap.remove(shadowRoot);
379 m_activeTreeScopes.remove(shadowRoot);
380 m_dirtyTreeScopes.remove(shadowRoot);
383 void StyleEngine::appendActiveAuthorStyleSheets()
385 ASSERT(isMaster());
387 m_resolver->appendAuthorStyleSheets(documentStyleSheetCollection()->activeAuthorStyleSheets());
388 for (TreeScope* treeScope : m_activeTreeScopes) {
389 if (TreeScopeStyleSheetCollection* collection = m_styleSheetCollectionMap.get(treeScope))
390 m_resolver->appendAuthorStyleSheets(collection->activeAuthorStyleSheets());
392 m_resolver->finishAppendAuthorStyleSheets();
395 void StyleEngine::createResolver()
397 TRACE_EVENT1("blink", "StyleEngine::createResolver", "frame", document().frame());
398 // It is a programming error to attempt to resolve style on a Document
399 // which is not in a frame. Code which hits this should have checked
400 // Document::isActive() before calling into code which could get here.
402 ASSERT(document().frame());
404 m_resolver = adoptPtrWillBeNoop(new StyleResolver(*m_document));
406 // A scoped style resolver for document will be created during
407 // appendActiveAuthorStyleSheets if needed.
408 appendActiveAuthorStyleSheets();
409 combineCSSFeatureFlags(m_resolver->ensureUpdatedRuleFeatureSet());
412 void StyleEngine::clearResolver()
414 ASSERT(!document().inStyleRecalc());
415 ASSERT(isMaster() || !m_resolver);
417 document().clearScopedStyleResolver();
418 // StyleEngine::shadowRootRemovedFromDocument removes not-in-document
419 // treescopes from activeTreeScopes. StyleEngine::didRemoveShadowRoot
420 // removes treescopes which are being destroyed from activeTreeScopes.
421 // So we need to clearScopedStyleResolver for treescopes which have been
422 // just removed from document. If document is destroyed before invoking
423 // updateActiveStyleSheets, the treescope has a scopedStyleResolver which
424 // has destroyed StyleSheetContents.
425 for (TreeScope* treeScope : m_activeTreeScopes)
426 treeScope->clearScopedStyleResolver();
428 if (m_resolver) {
429 TRACE_EVENT1("blink", "StyleEngine::clearResolver", "frame", document().frame());
430 m_resolver.clear();
434 void StyleEngine::clearMasterResolver()
436 if (Document* master = this->master())
437 master->styleEngine().clearResolver();
440 unsigned StyleEngine::resolverAccessCount() const
442 return m_resolver ? m_resolver->accessCount() : 0;
445 void StyleEngine::didDetach()
447 clearResolver();
450 bool StyleEngine::shouldClearResolver() const
452 return !m_didCalculateResolver && !haveStylesheetsLoaded();
455 void StyleEngine::resolverChanged(StyleResolverUpdateMode mode)
457 if (!isMaster()) {
458 if (Document* master = this->master())
459 master->styleResolverChanged(mode);
460 return;
463 // Don't bother updating, since we haven't loaded all our style info yet
464 // and haven't calculated the style selector for the first time.
465 if (!document().isActive() || shouldClearResolver()) {
466 clearResolver();
467 return;
470 m_didCalculateResolver = true;
471 updateActiveStyleSheets(mode);
474 void StyleEngine::clearFontCache()
476 if (m_fontSelector)
477 m_fontSelector->fontFaceCache()->clearCSSConnected();
478 if (m_resolver)
479 m_resolver->invalidateMatchedPropertiesCache();
482 void StyleEngine::updateGenericFontFamilySettings()
484 // FIXME: we should not update generic font family settings when
485 // document is inactive.
486 ASSERT(document().isActive());
488 if (!m_fontSelector)
489 return;
491 m_fontSelector->updateGenericFontFamilySettings(*m_document);
492 if (m_resolver)
493 m_resolver->invalidateMatchedPropertiesCache();
496 void StyleEngine::removeFontFaceRules(const WillBeHeapVector<RawPtrWillBeMember<const StyleRuleFontFace>>& fontFaceRules)
498 if (!m_fontSelector)
499 return;
501 FontFaceCache* cache = m_fontSelector->fontFaceCache();
502 for (unsigned i = 0; i < fontFaceRules.size(); ++i)
503 cache->remove(fontFaceRules[i]);
504 if (m_resolver)
505 m_resolver->invalidateMatchedPropertiesCache();
508 void StyleEngine::markTreeScopeDirty(TreeScope& scope)
510 if (scope == m_document) {
511 markDocumentDirty();
512 return;
515 ASSERT(m_styleSheetCollectionMap.contains(&scope));
516 m_dirtyTreeScopes.add(&scope);
519 void StyleEngine::markDocumentDirty()
521 m_documentScopeDirty = true;
522 if (document().importLoader())
523 document().importsController()->master()->styleEngine().markDocumentDirty();
526 static bool isCacheableForStyleElement(const StyleSheetContents& contents)
528 // FIXME: Support copying import rules.
529 if (!contents.importRules().isEmpty())
530 return false;
531 // Until import rules are supported in cached sheets it's not possible for loading to fail.
532 ASSERT(!contents.didLoadErrorOccur());
533 // It is not the original sheet anymore.
534 if (contents.isMutable())
535 return false;
536 if (!contents.hasSyntacticallyValidCSSHeader())
537 return false;
538 return true;
541 PassRefPtrWillBeRawPtr<CSSStyleSheet> StyleEngine::createSheet(Element* e, const String& text, TextPosition startPosition)
543 RefPtrWillBeRawPtr<CSSStyleSheet> styleSheet = nullptr;
545 e->document().styleEngine().addPendingSheet();
547 AtomicString textContent(text);
549 WillBeHeapHashMap<AtomicString, RawPtrWillBeMember<StyleSheetContents>>::AddResult result = m_textToSheetCache.add(textContent, nullptr);
550 if (result.isNewEntry || !result.storedValue->value) {
551 styleSheet = StyleEngine::parseSheet(e, text, startPosition);
552 if (result.isNewEntry && isCacheableForStyleElement(*styleSheet->contents())) {
553 result.storedValue->value = styleSheet->contents();
554 m_sheetToTextCache.add(styleSheet->contents(), textContent);
556 } else {
557 StyleSheetContents* contents = result.storedValue->value;
558 ASSERT(contents);
559 ASSERT(isCacheableForStyleElement(*contents));
560 ASSERT(contents->singleOwnerDocument() == e->document());
561 styleSheet = CSSStyleSheet::createInline(contents, e, startPosition);
564 ASSERT(styleSheet);
565 styleSheet->setTitle(e->title());
566 return styleSheet;
569 PassRefPtrWillBeRawPtr<CSSStyleSheet> StyleEngine::parseSheet(Element* e, const String& text, TextPosition startPosition)
571 RefPtrWillBeRawPtr<CSSStyleSheet> styleSheet = nullptr;
572 styleSheet = CSSStyleSheet::createInline(e, KURL(), startPosition, e->document().characterSet());
573 styleSheet->contents()->parseStringAtPosition(text, startPosition);
574 return styleSheet;
577 void StyleEngine::removeSheet(StyleSheetContents* contents)
579 WillBeHeapHashMap<RawPtrWillBeMember<StyleSheetContents>, AtomicString>::iterator it = m_sheetToTextCache.find(contents);
580 if (it == m_sheetToTextCache.end())
581 return;
583 m_textToSheetCache.remove(it->value);
584 m_sheetToTextCache.remove(contents);
587 void StyleEngine::collectScopedStyleFeaturesTo(RuleFeatureSet& features) const
589 HashSet<const StyleSheetContents*> visitedSharedStyleSheetContents;
590 if (document().scopedStyleResolver())
591 document().scopedStyleResolver()->collectFeaturesTo(features, visitedSharedStyleSheetContents);
592 for (TreeScope* treeScope : m_activeTreeScopes) {
593 // When creating StyleResolver, dirty treescopes might not be processed.
594 // So some active treescopes might not have a scoped style resolver.
595 // In this case, we should skip collectFeatures for the treescopes without
596 // scoped style resolvers. When invoking updateActiveStyleSheets,
597 // the treescope's features will be processed.
598 if (ScopedStyleResolver* resolver = treeScope->scopedStyleResolver())
599 resolver->collectFeaturesTo(features, visitedSharedStyleSheetContents);
603 void StyleEngine::fontsNeedUpdate(CSSFontSelector*)
605 if (!document().isActive())
606 return;
608 if (m_resolver)
609 m_resolver->invalidateMatchedPropertiesCache();
610 document().setNeedsStyleRecalc(SubtreeStyleChange, StyleChangeReasonForTracing::create(StyleChangeReason::Fonts));
613 void StyleEngine::setFontSelector(PassRefPtrWillBeRawPtr<CSSFontSelector> fontSelector)
615 #if !ENABLE(OILPAN)
616 if (m_fontSelector)
617 m_fontSelector->unregisterForInvalidationCallbacks(this);
618 #endif
619 m_fontSelector = fontSelector;
620 if (m_fontSelector)
621 m_fontSelector->registerForInvalidationCallbacks(this);
624 void StyleEngine::platformColorsChanged()
626 if (m_resolver)
627 m_resolver->invalidateMatchedPropertiesCache();
628 document().setNeedsStyleRecalc(SubtreeStyleChange, StyleChangeReasonForTracing::create(StyleChangeReason::PlatformColorChange));
631 void StyleEngine::classChangedForElement(const SpaceSplitString& changedClasses, Element& element)
633 ASSERT(isMaster());
634 InvalidationSetVector invalidationSets;
635 unsigned changedSize = changedClasses.size();
636 RuleFeatureSet& ruleFeatureSet = ensureResolver().ensureUpdatedRuleFeatureSet();
637 for (unsigned i = 0; i < changedSize; ++i)
638 ruleFeatureSet.collectInvalidationSetsForClass(invalidationSets, element, changedClasses[i]);
639 scheduleInvalidationSetsForElement(invalidationSets, element);
642 void StyleEngine::classChangedForElement(const SpaceSplitString& oldClasses, const SpaceSplitString& newClasses, Element& element)
644 ASSERT(isMaster());
645 InvalidationSetVector invalidationSets;
646 if (!oldClasses.size()) {
647 classChangedForElement(newClasses, element);
648 return;
651 // Class vectors tend to be very short. This is faster than using a hash table.
652 BitVector remainingClassBits;
653 remainingClassBits.ensureSize(oldClasses.size());
655 RuleFeatureSet& ruleFeatureSet = ensureResolver().ensureUpdatedRuleFeatureSet();
657 for (unsigned i = 0; i < newClasses.size(); ++i) {
658 bool found = false;
659 for (unsigned j = 0; j < oldClasses.size(); ++j) {
660 if (newClasses[i] == oldClasses[j]) {
661 // Mark each class that is still in the newClasses so we can skip doing
662 // an n^2 search below when looking for removals. We can't break from
663 // this loop early since a class can appear more than once.
664 remainingClassBits.quickSet(j);
665 found = true;
668 // Class was added.
669 if (!found)
670 ruleFeatureSet.collectInvalidationSetsForClass(invalidationSets, element, newClasses[i]);
673 for (unsigned i = 0; i < oldClasses.size(); ++i) {
674 if (remainingClassBits.quickGet(i))
675 continue;
676 // Class was removed.
677 ruleFeatureSet.collectInvalidationSetsForClass(invalidationSets, element, oldClasses[i]);
680 scheduleInvalidationSetsForElement(invalidationSets, element);
683 void StyleEngine::attributeChangedForElement(const QualifiedName& attributeName, Element& element)
685 ASSERT(isMaster());
686 InvalidationSetVector invalidationSets;
687 ensureResolver().ensureUpdatedRuleFeatureSet().collectInvalidationSetsForAttribute(invalidationSets, element, attributeName);
688 scheduleInvalidationSetsForElement(invalidationSets, element);
691 void StyleEngine::idChangedForElement(const AtomicString& oldId, const AtomicString& newId, Element& element)
693 ASSERT(isMaster());
694 InvalidationSetVector invalidationSets;
695 RuleFeatureSet& ruleFeatureSet = ensureResolver().ensureUpdatedRuleFeatureSet();
696 if (!oldId.isEmpty())
697 ruleFeatureSet.collectInvalidationSetsForId(invalidationSets, element, oldId);
698 if (!newId.isEmpty())
699 ruleFeatureSet.collectInvalidationSetsForId(invalidationSets, element, newId);
700 scheduleInvalidationSetsForElement(invalidationSets, element);
703 void StyleEngine::pseudoStateChangedForElement(CSSSelector::PseudoType pseudoType, Element& element)
705 ASSERT(isMaster());
706 InvalidationSetVector invalidationSets;
707 ensureResolver().ensureUpdatedRuleFeatureSet().collectInvalidationSetsForPseudoClass(invalidationSets, element, pseudoType);
708 scheduleInvalidationSetsForElement(invalidationSets, element);
711 void StyleEngine::scheduleInvalidationSetsForElement(const InvalidationSetVector& invalidationSets, Element& element)
713 for (auto invalidationSet : invalidationSets)
714 m_styleInvalidator.scheduleInvalidation(invalidationSet, element);
717 DEFINE_TRACE(StyleEngine)
719 #if ENABLE(OILPAN)
720 visitor->trace(m_document);
721 visitor->trace(m_authorStyleSheets);
722 visitor->trace(m_documentStyleSheetCollection);
723 visitor->trace(m_styleSheetCollectionMap);
724 visitor->trace(m_resolver);
725 visitor->trace(m_styleInvalidator);
726 visitor->trace(m_dirtyTreeScopes);
727 visitor->trace(m_activeTreeScopes);
728 visitor->trace(m_fontSelector);
729 visitor->trace(m_textToSheetCache);
730 visitor->trace(m_sheetToTextCache);
731 #endif
732 CSSFontSelectorClient::trace(visitor);