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