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
7  * rights reserved.
8  * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved.
9  * (http://www.torchmobile.com/)
10  * Copyright (C) 2008, 2009, 2011, 2012 Google Inc. All rights reserved.
11  * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
12  * Copyright (C) Research In Motion Limited 2010-2011. All rights reserved.
13  *
14  * This library is free software; you can redistribute it and/or
15  * modify it under the terms of the GNU Library General Public
16  * License as published by the Free Software Foundation; either
17  * version 2 of the License, or (at your option) any later version.
18  *
19  * This library is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
22  * Library General Public License for more details.
23  *
24  * You should have received a copy of the GNU Library General Public License
25  * along with this library; see the file COPYING.LIB.  If not, write to
26  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
27  * Boston, MA 02110-1301, USA.
28  */
29 
30 #include "third_party/blink/renderer/core/css/style_engine.h"
31 
32 #include "third_party/blink/public/mojom/frame/color_scheme.mojom-blink.h"
33 #include "third_party/blink/public/platform/platform.h"
34 #include "third_party/blink/public/platform/web_theme_engine.h"
35 #include "third_party/blink/renderer/core/css/css_default_style_sheets.h"
36 #include "third_party/blink/renderer/core/css/css_font_family_value.h"
37 #include "third_party/blink/renderer/core/css/css_font_selector.h"
38 #include "third_party/blink/renderer/core/css/css_identifier_value.h"
39 #include "third_party/blink/renderer/core/css/css_style_sheet.h"
40 #include "third_party/blink/renderer/core/css/css_uri_value.h"
41 #include "third_party/blink/renderer/core/css/css_value_list.h"
42 #include "third_party/blink/renderer/core/css/document_style_environment_variables.h"
43 #include "third_party/blink/renderer/core/css/document_style_sheet_collector.h"
44 #include "third_party/blink/renderer/core/css/font_face_cache.h"
45 #include "third_party/blink/renderer/core/css/invalidation/invalidation_set.h"
46 #include "third_party/blink/renderer/core/css/media_feature_overrides.h"
47 #include "third_party/blink/renderer/core/css/media_values.h"
48 #include "third_party/blink/renderer/core/css/property_registration.h"
49 #include "third_party/blink/renderer/core/css/property_registry.h"
50 #include "third_party/blink/renderer/core/css/resolver/scoped_style_resolver.h"
51 #include "third_party/blink/renderer/core/css/resolver/selector_filter_parent_scope.h"
52 #include "third_party/blink/renderer/core/css/resolver/style_rule_usage_tracker.h"
53 #include "third_party/blink/renderer/core/css/resolver/viewport_style_resolver.h"
54 #include "third_party/blink/renderer/core/css/shadow_tree_style_sheet_collection.h"
55 #include "third_party/blink/renderer/core/css/style_change_reason.h"
56 #include "third_party/blink/renderer/core/css/style_environment_variables.h"
57 #include "third_party/blink/renderer/core/css/style_sheet_contents.h"
58 #include "third_party/blink/renderer/core/css/vision_deficiency.h"
59 #include "third_party/blink/renderer/core/display_lock/display_lock_utilities.h"
60 #include "third_party/blink/renderer/core/dom/document_lifecycle.h"
61 #include "third_party/blink/renderer/core/dom/element.h"
62 #include "third_party/blink/renderer/core/dom/element_traversal.h"
63 #include "third_party/blink/renderer/core/dom/flat_tree_traversal.h"
64 #include "third_party/blink/renderer/core/dom/layout_tree_builder_traversal.h"
65 #include "third_party/blink/renderer/core/dom/node_computed_style.h"
66 #include "third_party/blink/renderer/core/dom/nth_index_cache.h"
67 #include "third_party/blink/renderer/core/dom/processing_instruction.h"
68 #include "third_party/blink/renderer/core/dom/shadow_root.h"
69 #include "third_party/blink/renderer/core/dom/text.h"
70 #include "third_party/blink/renderer/core/frame/settings.h"
71 #include "third_party/blink/renderer/core/html/html_body_element.h"
72 #include "third_party/blink/renderer/core/html/html_html_element.h"
73 #include "third_party/blink/renderer/core/html/html_iframe_element.h"
74 #include "third_party/blink/renderer/core/html/html_link_element.h"
75 #include "third_party/blink/renderer/core/html/html_slot_element.h"
76 #include "third_party/blink/renderer/core/html/imports/html_imports_controller.h"
77 #include "third_party/blink/renderer/core/html_names.h"
78 #include "third_party/blink/renderer/core/layout/layout_object.h"
79 #include "third_party/blink/renderer/core/layout/layout_theme.h"
80 #include "third_party/blink/renderer/core/layout/layout_view.h"
81 #include "third_party/blink/renderer/core/page/page.h"
82 #include "third_party/blink/renderer/core/page/page_popup_controller.h"
83 #include "third_party/blink/renderer/core/paint/paint_layer.h"
84 #include "third_party/blink/renderer/core/probe/core_probes.h"
85 #include "third_party/blink/renderer/core/style/computed_style.h"
86 #include "third_party/blink/renderer/core/style/filter_operations.h"
87 #include "third_party/blink/renderer/core/style/style_initial_data.h"
88 #include "third_party/blink/renderer/core/svg/svg_resource.h"
89 #include "third_party/blink/renderer/core/svg/svg_style_element.h"
90 #include "third_party/blink/renderer/platform/fonts/font_cache.h"
91 #include "third_party/blink/renderer/platform/fonts/font_selector.h"
92 #include "third_party/blink/renderer/platform/heap/heap.h"
93 #include "third_party/blink/renderer/platform/instrumentation/histogram.h"
94 #include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h"
95 #include "third_party/blink/renderer/platform/wtf/vector.h"
96 
97 namespace blink {
98 
99 namespace {
100 
CreateCSSFontSelectorFor(Document & document)101 CSSFontSelector* CreateCSSFontSelectorFor(Document& document) {
102   DCHECK(document.GetFrame());
103   if (UNLIKELY(document.GetFrame()->PagePopupOwner())) {
104     return PagePopupController::CreateCSSFontSelector(document);
105   }
106   return MakeGarbageCollected<CSSFontSelector>(&document);
107 }
108 
109 }  // namespace
110 
StyleEngine(Document & document)111 StyleEngine::StyleEngine(Document& document)
112     : document_(&document),
113       is_html_import_(document.IsHTMLImport()),
114       document_style_sheet_collection_(
115           MakeGarbageCollected<DocumentStyleSheetCollection>(document)),
116       owner_color_scheme_(mojom::blink::ColorScheme::kLight) {
117   if (document.GetFrame()) {
118     // We don't need to create CSSFontSelector for imported document or
119     // HTMLTemplateElement's document, because those documents have no frame.
120     // Likewise for the StyleResolver.
121     font_selector_ = CreateCSSFontSelectorFor(document);
122     font_selector_->RegisterForInvalidationCallbacks(this);
123     resolver_ = MakeGarbageCollected<StyleResolver>(document);
124     if (const auto* owner = document.GetFrame()->Owner())
125       owner_color_scheme_ = owner->GetColorScheme();
126   }
127   if (document.IsInMainFrame())
128     viewport_resolver_ = MakeGarbageCollected<ViewportStyleResolver>(document);
129   if (!IsHTMLImport())
130     global_rule_set_ = MakeGarbageCollected<CSSGlobalRuleSet>();
131   if (auto* settings = GetDocument().GetSettings()) {
132     if (!settings->GetForceDarkModeEnabled())
133       preferred_color_scheme_ = settings->GetPreferredColorScheme();
134     UpdateColorSchemeMetrics();
135   }
136   if (Platform::Current() && Platform::Current()->ThemeEngine())
137     forced_colors_ = Platform::Current()->ThemeEngine()->GetForcedColors();
138   UpdateForcedBackgroundColor();
139 }
140 
141 StyleEngine::~StyleEngine() = default;
142 
HTMLImportRootDocument()143 inline Document* StyleEngine::HTMLImportRootDocument() {
144   if (!IsHTMLImport())
145     return document_;
146   HTMLImportsController* import = GetDocument().ImportsController();
147   // Document::ImportsController() can return null while executing its
148   // destructor.
149   if (!import)
150     return nullptr;
151   return import->TreeRoot();
152 }
153 
EnsureStyleSheetCollectionFor(TreeScope & tree_scope)154 TreeScopeStyleSheetCollection& StyleEngine::EnsureStyleSheetCollectionFor(
155     TreeScope& tree_scope) {
156   if (tree_scope == document_)
157     return GetDocumentStyleSheetCollection();
158 
159   StyleSheetCollectionMap::AddResult result =
160       style_sheet_collection_map_.insert(&tree_scope, nullptr);
161   if (result.is_new_entry) {
162     result.stored_value->value =
163         MakeGarbageCollected<ShadowTreeStyleSheetCollection>(
164             To<ShadowRoot>(tree_scope));
165   }
166   return *result.stored_value->value.Get();
167 }
168 
StyleSheetCollectionFor(TreeScope & tree_scope)169 TreeScopeStyleSheetCollection* StyleEngine::StyleSheetCollectionFor(
170     TreeScope& tree_scope) {
171   if (tree_scope == document_)
172     return &GetDocumentStyleSheetCollection();
173 
174   StyleSheetCollectionMap::iterator it =
175       style_sheet_collection_map_.find(&tree_scope);
176   if (it == style_sheet_collection_map_.end())
177     return nullptr;
178   return it->value.Get();
179 }
180 
StyleSheetsForStyleSheetList(TreeScope & tree_scope)181 const HeapVector<Member<StyleSheet>>& StyleEngine::StyleSheetsForStyleSheetList(
182     TreeScope& tree_scope) {
183   DCHECK(HTMLImportRootDocument());
184   TreeScopeStyleSheetCollection& collection =
185       EnsureStyleSheetCollectionFor(tree_scope);
186   if (HTMLImportRootDocument()->IsActive())
187     collection.UpdateStyleSheetList();
188   return collection.StyleSheetsForStyleSheetList();
189 }
190 
InjectSheet(const StyleSheetKey & key,StyleSheetContents * sheet,WebDocument::CSSOrigin origin)191 void StyleEngine::InjectSheet(const StyleSheetKey& key,
192                               StyleSheetContents* sheet,
193                               WebDocument::CSSOrigin origin) {
194   HeapVector<std::pair<StyleSheetKey, Member<CSSStyleSheet>>>&
195       injected_style_sheets =
196           origin == WebDocument::kUserOrigin ? injected_user_style_sheets_
197                                              : injected_author_style_sheets_;
198   injected_style_sheets.push_back(std::make_pair(
199       key, MakeGarbageCollected<CSSStyleSheet>(sheet, *document_)));
200   if (origin == WebDocument::kUserOrigin)
201     MarkUserStyleDirty();
202   else
203     MarkDocumentDirty();
204 }
205 
RemoveInjectedSheet(const StyleSheetKey & key,WebDocument::CSSOrigin origin)206 void StyleEngine::RemoveInjectedSheet(const StyleSheetKey& key,
207                                       WebDocument::CSSOrigin origin) {
208   HeapVector<std::pair<StyleSheetKey, Member<CSSStyleSheet>>>&
209       injected_style_sheets =
210           origin == WebDocument::kUserOrigin ? injected_user_style_sheets_
211                                              : injected_author_style_sheets_;
212   // Remove the last sheet that matches.
213   const auto& it = std::find_if(injected_style_sheets.rbegin(),
214                                 injected_style_sheets.rend(),
215                                 [&key](const auto& item) {
216                                   return item.first == key;
217                                 });
218   if (it != injected_style_sheets.rend()) {
219     injected_style_sheets.erase(std::next(it).base());
220     if (origin == WebDocument::kUserOrigin)
221       MarkUserStyleDirty();
222     else
223       MarkDocumentDirty();
224   }
225 }
226 
EnsureInspectorStyleSheet()227 CSSStyleSheet& StyleEngine::EnsureInspectorStyleSheet() {
228   if (inspector_style_sheet_)
229     return *inspector_style_sheet_;
230 
231   auto* contents = MakeGarbageCollected<StyleSheetContents>(
232       MakeGarbageCollected<CSSParserContext>(*document_));
233   inspector_style_sheet_ =
234       MakeGarbageCollected<CSSStyleSheet>(contents, *document_);
235   MarkDocumentDirty();
236   // TODO(futhark@chromium.org): Making the active stylesheets up-to-date here
237   // is required by some inspector tests, at least. I theory this should not be
238   // necessary. Need to investigate to figure out if/why.
239   UpdateActiveStyle();
240   return *inspector_style_sheet_;
241 }
242 
AddPendingSheet(StyleEngineContext & context)243 void StyleEngine::AddPendingSheet(StyleEngineContext& context) {
244   pending_script_blocking_stylesheets_++;
245 
246   context.AddingPendingSheet(GetDocument());
247 
248   if (context.AddedPendingSheetBeforeBody() &&
249       !RuntimeEnabledFeatures::BlockHTMLParserOnStyleSheetsEnabled()) {
250     pending_render_blocking_stylesheets_++;
251   } else {
252     pending_parser_blocking_stylesheets_++;
253     GetDocument().DidAddPendingParserBlockingStylesheet();
254   }
255 }
256 
257 // This method is called whenever a top-level stylesheet has finished loading.
RemovePendingSheet(Node & style_sheet_candidate_node,const StyleEngineContext & context)258 void StyleEngine::RemovePendingSheet(Node& style_sheet_candidate_node,
259                                      const StyleEngineContext& context) {
260   if (style_sheet_candidate_node.isConnected())
261     SetNeedsActiveStyleUpdate(style_sheet_candidate_node.GetTreeScope());
262 
263   if (context.AddedPendingSheetBeforeBody() &&
264       !RuntimeEnabledFeatures::BlockHTMLParserOnStyleSheetsEnabled()) {
265     DCHECK_GT(pending_render_blocking_stylesheets_, 0);
266     pending_render_blocking_stylesheets_--;
267   } else {
268     DCHECK_GT(pending_parser_blocking_stylesheets_, 0);
269     pending_parser_blocking_stylesheets_--;
270     if (!pending_parser_blocking_stylesheets_)
271       GetDocument().DidLoadAllPendingParserBlockingStylesheets();
272   }
273 
274   // Make sure we knew this sheet was pending, and that our count isn't out of
275   // sync.
276   DCHECK_GT(pending_script_blocking_stylesheets_, 0);
277 
278   pending_script_blocking_stylesheets_--;
279   if (pending_script_blocking_stylesheets_)
280     return;
281 
282   GetDocument().DidRemoveAllPendingStylesheets();
283 }
284 
SetNeedsActiveStyleUpdate(TreeScope & tree_scope)285 void StyleEngine::SetNeedsActiveStyleUpdate(TreeScope& tree_scope) {
286   DCHECK(tree_scope.RootNode().isConnected());
287   if (GetDocument().IsActive() || IsHTMLImport())
288     MarkTreeScopeDirty(tree_scope);
289 }
290 
AddStyleSheetCandidateNode(Node & node)291 void StyleEngine::AddStyleSheetCandidateNode(Node& node) {
292   if (!node.isConnected() || GetDocument().IsDetached())
293     return;
294 
295   DCHECK(!IsXSLStyleSheet(node));
296   TreeScope& tree_scope = node.GetTreeScope();
297   EnsureStyleSheetCollectionFor(tree_scope).AddStyleSheetCandidateNode(node);
298 
299   SetNeedsActiveStyleUpdate(tree_scope);
300   if (tree_scope != document_)
301     active_tree_scopes_.insert(&tree_scope);
302 }
303 
RemoveStyleSheetCandidateNode(Node & node,ContainerNode & insertion_point)304 void StyleEngine::RemoveStyleSheetCandidateNode(
305     Node& node,
306     ContainerNode& insertion_point) {
307   DCHECK(!IsXSLStyleSheet(node));
308   DCHECK(insertion_point.isConnected());
309 
310   ShadowRoot* shadow_root = node.ContainingShadowRoot();
311   if (!shadow_root)
312     shadow_root = insertion_point.ContainingShadowRoot();
313 
314   static_assert(std::is_base_of<TreeScope, ShadowRoot>::value,
315                 "The ShadowRoot must be subclass of TreeScope.");
316   TreeScope& tree_scope =
317       shadow_root ? static_cast<TreeScope&>(*shadow_root) : GetDocument();
318   TreeScopeStyleSheetCollection* collection =
319       StyleSheetCollectionFor(tree_scope);
320   // After detaching document, collection could be null. In the case,
321   // we should not update anything. Instead, just return.
322   if (!collection)
323     return;
324   collection->RemoveStyleSheetCandidateNode(node);
325 
326   SetNeedsActiveStyleUpdate(tree_scope);
327 }
328 
ModifiedStyleSheetCandidateNode(Node & node)329 void StyleEngine::ModifiedStyleSheetCandidateNode(Node& node) {
330   if (node.isConnected())
331     SetNeedsActiveStyleUpdate(node.GetTreeScope());
332 }
333 
AdoptedStyleSheetsWillChange(TreeScope & tree_scope,const HeapVector<Member<CSSStyleSheet>> & old_sheets,const HeapVector<Member<CSSStyleSheet>> & new_sheets)334 void StyleEngine::AdoptedStyleSheetsWillChange(
335     TreeScope& tree_scope,
336     const HeapVector<Member<CSSStyleSheet>>& old_sheets,
337     const HeapVector<Member<CSSStyleSheet>>& new_sheets) {
338   if (GetDocument().IsDetached())
339     return;
340 
341   unsigned old_sheets_count = old_sheets.size();
342   unsigned new_sheets_count = new_sheets.size();
343 
344   unsigned min_count = std::min(old_sheets_count, new_sheets_count);
345   unsigned index = 0;
346   while (index < min_count && old_sheets[index] == new_sheets[index]) {
347     index++;
348   }
349 
350   if (old_sheets_count == new_sheets_count && index == old_sheets_count)
351     return;
352 
353   for (unsigned i = index; i < old_sheets_count; ++i) {
354     old_sheets[i]->RemovedAdoptedFromTreeScope(tree_scope);
355   }
356   for (unsigned i = index; i < new_sheets_count; ++i) {
357     new_sheets[i]->AddedAdoptedToTreeScope(tree_scope);
358   }
359 
360   if (!tree_scope.RootNode().isConnected())
361     return;
362 
363   if (new_sheets_count) {
364     EnsureStyleSheetCollectionFor(tree_scope);
365     if (tree_scope != document_)
366       active_tree_scopes_.insert(&tree_scope);
367   } else if (!StyleSheetCollectionFor(tree_scope)) {
368     return;
369   }
370   SetNeedsActiveStyleUpdate(tree_scope);
371 }
372 
AddedCustomElementDefaultStyles(const HeapVector<Member<CSSStyleSheet>> & default_styles)373 void StyleEngine::AddedCustomElementDefaultStyles(
374     const HeapVector<Member<CSSStyleSheet>>& default_styles) {
375   if (!RuntimeEnabledFeatures::CustomElementDefaultStyleEnabled() ||
376       GetDocument().IsDetached())
377     return;
378   for (CSSStyleSheet* sheet : default_styles)
379     custom_element_default_style_sheets_.insert(sheet);
380   global_rule_set_->MarkDirty();
381 }
382 
383 namespace {
384 
HasMediaQueries(const ActiveStyleSheetVector & active_style_sheets)385 bool HasMediaQueries(const ActiveStyleSheetVector& active_style_sheets) {
386   for (const auto& active_sheet : active_style_sheets) {
387     if (const MediaQuerySet* media_queries =
388             active_sheet.first->MediaQueries()) {
389       if (!media_queries->QueryVector().IsEmpty())
390         return true;
391     }
392     StyleSheetContents* contents = active_sheet.first->Contents();
393     if (contents->HasMediaQueries())
394       return true;
395   }
396   return false;
397 }
398 
HasSizeDependentMediaQueries(const ActiveStyleSheetVector & active_style_sheets)399 bool HasSizeDependentMediaQueries(
400     const ActiveStyleSheetVector& active_style_sheets) {
401   for (const auto& active_sheet : active_style_sheets) {
402     if (active_sheet.first->HasMediaQueryResults())
403       return true;
404     StyleSheetContents* contents = active_sheet.first->Contents();
405     if (!contents->HasRuleSet())
406       continue;
407     if (contents->GetRuleSet().Features().HasMediaQueryResults())
408       return true;
409   }
410   return false;
411 }
412 
413 }  // namespace
414 
MediaQueryAffectingValueChanged(const ActiveStyleSheetVector & active_sheets,MediaValueChange change)415 bool StyleEngine::MediaQueryAffectingValueChanged(
416     const ActiveStyleSheetVector& active_sheets,
417     MediaValueChange change) {
418   if (change == MediaValueChange::kSize)
419     return HasSizeDependentMediaQueries(active_sheets);
420 
421   DCHECK(change == MediaValueChange::kOther);
422   return HasMediaQueries(active_sheets);
423 }
424 
MediaQueryAffectingValueChanged(TreeScope & tree_scope,MediaValueChange change)425 void StyleEngine::MediaQueryAffectingValueChanged(TreeScope& tree_scope,
426                                                   MediaValueChange change) {
427   auto* collection = StyleSheetCollectionFor(tree_scope);
428   DCHECK(collection);
429   if (MediaQueryAffectingValueChanged(collection->ActiveAuthorStyleSheets(),
430                                       change)) {
431     SetNeedsActiveStyleUpdate(tree_scope);
432   }
433 }
434 
MediaQueriesChangedInScope(TreeScope & tree_scope)435 void StyleEngine::MediaQueriesChangedInScope(TreeScope& tree_scope) {
436   if (ScopedStyleResolver* resolver = tree_scope.GetScopedStyleResolver())
437     resolver->SetNeedsAppendAllSheets();
438   SetNeedsActiveStyleUpdate(tree_scope);
439 }
440 
WatchedSelectorsChanged()441 void StyleEngine::WatchedSelectorsChanged() {
442   DCHECK(!IsHTMLImport());
443   DCHECK(global_rule_set_);
444   global_rule_set_->InitWatchedSelectorsRuleSet(GetDocument());
445   // TODO(futhark@chromium.org): Should be able to use RuleSetInvalidation here.
446   MarkAllElementsForStyleRecalc(StyleChangeReasonForTracing::Create(
447       style_change_reason::kDeclarativeContent));
448 }
449 
ShouldUpdateDocumentStyleSheetCollection() const450 bool StyleEngine::ShouldUpdateDocumentStyleSheetCollection() const {
451   return document_scope_dirty_;
452 }
453 
ShouldUpdateShadowTreeStyleSheetCollection() const454 bool StyleEngine::ShouldUpdateShadowTreeStyleSheetCollection() const {
455   return !dirty_tree_scopes_.IsEmpty();
456 }
457 
MediaQueryAffectingValueChanged(UnorderedTreeScopeSet & tree_scopes,MediaValueChange change)458 void StyleEngine::MediaQueryAffectingValueChanged(
459     UnorderedTreeScopeSet& tree_scopes,
460     MediaValueChange change) {
461   for (TreeScope* tree_scope : tree_scopes) {
462     DCHECK(tree_scope != document_);
463     MediaQueryAffectingValueChanged(*tree_scope, change);
464   }
465 }
466 
AddTextTrack(TextTrack * text_track)467 void StyleEngine::AddTextTrack(TextTrack* text_track) {
468   text_tracks_.insert(text_track);
469 }
470 
RemoveTextTrack(TextTrack * text_track)471 void StyleEngine::RemoveTextTrack(TextTrack* text_track) {
472   text_tracks_.erase(text_track);
473 }
474 
EnsureVTTOriginatingElement()475 Element* StyleEngine::EnsureVTTOriginatingElement() {
476   if (!vtt_originating_element_) {
477     vtt_originating_element_ = MakeGarbageCollected<Element>(
478         QualifiedName(g_null_atom, g_empty_atom, g_empty_atom), document_);
479   }
480   return vtt_originating_element_;
481 }
482 
MediaQueryAffectingValueChanged(HeapHashSet<Member<TextTrack>> & text_tracks,MediaValueChange change)483 void StyleEngine::MediaQueryAffectingValueChanged(
484     HeapHashSet<Member<TextTrack>>& text_tracks,
485     MediaValueChange change) {
486   if (text_tracks.IsEmpty())
487     return;
488 
489   for (auto text_track : text_tracks) {
490     bool style_needs_recalc = false;
491     auto style_sheets = text_track->GetCSSStyleSheets();
492     for (const auto& sheet : style_sheets) {
493       StyleSheetContents* contents = sheet->Contents();
494       if (contents->HasMediaQueries()) {
495         style_needs_recalc = true;
496         contents->ClearRuleSet();
497       }
498     }
499 
500     if (style_needs_recalc) {
501       // Use kSubtreeTreeStyleChange instead of RuleSet style invalidation
502       // because it won't be expensive for tracks and we won't have dynamic
503       // changes.
504       text_track->Owner()->SetNeedsStyleRecalc(
505           kSubtreeStyleChange,
506           StyleChangeReasonForTracing::Create(style_change_reason::kShadow));
507     }
508   }
509 }
510 
MediaQueryAffectingValueChanged(MediaValueChange change)511 void StyleEngine::MediaQueryAffectingValueChanged(MediaValueChange change) {
512   if (MediaQueryAffectingValueChanged(active_user_style_sheets_, change))
513     MarkUserStyleDirty();
514   MediaQueryAffectingValueChanged(GetDocument(), change);
515   MediaQueryAffectingValueChanged(active_tree_scopes_, change);
516   MediaQueryAffectingValueChanged(text_tracks_, change);
517   if (resolver_)
518     resolver_->UpdateMediaType();
519 }
520 
UpdateActiveStyleSheetsInImport(StyleEngine & root_engine,DocumentStyleSheetCollector & parent_collector)521 void StyleEngine::UpdateActiveStyleSheetsInImport(
522     StyleEngine& root_engine,
523     DocumentStyleSheetCollector& parent_collector) {
524   DCHECK(RuntimeEnabledFeatures::HTMLImportsEnabled());
525   DCHECK(IsHTMLImport());
526   HeapVector<Member<StyleSheet>> sheets_for_list;
527   ImportedDocumentStyleSheetCollector subcollector(parent_collector,
528                                                    sheets_for_list);
529   GetDocumentStyleSheetCollection().CollectStyleSheets(root_engine,
530                                                        subcollector);
531   GetDocumentStyleSheetCollection().SwapSheetsForSheetList(sheets_for_list);
532 
533   // Mark false for consistency. It is never checked for import documents.
534   document_scope_dirty_ = false;
535 }
536 
UpdateActiveStyleSheetsInShadow(TreeScope * tree_scope,UnorderedTreeScopeSet & tree_scopes_removed)537 void StyleEngine::UpdateActiveStyleSheetsInShadow(
538     TreeScope* tree_scope,
539     UnorderedTreeScopeSet& tree_scopes_removed) {
540   DCHECK_NE(tree_scope, document_);
541   auto* collection =
542       To<ShadowTreeStyleSheetCollection>(StyleSheetCollectionFor(*tree_scope));
543   DCHECK(collection);
544   collection->UpdateActiveStyleSheets(*this);
545   if (!collection->HasStyleSheetCandidateNodes() &&
546       !tree_scope->HasAdoptedStyleSheets()) {
547     tree_scopes_removed.insert(tree_scope);
548     // When removing TreeScope from ActiveTreeScopes,
549     // its resolver should be destroyed by invoking resetAuthorStyle.
550     DCHECK(!tree_scope->GetScopedStyleResolver());
551   }
552 }
553 
UpdateActiveUserStyleSheets()554 void StyleEngine::UpdateActiveUserStyleSheets() {
555   DCHECK(user_style_dirty_);
556 
557   ActiveStyleSheetVector new_active_sheets;
558   for (auto& sheet : injected_user_style_sheets_) {
559     if (RuleSet* rule_set = RuleSetForSheet(*sheet.second))
560       new_active_sheets.push_back(std::make_pair(sheet.second, rule_set));
561   }
562 
563   ApplyUserRuleSetChanges(active_user_style_sheets_, new_active_sheets);
564   new_active_sheets.swap(active_user_style_sheets_);
565 }
566 
UpdateActiveStyleSheets()567 void StyleEngine::UpdateActiveStyleSheets() {
568   if (!NeedsActiveStyleSheetUpdate())
569     return;
570 
571   DCHECK(!IsHTMLImport());
572   DCHECK(!GetDocument().InStyleRecalc());
573   DCHECK(GetDocument().IsActive());
574 
575   TRACE_EVENT0("blink,blink_style", "StyleEngine::updateActiveStyleSheets");
576 
577   if (user_style_dirty_)
578     UpdateActiveUserStyleSheets();
579 
580   if (ShouldUpdateDocumentStyleSheetCollection())
581     GetDocumentStyleSheetCollection().UpdateActiveStyleSheets(*this);
582 
583   if (ShouldUpdateShadowTreeStyleSheetCollection()) {
584     UnorderedTreeScopeSet tree_scopes_removed;
585     for (TreeScope* tree_scope : dirty_tree_scopes_)
586       UpdateActiveStyleSheetsInShadow(tree_scope, tree_scopes_removed);
587     for (TreeScope* tree_scope : tree_scopes_removed)
588       active_tree_scopes_.erase(tree_scope);
589   }
590 
591   probe::ActiveStyleSheetsUpdated(document_);
592 
593   dirty_tree_scopes_.clear();
594   document_scope_dirty_ = false;
595   tree_scopes_removed_ = false;
596   user_style_dirty_ = false;
597 }
598 
UpdateViewport()599 void StyleEngine::UpdateViewport() {
600   if (viewport_resolver_)
601     viewport_resolver_->UpdateViewport(GetDocumentStyleSheetCollection());
602 }
603 
NeedsActiveStyleUpdate() const604 bool StyleEngine::NeedsActiveStyleUpdate() const {
605   return (viewport_resolver_ && viewport_resolver_->NeedsUpdate()) ||
606          NeedsActiveStyleSheetUpdate() ||
607          (global_rule_set_ && global_rule_set_->IsDirty());
608 }
609 
UpdateActiveStyle()610 void StyleEngine::UpdateActiveStyle() {
611   DCHECK(GetDocument().IsActive());
612   DCHECK(IsMainThread());
613   TRACE_EVENT0("blink", "Document::updateActiveStyle");
614   UpdateViewport();
615   UpdateActiveStyleSheets();
616   UpdateGlobalRuleSet();
617 }
618 
ActiveStyleSheetsForInspector()619 const ActiveStyleSheetVector StyleEngine::ActiveStyleSheetsForInspector() {
620   if (GetDocument().IsActive())
621     UpdateActiveStyle();
622 
623   if (active_tree_scopes_.IsEmpty())
624     return GetDocumentStyleSheetCollection().ActiveAuthorStyleSheets();
625 
626   ActiveStyleSheetVector active_style_sheets;
627 
628   active_style_sheets.AppendVector(
629       GetDocumentStyleSheetCollection().ActiveAuthorStyleSheets());
630   for (TreeScope* tree_scope : active_tree_scopes_) {
631     if (TreeScopeStyleSheetCollection* collection =
632             style_sheet_collection_map_.at(tree_scope))
633       active_style_sheets.AppendVector(collection->ActiveAuthorStyleSheets());
634   }
635 
636   // FIXME: Inspector needs a vector which has all active stylesheets.
637   // However, creating such a large vector might cause performance regression.
638   // Need to implement some smarter solution.
639   return active_style_sheets;
640 }
641 
ShadowRootInsertedToDocument(ShadowRoot & shadow_root)642 void StyleEngine::ShadowRootInsertedToDocument(ShadowRoot& shadow_root) {
643   DCHECK(shadow_root.isConnected());
644   if (GetDocument().IsDetached() || !shadow_root.HasAdoptedStyleSheets())
645     return;
646   EnsureStyleSheetCollectionFor(shadow_root);
647   SetNeedsActiveStyleUpdate(shadow_root);
648   active_tree_scopes_.insert(&shadow_root);
649 }
650 
ShadowRootRemovedFromDocument(ShadowRoot * shadow_root)651 void StyleEngine::ShadowRootRemovedFromDocument(ShadowRoot* shadow_root) {
652   style_sheet_collection_map_.erase(shadow_root);
653   active_tree_scopes_.erase(shadow_root);
654   dirty_tree_scopes_.erase(shadow_root);
655   tree_scopes_removed_ = true;
656   ResetAuthorStyle(*shadow_root);
657 }
658 
AddTreeBoundaryCrossingScope(const TreeScope & tree_scope)659 void StyleEngine::AddTreeBoundaryCrossingScope(const TreeScope& tree_scope) {
660   tree_boundary_crossing_scopes_.Add(&tree_scope.RootNode());
661 }
662 
ResetAuthorStyle(TreeScope & tree_scope)663 void StyleEngine::ResetAuthorStyle(TreeScope& tree_scope) {
664   tree_boundary_crossing_scopes_.Remove(&tree_scope.RootNode());
665 
666   ScopedStyleResolver* scoped_resolver = tree_scope.GetScopedStyleResolver();
667   if (!scoped_resolver)
668     return;
669 
670   if (global_rule_set_)
671     global_rule_set_->MarkDirty();
672   if (tree_scope.RootNode().IsDocumentNode()) {
673     scoped_resolver->ResetAuthorStyle();
674     return;
675   }
676 
677   tree_scope.ClearScopedStyleResolver();
678 }
679 
SetRuleUsageTracker(StyleRuleUsageTracker * tracker)680 void StyleEngine::SetRuleUsageTracker(StyleRuleUsageTracker* tracker) {
681   tracker_ = tracker;
682 
683   if (resolver_)
684     resolver_->SetRuleUsageTracker(tracker_);
685 }
686 
RuleSetForSheet(CSSStyleSheet & sheet)687 RuleSet* StyleEngine::RuleSetForSheet(CSSStyleSheet& sheet) {
688   if (!sheet.MatchesMediaQueries(EnsureMediaQueryEvaluator()))
689     return nullptr;
690 
691   AddRuleFlags add_rule_flags = kRuleHasNoSpecialState;
692   if (document_->GetExecutionContext()->GetSecurityOrigin()->CanRequest(
693           sheet.BaseURL())) {
694     add_rule_flags = kRuleHasDocumentSecurityOrigin;
695   }
696   return &sheet.Contents()->EnsureRuleSet(*media_query_evaluator_,
697                                           add_rule_flags);
698 }
699 
ClearResolvers()700 void StyleEngine::ClearResolvers() {
701   DCHECK(!GetDocument().InStyleRecalc());
702   DCHECK(!IsHTMLImport() || !resolver_);
703 
704   GetDocument().ClearScopedStyleResolver();
705   for (TreeScope* tree_scope : active_tree_scopes_)
706     tree_scope->ClearScopedStyleResolver();
707 
708   if (resolver_) {
709     TRACE_EVENT1("blink", "StyleEngine::clearResolver", "frame",
710                  ToTraceValue(GetDocument().GetFrame()));
711     resolver_->Dispose();
712     resolver_.Clear();
713   }
714 }
715 
DidDetach()716 void StyleEngine::DidDetach() {
717   ClearResolvers();
718   if (global_rule_set_)
719     global_rule_set_->Dispose();
720   global_rule_set_ = nullptr;
721   tree_boundary_crossing_scopes_.Clear();
722   dirty_tree_scopes_.clear();
723   active_tree_scopes_.clear();
724   viewport_resolver_ = nullptr;
725   media_query_evaluator_ = nullptr;
726   style_invalidation_root_.Clear();
727   style_recalc_root_.Clear();
728   layout_tree_rebuild_root_.Clear();
729   if (font_selector_)
730     font_selector_->GetFontFaceCache()->ClearAll();
731   font_selector_ = nullptr;
732   if (environment_variables_)
733     environment_variables_->DetachFromParent();
734   environment_variables_ = nullptr;
735 }
736 
ClearFontFaceCacheAndAddUserFonts()737 bool StyleEngine::ClearFontFaceCacheAndAddUserFonts() {
738   bool fonts_changed = false;
739 
740   if (font_selector_ &&
741       font_selector_->GetFontFaceCache()->ClearCSSConnected()) {
742     fonts_changed = true;
743     if (resolver_)
744       resolver_->InvalidateMatchedPropertiesCache();
745   }
746 
747   // Rebuild the font cache with @font-face rules from user style sheets.
748   for (unsigned i = 0; i < active_user_style_sheets_.size(); ++i) {
749     DCHECK(active_user_style_sheets_[i].second);
750     if (AddUserFontFaceRules(*active_user_style_sheets_[i].second))
751       fonts_changed = true;
752   }
753 
754   return fonts_changed;
755 }
756 
UpdateGenericFontFamilySettings()757 void StyleEngine::UpdateGenericFontFamilySettings() {
758   // FIXME: we should not update generic font family settings when
759   // document is inactive.
760   DCHECK(GetDocument().IsActive());
761 
762   if (!font_selector_)
763     return;
764 
765   font_selector_->UpdateGenericFontFamilySettings(*document_);
766   if (resolver_)
767     resolver_->InvalidateMatchedPropertiesCache();
768   FontCache::GetFontCache()->InvalidateShapeCache();
769 }
770 
RemoveFontFaceRules(const HeapVector<Member<const StyleRuleFontFace>> & font_face_rules)771 void StyleEngine::RemoveFontFaceRules(
772     const HeapVector<Member<const StyleRuleFontFace>>& font_face_rules) {
773   if (!font_selector_)
774     return;
775 
776   FontFaceCache* cache = font_selector_->GetFontFaceCache();
777   for (const auto& rule : font_face_rules)
778     cache->Remove(rule);
779   if (resolver_)
780     resolver_->InvalidateMatchedPropertiesCache();
781 }
782 
MarkTreeScopeDirty(TreeScope & scope)783 void StyleEngine::MarkTreeScopeDirty(TreeScope& scope) {
784   if (scope == document_) {
785     MarkDocumentDirty();
786     return;
787   }
788 
789   TreeScopeStyleSheetCollection* collection = StyleSheetCollectionFor(scope);
790   DCHECK(collection);
791   collection->MarkSheetListDirty();
792   dirty_tree_scopes_.insert(&scope);
793   GetDocument().ScheduleLayoutTreeUpdateIfNeeded();
794 }
795 
MarkDocumentDirty()796 void StyleEngine::MarkDocumentDirty() {
797   document_scope_dirty_ = true;
798   document_style_sheet_collection_->MarkSheetListDirty();
799   if (GetDocument().ImportLoader())
800     GetDocument().TreeRootDocument().GetStyleEngine().MarkDocumentDirty();
801   else
802     GetDocument().ScheduleLayoutTreeUpdateIfNeeded();
803 }
804 
MarkUserStyleDirty()805 void StyleEngine::MarkUserStyleDirty() {
806   user_style_dirty_ = true;
807   GetDocument().ScheduleLayoutTreeUpdateIfNeeded();
808 }
809 
MarkViewportStyleDirty()810 void StyleEngine::MarkViewportStyleDirty() {
811   viewport_style_dirty_ = true;
812   GetDocument().ScheduleLayoutTreeUpdateIfNeeded();
813 }
814 
CreateSheet(Element & element,const String & text,TextPosition start_position,StyleEngineContext & context)815 CSSStyleSheet* StyleEngine::CreateSheet(Element& element,
816                                         const String& text,
817                                         TextPosition start_position,
818                                         StyleEngineContext& context) {
819   DCHECK(element.GetDocument() == GetDocument());
820   CSSStyleSheet* style_sheet = nullptr;
821 
822   AddPendingSheet(context);
823 
824   AtomicString text_content(text);
825 
826   auto result = text_to_sheet_cache_.insert(text_content, nullptr);
827   StyleSheetContents* contents = result.stored_value->value;
828   if (result.is_new_entry || !contents ||
829       !contents->IsCacheableForStyleElement()) {
830     result.stored_value->value = nullptr;
831     style_sheet = ParseSheet(element, text, start_position);
832     if (style_sheet->Contents()->IsCacheableForStyleElement()) {
833       result.stored_value->value = style_sheet->Contents();
834       sheet_to_text_cache_.insert(style_sheet->Contents(), text_content);
835     }
836   } else {
837     DCHECK(contents);
838     DCHECK(contents->IsCacheableForStyleElement());
839     DCHECK(contents->HasSingleOwnerDocument());
840     contents->SetIsUsedFromTextCache();
841     style_sheet =
842         CSSStyleSheet::CreateInline(contents, element, start_position);
843   }
844 
845   DCHECK(style_sheet);
846   if (!element.IsInShadowTree()) {
847     String title = element.title();
848     if (!title.IsEmpty()) {
849       style_sheet->SetTitle(title);
850       SetPreferredStylesheetSetNameIfNotSet(title);
851     }
852   }
853   return style_sheet;
854 }
855 
ParseSheet(Element & element,const String & text,TextPosition start_position)856 CSSStyleSheet* StyleEngine::ParseSheet(Element& element,
857                                        const String& text,
858                                        TextPosition start_position) {
859   CSSStyleSheet* style_sheet = nullptr;
860   style_sheet = CSSStyleSheet::CreateInline(element, NullURL(), start_position,
861                                             GetDocument().Encoding());
862   style_sheet->Contents()->ParseStringAtPosition(text, start_position);
863   return style_sheet;
864 }
865 
CollectUserStyleFeaturesTo(RuleFeatureSet & features) const866 void StyleEngine::CollectUserStyleFeaturesTo(RuleFeatureSet& features) const {
867   for (unsigned i = 0; i < active_user_style_sheets_.size(); ++i) {
868     CSSStyleSheet* sheet = active_user_style_sheets_[i].first;
869     features.ViewportDependentMediaQueryResults().AppendVector(
870         sheet->ViewportDependentMediaQueryResults());
871     features.DeviceDependentMediaQueryResults().AppendVector(
872         sheet->DeviceDependentMediaQueryResults());
873     DCHECK(sheet->Contents()->HasRuleSet());
874     features.Add(sheet->Contents()->GetRuleSet().Features());
875   }
876 }
877 
CollectScopedStyleFeaturesTo(RuleFeatureSet & features) const878 void StyleEngine::CollectScopedStyleFeaturesTo(RuleFeatureSet& features) const {
879   HeapHashSet<Member<const StyleSheetContents>>
880       visited_shared_style_sheet_contents;
881   if (GetDocument().GetScopedStyleResolver()) {
882     GetDocument().GetScopedStyleResolver()->CollectFeaturesTo(
883         features, visited_shared_style_sheet_contents);
884   }
885   for (TreeScope* tree_scope : active_tree_scopes_) {
886     if (ScopedStyleResolver* resolver = tree_scope->GetScopedStyleResolver()) {
887       resolver->CollectFeaturesTo(features,
888                                   visited_shared_style_sheet_contents);
889     }
890   }
891 }
892 
InvalidateStyleAndLayoutForFontUpdates()893 void StyleEngine::InvalidateStyleAndLayoutForFontUpdates() {
894   if (!fonts_need_update_)
895     return;
896 
897   TRACE_EVENT0("blink", "StyleEngine::InvalidateStyleAndLayoutForFontUpdates");
898 
899   fonts_need_update_ = false;
900 
901   if (Element* root = GetDocument().documentElement()) {
902     TRACE_EVENT0("blink", "Node::MarkSubtreeNeedsStyleRecalcForFontUpdates");
903     root->MarkSubtreeNeedsStyleRecalcForFontUpdates();
904   }
905 
906   if (LayoutView* layout_view = GetDocument().GetLayoutView()) {
907     TRACE_EVENT0("blink", "LayoutObject::InvalidateSubtreeForFontUpdates");
908     layout_view->InvalidateSubtreeLayoutForFontUpdates();
909   }
910 }
911 
MarkFontsNeedUpdate()912 void StyleEngine::MarkFontsNeedUpdate() {
913   fonts_need_update_ = true;
914   GetDocument().ScheduleLayoutTreeUpdateIfNeeded();
915 }
916 
FontsNeedUpdate(FontSelector *,FontInvalidationReason)917 void StyleEngine::FontsNeedUpdate(FontSelector*, FontInvalidationReason) {
918   if (!GetDocument().IsActive())
919     return;
920 
921   if (resolver_)
922     resolver_->InvalidateMatchedPropertiesCache();
923   MarkViewportStyleDirty();
924   MarkFontsNeedUpdate();
925 
926   probe::FontsUpdated(document_->GetExecutionContext(), nullptr, String(),
927                       nullptr);
928 }
929 
PlatformColorsChanged()930 void StyleEngine::PlatformColorsChanged() {
931   UpdateForcedBackgroundColor();
932   if (resolver_)
933     resolver_->InvalidateMatchedPropertiesCache();
934   MarkAllElementsForStyleRecalc(StyleChangeReasonForTracing::Create(
935       style_change_reason::kPlatformColorChange));
936 }
937 
ShouldSkipInvalidationFor(const Element & element) const938 bool StyleEngine::ShouldSkipInvalidationFor(const Element& element) const {
939   if (!element.InActiveDocument())
940     return true;
941   if (GetDocument().InStyleRecalc()) {
942 #if DCHECK_IS_ON()
943     // TODO(futhark): The InStyleRecalc() if-guard above should have been a
944     // DCHECK(!InStyleRecalc()), but there are a couple of cases where we try to
945     // invalidate style from style recalc:
946     //
947     // 1. We may animate the class attribute of an SVG element and change it
948     //    during style recalc when applying the animation effect.
949     // 2. We may call SetInlineStyle on elements in a UA shadow tree as part of
950     //    style recalc. For instance from HTMLImageFallbackHelper.
951     //
952     // If there are more cases, we need to adjust the DCHECKs below, but ideally
953     // The origin of these invalidations should be fixed.
954     if (!element.IsSVGElement()) {
955       DCHECK(element.ContainingShadowRoot());
956       DCHECK(element.ContainingShadowRoot()->IsUserAgent());
957     }
958 #endif  // DCHECK_IS_ON()
959     return true;
960   }
961   if (GetDocument().GetStyleChangeType() == kSubtreeStyleChange)
962     return true;
963   Element* root = GetDocument().documentElement();
964   if (!root || root->GetStyleChangeType() == kSubtreeStyleChange)
965     return true;
966   if (!element.parentNode())
967     return true;
968   return element.parentNode()->GetStyleChangeType() == kSubtreeStyleChange;
969 }
970 
ClassChangedForElement(const SpaceSplitString & changed_classes,Element & element)971 void StyleEngine::ClassChangedForElement(
972     const SpaceSplitString& changed_classes,
973     Element& element) {
974   if (ShouldSkipInvalidationFor(element))
975     return;
976   InvalidationLists invalidation_lists;
977   unsigned changed_size = changed_classes.size();
978   const RuleFeatureSet& features = GetRuleFeatureSet();
979   for (unsigned i = 0; i < changed_size; ++i) {
980     features.CollectInvalidationSetsForClass(invalidation_lists, element,
981                                              changed_classes[i]);
982   }
983   pending_invalidations_.ScheduleInvalidationSetsForNode(invalidation_lists,
984                                                          element);
985 }
986 
ClassChangedForElement(const SpaceSplitString & old_classes,const SpaceSplitString & new_classes,Element & element)987 void StyleEngine::ClassChangedForElement(const SpaceSplitString& old_classes,
988                                          const SpaceSplitString& new_classes,
989                                          Element& element) {
990   if (ShouldSkipInvalidationFor(element))
991     return;
992 
993   if (!old_classes.size()) {
994     ClassChangedForElement(new_classes, element);
995     return;
996   }
997 
998   // Class vectors tend to be very short. This is faster than using a hash
999   // table.
1000   WTF::Vector<bool> remaining_class_bits(old_classes.size());
1001 
1002   InvalidationLists invalidation_lists;
1003   const RuleFeatureSet& features = GetRuleFeatureSet();
1004 
1005   for (unsigned i = 0; i < new_classes.size(); ++i) {
1006     bool found = false;
1007     for (unsigned j = 0; j < old_classes.size(); ++j) {
1008       if (new_classes[i] == old_classes[j]) {
1009         // Mark each class that is still in the newClasses so we can skip doing
1010         // an n^2 search below when looking for removals. We can't break from
1011         // this loop early since a class can appear more than once.
1012         remaining_class_bits[j] = true;
1013         found = true;
1014       }
1015     }
1016     // Class was added.
1017     if (!found) {
1018       features.CollectInvalidationSetsForClass(invalidation_lists, element,
1019                                                new_classes[i]);
1020     }
1021   }
1022 
1023   for (unsigned i = 0; i < old_classes.size(); ++i) {
1024     if (remaining_class_bits[i])
1025       continue;
1026     // Class was removed.
1027     features.CollectInvalidationSetsForClass(invalidation_lists, element,
1028                                              old_classes[i]);
1029   }
1030   pending_invalidations_.ScheduleInvalidationSetsForNode(invalidation_lists,
1031                                                          element);
1032 }
1033 
1034 namespace {
1035 
HasAttributeDependentGeneratedContent(const Element & element)1036 bool HasAttributeDependentGeneratedContent(const Element& element) {
1037   if (PseudoElement* before = element.GetPseudoElement(kPseudoIdBefore)) {
1038     const ComputedStyle* style = before->GetComputedStyle();
1039     if (style && style->HasAttrContent())
1040       return true;
1041   }
1042   if (PseudoElement* after = element.GetPseudoElement(kPseudoIdAfter)) {
1043     const ComputedStyle* style = after->GetComputedStyle();
1044     if (style && style->HasAttrContent())
1045       return true;
1046   }
1047   return false;
1048 }
1049 
1050 }  // namespace
1051 
AttributeChangedForElement(const QualifiedName & attribute_name,Element & element)1052 void StyleEngine::AttributeChangedForElement(
1053     const QualifiedName& attribute_name,
1054     Element& element) {
1055   if (ShouldSkipInvalidationFor(element))
1056     return;
1057 
1058   InvalidationLists invalidation_lists;
1059   GetRuleFeatureSet().CollectInvalidationSetsForAttribute(
1060       invalidation_lists, element, attribute_name);
1061   pending_invalidations_.ScheduleInvalidationSetsForNode(invalidation_lists,
1062                                                          element);
1063 
1064   if (!element.NeedsStyleRecalc() &&
1065       HasAttributeDependentGeneratedContent(element)) {
1066     element.SetNeedsStyleRecalc(
1067         kLocalStyleChange,
1068         StyleChangeReasonForTracing::FromAttribute(attribute_name));
1069   }
1070 }
1071 
IdChangedForElement(const AtomicString & old_id,const AtomicString & new_id,Element & element)1072 void StyleEngine::IdChangedForElement(const AtomicString& old_id,
1073                                       const AtomicString& new_id,
1074                                       Element& element) {
1075   if (ShouldSkipInvalidationFor(element))
1076     return;
1077 
1078   InvalidationLists invalidation_lists;
1079   const RuleFeatureSet& features = GetRuleFeatureSet();
1080   if (!old_id.IsEmpty())
1081     features.CollectInvalidationSetsForId(invalidation_lists, element, old_id);
1082   if (!new_id.IsEmpty())
1083     features.CollectInvalidationSetsForId(invalidation_lists, element, new_id);
1084   pending_invalidations_.ScheduleInvalidationSetsForNode(invalidation_lists,
1085                                                          element);
1086 }
1087 
PseudoStateChangedForElement(CSSSelector::PseudoType pseudo_type,Element & element)1088 void StyleEngine::PseudoStateChangedForElement(
1089     CSSSelector::PseudoType pseudo_type,
1090     Element& element) {
1091   if (ShouldSkipInvalidationFor(element))
1092     return;
1093 
1094   InvalidationLists invalidation_lists;
1095   GetRuleFeatureSet().CollectInvalidationSetsForPseudoClass(
1096       invalidation_lists, element, pseudo_type);
1097   pending_invalidations_.ScheduleInvalidationSetsForNode(invalidation_lists,
1098                                                          element);
1099 }
1100 
PartChangedForElement(Element & element)1101 void StyleEngine::PartChangedForElement(Element& element) {
1102   if (ShouldSkipInvalidationFor(element))
1103     return;
1104   if (element.GetTreeScope() == document_)
1105     return;
1106   if (!GetRuleFeatureSet().InvalidatesParts())
1107     return;
1108   element.SetNeedsStyleRecalc(
1109       kLocalStyleChange,
1110       StyleChangeReasonForTracing::FromAttribute(html_names::kPartAttr));
1111 }
1112 
ExportpartsChangedForElement(Element & element)1113 void StyleEngine::ExportpartsChangedForElement(Element& element) {
1114   if (ShouldSkipInvalidationFor(element))
1115     return;
1116   if (!element.GetShadowRoot())
1117     return;
1118 
1119   InvalidationLists invalidation_lists;
1120   GetRuleFeatureSet().CollectPartInvalidationSet(invalidation_lists);
1121   pending_invalidations_.ScheduleInvalidationSetsForNode(invalidation_lists,
1122                                                          element);
1123 }
1124 
ScheduleSiblingInvalidationsForElement(Element & element,ContainerNode & scheduling_parent,unsigned min_direct_adjacent)1125 void StyleEngine::ScheduleSiblingInvalidationsForElement(
1126     Element& element,
1127     ContainerNode& scheduling_parent,
1128     unsigned min_direct_adjacent) {
1129   DCHECK(min_direct_adjacent);
1130 
1131   InvalidationLists invalidation_lists;
1132 
1133   const RuleFeatureSet& features = GetRuleFeatureSet();
1134 
1135   if (element.HasID()) {
1136     features.CollectSiblingInvalidationSetForId(invalidation_lists, element,
1137                                                 element.IdForStyleResolution(),
1138                                                 min_direct_adjacent);
1139   }
1140 
1141   if (element.HasClass()) {
1142     const SpaceSplitString& class_names = element.ClassNames();
1143     for (wtf_size_t i = 0; i < class_names.size(); i++) {
1144       features.CollectSiblingInvalidationSetForClass(
1145           invalidation_lists, element, class_names[i], min_direct_adjacent);
1146     }
1147   }
1148 
1149   for (const Attribute& attribute : element.Attributes()) {
1150     features.CollectSiblingInvalidationSetForAttribute(
1151         invalidation_lists, element, attribute.GetName(), min_direct_adjacent);
1152   }
1153 
1154   features.CollectUniversalSiblingInvalidationSet(invalidation_lists,
1155                                                   min_direct_adjacent);
1156 
1157   pending_invalidations_.ScheduleSiblingInvalidationsAsDescendants(
1158       invalidation_lists, scheduling_parent);
1159 }
1160 
ScheduleInvalidationsForInsertedSibling(Element * before_element,Element & inserted_element)1161 void StyleEngine::ScheduleInvalidationsForInsertedSibling(
1162     Element* before_element,
1163     Element& inserted_element) {
1164   unsigned affected_siblings =
1165       inserted_element.parentNode()->ChildrenAffectedByIndirectAdjacentRules()
1166           ? SiblingInvalidationSet::kDirectAdjacentMax
1167           : MaxDirectAdjacentSelectors();
1168 
1169   ContainerNode* scheduling_parent =
1170       inserted_element.ParentElementOrShadowRoot();
1171   if (!scheduling_parent)
1172     return;
1173 
1174   ScheduleSiblingInvalidationsForElement(inserted_element, *scheduling_parent,
1175                                          1);
1176 
1177   for (unsigned i = 1; before_element && i <= affected_siblings;
1178        i++, before_element =
1179                 ElementTraversal::PreviousSibling(*before_element)) {
1180     ScheduleSiblingInvalidationsForElement(*before_element, *scheduling_parent,
1181                                            i);
1182   }
1183 }
1184 
ScheduleInvalidationsForRemovedSibling(Element * before_element,Element & removed_element,Element & after_element)1185 void StyleEngine::ScheduleInvalidationsForRemovedSibling(
1186     Element* before_element,
1187     Element& removed_element,
1188     Element& after_element) {
1189   unsigned affected_siblings =
1190       after_element.parentNode()->ChildrenAffectedByIndirectAdjacentRules()
1191           ? SiblingInvalidationSet::kDirectAdjacentMax
1192           : MaxDirectAdjacentSelectors();
1193 
1194   ContainerNode* scheduling_parent = after_element.ParentElementOrShadowRoot();
1195   if (!scheduling_parent)
1196     return;
1197 
1198   ScheduleSiblingInvalidationsForElement(removed_element, *scheduling_parent,
1199                                          1);
1200 
1201   for (unsigned i = 1; before_element && i <= affected_siblings;
1202        i++, before_element =
1203                 ElementTraversal::PreviousSibling(*before_element)) {
1204     ScheduleSiblingInvalidationsForElement(*before_element, *scheduling_parent,
1205                                            i);
1206   }
1207 }
1208 
ScheduleNthPseudoInvalidations(ContainerNode & nth_parent)1209 void StyleEngine::ScheduleNthPseudoInvalidations(ContainerNode& nth_parent) {
1210   InvalidationLists invalidation_lists;
1211   GetRuleFeatureSet().CollectNthInvalidationSet(invalidation_lists);
1212   pending_invalidations_.ScheduleInvalidationSetsForNode(invalidation_lists,
1213                                                          nth_parent);
1214 }
1215 
ScheduleRuleSetInvalidationsForElement(Element & element,const HeapHashSet<Member<RuleSet>> & rule_sets)1216 void StyleEngine::ScheduleRuleSetInvalidationsForElement(
1217     Element& element,
1218     const HeapHashSet<Member<RuleSet>>& rule_sets) {
1219   AtomicString id;
1220   const SpaceSplitString* class_names = nullptr;
1221 
1222   if (element.HasID())
1223     id = element.IdForStyleResolution();
1224   if (element.HasClass())
1225     class_names = &element.ClassNames();
1226 
1227   InvalidationLists invalidation_lists;
1228   for (const auto& rule_set : rule_sets) {
1229     if (!id.IsNull()) {
1230       rule_set->Features().CollectInvalidationSetsForId(invalidation_lists,
1231                                                         element, id);
1232     }
1233     if (class_names) {
1234       wtf_size_t class_name_count = class_names->size();
1235       for (wtf_size_t i = 0; i < class_name_count; i++) {
1236         rule_set->Features().CollectInvalidationSetsForClass(
1237             invalidation_lists, element, (*class_names)[i]);
1238       }
1239     }
1240     for (const Attribute& attribute : element.Attributes()) {
1241       rule_set->Features().CollectInvalidationSetsForAttribute(
1242           invalidation_lists, element, attribute.GetName());
1243     }
1244   }
1245   pending_invalidations_.ScheduleInvalidationSetsForNode(invalidation_lists,
1246                                                          element);
1247 }
1248 
ScheduleTypeRuleSetInvalidations(ContainerNode & node,const HeapHashSet<Member<RuleSet>> & rule_sets)1249 void StyleEngine::ScheduleTypeRuleSetInvalidations(
1250     ContainerNode& node,
1251     const HeapHashSet<Member<RuleSet>>& rule_sets) {
1252   InvalidationLists invalidation_lists;
1253   for (const auto& rule_set : rule_sets) {
1254     rule_set->Features().CollectTypeRuleInvalidationSet(invalidation_lists,
1255                                                         node);
1256   }
1257   DCHECK(invalidation_lists.siblings.IsEmpty());
1258   pending_invalidations_.ScheduleInvalidationSetsForNode(invalidation_lists,
1259                                                          node);
1260 
1261   auto* shadow_root = DynamicTo<ShadowRoot>(node);
1262   if (!shadow_root)
1263     return;
1264 
1265   Element& host = shadow_root->host();
1266   if (host.NeedsStyleRecalc())
1267     return;
1268 
1269   for (auto& invalidation_set : invalidation_lists.descendants) {
1270     if (invalidation_set->InvalidatesTagName(host)) {
1271       host.SetNeedsStyleRecalc(kLocalStyleChange,
1272                                StyleChangeReasonForTracing::Create(
1273                                    style_change_reason::kStyleSheetChange));
1274       return;
1275     }
1276   }
1277 }
1278 
ScheduleCustomElementInvalidations(HashSet<AtomicString> tag_names)1279 void StyleEngine::ScheduleCustomElementInvalidations(
1280     HashSet<AtomicString> tag_names) {
1281   scoped_refptr<DescendantInvalidationSet> invalidation_set =
1282       DescendantInvalidationSet::Create();
1283   for (auto& tag_name : tag_names) {
1284     invalidation_set->AddTagName(tag_name);
1285   }
1286   invalidation_set->SetTreeBoundaryCrossing();
1287   InvalidationLists invalidation_lists;
1288   invalidation_lists.descendants.push_back(invalidation_set);
1289   pending_invalidations_.ScheduleInvalidationSetsForNode(invalidation_lists,
1290                                                          *document_);
1291 }
1292 
InvalidateStyle()1293 void StyleEngine::InvalidateStyle() {
1294   StyleInvalidator style_invalidator(
1295       pending_invalidations_.GetPendingInvalidationMap());
1296   style_invalidator.Invalidate(GetDocument(),
1297                                style_invalidation_root_.RootElement());
1298   style_invalidation_root_.Clear();
1299 }
1300 
InvalidateSlottedElements(HTMLSlotElement & slot)1301 void StyleEngine::InvalidateSlottedElements(HTMLSlotElement& slot) {
1302   for (auto& node : slot.FlattenedAssignedNodes()) {
1303     if (node->IsElementNode()) {
1304       node->SetNeedsStyleRecalc(kLocalStyleChange,
1305                                 StyleChangeReasonForTracing::Create(
1306                                     style_change_reason::kStyleSheetChange));
1307     }
1308   }
1309 }
1310 
ScheduleInvalidationsForRuleSets(TreeScope & tree_scope,const HeapHashSet<Member<RuleSet>> & rule_sets,InvalidationScope invalidation_scope)1311 void StyleEngine::ScheduleInvalidationsForRuleSets(
1312     TreeScope& tree_scope,
1313     const HeapHashSet<Member<RuleSet>>& rule_sets,
1314     InvalidationScope invalidation_scope) {
1315 #if DCHECK_IS_ON()
1316   // Full scope recalcs should be handled while collecting the rule sets before
1317   // calling this method.
1318   for (auto rule_set : rule_sets)
1319     DCHECK(!rule_set->Features().NeedsFullRecalcForRuleSetInvalidation());
1320 #endif  // DCHECK_IS_ON()
1321 
1322   TRACE_EVENT0("blink,blink_style",
1323                "StyleEngine::scheduleInvalidationsForRuleSets");
1324 
1325   ScheduleTypeRuleSetInvalidations(tree_scope.RootNode(), rule_sets);
1326 
1327   bool invalidate_slotted = false;
1328   if (auto* shadow_root = DynamicTo<ShadowRoot>(&tree_scope.RootNode())) {
1329     Element& host = shadow_root->host();
1330     ScheduleRuleSetInvalidationsForElement(host, rule_sets);
1331     if (host.GetStyleChangeType() == kSubtreeStyleChange)
1332       return;
1333     for (auto rule_set : rule_sets) {
1334       if (rule_set->HasSlottedRules()) {
1335         invalidate_slotted = true;
1336         break;
1337       }
1338     }
1339   }
1340 
1341   Node* stay_within = &tree_scope.RootNode();
1342   Element* element = ElementTraversal::FirstChild(*stay_within);
1343   while (element) {
1344     ScheduleRuleSetInvalidationsForElement(*element, rule_sets);
1345     auto* html_slot_element = DynamicTo<HTMLSlotElement>(element);
1346     if (html_slot_element && invalidate_slotted)
1347       InvalidateSlottedElements(*html_slot_element);
1348 
1349     if (invalidation_scope == kInvalidateAllScopes) {
1350       if (ShadowRoot* shadow_root = element->GetShadowRoot()) {
1351         ScheduleInvalidationsForRuleSets(*shadow_root, rule_sets,
1352                                          kInvalidateAllScopes);
1353       }
1354     }
1355 
1356     if (element->GetStyleChangeType() < kSubtreeStyleChange &&
1357         element->GetComputedStyle()) {
1358       element = ElementTraversal::Next(*element, stay_within);
1359     } else {
1360       element = ElementTraversal::NextSkippingChildren(*element, stay_within);
1361     }
1362   }
1363 }
1364 
SetStatsEnabled(bool enabled)1365 void StyleEngine::SetStatsEnabled(bool enabled) {
1366   if (!enabled) {
1367     style_resolver_stats_ = nullptr;
1368     return;
1369   }
1370   if (!style_resolver_stats_)
1371     style_resolver_stats_ = std::make_unique<StyleResolverStats>();
1372   else
1373     style_resolver_stats_->Reset();
1374 }
1375 
SetPreferredStylesheetSetNameIfNotSet(const String & name)1376 void StyleEngine::SetPreferredStylesheetSetNameIfNotSet(const String& name) {
1377   DCHECK(!name.IsEmpty());
1378   if (!preferred_stylesheet_set_name_.IsEmpty())
1379     return;
1380   preferred_stylesheet_set_name_ = name;
1381   MarkDocumentDirty();
1382 }
1383 
SetHttpDefaultStyle(const String & content)1384 void StyleEngine::SetHttpDefaultStyle(const String& content) {
1385   if (!content.IsEmpty())
1386     SetPreferredStylesheetSetNameIfNotSet(content);
1387 }
1388 
EnsureUAStyleForXrOverlay()1389 void StyleEngine::EnsureUAStyleForXrOverlay() {
1390   DCHECK(!IsHTMLImport());
1391   DCHECK(global_rule_set_);
1392   if (CSSDefaultStyleSheets::Instance().EnsureDefaultStyleSheetForXrOverlay()) {
1393     global_rule_set_->MarkDirty();
1394     UpdateActiveStyle();
1395   }
1396 }
1397 
EnsureUAStyleForFullscreen()1398 void StyleEngine::EnsureUAStyleForFullscreen() {
1399   DCHECK(!IsHTMLImport());
1400   DCHECK(global_rule_set_);
1401   if (global_rule_set_->HasFullscreenUAStyle())
1402     return;
1403   CSSDefaultStyleSheets::Instance().EnsureDefaultStyleSheetForFullscreen();
1404   global_rule_set_->MarkDirty();
1405   UpdateActiveStyle();
1406 }
1407 
EnsureUAStyleForElement(const Element & element)1408 void StyleEngine::EnsureUAStyleForElement(const Element& element) {
1409   DCHECK(!IsHTMLImport());
1410   DCHECK(global_rule_set_);
1411   if (CSSDefaultStyleSheets::Instance().EnsureDefaultStyleSheetsForElement(
1412           element)) {
1413     global_rule_set_->MarkDirty();
1414     UpdateActiveStyle();
1415   }
1416 }
1417 
EnsureUAStyleForPseudoElement(PseudoId pseudo_id)1418 void StyleEngine::EnsureUAStyleForPseudoElement(PseudoId pseudo_id) {
1419   DCHECK(!IsHTMLImport());
1420   DCHECK(global_rule_set_);
1421   if (CSSDefaultStyleSheets::Instance()
1422           .EnsureDefaultStyleSheetsForPseudoElement(pseudo_id)) {
1423     global_rule_set_->MarkDirty();
1424     UpdateActiveStyle();
1425   }
1426 }
1427 
HasRulesForId(const AtomicString & id) const1428 bool StyleEngine::HasRulesForId(const AtomicString& id) const {
1429   DCHECK(!IsHTMLImport());
1430   DCHECK(global_rule_set_);
1431   return global_rule_set_->GetRuleFeatureSet().HasSelectorForId(id);
1432 }
1433 
InitialStyleChanged()1434 void StyleEngine::InitialStyleChanged() {
1435   if (viewport_resolver_)
1436     viewport_resolver_->InitialStyleChanged();
1437 
1438   // Media queries may rely on the initial font size relative lengths which may
1439   // have changed.
1440   MediaQueryAffectingValueChanged(MediaValueChange::kOther);
1441   MarkViewportStyleDirty();
1442   MarkAllElementsForStyleRecalc(
1443       StyleChangeReasonForTracing::Create(style_change_reason::kSettings));
1444 }
1445 
InitialViewportChanged()1446 void StyleEngine::InitialViewportChanged() {
1447   if (viewport_resolver_)
1448     viewport_resolver_->InitialViewportChanged();
1449 }
1450 
ViewportRulesChanged()1451 void StyleEngine::ViewportRulesChanged() {
1452   if (viewport_resolver_)
1453     viewport_resolver_->SetNeedsCollectRules();
1454 }
1455 
HtmlImportAddedOrRemoved()1456 void StyleEngine::HtmlImportAddedOrRemoved() {
1457   if (GetDocument().ImportLoader()) {
1458     GetDocument()
1459         .TreeRootDocument()
1460         .GetStyleEngine()
1461         .HtmlImportAddedOrRemoved();
1462     return;
1463   }
1464 
1465   // When we remove an import link and re-insert it into the document, the
1466   // import Document and CSSStyleSheet pointers are persisted. That means the
1467   // comparison of active stylesheets is not able to figure out that the order
1468   // of the stylesheets have changed after insertion.
1469   //
1470   // This is also the case when we import the same document twice where the
1471   // last inserted document is inserted before the first one in dom order where
1472   // the last would take precedence.
1473   //
1474   // Fall back to re-add all sheets to the scoped resolver and recalculate style
1475   // for the whole document when we remove or insert an import document.
1476   if (ScopedStyleResolver* resolver = GetDocument().GetScopedStyleResolver()) {
1477     MarkDocumentDirty();
1478     resolver->SetNeedsAppendAllSheets();
1479     MarkAllElementsForStyleRecalc(StyleChangeReasonForTracing::Create(
1480         style_change_reason::kActiveStylesheetsUpdate));
1481   }
1482 }
1483 
V0ShadowAddedOnV1Document()1484 void StyleEngine::V0ShadowAddedOnV1Document() {
1485   // No need to look into the ScopedStyleResolver for document, as ::slotted
1486   // never matches anything in a document tree.
1487   for (TreeScope* tree_scope : active_tree_scopes_) {
1488     if (ScopedStyleResolver* resolver = tree_scope->GetScopedStyleResolver())
1489       resolver->V0ShadowAddedOnV1Document();
1490   }
1491 }
1492 
1493 namespace {
1494 
1495 enum RuleSetFlags {
1496   kFontFaceRules = 1 << 0,
1497   kKeyframesRules = 1 << 1,
1498   kFullRecalcRules = 1 << 2,
1499   kPropertyRules = 1 << 3,
1500   kScrollTimelineRules = 1 << 4,
1501 };
1502 
GetRuleSetFlags(const HeapHashSet<Member<RuleSet>> rule_sets)1503 unsigned GetRuleSetFlags(const HeapHashSet<Member<RuleSet>> rule_sets) {
1504   unsigned flags = 0;
1505   for (auto& rule_set : rule_sets) {
1506     rule_set->CompactRulesIfNeeded();
1507     if (!rule_set->KeyframesRules().IsEmpty())
1508       flags |= kKeyframesRules;
1509     if (!rule_set->FontFaceRules().IsEmpty())
1510       flags |= kFontFaceRules;
1511     if (rule_set->NeedsFullRecalcForRuleSetInvalidation())
1512       flags |= kFullRecalcRules;
1513     if (!rule_set->PropertyRules().IsEmpty())
1514       flags |= kPropertyRules;
1515     if (!rule_set->ScrollTimelineRules().IsEmpty())
1516       flags |= kScrollTimelineRules;
1517   }
1518   return flags;
1519 }
1520 
1521 }  // namespace
1522 
InvalidateForRuleSetChanges(TreeScope & tree_scope,const HeapHashSet<Member<RuleSet>> & changed_rule_sets,unsigned changed_rule_flags,InvalidationScope invalidation_scope)1523 void StyleEngine::InvalidateForRuleSetChanges(
1524     TreeScope& tree_scope,
1525     const HeapHashSet<Member<RuleSet>>& changed_rule_sets,
1526     unsigned changed_rule_flags,
1527     InvalidationScope invalidation_scope) {
1528   if (tree_scope.GetDocument().HasPendingForcedStyleRecalc())
1529     return;
1530   if (!tree_scope.GetDocument().documentElement())
1531     return;
1532   if (changed_rule_sets.IsEmpty())
1533     return;
1534 
1535   Element& invalidation_root =
1536       ScopedStyleResolver::InvalidationRootForTreeScope(tree_scope);
1537   if (invalidation_root.GetStyleChangeType() == kSubtreeStyleChange)
1538     return;
1539 
1540   if (changed_rule_flags & kFullRecalcRules) {
1541     invalidation_root.SetNeedsStyleRecalc(
1542         kSubtreeStyleChange,
1543         StyleChangeReasonForTracing::Create(
1544             style_change_reason::kActiveStylesheetsUpdate));
1545     return;
1546   }
1547 
1548   if (changed_rule_sets.IsEmpty())
1549     return;
1550   ScheduleInvalidationsForRuleSets(tree_scope, changed_rule_sets,
1551                                    invalidation_scope);
1552 }
1553 
InvalidateInitialData()1554 void StyleEngine::InvalidateInitialData() {
1555   initial_data_ = nullptr;
1556 }
1557 
ApplyUserRuleSetChanges(const ActiveStyleSheetVector & old_style_sheets,const ActiveStyleSheetVector & new_style_sheets)1558 void StyleEngine::ApplyUserRuleSetChanges(
1559     const ActiveStyleSheetVector& old_style_sheets,
1560     const ActiveStyleSheetVector& new_style_sheets) {
1561   DCHECK(!IsHTMLImport());
1562   DCHECK(global_rule_set_);
1563   HeapHashSet<Member<RuleSet>> changed_rule_sets;
1564 
1565   ActiveSheetsChange change = CompareActiveStyleSheets(
1566       old_style_sheets, new_style_sheets, changed_rule_sets);
1567 
1568   if (change == kNoActiveSheetsChanged)
1569     return;
1570 
1571   // With rules added or removed, we need to re-aggregate rule meta data.
1572   global_rule_set_->MarkDirty();
1573 
1574   unsigned changed_rule_flags = GetRuleSetFlags(changed_rule_sets);
1575   bool has_rebuilt_font_face_cache = false;
1576   if (changed_rule_flags & kFontFaceRules) {
1577     if (ScopedStyleResolver* scoped_resolver =
1578             GetDocument().GetScopedStyleResolver()) {
1579       // User style and document scope author style shares the font cache. If
1580       // @font-face rules are added/removed from user stylesheets, we need to
1581       // reconstruct the font cache because @font-face rules from author style
1582       // need to be added to the cache after user rules.
1583       scoped_resolver->SetNeedsAppendAllSheets();
1584       MarkDocumentDirty();
1585     } else {
1586       has_rebuilt_font_face_cache = ClearFontFaceCacheAndAddUserFonts();
1587     }
1588   }
1589 
1590   if (changed_rule_flags & kKeyframesRules) {
1591     if (change == kActiveSheetsChanged)
1592       ClearKeyframeRules();
1593 
1594     for (auto* it = new_style_sheets.begin(); it != new_style_sheets.end();
1595          it++) {
1596       DCHECK(it->second);
1597       AddUserKeyframeRules(*it->second);
1598     }
1599     ScopedStyleResolver::KeyframesRulesAdded(GetDocument());
1600   }
1601 
1602   if (changed_rule_flags & (kPropertyRules | kScrollTimelineRules)) {
1603     if (changed_rule_flags & kPropertyRules) {
1604       ClearPropertyRules();
1605       AddPropertyRulesFromSheets(new_style_sheets);
1606     }
1607     if (changed_rule_flags & kScrollTimelineRules) {
1608       ClearScrollTimelineRules();
1609       AddScrollTimelineRulesFromSheets(new_style_sheets);
1610     }
1611 
1612     // We just cleared all the rules, which includes any author rules. They
1613     // must be forcibly re-added.
1614     if (ScopedStyleResolver* scoped_resolver =
1615             GetDocument().GetScopedStyleResolver()) {
1616       scoped_resolver->SetNeedsAppendAllSheets();
1617       MarkDocumentDirty();
1618     }
1619   }
1620 
1621   if ((changed_rule_flags & kFontFaceRules) || has_rebuilt_font_face_cache) {
1622     GetFontSelector()->FontFaceInvalidated(
1623         FontInvalidationReason::kGeneralInvalidation);
1624   }
1625 
1626   InvalidateForRuleSetChanges(GetDocument(), changed_rule_sets,
1627                               changed_rule_flags, kInvalidateAllScopes);
1628 }
1629 
ApplyRuleSetChanges(TreeScope & tree_scope,const ActiveStyleSheetVector & old_style_sheets,const ActiveStyleSheetVector & new_style_sheets)1630 void StyleEngine::ApplyRuleSetChanges(
1631     TreeScope& tree_scope,
1632     const ActiveStyleSheetVector& old_style_sheets,
1633     const ActiveStyleSheetVector& new_style_sheets) {
1634   DCHECK(!IsHTMLImport());
1635   DCHECK(global_rule_set_);
1636   HeapHashSet<Member<RuleSet>> changed_rule_sets;
1637 
1638   ActiveSheetsChange change = CompareActiveStyleSheets(
1639       old_style_sheets, new_style_sheets, changed_rule_sets);
1640 
1641   unsigned changed_rule_flags = GetRuleSetFlags(changed_rule_sets);
1642 
1643   bool rebuild_font_face_cache = change == kActiveSheetsChanged &&
1644                                  (changed_rule_flags & kFontFaceRules) &&
1645                                  tree_scope.RootNode().IsDocumentNode();
1646   bool rebuild_at_property_registry = false;
1647   bool rebuild_at_scroll_timeline_map = false;
1648   ScopedStyleResolver* scoped_resolver = tree_scope.GetScopedStyleResolver();
1649   if (scoped_resolver && scoped_resolver->NeedsAppendAllSheets()) {
1650     rebuild_font_face_cache = true;
1651     rebuild_at_property_registry = true;
1652     rebuild_at_scroll_timeline_map = true;
1653     change = kActiveSheetsChanged;
1654   }
1655 
1656   if (change == kNoActiveSheetsChanged)
1657     return;
1658 
1659   // With rules added or removed, we need to re-aggregate rule meta data.
1660   global_rule_set_->MarkDirty();
1661 
1662   if (changed_rule_flags & kKeyframesRules)
1663     ScopedStyleResolver::KeyframesRulesAdded(tree_scope);
1664 
1665   if ((changed_rule_flags & kPropertyRules) || rebuild_at_property_registry) {
1666     // @property rules are (for now) ignored in shadow trees, per spec.
1667     // https://drafts.css-houdini.org/css-properties-values-api-1/#at-property-rule
1668     if (tree_scope.RootNode().IsDocumentNode()) {
1669       ClearPropertyRules();
1670       AddPropertyRulesFromSheets(active_user_style_sheets_);
1671       AddPropertyRulesFromSheets(new_style_sheets);
1672     }
1673   }
1674 
1675   if ((changed_rule_flags & kScrollTimelineRules) ||
1676       rebuild_at_scroll_timeline_map) {
1677     // @scroll-timeline rules are currently not allowed in shadow trees.
1678     // https://drafts.csswg.org/scroll-animations-1/#scroll-timeline-at-rule
1679     if (tree_scope.RootNode().IsDocumentNode()) {
1680       ClearScrollTimelineRules();
1681       AddScrollTimelineRulesFromSheets(active_user_style_sheets_);
1682       AddScrollTimelineRulesFromSheets(new_style_sheets);
1683     }
1684   }
1685 
1686   bool has_rebuilt_font_face_cache = false;
1687   if (rebuild_font_face_cache)
1688     has_rebuilt_font_face_cache = ClearFontFaceCacheAndAddUserFonts();
1689 
1690   unsigned append_start_index = 0;
1691   if (scoped_resolver) {
1692     // - If all sheets were removed, we remove the ScopedStyleResolver.
1693     // - If new sheets were appended to existing ones, start appending after the
1694     //   common prefix.
1695     // - For other diffs, reset author style and re-add all sheets for the
1696     //   TreeScope.
1697     if (new_style_sheets.IsEmpty())
1698       ResetAuthorStyle(tree_scope);
1699     else if (change == kActiveSheetsAppended)
1700       append_start_index = old_style_sheets.size();
1701     else
1702       scoped_resolver->ResetAuthorStyle();
1703   }
1704 
1705   if (!new_style_sheets.IsEmpty()) {
1706     tree_scope.EnsureScopedStyleResolver().AppendActiveStyleSheets(
1707         append_start_index, new_style_sheets);
1708   }
1709 
1710   if (tree_scope.RootNode().IsDocumentNode()) {
1711     if ((changed_rule_flags & kFontFaceRules) || has_rebuilt_font_face_cache) {
1712       GetFontSelector()->FontFaceInvalidated(
1713           FontInvalidationReason::kGeneralInvalidation);
1714     }
1715   }
1716 
1717   InvalidateForRuleSetChanges(tree_scope, changed_rule_sets, changed_rule_flags,
1718                               kInvalidateCurrentScope);
1719 }
1720 
LoadVisionDeficiencyFilter()1721 void StyleEngine::LoadVisionDeficiencyFilter() {
1722   VisionDeficiency old_vision_deficiency = vision_deficiency_;
1723   vision_deficiency_ = GetDocument().GetPage()->GetVisionDeficiency();
1724   if (vision_deficiency_ == old_vision_deficiency)
1725     return;
1726 
1727   if (vision_deficiency_ == VisionDeficiency::kNoVisionDeficiency) {
1728     vision_deficiency_filter_ = nullptr;
1729   } else {
1730     AtomicString url = CreateVisionDeficiencyFilterUrl(vision_deficiency_);
1731     cssvalue::CSSURIValue css_uri_value(url);
1732     SVGResource* svg_resource = css_uri_value.EnsureResourceReference();
1733     // Note: The fact that we're using data: URLs here is an
1734     // implementation detail. Emulating vision deficiencies should still
1735     // work even if the Document's Content-Security-Policy disallows
1736     // data: URLs.
1737     svg_resource->LoadWithoutCSP(GetDocument());
1738     vision_deficiency_filter_ =
1739         MakeGarbageCollected<ReferenceFilterOperation>(url, svg_resource);
1740   }
1741 }
1742 
VisionDeficiencyChanged()1743 void StyleEngine::VisionDeficiencyChanged() {
1744   MarkViewportStyleDirty();
1745 }
1746 
ApplyVisionDeficiencyStyle(scoped_refptr<ComputedStyle> layout_view_style)1747 void StyleEngine::ApplyVisionDeficiencyStyle(
1748     scoped_refptr<ComputedStyle> layout_view_style) {
1749   LoadVisionDeficiencyFilter();
1750   if (vision_deficiency_filter_) {
1751     FilterOperations ops;
1752     ops.Operations().push_back(vision_deficiency_filter_);
1753     layout_view_style->SetFilter(ops);
1754   }
1755 }
1756 
EnsureMediaQueryEvaluator()1757 const MediaQueryEvaluator& StyleEngine::EnsureMediaQueryEvaluator() {
1758   if (!media_query_evaluator_) {
1759     if (GetDocument().GetFrame()) {
1760       media_query_evaluator_ =
1761           MakeGarbageCollected<MediaQueryEvaluator>(GetDocument().GetFrame());
1762     } else {
1763       media_query_evaluator_ = MakeGarbageCollected<MediaQueryEvaluator>("all");
1764     }
1765   }
1766   return *media_query_evaluator_;
1767 }
1768 
MediaQueryAffectedByViewportChange()1769 bool StyleEngine::MediaQueryAffectedByViewportChange() {
1770   DCHECK(!IsHTMLImport());
1771   DCHECK(global_rule_set_);
1772   return EnsureMediaQueryEvaluator().DidResultsChange(
1773       global_rule_set_->GetRuleFeatureSet()
1774           .ViewportDependentMediaQueryResults());
1775 }
1776 
MediaQueryAffectedByDeviceChange()1777 bool StyleEngine::MediaQueryAffectedByDeviceChange() {
1778   DCHECK(!IsHTMLImport());
1779   DCHECK(global_rule_set_);
1780   return EnsureMediaQueryEvaluator().DidResultsChange(
1781       global_rule_set_->GetRuleFeatureSet().DeviceDependentMediaQueryResults());
1782 }
1783 
UpdateRemUnits(const ComputedStyle * old_root_style,const ComputedStyle * new_root_style)1784 bool StyleEngine::UpdateRemUnits(const ComputedStyle* old_root_style,
1785                                  const ComputedStyle* new_root_style) {
1786   if (!new_root_style || !UsesRemUnits())
1787     return false;
1788   if (!old_root_style || old_root_style->SpecifiedFontSize() !=
1789                              new_root_style->SpecifiedFontSize()) {
1790     // Resolved rem units are stored in the matched properties cache so we need
1791     // to make sure to invalidate the cache if the documentElement font size
1792     // changes.
1793     GetStyleResolver().InvalidateMatchedPropertiesCache();
1794     return true;
1795   }
1796   return false;
1797 }
1798 
PropertyRegistryChanged()1799 void StyleEngine::PropertyRegistryChanged() {
1800   // TODO(timloh): Invalidate only elements with this custom property set
1801   MarkAllElementsForStyleRecalc(StyleChangeReasonForTracing::Create(
1802       style_change_reason::kPropertyRegistration));
1803   if (resolver_)
1804     resolver_->InvalidateMatchedPropertiesCache();
1805   InvalidateInitialData();
1806 }
1807 
EnvironmentVariableChanged()1808 void StyleEngine::EnvironmentVariableChanged() {
1809   MarkAllElementsForStyleRecalc(StyleChangeReasonForTracing::Create(
1810       style_change_reason::kPropertyRegistration));
1811   if (resolver_)
1812     resolver_->InvalidateMatchedPropertiesCache();
1813 }
1814 
MarkForWhitespaceReattachment()1815 void StyleEngine::MarkForWhitespaceReattachment() {
1816   for (auto element : whitespace_reattach_set_) {
1817     if (element->NeedsReattachLayoutTree() || !element->GetLayoutObject())
1818       continue;
1819       // This element might be located inside a display locked subtree, so we
1820       // might mark it for ReattachLayoutTree later on instead.
1821     if (Element* locked_ancestor =
1822             DisplayLockUtilities::NearestLockedInclusiveAncestor(*element)) {
1823       locked_ancestor->GetDisplayLockContext()->AddToWhitespaceReattachSet(
1824           *element);
1825       continue;
1826     }
1827     DCHECK(!element->NeedsStyleRecalc());
1828     DCHECK(!element->ChildNeedsStyleRecalc());
1829     if (Node* first_child = LayoutTreeBuilderTraversal::FirstChild(*element))
1830       first_child->MarkAncestorsWithChildNeedsReattachLayoutTree();
1831   }
1832 }
1833 
NodeWillBeRemoved(Node & node)1834 void StyleEngine::NodeWillBeRemoved(Node& node) {
1835   if (auto* element = DynamicTo<Element>(node)) {
1836     pending_invalidations_.RescheduleSiblingInvalidationsAsDescendants(
1837         *element);
1838   }
1839 
1840   // Mark closest ancestor with with LayoutObject to have all whitespace
1841   // children being considered for re-attachment during the layout tree build.
1842 
1843   LayoutObject* layout_object = node.GetLayoutObject();
1844   // The removed node does not have a layout object. No sibling whitespace nodes
1845   // will change rendering.
1846   if (!layout_object)
1847     return;
1848   // Floating or out-of-flow elements do not affect whitespace siblings.
1849   if (!layout_object->AffectsWhitespaceSiblings())
1850     return;
1851   layout_object = layout_object->Parent();
1852   while (layout_object->IsAnonymous())
1853     layout_object = layout_object->Parent();
1854   DCHECK(layout_object);
1855   DCHECK(layout_object->GetNode());
1856   if (auto* layout_object_element =
1857           DynamicTo<Element>(layout_object->GetNode())) {
1858     whitespace_reattach_set_.insert(layout_object_element);
1859     GetDocument().ScheduleLayoutTreeUpdateIfNeeded();
1860   }
1861 }
1862 
ChildrenRemoved(ContainerNode & parent)1863 void StyleEngine::ChildrenRemoved(ContainerNode& parent) {
1864   if (!parent.isConnected())
1865     return;
1866   if (in_dom_removal_) {
1867     // This is necessary for nested removals. There are elements which
1868     // removes parts of its UA shadow DOM as part of being removed which means
1869     // we do a removal from within another removal where isConnected() is not
1870     // completely up to date which would confuse this code. Instead we will
1871     // clean traversal roots properly when we are called from the outer remove.
1872     // TODO(crbug.com/882869): MediaControlLoadingPanelElement
1873     // TODO(crbug.com/888448): TextFieldInputType::ListAttributeTargetChanged
1874     return;
1875   }
1876   style_invalidation_root_.ChildrenRemoved(parent);
1877   style_recalc_root_.ChildrenRemoved(parent);
1878   DCHECK(!layout_tree_rebuild_root_.GetRootNode());
1879   layout_tree_rebuild_root_.ChildrenRemoved(parent);
1880 }
1881 
CollectMatchingUserRules(ElementRuleCollector & collector) const1882 void StyleEngine::CollectMatchingUserRules(
1883     ElementRuleCollector& collector) const {
1884   for (unsigned i = 0; i < active_user_style_sheets_.size(); ++i) {
1885     DCHECK(active_user_style_sheets_[i].second);
1886     collector.CollectMatchingRules(
1887         MatchRequest(active_user_style_sheets_[i].second, nullptr,
1888                      active_user_style_sheets_[i].first, i));
1889   }
1890 }
1891 
ClearPropertyRules()1892 void StyleEngine::ClearPropertyRules() {
1893   PropertyRegistration::RemoveDeclaredProperties(GetDocument());
1894 }
1895 
ClearScrollTimelineRules()1896 void StyleEngine::ClearScrollTimelineRules() {
1897   scroll_timeline_map_.clear();
1898 }
1899 
AddPropertyRulesFromSheets(const ActiveStyleSheetVector & sheets)1900 void StyleEngine::AddPropertyRulesFromSheets(
1901     const ActiveStyleSheetVector& sheets) {
1902   for (const ActiveStyleSheet& active_sheet : sheets) {
1903     if (RuleSet* rule_set = active_sheet.second)
1904       AddPropertyRules(*rule_set);
1905   }
1906 }
1907 
AddScrollTimelineRulesFromSheets(const ActiveStyleSheetVector & sheets)1908 void StyleEngine::AddScrollTimelineRulesFromSheets(
1909     const ActiveStyleSheetVector& sheets) {
1910   for (const ActiveStyleSheet& active_sheet : sheets) {
1911     if (RuleSet* rule_set = active_sheet.second)
1912       AddScrollTimelineRules(*rule_set);
1913   }
1914 }
1915 
AddUserFontFaceRules(const RuleSet & rule_set)1916 bool StyleEngine::AddUserFontFaceRules(const RuleSet& rule_set) {
1917   if (!font_selector_)
1918     return false;
1919 
1920   const HeapVector<Member<StyleRuleFontFace>> font_face_rules =
1921       rule_set.FontFaceRules();
1922   for (auto& font_face_rule : font_face_rules) {
1923     if (FontFace* font_face = FontFace::Create(document_, font_face_rule))
1924       font_selector_->GetFontFaceCache()->Add(font_face_rule, font_face);
1925   }
1926   if (resolver_ && font_face_rules.size())
1927     resolver_->InvalidateMatchedPropertiesCache();
1928   return font_face_rules.size();
1929 }
1930 
AddUserKeyframeRules(const RuleSet & rule_set)1931 void StyleEngine::AddUserKeyframeRules(const RuleSet& rule_set) {
1932   if (RuntimeEnabledFeatures::CSSKeyframesMemoryReductionEnabled())
1933     return;
1934 
1935   const HeapVector<Member<StyleRuleKeyframes>> keyframes_rules =
1936       rule_set.KeyframesRules();
1937   for (unsigned i = 0; i < keyframes_rules.size(); ++i)
1938     AddUserKeyframeStyle(keyframes_rules[i]);
1939 }
1940 
AddUserKeyframeStyle(StyleRuleKeyframes * rule)1941 void StyleEngine::AddUserKeyframeStyle(StyleRuleKeyframes* rule) {
1942   DCHECK(!RuntimeEnabledFeatures::CSSKeyframesMemoryReductionEnabled());
1943 
1944   AtomicString animation_name(rule->GetName());
1945 
1946   if (rule->IsVendorPrefixed()) {
1947     KeyframesRuleMap::iterator it = keyframes_rule_map_.find(animation_name);
1948     if (it == keyframes_rule_map_.end())
1949       keyframes_rule_map_.Set(animation_name, rule);
1950     else if (it->value->IsVendorPrefixed())
1951       keyframes_rule_map_.Set(animation_name, rule);
1952   } else {
1953     keyframes_rule_map_.Set(animation_name, rule);
1954   }
1955 }
1956 
AddPropertyRules(const RuleSet & rule_set)1957 void StyleEngine::AddPropertyRules(const RuleSet& rule_set) {
1958   const HeapVector<Member<StyleRuleProperty>> property_rules =
1959       rule_set.PropertyRules();
1960   for (unsigned i = 0; i < property_rules.size(); ++i) {
1961     StyleRuleProperty* rule = property_rules[i];
1962     AtomicString name(rule->GetName());
1963     PropertyRegistration::DeclareProperty(GetDocument(), name, *rule);
1964   }
1965 }
1966 
AddScrollTimelineRules(const RuleSet & rule_set)1967 void StyleEngine::AddScrollTimelineRules(const RuleSet& rule_set) {
1968   const HeapVector<Member<StyleRuleScrollTimeline>> scroll_timeline_rules =
1969       rule_set.ScrollTimelineRules();
1970   if (scroll_timeline_rules.IsEmpty())
1971     return;
1972   for (const auto& rule : scroll_timeline_rules)
1973     scroll_timeline_map_.Set(AtomicString(rule->GetName()), rule);
1974   MarkAllElementsForStyleRecalc(StyleChangeReasonForTracing::Create(
1975       style_change_reason::kScrollTimeline));
1976 }
1977 
KeyframeStylesForAnimation(const AtomicString & animation_name)1978 StyleRuleKeyframes* StyleEngine::KeyframeStylesForAnimation(
1979     const AtomicString& animation_name) {
1980   if (RuntimeEnabledFeatures::CSSKeyframesMemoryReductionEnabled()) {
1981     return ScopedStyleResolver::KeyframeStylesForAnimationFromActiveSheets(
1982         animation_name, active_user_style_sheets_);
1983   }
1984 
1985   if (keyframes_rule_map_.IsEmpty())
1986     return nullptr;
1987 
1988   KeyframesRuleMap::iterator it = keyframes_rule_map_.find(animation_name);
1989   if (it == keyframes_rule_map_.end())
1990     return nullptr;
1991 
1992   return it->value.Get();
1993 }
1994 
FindScrollTimelineRule(const AtomicString & name)1995 StyleRuleScrollTimeline* StyleEngine::FindScrollTimelineRule(
1996     const AtomicString& name) {
1997   return scroll_timeline_map_.at(name);
1998 }
1999 
EnsureEnvironmentVariables()2000 DocumentStyleEnvironmentVariables& StyleEngine::EnsureEnvironmentVariables() {
2001   if (!environment_variables_) {
2002     environment_variables_ = DocumentStyleEnvironmentVariables::Create(
2003         StyleEnvironmentVariables::GetRootInstance(), *document_);
2004   }
2005   return *environment_variables_.get();
2006 }
2007 
MaybeCreateAndGetInitialData()2008 scoped_refptr<StyleInitialData> StyleEngine::MaybeCreateAndGetInitialData() {
2009   if (initial_data_)
2010     return initial_data_;
2011   if (const PropertyRegistry* registry = document_->GetPropertyRegistry()) {
2012     if (!registry->IsEmpty())
2013       initial_data_ = StyleInitialData::Create(*registry);
2014   }
2015   return initial_data_;
2016 }
2017 
RecalcStyle()2018 void StyleEngine::RecalcStyle() {
2019   DCHECK(GetDocument().documentElement());
2020   Element* root_element = &style_recalc_root_.RootElement();
2021   Element* parent = root_element->ParentOrShadowHostElement();
2022 
2023   SelectorFilterRootScope filter_scope(parent);
2024   root_element->RecalcStyle({});
2025 
2026   for (ContainerNode* ancestor = root_element->GetStyleRecalcParent(); ancestor;
2027        ancestor = ancestor->GetStyleRecalcParent()) {
2028     if (auto* ancestor_element = DynamicTo<Element>(ancestor))
2029       ancestor_element->RecalcStyleForTraversalRootAncestor();
2030     ancestor->ClearChildNeedsStyleRecalc();
2031   }
2032   style_recalc_root_.Clear();
2033   PropagateWritingModeAndDirectionToHTMLRoot();
2034 }
2035 
ClearEnsuredDescendantStyles(Element & root)2036 void StyleEngine::ClearEnsuredDescendantStyles(Element& root) {
2037   Node* current = &root;
2038   while (current) {
2039     if (auto* element = DynamicTo<Element>(current)) {
2040       if (const auto* style = element->GetComputedStyle()) {
2041         DCHECK(style->IsEnsuredOutsideFlatTree());
2042         element->SetComputedStyle(nullptr);
2043         element->ClearNeedsStyleRecalc();
2044         element->ClearChildNeedsStyleRecalc();
2045         current = FlatTreeTraversal::Next(*current, &root);
2046         continue;
2047       }
2048     }
2049     current = FlatTreeTraversal::NextSkippingChildren(*current, &root);
2050   }
2051 }
2052 
RebuildLayoutTree()2053 void StyleEngine::RebuildLayoutTree() {
2054   DCHECK(GetDocument().documentElement());
2055   DCHECK(!InRebuildLayoutTree());
2056   in_layout_tree_rebuild_ = true;
2057 
2058   // We need a root scope here in case we recalc style for ::first-letter
2059   // elements as part of UpdateFirstLetterPseudoElement.
2060   SelectorFilterRootScope filter_scope(nullptr);
2061 
2062   Element& root_element = layout_tree_rebuild_root_.RootElement();
2063   {
2064     WhitespaceAttacher whitespace_attacher;
2065     root_element.RebuildLayoutTree(whitespace_attacher);
2066   }
2067 
2068   for (ContainerNode* ancestor = root_element.GetReattachParent(); ancestor;
2069        ancestor = ancestor->GetReattachParent()) {
2070     if (auto* ancestor_element = DynamicTo<Element>(ancestor))
2071       ancestor_element->RebuildLayoutTreeForTraversalRootAncestor();
2072     ancestor->ClearChildNeedsStyleRecalc();
2073     ancestor->ClearChildNeedsReattachLayoutTree();
2074   }
2075   layout_tree_rebuild_root_.Clear();
2076   in_layout_tree_rebuild_ = false;
2077 }
2078 
UpdateStyleAndLayoutTree()2079 void StyleEngine::UpdateStyleAndLayoutTree() {
2080   // All of layout tree dirtiness and rebuilding needs to happen on a stable
2081   // flat tree. We have an invariant that all of that happens in this method
2082   // as a result of style recalc and the following layout tree rebuild.
2083   //
2084   // NeedsReattachLayoutTree() marks dirty up the flat tree ancestors. Re-
2085   // slotting on a dirty tree could break ancestor chains and fail to update the
2086   // tree properly.
2087   DCHECK(!NeedsLayoutTreeRebuild());
2088 
2089   UpdateViewportStyle();
2090 
2091   if (Element* document_element = GetDocument().documentElement()) {
2092     NthIndexCache nth_index_cache(GetDocument());
2093     if (NeedsStyleRecalc()) {
2094       TRACE_EVENT0("blink,blink_style", "Document::recalcStyle");
2095       SCOPED_BLINK_UMA_HISTOGRAM_TIMER_HIGHRES("Style.RecalcTime");
2096       Element* viewport_defining = GetDocument().ViewportDefiningElement();
2097       RecalcStyle();
2098       if (viewport_defining != GetDocument().ViewportDefiningElement())
2099         ViewportDefiningElementDidChange();
2100     }
2101     MarkForWhitespaceReattachment();
2102     if (NeedsLayoutTreeRebuild()) {
2103       TRACE_EVENT0("blink,blink_style", "Document::rebuildLayoutTree");
2104       SCOPED_BLINK_UMA_HISTOGRAM_TIMER_HIGHRES("Style.RebuildLayoutTreeTime");
2105       RebuildLayoutTree();
2106     }
2107   } else {
2108     style_recalc_root_.Clear();
2109   }
2110   ClearWhitespaceReattachSet();
2111   UpdateColorSchemeBackground();
2112 }
2113 
ViewportDefiningElementDidChange()2114 void StyleEngine::ViewportDefiningElementDidChange() {
2115   HTMLBodyElement* body = GetDocument().FirstBodyElement();
2116   if (!body || body->NeedsReattachLayoutTree())
2117     return;
2118   LayoutObject* layout_object = body->GetLayoutObject();
2119   if (layout_object && layout_object->IsLayoutBlock()) {
2120     // When the overflow style for documentElement changes to or from visible,
2121     // it changes whether the body element's box should have scrollable overflow
2122     // on its own box or propagated to the viewport. If the body style did not
2123     // need a recalc, this will not be updated as its done as part of setting
2124     // ComputedStyle on the LayoutObject. Force a SetStyle for body when the
2125     // ViewportDefiningElement changes in order to trigger an update of
2126     // IsScrollContainer() and the PaintLayer in StyleDidChange().
2127     layout_object->SetStyle(ComputedStyle::Clone(*layout_object->Style()));
2128   }
2129 }
2130 
UpdateStyleInvalidationRoot(ContainerNode * ancestor,Node * dirty_node)2131 void StyleEngine::UpdateStyleInvalidationRoot(ContainerNode* ancestor,
2132                                               Node* dirty_node) {
2133   DCHECK(!IsHTMLImport());
2134   if (GetDocument().IsActive()) {
2135     if (in_dom_removal_) {
2136       ancestor = nullptr;
2137       dirty_node = document_;
2138     }
2139     style_invalidation_root_.Update(ancestor, dirty_node);
2140   }
2141 }
2142 
UpdateStyleRecalcRoot(ContainerNode * ancestor,Node * dirty_node)2143 void StyleEngine::UpdateStyleRecalcRoot(ContainerNode* ancestor,
2144                                         Node* dirty_node) {
2145   if (!GetDocument().IsActive())
2146     return;
2147   // We have at least one instance where we mark style dirty from style recalc
2148   // (from LayoutTextControl::StyleDidChange()). That means we are in the
2149   // process of traversing down the tree from the recalc root. Any updates to
2150   // the style recalc root will be cleared after the style recalc traversal
2151   // finishes and updating it may just trigger sanity DCHECKs in
2152   // StyleTraversalRoot. Just return here instead.
2153   if (GetDocument().InStyleRecalc()) {
2154     DCHECK(allow_mark_style_dirty_from_recalc_);
2155     return;
2156   }
2157   DCHECK(!in_layout_tree_rebuild_);
2158   if (in_dom_removal_) {
2159     ancestor = nullptr;
2160     dirty_node = document_;
2161   }
2162   style_recalc_root_.Update(ancestor, dirty_node);
2163 }
2164 
UpdateLayoutTreeRebuildRoot(ContainerNode * ancestor,Node * dirty_node)2165 void StyleEngine::UpdateLayoutTreeRebuildRoot(ContainerNode* ancestor,
2166                                               Node* dirty_node) {
2167   DCHECK(!in_dom_removal_);
2168   if (GetDocument().IsActive())
2169     layout_tree_rebuild_root_.Update(ancestor, dirty_node);
2170 }
2171 
SupportsDarkColorScheme()2172 bool StyleEngine::SupportsDarkColorScheme() {
2173   if (!meta_color_scheme_)
2174     return false;
2175   bool has_light = false;
2176   bool has_dark = false;
2177   if (const auto* scheme_list = DynamicTo<CSSValueList>(*meta_color_scheme_)) {
2178     for (auto& item : *scheme_list) {
2179       if (const auto* ident = DynamicTo<CSSIdentifierValue>(*item)) {
2180         if (ident->GetValueID() == CSSValueID::kDark)
2181           has_dark = true;
2182         else if (ident->GetValueID() == CSSValueID::kLight)
2183           has_light = true;
2184       }
2185     }
2186   }
2187   return has_dark &&
2188          (!has_light ||
2189           preferred_color_scheme_ == mojom::blink::PreferredColorScheme::kDark);
2190 }
2191 
UpdateColorScheme()2192 void StyleEngine::UpdateColorScheme() {
2193   auto* settings = GetDocument().GetSettings();
2194   auto* web_theme_engine =
2195       Platform::Current() ? Platform::Current()->ThemeEngine() : nullptr;
2196   if (!settings || !web_theme_engine)
2197     return;
2198 
2199   ForcedColors old_forced_colors = forced_colors_;
2200   forced_colors_ = web_theme_engine->GetForcedColors();
2201 
2202   mojom::blink::PreferredColorScheme old_preferred_color_scheme =
2203       preferred_color_scheme_;
2204   preferred_color_scheme_ = settings->GetPreferredColorScheme();
2205   if (const auto* overrides =
2206           GetDocument().GetPage()->GetMediaFeatureOverrides()) {
2207     MediaQueryExpValue value = overrides->GetOverride("prefers-color-scheme");
2208     if (value.IsValid())
2209       preferred_color_scheme_ = CSSValueIDToPreferredColorScheme(value.id);
2210   }
2211   if (!SupportsDarkColorScheme() && settings->GetForceDarkModeEnabled()) {
2212     // Make sure we don't match (prefers-color-scheme: dark) when forced
2213     // darkening is enabled.
2214     preferred_color_scheme_ = mojom::blink::PreferredColorScheme::kLight;
2215   }
2216   if (GetDocument().Printing())
2217     preferred_color_scheme_ = mojom::blink::PreferredColorScheme::kLight;
2218 
2219   bool color_scheme_changed = false;
2220   if (forced_colors_ != old_forced_colors ||
2221       preferred_color_scheme_ != old_preferred_color_scheme) {
2222     PlatformColorsChanged();
2223     color_scheme_changed = true;
2224   }
2225   UpdateColorSchemeBackground(color_scheme_changed);
2226 
2227   UpdateColorSchemeMetrics();
2228 }
2229 
UpdateColorSchemeMetrics()2230 void StyleEngine::UpdateColorSchemeMetrics() {
2231   auto* settings = GetDocument().GetSettings();
2232   if (settings->GetForceDarkModeEnabled())
2233     UseCounter::Count(GetDocument(), WebFeature::kForcedDarkMode);
2234 
2235   // True if the preferred color scheme will match dark.
2236   if (preferred_color_scheme_ == mojom::blink::PreferredColorScheme::kDark)
2237     UseCounter::Count(GetDocument(), WebFeature::kPreferredColorSchemeDark);
2238 
2239   // This is equal to kPreferredColorSchemeDark in most cases, but can differ
2240   // with forced dark mode. With the system in dark mode and forced dark mode
2241   // enabled, the preferred color scheme can be light while the setting is dark.
2242   if (settings->GetPreferredColorScheme() ==
2243       mojom::blink::PreferredColorScheme::kDark) {
2244     UseCounter::Count(GetDocument(),
2245                       WebFeature::kPreferredColorSchemeDarkSetting);
2246   }
2247 
2248   // Record kColorSchemeDarkSupportedOnRoot if the meta color-scheme contains
2249   // dark (though dark may not be used). This metric is also recorded in
2250   // longhands_custom.cc (see: ColorScheme::ApplyValue) if the root style
2251   // color-scheme contains dark.
2252   if (meta_color_scheme_) {
2253     const auto* scheme_list = DynamicTo<CSSValueList>(*meta_color_scheme_);
2254     if (scheme_list) {
2255       for (auto& item : *scheme_list) {
2256         const auto* ident = DynamicTo<CSSIdentifierValue>(*item);
2257         if (ident && ident->GetValueID() == CSSValueID::kDark) {
2258           UseCounter::Count(GetDocument(),
2259                             WebFeature::kColorSchemeDarkSupportedOnRoot);
2260         }
2261       }
2262     }
2263   }
2264 }
2265 
ColorSchemeChanged()2266 void StyleEngine::ColorSchemeChanged() {
2267   UpdateColorScheme();
2268 }
2269 
SetColorSchemeFromMeta(const CSSValue * color_scheme)2270 void StyleEngine::SetColorSchemeFromMeta(const CSSValue* color_scheme) {
2271   meta_color_scheme_ = color_scheme;
2272   DCHECK(GetDocument().documentElement());
2273   GetDocument().documentElement()->SetNeedsStyleRecalc(
2274       kLocalStyleChange, StyleChangeReasonForTracing::Create(
2275                              style_change_reason::kPlatformColorChange));
2276   UpdateColorScheme();
2277 }
2278 
UpdateColorSchemeBackground(bool color_scheme_changed)2279 void StyleEngine::UpdateColorSchemeBackground(bool color_scheme_changed) {
2280   LocalFrameView* view = GetDocument().View();
2281   if (!view)
2282     return;
2283 
2284   LocalFrameView::UseColorAdjustBackground use_color_adjust_background =
2285       LocalFrameView::UseColorAdjustBackground::kNo;
2286 
2287   if (forced_colors_ != ForcedColors::kNone) {
2288     if (GetDocument().IsInMainFrame()) {
2289       use_color_adjust_background =
2290           LocalFrameView::UseColorAdjustBackground::kIfBaseNotTransparent;
2291     }
2292   } else {
2293     // Find out if we should use a canvas color that is different from the
2294     // view's base background color in order to match the root element color-
2295     // scheme. See spec:
2296     // https://drafts.csswg.org/css-color-adjust/#color-scheme-effect
2297     mojom::blink::ColorScheme root_color_scheme =
2298         mojom::blink::ColorScheme::kLight;
2299     if (auto* root_element = GetDocument().documentElement()) {
2300       if (const ComputedStyle* style = root_element->GetComputedStyle())
2301         root_color_scheme = style->UsedColorSchemeForInitialColors();
2302       else if (SupportsDarkColorScheme())
2303         root_color_scheme = mojom::blink::ColorScheme::kDark;
2304     }
2305     color_scheme_background_ =
2306         root_color_scheme == mojom::blink::ColorScheme::kLight
2307             ? Color::kWhite
2308             : Color(0x12, 0x12, 0x12);
2309     if (GetDocument().IsInMainFrame()) {
2310       if (root_color_scheme == mojom::blink::ColorScheme::kDark) {
2311         use_color_adjust_background =
2312             LocalFrameView::UseColorAdjustBackground::kIfBaseNotTransparent;
2313       }
2314     } else if (root_color_scheme != owner_color_scheme_) {
2315       // Iframes should paint a solid background if the embedding iframe has a
2316       // used color-scheme different from the used color-scheme of the embedded
2317       // root element. Normally, iframes as transparent by default.
2318       use_color_adjust_background =
2319           LocalFrameView::UseColorAdjustBackground::kYes;
2320     }
2321   }
2322 
2323   view->SetUseColorAdjustBackground(use_color_adjust_background,
2324                                     color_scheme_changed);
2325 }
2326 
SetOwnerColorScheme(mojom::blink::ColorScheme color_scheme)2327 void StyleEngine::SetOwnerColorScheme(mojom::blink::ColorScheme color_scheme) {
2328   DCHECK(!GetDocument().IsInMainFrame());
2329   if (owner_color_scheme_ == color_scheme)
2330     return;
2331   owner_color_scheme_ = color_scheme;
2332   UpdateColorSchemeBackground(true);
2333 }
2334 
UpdateForcedBackgroundColor()2335 void StyleEngine::UpdateForcedBackgroundColor() {
2336   forced_background_color_ = LayoutTheme::GetTheme().SystemColor(
2337       CSSValueID::kCanvas, mojom::blink::ColorScheme::kLight);
2338 }
2339 
ColorAdjustBackgroundColor() const2340 Color StyleEngine::ColorAdjustBackgroundColor() const {
2341   if (forced_colors_ != ForcedColors::kNone)
2342     return ForcedBackgroundColor();
2343   return color_scheme_background_;
2344 }
2345 
MarkAllElementsForStyleRecalc(const StyleChangeReasonForTracing & reason)2346 void StyleEngine::MarkAllElementsForStyleRecalc(
2347     const StyleChangeReasonForTracing& reason) {
2348   if (Element* root = GetDocument().documentElement())
2349     root->SetNeedsStyleRecalc(kSubtreeStyleChange, reason);
2350 }
2351 
UpdateViewportStyle()2352 void StyleEngine::UpdateViewportStyle() {
2353   if (!viewport_style_dirty_)
2354     return;
2355 
2356   viewport_style_dirty_ = false;
2357 
2358   scoped_refptr<ComputedStyle> viewport_style = resolver_->StyleForViewport();
2359   if (ComputedStyle::ComputeDifference(
2360           viewport_style.get(), GetDocument().GetLayoutView()->Style()) !=
2361       ComputedStyle::Difference::kEqual) {
2362     GetDocument().GetLayoutView()->SetStyle(std::move(viewport_style));
2363   }
2364 }
2365 
NeedsFullStyleUpdate() const2366 bool StyleEngine::NeedsFullStyleUpdate() const {
2367   return NeedsActiveStyleUpdate() || NeedsWhitespaceReattachment() ||
2368          IsViewportStyleDirty();
2369 }
2370 
PropagateWritingModeAndDirectionToHTMLRoot()2371 void StyleEngine::PropagateWritingModeAndDirectionToHTMLRoot() {
2372   if (HTMLHtmlElement* root_element =
2373           DynamicTo<HTMLHtmlElement>(GetDocument().documentElement()))
2374     root_element->PropagateWritingModeAndDirectionFromBody();
2375 }
2376 
Trace(Visitor * visitor) const2377 void StyleEngine::Trace(Visitor* visitor) const {
2378   visitor->Trace(document_);
2379   visitor->Trace(injected_user_style_sheets_);
2380   visitor->Trace(injected_author_style_sheets_);
2381   visitor->Trace(active_user_style_sheets_);
2382   visitor->Trace(custom_element_default_style_sheets_);
2383   visitor->Trace(keyframes_rule_map_);
2384   visitor->Trace(scroll_timeline_map_);
2385   visitor->Trace(inspector_style_sheet_);
2386   visitor->Trace(document_style_sheet_collection_);
2387   visitor->Trace(style_sheet_collection_map_);
2388   visitor->Trace(dirty_tree_scopes_);
2389   visitor->Trace(active_tree_scopes_);
2390   visitor->Trace(tree_boundary_crossing_scopes_);
2391   visitor->Trace(resolver_);
2392   visitor->Trace(vision_deficiency_filter_);
2393   visitor->Trace(viewport_resolver_);
2394   visitor->Trace(media_query_evaluator_);
2395   visitor->Trace(global_rule_set_);
2396   visitor->Trace(pending_invalidations_);
2397   visitor->Trace(style_invalidation_root_);
2398   visitor->Trace(style_recalc_root_);
2399   visitor->Trace(layout_tree_rebuild_root_);
2400   visitor->Trace(whitespace_reattach_set_);
2401   visitor->Trace(font_selector_);
2402   visitor->Trace(text_to_sheet_cache_);
2403   visitor->Trace(sheet_to_text_cache_);
2404   visitor->Trace(tracker_);
2405   visitor->Trace(meta_color_scheme_);
2406   visitor->Trace(text_tracks_);
2407   visitor->Trace(vtt_originating_element_);
2408   FontSelectorClient::Trace(visitor);
2409 }
2410 
2411 }  // namespace blink
2412