1 /*
2  * Copyright (C) 1999 Antti Koivisto (koivisto@kde.org)
3  * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights
4  * reserved.
5  * Copyright (C) 2011 Adobe Systems Incorporated. All rights reserved.
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public License
18  * along with this library; see the file COPYING.LIB.  If not, write to
19  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20  * Boston, MA 02110-1301, USA.
21  *
22  */
23 
24 #include "third_party/blink/renderer/core/style/computed_style.h"
25 
26 #include <algorithm>
27 #include <memory>
28 #include <utility>
29 
30 #include "base/metrics/histogram_functions.h"
31 #include "base/numerics/clamped_math.h"
32 #include "base/numerics/ranges.h"
33 #include "build/build_config.h"
34 #include "cc/input/overscroll_behavior.h"
35 #include "third_party/blink/renderer/core/animation/css/css_animation_data.h"
36 #include "third_party/blink/renderer/core/animation/css/css_transition_data.h"
37 #include "third_party/blink/renderer/core/css/css_paint_value.h"
38 #include "third_party/blink/renderer/core/css/css_primitive_value.h"
39 #include "third_party/blink/renderer/core/css/css_property_equality.h"
40 #include "third_party/blink/renderer/core/css/properties/css_property.h"
41 #include "third_party/blink/renderer/core/css/properties/longhand.h"
42 #include "third_party/blink/renderer/core/css/resolver/style_resolver.h"
43 #include "third_party/blink/renderer/core/dom/document.h"
44 #include "third_party/blink/renderer/core/frame/local_dom_window.h"
45 #include "third_party/blink/renderer/core/html/html_progress_element.h"
46 #include "third_party/blink/renderer/core/layout/layout_theme.h"
47 #include "third_party/blink/renderer/core/layout/ng/custom/layout_worklet.h"
48 #include "third_party/blink/renderer/core/layout/text_autosizer.h"
49 #include "third_party/blink/renderer/core/style/applied_text_decoration.h"
50 #include "third_party/blink/renderer/core/style/border_edge.h"
51 #include "third_party/blink/renderer/core/style/computed_style_constants.h"
52 #include "third_party/blink/renderer/core/style/computed_style_initial_values.h"
53 #include "third_party/blink/renderer/core/style/content_data.h"
54 #include "third_party/blink/renderer/core/style/cursor_data.h"
55 #include "third_party/blink/renderer/core/style/data_equivalency.h"
56 #include "third_party/blink/renderer/core/style/quotes_data.h"
57 #include "third_party/blink/renderer/core/style/shadow_list.h"
58 #include "third_party/blink/renderer/core/style/style_difference.h"
59 #include "third_party/blink/renderer/core/style/style_fetched_image.h"
60 #include "third_party/blink/renderer/core/style/style_generated_image.h"
61 #include "third_party/blink/renderer/core/style/style_image.h"
62 #include "third_party/blink/renderer/core/style/style_inherited_variables.h"
63 #include "third_party/blink/renderer/core/style/style_non_inherited_variables.h"
64 #include "third_party/blink/renderer/core/style/style_ray.h"
65 #include "third_party/blink/renderer/platform/fonts/font.h"
66 #include "third_party/blink/renderer/platform/fonts/font_selector.h"
67 #include "third_party/blink/renderer/platform/geometry/length_functions.h"
68 #include "third_party/blink/renderer/platform/graphics/graphics_context.h"
69 #include "third_party/blink/renderer/platform/graphics/path.h"
70 #include "third_party/blink/renderer/platform/text/capitalize.h"
71 #include "third_party/blink/renderer/platform/text/character.h"
72 #include "third_party/blink/renderer/platform/transforms/rotate_transform_operation.h"
73 #include "third_party/blink/renderer/platform/transforms/scale_transform_operation.h"
74 #include "third_party/blink/renderer/platform/transforms/translate_transform_operation.h"
75 #include "third_party/blink/renderer/platform/wtf/assertions.h"
76 #include "third_party/blink/renderer/platform/wtf/math_extras.h"
77 #include "third_party/blink/renderer/platform/wtf/size_assertions.h"
78 #include "third_party/blink/renderer/platform/wtf/text/case_map.h"
79 #include "third_party/blink/renderer/platform/wtf/text/math_transform.h"
80 #include "ui/base/ui_base_features.h"
81 
82 namespace blink {
83 
84 struct SameSizeAsBorderValue {
85   StyleColor color_;
86   unsigned bitfield_;
87 };
88 
89 ASSERT_SIZE(BorderValue, SameSizeAsBorderValue);
90 
91 // Since different compilers/architectures pack ComputedStyle differently,
92 // re-create the same structure for an accurate size comparison.
93 //
94 // Keep a separate struct for ComputedStyleBase so that we can recreate the
95 // inheritance structure. Make sure the fields have the same access specifiers
96 // as in the "real" class since it can affect the layout. Reference the fields
97 // so that they are not seen as unused (-Wunused-private-field).
98 struct SameSizeAsComputedStyleBase {
SameSizeAsComputedStyleBaseblink::SameSizeAsComputedStyleBase99   SameSizeAsComputedStyleBase() {
100     base::debug::Alias(&data_refs);
101     base::debug::Alias(&bitfields);
102   }
103 
104  private:
105   void* data_refs[8];
106   unsigned bitfields[6];
107 };
108 
109 struct SameSizeAsComputedStyle : public SameSizeAsComputedStyleBase,
110                                  public RefCounted<SameSizeAsComputedStyle> {
SameSizeAsComputedStyleblink::SameSizeAsComputedStyle111   SameSizeAsComputedStyle() {
112     base::debug::Alias(&own_ptrs);
113     base::debug::Alias(&data_ref_svg_style);
114   }
115 
116  private:
117   void* own_ptrs[1];
118   void* data_ref_svg_style;
119 };
120 
121 // If this assert fails, it means that size of ComputedStyle has changed. Please
122 // check that you really *do* want to increase the size of ComputedStyle, then
123 // update the SameSizeAsComputedStyle struct to match the updated storage of
124 // ComputedStyle.
125 ASSERT_SIZE(ComputedStyle, SameSizeAsComputedStyle);
126 
Create()127 scoped_refptr<ComputedStyle> ComputedStyle::Create() {
128   return base::AdoptRef(new ComputedStyle(PassKey(), InitialStyle()));
129 }
130 
CreateInitialStyle()131 scoped_refptr<ComputedStyle> ComputedStyle::CreateInitialStyle() {
132   return base::AdoptRef(new ComputedStyle(PassKey()));
133 }
134 
MutableInitialStyle()135 ComputedStyle& ComputedStyle::MutableInitialStyle() {
136   LEAK_SANITIZER_DISABLED_SCOPE;
137   DEFINE_STATIC_REF(ComputedStyle, initial_style,
138                     (ComputedStyle::CreateInitialStyle()));
139   return *initial_style;
140 }
141 
InvalidateInitialStyle()142 void ComputedStyle::InvalidateInitialStyle() {
143   MutableInitialStyle().SetTapHighlightColor(
144       ComputedStyleInitialValues::InitialTapHighlightColor());
145 }
146 
CreateAnonymousStyleWithDisplay(const ComputedStyle & parent_style,EDisplay display)147 scoped_refptr<ComputedStyle> ComputedStyle::CreateAnonymousStyleWithDisplay(
148     const ComputedStyle& parent_style,
149     EDisplay display) {
150   scoped_refptr<ComputedStyle> new_style = ComputedStyle::Create();
151   new_style->InheritFrom(parent_style);
152   new_style->SetUnicodeBidi(parent_style.GetUnicodeBidi());
153   new_style->SetDisplay(display);
154   return new_style;
155 }
156 
157 scoped_refptr<ComputedStyle>
CreateInheritedDisplayContentsStyleIfNeeded(const ComputedStyle & parent_style,const ComputedStyle & layout_parent_style)158 ComputedStyle::CreateInheritedDisplayContentsStyleIfNeeded(
159     const ComputedStyle& parent_style,
160     const ComputedStyle& layout_parent_style) {
161   if (parent_style.InheritedEqual(layout_parent_style))
162     return nullptr;
163   return ComputedStyle::CreateAnonymousStyleWithDisplay(parent_style,
164                                                         EDisplay::kInline);
165 }
166 
Clone(const ComputedStyle & other)167 scoped_refptr<ComputedStyle> ComputedStyle::Clone(const ComputedStyle& other) {
168   return base::AdoptRef(new ComputedStyle(PassKey(), other));
169 }
170 
ComputedStyle()171 ALWAYS_INLINE ComputedStyle::ComputedStyle()
172     : ComputedStyleBase(), RefCounted<ComputedStyle>() {
173   svg_style_.Init();
174 }
175 
ComputedStyle(const ComputedStyle & o)176 ALWAYS_INLINE ComputedStyle::ComputedStyle(const ComputedStyle& o)
177     : ComputedStyleBase(o),
178       RefCounted<ComputedStyle>(),
179       svg_style_(o.svg_style_) {}
180 
ComputedStyle(PassKey key)181 ALWAYS_INLINE ComputedStyle::ComputedStyle(PassKey key) : ComputedStyle() {}
182 
ComputedStyle(PassKey key,const ComputedStyle & o)183 ALWAYS_INLINE ComputedStyle::ComputedStyle(PassKey key, const ComputedStyle& o)
184     : ComputedStyle(o) {}
185 
PseudoElementStylesEqual(const ComputedStyle & old_style,const ComputedStyle & new_style)186 static bool PseudoElementStylesEqual(const ComputedStyle& old_style,
187                                      const ComputedStyle& new_style) {
188   if (!old_style.HasAnyPseudoElementStyles() &&
189       !new_style.HasAnyPseudoElementStyles())
190     return true;
191   for (PseudoId pseudo_id = kFirstPublicPseudoId;
192        pseudo_id < kFirstInternalPseudoId;
193        pseudo_id = static_cast<PseudoId>(pseudo_id + 1)) {
194     if (!old_style.HasPseudoElementStyle(pseudo_id) &&
195         !new_style.HasPseudoElementStyle(pseudo_id))
196       continue;
197     const ComputedStyle* new_pseudo_style =
198         new_style.GetCachedPseudoElementStyle(pseudo_id);
199     if (!new_pseudo_style)
200       return false;
201     const ComputedStyle* old_pseudo_style =
202         old_style.GetCachedPseudoElementStyle(pseudo_id);
203     if (old_pseudo_style && *old_pseudo_style != *new_pseudo_style)
204       return false;
205   }
206   return true;
207 }
208 
NeedsReattachLayoutTree(const Element & element,const ComputedStyle * old_style,const ComputedStyle * new_style)209 bool ComputedStyle::NeedsReattachLayoutTree(const Element& element,
210                                             const ComputedStyle* old_style,
211                                             const ComputedStyle* new_style) {
212   if (old_style == new_style)
213     return false;
214   if (!old_style || !new_style)
215     return true;
216   if (old_style->Display() != new_style->Display())
217     return true;
218   if (old_style->HasPseudoElementStyle(kPseudoIdFirstLetter) !=
219       new_style->HasPseudoElementStyle(kPseudoIdFirstLetter))
220     return true;
221   if (!old_style->ContentDataEquivalent(*new_style))
222     return true;
223   if (old_style->HasTextCombine() != new_style->HasTextCombine())
224     return true;
225   // line-clamping is currently only handled by LayoutDeprecatedFlexibleBox,
226   // so that if line-clamping changes then the LayoutObject needs to be
227   // recreated.
228   if (old_style->IsDeprecatedFlexboxUsingFlexLayout() !=
229       new_style->IsDeprecatedFlexboxUsingFlexLayout())
230     return true;
231   // We need to perform a reattach if a "display: layout(foo)" has changed to a
232   // "display: layout(bar)". This is because one custom layout could be
233   // registered and the other may not, affecting the box-tree construction.
234   if (old_style->DisplayLayoutCustomName() !=
235       new_style->DisplayLayoutCustomName())
236     return true;
237   if (old_style->HasEffectiveAppearance() !=
238           new_style->HasEffectiveAppearance() &&
239       IsA<HTMLProgressElement>(element)) {
240     // HTMLProgressElement::CreateLayoutObject creates different LayoutObjects
241     // based on appearance.
242     return true;
243   }
244   if (!RuntimeEnabledFeatures::LayoutNGEnabled())
245     return false;
246 
247   // LayoutNG needs an anonymous inline wrapper if ::first-line is applied.
248   // Also see |LayoutBlockFlow::NeedsAnonymousInlineWrapper()|.
249   if (new_style->HasPseudoElementStyle(kPseudoIdFirstLine) &&
250       !old_style->HasPseudoElementStyle(kPseudoIdFirstLine))
251     return true;
252 
253   return false;
254 }
255 
ComputeDifference(const ComputedStyle * old_style,const ComputedStyle * new_style)256 ComputedStyle::Difference ComputedStyle::ComputeDifference(
257     const ComputedStyle* old_style,
258     const ComputedStyle* new_style) {
259   if (old_style == new_style)
260     return Difference::kEqual;
261   if (!old_style || !new_style)
262     return Difference::kInherited;
263 
264   // For inline elements, the new computed first line style will be |new_style|
265   // inheriting from the parent's first line style. If |new_style| is different
266   // from |old_style|'s cached inherited first line style, the new computed
267   // first line style may be different from the old even if |new_style| and
268   // |old_style| equal. Especially if the difference is on inherited properties,
269   // we need to propagate the difference to descendants.
270   // See external/wpt/css/css-pseudo/first-line-change-inline-color*.html.
271   auto inherited_first_line_style_diff = Difference::kEqual;
272   if (const ComputedStyle* cached_inherited_first_line_style =
273           old_style->GetCachedPseudoElementStyle(kPseudoIdFirstLineInherited)) {
274     DCHECK(
275         !new_style->GetCachedPseudoElementStyle(kPseudoIdFirstLineInherited));
276     inherited_first_line_style_diff =
277         ComputeDifferenceIgnoringInheritedFirstLineStyle(
278             *cached_inherited_first_line_style, *new_style);
279   }
280   return std::max(
281       inherited_first_line_style_diff,
282       ComputeDifferenceIgnoringInheritedFirstLineStyle(*old_style, *new_style));
283 }
284 
285 ComputedStyle::Difference
ComputeDifferenceIgnoringInheritedFirstLineStyle(const ComputedStyle & old_style,const ComputedStyle & new_style)286 ComputedStyle::ComputeDifferenceIgnoringInheritedFirstLineStyle(
287     const ComputedStyle& old_style,
288     const ComputedStyle& new_style) {
289   DCHECK_NE(&old_style, &new_style);
290   if (old_style.Display() != new_style.Display() &&
291       old_style.BlockifiesChildren() != new_style.BlockifiesChildren())
292     return Difference::kDisplayAffectingDescendantStyles;
293   if (!old_style.NonIndependentInheritedEqual(new_style))
294     return Difference::kInherited;
295   if (old_style.JustifyItems() != new_style.JustifyItems())
296     return Difference::kInherited;
297   bool non_inherited_equal = old_style.NonInheritedEqual(new_style);
298   if (!non_inherited_equal && old_style.ChildHasExplicitInheritance()) {
299     return Difference::kInherited;
300   }
301   bool variables_independent =
302       !old_style.HasVariableReference() && !old_style.HasVariableDeclaration();
303   bool inherited_variables_equal = old_style.InheritedVariablesEqual(new_style);
304   if (!inherited_variables_equal && !variables_independent)
305     return Difference::kInherited;
306   if (!old_style.IndependentInheritedEqual(new_style) ||
307       !inherited_variables_equal) {
308     return Difference::kIndependentInherited;
309   }
310   if (non_inherited_equal) {
311     DCHECK(old_style == new_style);
312     if (PseudoElementStylesEqual(old_style, new_style))
313       return Difference::kEqual;
314     return Difference::kPseudoElementStyle;
315   }
316   if (new_style.HasAnyPseudoElementStyles() ||
317       old_style.HasAnyPseudoElementStyles())
318     return Difference::kPseudoElementStyle;
319   if (old_style.Display() != new_style.Display() &&
320       (new_style.Display() == EDisplay::kListItem ||
321        old_style.Display() == EDisplay::kListItem))
322     return Difference::kPseudoElementStyle;
323   return Difference::kNonInherited;
324 }
325 
PropagateIndependentInheritedProperties(const ComputedStyle & parent_style)326 void ComputedStyle::PropagateIndependentInheritedProperties(
327     const ComputedStyle& parent_style) {
328   ComputedStyleBase::PropagateIndependentInheritedProperties(parent_style);
329   if (!HasVariableReference() && !HasVariableDeclaration())
330     InheritCustomPropertiesFrom(parent_style);
331 }
332 
ResolvedSelfAlignment(const StyleSelfAlignmentData & value,ItemPosition normal_value_behavior)333 StyleSelfAlignmentData ResolvedSelfAlignment(
334     const StyleSelfAlignmentData& value,
335     ItemPosition normal_value_behavior) {
336   if (value.GetPosition() == ItemPosition::kLegacy ||
337       value.GetPosition() == ItemPosition::kNormal ||
338       value.GetPosition() == ItemPosition::kAuto)
339     return {normal_value_behavior, OverflowAlignment::kDefault};
340   return value;
341 }
342 
ResolvedAlignItems(ItemPosition normal_value_behaviour) const343 StyleSelfAlignmentData ComputedStyle::ResolvedAlignItems(
344     ItemPosition normal_value_behaviour) const {
345   // We will return the behaviour of 'normal' value if needed, which is specific
346   // of each layout model.
347   return ResolvedSelfAlignment(AlignItems(), normal_value_behaviour);
348 }
349 
ResolvedAlignSelf(ItemPosition normal_value_behaviour,const ComputedStyle * parent_style) const350 StyleSelfAlignmentData ComputedStyle::ResolvedAlignSelf(
351     ItemPosition normal_value_behaviour,
352     const ComputedStyle* parent_style) const {
353   // We will return the behaviour of 'normal' value if needed, which is specific
354   // of each layout model.
355   if (!parent_style || AlignSelfPosition() != ItemPosition::kAuto)
356     return ResolvedSelfAlignment(AlignSelf(), normal_value_behaviour);
357 
358   // The 'auto' keyword computes to the parent's align-items computed value.
359   return parent_style->ResolvedAlignItems(normal_value_behaviour);
360 }
361 
ResolvedJustifyItems(ItemPosition normal_value_behaviour) const362 StyleSelfAlignmentData ComputedStyle::ResolvedJustifyItems(
363     ItemPosition normal_value_behaviour) const {
364   // We will return the behaviour of 'normal' value if needed, which is specific
365   // of each layout model.
366   return ResolvedSelfAlignment(JustifyItems(), normal_value_behaviour);
367 }
368 
ResolvedJustifySelf(ItemPosition normal_value_behaviour,const ComputedStyle * parent_style) const369 StyleSelfAlignmentData ComputedStyle::ResolvedJustifySelf(
370     ItemPosition normal_value_behaviour,
371     const ComputedStyle* parent_style) const {
372   // We will return the behaviour of 'normal' value if needed, which is specific
373   // of each layout model.
374   if (!parent_style || JustifySelfPosition() != ItemPosition::kAuto)
375     return ResolvedSelfAlignment(JustifySelf(), normal_value_behaviour);
376 
377   // The auto keyword computes to the parent's justify-items computed value.
378   return parent_style->ResolvedJustifyItems(normal_value_behaviour);
379 }
380 
ResolvedContentAlignment(const StyleContentAlignmentData & value,const StyleContentAlignmentData & normal_behaviour)381 StyleContentAlignmentData ResolvedContentAlignment(
382     const StyleContentAlignmentData& value,
383     const StyleContentAlignmentData& normal_behaviour) {
384   return (value.GetPosition() == ContentPosition::kNormal &&
385           value.Distribution() == ContentDistributionType::kDefault)
386              ? normal_behaviour
387              : value;
388 }
389 
ResolvedAlignContent(const StyleContentAlignmentData & normal_behaviour) const390 StyleContentAlignmentData ComputedStyle::ResolvedAlignContent(
391     const StyleContentAlignmentData& normal_behaviour) const {
392   // We will return the behaviour of 'normal' value if needed, which is specific
393   // of each layout model.
394   return ResolvedContentAlignment(AlignContent(), normal_behaviour);
395 }
396 
ResolvedJustifyContent(const StyleContentAlignmentData & normal_behaviour) const397 StyleContentAlignmentData ComputedStyle::ResolvedJustifyContent(
398     const StyleContentAlignmentData& normal_behaviour) const {
399   // We will return the behaviour of 'normal' value if needed, which is specific
400   // of each layout model.
401   return ResolvedContentAlignment(JustifyContent(), normal_behaviour);
402 }
403 
ResolvedContentAlignmentPosition(const StyleContentAlignmentData & value,const StyleContentAlignmentData & normal_value_behavior)404 static inline ContentPosition ResolvedContentAlignmentPosition(
405     const StyleContentAlignmentData& value,
406     const StyleContentAlignmentData& normal_value_behavior) {
407   return (value.GetPosition() == ContentPosition::kNormal &&
408           value.Distribution() == ContentDistributionType::kDefault)
409              ? normal_value_behavior.GetPosition()
410              : value.GetPosition();
411 }
412 
ResolvedContentAlignmentDistribution(const StyleContentAlignmentData & value,const StyleContentAlignmentData & normal_value_behavior)413 static inline ContentDistributionType ResolvedContentAlignmentDistribution(
414     const StyleContentAlignmentData& value,
415     const StyleContentAlignmentData& normal_value_behavior) {
416   return (value.GetPosition() == ContentPosition::kNormal &&
417           value.Distribution() == ContentDistributionType::kDefault)
418              ? normal_value_behavior.Distribution()
419              : value.Distribution();
420 }
421 
ResolvedJustifyContentPosition(const StyleContentAlignmentData & normal_value_behavior) const422 ContentPosition ComputedStyle::ResolvedJustifyContentPosition(
423     const StyleContentAlignmentData& normal_value_behavior) const {
424   return ResolvedContentAlignmentPosition(JustifyContent(),
425                                           normal_value_behavior);
426 }
427 
ResolvedJustifyContentDistribution(const StyleContentAlignmentData & normal_value_behavior) const428 ContentDistributionType ComputedStyle::ResolvedJustifyContentDistribution(
429     const StyleContentAlignmentData& normal_value_behavior) const {
430   return ResolvedContentAlignmentDistribution(JustifyContent(),
431                                               normal_value_behavior);
432 }
433 
ResolvedAlignContentPosition(const StyleContentAlignmentData & normal_value_behavior) const434 ContentPosition ComputedStyle::ResolvedAlignContentPosition(
435     const StyleContentAlignmentData& normal_value_behavior) const {
436   return ResolvedContentAlignmentPosition(AlignContent(),
437                                           normal_value_behavior);
438 }
439 
ResolvedAlignContentDistribution(const StyleContentAlignmentData & normal_value_behavior) const440 ContentDistributionType ComputedStyle::ResolvedAlignContentDistribution(
441     const StyleContentAlignmentData& normal_value_behavior) const {
442   return ResolvedContentAlignmentDistribution(AlignContent(),
443                                               normal_value_behavior);
444 }
445 
InheritFrom(const ComputedStyle & inherit_parent,IsAtShadowBoundary is_at_shadow_boundary)446 void ComputedStyle::InheritFrom(const ComputedStyle& inherit_parent,
447                                 IsAtShadowBoundary is_at_shadow_boundary) {
448   EUserModify current_user_modify = UserModify();
449 
450   ComputedStyleBase::InheritFrom(inherit_parent, is_at_shadow_boundary);
451   if (svg_style_ != inherit_parent.svg_style_)
452     svg_style_.Access()->InheritFrom(*inherit_parent.svg_style_);
453 
454   if (is_at_shadow_boundary == kAtShadowBoundary) {
455     // Even if surrounding content is user-editable, shadow DOM should act as a
456     // single unit, and not necessarily be editable
457     SetUserModify(current_user_modify);
458   }
459 }
460 
CopyNonInheritedFromCached(const ComputedStyle & other)461 void ComputedStyle::CopyNonInheritedFromCached(const ComputedStyle& other) {
462   DCHECK(MatchedPropertiesCache::IsStyleCacheable(other));
463 
464   ComputedStyleBase::CopyNonInheritedFromCached(other);
465 
466   // The flags are copied one-by-one because they contain
467   // bunch of stuff other than real style data.
468   // See comments for each skipped flag below.
469 
470   // Correctly set during selector matching:
471   // m_styleType
472   // m_pseudoBits
473 
474   // Set correctly while computing style for children:
475   // m_explicitInheritance
476 
477   // The following flags are set during matching before we decide that we get a
478   // match in the MatchedPropertiesCache which in turn calls this method. The
479   // reason why we don't copy these flags is that they're already correctly set
480   // and that they may differ between elements which have the same set of
481   // matched properties. For instance, given the rule:
482   //
483   // :-webkit-any(:hover, :focus) { background-color: green }"
484   //
485   // A hovered element, and a focused element may use the same cached matched
486   // properties here, but the affectedBy flags will be set differently based on
487   // the matching order of the :-webkit-any components.
488   //
489   // m_emptyState
490   // m_affectedByFocus
491   // m_affectedByHover
492   // m_affectedByActive
493   // m_affectedByDrag
494   // m_isLink
495 
496   if (svg_style_ != other.svg_style_)
497     svg_style_.Access()->CopyNonInheritedFromCached(*other.svg_style_);
498 }
499 
operator ==(const ComputedStyle & o) const500 bool ComputedStyle::operator==(const ComputedStyle& o) const {
501   return InheritedEqual(o) && NonInheritedEqual(o);
502 }
503 
GetCachedPseudoElementStyle(PseudoId pid) const504 const ComputedStyle* ComputedStyle::GetCachedPseudoElementStyle(
505     PseudoId pid) const {
506   if (!cached_pseudo_element_styles_ || !cached_pseudo_element_styles_->size())
507     return nullptr;
508 
509   if (StyleType() != kPseudoIdNone)
510     return nullptr;
511 
512   for (const auto& pseudo_style : *cached_pseudo_element_styles_) {
513     if (pseudo_style->StyleType() == pid)
514       return pseudo_style.get();
515   }
516 
517   return nullptr;
518 }
519 
CachedPseudoElementStylesDependOnFontMetrics() const520 bool ComputedStyle::CachedPseudoElementStylesDependOnFontMetrics() const {
521   if (!cached_pseudo_element_styles_ || !cached_pseudo_element_styles_->size())
522     return false;
523 
524   DCHECK_EQ(StyleType(), kPseudoIdNone);
525 
526   for (const auto& pseudo_style : *cached_pseudo_element_styles_) {
527     if (pseudo_style->DependsOnFontMetrics())
528       return true;
529   }
530 
531   return false;
532 }
533 
AddCachedPseudoElementStyle(scoped_refptr<const ComputedStyle> pseudo) const534 const ComputedStyle* ComputedStyle::AddCachedPseudoElementStyle(
535     scoped_refptr<const ComputedStyle> pseudo) const {
536   DCHECK(pseudo);
537   DCHECK_GT(pseudo->StyleType(), kPseudoIdNone);
538 
539   const ComputedStyle* result = pseudo.get();
540 
541   if (!cached_pseudo_element_styles_)
542     cached_pseudo_element_styles_ = std::make_unique<PseudoElementStyleCache>();
543 
544   cached_pseudo_element_styles_->push_back(std::move(pseudo));
545 
546   return result;
547 }
548 
InheritedEqual(const ComputedStyle & other) const549 bool ComputedStyle::InheritedEqual(const ComputedStyle& other) const {
550   return IndependentInheritedEqual(other) &&
551          NonIndependentInheritedEqual(other);
552 }
553 
IndependentInheritedEqual(const ComputedStyle & other) const554 bool ComputedStyle::IndependentInheritedEqual(
555     const ComputedStyle& other) const {
556   return ComputedStyleBase::IndependentInheritedEqual(other);
557 }
558 
NonIndependentInheritedEqual(const ComputedStyle & other) const559 bool ComputedStyle::NonIndependentInheritedEqual(
560     const ComputedStyle& other) const {
561   return ComputedStyleBase::NonIndependentInheritedEqual(other) &&
562          svg_style_->InheritedEqual(*other.svg_style_);
563 }
564 
NonInheritedEqual(const ComputedStyle & other) const565 bool ComputedStyle::NonInheritedEqual(const ComputedStyle& other) const {
566   // compare everything except the pseudoStyle pointer
567   return ComputedStyleBase::NonInheritedEqual(other) &&
568          svg_style_->NonInheritedEqual(*other.svg_style_);
569 }
570 
InheritedDataShared(const ComputedStyle & other) const571 bool ComputedStyle::InheritedDataShared(const ComputedStyle& other) const {
572   // This is a fast check that only looks if the data structures are shared.
573   return ComputedStyleBase::InheritedDataShared(other) &&
574          svg_style_.Get() == other.svg_style_.Get();
575 }
576 
DependenceOnContentHeightHasChanged(const ComputedStyle & a,const ComputedStyle & b)577 static bool DependenceOnContentHeightHasChanged(const ComputedStyle& a,
578                                                 const ComputedStyle& b) {
579   // If top or bottom become auto/non-auto then it means we either have to solve
580   // height based on the content or stop doing so
581   // (http://www.w3.org/TR/CSS2/visudet.html#abs-non-replaced-height)
582   // - either way requires a layout.
583   return a.LogicalTop().IsAuto() != b.LogicalTop().IsAuto() ||
584          a.LogicalBottom().IsAuto() != b.LogicalBottom().IsAuto();
585 }
586 
VisualInvalidationDiff(const Document & document,const ComputedStyle & other) const587 StyleDifference ComputedStyle::VisualInvalidationDiff(
588     const Document& document,
589     const ComputedStyle& other) const {
590   // Note, we use .Get() on each DataRef below because DataRef::operator== will
591   // do a deep compare, which is duplicate work when we're going to compare each
592   // property inside this function anyway.
593 
594   StyleDifference diff;
595   if (svg_style_.Get() != other.svg_style_.Get())
596     diff = svg_style_->Diff(*other.svg_style_);
597 
598   if ((!diff.NeedsReshape() || !diff.NeedsFullLayout() ||
599        !diff.NeedsPaintInvalidation()) &&
600       DiffNeedsReshapeAndFullLayoutAndPaintInvalidation(*this, other)) {
601     diff.SetNeedsReshape();
602     diff.SetNeedsFullLayout();
603     diff.SetNeedsPaintInvalidation();
604   }
605 
606   if ((!diff.NeedsFullLayout() || !diff.NeedsPaintInvalidation()) &&
607       DiffNeedsFullLayoutAndPaintInvalidation(other)) {
608     diff.SetNeedsFullLayout();
609     diff.SetNeedsPaintInvalidation();
610   }
611 
612   if (!diff.NeedsFullLayout() && DiffNeedsFullLayout(document, other))
613     diff.SetNeedsFullLayout();
614 
615   if (!diff.NeedsFullLayout() && !MarginEqual(other)) {
616     // Relative-positioned elements collapse their margins so need a full
617     // layout.
618     if (HasOutOfFlowPosition())
619       diff.SetNeedsPositionedMovementLayout();
620     else
621       diff.SetNeedsFullLayout();
622   }
623 
624   if (!diff.NeedsFullLayout() && GetPosition() != EPosition::kStatic &&
625       !OffsetEqual(other)) {
626     // Optimize for the case where a positioned layer is moving but not changing
627     // size.
628     if (DependenceOnContentHeightHasChanged(*this, other))
629       diff.SetNeedsFullLayout();
630     else
631       diff.SetNeedsPositionedMovementLayout();
632   }
633 
634   AdjustDiffForNeedsPaintInvalidation(other, diff, document);
635 
636   if (DiffNeedsVisualRectUpdate(other))
637     diff.SetNeedsVisualRectUpdate();
638 
639   UpdatePropertySpecificDifferences(other, diff);
640 
641   // The following condition needs to be at last, because it may depend on
642   // conditions in diff computed above.
643   if (ScrollAnchorDisablingPropertyChanged(other, diff))
644     diff.SetScrollAnchorDisablingPropertyChanged();
645 
646   // Cursors are not checked, since they will be set appropriately in response
647   // to mouse events, so they don't need to cause any paint invalidation or
648   // layout.
649 
650   // Animations don't need to be checked either. We always set the new style on
651   // the layoutObject, so we will get a chance to fire off the resulting
652   // transition properly.
653 
654   return diff;
655 }
656 
ScrollAnchorDisablingPropertyChanged(const ComputedStyle & other,const StyleDifference & diff) const657 bool ComputedStyle::ScrollAnchorDisablingPropertyChanged(
658     const ComputedStyle& other,
659     const StyleDifference& diff) const {
660   if (ComputedStyleBase::ScrollAnchorDisablingPropertyChanged(*this, other))
661     return true;
662 
663   if (diff.TransformChanged())
664     return true;
665 
666   return false;
667 }
668 
DiffNeedsFullLayoutAndPaintInvalidation(const ComputedStyle & other) const669 bool ComputedStyle::DiffNeedsFullLayoutAndPaintInvalidation(
670     const ComputedStyle& other) const {
671   // FIXME: Not all cases in this method need both full layout and paint
672   // invalidation.
673   // Should move cases into DiffNeedsFullLayout() if
674   // - don't need paint invalidation at all;
675   // - or the layoutObject knows how to exactly invalidate paints caused by the
676   //   layout change instead of forced full paint invalidation.
677 
678   if (ComputedStyleBase::DiffNeedsFullLayoutAndPaintInvalidation(*this, other))
679     return true;
680 
681   if (IsDisplayTableType(Display())) {
682     if (ComputedStyleBase::
683             DiffNeedsFullLayoutAndPaintInvalidationDisplayTableType(*this,
684                                                                     other))
685       return true;
686 
687     // In the collapsing border model, 'hidden' suppresses other borders, while
688     // 'none' does not, so these style differences can be width differences.
689     if ((BorderCollapse() == EBorderCollapse::kCollapse) &&
690         ((BorderTopStyle() == EBorderStyle::kHidden &&
691           other.BorderTopStyle() == EBorderStyle::kNone) ||
692          (BorderTopStyle() == EBorderStyle::kNone &&
693           other.BorderTopStyle() == EBorderStyle::kHidden) ||
694          (BorderBottomStyle() == EBorderStyle::kHidden &&
695           other.BorderBottomStyle() == EBorderStyle::kNone) ||
696          (BorderBottomStyle() == EBorderStyle::kNone &&
697           other.BorderBottomStyle() == EBorderStyle::kHidden) ||
698          (BorderLeftStyle() == EBorderStyle::kHidden &&
699           other.BorderLeftStyle() == EBorderStyle::kNone) ||
700          (BorderLeftStyle() == EBorderStyle::kNone &&
701           other.BorderLeftStyle() == EBorderStyle::kHidden) ||
702          (BorderRightStyle() == EBorderStyle::kHidden &&
703           other.BorderRightStyle() == EBorderStyle::kNone) ||
704          (BorderRightStyle() == EBorderStyle::kNone &&
705           other.BorderRightStyle() == EBorderStyle::kHidden)))
706       return true;
707   } else if (Display() == EDisplay::kListItem) {
708     if (ComputedStyleBase::
709             DiffNeedsFullLayoutAndPaintInvalidationDisplayListItem(*this,
710                                                                    other))
711       return true;
712   }
713 
714   if ((Visibility() == EVisibility::kCollapse) !=
715       (other.Visibility() == EVisibility::kCollapse))
716     return true;
717 
718   // Movement of non-static-positioned object is special cased in
719   // ComputedStyle::VisualInvalidationDiff().
720 
721   return false;
722 }
723 
DiffNeedsFullLayout(const Document & document,const ComputedStyle & other) const724 bool ComputedStyle::DiffNeedsFullLayout(const Document& document,
725                                         const ComputedStyle& other) const {
726   if (ComputedStyleBase::DiffNeedsFullLayout(*this, other))
727     return true;
728 
729   if (IsDisplayLayoutCustomBox()) {
730     if (DiffNeedsFullLayoutForLayoutCustom(document, other))
731       return true;
732   }
733 
734   if (DisplayLayoutCustomParentName()) {
735     if (DiffNeedsFullLayoutForLayoutCustomChild(document, other))
736       return true;
737   }
738 
739   return false;
740 }
741 
DiffNeedsFullLayoutForLayoutCustom(const Document & document,const ComputedStyle & other) const742 bool ComputedStyle::DiffNeedsFullLayoutForLayoutCustom(
743     const Document& document,
744     const ComputedStyle& other) const {
745   DCHECK(IsDisplayLayoutCustomBox());
746 
747   LayoutWorklet* worklet = LayoutWorklet::From(*document.domWindow());
748   const AtomicString& name = DisplayLayoutCustomName();
749 
750   if (!worklet->GetDocumentDefinitionMap()->Contains(name))
751     return false;
752 
753   const DocumentLayoutDefinition* definition =
754       worklet->GetDocumentDefinitionMap()->at(name);
755   if (definition == kInvalidDocumentLayoutDefinition)
756     return false;
757 
758   if (!PropertiesEqual(definition->NativeInvalidationProperties(), other))
759     return true;
760 
761   if (!CustomPropertiesEqual(definition->CustomInvalidationProperties(), other))
762     return true;
763 
764   return false;
765 }
766 
DiffNeedsFullLayoutForLayoutCustomChild(const Document & document,const ComputedStyle & other) const767 bool ComputedStyle::DiffNeedsFullLayoutForLayoutCustomChild(
768     const Document& document,
769     const ComputedStyle& other) const {
770   LayoutWorklet* worklet = LayoutWorklet::From(*document.domWindow());
771   const AtomicString& name = DisplayLayoutCustomParentName();
772 
773   if (!worklet->GetDocumentDefinitionMap()->Contains(name))
774     return false;
775 
776   const DocumentLayoutDefinition* definition =
777       worklet->GetDocumentDefinitionMap()->at(name);
778   if (definition == kInvalidDocumentLayoutDefinition)
779     return false;
780 
781   if (!PropertiesEqual(definition->ChildNativeInvalidationProperties(), other))
782     return true;
783 
784   if (!CustomPropertiesEqual(definition->ChildCustomInvalidationProperties(),
785                              other))
786     return true;
787 
788   return false;
789 }
790 
AdjustDiffForNeedsPaintInvalidation(const ComputedStyle & other,StyleDifference & diff,const Document & document) const791 void ComputedStyle::AdjustDiffForNeedsPaintInvalidation(
792     const ComputedStyle& other,
793     StyleDifference& diff,
794     const Document& document) const {
795   if (ComputedStyleBase::DiffNeedsPaintInvalidation(*this, other) ||
796       !BorderVisuallyEqual(other) || !RadiiEqual(other))
797     diff.SetNeedsPaintInvalidation();
798 
799   AdjustDiffForBackgroundVisuallyEqual(other, diff);
800 
801   if (diff.NeedsPaintInvalidation())
802     return;
803 
804   if (PaintImagesInternal()) {
805     for (const auto& image : *PaintImagesInternal()) {
806       DCHECK(image);
807       if (DiffNeedsPaintInvalidationForPaintImage(*image, other, document)) {
808         diff.SetNeedsPaintInvalidation();
809         return;
810       }
811     }
812   }
813 }
814 
AdjustDiffForBackgroundVisuallyEqual(const ComputedStyle & other,StyleDifference & diff) const815 void ComputedStyle::AdjustDiffForBackgroundVisuallyEqual(
816     const ComputedStyle& other,
817     StyleDifference& diff) const {
818   if (BackgroundColorInternal() != other.BackgroundColorInternal()) {
819     diff.SetNeedsPaintInvalidation();
820     if (BackgroundColorInternal()
821             .Resolve(GetCurrentColor(), UsedColorScheme())
822             .HasAlpha() !=
823         other.BackgroundColorInternal()
824             .Resolve(other.GetCurrentColor(), other.UsedColorScheme())
825             .HasAlpha()) {
826       diff.SetHasAlphaChanged();
827       return;
828     }
829   }
830   if (!BackgroundInternal().VisuallyEqual(other.BackgroundInternal())) {
831     diff.SetNeedsPaintInvalidation();
832     // Changes of background fill layers, such as images, may have
833     // changed alpha.
834     diff.SetHasAlphaChanged();
835   }
836 }
837 
DiffNeedsPaintInvalidationForPaintImage(const StyleImage & image,const ComputedStyle & other,const Document & document) const838 bool ComputedStyle::DiffNeedsPaintInvalidationForPaintImage(
839     const StyleImage& image,
840     const ComputedStyle& other,
841     const Document& document) const {
842   // https://crbug.com/835589: early exit when paint target is associated with
843   // a link.
844   if (InsideLink() != EInsideLink::kNotInsideLink)
845     return false;
846 
847   CSSPaintValue* value = To<CSSPaintValue>(image.CssValue());
848 
849   // NOTE: If the invalidation properties vectors are null, we are invalid as
850   // we haven't yet been painted (and can't provide the invalidation
851   // properties yet).
852   if (!value->NativeInvalidationProperties(document) ||
853       !value->CustomInvalidationProperties(document))
854     return true;
855 
856   if (!PropertiesEqual(*value->NativeInvalidationProperties(document), other))
857     return true;
858 
859   if (!CustomPropertiesEqual(*value->CustomInvalidationProperties(document),
860                              other))
861     return true;
862 
863   return false;
864 }
865 
PropertiesEqual(const Vector<CSSPropertyID> & properties,const ComputedStyle & other) const866 bool ComputedStyle::PropertiesEqual(const Vector<CSSPropertyID>& properties,
867                                     const ComputedStyle& other) const {
868   for (CSSPropertyID property_id : properties) {
869     // TODO(ikilpatrick): remove IsInterpolableProperty check once
870     // CSSPropertyEquality::PropertiesEqual correctly handles all properties.
871     const CSSProperty& property = CSSProperty::Get(property_id);
872     if (!property.IsInterpolable() ||
873         !CSSPropertyEquality::PropertiesEqual(PropertyHandle(property), *this,
874                                               other))
875       return false;
876   }
877 
878   return true;
879 }
880 
CustomPropertiesEqual(const Vector<AtomicString> & properties,const ComputedStyle & other) const881 bool ComputedStyle::CustomPropertiesEqual(
882     const Vector<AtomicString>& properties,
883     const ComputedStyle& other) const {
884   // Short-circuit if neither of the styles have custom properties.
885   if (!HasVariables() && !other.HasVariables())
886     return true;
887 
888   for (const AtomicString& property_name : properties) {
889     if (!DataEquivalent(GetVariableData(property_name),
890                         other.GetVariableData(property_name))) {
891       return false;
892     }
893     if (!DataEquivalent(GetVariableValue(property_name),
894                         other.GetVariableValue(property_name))) {
895       return false;
896     }
897   }
898 
899   return true;
900 }
901 
902 // This doesn't include conditions needing layout or overflow recomputation
903 // which implies visual rect update.
DiffNeedsVisualRectUpdate(const ComputedStyle & other) const904 bool ComputedStyle::DiffNeedsVisualRectUpdate(
905     const ComputedStyle& other) const {
906   // Visual rect is empty if visibility is hidden. Also need to update visual
907   // rect of the resizer.
908   return ComputedStyleBase::DiffNeedsVisualRectUpdate(*this, other);
909 }
910 
UpdatePropertySpecificDifferences(const ComputedStyle & other,StyleDifference & diff) const911 void ComputedStyle::UpdatePropertySpecificDifferences(
912     const ComputedStyle& other,
913     StyleDifference& diff) const {
914   if (ComputedStyleBase::UpdatePropertySpecificDifferencesZIndex(*this, other))
915     diff.SetZIndexChanged();
916 
917   if (UpdatePropertySpecificDifferencesTransform(*this, other))
918     diff.SetTransformChanged();
919 
920   if (ComputedStyleBase::UpdatePropertySpecificDifferencesOpacity(*this, other))
921     diff.SetOpacityChanged();
922 
923   if (ComputedStyleBase::UpdatePropertySpecificDifferencesFilter(*this, other))
924     diff.SetFilterChanged();
925 
926   if (ComputedStyleBase::
927           UpdatePropertySpecificDifferencesNeedsRecomputeVisualOverflow(*this,
928                                                                         other))
929     diff.SetNeedsRecomputeVisualOverflow();
930 
931   if (!diff.NeedsPaintInvalidation() &&
932       ComputedStyleBase::UpdatePropertySpecificDifferencesTextDecorationOrColor(
933           *this, other)) {
934     diff.SetTextDecorationOrColorChanged();
935   }
936 
937   if (ComputedStyleBase::UpdatePropertySpecificDifferencesMask(*this, other))
938     diff.SetMaskChanged();
939 
940   bool has_clip = HasOutOfFlowPosition() && !HasAutoClip();
941   bool other_has_clip = other.HasOutOfFlowPosition() && !other.HasAutoClip();
942   if (has_clip != other_has_clip ||
943       (has_clip && Clip() != other.Clip()))
944     diff.SetCSSClipChanged();
945 
946   if (GetBlendMode() != other.GetBlendMode())
947     diff.SetBlendModeChanged();
948 
949   if (HasCurrentTransformAnimation() != other.HasCurrentTransformAnimation() ||
950       HasCurrentOpacityAnimation() != other.HasCurrentOpacityAnimation() ||
951       HasCurrentFilterAnimation() != other.HasCurrentFilterAnimation() ||
952       HasCurrentBackdropFilterAnimation() !=
953           other.HasCurrentBackdropFilterAnimation() ||
954       SubtreeWillChangeContents() != other.SubtreeWillChangeContents() ||
955       BackfaceVisibility() != other.BackfaceVisibility() ||
956       UsedTransformStyle3D() != other.UsedTransformStyle3D() ||
957       ContainsPaint() != other.ContainsPaint() ||
958       IsOverflowVisibleAlongBothAxes() !=
959           other.IsOverflowVisibleAlongBothAxes() ||
960       WillChangeProperties() != other.WillChangeProperties() ||
961       !BackdropFilterDataEquivalent(other)) {
962     diff.SetCompositingReasonsChanged();
963   }
964 }
965 
AddPaintImage(StyleImage * image)966 void ComputedStyle::AddPaintImage(StyleImage* image) {
967   if (!MutablePaintImagesInternal()) {
968     SetPaintImagesInternal(std::make_unique<PaintImages>());
969   }
970   MutablePaintImagesInternal()->push_back(image);
971 }
972 
HasCSSPaintImagesUsingCustomProperty(const AtomicString & custom_property_name,const Document & document) const973 bool ComputedStyle::HasCSSPaintImagesUsingCustomProperty(
974     const AtomicString& custom_property_name,
975     const Document& document) const {
976   if (PaintImagesInternal()) {
977     for (const auto& image : *PaintImagesInternal()) {
978       DCHECK(image);
979       // IsPaintImage is true for CSS Paint images only, please refer to the
980       // constructor of StyleGeneratedImage.
981       if (image->IsPaintImage()) {
982         return To<StyleGeneratedImage>(image.Get())
983             ->IsUsingCustomProperty(custom_property_name, document);
984       }
985     }
986   }
987   return false;
988 }
989 
AddCursor(StyleImage * image,bool hot_spot_specified,const IntPoint & hot_spot)990 void ComputedStyle::AddCursor(StyleImage* image,
991                               bool hot_spot_specified,
992                               const IntPoint& hot_spot) {
993   if (!CursorDataInternal())
994     SetCursorDataInternal(MakeGarbageCollected<CursorList>());
995   MutableCursorDataInternal()->push_back(
996       CursorData(image, hot_spot_specified, hot_spot));
997 }
998 
SetCursorList(CursorList * other)999 void ComputedStyle::SetCursorList(CursorList* other) {
1000   SetCursorDataInternal(other);
1001 }
1002 
QuotesDataEquivalent(const ComputedStyle & other) const1003 bool ComputedStyle::QuotesDataEquivalent(const ComputedStyle& other) const {
1004   return DataEquivalent(Quotes(), other.Quotes());
1005 }
1006 
ClearCursorList()1007 void ComputedStyle::ClearCursorList() {
1008   if (CursorDataInternal())
1009     SetCursorDataInternal(nullptr);
1010 }
1011 
HasPropertyThatCreatesStackingContext(const Vector<CSSPropertyID> & properties)1012 static bool HasPropertyThatCreatesStackingContext(
1013     const Vector<CSSPropertyID>& properties) {
1014   for (CSSPropertyID property : properties) {
1015     switch (property) {
1016       case CSSPropertyID::kOpacity:
1017       case CSSPropertyID::kTransform:
1018       case CSSPropertyID::kAliasWebkitTransform:
1019       case CSSPropertyID::kTransformStyle:
1020       case CSSPropertyID::kAliasWebkitTransformStyle:
1021       case CSSPropertyID::kPerspective:
1022       case CSSPropertyID::kAliasWebkitPerspective:
1023       case CSSPropertyID::kTranslate:
1024       case CSSPropertyID::kRotate:
1025       case CSSPropertyID::kScale:
1026       case CSSPropertyID::kOffsetPath:
1027       case CSSPropertyID::kOffsetPosition:
1028       case CSSPropertyID::kWebkitMask:
1029       case CSSPropertyID::kWebkitMaskBoxImage:
1030       case CSSPropertyID::kClipPath:
1031       case CSSPropertyID::kAliasWebkitClipPath:
1032       case CSSPropertyID::kWebkitBoxReflect:
1033       case CSSPropertyID::kFilter:
1034       case CSSPropertyID::kAliasWebkitFilter:
1035       case CSSPropertyID::kBackdropFilter:
1036       case CSSPropertyID::kZIndex:
1037       case CSSPropertyID::kPosition:
1038       case CSSPropertyID::kMixBlendMode:
1039       case CSSPropertyID::kIsolation:
1040       case CSSPropertyID::kContain:
1041         return true;
1042       default:
1043         break;
1044     }
1045   }
1046   return false;
1047 }
1048 
UpdateIsStackingContextWithoutContainment(bool is_document_element,bool is_in_top_layer,bool is_svg_stacking)1049 void ComputedStyle::UpdateIsStackingContextWithoutContainment(
1050     bool is_document_element,
1051     bool is_in_top_layer,
1052     bool is_svg_stacking) {
1053   if (IsStackingContextWithoutContainment())
1054     return;
1055 
1056   // Force a stacking context for transform-style: preserve-3d. This happens
1057   // even if preserves-3d is ignored due to a 'grouping property' being present
1058   // which requires flattening. See:
1059   // ComputedStyle::HasGroupingPropertyForUsedTransformStyle3D().
1060   // This is legacy behavior that is left ambiguous in the official specs.
1061   // See https://crbug.com/663650 for more details.
1062   if (TransformStyle3D() == ETransformStyle3D::kPreserve3d) {
1063     SetIsStackingContextWithoutContainment(true);
1064     return;
1065   }
1066 
1067   if (is_document_element || is_in_top_layer || is_svg_stacking ||
1068       StyleType() == kPseudoIdBackdrop || HasTransformRelatedProperty() ||
1069       HasStackingGroupingProperty(BoxReflect()) ||
1070       HasViewportConstrainedPosition() || GetPosition() == EPosition::kSticky ||
1071       HasPropertyThatCreatesStackingContext(WillChangeProperties()) ||
1072       /* TODO(882625): This becomes unnecessary when will-change correctly takes
1073       into account active animations. */
1074       ShouldCompositeForCurrentAnimations()) {
1075     SetIsStackingContextWithoutContainment(true);
1076   }
1077 }
1078 
AddCallbackSelector(const String & selector)1079 void ComputedStyle::AddCallbackSelector(const String& selector) {
1080   if (!CallbackSelectors().Contains(selector))
1081     MutableCallbackSelectorsInternal().push_back(selector);
1082 }
1083 
SetContent(ContentData * content_data)1084 void ComputedStyle::SetContent(ContentData* content_data) {
1085   SetContentInternal(content_data);
1086 }
1087 
IsWillChangeTransformHintProperty(CSSPropertyID property)1088 static bool IsWillChangeTransformHintProperty(CSSPropertyID property) {
1089   switch (property) {
1090     case CSSPropertyID::kTransform:
1091     case CSSPropertyID::kAliasWebkitTransform:
1092     case CSSPropertyID::kPerspective:
1093     case CSSPropertyID::kTranslate:
1094     case CSSPropertyID::kScale:
1095     case CSSPropertyID::kRotate:
1096     case CSSPropertyID::kOffsetPath:
1097     case CSSPropertyID::kOffsetPosition:
1098       return true;
1099     default:
1100       break;
1101   }
1102   return false;
1103 }
1104 
IsWillChangeCompositingHintProperty(CSSPropertyID property)1105 static bool IsWillChangeCompositingHintProperty(CSSPropertyID property) {
1106   if (IsWillChangeTransformHintProperty(property))
1107     return true;
1108   switch (property) {
1109     case CSSPropertyID::kOpacity:
1110     case CSSPropertyID::kFilter:
1111     case CSSPropertyID::kAliasWebkitFilter:
1112     case CSSPropertyID::kBackdropFilter:
1113     case CSSPropertyID::kTop:
1114     case CSSPropertyID::kLeft:
1115     case CSSPropertyID::kBottom:
1116     case CSSPropertyID::kRight:
1117       return true;
1118     default:
1119       break;
1120   }
1121   return false;
1122 }
1123 
HasWillChangeCompositingHint() const1124 bool ComputedStyle::HasWillChangeCompositingHint() const {
1125   const auto& properties = WillChangeProperties();
1126   return std::any_of(properties.begin(), properties.end(),
1127                      IsWillChangeCompositingHintProperty);
1128 }
1129 
HasWillChangeTransformHint() const1130 bool ComputedStyle::HasWillChangeTransformHint() const {
1131   const auto& properties = WillChangeProperties();
1132   return std::any_of(properties.begin(), properties.end(),
1133                      IsWillChangeTransformHintProperty);
1134 }
1135 
RequireTransformOrigin(ApplyTransformOrigin apply_origin,ApplyMotionPath apply_motion_path) const1136 bool ComputedStyle::RequireTransformOrigin(
1137     ApplyTransformOrigin apply_origin,
1138     ApplyMotionPath apply_motion_path) const {
1139   // transform-origin brackets the transform with translate operations.
1140   // Optimize for the case where the only transform is a translation, since the
1141   // transform-origin is irrelevant in that case.
1142   if (apply_origin != kIncludeTransformOrigin)
1143     return false;
1144 
1145   if (apply_motion_path == kIncludeMotionPath)
1146     return true;
1147 
1148   for (const auto& operation : Transform().Operations()) {
1149     TransformOperation::OperationType type = operation->GetType();
1150     if (type != TransformOperation::kTranslateX &&
1151         type != TransformOperation::kTranslateY &&
1152         type != TransformOperation::kTranslate &&
1153         type != TransformOperation::kTranslateZ &&
1154         type != TransformOperation::kTranslate3D)
1155       return true;
1156   }
1157 
1158   return Scale() || Rotate();
1159 }
1160 
GetInterpolationQuality() const1161 InterpolationQuality ComputedStyle::GetInterpolationQuality() const {
1162   if (ImageRendering() == EImageRendering::kPixelated)
1163     return kInterpolationNone;
1164 
1165   if (ImageRendering() == EImageRendering::kWebkitOptimizeContrast)
1166     return kInterpolationLow;
1167 
1168   return kInterpolationDefault;
1169 }
1170 
LoadDeferredImages(Document & document) const1171 void ComputedStyle::LoadDeferredImages(Document& document) const {
1172   if (HasBackgroundImage()) {
1173     for (const FillLayer* background_layer = &BackgroundLayers();
1174          background_layer; background_layer = background_layer->Next()) {
1175       if (StyleImage* image = background_layer->GetImage()) {
1176         if (image->IsImageResource() && image->IsLazyloadPossiblyDeferred())
1177           To<StyleFetchedImage>(image)->LoadDeferredImage(document);
1178       }
1179     }
1180   }
1181 }
1182 
ApplyTransform(TransformationMatrix & result,const LayoutSize & border_box_size,ApplyTransformOrigin apply_origin,ApplyMotionPath apply_motion_path,ApplyIndependentTransformProperties apply_independent_transform_properties) const1183 void ComputedStyle::ApplyTransform(
1184     TransformationMatrix& result,
1185     const LayoutSize& border_box_size,
1186     ApplyTransformOrigin apply_origin,
1187     ApplyMotionPath apply_motion_path,
1188     ApplyIndependentTransformProperties apply_independent_transform_properties)
1189     const {
1190   ApplyTransform(result, FloatRect(FloatPoint(), FloatSize(border_box_size)),
1191                  apply_origin, apply_motion_path,
1192                  apply_independent_transform_properties);
1193 }
1194 
ApplyTransform(TransformationMatrix & result,const FloatRect & bounding_box,ApplyTransformOrigin apply_origin,ApplyMotionPath apply_motion_path,ApplyIndependentTransformProperties apply_independent_transform_properties) const1195 void ComputedStyle::ApplyTransform(
1196     TransformationMatrix& result,
1197     const FloatRect& bounding_box,
1198     ApplyTransformOrigin apply_origin,
1199     ApplyMotionPath apply_motion_path,
1200     ApplyIndependentTransformProperties apply_independent_transform_properties)
1201     const {
1202   if (!HasOffset())
1203     apply_motion_path = kExcludeMotionPath;
1204   bool apply_transform_origin =
1205       RequireTransformOrigin(apply_origin, apply_motion_path);
1206 
1207   float origin_x = 0;
1208   float origin_y = 0;
1209   float origin_z = 0;
1210 
1211   const FloatSize& box_size = bounding_box.Size();
1212   if (apply_transform_origin ||
1213       // We need to calculate originX and originY for applying motion path.
1214       apply_motion_path == kIncludeMotionPath) {
1215     origin_x = FloatValueForLength(TransformOriginX(), box_size.Width()) +
1216                bounding_box.X();
1217     origin_y = FloatValueForLength(TransformOriginY(), box_size.Height()) +
1218                bounding_box.Y();
1219     if (apply_transform_origin) {
1220       origin_z = TransformOriginZ();
1221       result.Translate3d(origin_x, origin_y, origin_z);
1222     }
1223   }
1224 
1225   if (apply_independent_transform_properties ==
1226       kIncludeIndependentTransformProperties) {
1227     if (Translate())
1228       Translate()->Apply(result, box_size);
1229 
1230     if (Rotate())
1231       Rotate()->Apply(result, box_size);
1232 
1233     if (Scale())
1234       Scale()->Apply(result, box_size);
1235   }
1236 
1237   if (apply_motion_path == kIncludeMotionPath)
1238     ApplyMotionPathTransform(origin_x, origin_y, bounding_box, result);
1239 
1240   for (const auto& operation : Transform().Operations())
1241     operation->Apply(result, box_size);
1242 
1243   if (apply_transform_origin) {
1244     result.Translate3d(-origin_x, -origin_y, -origin_z);
1245   }
1246 }
1247 
HasFilters() const1248 bool ComputedStyle::HasFilters() const {
1249   return FilterInternal().Get() && !FilterInternal()->operations_.IsEmpty();
1250 }
1251 
ApplyMotionPathTransform(float origin_x,float origin_y,const FloatRect & bounding_box,TransformationMatrix & transform) const1252 void ComputedStyle::ApplyMotionPathTransform(
1253     float origin_x,
1254     float origin_y,
1255     const FloatRect& bounding_box,
1256     TransformationMatrix& transform) const {
1257   // TODO(ericwilligers): crbug.com/638055 Apply offset-position.
1258   if (!OffsetPath()) {
1259     return;
1260   }
1261   const LengthPoint& position = OffsetPosition();
1262   const LengthPoint& anchor = OffsetAnchor();
1263   const Length& distance = OffsetDistance();
1264   const BasicShape* path = OffsetPath();
1265   const StyleOffsetRotation& rotate = OffsetRotate();
1266 
1267   FloatPoint point;
1268   float angle;
1269   if (path->GetType() == BasicShape::kStyleRayType) {
1270     // TODO(ericwilligers): crbug.com/641245 Support <size> for ray paths.
1271     float float_distance = FloatValueForLength(distance, 0);
1272 
1273     angle = To<StyleRay>(*path).Angle() - 90;
1274     point.SetX(float_distance * cos(deg2rad(angle)));
1275     point.SetY(float_distance * sin(deg2rad(angle)));
1276   } else {
1277     float zoom = EffectiveZoom();
1278     const StylePath& motion_path = To<StylePath>(*path);
1279     float path_length = motion_path.length();
1280     float float_distance =
1281         FloatValueForLength(distance, path_length * zoom) / zoom;
1282     float computed_distance;
1283     if (motion_path.IsClosed() && path_length > 0) {
1284       computed_distance = fmod(float_distance, path_length);
1285       if (computed_distance < 0)
1286         computed_distance += path_length;
1287     } else {
1288       computed_distance = clampTo<float>(float_distance, 0, path_length);
1289     }
1290 
1291     motion_path.GetPath().PointAndNormalAtLength(computed_distance, point,
1292                                                  angle);
1293 
1294     point.Scale(zoom, zoom);
1295   }
1296 
1297   if (rotate.type == OffsetRotationType::kFixed)
1298     angle = 0;
1299 
1300   float origin_shift_x = 0;
1301   float origin_shift_y = 0;
1302   // If the offset-position and offset-anchor properties are not yet enabled,
1303   // they will have the default value, auto.
1304   FloatPoint anchor_point(origin_x, origin_y);
1305   if (!position.X().IsAuto() || !anchor.X().IsAuto()) {
1306     anchor_point = FloatPointForLengthPoint(anchor, bounding_box.Size());
1307     anchor_point += bounding_box.Location();
1308 
1309     // Shift the origin from transform-origin to offset-anchor.
1310     origin_shift_x = anchor_point.X() - origin_x;
1311     origin_shift_y = anchor_point.Y() - origin_y;
1312   }
1313 
1314   transform.Translate(point.X() - anchor_point.X() + origin_shift_x,
1315                       point.Y() - anchor_point.Y() + origin_shift_y);
1316   transform.Rotate(angle + rotate.angle);
1317 
1318   if (!position.X().IsAuto() || !anchor.X().IsAuto())
1319     // Shift the origin back to transform-origin.
1320     transform.Translate(-origin_shift_x, -origin_shift_y);
1321 }
1322 
TextShadowDataEquivalent(const ComputedStyle & other) const1323 bool ComputedStyle::TextShadowDataEquivalent(const ComputedStyle& other) const {
1324   return DataEquivalent(TextShadow(), other.TextShadow());
1325 }
1326 
ListStyleImage() const1327 StyleImage* ComputedStyle::ListStyleImage() const {
1328   return ListStyleImageInternal();
1329 }
SetListStyleImage(StyleImage * v)1330 void ComputedStyle::SetListStyleImage(StyleImage* v) {
1331   SetListStyleImageInternal(v);
1332 }
1333 
SetEffectiveZoom(float f)1334 bool ComputedStyle::SetEffectiveZoom(float f) {
1335   // Clamp the effective zoom value to a smaller (but hopeful still large
1336   // enough) range, to avoid overflow in derived computations.
1337   float clamped_effective_zoom = clampTo<float>(f, 1e-6, 1e6);
1338   if (EffectiveZoom() == clamped_effective_zoom)
1339     return false;
1340   SetEffectiveZoomInternal(clamped_effective_zoom);
1341   // Record UMA for the effective zoom in order to assess the relative
1342   // importance of sub-pixel behavior, and related features and bugs.
1343   // Clamp to a max of 400%, to make the histogram behave better at no
1344   // real cost to our understanding of the zooms in use.
1345   base::UmaHistogramSparse(
1346       "Blink.EffectiveZoom",
1347       base::ClampToRange<float>(clamped_effective_zoom * 100, 0, 400));
1348   return true;
1349 }
1350 
CanRenderBorderImage() const1351 bool ComputedStyle::CanRenderBorderImage() const {
1352   if (!HasBorderDecoration())
1353     return false;
1354 
1355   StyleImage* border_image = BorderImage().GetImage();
1356   return border_image && border_image->CanRender() && border_image->IsLoaded();
1357 }
1358 
GetCounterDirectives() const1359 const CounterDirectiveMap* ComputedStyle::GetCounterDirectives() const {
1360   return CounterDirectivesInternal().get();
1361 }
1362 
AccessCounterDirectives()1363 CounterDirectiveMap& ComputedStyle::AccessCounterDirectives() {
1364   std::unique_ptr<CounterDirectiveMap>& map =
1365       MutableCounterDirectivesInternal();
1366   if (!map)
1367     map = std::make_unique<CounterDirectiveMap>();
1368   return *map;
1369 }
1370 
GetCounterDirectives(const AtomicString & identifier) const1371 const CounterDirectives ComputedStyle::GetCounterDirectives(
1372     const AtomicString& identifier) const {
1373   if (const CounterDirectiveMap* directives = GetCounterDirectives())
1374     return directives->at(identifier);
1375   return CounterDirectives();
1376 }
1377 
ClearIncrementDirectives()1378 void ComputedStyle::ClearIncrementDirectives() {
1379   if (!GetCounterDirectives())
1380     return;
1381 
1382   // This makes us copy even if we may not be removing any items.
1383   CounterDirectiveMap& map = AccessCounterDirectives();
1384   typedef CounterDirectiveMap::iterator Iterator;
1385 
1386   Iterator end = map.end();
1387   for (Iterator it = map.begin(); it != end; ++it)
1388     it->value.ClearIncrement();
1389 }
1390 
ClearResetDirectives()1391 void ComputedStyle::ClearResetDirectives() {
1392   if (!GetCounterDirectives())
1393     return;
1394 
1395   // This makes us copy even if we may not be removing any items.
1396   CounterDirectiveMap& map = AccessCounterDirectives();
1397   typedef CounterDirectiveMap::iterator Iterator;
1398 
1399   Iterator end = map.end();
1400   for (Iterator it = map.begin(); it != end; ++it)
1401     it->value.ClearReset();
1402 }
1403 
ClearSetDirectives()1404 void ComputedStyle::ClearSetDirectives() {
1405   if (!GetCounterDirectives())
1406     return;
1407 
1408   auto& map = AccessCounterDirectives();
1409   for (auto& value_pair : map)
1410     value_pair.value.ClearSet();
1411 }
1412 
LocaleForLineBreakIterator() const1413 AtomicString ComputedStyle::LocaleForLineBreakIterator() const {
1414   LineBreakIteratorMode mode = LineBreakIteratorMode::kDefault;
1415   switch (GetLineBreak()) {
1416     case LineBreak::kAuto:
1417     case LineBreak::kAfterWhiteSpace:
1418     case LineBreak::kAnywhere:
1419       return Locale();
1420     case LineBreak::kNormal:
1421       mode = LineBreakIteratorMode::kNormal;
1422       break;
1423     case LineBreak::kStrict:
1424       mode = LineBreakIteratorMode::kStrict;
1425       break;
1426     case LineBreak::kLoose:
1427       mode = LineBreakIteratorMode::kLoose;
1428       break;
1429   }
1430   if (const LayoutLocale* locale = GetFontDescription().Locale())
1431     return locale->LocaleWithBreakKeyword(mode);
1432   return Locale();
1433 }
1434 
GetHyphenation() const1435 Hyphenation* ComputedStyle::GetHyphenation() const {
1436   if (GetHyphens() != Hyphens::kAuto)
1437     return nullptr;
1438   if (const LayoutLocale* locale = GetFontDescription().Locale())
1439     return locale->GetHyphenation();
1440   return nullptr;
1441 }
1442 
HyphenString() const1443 const AtomicString& ComputedStyle::HyphenString() const {
1444   const AtomicString& hyphenation_string = HyphenationString();
1445   if (!hyphenation_string.IsNull())
1446     return hyphenation_string;
1447 
1448   // FIXME: This should depend on locale.
1449   DEFINE_STATIC_LOCAL(AtomicString, hyphen_minus_string,
1450                       (&kHyphenMinusCharacter, 1));
1451   DEFINE_STATIC_LOCAL(AtomicString, hyphen_string, (&kHyphenCharacter, 1));
1452   const SimpleFontData* primary_font = GetFont().PrimaryFont();
1453   DCHECK(primary_font);
1454   return primary_font && primary_font->GlyphForCharacter(kHyphenCharacter)
1455              ? hyphen_string
1456              : hyphen_minus_string;
1457 }
1458 
GetTextAlign(bool is_last_line) const1459 ETextAlign ComputedStyle::GetTextAlign(bool is_last_line) const {
1460   if (!is_last_line)
1461     return GetTextAlign();
1462 
1463   // When this is the last line of a block, or the line ends with a forced line
1464   // break.
1465   // https://drafts.csswg.org/css-text-3/#propdef-text-align-last
1466   switch (TextAlignLast()) {
1467     case ETextAlignLast::kStart:
1468       return ETextAlign::kStart;
1469     case ETextAlignLast::kEnd:
1470       return ETextAlign::kEnd;
1471     case ETextAlignLast::kLeft:
1472       return ETextAlign::kLeft;
1473     case ETextAlignLast::kRight:
1474       return ETextAlign::kRight;
1475     case ETextAlignLast::kCenter:
1476       return ETextAlign::kCenter;
1477     case ETextAlignLast::kJustify:
1478       return ETextAlign::kJustify;
1479     case ETextAlignLast::kAuto:
1480       ETextAlign text_align = GetTextAlign();
1481       if (text_align == ETextAlign::kJustify)
1482         return ETextAlign::kStart;
1483       return text_align;
1484   }
1485   NOTREACHED();
1486   return GetTextAlign();
1487 }
1488 
ShouldUseTextIndent(bool is_first_line,bool is_after_forced_break) const1489 bool ComputedStyle::ShouldUseTextIndent(bool is_first_line,
1490                                         bool is_after_forced_break) const {
1491   bool should_use =
1492       is_first_line || (is_after_forced_break &&
1493                         GetTextIndentLine() != TextIndentLine::kFirstLine);
1494   return GetTextIndentType() == TextIndentType::kNormal ? should_use
1495                                                         : !should_use;
1496 }
1497 
1498 // Unicode 11 introduced Georgian capital letters (U+1C90 - U+1CBA,
1499 // U+1CB[D-F]), but virtually no font covers them. For now map them back
1500 // to their lowercase counterparts (U+10D0 - U+10FA, U+10F[D-F]).
1501 // https://www.unicode.org/charts/PDF/U10A0.pdf
1502 // https://www.unicode.org/charts/PDF/U1C90.pdf
1503 // See https://crbug.com/865427 .
1504 // TODO(jshin): Make this platform-dependent. For instance, turn this
1505 // off when CrOS gets new Georgian fonts covering capital letters.
1506 // ( https://crbug.com/880144 ).
DisableNewGeorgianCapitalLetters(const String & text)1507 static String DisableNewGeorgianCapitalLetters(const String& text) {
1508   if (text.IsNull() || text.Is8Bit())
1509     return text;
1510   unsigned length = text.length();
1511   const StringImpl& input = *(text.Impl());
1512   StringBuilder result;
1513   result.ReserveCapacity(length);
1514   // |input| must be well-formed UTF-16 so that there's no worry
1515   // about surrogate handling.
1516   for (unsigned i = 0; i < length; ++i) {
1517     UChar character = input[i];
1518     if (Character::IsModernGeorgianUppercase(character))
1519       result.Append(Character::LowercaseModernGeorgianUppercase(character));
1520     else
1521       result.Append(character);
1522   }
1523   return result.ToString();
1524 }
1525 
1526 namespace {
1527 
1528 // TODO(https://crbug.com/1076420): this needs to handle all text-transform
1529 // values.
ApplyMathTransform(String * text,ETextTransform math_variant)1530 static void ApplyMathTransform(String* text, ETextTransform math_variant) {
1531   DCHECK(math_variant == ETextTransform::kMathAuto);
1532   DCHECK_EQ(text->length(), 1u);
1533   UChar character = (*text)[0];
1534   UChar32 transformed_char = MathVariant((*text)[0]);
1535   if (transformed_char == static_cast<UChar32>(character))
1536     return;
1537 
1538   Vector<UChar> transformed_text(U16_LENGTH(transformed_char));
1539   int i = 0;
1540   U16_APPEND_UNSAFE(transformed_text, i, transformed_char);
1541   *text = String(transformed_text);
1542 }
1543 
1544 }  // namespace
1545 
ApplyTextTransform(String * text,UChar previous_character) const1546 void ComputedStyle::ApplyTextTransform(String* text,
1547                                        UChar previous_character) const {
1548   switch (TextTransform()) {
1549     case ETextTransform::kNone:
1550       return;
1551     case ETextTransform::kCapitalize:
1552       *text = Capitalize(*text, previous_character);
1553       return;
1554     case ETextTransform::kUppercase: {
1555       const LayoutLocale* locale = GetFontDescription().Locale();
1556       CaseMap case_map(locale ? locale->CaseMapLocale() : CaseMap::Locale());
1557       *text = DisableNewGeorgianCapitalLetters(case_map.ToUpper(*text));
1558       return;
1559     }
1560     case ETextTransform::kLowercase: {
1561       const LayoutLocale* locale = GetFontDescription().Locale();
1562       CaseMap case_map(locale ? locale->CaseMapLocale() : CaseMap::Locale());
1563       *text = case_map.ToLower(*text);
1564       return;
1565     }
1566     case ETextTransform::kMathAuto:
1567       if (text->length() == 1)
1568         ApplyMathTransform(text, ETextTransform::kMathAuto);
1569       return;
1570   }
1571   NOTREACHED();
1572 }
1573 
TextEmphasisMarkString() const1574 const AtomicString& ComputedStyle::TextEmphasisMarkString() const {
1575   switch (GetTextEmphasisMark()) {
1576     case TextEmphasisMark::kNone:
1577       return g_null_atom;
1578     case TextEmphasisMark::kCustom:
1579       return TextEmphasisCustomMark();
1580     case TextEmphasisMark::kDot: {
1581       DEFINE_STATIC_LOCAL(AtomicString, filled_dot_string,
1582                           (&kBulletCharacter, 1));
1583       DEFINE_STATIC_LOCAL(AtomicString, open_dot_string,
1584                           (&kWhiteBulletCharacter, 1));
1585       return GetTextEmphasisFill() == TextEmphasisFill::kFilled
1586                  ? filled_dot_string
1587                  : open_dot_string;
1588     }
1589     case TextEmphasisMark::kCircle: {
1590       DEFINE_STATIC_LOCAL(AtomicString, filled_circle_string,
1591                           (&kBlackCircleCharacter, 1));
1592       DEFINE_STATIC_LOCAL(AtomicString, open_circle_string,
1593                           (&kWhiteCircleCharacter, 1));
1594       return GetTextEmphasisFill() == TextEmphasisFill::kFilled
1595                  ? filled_circle_string
1596                  : open_circle_string;
1597     }
1598     case TextEmphasisMark::kDoubleCircle: {
1599       DEFINE_STATIC_LOCAL(AtomicString, filled_double_circle_string,
1600                           (&kFisheyeCharacter, 1));
1601       DEFINE_STATIC_LOCAL(AtomicString, open_double_circle_string,
1602                           (&kBullseyeCharacter, 1));
1603       return GetTextEmphasisFill() == TextEmphasisFill::kFilled
1604                  ? filled_double_circle_string
1605                  : open_double_circle_string;
1606     }
1607     case TextEmphasisMark::kTriangle: {
1608       DEFINE_STATIC_LOCAL(AtomicString, filled_triangle_string,
1609                           (&kBlackUpPointingTriangleCharacter, 1));
1610       DEFINE_STATIC_LOCAL(AtomicString, open_triangle_string,
1611                           (&kWhiteUpPointingTriangleCharacter, 1));
1612       return GetTextEmphasisFill() == TextEmphasisFill::kFilled
1613                  ? filled_triangle_string
1614                  : open_triangle_string;
1615     }
1616     case TextEmphasisMark::kSesame: {
1617       DEFINE_STATIC_LOCAL(AtomicString, filled_sesame_string,
1618                           (&kSesameDotCharacter, 1));
1619       DEFINE_STATIC_LOCAL(AtomicString, open_sesame_string,
1620                           (&kWhiteSesameDotCharacter, 1));
1621       return GetTextEmphasisFill() == TextEmphasisFill::kFilled
1622                  ? filled_sesame_string
1623                  : open_sesame_string;
1624     }
1625     case TextEmphasisMark::kAuto:
1626       NOTREACHED();
1627       return g_null_atom;
1628   }
1629 
1630   NOTREACHED();
1631   return g_null_atom;
1632 }
1633 
GetTextEmphasisLineLogicalSide() const1634 LineLogicalSide ComputedStyle::GetTextEmphasisLineLogicalSide() const {
1635   TextEmphasisPosition position = GetTextEmphasisPosition();
1636   if (IsHorizontalWritingMode()) {
1637     return position == TextEmphasisPosition::kOverRight ||
1638                    position == TextEmphasisPosition::kOverLeft
1639                ? LineLogicalSide::kOver
1640                : LineLogicalSide::kUnder;
1641   }
1642   if (GetWritingMode() != WritingMode::kSidewaysLr) {
1643     return position == TextEmphasisPosition::kOverRight ||
1644                    position == TextEmphasisPosition::kUnderRight
1645                ? LineLogicalSide::kOver
1646                : LineLogicalSide::kUnder;
1647   }
1648   return position == TextEmphasisPosition::kOverLeft ||
1649                  position == TextEmphasisPosition::kUnderLeft
1650              ? LineLogicalSide::kOver
1651              : LineLogicalSide::kUnder;
1652 }
1653 
AccessAnimations()1654 CSSAnimationData& ComputedStyle::AccessAnimations() {
1655   std::unique_ptr<CSSAnimationData>& animations = MutableAnimationsInternal();
1656   if (!animations)
1657     animations = std::make_unique<CSSAnimationData>();
1658   return *animations;
1659 }
1660 
AccessTransitions()1661 CSSTransitionData& ComputedStyle::AccessTransitions() {
1662   std::unique_ptr<CSSTransitionData>& transitions =
1663       MutableTransitionsInternal();
1664   if (!transitions)
1665     transitions = std::make_unique<CSSTransitionData>();
1666   return *transitions;
1667 }
1668 
GetFontBaseline() const1669 FontBaseline ComputedStyle::GetFontBaseline() const {
1670   // TODO(kojii): Incorporate 'dominant-baseline' when we support it.
1671   // https://www.w3.org/TR/css-inline-3/#dominant-baseline-property
1672 
1673   // Vertical flow (except 'text-orientation: sideways') uses ideographic
1674   // baseline. https://drafts.csswg.org/css-writing-modes-3/#intro-baselines
1675   return !GetFontDescription().IsVerticalAnyUpright() ? kAlphabeticBaseline
1676                                                       : kIdeographicBaseline;
1677 }
1678 
GetFontHeight(FontBaseline baseline) const1679 FontHeight ComputedStyle::GetFontHeight(FontBaseline baseline) const {
1680   if (const SimpleFontData* font_data = GetFont().PrimaryFont())
1681     return font_data->GetFontMetrics().GetFontHeight(baseline);
1682   NOTREACHED();
1683   return FontHeight();
1684 }
1685 
ComputeFontOrientation() const1686 FontOrientation ComputedStyle::ComputeFontOrientation() const {
1687   if (IsHorizontalWritingMode())
1688     return FontOrientation::kHorizontal;
1689 
1690   switch (GetTextOrientation()) {
1691     case ETextOrientation::kMixed:
1692       return FontOrientation::kVerticalMixed;
1693     case ETextOrientation::kUpright:
1694       return FontOrientation::kVerticalUpright;
1695     case ETextOrientation::kSideways:
1696       return FontOrientation::kVerticalRotated;
1697     default:
1698       NOTREACHED();
1699       return FontOrientation::kVerticalMixed;
1700   }
1701 }
1702 
UpdateFontOrientation()1703 void ComputedStyle::UpdateFontOrientation() {
1704   FontOrientation orientation = ComputeFontOrientation();
1705   if (GetFontDescription().Orientation() == orientation)
1706     return;
1707   FontDescription font_description = GetFontDescription();
1708   font_description.SetOrientation(orientation);
1709   SetFontDescription(font_description);
1710 }
1711 
TextDecorationVisualOverflowEqual(const ComputedStyle & o) const1712 bool ComputedStyle::TextDecorationVisualOverflowEqual(
1713     const ComputedStyle& o) const {
1714   const Vector<AppliedTextDecoration>& applied_with_this =
1715       AppliedTextDecorations();
1716   const Vector<AppliedTextDecoration>& applied_with_other =
1717       o.AppliedTextDecorations();
1718   if (applied_with_this.size() != applied_with_other.size())
1719     return false;
1720   for (auto decoration_index = 0u; decoration_index < applied_with_this.size();
1721        ++decoration_index) {
1722     const AppliedTextDecoration& decoration_from_this =
1723         applied_with_this[decoration_index];
1724     const AppliedTextDecoration& decoration_from_other =
1725         applied_with_other[decoration_index];
1726     if (decoration_from_this.Thickness() != decoration_from_other.Thickness() ||
1727         decoration_from_this.UnderlineOffset() !=
1728             decoration_from_other.UnderlineOffset() ||
1729         decoration_from_this.Style() != decoration_from_other.Style() ||
1730         decoration_from_this.Lines() != decoration_from_other.Lines())
1731       return false;
1732   }
1733   if (TextUnderlinePosition() != o.TextUnderlinePosition())
1734     return false;
1735 
1736   return true;
1737 }
1738 
TextDecorationsInEffect() const1739 TextDecoration ComputedStyle::TextDecorationsInEffect() const {
1740   if (HasSimpleUnderlineInternal())
1741     return TextDecoration::kUnderline;
1742   if (!AppliedTextDecorationsInternal())
1743     return TextDecoration::kNone;
1744 
1745   TextDecoration decorations = TextDecoration::kNone;
1746 
1747   const Vector<AppliedTextDecoration>& applied = AppliedTextDecorations();
1748 
1749   for (const AppliedTextDecoration& decoration : applied)
1750     decorations |= decoration.Lines();
1751 
1752   return decorations;
1753 }
1754 
AppliedTextDecorations() const1755 const Vector<AppliedTextDecoration>& ComputedStyle::AppliedTextDecorations()
1756     const {
1757   if (HasSimpleUnderlineInternal()) {
1758     DEFINE_STATIC_LOCAL(
1759         Vector<AppliedTextDecoration>, underline,
1760         (1, AppliedTextDecoration(
1761                 TextDecoration::kUnderline, ETextDecorationStyle::kSolid,
1762                 VisitedDependentColor(GetCSSPropertyTextDecorationColor()),
1763                 TextDecorationThickness(), Length::Auto())));
1764     // Since we only have one of these in memory, just update the color before
1765     // returning.
1766     underline.at(0).SetColor(
1767         VisitedDependentColor(GetCSSPropertyTextDecorationColor()));
1768     return underline;
1769   }
1770   if (!AppliedTextDecorationsInternal()) {
1771     DEFINE_STATIC_LOCAL(Vector<AppliedTextDecoration>, empty, ());
1772     return empty;
1773   }
1774 
1775   return AppliedTextDecorationsInternal()->data;
1776 }
1777 
HasInitialVariables(const StyleInitialData * initial_data)1778 static bool HasInitialVariables(const StyleInitialData* initial_data) {
1779   return initial_data && initial_data->HasInitialVariables();
1780 }
1781 
HasVariables() const1782 bool ComputedStyle::HasVariables() const {
1783   return InheritedVariables() || NonInheritedVariables() ||
1784          HasInitialVariables(InitialDataInternal().get());
1785 }
1786 
GetVariableNames() const1787 HashSet<AtomicString> ComputedStyle::GetVariableNames() const {
1788   HashSet<AtomicString> names;
1789   if (auto* initial_data = InitialDataInternal().get())
1790     initial_data->CollectVariableNames(names);
1791   if (auto* inherited_variables = InheritedVariables())
1792     inherited_variables->CollectNames(names);
1793   if (auto* non_inherited_variables = NonInheritedVariables())
1794     non_inherited_variables->CollectNames(names);
1795   return names;
1796 }
1797 
InheritedVariables() const1798 StyleInheritedVariables* ComputedStyle::InheritedVariables() const {
1799   return InheritedVariablesInternal().get();
1800 }
1801 
NonInheritedVariables() const1802 StyleNonInheritedVariables* ComputedStyle::NonInheritedVariables() const {
1803   return NonInheritedVariablesInternal().get();
1804 }
1805 
MutableInheritedVariables()1806 StyleInheritedVariables& ComputedStyle::MutableInheritedVariables() {
1807   scoped_refptr<StyleInheritedVariables>& variables =
1808       MutableInheritedVariablesInternal();
1809   if (!variables)
1810     variables = StyleInheritedVariables::Create();
1811   else if (!variables->HasOneRef())
1812     variables = variables->Copy();
1813   return *variables;
1814 }
1815 
MutableNonInheritedVariables()1816 StyleNonInheritedVariables& ComputedStyle::MutableNonInheritedVariables() {
1817   std::unique_ptr<StyleNonInheritedVariables>& variables =
1818       MutableNonInheritedVariablesInternal();
1819   if (!variables)
1820     variables = std::make_unique<StyleNonInheritedVariables>();
1821   return *variables;
1822 }
1823 
SetInitialData(scoped_refptr<StyleInitialData> data)1824 void ComputedStyle::SetInitialData(scoped_refptr<StyleInitialData> data) {
1825   MutableInitialDataInternal() = std::move(data);
1826 }
1827 
SetVariableData(const AtomicString & name,scoped_refptr<CSSVariableData> value,bool is_inherited_property)1828 void ComputedStyle::SetVariableData(const AtomicString& name,
1829                                     scoped_refptr<CSSVariableData> value,
1830                                     bool is_inherited_property) {
1831   if (is_inherited_property)
1832     MutableInheritedVariables().SetData(name, std::move(value));
1833   else
1834     MutableNonInheritedVariables().SetData(name, std::move(value));
1835 }
1836 
SetVariableValue(const AtomicString & name,const CSSValue * value,bool is_inherited_property)1837 void ComputedStyle::SetVariableValue(const AtomicString& name,
1838                                      const CSSValue* value,
1839                                      bool is_inherited_property) {
1840   if (is_inherited_property)
1841     MutableInheritedVariables().SetValue(name, value);
1842   else
1843     MutableNonInheritedVariables().SetValue(name, value);
1844 }
1845 
GetInitialVariableData(const AtomicString & name,const StyleInitialData * initial_data)1846 static CSSVariableData* GetInitialVariableData(
1847     const AtomicString& name,
1848     const StyleInitialData* initial_data) {
1849   if (!initial_data)
1850     return nullptr;
1851   return initial_data->GetVariableData(name);
1852 }
1853 
GetVariableData(const AtomicString & name) const1854 CSSVariableData* ComputedStyle::GetVariableData(
1855     const AtomicString& name) const {
1856   if (InheritedVariables()) {
1857     if (auto data = InheritedVariables()->GetData(name))
1858       return *data;
1859   }
1860   if (NonInheritedVariables()) {
1861     if (auto data = NonInheritedVariables()->GetData(name))
1862       return *data;
1863   }
1864   return GetInitialVariableData(name, InitialDataInternal().get());
1865 }
1866 
GetVariableData(const AtomicString & name,bool is_inherited_property) const1867 CSSVariableData* ComputedStyle::GetVariableData(
1868     const AtomicString& name,
1869     bool is_inherited_property) const {
1870   if (is_inherited_property) {
1871     if (InheritedVariables()) {
1872       if (auto data = InheritedVariables()->GetData(name))
1873         return *data;
1874     }
1875   } else {
1876     if (NonInheritedVariables()) {
1877       if (auto data = NonInheritedVariables()->GetData(name))
1878         return *data;
1879     }
1880   }
1881   return GetInitialVariableData(name, InitialDataInternal().get());
1882 }
1883 
GetInitialVariableValue(const AtomicString & name,const StyleInitialData * initial_data)1884 static const CSSValue* GetInitialVariableValue(
1885     const AtomicString& name,
1886     const StyleInitialData* initial_data) {
1887   if (!initial_data)
1888     return nullptr;
1889   return initial_data->GetVariableValue(name);
1890 }
1891 
GetVariableValue(const AtomicString & name) const1892 const CSSValue* ComputedStyle::GetVariableValue(
1893     const AtomicString& name) const {
1894   if (InheritedVariables()) {
1895     if (auto value = InheritedVariables()->GetValue(name))
1896       return *value;
1897   }
1898   if (NonInheritedVariables()) {
1899     if (auto value = NonInheritedVariables()->GetValue(name))
1900       return *value;
1901   }
1902   return GetInitialVariableValue(name, InitialDataInternal().get());
1903 }
1904 
GetVariableValue(const AtomicString & name,bool is_inherited_property) const1905 const CSSValue* ComputedStyle::GetVariableValue(
1906     const AtomicString& name,
1907     bool is_inherited_property) const {
1908   if (is_inherited_property) {
1909     if (InheritedVariables()) {
1910       if (auto value = InheritedVariables()->GetValue(name))
1911         return *value;
1912     }
1913   } else {
1914     if (NonInheritedVariables()) {
1915       if (auto value = NonInheritedVariables()->GetValue(name))
1916         return *value;
1917     }
1918   }
1919   return GetInitialVariableValue(name, InitialDataInternal().get());
1920 }
1921 
SetFontDescription(const FontDescription & v)1922 bool ComputedStyle::SetFontDescription(const FontDescription& v) {
1923   if (FontInternal().GetFontDescription() != v) {
1924     SetFontInternal(Font(v, FontInternal().GetFontSelector()));
1925     return true;
1926   }
1927   return false;
1928 }
1929 
HasIdenticalAscentDescentAndLineGap(const ComputedStyle & other) const1930 bool ComputedStyle::HasIdenticalAscentDescentAndLineGap(
1931     const ComputedStyle& other) const {
1932   const SimpleFontData* font_data = GetFont().PrimaryFont();
1933   const SimpleFontData* other_font_data = other.GetFont().PrimaryFont();
1934   return font_data && other_font_data &&
1935          font_data->GetFontMetrics().HasIdenticalAscentDescentAndLineGap(
1936              other_font_data->GetFontMetrics());
1937 }
1938 
LineHeight() const1939 Length ComputedStyle::LineHeight() const {
1940   const Length& lh = LineHeightInternal();
1941   // Unlike getFontDescription().computedSize() and hence fontSize(), this is
1942   // recalculated on demand as we only store the specified line height.
1943   // FIXME: Should consider scaling the fixed part of any calc expressions
1944   // too, though this involves messily poking into CalcExpressionLength.
1945   if (lh.IsFixed()) {
1946     float multiplier = TextAutosizingMultiplier();
1947     return Length::Fixed(TextAutosizer::ComputeAutosizedFontSize(
1948         lh.Value(), multiplier, EffectiveZoom()));
1949   }
1950 
1951   return lh;
1952 }
1953 
ComputedLineHeight() const1954 int ComputedStyle::ComputedLineHeight() const {
1955   const Length& lh = LineHeight();
1956 
1957   // Negative value means the line height is not set. Use the font's built-in
1958   // spacing, if avalible.
1959   if (lh.IsNegative() && GetFont().PrimaryFont())
1960     return GetFont().PrimaryFont()->GetFontMetrics().LineSpacing();
1961 
1962   if (lh.IsPercentOrCalc())
1963     return MinimumValueForLength(lh, LayoutUnit(ComputedFontSize())).ToInt();
1964 
1965   return std::min(lh.Value(), LayoutUnit::Max().ToFloat());
1966 }
1967 
ComputedLineHeightAsFixed() const1968 LayoutUnit ComputedStyle::ComputedLineHeightAsFixed() const {
1969   const Length& lh = LineHeight();
1970 
1971   // Negative value means the line height is not set. Use the font's built-in
1972   // spacing, if avalible.
1973   if (lh.IsNegative() && GetFont().PrimaryFont())
1974     return GetFont().PrimaryFont()->GetFontMetrics().FixedLineSpacing();
1975 
1976   if (lh.IsPercentOrCalc()) {
1977     return LayoutUnit(
1978         MinimumValueForLength(lh, ComputedFontSizeAsFixed()).ToInt());
1979   }
1980 
1981   return LayoutUnit(floorf(lh.Value()));
1982 }
1983 
SetWordSpacing(float word_spacing)1984 void ComputedStyle::SetWordSpacing(float word_spacing) {
1985   FontDescription desc(GetFontDescription());
1986   desc.SetWordSpacing(word_spacing);
1987   SetFontDescription(desc);
1988 }
1989 
SetLetterSpacing(float letter_spacing)1990 void ComputedStyle::SetLetterSpacing(float letter_spacing) {
1991   FontDescription desc(GetFontDescription());
1992   desc.SetLetterSpacing(letter_spacing);
1993   SetFontDescription(desc);
1994 }
1995 
SetTextAutosizingMultiplier(float multiplier)1996 void ComputedStyle::SetTextAutosizingMultiplier(float multiplier) {
1997   SetTextAutosizingMultiplierInternal(multiplier);
1998 
1999   float size = SpecifiedFontSize();
2000 
2001   DCHECK(std::isfinite(size));
2002   if (!std::isfinite(size) || size < 0)
2003     size = 0;
2004   else
2005     size = std::min(kMaximumAllowedFontSize, size);
2006 
2007   FontDescription desc(GetFontDescription());
2008   desc.SetSpecifiedSize(size);
2009 
2010   float computed_size = size * EffectiveZoom();
2011 
2012   float autosized_font_size = TextAutosizer::ComputeAutosizedFontSize(
2013       computed_size, multiplier, EffectiveZoom());
2014   desc.SetComputedSize(std::min(kMaximumAllowedFontSize, autosized_font_size));
2015 
2016   SetFontDescription(desc);
2017 }
2018 
AddAppliedTextDecoration(const AppliedTextDecoration & decoration)2019 void ComputedStyle::AddAppliedTextDecoration(
2020     const AppliedTextDecoration& decoration) {
2021   scoped_refptr<AppliedTextDecorationList>& list =
2022       MutableAppliedTextDecorationsInternal();
2023 
2024   if (!list)
2025     list = base::MakeRefCounted<AppliedTextDecorationList>();
2026   else if (!list->HasOneRef())
2027     list = base::MakeRefCounted<AppliedTextDecorationList>(list->data);
2028 
2029   list->data.push_back(decoration);
2030 }
2031 
OverrideTextDecorationColors(Color override_color)2032 void ComputedStyle::OverrideTextDecorationColors(Color override_color) {
2033   scoped_refptr<AppliedTextDecorationList>& list =
2034       MutableAppliedTextDecorationsInternal();
2035   DCHECK(list);
2036   if (!list->HasOneRef())
2037     list = base::MakeRefCounted<AppliedTextDecorationList>(list->data);
2038 
2039   for (AppliedTextDecoration& decoration : list->data)
2040     decoration.SetColor(override_color);
2041 }
2042 
ApplyTextDecorations(const Color & parent_text_decoration_color,bool override_existing_colors)2043 void ComputedStyle::ApplyTextDecorations(
2044     const Color& parent_text_decoration_color,
2045     bool override_existing_colors) {
2046   if (GetTextDecoration() == TextDecoration::kNone &&
2047       !HasSimpleUnderlineInternal() && !AppliedTextDecorationsInternal())
2048     return;
2049 
2050   // If there are any color changes or decorations set by this element, stop
2051   // using m_hasSimpleUnderline.
2052   Color current_text_decoration_color =
2053       VisitedDependentColor(GetCSSPropertyTextDecorationColor());
2054   if (HasSimpleUnderlineInternal() &&
2055       (GetTextDecoration() != TextDecoration::kNone ||
2056        current_text_decoration_color != parent_text_decoration_color)) {
2057     SetHasSimpleUnderlineInternal(false);
2058     AddAppliedTextDecoration(AppliedTextDecoration(
2059         TextDecoration::kUnderline, ETextDecorationStyle::kSolid,
2060         parent_text_decoration_color, TextDecorationThickness(),
2061         Length::Auto()));
2062   }
2063   if (override_existing_colors && AppliedTextDecorationsInternal())
2064     OverrideTextDecorationColors(current_text_decoration_color);
2065   if (GetTextDecoration() == TextDecoration::kNone)
2066     return;
2067   DCHECK(!HasSimpleUnderlineInternal());
2068   // To save memory, we don't use AppliedTextDecoration objects in the common
2069   // case of a single simple underline of currentColor.
2070   TextDecoration decoration_lines = GetTextDecoration();
2071   ETextDecorationStyle decoration_style = TextDecorationStyle();
2072   bool is_simple_underline = decoration_lines == TextDecoration::kUnderline &&
2073                              decoration_style == ETextDecorationStyle::kSolid &&
2074                              TextDecorationColor().IsCurrentColor() &&
2075                              TextUnderlineOffset().IsAuto();
2076   if (is_simple_underline && !AppliedTextDecorationsInternal()) {
2077     SetHasSimpleUnderlineInternal(true);
2078     return;
2079   }
2080 
2081   AddAppliedTextDecoration(AppliedTextDecoration(
2082       decoration_lines, decoration_style, current_text_decoration_color,
2083       GetTextDecorationThickness(), TextUnderlineOffset()));
2084 }
2085 
ClearAppliedTextDecorations()2086 void ComputedStyle::ClearAppliedTextDecorations() {
2087   SetHasSimpleUnderlineInternal(false);
2088 
2089   if (AppliedTextDecorationsInternal())
2090     SetAppliedTextDecorationsInternal(nullptr);
2091 }
2092 
RestoreParentTextDecorations(const ComputedStyle & parent_style)2093 void ComputedStyle::RestoreParentTextDecorations(
2094     const ComputedStyle& parent_style) {
2095   SetHasSimpleUnderlineInternal(parent_style.HasSimpleUnderlineInternal());
2096   if (AppliedTextDecorationsInternal() !=
2097       parent_style.AppliedTextDecorationsInternal()) {
2098     SetAppliedTextDecorationsInternal(scoped_refptr<AppliedTextDecorationList>(
2099         parent_style.AppliedTextDecorationsInternal()));
2100   }
2101 }
2102 
ClearMultiCol()2103 void ComputedStyle::ClearMultiCol() {
2104   SetColumnGap(ComputedStyleInitialValues::InitialColumnGap());
2105   SetColumnWidthInternal(ComputedStyleInitialValues::InitialColumnWidth());
2106   SetColumnRuleStyle(ComputedStyleInitialValues::InitialColumnRuleStyle());
2107   SetColumnRuleWidthInternal(
2108       LayoutUnit(ComputedStyleInitialValues::InitialColumnRuleWidth()));
2109   SetColumnRuleColorInternal(
2110       ComputedStyleInitialValues::InitialColumnRuleColor());
2111   SetInternalVisitedColumnRuleColorInternal(
2112       ComputedStyleInitialValues::InitialInternalVisitedColumnRuleColor());
2113   SetColumnCountInternal(ComputedStyleInitialValues::InitialColumnCount());
2114   SetHasAutoColumnCountInternal(
2115       ComputedStyleInitialValues::InitialHasAutoColumnCount());
2116   SetHasAutoColumnWidthInternal(
2117       ComputedStyleInitialValues::InitialHasAutoColumnWidth());
2118   ResetColumnFill();
2119   ResetColumnSpan();
2120 }
2121 
DecorationColorIncludingFallback(bool visited_link) const2122 StyleColor ComputedStyle::DecorationColorIncludingFallback(
2123     bool visited_link) const {
2124   StyleColor style_color = visited_link ? InternalVisitedTextDecorationColor()
2125                                         : TextDecorationColor();
2126 
2127   if (!style_color.IsCurrentColor())
2128     return style_color;
2129 
2130   if (TextStrokeWidth()) {
2131     // Prefer stroke color if possible, but not if it's fully transparent.
2132     StyleColor text_stroke_style_color =
2133         visited_link ? InternalVisitedTextStrokeColor() : TextStrokeColor();
2134     if (!text_stroke_style_color.IsCurrentColor() &&
2135         text_stroke_style_color.Resolve(Color(), UsedColorScheme()).Alpha()) {
2136       return text_stroke_style_color;
2137     }
2138   }
2139 
2140   return visited_link ? InternalVisitedTextFillColor() : TextFillColor();
2141 }
2142 
VisitedDependentColor(const CSSProperty & color_property) const2143 Color ComputedStyle::VisitedDependentColor(
2144     const CSSProperty& color_property) const {
2145   DCHECK(!color_property.IsVisited());
2146 
2147   Color unvisited_color =
2148       To<Longhand>(color_property).ColorIncludingFallback(false, *this);
2149   if (InsideLink() != EInsideLink::kInsideVisitedLink)
2150     return unvisited_color;
2151 
2152   // Properties that provide a GetVisitedProperty() must use the
2153   // ColorIncludingFallback function on that property.
2154   //
2155   // TODO(andruud): Simplify this when all properties support
2156   // GetVisitedProperty.
2157   const CSSProperty* visited_property = &color_property;
2158   if (const CSSProperty* visited = color_property.GetVisitedProperty())
2159     visited_property = visited;
2160 
2161   Color visited_color =
2162       To<Longhand>(*visited_property).ColorIncludingFallback(true, *this);
2163 
2164   // Take the alpha from the unvisited color, but get the RGB values from the
2165   // visited color.
2166   return Color(visited_color.Red(), visited_color.Green(), visited_color.Blue(),
2167                unvisited_color.Alpha());
2168 }
2169 
ResolvedColor(const StyleColor & color) const2170 Color ComputedStyle::ResolvedColor(const StyleColor& color) const {
2171   bool visited_link = (InsideLink() == EInsideLink::kInsideVisitedLink);
2172   Color current_color =
2173       visited_link ? GetInternalVisitedCurrentColor() : GetCurrentColor();
2174   return color.Resolve(current_color, UsedColorScheme());
2175 }
2176 
SetMarginStart(const Length & margin)2177 void ComputedStyle::SetMarginStart(const Length& margin) {
2178   if (IsHorizontalWritingMode()) {
2179     if (IsLeftToRightDirection())
2180       SetMarginLeft(margin);
2181     else
2182       SetMarginRight(margin);
2183   } else {
2184     if (IsLeftToRightDirection())
2185       SetMarginTop(margin);
2186     else
2187       SetMarginBottom(margin);
2188   }
2189 }
2190 
SetMarginEnd(const Length & margin)2191 void ComputedStyle::SetMarginEnd(const Length& margin) {
2192   if (IsHorizontalWritingMode()) {
2193     if (IsLeftToRightDirection())
2194       SetMarginRight(margin);
2195     else
2196       SetMarginLeft(margin);
2197   } else {
2198     if (IsLeftToRightDirection())
2199       SetMarginBottom(margin);
2200     else
2201       SetMarginTop(margin);
2202   }
2203 }
2204 
OutlineOutsetExtent() const2205 int ComputedStyle::OutlineOutsetExtent() const {
2206   if (!HasOutline())
2207     return 0;
2208   if (OutlineStyleIsAuto()) {
2209     return GraphicsContext::FocusRingOutsetExtent(
2210         OutlineOffsetInt(), std::ceil(GetOutlineStrokeWidthForFocusRing()));
2211   }
2212   return base::ClampAdd(OutlineWidthInt(), OutlineOffsetInt()).Max(0);
2213 }
2214 
GetOutlineStrokeWidthForFocusRing() const2215 float ComputedStyle::GetOutlineStrokeWidthForFocusRing() const {
2216   if (::features::IsFormControlsRefreshEnabled() && OutlineStyleIsAuto()) {
2217     return std::max(EffectiveZoom(), 3.f);
2218   }
2219 
2220 #if defined(OS_MAC)
2221   return OutlineWidthInt();
2222 #else
2223   // Draw an outline with thickness in proportion to the zoom level, but never
2224   // so narrow that it becomes invisible.
2225   return std::max(EffectiveZoom(), 1.f);
2226 #endif
2227 }
2228 
ColumnRuleEquivalent(const ComputedStyle & other_style) const2229 bool ComputedStyle::ColumnRuleEquivalent(
2230     const ComputedStyle& other_style) const {
2231   return ColumnRuleStyle() == other_style.ColumnRuleStyle() &&
2232          ColumnRuleWidth() == other_style.ColumnRuleWidth() &&
2233          VisitedDependentColor(GetCSSPropertyColumnRuleColor()) ==
2234              other_style.VisitedDependentColor(GetCSSPropertyColumnRuleColor());
2235 }
2236 
GetTextEmphasisMark() const2237 TextEmphasisMark ComputedStyle::GetTextEmphasisMark() const {
2238   TextEmphasisMark mark = TextEmphasisMarkInternal();
2239   if (mark != TextEmphasisMark::kAuto)
2240     return mark;
2241 
2242   if (IsHorizontalWritingMode())
2243     return TextEmphasisMark::kDot;
2244 
2245   return TextEmphasisMark::kSesame;
2246 }
2247 
ImageOutsets(const NinePieceImage & image) const2248 LayoutRectOutsets ComputedStyle::ImageOutsets(
2249     const NinePieceImage& image) const {
2250   return LayoutRectOutsets(
2251       NinePieceImage::ComputeOutset(image.Outset().Top(), BorderTopWidth()),
2252       NinePieceImage::ComputeOutset(image.Outset().Right(), BorderRightWidth()),
2253       NinePieceImage::ComputeOutset(image.Outset().Bottom(),
2254                                     BorderBottomWidth()),
2255       NinePieceImage::ComputeOutset(image.Outset().Left(), BorderLeftWidth()));
2256 }
2257 
SetBorderImageSource(StyleImage * image)2258 void ComputedStyle::SetBorderImageSource(StyleImage* image) {
2259   if (BorderImage().GetImage() == image)
2260     return;
2261   MutableBorderImageInternal().SetImage(image);
2262 }
2263 
SetBorderImageSlices(const LengthBox & slices)2264 void ComputedStyle::SetBorderImageSlices(const LengthBox& slices) {
2265   if (BorderImage().ImageSlices() == slices)
2266     return;
2267   MutableBorderImageInternal().SetImageSlices(slices);
2268 }
2269 
SetBorderImageSlicesFill(bool fill)2270 void ComputedStyle::SetBorderImageSlicesFill(bool fill) {
2271   if (BorderImage().Fill() == fill)
2272     return;
2273   MutableBorderImageInternal().SetFill(fill);
2274 }
2275 
SetBorderImageWidth(const BorderImageLengthBox & slices)2276 void ComputedStyle::SetBorderImageWidth(const BorderImageLengthBox& slices) {
2277   if (BorderImage().BorderSlices() == slices)
2278     return;
2279   MutableBorderImageInternal().SetBorderSlices(slices);
2280 }
2281 
SetBorderImageOutset(const BorderImageLengthBox & outset)2282 void ComputedStyle::SetBorderImageOutset(const BorderImageLengthBox& outset) {
2283   if (BorderImage().Outset() == outset)
2284     return;
2285   MutableBorderImageInternal().SetOutset(outset);
2286 }
2287 
BorderObscuresBackground() const2288 bool ComputedStyle::BorderObscuresBackground() const {
2289   if (!HasBorder())
2290     return false;
2291 
2292   // Bail if we have any border-image for now. We could look at the image alpha
2293   // to improve this.
2294   if (BorderImage().GetImage())
2295     return false;
2296 
2297   BorderEdge edges[4];
2298   GetBorderEdgeInfo(edges);
2299 
2300   for (unsigned int i = static_cast<unsigned>(BoxSide::kTop);
2301        i <= static_cast<unsigned>(BoxSide::kLeft); ++i) {
2302     const BorderEdge& curr_edge = edges[i];
2303     if (!curr_edge.ObscuresBackground())
2304       return false;
2305   }
2306 
2307   return true;
2308 }
2309 
BoxDecorationOutsets() const2310 LayoutRectOutsets ComputedStyle::BoxDecorationOutsets() const {
2311   DCHECK(HasVisualOverflowingEffect());
2312   LayoutRectOutsets outsets;
2313 
2314   if (const ShadowList* box_shadow = BoxShadow())
2315     outsets = LayoutRectOutsets(box_shadow->RectOutsetsIncludingOriginal());
2316 
2317   if (HasBorderImageOutsets())
2318     outsets.Unite(BorderImageOutsets());
2319 
2320   if (HasMaskBoxImageOutsets())
2321     outsets.Unite(MaskBoxImageOutsets());
2322 
2323   return outsets;
2324 }
2325 
GetBorderEdgeInfo(BorderEdge edges[],PhysicalBoxSides sides_to_include) const2326 void ComputedStyle::GetBorderEdgeInfo(BorderEdge edges[],
2327                                       PhysicalBoxSides sides_to_include) const {
2328   edges[static_cast<unsigned>(BoxSide::kTop)] = BorderEdge(
2329       BorderTopWidth(), VisitedDependentColor(GetCSSPropertyBorderTopColor()),
2330       BorderTopStyle(), sides_to_include.top);
2331 
2332   edges[static_cast<unsigned>(BoxSide::kRight)] =
2333       BorderEdge(BorderRightWidth(),
2334                  VisitedDependentColor(GetCSSPropertyBorderRightColor()),
2335                  BorderRightStyle(), sides_to_include.right);
2336 
2337   edges[static_cast<unsigned>(BoxSide::kBottom)] =
2338       BorderEdge(BorderBottomWidth(),
2339                  VisitedDependentColor(GetCSSPropertyBorderBottomColor()),
2340                  BorderBottomStyle(), sides_to_include.bottom);
2341 
2342   edges[static_cast<unsigned>(BoxSide::kLeft)] = BorderEdge(
2343       BorderLeftWidth(), VisitedDependentColor(GetCSSPropertyBorderLeftColor()),
2344       BorderLeftStyle(), sides_to_include.left);
2345 }
2346 
CopyChildDependentFlagsFrom(const ComputedStyle & other)2347 void ComputedStyle::CopyChildDependentFlagsFrom(const ComputedStyle& other) {
2348   if (other.ChildHasExplicitInheritance())
2349     SetChildHasExplicitInheritance();
2350 }
2351 
GetCurrentColor() const2352 Color ComputedStyle::GetCurrentColor() const {
2353   DCHECK(!GetColor().IsCurrentColor());
2354   return GetColor().Resolve(Color(), UsedColorScheme());
2355 }
2356 
GetInternalVisitedCurrentColor() const2357 Color ComputedStyle::GetInternalVisitedCurrentColor() const {
2358   DCHECK(!InternalVisitedColor().IsCurrentColor());
2359   return InternalVisitedColor().Resolve(Color(), UsedColorScheme());
2360 }
2361 
ShadowListHasCurrentColor(const ShadowList * shadow_list)2362 bool ComputedStyle::ShadowListHasCurrentColor(const ShadowList* shadow_list) {
2363   if (!shadow_list)
2364     return false;
2365   return std::any_of(shadow_list->Shadows().begin(),
2366                      shadow_list->Shadows().end(),
2367                      [](const ShadowData& shadow) {
2368                        return shadow.GetColor().IsCurrentColor();
2369                      });
2370 }
2371 
2372 STATIC_ASSERT_ENUM(cc::OverscrollBehavior::Type::kAuto,
2373                    EOverscrollBehavior::kAuto);
2374 STATIC_ASSERT_ENUM(cc::OverscrollBehavior::Type::kContain,
2375                    EOverscrollBehavior::kContain);
2376 STATIC_ASSERT_ENUM(cc::OverscrollBehavior::Type::kNone,
2377                    EOverscrollBehavior::kNone);
2378 
2379 }  // namespace blink
2380