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