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.
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"
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)
73 m_fontSelector
->registerForInvalidationCallbacks(this);
76 StyleEngine::~StyleEngine()
80 static bool isStyleElement(Node
& node
)
82 return isHTMLStyleElement(node
) || isSVGStyleElement(node
);
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();
95 m_fontSelector
->clearDocument();
96 m_fontSelector
->unregisterForInvalidationCallbacks(this);
99 // Decrement reference counts for things we could be keeping alive.
100 m_fontSelector
.clear();
102 m_styleSheetCollectionMap
.clear();
103 m_activeTreeScopes
.clear();
107 inline Document
* StyleEngine::master()
111 HTMLImportsController
* import
= document().importsController();
112 if (!import
) // Document::import() can return null while executing its destructor.
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())
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());
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
)
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
)
206 Node
* node
= sheet
->ownerNode();
207 if (!node
|| !node
->inDocument())
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())
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
);
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.
248 collection
->removeStyleSheetCandidateNode(node
);
250 markTreeScopeDirty(treeScope
);
253 void StyleEngine::modifiedStyleSheetCandidateNode(Node
* node
)
255 if (!node
->inDocument())
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
));
279 collection
->clearMediaQueryRuleSetStyleSheets();
283 void StyleEngine::clearMediaQueryRuleSetStyleSheets()
285 documentStyleSheetCollection()->clearMediaQueryRuleSetStyleSheets();
286 clearMediaQueryRuleSetOnTreeScopeStyleSheets(m_activeTreeScopes
);
287 clearMediaQueryRuleSetOnTreeScopeStyleSheets(m_dirtyTreeScopes
);
290 void StyleEngine::updateStyleSheetsInImport(DocumentStyleSheetCollector
& parentCollector
)
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
));
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
)
316 ASSERT(!document().inStyleRecalc());
318 if (!document().isActive())
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
);
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()
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();
429 TRACE_EVENT1("blink", "StyleEngine::clearResolver", "frame", document().frame());
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()
450 bool StyleEngine::shouldClearResolver() const
452 return !m_didCalculateResolver
&& !haveStylesheetsLoaded();
455 void StyleEngine::resolverChanged(StyleResolverUpdateMode mode
)
458 if (Document
* master
= this->master())
459 master
->styleResolverChanged(mode
);
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()) {
470 m_didCalculateResolver
= true;
471 updateActiveStyleSheets(mode
);
474 void StyleEngine::clearFontCache()
477 m_fontSelector
->fontFaceCache()->clearCSSConnected();
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());
491 m_fontSelector
->updateGenericFontFamilySettings(*m_document
);
493 m_resolver
->invalidateMatchedPropertiesCache();
496 void StyleEngine::removeFontFaceRules(const WillBeHeapVector
<RawPtrWillBeMember
<const StyleRuleFontFace
>>& fontFaceRules
)
501 FontFaceCache
* cache
= m_fontSelector
->fontFaceCache();
502 for (unsigned i
= 0; i
< fontFaceRules
.size(); ++i
)
503 cache
->remove(fontFaceRules
[i
]);
505 m_resolver
->invalidateMatchedPropertiesCache();
508 void StyleEngine::markTreeScopeDirty(TreeScope
& scope
)
510 if (scope
== m_document
) {
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())
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())
536 if (!contents
.hasSyntacticallyValidCSSHeader())
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
);
557 StyleSheetContents
* contents
= result
.storedValue
->value
;
559 ASSERT(isCacheableForStyleElement(*contents
));
560 ASSERT(contents
->singleOwnerDocument() == e
->document());
561 styleSheet
= CSSStyleSheet::createInline(contents
, e
, startPosition
);
565 styleSheet
->setTitle(e
->title());
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
);
577 void StyleEngine::removeSheet(StyleSheetContents
* contents
)
579 WillBeHeapHashMap
<RawPtrWillBeMember
<StyleSheetContents
>, AtomicString
>::iterator it
= m_sheetToTextCache
.find(contents
);
580 if (it
== m_sheetToTextCache
.end())
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())
609 m_resolver
->invalidateMatchedPropertiesCache();
610 document().setNeedsStyleRecalc(SubtreeStyleChange
, StyleChangeReasonForTracing::create(StyleChangeReason::Fonts
));
613 void StyleEngine::setFontSelector(PassRefPtrWillBeRawPtr
<CSSFontSelector
> fontSelector
)
617 m_fontSelector
->unregisterForInvalidationCallbacks(this);
619 m_fontSelector
= fontSelector
;
621 m_fontSelector
->registerForInvalidationCallbacks(this);
624 void StyleEngine::platformColorsChanged()
627 m_resolver
->invalidateMatchedPropertiesCache();
628 document().setNeedsStyleRecalc(SubtreeStyleChange
, StyleChangeReasonForTracing::create(StyleChangeReason::PlatformColorChange
));
631 void StyleEngine::classChangedForElement(const SpaceSplitString
& changedClasses
, Element
& element
)
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
)
645 InvalidationSetVector invalidationSets
;
646 if (!oldClasses
.size()) {
647 classChangedForElement(newClasses
, element
);
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
) {
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
);
670 ruleFeatureSet
.collectInvalidationSetsForClass(invalidationSets
, element
, newClasses
[i
]);
673 for (unsigned i
= 0; i
< oldClasses
.size(); ++i
) {
674 if (remainingClassBits
.quickGet(i
))
676 // Class was removed.
677 ruleFeatureSet
.collectInvalidationSetsForClass(invalidationSets
, element
, oldClasses
[i
]);
680 scheduleInvalidationSetsForElement(invalidationSets
, element
);
683 void StyleEngine::attributeChangedForElement(const QualifiedName
& attributeName
, Element
& element
)
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
)
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
)
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
)
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
);
732 CSSFontSelectorClient::trace(visitor
);