1 /*
2  * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3  *           (C) 2004-2005 Allan Sandfeld Jensen (kde@carewolf.com)
4  * Copyright (C) 2006, 2007 Nicholas Shanks (webkit@nickshanks.com)
5  * Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 Apple Inc.
6  * All rights reserved.
7  * Copyright (C) 2007 Alexey Proskuryakov <ap@webkit.org>
8  * Copyright (C) 2007, 2008 Eric Seidel <eric@webkit.org>
9  * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved.
10  * (http://www.torchmobile.com/)
11  * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
12  * Copyright (C) Research In Motion Limited 2011. All rights reserved.
13  * Copyright (C) 2012 Google Inc. All rights reserved.
14  *
15  * This library is free software; you can redistribute it and/or
16  * modify it under the terms of the GNU Library General Public
17  * License as published by the Free Software Foundation; either
18  * version 2 of the License, or (at your option) any later version.
19  *
20  * This library is distributed in the hope that it will be useful,
21  * but WITHOUT ANY WARRANTY; without even the implied warranty of
22  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
23  * Library General Public License for more details.
24  *
25  * You should have received a copy of the GNU Library General Public License
26  * along with this library; see the file COPYING.LIB.  If not, write to
27  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
28  * Boston, MA 02110-1301, USA.
29  */
30 
31 #include "third_party/blink/renderer/core/css/resolver/style_resolver.h"
32 
33 #include "third_party/blink/renderer/core/animation/css/compositor_keyframe_value_factory.h"
34 #include "third_party/blink/renderer/core/animation/css/css_animations.h"
35 #include "third_party/blink/renderer/core/animation/element_animations.h"
36 #include "third_party/blink/renderer/core/animation/invalidatable_interpolation.h"
37 #include "third_party/blink/renderer/core/css/css_default_style_sheets.h"
38 #include "third_party/blink/renderer/core/css/css_font_selector.h"
39 #include "third_party/blink/renderer/core/css/css_identifier_value.h"
40 #include "third_party/blink/renderer/core/css/css_initial_color_value.h"
41 #include "third_party/blink/renderer/core/css/css_keyframe_rule.h"
42 #include "third_party/blink/renderer/core/css/css_keyframes_rule.h"
43 #include "third_party/blink/renderer/core/css/css_property_names.h"
44 #include "third_party/blink/renderer/core/css/css_rule_list.h"
45 #include "third_party/blink/renderer/core/css/css_selector.h"
46 #include "third_party/blink/renderer/core/css/css_selector_watch.h"
47 #include "third_party/blink/renderer/core/css/css_style_declaration.h"
48 #include "third_party/blink/renderer/core/css/css_style_rule.h"
49 #include "third_party/blink/renderer/core/css/element_rule_collector.h"
50 #include "third_party/blink/renderer/core/css/font_face.h"
51 #include "third_party/blink/renderer/core/css/page_rule_collector.h"
52 #include "third_party/blink/renderer/core/css/part_names.h"
53 #include "third_party/blink/renderer/core/css/properties/computed_style_utils.h"
54 #include "third_party/blink/renderer/core/css/properties/css_property.h"
55 #include "third_party/blink/renderer/core/css/properties/css_property_ref.h"
56 #include "third_party/blink/renderer/core/css/resolver/match_result.h"
57 #include "third_party/blink/renderer/core/css/resolver/scoped_style_resolver.h"
58 #include "third_party/blink/renderer/core/css/resolver/selector_filter_parent_scope.h"
59 #include "third_party/blink/renderer/core/css/resolver/style_adjuster.h"
60 #include "third_party/blink/renderer/core/css/resolver/style_builder_converter.h"
61 #include "third_party/blink/renderer/core/css/resolver/style_cascade.h"
62 #include "third_party/blink/renderer/core/css/resolver/style_resolver_state.h"
63 #include "third_party/blink/renderer/core/css/resolver/style_resolver_stats.h"
64 #include "third_party/blink/renderer/core/css/resolver/style_rule_usage_tracker.h"
65 #include "third_party/blink/renderer/core/css/scoped_css_value.h"
66 #include "third_party/blink/renderer/core/css/style_engine.h"
67 #include "third_party/blink/renderer/core/css/style_rule_import.h"
68 #include "third_party/blink/renderer/core/css/style_sheet_contents.h"
69 #include "third_party/blink/renderer/core/dom/first_letter_pseudo_element.h"
70 #include "third_party/blink/renderer/core/dom/node_computed_style.h"
71 #include "third_party/blink/renderer/core/dom/shadow_root.h"
72 #include "third_party/blink/renderer/core/dom/space_split_string.h"
73 #include "third_party/blink/renderer/core/dom/text.h"
74 #include "third_party/blink/renderer/core/frame/local_frame.h"
75 #include "third_party/blink/renderer/core/frame/local_frame_view.h"
76 #include "third_party/blink/renderer/core/frame/settings.h"
77 #include "third_party/blink/renderer/core/frame/web_feature.h"
78 #include "third_party/blink/renderer/core/html/custom/custom_element_definition.h"
79 #include "third_party/blink/renderer/core/html/html_iframe_element.h"
80 #include "third_party/blink/renderer/core/html/html_slot_element.h"
81 #include "third_party/blink/renderer/core/html/shadow/shadow_element_names.h"
82 #include "third_party/blink/renderer/core/html/track/text_track.h"
83 #include "third_party/blink/renderer/core/html/track/vtt/vtt_cue.h"
84 #include "third_party/blink/renderer/core/html/track/vtt/vtt_element.h"
85 #include "third_party/blink/renderer/core/html_names.h"
86 #include "third_party/blink/renderer/core/mathml/mathml_fraction_element.h"
87 #include "third_party/blink/renderer/core/mathml/mathml_operator_element.h"
88 #include "third_party/blink/renderer/core/mathml/mathml_padded_element.h"
89 #include "third_party/blink/renderer/core/mathml/mathml_space_element.h"
90 #include "third_party/blink/renderer/core/mathml_names.h"
91 #include "third_party/blink/renderer/core/media_type_names.h"
92 #include "third_party/blink/renderer/core/probe/core_probes.h"
93 #include "third_party/blink/renderer/core/style/style_initial_data.h"
94 #include "third_party/blink/renderer/core/style_property_shorthand.h"
95 #include "third_party/blink/renderer/core/svg/svg_element.h"
96 #include "third_party/blink/renderer/platform/heap/heap.h"
97 #include "third_party/blink/renderer/platform/instrumentation/use_counter.h"
98 #include "third_party/blink/renderer/platform/runtime_enabled_features.h"
99 #include "third_party/blink/renderer/platform/wtf/hash_set.h"
100 #include "third_party/blink/renderer/platform/wtf/std_lib_extras.h"
101 #include "third_party/blink/renderer/platform/wtf/text/atomic_string.h"
102 #include "third_party/blink/renderer/platform/wtf/text/atomic_string_hash.h"
103 
104 namespace blink {
105 
106 namespace {
107 
SetAnimationUpdateIfNeeded(StyleResolverState & state,Element & element)108 void SetAnimationUpdateIfNeeded(StyleResolverState& state, Element& element) {
109   // If any changes to CSS Animations were detected, stash the update away for
110   // application after the layout object is updated if we're in the appropriate
111   // scope.
112   if (!state.AnimationUpdate().IsEmpty()) {
113     auto& element_animations = element.EnsureElementAnimations();
114     element_animations.CssAnimations().SetPendingUpdate(
115         state.AnimationUpdate());
116   }
117 }
118 
HasAnimationsOrTransitions(const StyleResolverState & state)119 bool HasAnimationsOrTransitions(const StyleResolverState& state) {
120   return state.Style()->Animations() || state.Style()->Transitions() ||
121          (state.GetAnimatingElement() &&
122           state.GetAnimatingElement()->HasAnimations());
123 }
124 
ShouldComputeBaseComputedStyle(const ComputedStyle * base_computed_style)125 bool ShouldComputeBaseComputedStyle(const ComputedStyle* base_computed_style) {
126 #if DCHECK_IS_ON()
127   // The invariant in the base computed style optimization is that as long as
128   // |IsAnimationStyleChange| is true, the computed style that would be
129   // generated by the style resolver is equivalent to the one we hold
130   // internally. To ensure this, we always compute a new style here disregarding
131   // the fact that we have a base computed style when DCHECKs are enabled, and
132   // call ValidateBaseComputedStyle() to check that the optimization was sound.
133   return true;
134 #else
135   return !base_computed_style;
136 #endif  // !DCHECK_IS_ON()
137 }
138 
139 // Compare the base computed style with the one we compute to validate that the
140 // optimization is sound.
ValidateBaseComputedStyle(const ComputedStyle * base_computed_style,const ComputedStyle & computed_style)141 bool ValidateBaseComputedStyle(const ComputedStyle* base_computed_style,
142                                const ComputedStyle& computed_style) {
143 #if DCHECK_IS_ON()
144   if (!base_computed_style)
145     return true;
146   // Under certain conditions ComputedStyle::operator==() may return false for
147   // differences that are permitted during an animation.
148   // The FontFaceCache version number may be increased without forcing a style
149   // recalc (see crbug.com/471079).
150   if (!base_computed_style->GetFont().IsFallbackValid())
151     return true;
152   // Images use instance equality rather than value equality (see
153   // crbug.com/781461).
154   for (CSSPropertyID id :
155        {CSSPropertyID::kBackgroundImage, CSSPropertyID::kWebkitMaskImage}) {
156     if (!CSSPropertyEquality::PropertiesEqual(
157             PropertyHandle(CSSProperty::Get(id)), *base_computed_style,
158             computed_style)) {
159       return true;
160     }
161   }
162   return *base_computed_style == computed_style;
163 #else
164   return true;
165 #endif  // DCHECK_IS_ON()
166 }
167 
168 // When force-computing the base computed style for validation purposes,
169 // we need to reset the StyleCascade when the base computed style optimization
170 // is used. This is because we don't want the computation of the base to
171 // populate the cascade, as they are supposed to be empty when the optimization
172 // is in use. This is to match the behavior of non-DCHECK builds.
MaybeResetCascade(StyleCascade & cascade)173 void MaybeResetCascade(StyleCascade& cascade) {
174 #if DCHECK_IS_ON()
175   cascade.Reset();
176 #endif  // DCHECK_IS_ON()
177 }
178 
179 }  // namespace
180 
LeftToRightDeclaration()181 static CSSPropertyValueSet* LeftToRightDeclaration() {
182   DEFINE_STATIC_LOCAL(
183       Persistent<MutableCSSPropertyValueSet>, left_to_right_decl,
184       (MakeGarbageCollected<MutableCSSPropertyValueSet>(kHTMLQuirksMode)));
185   if (left_to_right_decl->IsEmpty()) {
186     left_to_right_decl->SetProperty(CSSPropertyID::kDirection,
187                                     CSSValueID::kLtr);
188   }
189   return left_to_right_decl;
190 }
191 
RightToLeftDeclaration()192 static CSSPropertyValueSet* RightToLeftDeclaration() {
193   DEFINE_STATIC_LOCAL(
194       Persistent<MutableCSSPropertyValueSet>, right_to_left_decl,
195       (MakeGarbageCollected<MutableCSSPropertyValueSet>(kHTMLQuirksMode)));
196   if (right_to_left_decl->IsEmpty()) {
197     right_to_left_decl->SetProperty(CSSPropertyID::kDirection,
198                                     CSSValueID::kRtl);
199   }
200   return right_to_left_decl;
201 }
202 
DocumentElementUserAgentDeclarations()203 static CSSPropertyValueSet* DocumentElementUserAgentDeclarations() {
204   DEFINE_STATIC_LOCAL(
205       Persistent<MutableCSSPropertyValueSet>, document_element_ua_decl,
206       (MakeGarbageCollected<MutableCSSPropertyValueSet>(kHTMLStandardMode)));
207   if (document_element_ua_decl->IsEmpty()) {
208     document_element_ua_decl->SetProperty(CSSPropertyID::kColor,
209                                           *CSSInitialColorValue::Create());
210   }
211   return document_element_ua_decl;
212 }
213 
CollectScopedResolversForHostedShadowTrees(const Element & element,HeapVector<Member<ScopedStyleResolver>,8> & resolvers)214 static void CollectScopedResolversForHostedShadowTrees(
215     const Element& element,
216     HeapVector<Member<ScopedStyleResolver>, 8>& resolvers) {
217   ShadowRoot* root = element.GetShadowRoot();
218   if (!root)
219     return;
220 
221   // Adding scoped resolver for active shadow roots for shadow host styling.
222   if (ScopedStyleResolver* resolver = root->GetScopedStyleResolver())
223     resolvers.push_back(resolver);
224 }
225 
StyleResolver(Document & document)226 StyleResolver::StyleResolver(Document& document) : document_(document) {
227   UpdateMediaType();
228 }
229 
230 StyleResolver::~StyleResolver() = default;
231 
Dispose()232 void StyleResolver::Dispose() {
233   matched_properties_cache_.Clear();
234 }
235 
SetRuleUsageTracker(StyleRuleUsageTracker * tracker)236 void StyleResolver::SetRuleUsageTracker(StyleRuleUsageTracker* tracker) {
237   tracker_ = tracker;
238 }
239 
ScopedResolverFor(const Element & element)240 static inline ScopedStyleResolver* ScopedResolverFor(const Element& element) {
241   // For normal elements, returning element->treeScope().scopedStyleResolver()
242   // is enough. Rules for ::cue and custom pseudo elements like
243   // ::-webkit-meter-bar pierce through a single shadow dom boundary and apply
244   // to elements in sub-scopes.
245   //
246   // An assumption here is that these elements belong to scopes without a
247   // ScopedStyleResolver due to the fact that VTT scopes and UA shadow trees
248   // don't have <style> or <link> elements. This is backed up by the DCHECKs
249   // below. The one exception to this assumption are the media controls which
250   // use a <style> element for CSS animations in the shadow DOM. If a <style>
251   // element is present in the shadow DOM then this will also block any
252   // author styling.
253 
254   TreeScope* tree_scope = &element.GetTreeScope();
255   if (ScopedStyleResolver* resolver = tree_scope->GetScopedStyleResolver()) {
256 #if DCHECK_IS_ON()
257     if (!element.HasMediaControlAncestor())
258       DCHECK(element.ShadowPseudoId().IsEmpty());
259 #endif
260     DCHECK(!element.IsVTTElement());
261     return resolver;
262   }
263 
264   tree_scope = tree_scope->ParentTreeScope();
265   if (!tree_scope)
266     return nullptr;
267   if (element.ShadowPseudoId().IsEmpty() && !element.IsVTTElement())
268     return nullptr;
269   return tree_scope->GetScopedStyleResolver();
270 }
271 
272 // Matches :host and :host-context rules if the element is a shadow host.
273 // It matches rules from the ShadowHostRules of the ScopedStyleResolver
274 // of the attached shadow root.
MatchHostRules(const Element & element,ElementRuleCollector & collector)275 static void MatchHostRules(const Element& element,
276                            ElementRuleCollector& collector) {
277   ShadowRoot* shadow_root = element.GetShadowRoot();
278   if (!shadow_root)
279     return;
280   if (ScopedStyleResolver* resolver = shadow_root->GetScopedStyleResolver())
281     resolver->CollectMatchingShadowHostRules(collector);
282 }
283 
284 // Matches custom element rules from Custom Element Default Style.
MatchCustomElementRules(const Element & element,ElementRuleCollector & collector)285 static void MatchCustomElementRules(const Element& element,
286                                     ElementRuleCollector& collector) {
287   if (!RuntimeEnabledFeatures::CustomElementDefaultStyleEnabled())
288     return;
289   if (CustomElementDefinition* definition =
290           element.GetCustomElementDefinition()) {
291     if (definition->HasDefaultStyleSheets()) {
292       for (CSSStyleSheet* style : definition->DefaultStyleSheets()) {
293         if (!style)
294           continue;
295         RuleSet* rule_set =
296             element.GetDocument().GetStyleEngine().RuleSetForSheet(*style);
297         if (rule_set)
298           collector.CollectMatchingRules(MatchRequest(rule_set));
299       }
300     }
301   }
302 }
303 
304 // Matches :host and :host-context rules
305 // and custom element rules from Custom Element Default Style.
MatchHostAndCustomElementRules(const Element & element,ElementRuleCollector & collector)306 static void MatchHostAndCustomElementRules(const Element& element,
307                                            ElementRuleCollector& collector) {
308   ShadowRoot* shadow_root = element.GetShadowRoot();
309   ScopedStyleResolver* resolver =
310       shadow_root ? shadow_root->GetScopedStyleResolver() : nullptr;
311   if (!resolver && !RuntimeEnabledFeatures::CustomElementDefaultStyleEnabled())
312     return;
313   collector.ClearMatchedRules();
314   MatchCustomElementRules(element, collector);
315   MatchHostRules(element, collector);
316   collector.SortAndTransferMatchedRules();
317   // TODO(futhark): If the resolver is null here, it means we are matching rules
318   // for custom element default styles. Since we don't have a
319   // ScopedStyleResolver if the custom element does not have a shadow root,
320   // there is no way to collect @-rules for @font-face, @keyframes, etc. We
321   // currently pass the element's TreeScope, which might not be what we want. It
322   // means that if you have:
323   //
324   //   <style>@keyframes anim { ... }</style>
325   //   <custom-element></custom-element>
326   //
327   // and the custom-element is defined with:
328   //
329   //   @keyframes anim { ... }
330   //   custom-element { animation-name: anim }
331   //
332   // it means that the custom element will pick up the @keyframes definition
333   // from the element's scope.
334   collector.FinishAddingAuthorRulesForTreeScope(
335       resolver ? resolver->GetTreeScope() : element.GetTreeScope());
336 }
337 
338 static void MatchSlottedRules(const Element&, ElementRuleCollector&);
MatchSlottedRulesForUAHost(const Element & element,ElementRuleCollector & collector)339 static void MatchSlottedRulesForUAHost(const Element& element,
340                                        ElementRuleCollector& collector) {
341   if (element.ShadowPseudoId() != shadow_element_names::kPseudoInputPlaceholder)
342     return;
343 
344   // We allow ::placeholder pseudo element after ::slotted(). Since we are
345   // matching such pseudo elements starting from inside the UA shadow DOM of
346   // the element having the placeholder, we need to match ::slotted rules from
347   // the scopes to which the placeholder's host element may be slotted.
348   //
349   // Example:
350   //
351   // <div id=host>
352   //   <:shadow-root>
353   //     <style>::slotted(input)::placeholder { color: green }</style>
354   //     <slot />
355   //   </:shadow-root>
356   //   <input placeholder="PLACEHOLDER-TEXT">
357   //     <:ua-shadow-root>
358   //       ... <placeholder>PLACEHOLDER-TEXT</placeholder> ...
359   //     </:ua-shadow-root>
360   //   </input>
361   // </div>
362   //
363   // Here we need to match the ::slotted rule from the #host shadow tree where
364   // the input is slotted on the placeholder element.
365   DCHECK(element.OwnerShadowHost());
366   MatchSlottedRules(*element.OwnerShadowHost(), collector);
367 }
368 
369 // Matches `::slotted` selectors. It matches rules in the element's slot's
370 // scope. If that slot is itself slotted it will match rules in the slot's
371 // slot's scope and so on. The result is that it considers a chain of scopes
372 // descending from the element's own scope.
MatchSlottedRules(const Element & element,ElementRuleCollector & collector)373 static void MatchSlottedRules(const Element& element,
374                               ElementRuleCollector& collector) {
375   MatchSlottedRulesForUAHost(element, collector);
376   HTMLSlotElement* slot = element.AssignedSlot();
377   if (!slot)
378     return;
379 
380   HeapVector<Member<ScopedStyleResolver>> resolvers;
381   for (; slot; slot = slot->AssignedSlot()) {
382     if (ScopedStyleResolver* resolver =
383             slot->GetTreeScope().GetScopedStyleResolver())
384       resolvers.push_back(resolver);
385   }
386   for (auto it = resolvers.rbegin(); it != resolvers.rend(); ++it) {
387     collector.ClearMatchedRules();
388     (*it)->CollectMatchingSlottedRules(collector);
389     collector.SortAndTransferMatchedRules();
390     collector.FinishAddingAuthorRulesForTreeScope((*it)->GetTreeScope());
391   }
392 }
393 
GetTextTrackFromElement(const Element & element)394 const static TextTrack* GetTextTrackFromElement(const Element& element) {
395   if (auto* vtt_element = DynamicTo<VTTElement>(element))
396     return vtt_element->GetTrack();
397   if (auto* vtt_cue_background_box = DynamicTo<VTTCueBackgroundBox>(element))
398     return vtt_cue_background_box->GetTrack();
399   return nullptr;
400 }
401 
MatchVTTRules(const Element & element,ElementRuleCollector & collector)402 static void MatchVTTRules(const Element& element,
403                                   ElementRuleCollector& collector) {
404   const TextTrack* text_track = GetTextTrackFromElement(element);
405   if (!text_track)
406     return;
407   const HeapVector<Member<CSSStyleSheet>>& styles =
408       text_track->GetCSSStyleSheets();
409   if (!styles.IsEmpty()) {
410     int style_sheet_index = 0;
411     collector.ClearMatchedRules();
412     for (CSSStyleSheet* style : styles) {
413       StyleEngine& style_engine = element.GetDocument().GetStyleEngine();
414       RuleSet* rule_set = style_engine.RuleSetForSheet(*style);
415       if (rule_set) {
416         collector.CollectMatchingRules(MatchRequest(
417             rule_set, nullptr /* scope */, style, style_sheet_index,
418             style_engine.EnsureVTTOriginatingElement()));
419         style_sheet_index++;
420       }
421     }
422     collector.SortAndTransferMatchedRules();
423   }
424 }
425 
426 // Matches rules from the element's scope. The selectors may cross shadow
427 // boundaries during matching, like for :host-context.
MatchElementScopeRules(const Element & element,ScopedStyleResolver * element_scope_resolver,ElementRuleCollector & collector)428 static void MatchElementScopeRules(const Element& element,
429                                    ScopedStyleResolver* element_scope_resolver,
430                                    ElementRuleCollector& collector) {
431   if (element_scope_resolver) {
432     collector.ClearMatchedRules();
433     element_scope_resolver->CollectMatchingAuthorRules(collector);
434     element_scope_resolver->CollectMatchingTreeBoundaryCrossingRules(collector);
435     collector.SortAndTransferMatchedRules();
436   }
437 
438   MatchVTTRules(element, collector);
439   if (element.IsStyledElement() && element.InlineStyle() &&
440       !collector.IsCollectingForPseudoElement()) {
441     // Inline style is immutable as long as there is no CSSOM wrapper.
442     bool is_inline_style_cacheable = !element.InlineStyle()->IsMutable();
443     collector.AddElementStyleProperties(element.InlineStyle(),
444                                         is_inline_style_cacheable);
445   }
446 
447   collector.FinishAddingAuthorRulesForTreeScope(
448       element_scope_resolver ? element_scope_resolver->GetTreeScope()
449                              : element.GetTreeScope());
450 }
451 
MatchPseudoPartRulesForUAHost(const Element & element,ElementRuleCollector & collector)452 void StyleResolver::MatchPseudoPartRulesForUAHost(
453     const Element& element,
454     ElementRuleCollector& collector) {
455   if (element.ShadowPseudoId() != shadow_element_names::kPseudoInputPlaceholder)
456     return;
457 
458   // We allow ::placeholder pseudo element after ::part(). See
459   // MatchSlottedRulesForUAHost for a more detailed explanation.
460   DCHECK(element.OwnerShadowHost());
461   MatchPseudoPartRules(*element.OwnerShadowHost(), collector);
462 }
463 
MatchPseudoPartRules(const Element & element,ElementRuleCollector & collector)464 void StyleResolver::MatchPseudoPartRules(const Element& element,
465                                          ElementRuleCollector& collector) {
466   MatchPseudoPartRulesForUAHost(element, collector);
467   DOMTokenList* part = element.GetPart();
468   if (!part)
469     return;
470 
471   PartNames current_names(part->TokenSet());
472 
473   // ::part selectors in the shadow host's scope and above can match this
474   // element.
475   Element* host = element.OwnerShadowHost();
476   if (!host)
477     return;
478 
479   while (current_names.size()) {
480     TreeScope& tree_scope = host->GetTreeScope();
481     if (ScopedStyleResolver* resolver = tree_scope.GetScopedStyleResolver()) {
482       collector.ClearMatchedRules();
483       resolver->CollectMatchingPartPseudoRules(collector, current_names);
484       collector.SortAndTransferMatchedRules();
485       collector.FinishAddingAuthorRulesForTreeScope(resolver->GetTreeScope());
486     }
487 
488     // If the host doesn't forward any parts using partmap= then the element is
489     // unreachable from any scope further above and we can stop.
490     const NamesMap* part_map = host->PartNamesMap();
491     if (!part_map)
492       return;
493 
494     // We have reached the top-level document.
495     if (!(host = host->OwnerShadowHost()))
496       return;
497 
498     current_names.PushMap(*part_map);
499   }
500 }
501 
ShouldCheckScope(const Element & element,const Node & scoping_node,bool is_inner_tree_scope)502 static bool ShouldCheckScope(const Element& element,
503                              const Node& scoping_node,
504                              bool is_inner_tree_scope) {
505   if (is_inner_tree_scope &&
506       element.GetTreeScope() != scoping_node.GetTreeScope()) {
507     // Check if |element| may be affected by a ::content rule in |scopingNode|'s
508     // style.  If |element| is a descendant of a shadow host which is ancestral
509     // to |scopingNode|, the |element| should be included for rule collection.
510     // Skip otherwise.
511     const TreeScope* scope = &scoping_node.GetTreeScope();
512     while (scope && scope->ParentTreeScope() != &element.GetTreeScope())
513       scope = scope->ParentTreeScope();
514     Element* shadow_host =
515         scope ? scope->RootNode().OwnerShadowHost() : nullptr;
516     return shadow_host && element.IsDescendantOf(shadow_host);
517   }
518 
519   // When |element| can be distributed to |scopingNode| via <shadow>, ::content
520   // rule can match, thus the case should be included.
521   if (!is_inner_tree_scope &&
522       scoping_node.ParentOrShadowHostNode() ==
523           element.GetTreeScope().RootNode().ParentOrShadowHostNode())
524     return true;
525 
526   // Obviously cases when ancestor scope has /deep/ or ::shadow rule should be
527   // included.  Skip otherwise.
528   return scoping_node.GetTreeScope()
529       .GetScopedStyleResolver()
530       ->HasDeepOrShadowSelector();
531 }
532 
MatchScopedRulesV0(const Element & element,ElementRuleCollector & collector,ScopedStyleResolver * element_scope_resolver)533 void StyleResolver::MatchScopedRulesV0(
534     const Element& element,
535     ElementRuleCollector& collector,
536     ScopedStyleResolver* element_scope_resolver) {
537   // Match rules from treeScopes in the reverse tree-of-trees order, since the
538   // cascading order for normal rules is such that when comparing rules from
539   // different shadow trees, the rule from the tree which comes first in the
540   // tree-of-trees order wins. From other treeScopes than the element's own
541   // scope, only tree-boundary-crossing rules may match.
542 
543   bool match_element_scope_done =
544       !element_scope_resolver && !element.InlineStyle();
545 
546   const auto& tree_boundary_crossing_scopes =
547       GetDocument().GetStyleEngine().TreeBoundaryCrossingScopes();
548   for (auto it = tree_boundary_crossing_scopes.rbegin();
549        it != tree_boundary_crossing_scopes.rend(); ++it) {
550     const TreeScope& scope = (*it)->ContainingTreeScope();
551     ScopedStyleResolver* resolver = scope.GetScopedStyleResolver();
552     DCHECK(resolver);
553 
554     bool is_inner_tree_scope =
555         element.ContainingTreeScope().IsInclusiveAncestorOf(scope);
556     if (!ShouldCheckScope(element, **it, is_inner_tree_scope))
557       continue;
558 
559     if (!match_element_scope_done &&
560         scope.IsInclusiveAncestorOf(element.ContainingTreeScope())) {
561       match_element_scope_done = true;
562 
563       // At this point, the iterator has either encountered the scope for the
564       // element itself (if that scope has boundary-crossing rules), or the
565       // iterator has moved to a scope which appears before the element's scope
566       // in the tree-of-trees order.  Try to match all rules from the element's
567       // scope.
568 
569       MatchElementScopeRules(element, element_scope_resolver, collector);
570       if (resolver == element_scope_resolver) {
571         // Boundary-crossing rules already collected in matchElementScopeRules.
572         continue;
573       }
574     }
575 
576     collector.ClearMatchedRules();
577     resolver->CollectMatchingTreeBoundaryCrossingRules(collector);
578     collector.SortAndTransferMatchedRules();
579     collector.FinishAddingAuthorRulesForTreeScope(resolver->GetTreeScope());
580   }
581 
582   if (!match_element_scope_done)
583     MatchElementScopeRules(element, element_scope_resolver, collector);
584 }
585 
MatchAuthorRules(const Element & element,ScopedStyleResolver * element_scope_resolver,ElementRuleCollector & collector)586 void StyleResolver::MatchAuthorRules(
587     const Element& element,
588     ScopedStyleResolver* element_scope_resolver,
589     ElementRuleCollector& collector) {
590   if (GetDocument().GetShadowCascadeOrder() ==
591       ShadowCascadeOrder::kShadowCascadeV0) {
592     MatchAuthorRulesV0(element, element_scope_resolver, collector);
593     return;
594   }
595   MatchHostAndCustomElementRules(element, collector);
596 
597   if (GetDocument().MayContainV0Shadow()) {
598     MatchScopedRulesV0(element, collector, element_scope_resolver);
599     return;
600   }
601 
602   MatchSlottedRules(element, collector);
603   MatchElementScopeRules(element, element_scope_resolver, collector);
604   MatchPseudoPartRules(element, collector);
605 }
606 
MatchAuthorRulesV0(const Element & element,ScopedStyleResolver * element_scope_resolver,ElementRuleCollector & collector)607 void StyleResolver::MatchAuthorRulesV0(
608     const Element& element,
609     ScopedStyleResolver* element_scope_resolver,
610     ElementRuleCollector& collector) {
611   collector.ClearMatchedRules();
612 
613   ShadowV0CascadeOrder cascade_order = 0;
614   HeapVector<Member<ScopedStyleResolver>, 8> resolvers_in_shadow_tree;
615   CollectScopedResolversForHostedShadowTrees(element, resolvers_in_shadow_tree);
616 
617   // Apply :host and :host-context rules from inner scopes.
618   for (int j = resolvers_in_shadow_tree.size() - 1; j >= 0; --j)
619     resolvers_in_shadow_tree.at(j)->CollectMatchingShadowHostRules(
620         collector, ++cascade_order);
621 
622   // Apply normal rules from element scope.
623   if (element_scope_resolver) {
624     element_scope_resolver->CollectMatchingAuthorRules(collector,
625                                                        ++cascade_order);
626   }
627 
628   // Apply /deep/ and ::shadow rules from outer scopes, and ::content from
629   // inner.
630   CollectTreeBoundaryCrossingRulesV0CascadeOrder(element, collector);
631   collector.SortAndTransferMatchedRules();
632 }
633 
MatchUserRules(ElementRuleCollector & collector)634 void StyleResolver::MatchUserRules(ElementRuleCollector& collector) {
635   collector.ClearMatchedRules();
636   GetDocument().GetStyleEngine().CollectMatchingUserRules(collector);
637   collector.SortAndTransferMatchedRules();
638   collector.FinishAddingUserRules();
639 }
640 
MatchUARules(const Element & element,ElementRuleCollector & collector)641 void StyleResolver::MatchUARules(const Element& element,
642                                  ElementRuleCollector& collector) {
643   collector.SetMatchingUARules(true);
644 
645   CSSDefaultStyleSheets& default_style_sheets =
646       CSSDefaultStyleSheets::Instance();
647   if (!print_media_type_) {
648     if (LIKELY(element.IsHTMLElement() || element.IsVTTElement()))
649       MatchRuleSet(collector, default_style_sheets.DefaultStyle());
650     else if (element.IsSVGElement())
651       MatchRuleSet(collector, default_style_sheets.DefaultSVGStyle());
652     else if (element.namespaceURI() == mathml_names::kNamespaceURI)
653       MatchRuleSet(collector, default_style_sheets.DefaultMathMLStyle());
654   } else {
655     MatchRuleSet(collector, default_style_sheets.DefaultPrintStyle());
656   }
657 
658   // In quirks mode, we match rules from the quirks user agent sheet.
659   if (GetDocument().InQuirksMode())
660     MatchRuleSet(collector, default_style_sheets.DefaultQuirksStyle());
661 
662   // If document uses view source styles (in view source mode or in xml viewer
663   // mode), then we match rules from the view source style sheet.
664   if (GetDocument().IsViewSource())
665     MatchRuleSet(collector, default_style_sheets.DefaultViewSourceStyle());
666 
667   // If the system is in forced colors mode, match rules from the forced colors
668   // style sheet.
669   if (IsForcedColorsModeEnabled())
670     MatchRuleSet(collector, default_style_sheets.DefaultForcedColorStyle());
671 
672   if (collector.IsCollectingForPseudoElement()) {
673     if (RuleSet* default_pseudo_style =
674             default_style_sheets.DefaultPseudoElementStyleOrNull())
675       MatchRuleSet(collector, default_pseudo_style);
676   }
677 
678   collector.FinishAddingUARules();
679   collector.SetMatchingUARules(false);
680 }
681 
MatchRuleSet(ElementRuleCollector & collector,RuleSet * rules)682 void StyleResolver::MatchRuleSet(ElementRuleCollector& collector,
683                                  RuleSet* rules) {
684   collector.ClearMatchedRules();
685   collector.CollectMatchingRules(MatchRequest(rules));
686   collector.SortAndTransferMatchedRules();
687 }
688 
689 DISABLE_CFI_PERF
MatchAllRules(StyleResolverState & state,ElementRuleCollector & collector,bool include_smil_properties)690 void StyleResolver::MatchAllRules(StyleResolverState& state,
691                                   ElementRuleCollector& collector,
692                                   bool include_smil_properties) {
693   Element& element = state.GetElement();
694   MatchUARules(element, collector);
695   MatchUserRules(collector);
696 
697   // Now check author rules, beginning first with presentational attributes
698   // mapped from HTML.
699   if (element.IsStyledElement() && !state.IsForPseudoElement()) {
700     collector.AddElementStyleProperties(element.PresentationAttributeStyle());
701 
702     // Now we check additional mapped declarations.
703     // Tables and table cells share an additional mapped rule that must be
704     // applied after all attributes, since their mapped style depends on the
705     // values of multiple attributes.
706     collector.AddElementStyleProperties(
707         element.AdditionalPresentationAttributeStyle());
708 
709     if (auto* html_element = DynamicTo<HTMLElement>(element)) {
710       bool is_auto;
711       TextDirection text_direction =
712           html_element->DirectionalityIfhasDirAutoAttribute(is_auto);
713       if (is_auto) {
714         state.SetHasDirAutoAttribute(true);
715         collector.AddElementStyleProperties(
716             text_direction == TextDirection::kLtr ? LeftToRightDeclaration()
717                                                   : RightToLeftDeclaration());
718       }
719     }
720   }
721 
722   ScopedStyleResolver* element_scope_resolver = ScopedResolverFor(element);
723   MatchAuthorRules(element, element_scope_resolver, collector);
724 
725   if (element.IsStyledElement() && !state.IsForPseudoElement()) {
726     // For Shadow DOM V1, inline style is already collected in
727     // matchScopedRules().
728     if (GetDocument().GetShadowCascadeOrder() ==
729             ShadowCascadeOrder::kShadowCascadeV0 &&
730         element.InlineStyle()) {
731       // Inline style is immutable as long as there is no CSSOM wrapper.
732       bool is_inline_style_cacheable = !element.InlineStyle()->IsMutable();
733       collector.AddElementStyleProperties(element.InlineStyle(),
734                                           is_inline_style_cacheable);
735     }
736 
737     // Now check SMIL animation override style.
738     auto* svg_element = DynamicTo<SVGElement>(element);
739     if (include_smil_properties && svg_element) {
740       collector.AddElementStyleProperties(
741           svg_element->AnimatedSMILStyleProperties(), false /* isCacheable */);
742     }
743   }
744 
745   collector.FinishAddingAuthorRulesForTreeScope(
746       element_scope_resolver ? element_scope_resolver->GetTreeScope()
747                              : element.GetTreeScope());
748 }
749 
CollectTreeBoundaryCrossingRulesV0CascadeOrder(const Element & element,ElementRuleCollector & collector)750 void StyleResolver::CollectTreeBoundaryCrossingRulesV0CascadeOrder(
751     const Element& element,
752     ElementRuleCollector& collector) {
753   const auto& tree_boundary_crossing_scopes =
754       GetDocument().GetStyleEngine().TreeBoundaryCrossingScopes();
755   if (tree_boundary_crossing_scopes.IsEmpty())
756     return;
757 
758   // When comparing rules declared in outer treescopes, outer's rules win.
759   ShadowV0CascadeOrder outer_cascade_order =
760       tree_boundary_crossing_scopes.size() * 2;
761   // When comparing rules declared in inner treescopes, inner's rules win.
762   ShadowV0CascadeOrder inner_cascade_order =
763       tree_boundary_crossing_scopes.size();
764 
765   for (const auto& scoping_node : tree_boundary_crossing_scopes) {
766     // Skip rule collection for element when tree boundary crossing rules of
767     // scopingNode's scope can never apply to it.
768     bool is_inner_tree_scope =
769         element.ContainingTreeScope().IsInclusiveAncestorOf(
770             scoping_node->ContainingTreeScope());
771     if (!ShouldCheckScope(element, *scoping_node, is_inner_tree_scope))
772       continue;
773 
774     ShadowV0CascadeOrder cascade_order =
775         is_inner_tree_scope ? inner_cascade_order : outer_cascade_order;
776     scoping_node->GetTreeScope()
777         .GetScopedStyleResolver()
778         ->CollectMatchingTreeBoundaryCrossingRules(collector, cascade_order);
779 
780     ++inner_cascade_order;
781     --outer_cascade_order;
782   }
783 }
784 
StyleForViewport()785 scoped_refptr<ComputedStyle> StyleResolver::StyleForViewport() {
786   scoped_refptr<ComputedStyle> viewport_style =
787       InitialStyleForElement(GetDocument());
788 
789   viewport_style->SetZIndex(0);
790   viewport_style->SetIsStackingContextWithoutContainment(true);
791   viewport_style->SetDisplay(EDisplay::kBlock);
792   viewport_style->SetPosition(EPosition::kAbsolute);
793 
794   // Document::InheritHtmlAndBodyElementStyles will set the final overflow
795   // style values, but they should initially be auto to avoid premature
796   // scrollbar removal in PaintLayerScrollableArea::UpdateAfterStyleChange.
797   viewport_style->SetOverflowX(EOverflow::kAuto);
798   viewport_style->SetOverflowY(EOverflow::kAuto);
799 
800   GetDocument().GetStyleEngine().ApplyVisionDeficiencyStyle(viewport_style);
801 
802   return viewport_style;
803 }
804 
GetElementAnimations(const StyleResolverState & state)805 static ElementAnimations* GetElementAnimations(
806     const StyleResolverState& state) {
807   if (!state.GetAnimatingElement())
808     return nullptr;
809   return state.GetAnimatingElement()->GetElementAnimations();
810 }
811 
CachedAnimationBaseComputedStyle(StyleResolverState & state)812 static const ComputedStyle* CachedAnimationBaseComputedStyle(
813     StyleResolverState& state) {
814   ElementAnimations* element_animations = GetElementAnimations(state);
815   if (!element_animations)
816     return nullptr;
817 
818   return element_animations->BaseComputedStyle();
819 }
820 
UpdateAnimationBaseComputedStyle(StyleResolverState & state,StyleCascade & cascade,bool forced_update)821 static void UpdateAnimationBaseComputedStyle(StyleResolverState& state,
822                                              StyleCascade& cascade,
823                                              bool forced_update) {
824   if (!state.GetAnimatingElement())
825     return;
826 
827   if (!state.CanCacheBaseStyle())
828     return;
829 
830   if (forced_update)
831     state.GetAnimatingElement()->EnsureElementAnimations();
832 
833   ElementAnimations* element_animations =
834       state.GetAnimatingElement()->GetElementAnimations();
835   if (!element_animations)
836     return;
837 
838   if (element_animations->IsAnimationStyleChange() &&
839       element_animations->BaseComputedStyle()) {
840     return;
841   }
842 
843   std::unique_ptr<CSSBitset> important_set = cascade.GetImportantSet();
844   element_animations->UpdateBaseComputedStyle(state.Style(),
845                                               std::move(important_set));
846 }
847 
StyleForElement(Element * element,const ComputedStyle * default_parent,const ComputedStyle * default_layout_parent,RuleMatchingBehavior matching_behavior)848 scoped_refptr<ComputedStyle> StyleResolver::StyleForElement(
849     Element* element,
850     const ComputedStyle* default_parent,
851     const ComputedStyle* default_layout_parent,
852     RuleMatchingBehavior matching_behavior) {
853   DCHECK(GetDocument().GetFrame());
854   DCHECK(GetDocument().GetSettings());
855 
856   GetDocument().GetStyleEngine().IncStyleForElementCount();
857   INCREMENT_STYLE_STATS_COUNTER(GetDocument().GetStyleEngine(), elements_styled,
858                                 1);
859 
860   SelectorFilterParentScope::EnsureParentStackIsPushed();
861 
862   StyleResolverState state(GetDocument(), *element, default_parent,
863                            default_layout_parent);
864 
865   // This function can return different results with different last 3 params,
866   // but we can only cache one base computed style for animations, thus we cache
867   // only when this function is called with default last 3 params.
868   bool can_cache_animation_base_computed_style =
869       !default_parent && !default_layout_parent &&
870       matching_behavior == kMatchAllRules;
871   state.SetCanCacheBaseStyle(can_cache_animation_base_computed_style);
872 
873   STACK_UNINITIALIZED StyleCascade cascade(state);
874 
875   ApplyBaseStyle(element, state, cascade, cascade.MutableMatchResult(),
876                  matching_behavior, can_cache_animation_base_computed_style);
877 
878   if (ApplyAnimatedStyle(state, cascade)) {
879     INCREMENT_STYLE_STATS_COUNTER(GetDocument().GetStyleEngine(),
880                                   styles_animated, 1);
881     StyleAdjuster::AdjustComputedStyle(state, element);
882   }
883 
884   if (IsA<HTMLBodyElement>(*element)) {
885     GetDocument().GetTextLinkColors().SetTextColor(
886         state.Style()->GetCurrentColor());
887   }
888 
889   if (element->IsMathMLElement())
890     ApplyMathMLCustomStyleProperties(element, state);
891 
892   SetAnimationUpdateIfNeeded(state, *element);
893 
894   if (state.Style()->HasViewportUnits())
895     GetDocument().SetHasViewportUnits();
896 
897   if (state.Style()->HasRemUnits())
898     GetDocument().GetStyleEngine().SetUsesRemUnit(true);
899 
900   if (state.Style()->HasGlyphRelativeUnits())
901     UseCounter::Count(GetDocument(), WebFeature::kHasGlyphRelativeUnits);
902 
903   state.LoadPendingResources();
904 
905   // Now return the style.
906   return state.TakeStyle();
907 }
908 
InitStyleAndApplyInheritance(Element & element,StyleResolverState & state)909 void StyleResolver::InitStyleAndApplyInheritance(Element& element,
910                                                  StyleResolverState& state) {
911   if (state.ParentStyle()) {
912     scoped_refptr<ComputedStyle> style = ComputedStyle::Create();
913     style->InheritFrom(*state.ParentStyle(),
914                        IsAtShadowBoundary(&element)
915                            ? ComputedStyle::kAtShadowBoundary
916                            : ComputedStyle::kNotAtShadowBoundary);
917     state.SetStyle(std::move(style));
918 
919     // contenteditable attribute (implemented by -webkit-user-modify) should
920     // be propagated from shadow host to distributed node.
921     if (state.DistributedToV0InsertionPoint() || element.AssignedSlot()) {
922       if (Element* parent = element.parentElement()) {
923         if (const ComputedStyle* shadow_host_style = parent->GetComputedStyle())
924           state.Style()->SetUserModify(shadow_host_style->UserModify());
925       }
926     }
927   } else {
928     state.SetStyle(InitialStyleForElement(GetDocument()));
929     state.SetParentStyle(ComputedStyle::Clone(*state.Style()));
930     state.SetLayoutParentStyle(state.ParentStyle());
931     if (element != GetDocument().documentElement()) {
932       // Strictly, we should only allow the root element to inherit from
933       // initial styles, but we allow getComputedStyle() for connected
934       // elements outside the flat tree rooted at an unassigned shadow host
935       // child, a slot fallback element, or Shadow DOM V0 insertion points.
936       DCHECK(element.IsV0InsertionPoint() ||
937              ((IsShadowHost(element.parentNode()) ||
938                IsA<HTMLSlotElement>(element.parentNode())) &&
939               !LayoutTreeBuilderTraversal::ParentElement(element)));
940       state.Style()->SetIsEnsuredOutsideFlatTree();
941     }
942   }
943 
944   if (element.IsLink()) {
945     state.Style()->SetIsLink();
946     EInsideLink link_state = state.ElementLinkState();
947     if (link_state != EInsideLink::kNotInsideLink) {
948       bool force_visited = false;
949       probe::ForcePseudoState(&element, CSSSelector::kPseudoVisited,
950                               &force_visited);
951       if (force_visited)
952         link_state = EInsideLink::kInsideVisitedLink;
953     }
954     state.Style()->SetInsideLink(link_state);
955   }
956 }
957 
ApplyMathMLCustomStyleProperties(Element * element,StyleResolverState & state)958 void StyleResolver::ApplyMathMLCustomStyleProperties(
959     Element* element,
960     StyleResolverState& state) {
961   DCHECK(element && element->IsMathMLElement());
962   ComputedStyle& style = state.StyleRef();
963   if (auto* space = DynamicTo<MathMLSpaceElement>(*element)) {
964     space->AddMathBaselineIfNeeded(style, state.CssToLengthConversionData());
965   } else if (auto* padded = DynamicTo<MathMLPaddedElement>(*element)) {
966     padded->AddMathBaselineIfNeeded(style, state.CssToLengthConversionData());
967     padded->AddMathPaddedDepthIfNeeded(style,
968                                        state.CssToLengthConversionData());
969     padded->AddMathPaddedLSpaceIfNeeded(style,
970                                         state.CssToLengthConversionData());
971     padded->AddMathPaddedVOffsetIfNeeded(style,
972                                          state.CssToLengthConversionData());
973   } else if (auto* fraction = DynamicTo<MathMLFractionElement>(*element)) {
974     fraction->AddMathFractionBarThicknessIfNeeded(
975         style, state.CssToLengthConversionData());
976   } else if (auto* operator_element =
977                  DynamicTo<MathMLOperatorElement>(*element)) {
978     operator_element->AddMathLSpaceIfNeeded(style,
979                                             state.CssToLengthConversionData());
980     operator_element->AddMathRSpaceIfNeeded(style,
981                                             state.CssToLengthConversionData());
982     operator_element->AddMathMinSizeIfNeeded(style,
983                                              state.CssToLengthConversionData());
984     operator_element->AddMathMaxSizeIfNeeded(style,
985                                              state.CssToLengthConversionData());
986   }
987 }
988 
ApplyBaseStyle(Element * element,StyleResolverState & state,StyleCascade & cascade,MatchResult & match_result,RuleMatchingBehavior matching_behavior,bool can_cache_animation_base_computed_style)989 void StyleResolver::ApplyBaseStyle(
990     Element* element,
991     StyleResolverState& state,
992     StyleCascade& cascade,
993     MatchResult& match_result,
994     RuleMatchingBehavior matching_behavior,
995     bool can_cache_animation_base_computed_style) {
996   bool base_is_usable = can_cache_animation_base_computed_style &&
997                         CanReuseBaseComputedStyle(state);
998   const ComputedStyle* animation_base_computed_style =
999       base_is_usable ? CachedAnimationBaseComputedStyle(state) : nullptr;
1000   if (ShouldComputeBaseComputedStyle(animation_base_computed_style)) {
1001     InitStyleAndApplyInheritance(*element, state);
1002 
1003     GetDocument().GetStyleEngine().EnsureUAStyleForElement(*element);
1004 
1005     // This adds a CSSInitialColorValue to the cascade for the document
1006     // element. The CSSInitialColorValue will resolve to a color-scheme
1007     // sensitive color in Color::ApplyValue. It is added at the start of the
1008     // MatchResult such that subsequent declarations (even from the UA sheet)
1009     // get a higher priority.
1010     //
1011     // TODO(crbug.com/1046753): Remove this when canvastext is supported.
1012     if (element == state.GetDocument().documentElement()) {
1013       cascade.MutableMatchResult().AddMatchedProperties(
1014           DocumentElementUserAgentDeclarations());
1015     }
1016 
1017     ElementRuleCollector collector(state.ElementContext(), selector_filter_,
1018                                    match_result, state.Style(),
1019                                    state.Style()->InsideLink());
1020 
1021     MatchAllRules(state, collector,
1022                   matching_behavior != kMatchAllRulesExcludingSMIL);
1023 
1024     if (tracker_)
1025       AddMatchedRulesToTracker(collector);
1026 
1027     if (element->GetComputedStyle() &&
1028         element->GetComputedStyle()->TextAutosizingMultiplier() !=
1029             state.Style()->TextAutosizingMultiplier()) {
1030       // Preserve the text autosizing multiplier on style recalc. Autosizer will
1031       // update it during layout if needed.
1032       // NOTE: this must occur before ApplyMatchedProperties for correct
1033       // computation of font-relative lengths.
1034       state.Style()->SetTextAutosizingMultiplier(
1035           element->GetComputedStyle()->TextAutosizingMultiplier());
1036     }
1037 
1038     if (state.HasDirAutoAttribute())
1039       state.Style()->SetSelfOrAncestorHasDirAutoAttribute(true);
1040 
1041     CascadeAndApplyMatchedProperties(state, cascade);
1042 
1043     ApplyCallbackSelectors(state);
1044 
1045     // Cache our original display.
1046     state.Style()->SetOriginalDisplay(state.Style()->Display());
1047 
1048     StyleAdjuster::AdjustComputedStyle(state, element);
1049 
1050     DCHECK(ValidateBaseComputedStyle(animation_base_computed_style,
1051                                      *state.Style()));
1052   }
1053 
1054   if (base_is_usable) {
1055     DCHECK(animation_base_computed_style);
1056     state.SetStyle(ComputedStyle::Clone(*animation_base_computed_style));
1057     if (!state.ParentStyle()) {
1058       state.SetParentStyle(InitialStyleForElement(GetDocument()));
1059       state.SetLayoutParentStyle(state.ParentStyle());
1060     }
1061     MaybeResetCascade(cascade);
1062     INCREMENT_STYLE_STATS_COUNTER(GetDocument().GetStyleEngine(),
1063                                   base_styles_used, 1);
1064   }
1065 }
1066 
CreateCompositorKeyframeValueSnapshot(Element & element,const ComputedStyle & base_style,const ComputedStyle * parent_style,const PropertyHandle & property,const CSSValue * value)1067 CompositorKeyframeValue* StyleResolver::CreateCompositorKeyframeValueSnapshot(
1068     Element& element,
1069     const ComputedStyle& base_style,
1070     const ComputedStyle* parent_style,
1071     const PropertyHandle& property,
1072     const CSSValue* value) {
1073   // TODO(alancutter): Avoid creating a StyleResolverState just to apply a
1074   // single value on a ComputedStyle.
1075   StyleResolverState state(element.GetDocument(), element, parent_style,
1076                            parent_style);
1077   state.SetStyle(ComputedStyle::Clone(base_style));
1078   if (value) {
1079     STACK_UNINITIALIZED StyleCascade cascade(state);
1080     auto* set =
1081         MakeGarbageCollected<MutableCSSPropertyValueSet>(state.GetParserMode());
1082     set->SetProperty(property.GetCSSProperty().PropertyID(), *value);
1083     cascade.MutableMatchResult().FinishAddingUARules();
1084     cascade.MutableMatchResult().FinishAddingUserRules();
1085     cascade.MutableMatchResult().AddMatchedProperties(set);
1086     cascade.MutableMatchResult().FinishAddingAuthorRulesForTreeScope(
1087         element.GetTreeScope());
1088     cascade.Apply();
1089   }
1090   return CompositorKeyframeValueFactory::Create(property, *state.Style());
1091 }
1092 
PseudoStyleForElement(Element * element,const PseudoElementStyleRequest & pseudo_style_request,const ComputedStyle * parent_style,const ComputedStyle * parent_layout_object_style)1093 scoped_refptr<ComputedStyle> StyleResolver::PseudoStyleForElement(
1094     Element* element,
1095     const PseudoElementStyleRequest& pseudo_style_request,
1096     const ComputedStyle* parent_style,
1097     const ComputedStyle* parent_layout_object_style) {
1098   DCHECK(parent_style);
1099   if (!element)
1100     return nullptr;
1101 
1102   StyleResolverState state(
1103       GetDocument(), *element, pseudo_style_request.pseudo_id,
1104       pseudo_style_request.type, parent_style, parent_layout_object_style);
1105 
1106   DCHECK(GetDocument().GetFrame());
1107   DCHECK(GetDocument().GetSettings());
1108   DCHECK(pseudo_style_request.pseudo_id != kPseudoIdFirstLineInherited);
1109 
1110   SelectorFilterParentScope::EnsureParentStackIsPushed();
1111 
1112   bool base_is_usable = CanReuseBaseComputedStyle(state);
1113   const ComputedStyle* animation_base_computed_style =
1114       base_is_usable ? CachedAnimationBaseComputedStyle(state) : nullptr;
1115 
1116   // Since we don't use pseudo-elements in any of our quirk/print
1117   // user agent rules, don't waste time walking those rules.
1118 
1119   STACK_UNINITIALIZED StyleCascade cascade(state);
1120 
1121   if (ShouldComputeBaseComputedStyle(animation_base_computed_style)) {
1122     if (pseudo_style_request.AllowsInheritance(parent_style)) {
1123       scoped_refptr<ComputedStyle> style = ComputedStyle::Create();
1124       style->InheritFrom(*parent_style);
1125       state.SetStyle(std::move(style));
1126     } else {
1127       // ::backdrop inherits from initial styles. All other pseudo elements
1128       // inherit from their originating element (::before/::after), or
1129       // originating element descendants (::first-line/::first-letter).
1130       DCHECK(pseudo_style_request.pseudo_id == kPseudoIdBackdrop);
1131       state.SetStyle(InitialStyleForElement(GetDocument()));
1132       state.SetParentStyle(ComputedStyle::Clone(*state.Style()));
1133     }
1134     state.Style()->SetStyleType(pseudo_style_request.pseudo_id);
1135 
1136     // Check UA, user and author rules.
1137     ElementRuleCollector collector(state.ElementContext(), selector_filter_,
1138                                    cascade.MutableMatchResult(), state.Style(),
1139                                    state.Style()->InsideLink());
1140     collector.SetPseudoElementStyleRequest(pseudo_style_request);
1141 
1142     GetDocument().GetStyleEngine().EnsureUAStyleForPseudoElement(
1143         pseudo_style_request.pseudo_id);
1144 
1145     // TODO(obrufau): support styling nested pseudo-elements
1146     if (!element->IsPseudoElement())
1147       MatchAllRules(state, collector, /* include_smil_properties */ false);
1148     else
1149       MatchUARules(*element, collector);
1150 
1151     if (tracker_)
1152       AddMatchedRulesToTracker(collector);
1153 
1154     if (!collector.MatchedResult().HasMatchedProperties()) {
1155       StyleAdjuster::AdjustComputedStyle(state, nullptr);
1156       if (pseudo_style_request.type == PseudoElementStyleRequest::kForRenderer)
1157         return nullptr;
1158       return state.TakeStyle();
1159     }
1160 
1161     CascadeAndApplyMatchedProperties(state, cascade);
1162 
1163     ApplyCallbackSelectors(state);
1164 
1165     // Cache our original display.
1166     state.Style()->SetOriginalDisplay(state.Style()->Display());
1167 
1168     // FIXME: Passing 0 as the Element* introduces a lot of complexity
1169     // in the StyleAdjuster::AdjustComputedStyle code.
1170     StyleAdjuster::AdjustComputedStyle(state, nullptr);
1171 
1172     DCHECK(ValidateBaseComputedStyle(animation_base_computed_style,
1173                                      *state.Style()));
1174   }
1175 
1176   if (animation_base_computed_style) {
1177     state.SetStyle(ComputedStyle::Clone(*animation_base_computed_style));
1178     state.Style()->SetStyleType(pseudo_style_request.pseudo_id);
1179     MaybeResetCascade(cascade);
1180   }
1181 
1182   state.SetCanCacheBaseStyle(true);
1183   if (ApplyAnimatedStyle(state, cascade))
1184     StyleAdjuster::AdjustComputedStyle(state, nullptr);
1185 
1186   GetDocument().GetStyleEngine().IncStyleForElementCount();
1187   INCREMENT_STYLE_STATS_COUNTER(GetDocument().GetStyleEngine(),
1188                                 pseudo_elements_styled, 1);
1189 
1190   if (state.Style()->HasViewportUnits())
1191     GetDocument().SetHasViewportUnits();
1192 
1193   if (state.Style()->HasGlyphRelativeUnits())
1194     UseCounter::Count(GetDocument(), WebFeature::kHasGlyphRelativeUnits);
1195 
1196   if (PseudoElement* pseudo_element =
1197           element->GetPseudoElement(pseudo_style_request.pseudo_id)) {
1198     SetAnimationUpdateIfNeeded(state, *pseudo_element);
1199     state.LoadPendingResources();
1200   }
1201 
1202   return state.TakeStyle();
1203 }
1204 
StyleForPage(uint32_t page_index,const AtomicString & page_name)1205 scoped_refptr<const ComputedStyle> StyleResolver::StyleForPage(
1206     uint32_t page_index,
1207     const AtomicString& page_name) {
1208   scoped_refptr<const ComputedStyle> initial_style =
1209       InitialStyleForElement(GetDocument());
1210   if (!GetDocument().documentElement())
1211     return initial_style;
1212 
1213   StyleResolverState state(GetDocument(), *GetDocument().documentElement(),
1214                            initial_style.get(), initial_style.get());
1215 
1216   scoped_refptr<ComputedStyle> style = ComputedStyle::Create();
1217   const ComputedStyle* root_element_style =
1218       state.RootElementStyle() ? state.RootElementStyle()
1219                                : GetDocument().GetComputedStyle();
1220   DCHECK(root_element_style);
1221   style->InheritFrom(*root_element_style);
1222   state.SetStyle(std::move(style));
1223 
1224   STACK_UNINITIALIZED StyleCascade cascade(state);
1225 
1226   PageRuleCollector collector(root_element_style, page_index, page_name,
1227                               cascade.MutableMatchResult());
1228 
1229   collector.MatchPageRules(
1230       CSSDefaultStyleSheets::Instance().DefaultPrintStyle());
1231 
1232   if (ScopedStyleResolver* scoped_resolver =
1233           GetDocument().GetScopedStyleResolver())
1234     scoped_resolver->MatchPageRules(collector);
1235 
1236   cascade.Apply();
1237 
1238   // Now return the style.
1239   return state.TakeStyle();
1240 }
1241 
InitialStyleForElement(Document & document)1242 scoped_refptr<ComputedStyle> StyleResolver::InitialStyleForElement(
1243     Document& document) {
1244   const LocalFrame* frame = document.GetFrame();
1245 
1246   scoped_refptr<ComputedStyle> initial_style = ComputedStyle::Create();
1247 
1248   initial_style->SetRtlOrdering(document.VisuallyOrdered() ? EOrder::kVisual
1249                                                            : EOrder::kLogical);
1250   initial_style->SetZoom(frame && !document.Printing() ? frame->PageZoomFactor()
1251                                                        : 1);
1252   initial_style->SetEffectiveZoom(initial_style->Zoom());
1253 
1254   FontDescription document_font_description =
1255       initial_style->GetFontDescription();
1256   document_font_description.SetLocale(
1257       LayoutLocale::Get(document.ContentLanguage()));
1258 
1259   initial_style->SetFontDescription(document_font_description);
1260   initial_style->SetUserModify(document.InDesignMode()
1261                                    ? EUserModify::kReadWrite
1262                                    : EUserModify::kReadOnly);
1263   document.SetupFontBuilder(*initial_style);
1264 
1265   scoped_refptr<StyleInitialData> initial_data =
1266       document.GetStyleEngine().MaybeCreateAndGetInitialData();
1267   if (initial_data)
1268     initial_style->SetInitialData(std::move(initial_data));
1269 
1270   return initial_style;
1271 }
1272 
StyleForText(Text * text_node)1273 scoped_refptr<const ComputedStyle> StyleResolver::StyleForText(
1274     Text* text_node) {
1275   DCHECK(text_node);
1276   if (Node* parent_node = LayoutTreeBuilderTraversal::Parent(*text_node)) {
1277     const ComputedStyle* style = parent_node->GetComputedStyle();
1278     if (style && !style->IsEnsuredInDisplayNone())
1279       return style;
1280   }
1281   return nullptr;
1282 }
1283 
UpdateFont(StyleResolverState & state)1284 void StyleResolver::UpdateFont(StyleResolverState& state) {
1285   state.GetFontBuilder().CreateFont(state.StyleRef(), state.ParentStyle());
1286   state.SetConversionFontSizes(CSSToLengthConversionData::FontSizes(
1287       state.Style(), state.RootElementStyle()));
1288   state.SetConversionZoom(state.Style()->EffectiveZoom());
1289 }
1290 
AddMatchedRulesToTracker(const ElementRuleCollector & collector)1291 void StyleResolver::AddMatchedRulesToTracker(
1292     const ElementRuleCollector& collector) {
1293   collector.AddMatchedRulesToTracker(tracker_);
1294 }
1295 
StyleRulesForElement(Element * element,unsigned rules_to_include)1296 StyleRuleList* StyleResolver::StyleRulesForElement(Element* element,
1297                                                    unsigned rules_to_include) {
1298   DCHECK(element);
1299   StyleResolverState state(GetDocument(), *element);
1300   MatchResult match_result;
1301   ElementRuleCollector collector(state.ElementContext(), selector_filter_,
1302                                  match_result, state.Style(),
1303                                  EInsideLink::kNotInsideLink);
1304   collector.SetMode(SelectorChecker::kCollectingStyleRules);
1305   CollectPseudoRulesForElement(*element, collector, kPseudoIdNone,
1306                                rules_to_include);
1307   return collector.MatchedStyleRuleList();
1308 }
1309 
1310 HeapHashMap<CSSPropertyName, Member<const CSSValue>>
CascadedValuesForElement(Element * element,PseudoId pseudo_id)1311 StyleResolver::CascadedValuesForElement(Element* element, PseudoId pseudo_id) {
1312   StyleResolverState state(GetDocument(), *element);
1313   state.SetStyle(ComputedStyle::Create());
1314 
1315   STACK_UNINITIALIZED StyleCascade cascade(state);
1316   ElementRuleCollector collector(state.ElementContext(), selector_filter_,
1317                                  cascade.MutableMatchResult(), state.Style(),
1318                                  EInsideLink::kNotInsideLink);
1319   collector.SetPseudoElementStyleRequest(PseudoElementStyleRequest(pseudo_id));
1320   MatchAllRules(state, collector, false /* include_smil_properties */);
1321 
1322   cascade.Apply();
1323   return cascade.GetCascadedValues();
1324 }
1325 
PseudoCSSRulesForElement(Element * element,PseudoId pseudo_id,unsigned rules_to_include)1326 RuleIndexList* StyleResolver::PseudoCSSRulesForElement(
1327     Element* element,
1328     PseudoId pseudo_id,
1329     unsigned rules_to_include) {
1330   DCHECK(element);
1331   StyleResolverState state(GetDocument(), *element);
1332   MatchResult match_result;
1333   ElementRuleCollector collector(state.ElementContext(), selector_filter_,
1334                                  match_result, state.Style(),
1335                                  EInsideLink::kNotInsideLink);
1336   collector.SetMode(SelectorChecker::kCollectingCSSRules);
1337   // TODO(obrufau): support collecting rules for nested ::marker
1338   if (!element->IsPseudoElement()) {
1339     CollectPseudoRulesForElement(*element, collector, pseudo_id,
1340                                  rules_to_include);
1341   }
1342 
1343   if (tracker_)
1344     AddMatchedRulesToTracker(collector);
1345   return collector.MatchedCSSRuleList();
1346 }
1347 
CssRulesForElement(Element * element,unsigned rules_to_include)1348 RuleIndexList* StyleResolver::CssRulesForElement(Element* element,
1349                                                  unsigned rules_to_include) {
1350   return PseudoCSSRulesForElement(element, kPseudoIdNone, rules_to_include);
1351 }
1352 
CollectPseudoRulesForElement(const Element & element,ElementRuleCollector & collector,PseudoId pseudo_id,unsigned rules_to_include)1353 void StyleResolver::CollectPseudoRulesForElement(
1354     const Element& element,
1355     ElementRuleCollector& collector,
1356     PseudoId pseudo_id,
1357     unsigned rules_to_include) {
1358   collector.SetPseudoElementStyleRequest(PseudoElementStyleRequest(pseudo_id));
1359 
1360   if (rules_to_include & kUACSSRules)
1361     MatchUARules(element, collector);
1362   else
1363     collector.FinishAddingUARules();
1364 
1365   if (rules_to_include & kUserCSSRules)
1366     MatchUserRules(collector);
1367   else
1368     collector.FinishAddingUserRules();
1369 
1370   if (rules_to_include & kAuthorCSSRules) {
1371     collector.SetSameOriginOnly(!(rules_to_include & kCrossOriginCSSRules));
1372     collector.SetIncludeEmptyRules(rules_to_include & kEmptyCSSRules);
1373     MatchAuthorRules(element, ScopedResolverFor(element), collector);
1374   }
1375 }
1376 
ApplyAnimatedStyle(StyleResolverState & state,StyleCascade & cascade)1377 bool StyleResolver::ApplyAnimatedStyle(StyleResolverState& state,
1378                                        StyleCascade& cascade) {
1379   Element& element = state.GetElement();
1380 
1381   // The animating element may be this element, the pseudo element we are
1382   // resolving style for, or null if we are resolving style for a pseudo
1383   // element which is not represented by a PseudoElement like scrollbar pseudo
1384   // elements.
1385   Element* animating_element = state.GetAnimatingElement();
1386   DCHECK(animating_element == &element || !animating_element ||
1387          animating_element->ParentOrShadowHostElement() == element);
1388 
1389   if (!HasAnimationsOrTransitions(state)) {
1390     // Ensure that the base computed style is not stale even if not currently
1391     // running an animation or transition. This ensures that any new transitions
1392     // use the correct starting point based on the "before change" style.
1393     UpdateAnimationBaseComputedStyle(state, cascade, false);
1394     return false;
1395   }
1396 
1397   CalculateAnimationUpdate(state);
1398 
1399   CSSAnimations::CalculateCompositorAnimationUpdate(
1400       state.AnimationUpdate(), animating_element, element, *state.Style(),
1401       state.ParentStyle(), WasViewportResized());
1402   CSSAnimations::CalculateTransitionUpdate(
1403       state.AnimationUpdate(), CSSAnimations::PropertyPass::kStandard,
1404       animating_element, *state.Style());
1405   CSSAnimations::CalculateTransitionUpdate(state.AnimationUpdate(),
1406                                            CSSAnimations::PropertyPass::kCustom,
1407                                            animating_element, *state.Style());
1408 
1409   CSSAnimations::SnapshotCompositorKeyframes(
1410       element, state.AnimationUpdate(), *state.Style(), state.ParentStyle());
1411 
1412   bool has_update = !state.AnimationUpdate().IsEmpty();
1413   UpdateAnimationBaseComputedStyle(state, cascade, has_update);
1414 
1415   if (!has_update)
1416     return false;
1417 
1418   const ActiveInterpolationsMap& standard_animations =
1419       state.AnimationUpdate().ActiveInterpolationsForStandardAnimations();
1420   const ActiveInterpolationsMap& standard_transitions =
1421       state.AnimationUpdate().ActiveInterpolationsForStandardTransitions();
1422   const ActiveInterpolationsMap& custom_animations =
1423       state.AnimationUpdate().ActiveInterpolationsForCustomAnimations();
1424   const ActiveInterpolationsMap& custom_transitions =
1425       state.AnimationUpdate().ActiveInterpolationsForCustomTransitions();
1426 
1427   cascade.AddInterpolations(&standard_animations, CascadeOrigin::kAnimation);
1428   cascade.AddInterpolations(&standard_transitions, CascadeOrigin::kTransition);
1429   cascade.AddInterpolations(&custom_animations, CascadeOrigin::kAnimation);
1430   cascade.AddInterpolations(&custom_transitions, CascadeOrigin::kTransition);
1431 
1432   CascadeFilter filter;
1433   if (state.Style()->StyleType() == kPseudoIdMarker)
1434     filter = filter.Add(CSSProperty::kValidForMarker, false);
1435   if (IsHighlightPseudoElement(state.Style()->StyleType()))
1436     filter = filter.Add(CSSProperty::kValidForHighlight, false);
1437   filter = filter.Add(CSSProperty::kAnimation, true);
1438 
1439   cascade.Apply(filter);
1440 
1441   // Start loading resources used by animations.
1442   state.LoadPendingResources();
1443 
1444   DCHECK(!state.GetFontBuilder().FontDirty());
1445 
1446   return true;
1447 }
1448 
FindKeyframesRule(const Element * element,const AtomicString & animation_name)1449 StyleRuleKeyframes* StyleResolver::FindKeyframesRule(
1450     const Element* element,
1451     const AtomicString& animation_name) {
1452   HeapVector<Member<ScopedStyleResolver>, 8> resolvers;
1453   CollectScopedResolversForHostedShadowTrees(*element, resolvers);
1454   if (ScopedStyleResolver* scoped_resolver =
1455           element->GetTreeScope().GetScopedStyleResolver())
1456     resolvers.push_back(scoped_resolver);
1457 
1458   for (auto& resolver : resolvers) {
1459     if (StyleRuleKeyframes* keyframes_rule =
1460             resolver->KeyframeStylesForAnimation(animation_name))
1461       return keyframes_rule;
1462   }
1463 
1464   if (StyleRuleKeyframes* keyframes_rule =
1465           GetDocument().GetStyleEngine().KeyframeStylesForAnimation(
1466               animation_name))
1467     return keyframes_rule;
1468 
1469   for (auto& resolver : resolvers)
1470     resolver->SetHasUnresolvedKeyframesRule();
1471   return nullptr;
1472 }
1473 
InvalidateMatchedPropertiesCache()1474 void StyleResolver::InvalidateMatchedPropertiesCache() {
1475   matched_properties_cache_.Clear();
1476 }
1477 
SetResizedForViewportUnits()1478 void StyleResolver::SetResizedForViewportUnits() {
1479   DCHECK(!was_viewport_resized_);
1480   was_viewport_resized_ = true;
1481   GetDocument().GetStyleEngine().UpdateActiveStyle();
1482   matched_properties_cache_.ClearViewportDependent();
1483 }
1484 
ClearResizedForViewportUnits()1485 void StyleResolver::ClearResizedForViewportUnits() {
1486   was_viewport_resized_ = false;
1487 }
1488 
EffectiveZoomChanged(const ComputedStyle & style) const1489 bool StyleResolver::CacheSuccess::EffectiveZoomChanged(
1490     const ComputedStyle& style) const {
1491   if (!cached_matched_properties)
1492     return false;
1493   return cached_matched_properties->computed_style->EffectiveZoom() !=
1494          style.EffectiveZoom();
1495 }
1496 
FontChanged(const ComputedStyle & style) const1497 bool StyleResolver::CacheSuccess::FontChanged(
1498     const ComputedStyle& style) const {
1499   if (!cached_matched_properties)
1500     return false;
1501   return cached_matched_properties->computed_style->GetFontDescription() !=
1502          style.GetFontDescription();
1503 }
1504 
InheritedVariablesChanged(const ComputedStyle & style) const1505 bool StyleResolver::CacheSuccess::InheritedVariablesChanged(
1506     const ComputedStyle& style) const {
1507   if (!cached_matched_properties)
1508     return false;
1509   return cached_matched_properties->computed_style->InheritedVariables() !=
1510          style.InheritedVariables();
1511 }
1512 
IsUsableAfterApplyInheritedOnly(const ComputedStyle & style) const1513 bool StyleResolver::CacheSuccess::IsUsableAfterApplyInheritedOnly(
1514     const ComputedStyle& style) const {
1515   return !EffectiveZoomChanged(style) && !FontChanged(style) &&
1516          !InheritedVariablesChanged(style);
1517 }
1518 
ApplyMatchedCache(StyleResolverState & state,const MatchResult & match_result)1519 StyleResolver::CacheSuccess StyleResolver::ApplyMatchedCache(
1520     StyleResolverState& state,
1521     const MatchResult& match_result) {
1522   const Element& element = state.GetElement();
1523 
1524   MatchedPropertiesCache::Key key(match_result);
1525 
1526   bool is_inherited_cache_hit = false;
1527   bool is_non_inherited_cache_hit = false;
1528   const CachedMatchedProperties* cached_matched_properties =
1529       key.IsValid() ? matched_properties_cache_.Find(key, state) : nullptr;
1530 
1531   if (cached_matched_properties && MatchedPropertiesCache::IsCacheable(state)) {
1532     INCREMENT_STYLE_STATS_COUNTER(GetDocument().GetStyleEngine(),
1533                                   matched_property_cache_hit, 1);
1534     // We can build up the style by copying non-inherited properties from an
1535     // earlier style object built using the same exact style declarations. We
1536     // then only need to apply the inherited properties, if any, as their values
1537     // can depend on the element context. This is fast and saves memory by
1538     // reusing the style data structures.
1539     if (state.ParentStyle()->InheritedDataShared(
1540             *cached_matched_properties->parent_computed_style) &&
1541         !IsAtShadowBoundary(&element) &&
1542         (!state.DistributedToV0InsertionPoint() || element.AssignedSlot() ||
1543          state.Style()->UserModify() == EUserModify::kReadOnly)) {
1544       INCREMENT_STYLE_STATS_COUNTER(GetDocument().GetStyleEngine(),
1545                                     matched_property_cache_inherited_hit, 1);
1546 
1547       EInsideLink link_status = state.Style()->InsideLink();
1548       // If the cache item parent style has identical inherited properties to
1549       // the current parent style then the resulting style will be identical
1550       // too. We copy the inherited properties over from the cache and are done.
1551       state.Style()->InheritFrom(*cached_matched_properties->computed_style);
1552 
1553       // Unfortunately the link status is treated like an inherited property. We
1554       // need to explicitly restore it.
1555       state.Style()->SetInsideLink(link_status);
1556 
1557       is_inherited_cache_hit = true;
1558     }
1559     if (!IsForcedColorsModeEnabled() || is_inherited_cache_hit) {
1560       state.Style()->CopyNonInheritedFromCached(
1561           *cached_matched_properties->computed_style);
1562       // If the child style is a cache hit, we'll never reach StyleBuilder::
1563       // ApplyProperty, hence we'll never set the flag on the parent.
1564       if (state.Style()->HasExplicitInheritance())
1565         state.ParentStyle()->SetChildHasExplicitInheritance();
1566       is_non_inherited_cache_hit = true;
1567     }
1568     UpdateFont(state);
1569   }
1570 
1571   return CacheSuccess(is_inherited_cache_hit, is_non_inherited_cache_hit, key,
1572                       cached_matched_properties);
1573 }
1574 
MaybeAddToMatchedPropertiesCache(StyleResolverState & state,const CacheSuccess & cache_success,const MatchResult & match_result)1575 void StyleResolver::MaybeAddToMatchedPropertiesCache(
1576     StyleResolverState& state,
1577     const CacheSuccess& cache_success,
1578     const MatchResult& match_result) {
1579   state.LoadPendingResources();
1580   if (!cache_success.cached_matched_properties && cache_success.key.IsValid() &&
1581       MatchedPropertiesCache::IsCacheable(state)) {
1582     INCREMENT_STYLE_STATS_COUNTER(GetDocument().GetStyleEngine(),
1583                                   matched_property_cache_added, 1);
1584     matched_properties_cache_.Add(cache_success.key, *state.Style(),
1585                                   *state.ParentStyle(), state.Dependencies());
1586   }
1587 }
1588 
CalculateAnimationUpdate(StyleResolverState & state)1589 void StyleResolver::CalculateAnimationUpdate(StyleResolverState& state) {
1590   Element* animating_element = state.GetAnimatingElement();
1591 
1592   DCHECK(state.Style()->Animations() || state.Style()->Transitions() ||
1593          (animating_element && animating_element->HasAnimations()));
1594   DCHECK(!state.IsAnimationInterpolationMapReady());
1595 
1596   CSSAnimations::CalculateAnimationUpdate(
1597       state.AnimationUpdate(), animating_element, state.GetElement(),
1598       *state.Style(), state.ParentStyle(), this);
1599 
1600   state.SetIsAnimationInterpolationMapReady();
1601 }
1602 
CanReuseBaseComputedStyle(const StyleResolverState & state)1603 bool StyleResolver::CanReuseBaseComputedStyle(const StyleResolverState& state) {
1604   ElementAnimations* element_animations = GetElementAnimations(state);
1605   if (!element_animations || !element_animations->BaseComputedStyle())
1606     return false;
1607 
1608   if (!element_animations->IsAnimationStyleChange())
1609     return false;
1610 
1611   // Animating a custom property can have side effects on other properties
1612   // via variable references. Disallow base computed style optimization in such
1613   // cases.
1614   if (CSSAnimations::IsAnimatingCustomProperties(element_animations))
1615     return false;
1616 
1617   // We need to build the cascade to know what to revert to.
1618   if (CSSAnimations::IsAnimatingRevert(element_animations))
1619     return false;
1620 
1621   // When applying an animation or transition for a font affecting property,
1622   // font-relative units (e.g. em, ex) in the base style must respond to the
1623   // animation. We cannot use the base computed style optimization in such
1624   // cases.
1625   if (CSSAnimations::IsAnimatingFontAffectingProperties(element_animations)) {
1626     if (element_animations->BaseComputedStyle() &&
1627         element_animations->BaseComputedStyle()->HasFontRelativeUnits()) {
1628       return false;
1629     }
1630   }
1631 
1632   // Normally, we apply all active animation effects on top of the style created
1633   // by regular CSS declarations. However, !important declarations have a
1634   // higher priority than animation effects [1]. If we're currently animating
1635   // (not transitioning) a property which was declared !important in the base
1636   // style, we disable the base computed style optimization.
1637   // [1] https://drafts.csswg.org/css-cascade-4/#cascade-origin
1638   if (CSSAnimations::IsAnimatingStandardProperties(
1639           element_animations, element_animations->BaseImportantSet(),
1640           KeyframeEffect::kDefaultPriority)) {
1641     return false;
1642   }
1643 
1644   return true;
1645 }
1646 
ComputeValue(Element * element,const CSSPropertyName & property_name,const CSSValue & value)1647 const CSSValue* StyleResolver::ComputeValue(
1648     Element* element,
1649     const CSSPropertyName& property_name,
1650     const CSSValue& value) {
1651   const ComputedStyle* base_style = element->GetComputedStyle();
1652   StyleResolverState state(element->GetDocument(), *element);
1653   STACK_UNINITIALIZED StyleCascade cascade(state);
1654   state.SetStyle(ComputedStyle::Clone(*base_style));
1655   auto* set =
1656       MakeGarbageCollected<MutableCSSPropertyValueSet>(state.GetParserMode());
1657   if (property_name.IsCustomProperty()) {
1658     set->SetProperty(CSSPropertyValue(property_name, value));
1659   } else {
1660     set->SetProperty(property_name.Id(), value);
1661   }
1662   cascade.MutableMatchResult().FinishAddingUARules();
1663   cascade.MutableMatchResult().FinishAddingUserRules();
1664   cascade.MutableMatchResult().AddMatchedProperties(set);
1665   cascade.MutableMatchResult().FinishAddingAuthorRulesForTreeScope(
1666       element->GetTreeScope());
1667   cascade.Apply();
1668 
1669   CSSPropertyRef property_ref(property_name, element->GetDocument());
1670   return ComputedStyleUtils::ComputedPropertyValue(property_ref.GetProperty(),
1671                                                    *state.Style());
1672 }
1673 
StyleForInterpolations(Element & element,ActiveInterpolationsMap & interpolations)1674 scoped_refptr<ComputedStyle> StyleResolver::StyleForInterpolations(
1675     Element& element,
1676     ActiveInterpolationsMap& interpolations) {
1677   StyleResolverState state(GetDocument(), element);
1678   STACK_UNINITIALIZED StyleCascade cascade(state);
1679 
1680   ApplyBaseStyle(&element, state, cascade, cascade.MutableMatchResult(),
1681                  kMatchAllRules, true);
1682   ApplyInterpolations(state, cascade, interpolations);
1683 
1684   return state.TakeStyle();
1685 }
1686 
ApplyInterpolations(StyleResolverState & state,StyleCascade & cascade,ActiveInterpolationsMap & interpolations)1687 void StyleResolver::ApplyInterpolations(
1688     StyleResolverState& state,
1689     StyleCascade& cascade,
1690     ActiveInterpolationsMap& interpolations) {
1691   cascade.AddInterpolations(&interpolations, CascadeOrigin::kAnimation);
1692   cascade.Apply();
1693 }
1694 
1695 scoped_refptr<ComputedStyle>
BeforeChangeStyleForTransitionUpdate(Element & element,const ComputedStyle & base_style,ActiveInterpolationsMap & transition_interpolations)1696 StyleResolver::BeforeChangeStyleForTransitionUpdate(
1697     Element& element,
1698     const ComputedStyle& base_style,
1699     ActiveInterpolationsMap& transition_interpolations) {
1700   StyleResolverState state(GetDocument(), element);
1701   STACK_UNINITIALIZED StyleCascade cascade(state);
1702   state.SetStyle(ComputedStyle::Clone(base_style));
1703 
1704   // Various property values may depend on the parent style. A valid parent
1705   // style is required, even if animating the root element, in order to
1706   // handle these dependencies. The root element inherits from initial
1707   // styles.
1708   if (!state.ParentStyle()) {
1709     if (element != GetDocument().documentElement()) {
1710       // Do not apply interpolations to a detached element.
1711       return state.TakeStyle();
1712     }
1713     state.SetParentStyle(InitialStyleForElement(GetDocument()));
1714     state.SetLayoutParentStyle(state.ParentStyle());
1715   }
1716 
1717   // TODO(crbug.com/1098937): Include active CSS animations in a separate
1718   // interpolations map and add each map at the appropriate CascadeOrigin.
1719   ApplyInterpolations(state, cascade, transition_interpolations);
1720   return state.TakeStyle();
1721 }
1722 
CascadeAndApplyMatchedProperties(StyleResolverState & state,StyleCascade & cascade)1723 void StyleResolver::CascadeAndApplyMatchedProperties(StyleResolverState& state,
1724                                                      StyleCascade& cascade) {
1725   const MatchResult& result = cascade.GetMatchResult();
1726 
1727   CacheSuccess cache_success = ApplyMatchedCache(state, result);
1728 
1729   if (cache_success.IsFullCacheHit())
1730     return;
1731 
1732   if (cache_success.ShouldApplyInheritedOnly()) {
1733     cascade.Apply(CascadeFilter(CSSProperty::kInherited, false));
1734     if (!cache_success.IsUsableAfterApplyInheritedOnly(state.StyleRef()))
1735       cascade.Apply(CascadeFilter(CSSProperty::kInherited, true));
1736   } else {
1737     cascade.Apply();
1738   }
1739 
1740   MaybeAddToMatchedPropertiesCache(state, cache_success, result);
1741 
1742   DCHECK(!state.GetFontBuilder().FontDirty());
1743 }
1744 
ApplyCallbackSelectors(StyleResolverState & state)1745 void StyleResolver::ApplyCallbackSelectors(StyleResolverState& state) {
1746   RuleSet* watched_selectors_rule_set =
1747       GetDocument().GetStyleEngine().WatchedSelectorsRuleSet();
1748   if (!watched_selectors_rule_set)
1749     return;
1750 
1751   MatchResult match_result;
1752   ElementRuleCollector collector(state.ElementContext(), selector_filter_,
1753                                  match_result, state.Style(),
1754                                  state.Style()->InsideLink());
1755   collector.SetMode(SelectorChecker::kCollectingStyleRules);
1756   collector.SetIncludeEmptyRules(true);
1757 
1758   MatchRequest match_request(watched_selectors_rule_set);
1759   collector.CollectMatchingRules(match_request);
1760   collector.SortAndTransferMatchedRules();
1761 
1762   if (tracker_)
1763     AddMatchedRulesToTracker(collector);
1764 
1765   StyleRuleList* rules = collector.MatchedStyleRuleList();
1766   if (!rules)
1767     return;
1768   for (auto rule : *rules)
1769     state.Style()->AddCallbackSelector(rule->SelectorList().SelectorsText());
1770 }
1771 
1772 // Font properties are also handled by FontStyleResolver outside the main
1773 // thread. If you add/remove properties here, make sure they are also properly
1774 // handled by FontStyleResolver.
ComputeFont(Element & element,ComputedStyle * style,const CSSPropertyValueSet & property_set)1775 void StyleResolver::ComputeFont(Element& element,
1776                                 ComputedStyle* style,
1777                                 const CSSPropertyValueSet& property_set) {
1778   static const CSSProperty* properties[7] = {
1779       &GetCSSPropertyFontSize(),        &GetCSSPropertyFontFamily(),
1780       &GetCSSPropertyFontStretch(),     &GetCSSPropertyFontStyle(),
1781       &GetCSSPropertyFontVariantCaps(), &GetCSSPropertyFontWeight(),
1782       &GetCSSPropertyLineHeight(),
1783   };
1784 
1785   // TODO(timloh): This is weird, the style is being used as its own parent
1786   StyleResolverState state(GetDocument(), element, style, style);
1787   state.SetStyle(style);
1788 
1789   for (const CSSProperty* property : properties) {
1790     if (property->IDEquals(CSSPropertyID::kLineHeight))
1791       UpdateFont(state);
1792     // TODO(futhark): If we start supporting fonts on ShadowRoot.fonts in
1793     // addition to Document.fonts, we need to pass the correct TreeScope instead
1794     // of GetDocument() in the ScopedCSSValue below.
1795     StyleBuilder::ApplyProperty(
1796         *property, state,
1797         ScopedCSSValue(
1798             *property_set.GetPropertyCSSValue(property->PropertyID()),
1799             &GetDocument()));
1800   }
1801 }
1802 
UpdateMediaType()1803 void StyleResolver::UpdateMediaType() {
1804   if (LocalFrameView* view = GetDocument().View()) {
1805     bool was_print = print_media_type_;
1806     print_media_type_ =
1807         EqualIgnoringASCIICase(view->MediaType(), media_type_names::kPrint);
1808     if (was_print != print_media_type_)
1809       matched_properties_cache_.ClearViewportDependent();
1810   }
1811 }
1812 
Trace(Visitor * visitor) const1813 void StyleResolver::Trace(Visitor* visitor) const {
1814   visitor->Trace(matched_properties_cache_);
1815   visitor->Trace(selector_filter_);
1816   visitor->Trace(document_);
1817   visitor->Trace(tracker_);
1818 }
1819 
IsForcedColorsModeEnabled() const1820 bool StyleResolver::IsForcedColorsModeEnabled() const {
1821   return GetDocument().InForcedColorsMode();
1822 }
1823 
IsForcedColorsModeEnabled(const StyleResolverState & state) const1824 bool StyleResolver::IsForcedColorsModeEnabled(
1825     const StyleResolverState& state) const {
1826   return IsForcedColorsModeEnabled() &&
1827          state.Style()->ForcedColorAdjust() != EForcedColorAdjust::kNone;
1828 }
1829 
1830 }  // namespace blink
1831