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