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