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-2009, 2011-2012, 2015-2017 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 "StyleScope.h"
30
31#include "CSSFontSelector.h"
32#include "CSSStyleSheet.h"
33#include "Element.h"
34#include "ElementChildIterator.h"
35#include "ExtensionStyleSheets.h"
36#include "HTMLHeadElement.h"
37#include "HTMLIFrameElement.h"
38#include "HTMLLinkElement.h"
39#include "HTMLSlotElement.h"
40#include "HTMLStyleElement.h"
41#include "InspectorInstrumentation.h"
42#include "ProcessingInstruction.h"
43#include "SVGStyleElement.h"
44#include "Settings.h"
45#include "ShadowRoot.h"
46#include "StyleInvalidator.h"
47#include "StyleResolver.h"
48#include "StyleSheetContents.h"
49#include "StyleSheetList.h"
50#include "UserContentController.h"
51#include "UserContentURLPattern.h"
52#include "UserStyleSheet.h"
53#include <wtf/SetForScope.h>
54
55namespace WebCore {
56
57using namespace HTMLNames;
58
59namespace Style {
60
61Scope::Scope(Document& document)
62 : m_document(document)
63 , m_pendingUpdateTimer(*this, &Scope::pendingUpdateTimerFired)
64{
65}
66
67Scope::Scope(ShadowRoot& shadowRoot)
68 : m_document(shadowRoot.documentScope())
69 , m_shadowRoot(&shadowRoot)
70 , m_pendingUpdateTimer(*this, &Scope::pendingUpdateTimerFired)
71{
72}
73
74Scope::~Scope()
75{
76 ASSERT(!hasPendingSheets());
77}
78
79bool Scope::shouldUseSharedUserAgentShadowTreeStyleResolver() const
80{
81 if (!m_shadowRoot)
82 return false;
83 if (m_shadowRoot->mode() != ShadowRootMode::UserAgent)
84 return false;
85 // If we have stylesheets in the user agent shadow tree use per-scope resolver.
86 if (!m_styleSheetCandidateNodes.isEmpty())
87 return false;
88 return true;
89}
90
91StyleResolver& Scope::resolver()
92{
93 if (shouldUseSharedUserAgentShadowTreeStyleResolver())
94 return m_document.userAgentShadowTreeStyleResolver();
95
96 if (!m_resolver) {
97 SetForScope<bool> isUpdatingStyleResolver { m_isUpdatingStyleResolver, true };
98
99 m_resolver = std::make_unique<StyleResolver>(m_document);
100
101 if (!m_shadowRoot) {
102 m_document.fontSelector().buildStarted();
103 m_resolver->ruleSets().initializeUserStyle();
104 } else {
105 m_resolver->ruleSets().setIsForShadowScope();
106 m_resolver->ruleSets().setUsesSharedUserStyle(m_shadowRoot->mode() != ShadowRootMode::UserAgent);
107 }
108
109 m_resolver->addCurrentSVGFontFaceRules();
110 m_resolver->appendAuthorStyleSheets(m_activeStyleSheets);
111
112 if (!m_shadowRoot)
113 m_document.fontSelector().buildCompleted();
114 }
115 ASSERT(!m_shadowRoot || &m_document == &m_shadowRoot->document());
116 ASSERT(&m_resolver->document() == &m_document);
117 return *m_resolver;
118}
119
120StyleResolver* Scope::resolverIfExists()
121{
122 if (shouldUseSharedUserAgentShadowTreeStyleResolver())
123 return &m_document.userAgentShadowTreeStyleResolver();
124
125 return m_resolver.get();
126}
127
128void Scope::clearResolver()
129{
130 m_resolver = nullptr;
131
132 if (!m_shadowRoot)
133 m_document.didClearStyleResolver();
134}
135
136void Scope::releaseMemory()
137{
138 if (!m_shadowRoot) {
139 for (auto* descendantShadowRoot : m_document.inDocumentShadowRoots())
140 descendantShadowRoot->styleScope().releaseMemory();
141 }
142
143#if ENABLE(CSS_SELECTOR_JIT)
144 for (auto& sheet : m_activeStyleSheets) {
145 sheet->contents().traverseRules([] (const StyleRuleBase& rule) {
146 if (is<StyleRule>(rule))
147 downcast<StyleRule>(rule).releaseCompiledSelectors();
148 return false;
149 });
150 }
151#endif
152 clearResolver();
153}
154
155Scope& Scope::forNode(Node& node)
156{
157 ASSERT(node.isConnected());
158 auto* shadowRoot = node.containingShadowRoot();
159 if (shadowRoot)
160 return shadowRoot->styleScope();
161 return node.document().styleScope();
162}
163
164Scope* Scope::forOrdinal(Element& element, ScopeOrdinal ordinal)
165{
166 switch (ordinal) {
167 case ScopeOrdinal::Element:
168 return &forNode(element);
169 case ScopeOrdinal::ContainingHost: {
170 auto* containingShadowRoot = element.containingShadowRoot();
171 if (!containingShadowRoot)
172 return nullptr;
173 return &forNode(*containingShadowRoot->host());
174 }
175 case ScopeOrdinal::Shadow: {
176 auto* shadowRoot = element.shadowRoot();
177 if (!shadowRoot)
178 return nullptr;
179 return &shadowRoot->styleScope();
180 }
181 default: {
182 ASSERT(ordinal >= ScopeOrdinal::FirstSlot);
183 auto slotIndex = ScopeOrdinal::FirstSlot;
184 for (auto* slot = element.assignedSlot(); slot; slot = slot->assignedSlot(), ++slotIndex) {
185 if (slotIndex == ordinal)
186 return &forNode(*slot);
187 }
188 return nullptr;
189 }
190 }
191}
192
193void Scope::setPreferredStylesheetSetName(const String& name)
194{
195 if (m_preferredStylesheetSetName == name)
196 return;
197 m_preferredStylesheetSetName = name;
198 didChangeActiveStyleSheetCandidates();
199}
200
201void Scope::addPendingSheet(const Element& element)
202{
203 ASSERT(!hasPendingSheet(element));
204
205 bool isInHead = ancestorsOfType<HTMLHeadElement>(element).first();
206 if (isInHead)
207 m_elementsInHeadWithPendingSheets.add(&element);
208 else
209 m_elementsInBodyWithPendingSheets.add(&element);
210}
211
212// This method is called whenever a top-level stylesheet has finished loading.
213void Scope::removePendingSheet(const Element& element)
214{
215 ASSERT(hasPendingSheet(element));
216
217 if (!m_elementsInHeadWithPendingSheets.remove(&element))
218 m_elementsInBodyWithPendingSheets.remove(&element);
219
220 didRemovePendingStylesheet();
221}
222
223void Scope::addPendingSheet(const ProcessingInstruction& processingInstruction)
224{
225 ASSERT(!m_processingInstructionsWithPendingSheets.contains(&processingInstruction));
226
227 m_processingInstructionsWithPendingSheets.add(&processingInstruction);
228}
229
230void Scope::removePendingSheet(const ProcessingInstruction& processingInstruction)
231{
232 ASSERT(m_processingInstructionsWithPendingSheets.contains(&processingInstruction));
233
234 m_processingInstructionsWithPendingSheets.remove(&processingInstruction);
235
236 didRemovePendingStylesheet();
237}
238
239void Scope::didRemovePendingStylesheet()
240{
241 if (hasPendingSheets())
242 return;
243
244 didChangeActiveStyleSheetCandidates();
245
246 if (!m_shadowRoot)
247 m_document.didRemoveAllPendingStylesheet();
248}
249
250bool Scope::hasPendingSheet(const Element& element) const
251{
252 return m_elementsInHeadWithPendingSheets.contains(&element) || hasPendingSheetInBody(element);
253}
254
255bool Scope::hasPendingSheetInBody(const Element& element) const
256{
257 return m_elementsInBodyWithPendingSheets.contains(&element);
258}
259
260bool Scope::hasPendingSheet(const ProcessingInstruction& processingInstruction) const
261{
262 return m_processingInstructionsWithPendingSheets.contains(&processingInstruction);
263}
264
265void Scope::addStyleSheetCandidateNode(Node& node, bool createdByParser)
266{
267 if (!node.isConnected())
268 return;
269
270 // Until the <body> exists, we have no choice but to compare document positions,
271 // since styles outside of the body and head continue to be shunted into the head
272 // (and thus can shift to end up before dynamically added DOM content that is also
273 // outside the body).
274 if ((createdByParser && m_document.bodyOrFrameset()) || m_styleSheetCandidateNodes.isEmpty()) {
275 m_styleSheetCandidateNodes.add(&node);
276 return;
277 }
278
279 // Determine an appropriate insertion point.
280 auto begin = m_styleSheetCandidateNodes.begin();
281 auto end = m_styleSheetCandidateNodes.end();
282 auto it = end;
283 Node* followingNode = nullptr;
284 do {
285 --it;
286 Node* n = *it;
287 unsigned short position = n->compareDocumentPosition(node);
288 if (position == Node::DOCUMENT_POSITION_FOLLOWING) {
289 m_styleSheetCandidateNodes.insertBefore(followingNode, &node);
290 return;
291 }
292 followingNode = n;
293 } while (it != begin);
294
295 m_styleSheetCandidateNodes.insertBefore(followingNode, &node);
296}
297
298void Scope::removeStyleSheetCandidateNode(Node& node)
299{
300 if (m_styleSheetCandidateNodes.remove(&node))
301 didChangeActiveStyleSheetCandidates();
302}
303
304#if ENABLE(XSLT)
305// FIXME: <https://webkit.org/b/178830> Remove XSLT relaed code from Style::Scope.
306Vector<Ref<ProcessingInstruction>> Scope::collectXSLTransforms()
307{
308 Vector<Ref<ProcessingInstruction>> processingInstructions;
309 for (auto& node : m_styleSheetCandidateNodes) {
310 if (is<ProcessingInstruction>(*node) && downcast<ProcessingInstruction>(*node).isXSL())
311 processingInstructions.append(downcast<ProcessingInstruction>(*node));
312 }
313 return processingInstructions;
314}
315#endif
316
317void Scope::collectActiveStyleSheets(Vector<RefPtr<StyleSheet>>& sheets)
318{
319 if (!m_document.settings().authorAndUserStylesEnabled())
320 return;
321
322 for (auto& node : m_styleSheetCandidateNodes) {
323 RefPtr<StyleSheet> sheet;
324 if (is<ProcessingInstruction>(*node)) {
325 if (!downcast<ProcessingInstruction>(*node).isCSS())
326 continue;
327 // We don't support linking to embedded CSS stylesheets, see <https://bugs.webkit.org/show_bug.cgi?id=49281> for discussion.
328 sheet = downcast<ProcessingInstruction>(*node).sheet();
329 } else if (is<HTMLLinkElement>(*node) || is<HTMLStyleElement>(*node) || is<SVGStyleElement>(*node)) {
330 Element& element = downcast<Element>(*node);
331 AtomicString title = element.isInShadowTree() ? nullAtom() : element.attributeWithoutSynchronization(titleAttr);
332 bool enabledViaScript = false;
333 if (is<HTMLLinkElement>(element)) {
334 // <LINK> element
335 HTMLLinkElement& linkElement = downcast<HTMLLinkElement>(element);
336 if (linkElement.isDisabled())
337 continue;
338 enabledViaScript = linkElement.isEnabledViaScript();
339 if (linkElement.styleSheetIsLoading()) {
340 // it is loading but we should still decide which style sheet set to use
341 if (!enabledViaScript && !title.isEmpty() && m_preferredStylesheetSetName.isEmpty()) {
342 if (!linkElement.attributeWithoutSynchronization(relAttr).contains("alternate"))
343 m_preferredStylesheetSetName = title;
344 }
345 continue;
346 }
347 if (!linkElement.sheet())
348 title = nullAtom();
349 }
350 // Get the current preferred styleset. This is the
351 // set of sheets that will be enabled.
352 if (is<SVGStyleElement>(element))
353 sheet = downcast<SVGStyleElement>(element).sheet();
354 else if (is<HTMLLinkElement>(element))
355 sheet = downcast<HTMLLinkElement>(element).sheet();
356 else
357 sheet = downcast<HTMLStyleElement>(element).sheet();
358 // Check to see if this sheet belongs to a styleset
359 // (thus making it PREFERRED or ALTERNATE rather than
360 // PERSISTENT).
361 auto& rel = element.attributeWithoutSynchronization(relAttr);
362 if (!enabledViaScript && !title.isEmpty()) {
363 // Yes, we have a title.
364 if (m_preferredStylesheetSetName.isEmpty()) {
365 // No preferred set has been established. If
366 // we are NOT an alternate sheet, then establish
367 // us as the preferred set. Otherwise, just ignore
368 // this sheet.
369 if (is<HTMLStyleElement>(element) || !rel.contains("alternate"))
370 m_preferredStylesheetSetName = title;
371 }
372 if (title != m_preferredStylesheetSetName)
373 sheet = nullptr;
374 }
375
376 if (rel.contains("alternate") && title.isEmpty())
377 sheet = nullptr;
378 }
379 if (sheet)
380 sheets.append(WTFMove(sheet));
381 }
382}
383
384Scope::StyleResolverUpdateType Scope::analyzeStyleSheetChange(const Vector<RefPtr<CSSStyleSheet>>& newStylesheets, bool& requiresFullStyleRecalc)
385{
386 requiresFullStyleRecalc = true;
387
388 unsigned newStylesheetCount = newStylesheets.size();
389
390 if (!resolverIfExists())
391 return Reconstruct;
392
393 auto& styleResolver = *resolverIfExists();
394
395 // Find out which stylesheets are new.
396 unsigned oldStylesheetCount = m_activeStyleSheets.size();
397 if (newStylesheetCount < oldStylesheetCount)
398 return Reconstruct;
399
400 Vector<StyleSheetContents*> addedSheets;
401 unsigned newIndex = 0;
402 for (unsigned oldIndex = 0; oldIndex < oldStylesheetCount; ++oldIndex) {
403 if (newIndex >= newStylesheetCount)
404 return Reconstruct;
405 while (m_activeStyleSheets[oldIndex] != newStylesheets[newIndex]) {
406 addedSheets.append(&newStylesheets[newIndex]->contents());
407 ++newIndex;
408 if (newIndex == newStylesheetCount)
409 return Reconstruct;
410 }
411 ++newIndex;
412 }
413 bool hasInsertions = !addedSheets.isEmpty();
414 while (newIndex < newStylesheetCount) {
415 addedSheets.append(&newStylesheets[newIndex]->contents());
416 ++newIndex;
417 }
418 // If all new sheets were added at the end of the list we can just add them to existing StyleResolver.
419 // If there were insertions we need to re-add all the stylesheets so rules are ordered correctly.
420 auto styleResolverUpdateType = hasInsertions ? Reset : Additive;
421
422 // If we are already parsing the body and so may have significant amount of elements, put some effort into trying to avoid style recalcs.
423 if (!m_document.bodyOrFrameset() || m_document.hasNodesWithNonFinalStyle() || m_document.hasNodesWithMissingStyle())
424 return styleResolverUpdateType;
425
426 Invalidator invalidator(addedSheets, styleResolver.mediaQueryEvaluator());
427 if (invalidator.dirtiesAllStyle())
428 return styleResolverUpdateType;
429
430 if (m_shadowRoot)
431 invalidator.invalidateStyle(*m_shadowRoot);
432 else
433 invalidator.invalidateStyle(m_document);
434
435 requiresFullStyleRecalc = false;
436
437 return styleResolverUpdateType;
438}
439
440static void filterEnabledNonemptyCSSStyleSheets(Vector<RefPtr<CSSStyleSheet>>& result, const Vector<RefPtr<StyleSheet>>& sheets)
441{
442 for (auto& sheet : sheets) {
443 if (!is<CSSStyleSheet>(*sheet))
444 continue;
445 CSSStyleSheet& styleSheet = downcast<CSSStyleSheet>(*sheet);
446 if (styleSheet.isLoading())
447 continue;
448 if (styleSheet.disabled())
449 continue;
450 if (!styleSheet.length())
451 continue;
452 result.append(&styleSheet);
453 }
454}
455
456static void invalidateHostAndSlottedStyleIfNeeded(ShadowRoot& shadowRoot, StyleResolver& resolver)
457{
458 auto& host = *shadowRoot.host();
459 if (!resolver.ruleSets().authorStyle().hostPseudoClassRules().isEmpty())
460 host.invalidateStyle();
461
462 if (!resolver.ruleSets().authorStyle().slottedPseudoElementRules().isEmpty()) {
463 for (auto& shadowChild : childrenOfType<Element>(host))
464 shadowChild.invalidateStyle();
465 }
466}
467
468void Scope::updateActiveStyleSheets(UpdateType updateType)
469{
470 ASSERT(!m_pendingUpdate);
471
472 if (!m_document.hasLivingRenderTree())
473 return;
474
475 if (m_document.inStyleRecalc() || m_document.inRenderTreeUpdate()) {
476 // Protect against deleting style resolver in the middle of a style resolution.
477 // Crash stacks indicate we can get here when a resource load fails synchronously (for example due to content blocking).
478 // FIXME: These kind of cases should be eliminated and this path replaced by an assert.
479 m_pendingUpdate = UpdateType::ContentsOrInterpretation;
480 m_document.scheduleFullStyleRebuild();
481 return;
482 }
483
484 Vector<RefPtr<StyleSheet>> activeStyleSheets;
485 collectActiveStyleSheets(activeStyleSheets);
486
487 Vector<RefPtr<CSSStyleSheet>> activeCSSStyleSheets;
488 activeCSSStyleSheets.appendVector(m_document.extensionStyleSheets().injectedAuthorStyleSheets());
489 activeCSSStyleSheets.appendVector(m_document.extensionStyleSheets().authorStyleSheetsForTesting());
490 filterEnabledNonemptyCSSStyleSheets(activeCSSStyleSheets, activeStyleSheets);
491
492 bool requiresFullStyleRecalc = true;
493 StyleResolverUpdateType styleResolverUpdateType = Reconstruct;
494 if (updateType == UpdateType::ActiveSet)
495 styleResolverUpdateType = analyzeStyleSheetChange(activeCSSStyleSheets, requiresFullStyleRecalc);
496
497 updateStyleResolver(activeCSSStyleSheets, styleResolverUpdateType);
498
499 m_weakCopyOfActiveStyleSheetListForFastLookup = nullptr;
500 m_activeStyleSheets.swap(activeCSSStyleSheets);
501 m_styleSheetsForStyleSheetList.swap(activeStyleSheets);
502
503 InspectorInstrumentation::activeStyleSheetsUpdated(m_document);
504
505 for (const auto& sheet : m_activeStyleSheets) {
506 if (sheet->contents().usesStyleBasedEditability())
507 m_usesStyleBasedEditability = true;
508 }
509
510 // FIXME: Move this code somewhere else.
511 if (requiresFullStyleRecalc) {
512 if (m_shadowRoot) {
513 for (auto& shadowChild : childrenOfType<Element>(*m_shadowRoot))
514 shadowChild.invalidateStyleForSubtree();
515 invalidateHostAndSlottedStyleIfNeeded(*m_shadowRoot, resolver());
516 } else
517 m_document.scheduleFullStyleRebuild();
518 }
519}
520
521void Scope::updateStyleResolver(Vector<RefPtr<CSSStyleSheet>>& activeStyleSheets, StyleResolverUpdateType updateType)
522{
523 if (updateType == Reconstruct) {
524 clearResolver();
525 return;
526 }
527 auto& styleResolver = resolver();
528
529 SetForScope<bool> isUpdatingStyleResolver { m_isUpdatingStyleResolver, true };
530 if (updateType == Reset) {
531 styleResolver.ruleSets().resetAuthorStyle();
532 styleResolver.appendAuthorStyleSheets(activeStyleSheets);
533 } else {
534 ASSERT(updateType == Additive);
535 unsigned firstNewIndex = m_activeStyleSheets.size();
536 Vector<RefPtr<CSSStyleSheet>> newStyleSheets;
537 newStyleSheets.appendRange(activeStyleSheets.begin() + firstNewIndex, activeStyleSheets.end());
538 styleResolver.appendAuthorStyleSheets(newStyleSheets);
539 }
540}
541
542const Vector<RefPtr<CSSStyleSheet>> Scope::activeStyleSheetsForInspector()
543{
544 Vector<RefPtr<CSSStyleSheet>> result;
545
546 result.appendVector(m_document.extensionStyleSheets().injectedAuthorStyleSheets());
547 result.appendVector(m_document.extensionStyleSheets().authorStyleSheetsForTesting());
548
549 for (auto& styleSheet : m_styleSheetsForStyleSheetList) {
550 if (!is<CSSStyleSheet>(*styleSheet))
551 continue;
552
553 CSSStyleSheet& sheet = downcast<CSSStyleSheet>(*styleSheet);
554 if (sheet.disabled())
555 continue;
556
557 result.append(&sheet);
558 }
559
560 return result;
561}
562
563bool Scope::activeStyleSheetsContains(const CSSStyleSheet* sheet) const
564{
565 if (!m_weakCopyOfActiveStyleSheetListForFastLookup) {
566 m_weakCopyOfActiveStyleSheetListForFastLookup = std::make_unique<HashSet<const CSSStyleSheet*>>();
567 for (auto& activeStyleSheet : m_activeStyleSheets)
568 m_weakCopyOfActiveStyleSheetListForFastLookup->add(activeStyleSheet.get());
569 }
570 return m_weakCopyOfActiveStyleSheetListForFastLookup->contains(sheet);
571}
572
573void Scope::flushPendingSelfUpdate()
574{
575 ASSERT(m_pendingUpdate);
576
577 auto updateType = *m_pendingUpdate;
578
579 clearPendingUpdate();
580 updateActiveStyleSheets(updateType);
581}
582
583void Scope::flushPendingDescendantUpdates()
584{
585 ASSERT(m_hasDescendantWithPendingUpdate);
586 ASSERT(!m_shadowRoot);
587 for (auto* descendantShadowRoot : m_document.inDocumentShadowRoots())
588 descendantShadowRoot->styleScope().flushPendingUpdate();
589 m_hasDescendantWithPendingUpdate = false;
590}
591
592void Scope::clearPendingUpdate()
593{
594 m_pendingUpdateTimer.stop();
595 m_pendingUpdate = { };
596}
597
598void Scope::scheduleUpdate(UpdateType update)
599{
600 if (update == UpdateType::ContentsOrInterpretation) {
601 // :host and ::slotted rules might go away.
602 if (m_shadowRoot && m_resolver)
603 invalidateHostAndSlottedStyleIfNeeded(*m_shadowRoot, *m_resolver);
604 // FIXME: Animation code may trigger resource load in middle of style recalc and that can add a rule to a content extension stylesheet.
605 // Fix and remove isResolvingTreeStyle() test below, see https://bugs.webkit.org/show_bug.cgi?id=194335
606 // FIXME: The m_isUpdatingStyleResolver test is here because extension stylesheets can get us here from StyleResolver::appendAuthorStyleSheets.
607 if (!m_isUpdatingStyleResolver && !m_document.isResolvingTreeStyle())
608 clearResolver();
609 }
610
611 if (!m_pendingUpdate || *m_pendingUpdate < update) {
612 m_pendingUpdate = update;
613 if (m_shadowRoot)
614 m_document.styleScope().m_hasDescendantWithPendingUpdate = true;
615 }
616
617 if (m_pendingUpdateTimer.isActive())
618 return;
619 m_pendingUpdateTimer.startOneShot(0_s);
620}
621
622void Scope::evaluateMediaQueriesForViewportChange()
623{
624 evaluateMediaQueries([] (StyleResolver& resolver) {
625 return resolver.hasMediaQueriesAffectedByViewportChange();
626 });
627}
628
629void Scope::evaluateMediaQueriesForAccessibilitySettingsChange()
630{
631 evaluateMediaQueries([] (StyleResolver& resolver) {
632 return resolver.hasMediaQueriesAffectedByAccessibilitySettingsChange();
633 });
634}
635
636void Scope::evaluateMediaQueriesForAppearanceChange()
637{
638 evaluateMediaQueries([] (StyleResolver& resolver) {
639 return resolver.hasMediaQueriesAffectedByAppearanceChange();
640 });
641}
642
643template <typename TestFunction>
644void Scope::evaluateMediaQueries(TestFunction&& testFunction)
645{
646 if (!m_shadowRoot) {
647 for (auto* descendantShadowRoot : m_document.inDocumentShadowRoots())
648 descendantShadowRoot->styleScope().evaluateMediaQueries(testFunction);
649 }
650 auto* resolver = resolverIfExists();
651 if (!resolver)
652 return;
653 if (!testFunction(*resolver))
654 return;
655 scheduleUpdate(UpdateType::ContentsOrInterpretation);
656 InspectorInstrumentation::mediaQueryResultChanged(m_document);
657}
658
659void Scope::didChangeActiveStyleSheetCandidates()
660{
661 scheduleUpdate(UpdateType::ActiveSet);
662}
663
664void Scope::didChangeStyleSheetContents()
665{
666 scheduleUpdate(UpdateType::ContentsOrInterpretation);
667}
668
669void Scope::didChangeStyleSheetEnvironment()
670{
671 if (!m_shadowRoot) {
672 for (auto* descendantShadowRoot : m_document.inDocumentShadowRoots()) {
673 // Stylesheets is author shadow roots are potentially affected.
674 if (descendantShadowRoot->mode() != ShadowRootMode::UserAgent)
675 descendantShadowRoot->styleScope().scheduleUpdate(UpdateType::ContentsOrInterpretation);
676 }
677 }
678 scheduleUpdate(UpdateType::ContentsOrInterpretation);
679}
680
681void Scope::pendingUpdateTimerFired()
682{
683 flushPendingUpdate();
684}
685
686const Vector<RefPtr<StyleSheet>>& Scope::styleSheetsForStyleSheetList()
687{
688 // FIXME: StyleSheetList content should be updated separately from style resolver updates.
689 flushPendingUpdate();
690 return m_styleSheetsForStyleSheetList;
691}
692
693}
694}
695