Move rem handling out of CSSParserValues
[chromium-blink-merge.git] / third_party / WebKit / Source / core / dom / StyleEngine.cpp
blobc2d1b693dde58a47cebebb6f385e8147fbb8d2a7
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"
50 namespace blink {
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)
71 if (m_fontSelector)
72 m_fontSelector->registerForInvalidationCallbacks(this);
75 StyleEngine::~StyleEngine()
79 static bool isStyleElement(Node& node)
81 return isHTMLStyleElement(node) || isSVGStyleElement(node);
84 #if !ENABLE(OILPAN)
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();
93 if (m_fontSelector) {
94 m_fontSelector->clearDocument();
95 m_fontSelector->unregisterForInvalidationCallbacks(this);
98 // Decrement reference counts for things we could be keeping alive.
99 m_fontSelector.clear();
100 m_resolver.clear();
101 m_styleSheetCollectionMap.clear();
102 m_activeTreeScopes.clear();
104 #endif
106 inline Document* StyleEngine::master()
108 if (isMaster())
109 return m_document;
110 HTMLImportsController* import = document().importsController();
111 if (!import) // Document::import() can return null while executing its destructor.
112 return 0;
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())
134 return 0;
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());
172 markDocumentDirty();
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)
193 return;
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)
202 if (!sheet)
203 return;
205 Node* node = sheet->ownerNode();
206 if (!node || !node->inDocument())
207 return;
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())
218 return;
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);
224 ASSERT(collection);
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.
245 if (!collection)
246 return;
247 collection->removeStyleSheetCandidateNode(node);
249 markTreeScopeDirty(treeScope);
252 void StyleEngine::modifiedStyleSheetCandidateNode(Node* node)
254 if (!node->inDocument())
255 return;
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));
277 ASSERT(collection);
278 collection->clearMediaQueryRuleSetStyleSheets();
282 void StyleEngine::clearMediaQueryRuleSetStyleSheets()
284 documentStyleSheetCollection()->clearMediaQueryRuleSetStyleSheets();
285 clearMediaQueryRuleSetOnTreeScopeStyleSheets(m_activeTreeScopes);
286 clearMediaQueryRuleSetOnTreeScopeStyleSheets(m_dirtyTreeScopes);
289 void StyleEngine::updateStyleSheetsInImport(DocumentStyleSheetCollector& parentCollector)
291 ASSERT(!isMaster());
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));
302 ASSERT(collection);
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)
314 ASSERT(isMaster());
315 ASSERT(!document().inStyleRecalc());
317 if (!document().isActive())
318 return;
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);
329 } else {
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()
384 ASSERT(isMaster());
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();
426 m_resolver.clear();
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()
442 clearResolver();
445 bool StyleEngine::shouldClearResolver() const
447 return !m_didCalculateResolver && !haveStylesheetsLoaded();
450 void StyleEngine::resolverChanged(StyleResolverUpdateMode mode)
452 if (!isMaster()) {
453 if (Document* master = this->master())
454 master->styleResolverChanged(mode);
455 return;
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()) {
461 clearResolver();
462 return;
465 m_didCalculateResolver = true;
466 updateActiveStyleSheets(mode);
469 void StyleEngine::clearFontCache()
471 if (m_fontSelector)
472 m_fontSelector->fontFaceCache()->clearCSSConnected();
473 if (m_resolver)
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());
483 if (!m_fontSelector)
484 return;
486 m_fontSelector->updateGenericFontFamilySettings(*m_document);
487 if (m_resolver)
488 m_resolver->invalidateMatchedPropertiesCache();
491 void StyleEngine::removeFontFaceRules(const WillBeHeapVector<RawPtrWillBeMember<const StyleRuleFontFace>>& fontFaceRules)
493 if (!m_fontSelector)
494 return;
496 FontFaceCache* cache = m_fontSelector->fontFaceCache();
497 for (unsigned i = 0; i < fontFaceRules.size(); ++i)
498 cache->remove(fontFaceRules[i]);
499 if (m_resolver)
500 m_resolver->invalidateMatchedPropertiesCache();
503 void StyleEngine::markTreeScopeDirty(TreeScope& scope)
505 if (scope == m_document) {
506 markDocumentDirty();
507 return;
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())
525 return false;
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())
530 return false;
531 if (!contents.hasSyntacticallyValidCSSHeader())
532 return false;
533 return true;
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);
551 } else {
552 StyleSheetContents* contents = result.storedValue->value;
553 ASSERT(contents);
554 ASSERT(isCacheableForStyleElement(*contents));
555 ASSERT(contents->singleOwnerDocument() == e->document());
556 styleSheet = CSSStyleSheet::createInline(contents, e, startPosition);
559 ASSERT(styleSheet);
560 styleSheet->setTitle(e->title());
561 return styleSheet;
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);
569 return styleSheet;
572 void StyleEngine::removeSheet(StyleSheetContents* contents)
574 WillBeHeapHashMap<RawPtrWillBeMember<StyleSheetContents>, AtomicString>::iterator it = m_sheetToTextCache.find(contents);
575 if (it == m_sheetToTextCache.end())
576 return;
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())
601 return;
603 if (m_resolver)
604 m_resolver->invalidateMatchedPropertiesCache();
605 document().setNeedsStyleRecalc(SubtreeStyleChange, StyleChangeReasonForTracing::create(StyleChangeReason::Fonts));
608 void StyleEngine::setFontSelector(PassRefPtrWillBeRawPtr<CSSFontSelector> fontSelector)
610 #if !ENABLE(OILPAN)
611 if (m_fontSelector)
612 m_fontSelector->unregisterForInvalidationCallbacks(this);
613 #endif
614 m_fontSelector = fontSelector;
615 if (m_fontSelector)
616 m_fontSelector->registerForInvalidationCallbacks(this);
619 void StyleEngine::platformColorsChanged()
621 if (m_resolver)
622 m_resolver->invalidateMatchedPropertiesCache();
623 document().setNeedsStyleRecalc(SubtreeStyleChange, StyleChangeReasonForTracing::create(StyleChangeReason::PlatformColorChange));
626 void StyleEngine::classChangedForElement(const SpaceSplitString& changedClasses, Element& element)
628 ASSERT(isMaster());
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)
639 ASSERT(isMaster());
640 InvalidationSetVector invalidationSets;
641 if (!oldClasses.size()) {
642 classChangedForElement(newClasses, element);
643 return;
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) {
653 bool found = false;
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);
660 found = true;
663 // Class was added.
664 if (!found)
665 ruleFeatureSet.collectInvalidationSetsForClass(invalidationSets, element, newClasses[i]);
668 for (unsigned i = 0; i < oldClasses.size(); ++i) {
669 if (remainingClassBits.quickGet(i))
670 continue;
671 // Class was removed.
672 ruleFeatureSet.collectInvalidationSetsForClass(invalidationSets, element, oldClasses[i]);
675 scheduleInvalidationSetsForElement(invalidationSets, element);
678 void StyleEngine::attributeChangedForElement(const QualifiedName& attributeName, Element& element)
680 ASSERT(isMaster());
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)
688 ASSERT(isMaster());
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)
700 ASSERT(isMaster());
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)
714 #if ENABLE(OILPAN)
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);
726 #endif
727 CSSFontSelectorClient::trace(visitor);