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"
52 using namespace HTMLNames
;
54 StyleEngine::StyleEngine(Document
& document
)
55 : m_document(&document
)
56 , m_isMaster(!document
.importsController() || document
.importsController()->master() == &document
)
57 , m_pendingStylesheets(0)
58 , m_documentStyleSheetCollection(DocumentStyleSheetCollection::create(document
))
59 , m_documentScopeDirty(true)
60 , m_usesSiblingRules(false)
61 , m_usesFirstLineRules(false)
62 , m_usesWindowInactiveSelector(false)
63 , m_usesRemUnits(false)
64 , m_maxDirectAdjacentSelectors(0)
65 , m_ignorePendingStylesheets(false)
66 , m_didCalculateResolver(false)
67 // We don't need to create CSSFontSelector for imported document or
68 // HTMLTemplateElement's document, because those documents have no frame.
69 , m_fontSelector(document
.frame() ? CSSFontSelector::create(&document
) : nullptr)
72 m_fontSelector
->registerForInvalidationCallbacks(this);
75 StyleEngine::~StyleEngine()
79 static bool isStyleElement(Node
& node
)
81 return isHTMLStyleElement(node
) || isSVGStyleElement(node
);
85 void StyleEngine::detachFromDocument()
87 // Cleanup is performed eagerly when the StyleEngine is removed from the
88 // document. The StyleEngine is unreachable after this, since only the
89 // document has a reference to it.
90 for (unsigned i
= 0; i
< m_authorStyleSheets
.size(); ++i
)
91 m_authorStyleSheets
[i
]->clearOwnerNode();
94 m_fontSelector
->clearDocument();
95 m_fontSelector
->unregisterForInvalidationCallbacks(this);
98 // Decrement reference counts for things we could be keeping alive.
99 m_fontSelector
.clear();
101 m_styleSheetCollectionMap
.clear();
102 m_activeTreeScopes
.clear();
106 inline Document
* StyleEngine::master()
110 HTMLImportsController
* import
= document().importsController();
111 if (!import
) // Document::import() can return null while executing its destructor.
113 return import
->master();
116 TreeScopeStyleSheetCollection
* StyleEngine::ensureStyleSheetCollectionFor(TreeScope
& treeScope
)
118 if (treeScope
== m_document
)
119 return documentStyleSheetCollection();
121 StyleSheetCollectionMap::AddResult result
= m_styleSheetCollectionMap
.add(&treeScope
, nullptr);
122 if (result
.isNewEntry
)
123 result
.storedValue
->value
= adoptPtrWillBeNoop(new ShadowTreeStyleSheetCollection(toShadowRoot(treeScope
)));
124 return result
.storedValue
->value
.get();
127 TreeScopeStyleSheetCollection
* StyleEngine::styleSheetCollectionFor(TreeScope
& treeScope
)
129 if (treeScope
== m_document
)
130 return documentStyleSheetCollection();
132 StyleSheetCollectionMap::iterator it
= m_styleSheetCollectionMap
.find(&treeScope
);
133 if (it
== m_styleSheetCollectionMap
.end())
135 return it
->value
.get();
138 const WillBeHeapVector
<RefPtrWillBeMember
<StyleSheet
>>& StyleEngine::styleSheetsForStyleSheetList(TreeScope
& treeScope
)
140 if (treeScope
== m_document
)
141 return documentStyleSheetCollection()->styleSheetsForStyleSheetList();
143 return ensureStyleSheetCollectionFor(treeScope
)->styleSheetsForStyleSheetList();
146 const WillBeHeapVector
<RefPtrWillBeMember
<CSSStyleSheet
>>& StyleEngine::activeAuthorStyleSheets() const
148 return documentStyleSheetCollection()->activeAuthorStyleSheets();
151 void StyleEngine::combineCSSFeatureFlags(const RuleFeatureSet
& features
)
153 // 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).
154 m_usesSiblingRules
= m_usesSiblingRules
|| features
.usesSiblingRules();
155 m_usesFirstLineRules
= m_usesFirstLineRules
|| features
.usesFirstLineRules();
156 m_usesWindowInactiveSelector
= m_usesWindowInactiveSelector
|| features
.usesWindowInactiveSelector();
157 m_maxDirectAdjacentSelectors
= max(m_maxDirectAdjacentSelectors
, features
.maxDirectAdjacentSelectors());
160 void StyleEngine::resetCSSFeatureFlags(const RuleFeatureSet
& features
)
162 m_usesSiblingRules
= features
.usesSiblingRules();
163 m_usesFirstLineRules
= features
.usesFirstLineRules();
164 m_usesWindowInactiveSelector
= features
.usesWindowInactiveSelector();
165 m_maxDirectAdjacentSelectors
= features
.maxDirectAdjacentSelectors();
168 void StyleEngine::addAuthorSheet(PassRefPtrWillBeRawPtr
<StyleSheetContents
> authorSheet
)
170 m_authorStyleSheets
.append(CSSStyleSheet::create(authorSheet
, m_document
));
171 document().addedStyleSheet(m_authorStyleSheets
.last().get());
175 void StyleEngine::addPendingSheet()
177 m_pendingStylesheets
++;
180 // This method is called whenever a top-level stylesheet has finished loading.
181 void StyleEngine::removePendingSheet(Node
* styleSheetCandidateNode
)
183 ASSERT(styleSheetCandidateNode
);
184 TreeScope
* treeScope
= isStyleElement(*styleSheetCandidateNode
) ? &styleSheetCandidateNode
->treeScope() : m_document
.get();
185 if (styleSheetCandidateNode
->inDocument())
186 markTreeScopeDirty(*treeScope
);
188 // Make sure we knew this sheet was pending, and that our count isn't out of sync.
189 ASSERT(m_pendingStylesheets
> 0);
191 m_pendingStylesheets
--;
192 if (m_pendingStylesheets
)
195 // FIXME: We can't call addedStyleSheet or removedStyleSheet here because we don't know
196 // what's new. We should track that to tell the style system what changed.
197 document().didRemoveAllPendingStylesheet();
200 void StyleEngine::modifiedStyleSheet(StyleSheet
* sheet
)
205 Node
* node
= sheet
->ownerNode();
206 if (!node
|| !node
->inDocument())
209 TreeScope
& treeScope
= isStyleElement(*node
) ? node
->treeScope() : *m_document
;
210 ASSERT(isStyleElement(*node
) || treeScope
== m_document
);
212 markTreeScopeDirty(treeScope
);
215 void StyleEngine::addStyleSheetCandidateNode(Node
* node
, bool createdByParser
)
217 if (!node
->inDocument() || document().isDetached())
220 TreeScope
& treeScope
= isStyleElement(*node
) ? node
->treeScope() : *m_document
;
221 ASSERT(isStyleElement(*node
) || treeScope
== m_document
);
222 ASSERT(!isXSLStyleSheet(*node
));
223 TreeScopeStyleSheetCollection
* collection
= ensureStyleSheetCollectionFor(treeScope
);
225 collection
->addStyleSheetCandidateNode(node
, createdByParser
);
227 markTreeScopeDirty(treeScope
);
228 if (treeScope
!= m_document
)
229 m_activeTreeScopes
.add(&treeScope
);
232 void StyleEngine::removeStyleSheetCandidateNode(Node
* node
)
234 removeStyleSheetCandidateNode(node
, *m_document
);
237 void StyleEngine::removeStyleSheetCandidateNode(Node
* node
, TreeScope
& treeScope
)
239 ASSERT(isStyleElement(*node
) || treeScope
== m_document
);
240 ASSERT(!isXSLStyleSheet(*node
));
242 TreeScopeStyleSheetCollection
* collection
= styleSheetCollectionFor(treeScope
);
243 // After detaching document, collection could be null. In the case,
244 // we should not update anything. Instead, just return.
247 collection
->removeStyleSheetCandidateNode(node
);
249 markTreeScopeDirty(treeScope
);
252 void StyleEngine::modifiedStyleSheetCandidateNode(Node
* node
)
254 if (!node
->inDocument())
257 TreeScope
& treeScope
= isStyleElement(*node
) ? node
->treeScope() : *m_document
;
258 ASSERT(isStyleElement(*node
) || treeScope
== m_document
);
259 markTreeScopeDirty(treeScope
);
262 bool StyleEngine::shouldUpdateDocumentStyleSheetCollection(StyleResolverUpdateMode updateMode
) const
264 return m_documentScopeDirty
|| updateMode
== FullStyleUpdate
;
267 bool StyleEngine::shouldUpdateShadowTreeStyleSheetCollection(StyleResolverUpdateMode updateMode
) const
269 return !m_dirtyTreeScopes
.isEmpty() || updateMode
== FullStyleUpdate
;
272 void StyleEngine::clearMediaQueryRuleSetOnTreeScopeStyleSheets(UnorderedTreeScopeSet
& treeScopes
)
274 for (TreeScope
* treeScope
: treeScopes
) {
275 ASSERT(treeScope
!= m_document
);
276 ShadowTreeStyleSheetCollection
* collection
= static_cast<ShadowTreeStyleSheetCollection
*>(styleSheetCollectionFor(*treeScope
));
278 collection
->clearMediaQueryRuleSetStyleSheets();
282 void StyleEngine::clearMediaQueryRuleSetStyleSheets()
284 documentStyleSheetCollection()->clearMediaQueryRuleSetStyleSheets();
285 clearMediaQueryRuleSetOnTreeScopeStyleSheets(m_activeTreeScopes
);
286 clearMediaQueryRuleSetOnTreeScopeStyleSheets(m_dirtyTreeScopes
);
289 void StyleEngine::updateStyleSheetsInImport(DocumentStyleSheetCollector
& parentCollector
)
292 WillBeHeapVector
<RefPtrWillBeMember
<StyleSheet
>> sheetsForList
;
293 ImportedDocumentStyleSheetCollector
subcollector(parentCollector
, sheetsForList
);
294 documentStyleSheetCollection()->collectStyleSheets(*this, subcollector
);
295 documentStyleSheetCollection()->swapSheetsForSheetList(sheetsForList
);
298 void StyleEngine::updateActiveStyleSheetsInShadow(StyleResolverUpdateMode updateMode
, TreeScope
* treeScope
, UnorderedTreeScopeSet
& treeScopesRemoved
)
300 ASSERT(treeScope
!= m_document
);
301 ShadowTreeStyleSheetCollection
* collection
= static_cast<ShadowTreeStyleSheetCollection
*>(styleSheetCollectionFor(*treeScope
));
303 collection
->updateActiveStyleSheets(*this, updateMode
);
304 if (!collection
->hasStyleSheetCandidateNodes()) {
305 treeScopesRemoved
.add(treeScope
);
306 // When removing TreeScope from ActiveTreeScopes,
307 // its resolver should be destroyed by invoking resetAuthorStyle.
308 ASSERT(!treeScope
->scopedStyleResolver());
312 void StyleEngine::updateActiveStyleSheets(StyleResolverUpdateMode updateMode
)
315 ASSERT(!document().inStyleRecalc());
317 if (!document().isActive())
320 if (shouldUpdateDocumentStyleSheetCollection(updateMode
))
321 documentStyleSheetCollection()->updateActiveStyleSheets(*this, updateMode
);
323 if (shouldUpdateShadowTreeStyleSheetCollection(updateMode
)) {
324 UnorderedTreeScopeSet treeScopesRemoved
;
326 if (updateMode
== FullStyleUpdate
) {
327 for (TreeScope
* treeScope
: m_activeTreeScopes
)
328 updateActiveStyleSheetsInShadow(updateMode
, treeScope
, treeScopesRemoved
);
330 for (TreeScope
* treeScope
: m_dirtyTreeScopes
)
331 updateActiveStyleSheetsInShadow(updateMode
, treeScope
, treeScopesRemoved
);
333 for (TreeScope
* treeScope
: treeScopesRemoved
)
334 m_activeTreeScopes
.remove(treeScope
);
337 InspectorInstrumentation::activeStyleSheetsUpdated(m_document
);
339 m_dirtyTreeScopes
.clear();
340 m_documentScopeDirty
= false;
343 const WillBeHeapVector
<RefPtrWillBeMember
<CSSStyleSheet
>> StyleEngine::activeStyleSheetsForInspector() const
345 if (m_activeTreeScopes
.isEmpty())
346 return documentStyleSheetCollection()->activeAuthorStyleSheets();
348 WillBeHeapVector
<RefPtrWillBeMember
<CSSStyleSheet
>> activeStyleSheets
;
350 activeStyleSheets
.appendVector(documentStyleSheetCollection()->activeAuthorStyleSheets());
351 for (TreeScope
* treeScope
: m_activeTreeScopes
) {
352 if (TreeScopeStyleSheetCollection
* collection
= m_styleSheetCollectionMap
.get(treeScope
))
353 activeStyleSheets
.appendVector(collection
->activeAuthorStyleSheets());
356 // FIXME: Inspector needs a vector which has all active stylesheets.
357 // However, creating such a large vector might cause performance regression.
358 // Need to implement some smarter solution.
359 return activeStyleSheets
;
362 void StyleEngine::didRemoveShadowRoot(ShadowRoot
* shadowRoot
)
364 m_styleSheetCollectionMap
.remove(shadowRoot
);
365 m_activeTreeScopes
.remove(shadowRoot
);
366 m_dirtyTreeScopes
.remove(shadowRoot
);
369 void StyleEngine::shadowRootRemovedFromDocument(ShadowRoot
* shadowRoot
)
371 if (StyleResolver
* styleResolver
= resolver()) {
372 styleResolver
->resetAuthorStyle(*shadowRoot
);
374 if (TreeScopeStyleSheetCollection
* collection
= styleSheetCollectionFor(*shadowRoot
))
375 styleResolver
->removePendingAuthorStyleSheets(collection
->activeAuthorStyleSheets());
377 m_styleSheetCollectionMap
.remove(shadowRoot
);
378 m_activeTreeScopes
.remove(shadowRoot
);
379 m_dirtyTreeScopes
.remove(shadowRoot
);
382 void StyleEngine::appendActiveAuthorStyleSheets()
386 m_resolver
->appendAuthorStyleSheets(documentStyleSheetCollection()->activeAuthorStyleSheets());
387 for (TreeScope
* treeScope
: m_activeTreeScopes
) {
388 if (TreeScopeStyleSheetCollection
* collection
= m_styleSheetCollectionMap
.get(treeScope
))
389 m_resolver
->appendAuthorStyleSheets(collection
->activeAuthorStyleSheets());
391 m_resolver
->finishAppendAuthorStyleSheets();
394 void StyleEngine::createResolver()
396 // It is a programming error to attempt to resolve style on a Document
397 // which is not in a frame. Code which hits this should have checked
398 // Document::isActive() before calling into code which could get here.
400 ASSERT(document().frame());
402 m_resolver
= adoptPtrWillBeNoop(new StyleResolver(*m_document
));
404 // A scoped style resolver for document will be created during
405 // appendActiveAuthorStyleSheets if needed.
406 appendActiveAuthorStyleSheets();
407 combineCSSFeatureFlags(m_resolver
->ensureUpdatedRuleFeatureSet());
410 void StyleEngine::clearResolver()
412 ASSERT(!document().inStyleRecalc());
413 ASSERT(isMaster() || !m_resolver
);
415 document().clearScopedStyleResolver();
416 // StyleEngine::shadowRootRemovedFromDocument removes not-in-document
417 // treescopes from activeTreeScopes. StyleEngine::didRemoveShadowRoot
418 // removes treescopes which are being destroyed from activeTreeScopes.
419 // So we need to clearScopedStyleResolver for treescopes which have been
420 // just removed from document. If document is destroyed before invoking
421 // updateActiveStyleSheets, the treescope has a scopedStyleResolver which
422 // has destroyed StyleSheetContents.
423 for (TreeScope
* treeScope
: m_activeTreeScopes
)
424 treeScope
->clearScopedStyleResolver();
429 void StyleEngine::clearMasterResolver()
431 if (Document
* master
= this->master())
432 master
->styleEngine().clearResolver();
435 unsigned StyleEngine::resolverAccessCount() const
437 return m_resolver
? m_resolver
->accessCount() : 0;
440 void StyleEngine::didDetach()
445 bool StyleEngine::shouldClearResolver() const
447 return !m_didCalculateResolver
&& !haveStylesheetsLoaded();
450 void StyleEngine::resolverChanged(StyleResolverUpdateMode mode
)
453 if (Document
* master
= this->master())
454 master
->styleResolverChanged(mode
);
458 // Don't bother updating, since we haven't loaded all our style info yet
459 // and haven't calculated the style selector for the first time.
460 if (!document().isActive() || shouldClearResolver()) {
465 m_didCalculateResolver
= true;
466 updateActiveStyleSheets(mode
);
469 void StyleEngine::clearFontCache()
472 m_fontSelector
->fontFaceCache()->clearCSSConnected();
474 m_resolver
->invalidateMatchedPropertiesCache();
477 void StyleEngine::updateGenericFontFamilySettings()
479 // FIXME: we should not update generic font family settings when
480 // document is inactive.
481 ASSERT(document().isActive());
486 m_fontSelector
->updateGenericFontFamilySettings(*m_document
);
488 m_resolver
->invalidateMatchedPropertiesCache();
491 void StyleEngine::removeFontFaceRules(const WillBeHeapVector
<RawPtrWillBeMember
<const StyleRuleFontFace
>>& fontFaceRules
)
496 FontFaceCache
* cache
= m_fontSelector
->fontFaceCache();
497 for (unsigned i
= 0; i
< fontFaceRules
.size(); ++i
)
498 cache
->remove(fontFaceRules
[i
]);
500 m_resolver
->invalidateMatchedPropertiesCache();
503 void StyleEngine::markTreeScopeDirty(TreeScope
& scope
)
505 if (scope
== m_document
) {
510 ASSERT(m_styleSheetCollectionMap
.contains(&scope
));
511 m_dirtyTreeScopes
.add(&scope
);
514 void StyleEngine::markDocumentDirty()
516 m_documentScopeDirty
= true;
517 if (document().importLoader())
518 document().importsController()->master()->styleEngine().markDocumentDirty();
521 static bool isCacheableForStyleElement(const StyleSheetContents
& contents
)
523 // FIXME: Support copying import rules.
524 if (!contents
.importRules().isEmpty())
526 // Until import rules are supported in cached sheets it's not possible for loading to fail.
527 ASSERT(!contents
.didLoadErrorOccur());
528 // It is not the original sheet anymore.
529 if (contents
.isMutable())
531 if (!contents
.hasSyntacticallyValidCSSHeader())
536 PassRefPtrWillBeRawPtr
<CSSStyleSheet
> StyleEngine::createSheet(Element
* e
, const String
& text
, TextPosition startPosition
)
538 RefPtrWillBeRawPtr
<CSSStyleSheet
> styleSheet
= nullptr;
540 e
->document().styleEngine().addPendingSheet();
542 AtomicString
textContent(text
);
544 WillBeHeapHashMap
<AtomicString
, RawPtrWillBeMember
<StyleSheetContents
>>::AddResult result
= m_textToSheetCache
.add(textContent
, nullptr);
545 if (result
.isNewEntry
|| !result
.storedValue
->value
) {
546 styleSheet
= StyleEngine::parseSheet(e
, text
, startPosition
);
547 if (result
.isNewEntry
&& isCacheableForStyleElement(*styleSheet
->contents())) {
548 result
.storedValue
->value
= styleSheet
->contents();
549 m_sheetToTextCache
.add(styleSheet
->contents(), textContent
);
552 StyleSheetContents
* contents
= result
.storedValue
->value
;
554 ASSERT(isCacheableForStyleElement(*contents
));
555 ASSERT(contents
->singleOwnerDocument() == e
->document());
556 styleSheet
= CSSStyleSheet::createInline(contents
, e
, startPosition
);
560 styleSheet
->setTitle(e
->title());
564 PassRefPtrWillBeRawPtr
<CSSStyleSheet
> StyleEngine::parseSheet(Element
* e
, const String
& text
, TextPosition startPosition
)
566 RefPtrWillBeRawPtr
<CSSStyleSheet
> styleSheet
= nullptr;
567 styleSheet
= CSSStyleSheet::createInline(e
, KURL(), startPosition
, e
->document().characterSet());
568 styleSheet
->contents()->parseStringAtPosition(text
, startPosition
);
572 void StyleEngine::removeSheet(StyleSheetContents
* contents
)
574 WillBeHeapHashMap
<RawPtrWillBeMember
<StyleSheetContents
>, AtomicString
>::iterator it
= m_sheetToTextCache
.find(contents
);
575 if (it
== m_sheetToTextCache
.end())
578 m_textToSheetCache
.remove(it
->value
);
579 m_sheetToTextCache
.remove(contents
);
582 void StyleEngine::collectScopedStyleFeaturesTo(RuleFeatureSet
& features
) const
584 HashSet
<const StyleSheetContents
*> visitedSharedStyleSheetContents
;
585 if (document().scopedStyleResolver())
586 document().scopedStyleResolver()->collectFeaturesTo(features
, visitedSharedStyleSheetContents
);
587 for (TreeScope
* treeScope
: m_activeTreeScopes
) {
588 // When creating StyleResolver, dirty treescopes might not be processed.
589 // So some active treescopes might not have a scoped style resolver.
590 // In this case, we should skip collectFeatures for the treescopes without
591 // scoped style resolvers. When invoking updateActiveStyleSheets,
592 // the treescope's features will be processed.
593 if (ScopedStyleResolver
* resolver
= treeScope
->scopedStyleResolver())
594 resolver
->collectFeaturesTo(features
, visitedSharedStyleSheetContents
);
598 void StyleEngine::fontsNeedUpdate(CSSFontSelector
*)
600 if (!document().isActive())
604 m_resolver
->invalidateMatchedPropertiesCache();
605 document().setNeedsStyleRecalc(SubtreeStyleChange
, StyleChangeReasonForTracing::create(StyleChangeReason::Fonts
));
608 void StyleEngine::setFontSelector(PassRefPtrWillBeRawPtr
<CSSFontSelector
> fontSelector
)
612 m_fontSelector
->unregisterForInvalidationCallbacks(this);
614 m_fontSelector
= fontSelector
;
616 m_fontSelector
->registerForInvalidationCallbacks(this);
619 void StyleEngine::platformColorsChanged()
622 m_resolver
->invalidateMatchedPropertiesCache();
623 document().setNeedsStyleRecalc(SubtreeStyleChange
, StyleChangeReasonForTracing::create(StyleChangeReason::PlatformColorChange
));
626 void StyleEngine::classChangedForElement(const SpaceSplitString
& changedClasses
, Element
& element
)
629 InvalidationSetVector invalidationSets
;
630 unsigned changedSize
= changedClasses
.size();
631 RuleFeatureSet
& ruleFeatureSet
= ensureResolver().ensureUpdatedRuleFeatureSet();
632 for (unsigned i
= 0; i
< changedSize
; ++i
)
633 ruleFeatureSet
.collectInvalidationSetsForClass(invalidationSets
, element
, changedClasses
[i
]);
634 scheduleInvalidationSetsForElement(invalidationSets
, element
);
637 void StyleEngine::classChangedForElement(const SpaceSplitString
& oldClasses
, const SpaceSplitString
& newClasses
, Element
& element
)
640 InvalidationSetVector invalidationSets
;
641 if (!oldClasses
.size()) {
642 classChangedForElement(newClasses
, element
);
646 // Class vectors tend to be very short. This is faster than using a hash table.
647 BitVector remainingClassBits
;
648 remainingClassBits
.ensureSize(oldClasses
.size());
650 RuleFeatureSet
& ruleFeatureSet
= ensureResolver().ensureUpdatedRuleFeatureSet();
652 for (unsigned i
= 0; i
< newClasses
.size(); ++i
) {
654 for (unsigned j
= 0; j
< oldClasses
.size(); ++j
) {
655 if (newClasses
[i
] == oldClasses
[j
]) {
656 // Mark each class that is still in the newClasses so we can skip doing
657 // an n^2 search below when looking for removals. We can't break from
658 // this loop early since a class can appear more than once.
659 remainingClassBits
.quickSet(j
);
665 ruleFeatureSet
.collectInvalidationSetsForClass(invalidationSets
, element
, newClasses
[i
]);
668 for (unsigned i
= 0; i
< oldClasses
.size(); ++i
) {
669 if (remainingClassBits
.quickGet(i
))
671 // Class was removed.
672 ruleFeatureSet
.collectInvalidationSetsForClass(invalidationSets
, element
, oldClasses
[i
]);
675 scheduleInvalidationSetsForElement(invalidationSets
, element
);
678 void StyleEngine::attributeChangedForElement(const QualifiedName
& attributeName
, Element
& element
)
681 InvalidationSetVector invalidationSets
;
682 ensureResolver().ensureUpdatedRuleFeatureSet().collectInvalidationSetsForAttribute(invalidationSets
, element
, attributeName
);
683 scheduleInvalidationSetsForElement(invalidationSets
, element
);
686 void StyleEngine::idChangedForElement(const AtomicString
& oldId
, const AtomicString
& newId
, Element
& element
)
689 InvalidationSetVector invalidationSets
;
690 RuleFeatureSet
& ruleFeatureSet
= ensureResolver().ensureUpdatedRuleFeatureSet();
691 if (!oldId
.isEmpty())
692 ruleFeatureSet
.collectInvalidationSetsForId(invalidationSets
, element
, oldId
);
693 if (!newId
.isEmpty())
694 ruleFeatureSet
.collectInvalidationSetsForId(invalidationSets
, element
, newId
);
695 scheduleInvalidationSetsForElement(invalidationSets
, element
);
698 void StyleEngine::pseudoStateChangedForElement(CSSSelector::PseudoType pseudoType
, Element
& element
)
701 InvalidationSetVector invalidationSets
;
702 ensureResolver().ensureUpdatedRuleFeatureSet().collectInvalidationSetsForPseudoClass(invalidationSets
, element
, pseudoType
);
703 scheduleInvalidationSetsForElement(invalidationSets
, element
);
706 void StyleEngine::scheduleInvalidationSetsForElement(const InvalidationSetVector
& invalidationSets
, Element
& element
)
708 for (auto invalidationSet
: invalidationSets
)
709 m_styleInvalidator
.scheduleInvalidation(invalidationSet
, element
);
712 DEFINE_TRACE(StyleEngine
)
715 visitor
->trace(m_document
);
716 visitor
->trace(m_authorStyleSheets
);
717 visitor
->trace(m_documentStyleSheetCollection
);
718 visitor
->trace(m_styleSheetCollectionMap
);
719 visitor
->trace(m_resolver
);
720 visitor
->trace(m_styleInvalidator
);
721 visitor
->trace(m_dirtyTreeScopes
);
722 visitor
->trace(m_activeTreeScopes
);
723 visitor
->trace(m_fontSelector
);
724 visitor
->trace(m_textToSheetCache
);
725 visitor
->trace(m_sheetToTextCache
);
727 CSSFontSelectorClient::trace(visitor
);