1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "third_party/blink/renderer/core/style/computed_style.h"
6 
7 #include "build/build_config.h"
8 #include "testing/gtest/include/gtest/gtest.h"
9 #include "third_party/blink/renderer/core/css/css_font_selector.h"
10 #include "third_party/blink/renderer/core/css/css_gradient_value.h"
11 #include "third_party/blink/renderer/core/css/css_identifier_value.h"
12 #include "third_party/blink/renderer/core/css/css_math_expression_node.h"
13 #include "third_party/blink/renderer/core/css/css_math_function_value.h"
14 #include "third_party/blink/renderer/core/css/css_numeric_literal_value.h"
15 #include "third_party/blink/renderer/core/css/css_test_helpers.h"
16 #include "third_party/blink/renderer/core/css/css_value_list.h"
17 #include "third_party/blink/renderer/core/css/parser/css_parser.h"
18 #include "third_party/blink/renderer/core/css/properties/css_property_ref.h"
19 #include "third_party/blink/renderer/core/css/property_registry.h"
20 #include "third_party/blink/renderer/core/css/resolver/style_adjuster.h"
21 #include "third_party/blink/renderer/core/css/resolver/style_cascade.h"
22 #include "third_party/blink/renderer/core/css/resolver/style_resolver_state.h"
23 #include "third_party/blink/renderer/core/css/style_engine.h"
24 #include "third_party/blink/renderer/core/dom/document.h"
25 #include "third_party/blink/renderer/core/frame/settings.h"
26 #include "third_party/blink/renderer/core/style/clip_path_operation.h"
27 #include "third_party/blink/renderer/core/style/shape_clip_path_operation.h"
28 #include "third_party/blink/renderer/core/style/shape_value.h"
29 #include "third_party/blink/renderer/core/style/style_difference.h"
30 #include "third_party/blink/renderer/core/style/style_generated_image.h"
31 #include "third_party/blink/renderer/core/style/style_initial_data.h"
32 #include "third_party/blink/renderer/core/testing/color_scheme_helper.h"
33 #include "third_party/blink/renderer/core/testing/dummy_page_holder.h"
34 #include "third_party/blink/renderer/platform/heap/heap.h"
35 #include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h"
36 #include "third_party/blink/renderer/platform/transforms/scale_transform_operation.h"
37 #include "ui/base/ui_base_features.h"
38 
39 namespace blink {
40 
TEST(ComputedStyleTest,ShapeOutsideBoxEqual)41 TEST(ComputedStyleTest, ShapeOutsideBoxEqual) {
42   auto* shape1 = MakeGarbageCollected<ShapeValue>(CSSBoxType::kContent);
43   auto* shape2 = MakeGarbageCollected<ShapeValue>(CSSBoxType::kContent);
44   scoped_refptr<ComputedStyle> style1 = ComputedStyle::Create();
45   scoped_refptr<ComputedStyle> style2 = ComputedStyle::Create();
46   style1->SetShapeOutside(shape1);
47   style2->SetShapeOutside(shape2);
48   EXPECT_EQ(*style1, *style2);
49 }
50 
TEST(ComputedStyleTest,ShapeOutsideCircleEqual)51 TEST(ComputedStyleTest, ShapeOutsideCircleEqual) {
52   scoped_refptr<BasicShapeCircle> circle1 = BasicShapeCircle::Create();
53   scoped_refptr<BasicShapeCircle> circle2 = BasicShapeCircle::Create();
54   auto* shape1 = MakeGarbageCollected<ShapeValue>(std::move(circle1),
55                                                   CSSBoxType::kContent);
56   auto* shape2 = MakeGarbageCollected<ShapeValue>(std::move(circle2),
57                                                   CSSBoxType::kContent);
58   scoped_refptr<ComputedStyle> style1 = ComputedStyle::Create();
59   scoped_refptr<ComputedStyle> style2 = ComputedStyle::Create();
60   style1->SetShapeOutside(shape1);
61   style2->SetShapeOutside(shape2);
62   EXPECT_EQ(*style1, *style2);
63 }
64 
TEST(ComputedStyleTest,ClipPathEqual)65 TEST(ComputedStyleTest, ClipPathEqual) {
66   scoped_refptr<BasicShapeCircle> shape = BasicShapeCircle::Create();
67   scoped_refptr<ShapeClipPathOperation> path1 =
68       ShapeClipPathOperation::Create(shape);
69   scoped_refptr<ShapeClipPathOperation> path2 =
70       ShapeClipPathOperation::Create(shape);
71   scoped_refptr<ComputedStyle> style1 = ComputedStyle::Create();
72   scoped_refptr<ComputedStyle> style2 = ComputedStyle::Create();
73   style1->SetClipPath(path1);
74   style2->SetClipPath(path2);
75   EXPECT_EQ(*style1, *style2);
76 }
77 
TEST(ComputedStyleTest,FocusRingWidth)78 TEST(ComputedStyleTest, FocusRingWidth) {
79   scoped_refptr<ComputedStyle> style = ComputedStyle::Create();
80   if (::features::IsFormControlsRefreshEnabled()) {
81     style->SetOutlineStyleIsAuto(static_cast<bool>(OutlineIsAuto::kOn));
82     EXPECT_EQ(3, style->GetOutlineStrokeWidthForFocusRing());
83     style->SetEffectiveZoom(3.5);
84     style->SetOutlineWidth(4);
85     EXPECT_EQ(3.5, style->GetOutlineStrokeWidthForFocusRing());
86   } else {
87     style->SetEffectiveZoom(3.5);
88     style->SetOutlineStyle(EBorderStyle::kSolid);
89 #if defined(OS_MAC)
90     EXPECT_EQ(3, style->GetOutlineStrokeWidthForFocusRing());
91 #else
92     style->SetOutlineStyleIsAuto(static_cast<bool>(OutlineIsAuto::kOn));
93     static uint16_t outline_width = 4;
94     style->SetOutlineWidth(outline_width);
95 
96     double expected_width = 3.5;
97     EXPECT_EQ(expected_width, style->GetOutlineStrokeWidthForFocusRing());
98 
99     expected_width = 1.0;
100     style->SetEffectiveZoom(0.5);
101     EXPECT_EQ(expected_width, style->GetOutlineStrokeWidthForFocusRing());
102 #endif
103   }
104 }
105 
TEST(ComputedStyleTest,FocusRingOutset)106 TEST(ComputedStyleTest, FocusRingOutset) {
107   scoped_refptr<ComputedStyle> style = ComputedStyle::Create();
108   style->SetOutlineStyle(EBorderStyle::kSolid);
109   style->SetOutlineStyleIsAuto(static_cast<bool>(OutlineIsAuto::kOn));
110   style->SetEffectiveZoom(4.75);
111   if (::features::IsFormControlsRefreshEnabled()) {
112     EXPECT_EQ(4, style->OutlineOutsetExtent());
113   } else {
114 #if defined(OS_MAC)
115     EXPECT_EQ(4, style->OutlineOutsetExtent());
116 #else
117     EXPECT_EQ(3, style->OutlineOutsetExtent());
118 #endif
119   }
120 }
121 
TEST(ComputedStyleTest,SVGStackingContext)122 TEST(ComputedStyleTest, SVGStackingContext) {
123   scoped_refptr<ComputedStyle> style = ComputedStyle::Create();
124   style->UpdateIsStackingContextWithoutContainment(false, false, true);
125   EXPECT_TRUE(style->IsStackingContextWithoutContainment());
126 }
127 
TEST(ComputedStyleTest,Preserve3dForceStackingContext)128 TEST(ComputedStyleTest, Preserve3dForceStackingContext) {
129   scoped_refptr<ComputedStyle> style = ComputedStyle::Create();
130   style->SetTransformStyle3D(ETransformStyle3D::kPreserve3d);
131   style->SetOverflowX(EOverflow::kHidden);
132   style->SetOverflowY(EOverflow::kHidden);
133   style->UpdateIsStackingContextWithoutContainment(false, false, false);
134   EXPECT_EQ(ETransformStyle3D::kFlat, style->UsedTransformStyle3D());
135   EXPECT_TRUE(style->IsStackingContextWithoutContainment());
136 }
137 
TEST(ComputedStyleTest,LayoutContainmentStackingContext)138 TEST(ComputedStyleTest, LayoutContainmentStackingContext) {
139   scoped_refptr<ComputedStyle> style = ComputedStyle::Create();
140   EXPECT_FALSE(style->IsStackingContextWithoutContainment());
141   style->SetContain(kContainsLayout);
142   style->UpdateIsStackingContextWithoutContainment(false, false, false);
143   // Containment doesn't change IsStackingContextWithoutContainment
144   EXPECT_FALSE(style->IsStackingContextWithoutContainment());
145 }
146 
TEST(ComputedStyleTest,FirstPublicPseudoStyle)147 TEST(ComputedStyleTest, FirstPublicPseudoStyle) {
148   static_assert(kFirstPublicPseudoId == kPseudoIdFirstLine,
149                 "Make sure we are testing the first public pseudo id");
150 
151   scoped_refptr<ComputedStyle> style = ComputedStyle::Create();
152   style->SetHasPseudoElementStyle(kPseudoIdFirstLine);
153   EXPECT_TRUE(style->HasPseudoElementStyle(kPseudoIdFirstLine));
154   EXPECT_TRUE(style->HasAnyPseudoElementStyles());
155 }
156 
TEST(ComputedStyleTest,LastPublicPseudoElementStyle)157 TEST(ComputedStyleTest, LastPublicPseudoElementStyle) {
158   static_assert(kFirstInternalPseudoId - 1 == kPseudoIdTargetText,
159                 "Make sure we are testing the last public pseudo id");
160 
161   scoped_refptr<ComputedStyle> style = ComputedStyle::Create();
162   style->SetHasPseudoElementStyle(kPseudoIdTargetText);
163   EXPECT_TRUE(style->HasPseudoElementStyle(kPseudoIdTargetText));
164   EXPECT_TRUE(style->HasAnyPseudoElementStyles());
165 }
166 
TEST(ComputedStyleTest,UpdatePropertySpecificDifferencesRespectsTransformAnimation)167 TEST(ComputedStyleTest,
168      UpdatePropertySpecificDifferencesRespectsTransformAnimation) {
169   scoped_refptr<ComputedStyle> style = ComputedStyle::Create();
170   scoped_refptr<ComputedStyle> other = ComputedStyle::Clone(*style);
171   other->SetHasCurrentTransformAnimation(true);
172   StyleDifference diff;
173   style->UpdatePropertySpecificDifferences(*other, diff);
174   EXPECT_TRUE(diff.TransformChanged());
175 }
176 
TEST(ComputedStyleTest,UpdatePropertySpecificDifferencesCompositingReasonsTransforom)177 TEST(ComputedStyleTest,
178      UpdatePropertySpecificDifferencesCompositingReasonsTransforom) {
179   scoped_refptr<ComputedStyle> style = ComputedStyle::Create();
180   scoped_refptr<ComputedStyle> other = ComputedStyle::Clone(*style);
181 
182   TransformOperations operations;
183   // An operation is necessary since having either a non-empty transform list
184   // or a transform animation will set HasTransform();
185   operations.Operations().push_back(
186       ScaleTransformOperation::Create(1, 1, TransformOperation::kScale));
187 
188   style->SetTransform(operations);
189   other->SetTransform(operations);
190 
191   other->SetHasCurrentTransformAnimation(true);
192   StyleDifference diff;
193   style->UpdatePropertySpecificDifferences(*other, diff);
194   EXPECT_FALSE(diff.TransformChanged());
195   EXPECT_TRUE(diff.CompositingReasonsChanged());
196 }
197 
TEST(ComputedStyleTest,UpdatePropertySpecificDifferencesCompositingReasonsOpacity)198 TEST(ComputedStyleTest,
199      UpdatePropertySpecificDifferencesCompositingReasonsOpacity) {
200   scoped_refptr<ComputedStyle> style = ComputedStyle::Create();
201   scoped_refptr<ComputedStyle> other = ComputedStyle::Clone(*style);
202 
203   other->SetHasCurrentOpacityAnimation(true);
204   StyleDifference diff;
205   style->UpdatePropertySpecificDifferences(*other, diff);
206   EXPECT_TRUE(diff.CompositingReasonsChanged());
207 }
208 
TEST(ComputedStyleTest,UpdatePropertySpecificDifferencesCompositingReasonsFilter)209 TEST(ComputedStyleTest,
210      UpdatePropertySpecificDifferencesCompositingReasonsFilter) {
211   scoped_refptr<ComputedStyle> style = ComputedStyle::Create();
212   scoped_refptr<ComputedStyle> other = ComputedStyle::Clone(*style);
213 
214   other->SetHasCurrentFilterAnimation(true);
215   StyleDifference diff;
216   style->UpdatePropertySpecificDifferences(*other, diff);
217   EXPECT_TRUE(diff.CompositingReasonsChanged());
218 }
219 
TEST(ComputedStyleTest,UpdatePropertySpecificDifferencesCompositingReasonsBackdropFilter)220 TEST(ComputedStyleTest,
221      UpdatePropertySpecificDifferencesCompositingReasonsBackdropFilter) {
222   scoped_refptr<ComputedStyle> style = ComputedStyle::Create();
223   scoped_refptr<ComputedStyle> other = ComputedStyle::Clone(*style);
224 
225   other->SetHasCurrentBackdropFilterAnimation(true);
226   StyleDifference diff;
227   style->UpdatePropertySpecificDifferences(*other, diff);
228   EXPECT_TRUE(diff.CompositingReasonsChanged());
229 }
230 
TEST(ComputedStyleTest,UpdatePropertySpecificDifferencesCompositingReasonsBackfaceVisibility)231 TEST(ComputedStyleTest,
232      UpdatePropertySpecificDifferencesCompositingReasonsBackfaceVisibility) {
233   scoped_refptr<ComputedStyle> style = ComputedStyle::Create();
234   scoped_refptr<ComputedStyle> other = ComputedStyle::Clone(*style);
235 
236   other->SetBackfaceVisibility(EBackfaceVisibility::kHidden);
237   StyleDifference diff;
238   style->UpdatePropertySpecificDifferences(*other, diff);
239   EXPECT_TRUE(diff.CompositingReasonsChanged());
240 }
241 
TEST(ComputedStyleTest,UpdatePropertySpecificDifferencesCompositingReasonsWillChange)242 TEST(ComputedStyleTest,
243      UpdatePropertySpecificDifferencesCompositingReasonsWillChange) {
244   scoped_refptr<ComputedStyle> style = ComputedStyle::Create();
245   scoped_refptr<ComputedStyle> other = ComputedStyle::Clone(*style);
246 
247   other->SetBackfaceVisibility(EBackfaceVisibility::kHidden);
248   StyleDifference diff;
249   style->UpdatePropertySpecificDifferences(*other, diff);
250   EXPECT_TRUE(diff.CompositingReasonsChanged());
251 }
252 
TEST(ComputedStyleTest,UpdatePropertySpecificDifferencesCompositingReasonsUsedStylePreserve3D)253 TEST(ComputedStyleTest,
254      UpdatePropertySpecificDifferencesCompositingReasonsUsedStylePreserve3D) {
255   scoped_refptr<ComputedStyle> style = ComputedStyle::Create();
256   style->SetTransformStyle3D(ETransformStyle3D::kPreserve3d);
257   scoped_refptr<ComputedStyle> other = ComputedStyle::Clone(*style);
258 
259   // This induces a flat used transform style.
260   other->SetOpacity(0.5);
261   StyleDifference diff;
262   style->UpdatePropertySpecificDifferences(*other, diff);
263   EXPECT_TRUE(diff.CompositingReasonsChanged());
264 }
265 
TEST(ComputedStyleTest,UpdatePropertySpecificDifferencesCompositingReasonsOverflow)266 TEST(ComputedStyleTest,
267      UpdatePropertySpecificDifferencesCompositingReasonsOverflow) {
268   scoped_refptr<ComputedStyle> style = ComputedStyle::Create();
269   scoped_refptr<ComputedStyle> other = ComputedStyle::Clone(*style);
270 
271   other->SetOverflowX(EOverflow::kHidden);
272   StyleDifference diff;
273   style->UpdatePropertySpecificDifferences(*other, diff);
274   EXPECT_TRUE(diff.CompositingReasonsChanged());
275 }
276 
TEST(ComputedStyleTest,UpdatePropertySpecificDifferencesCompositingReasonsContainsPaint)277 TEST(ComputedStyleTest,
278      UpdatePropertySpecificDifferencesCompositingReasonsContainsPaint) {
279   scoped_refptr<ComputedStyle> style = ComputedStyle::Create();
280   scoped_refptr<ComputedStyle> other = ComputedStyle::Clone(*style);
281 
282   // This induces a flat used transform style.
283   other->SetContain(kContainsPaint);
284   StyleDifference diff;
285   style->UpdatePropertySpecificDifferences(*other, diff);
286   EXPECT_TRUE(diff.CompositingReasonsChanged());
287 }
288 
TEST(ComputedStyleTest,UpdateBackgroundColorDifferencesHasAlpha)289 TEST(ComputedStyleTest, UpdateBackgroundColorDifferencesHasAlpha) {
290   scoped_refptr<ComputedStyle> style = ComputedStyle::Create();
291   scoped_refptr<ComputedStyle> other = ComputedStyle::Clone(*style);
292 
293   StyleDifference diff;
294   style->AdjustDiffForBackgroundVisuallyEqual(*other, diff);
295   EXPECT_FALSE(diff.HasAlphaChanged());
296 
297   style->SetBackgroundColor(StyleColor(Color(255, 255, 255, 255)));
298   other->SetBackgroundColor(StyleColor(Color(255, 255, 255, 128)));
299 
300   EXPECT_FALSE(
301       style->VisitedDependentColor(GetCSSPropertyBackgroundColor()).HasAlpha());
302   EXPECT_TRUE(
303       other->VisitedDependentColor(GetCSSPropertyBackgroundColor()).HasAlpha());
304 
305   style->AdjustDiffForBackgroundVisuallyEqual(*other, diff);
306   EXPECT_TRUE(diff.HasAlphaChanged());
307 }
308 
TEST(ComputedStyleTest,UpdateBackgroundLayerDifferencesHasAlpha)309 TEST(ComputedStyleTest, UpdateBackgroundLayerDifferencesHasAlpha) {
310   scoped_refptr<ComputedStyle> style = ComputedStyle::Create();
311   scoped_refptr<ComputedStyle> other = ComputedStyle::Clone(*style);
312 
313   StyleDifference diff;
314   style->AdjustDiffForBackgroundVisuallyEqual(*other, diff);
315   EXPECT_FALSE(diff.HasAlphaChanged());
316 
317   other->AccessBackgroundLayers().EnsureNext();
318   style->AdjustDiffForBackgroundVisuallyEqual(*other, diff);
319   EXPECT_TRUE(diff.HasAlphaChanged());
320 }
321 
TEST(ComputedStyleTest,HasOutlineWithCurrentColor)322 TEST(ComputedStyleTest, HasOutlineWithCurrentColor) {
323   scoped_refptr<ComputedStyle> style = ComputedStyle::Create();
324   EXPECT_FALSE(style->HasOutline());
325   EXPECT_FALSE(style->HasOutlineWithCurrentColor());
326   style->SetOutlineColor(StyleColor::CurrentColor());
327   EXPECT_FALSE(style->HasOutlineWithCurrentColor());
328   style->SetOutlineWidth(5);
329   EXPECT_FALSE(style->HasOutlineWithCurrentColor());
330   style->SetOutlineStyle(EBorderStyle::kSolid);
331   EXPECT_TRUE(style->HasOutlineWithCurrentColor());
332 }
333 
TEST(ComputedStyleTest,HasBorderColorReferencingCurrentColor)334 TEST(ComputedStyleTest, HasBorderColorReferencingCurrentColor) {
335   scoped_refptr<ComputedStyle> style = ComputedStyle::Create();
336   EXPECT_FALSE(style->HasBorderColorReferencingCurrentColor());
337   style->SetBorderBottomColor(StyleColor::CurrentColor());
338   EXPECT_FALSE(style->HasBorderColorReferencingCurrentColor());
339   style->SetBorderBottomWidth(5);
340   EXPECT_FALSE(style->HasBorderColorReferencingCurrentColor());
341   style->SetBorderBottomStyle(EBorderStyle::kSolid);
342   EXPECT_TRUE(style->HasBorderColorReferencingCurrentColor());
343 }
344 
TEST(ComputedStyleTest,BorderWidth)345 TEST(ComputedStyleTest, BorderWidth) {
346   scoped_refptr<ComputedStyle> style = ComputedStyle::Create();
347   style->SetBorderBottomWidth(5);
348   EXPECT_EQ(style->BorderBottomWidth(), 0);
349   EXPECT_EQ(style->BorderBottom().Width(), 5);
350   style->SetBorderBottomStyle(EBorderStyle::kSolid);
351   EXPECT_EQ(style->BorderBottomWidth(), 5);
352   EXPECT_EQ(style->BorderBottom().Width(), 5);
353 }
354 
TEST(ComputedStyleTest,CursorList)355 TEST(ComputedStyleTest, CursorList) {
356   scoped_refptr<ComputedStyle> style = ComputedStyle::Create();
357   scoped_refptr<ComputedStyle> other = ComputedStyle::Create();
358 
359   auto* gradient = MakeGarbageCollected<cssvalue::CSSLinearGradientValue>(
360       nullptr, nullptr, nullptr, nullptr, nullptr, cssvalue::kRepeating);
361 
362   auto* image_value = MakeGarbageCollected<StyleGeneratedImage>(*gradient);
363   auto* other_image_value =
364       MakeGarbageCollected<StyleGeneratedImage>(*gradient);
365 
366   EXPECT_TRUE(DataEquivalent(image_value, other_image_value));
367 
368   style->AddCursor(image_value, false);
369   other->AddCursor(other_image_value, false);
370   EXPECT_EQ(*style, *other);
371 }
372 
TEST(ComputedStyleTest,BorderStyle)373 TEST(ComputedStyleTest, BorderStyle) {
374   scoped_refptr<ComputedStyle> style = ComputedStyle::Create();
375   scoped_refptr<ComputedStyle> other = ComputedStyle::Create();
376   style->SetBorderLeftStyle(EBorderStyle::kSolid);
377   style->SetBorderTopStyle(EBorderStyle::kSolid);
378   style->SetBorderRightStyle(EBorderStyle::kSolid);
379   style->SetBorderBottomStyle(EBorderStyle::kSolid);
380   other->SetBorderLeftStyle(EBorderStyle::kSolid);
381   other->SetBorderTopStyle(EBorderStyle::kSolid);
382   other->SetBorderRightStyle(EBorderStyle::kSolid);
383   other->SetBorderBottomStyle(EBorderStyle::kSolid);
384 
385   EXPECT_TRUE(style->BorderSizeEquals(*other));
386   style->SetBorderLeftWidth(1.0);
387   EXPECT_FALSE(style->BorderSizeEquals(*other));
388   other->SetBorderLeftWidth(1.0);
389   EXPECT_TRUE(style->BorderSizeEquals(*other));
390 
391   EXPECT_TRUE(style->BorderSizeEquals(*other));
392   style->SetBorderTopWidth(1.0);
393   EXPECT_FALSE(style->BorderSizeEquals(*other));
394   other->SetBorderTopWidth(1.0);
395   EXPECT_TRUE(style->BorderSizeEquals(*other));
396 
397   EXPECT_TRUE(style->BorderSizeEquals(*other));
398   style->SetBorderRightWidth(1.0);
399   EXPECT_FALSE(style->BorderSizeEquals(*other));
400   other->SetBorderRightWidth(1.0);
401   EXPECT_TRUE(style->BorderSizeEquals(*other));
402 
403   EXPECT_TRUE(style->BorderSizeEquals(*other));
404   style->SetBorderBottomWidth(1.0);
405   EXPECT_FALSE(style->BorderSizeEquals(*other));
406   other->SetBorderBottomWidth(1.0);
407   EXPECT_TRUE(style->BorderSizeEquals(*other));
408 
409   style->SetBorderLeftStyle(EBorderStyle::kHidden);
410   EXPECT_FALSE(style->BorderSizeEquals(*other));
411   style->SetBorderLeftStyle(EBorderStyle::kNone);
412   EXPECT_FALSE(style->BorderSizeEquals(*other));
413   style->SetBorderLeftStyle(EBorderStyle::kSolid);
414   EXPECT_TRUE(style->BorderSizeEquals(*other));
415 
416   style->SetBorderTopStyle(EBorderStyle::kHidden);
417   EXPECT_FALSE(style->BorderSizeEquals(*other));
418   style->SetBorderTopStyle(EBorderStyle::kNone);
419   EXPECT_FALSE(style->BorderSizeEquals(*other));
420   style->SetBorderTopStyle(EBorderStyle::kSolid);
421   EXPECT_TRUE(style->BorderSizeEquals(*other));
422 
423   style->SetBorderRightStyle(EBorderStyle::kHidden);
424   EXPECT_FALSE(style->BorderSizeEquals(*other));
425   style->SetBorderRightStyle(EBorderStyle::kNone);
426   EXPECT_FALSE(style->BorderSizeEquals(*other));
427   style->SetBorderRightStyle(EBorderStyle::kSolid);
428   EXPECT_TRUE(style->BorderSizeEquals(*other));
429 
430   style->SetBorderBottomStyle(EBorderStyle::kHidden);
431   EXPECT_FALSE(style->BorderSizeEquals(*other));
432   style->SetBorderBottomStyle(EBorderStyle::kNone);
433   EXPECT_FALSE(style->BorderSizeEquals(*other));
434   style->SetBorderBottomStyle(EBorderStyle::kSolid);
435   EXPECT_TRUE(style->BorderSizeEquals(*other));
436 }
437 
438 #define TEST_ANIMATION_FLAG(flag, inherited)                               \
439   do {                                                                     \
440     auto style = ComputedStyle::Create();                                  \
441     auto other = ComputedStyle::Create();                                  \
442     EXPECT_FALSE(style->flag());                                           \
443     EXPECT_FALSE(other->flag());                                           \
444     style->Set##flag(true);                                                \
445     EXPECT_TRUE(style->flag());                                            \
446     EXPECT_EQ(ComputedStyle::Difference::inherited,                        \
447               ComputedStyle::ComputeDifference(style.get(), other.get())); \
448     auto diff = style->VisualInvalidationDiff(*document, *other);          \
449     EXPECT_TRUE(diff.HasDifference());                                     \
450     EXPECT_TRUE(diff.CompositingReasonsChanged());                         \
451   } while (false)
452 
453 #define TEST_ANIMATION_FLAG_NO_DIFF(flag)                                  \
454   do {                                                                     \
455     auto style = ComputedStyle::Create();                                  \
456     auto other = ComputedStyle::Create();                                  \
457     EXPECT_FALSE(style->flag());                                           \
458     EXPECT_FALSE(other->flag());                                           \
459     style->Set##flag(true);                                                \
460     EXPECT_TRUE(style->flag());                                            \
461     EXPECT_EQ(ComputedStyle::Difference::kEqual,                           \
462               ComputedStyle::ComputeDifference(style.get(), other.get())); \
463     auto diff = style->VisualInvalidationDiff(*document, *other);          \
464     EXPECT_FALSE(diff.HasDifference());                                    \
465     EXPECT_FALSE(diff.CompositingReasonsChanged());                        \
466   } while (false)
467 
TEST(ComputedStyleTest,AnimationFlags)468 TEST(ComputedStyleTest, AnimationFlags) {
469   Persistent<Document> document = Document::CreateForTest();
470   TEST_ANIMATION_FLAG(HasCurrentTransformAnimation, kNonInherited);
471   TEST_ANIMATION_FLAG(HasCurrentOpacityAnimation, kNonInherited);
472   TEST_ANIMATION_FLAG(HasCurrentFilterAnimation, kNonInherited);
473   TEST_ANIMATION_FLAG(HasCurrentBackdropFilterAnimation, kNonInherited);
474   TEST_ANIMATION_FLAG(SubtreeWillChangeContents, kInherited);
475   TEST_ANIMATION_FLAG_NO_DIFF(IsRunningTransformAnimationOnCompositor);
476   TEST_ANIMATION_FLAG_NO_DIFF(IsRunningOpacityAnimationOnCompositor);
477   TEST_ANIMATION_FLAG_NO_DIFF(IsRunningFilterAnimationOnCompositor);
478   TEST_ANIMATION_FLAG_NO_DIFF(IsRunningBackdropFilterAnimationOnCompositor);
479 }
480 
TEST(ComputedStyleTest,CustomPropertiesEqual_Values)481 TEST(ComputedStyleTest, CustomPropertiesEqual_Values) {
482   auto dummy = std::make_unique<DummyPageHolder>(IntSize(0, 0));
483   css_test_helpers::RegisterProperty(dummy->GetDocument(), "--x", "<length>",
484                                      "0px", false);
485 
486   scoped_refptr<ComputedStyle> style1 = ComputedStyle::Create();
487   scoped_refptr<ComputedStyle> style2 = ComputedStyle::Create();
488 
489   using UnitType = CSSPrimitiveValue::UnitType;
490 
491   const auto* value1 = CSSNumericLiteralValue::Create(1.0, UnitType::kPixels);
492   const auto* value2 = CSSNumericLiteralValue::Create(2.0, UnitType::kPixels);
493   const auto* value3 = CSSNumericLiteralValue::Create(1.0, UnitType::kPixels);
494 
495   Vector<AtomicString> properties;
496   properties.push_back("--x");
497 
498   style1->SetVariableValue("--x", value1, false);
499   style2->SetVariableValue("--x", value1, false);
500   EXPECT_TRUE(style1->CustomPropertiesEqual(properties, *style2));
501 
502   style1->SetVariableValue("--x", value1, false);
503   style2->SetVariableValue("--x", value3, false);
504   EXPECT_TRUE(style1->CustomPropertiesEqual(properties, *style2));
505 
506   style1->SetVariableValue("--x", value1, false);
507   style2->SetVariableValue("--x", value2, false);
508   EXPECT_FALSE(style1->CustomPropertiesEqual(properties, *style2));
509 }
510 
TEST(ComputedStyleTest,CustomPropertiesEqual_Data)511 TEST(ComputedStyleTest, CustomPropertiesEqual_Data) {
512   auto dummy = std::make_unique<DummyPageHolder>(IntSize(0, 0));
513   css_test_helpers::RegisterProperty(dummy->GetDocument(), "--x", "<length>",
514                                      "0px", false);
515 
516   scoped_refptr<ComputedStyle> style1 = ComputedStyle::Create();
517   scoped_refptr<ComputedStyle> style2 = ComputedStyle::Create();
518 
519   auto value1 = css_test_helpers::CreateVariableData("foo");
520   auto value2 = css_test_helpers::CreateVariableData("bar");
521   auto value3 = css_test_helpers::CreateVariableData("foo");
522 
523   Vector<AtomicString> properties;
524   properties.push_back("--x");
525 
526   style1->SetVariableData("--x", value1, false);
527   style2->SetVariableData("--x", value1, false);
528   EXPECT_TRUE(style1->CustomPropertiesEqual(properties, *style2));
529 
530   style1->SetVariableData("--x", value1, false);
531   style2->SetVariableData("--x", value3, false);
532   EXPECT_TRUE(style1->CustomPropertiesEqual(properties, *style2));
533 
534   style1->SetVariableData("--x", value1, false);
535   style2->SetVariableData("--x", value2, false);
536   EXPECT_FALSE(style1->CustomPropertiesEqual(properties, *style2));
537 }
538 
TEST(ComputedStyleTest,CustomPropertiesInheritance_FastPath)539 TEST(ComputedStyleTest, CustomPropertiesInheritance_FastPath) {
540   auto dummy = std::make_unique<DummyPageHolder>(IntSize(0, 0));
541   css_test_helpers::RegisterProperty(dummy->GetDocument(), "--x", "<length>",
542                                      "0px", true);
543 
544   scoped_refptr<ComputedStyle> old_style = ComputedStyle::Create();
545   scoped_refptr<ComputedStyle> new_style = ComputedStyle::Create();
546 
547   using UnitType = CSSPrimitiveValue::UnitType;
548 
549   const auto* value1 = CSSNumericLiteralValue::Create(1.0, UnitType::kPixels);
550   const auto* value2 = CSSNumericLiteralValue::Create(2.0, UnitType::kPixels);
551 
552   EXPECT_FALSE(old_style->HasVariableDeclaration());
553   EXPECT_FALSE(old_style->HasVariableReference());
554   EXPECT_FALSE(new_style->HasVariableReference());
555   EXPECT_FALSE(new_style->HasVariableDeclaration());
556 
557   // Removed variable
558   old_style->SetVariableValue("--x", value1, true);
559   EXPECT_EQ(ComputedStyle::Difference::kIndependentInherited,
560             ComputedStyle::ComputeDifference(old_style.get(), new_style.get()));
561 
562   old_style = ComputedStyle::Create();
563   new_style = ComputedStyle::Create();
564 
565   // Added a new variable
566   new_style->SetVariableValue("--x", value2, true);
567   EXPECT_EQ(ComputedStyle::Difference::kIndependentInherited,
568             ComputedStyle::ComputeDifference(old_style.get(), new_style.get()));
569 
570   // Change value of variable
571   old_style->SetVariableValue("--x", value1, true);
572   new_style->SetVariableValue("--x", value2, true);
573   new_style->SetHasVariableReference();
574   EXPECT_FALSE(new_style->HasVariableDeclaration());
575   EXPECT_TRUE(new_style->HasVariableReference());
576   EXPECT_EQ(ComputedStyle::Difference::kIndependentInherited,
577             ComputedStyle::ComputeDifference(old_style.get(), new_style.get()));
578 
579   old_style = ComputedStyle::Create();
580   new_style = ComputedStyle::Create();
581 
582   // New styles with variable declaration don't force style recalc
583   old_style->SetVariableValue("--x", value1, true);
584   new_style->SetVariableValue("--x", value2, true);
585   new_style->SetHasVariableDeclaration();
586   EXPECT_TRUE(new_style->HasVariableDeclaration());
587   EXPECT_FALSE(new_style->HasVariableReference());
588   EXPECT_EQ(ComputedStyle::Difference::kIndependentInherited,
589             ComputedStyle::ComputeDifference(old_style.get(), new_style.get()));
590 
591   old_style = ComputedStyle::Create();
592   new_style = ComputedStyle::Create();
593 
594   // New styles with variable reference don't force style recalc
595   old_style->SetVariableValue("--x", value1, true);
596   new_style->SetVariableValue("--x", value2, true);
597   new_style->SetHasVariableDeclaration();
598   new_style->SetHasVariableReference();
599   EXPECT_TRUE(new_style->HasVariableDeclaration());
600   EXPECT_TRUE(new_style->HasVariableReference());
601   EXPECT_EQ(ComputedStyle::Difference::kIndependentInherited,
602             ComputedStyle::ComputeDifference(old_style.get(), new_style.get()));
603 }
604 
TEST(ComputedStyleTest,CustomPropertiesInheritance_StyleRecalc)605 TEST(ComputedStyleTest, CustomPropertiesInheritance_StyleRecalc) {
606   auto dummy = std::make_unique<DummyPageHolder>(IntSize(0, 0));
607   css_test_helpers::RegisterProperty(dummy->GetDocument(), "--x", "<length>",
608                                      "0px", true);
609 
610   scoped_refptr<ComputedStyle> old_style = ComputedStyle::Create();
611   scoped_refptr<ComputedStyle> new_style = ComputedStyle::Create();
612 
613   using UnitType = CSSPrimitiveValue::UnitType;
614 
615   const auto* value1 = CSSNumericLiteralValue::Create(1.0, UnitType::kPixels);
616   const auto* value2 = CSSNumericLiteralValue::Create(2.0, UnitType::kPixels);
617 
618   EXPECT_FALSE(old_style->HasVariableDeclaration());
619   EXPECT_FALSE(old_style->HasVariableReference());
620   EXPECT_FALSE(new_style->HasVariableReference());
621   EXPECT_FALSE(new_style->HasVariableDeclaration());
622 
623   // Removed variable value
624   // Old styles with variable reference force style recalc
625   old_style->SetHasVariableReference();
626   old_style->SetVariableValue("--x", value2, true);
627   EXPECT_TRUE(old_style->HasVariableReference());
628   EXPECT_EQ(ComputedStyle::Difference::kInherited,
629             ComputedStyle::ComputeDifference(old_style.get(), new_style.get()));
630 
631   old_style = ComputedStyle::Create();
632   new_style = ComputedStyle::Create();
633 
634   // New variable value
635   // Old styles with variable declaration force style recalc
636   old_style->SetHasVariableDeclaration();
637   new_style->SetVariableValue("--x", value2, true);
638   EXPECT_TRUE(old_style->HasVariableDeclaration());
639   EXPECT_EQ(ComputedStyle::Difference::kInherited,
640             ComputedStyle::ComputeDifference(old_style.get(), new_style.get()));
641 
642   old_style = ComputedStyle::Create();
643   new_style = ComputedStyle::Create();
644 
645   // Change variable value
646   // Old styles with variable declaration force style recalc
647   old_style->SetVariableValue("--x", value1, true);
648   new_style->SetVariableValue("--x", value2, true);
649   old_style->SetHasVariableDeclaration();
650   EXPECT_TRUE(old_style->HasVariableDeclaration());
651   EXPECT_EQ(ComputedStyle::Difference::kInherited,
652             ComputedStyle::ComputeDifference(old_style.get(), new_style.get()));
653 
654   old_style = ComputedStyle::Create();
655   new_style = ComputedStyle::Create();
656 
657   // Change variable value
658   // Old styles with variable reference force style recalc
659   old_style->SetVariableValue("--x", value1, true);
660   new_style->SetVariableValue("--x", value2, true);
661   old_style->SetHasVariableReference();
662   EXPECT_TRUE(old_style->HasVariableReference());
663   EXPECT_EQ(ComputedStyle::Difference::kInherited,
664             ComputedStyle::ComputeDifference(old_style.get(), new_style.get()));
665 }
666 
TEST(ComputedStyleTest,ApplyColorSchemeLightOnDark)667 TEST(ComputedStyleTest, ApplyColorSchemeLightOnDark) {
668   ScopedCSSColorSchemeUARenderingForTest scoped_ua_enabled(true);
669 
670   std::unique_ptr<DummyPageHolder> dummy_page_holder_ =
671       std::make_unique<DummyPageHolder>(IntSize(0, 0), nullptr);
672   const ComputedStyle* initial = &ComputedStyle::InitialStyle();
673 
674   ColorSchemeHelper color_scheme_helper(dummy_page_holder_->GetDocument());
675   color_scheme_helper.SetPreferredColorScheme(
676       mojom::blink::PreferredColorScheme::kDark);
677   StyleResolverState state(dummy_page_holder_->GetDocument(),
678                            *dummy_page_holder_->GetDocument().documentElement(),
679                            initial, initial);
680 
681   scoped_refptr<ComputedStyle> style = ComputedStyle::Create();
682   state.SetStyle(style);
683 
684   CSSPropertyRef ref("color-scheme", state.GetDocument());
685 
686   CSSValueList* dark_value = CSSValueList::CreateSpaceSeparated();
687   dark_value->Append(*CSSIdentifierValue::Create(CSSValueID::kDark));
688 
689   CSSValueList* light_value = CSSValueList::CreateSpaceSeparated();
690   light_value->Append(*CSSIdentifierValue::Create(CSSValueID::kLight));
691 
692   To<Longhand>(ref.GetProperty()).ApplyValue(state, *dark_value);
693   EXPECT_EQ(mojom::blink::ColorScheme::kDark, style->UsedColorScheme());
694 
695   To<Longhand>(ref.GetProperty()).ApplyValue(state, *light_value);
696   EXPECT_EQ(mojom::blink::ColorScheme::kLight, style->UsedColorScheme());
697 }
698 
TEST(ComputedStyleTest,ApplyInternalLightDarkColor)699 TEST(ComputedStyleTest, ApplyInternalLightDarkColor) {
700   using css_test_helpers::ParseDeclarationBlock;
701 
702   ScopedCSSColorSchemeUARenderingForTest scoped_ua_enabled(true);
703 
704   std::unique_ptr<DummyPageHolder> dummy_page_holder_ =
705       std::make_unique<DummyPageHolder>(IntSize(0, 0), nullptr);
706   const ComputedStyle* initial = &ComputedStyle::InitialStyle();
707 
708   ColorSchemeHelper color_scheme_helper(dummy_page_holder_->GetDocument());
709   color_scheme_helper.SetPreferredColorScheme(
710       mojom::blink::PreferredColorScheme::kDark);
711   StyleResolverState state(dummy_page_holder_->GetDocument(),
712                            *dummy_page_holder_->GetDocument().documentElement(),
713                            initial, initial);
714 
715   scoped_refptr<ComputedStyle> style = ComputedStyle::Create();
716   state.SetStyle(style);
717 
718   CSSValueList* dark_value = CSSValueList::CreateSpaceSeparated();
719   dark_value->Append(*CSSIdentifierValue::Create(CSSValueID::kDark));
720 
721   CSSValueList* light_value = CSSValueList::CreateSpaceSeparated();
722   light_value->Append(*CSSIdentifierValue::Create(CSSValueID::kLight));
723 
724   auto* color_declaration = ParseDeclarationBlock(
725       "color:-internal-light-dark(black, white)", CSSParserMode::kUASheetMode);
726   auto* dark_declaration = ParseDeclarationBlock("color-scheme:dark");
727   auto* light_declaration = ParseDeclarationBlock("color-scheme:light");
728 
729   StyleCascade cascade1(state);
730   cascade1.MutableMatchResult().AddMatchedProperties(color_declaration);
731   cascade1.MutableMatchResult().AddMatchedProperties(dark_declaration);
732   cascade1.Apply();
733   EXPECT_EQ(Color::kWhite, style->VisitedDependentColor(GetCSSPropertyColor()));
734 
735   StyleCascade cascade2(state);
736   cascade2.MutableMatchResult().AddMatchedProperties(color_declaration);
737   cascade2.MutableMatchResult().AddMatchedProperties(light_declaration);
738   cascade2.Apply();
739   EXPECT_EQ(Color::kBlack, style->VisitedDependentColor(GetCSSPropertyColor()));
740 }
741 
TEST(ComputedStyleTest,ApplyInternalLightDarkBackgroundImage)742 TEST(ComputedStyleTest, ApplyInternalLightDarkBackgroundImage) {
743   using css_test_helpers::ParseDeclarationBlock;
744 
745   ScopedCSSColorSchemeUARenderingForTest scoped_ua_enabled(true);
746 
747   std::unique_ptr<DummyPageHolder> dummy_page_holder_ =
748       std::make_unique<DummyPageHolder>(IntSize(0, 0), nullptr);
749   const ComputedStyle* initial = &ComputedStyle::InitialStyle();
750 
751   ColorSchemeHelper color_scheme_helper(dummy_page_holder_->GetDocument());
752   color_scheme_helper.SetPreferredColorScheme(
753       mojom::blink::PreferredColorScheme::kDark);
754   StyleResolverState state(dummy_page_holder_->GetDocument(),
755                            *dummy_page_holder_->GetDocument().documentElement(),
756                            initial, initial);
757 
758   scoped_refptr<ComputedStyle> style = ComputedStyle::Create();
759   state.SetStyle(style);
760 
761   auto* bgimage_declaration = ParseDeclarationBlock(
762       "background-image:-internal-light-dark(none, url(dummy.png))",
763       kUASheetMode);
764   auto* dark_declaration = ParseDeclarationBlock("color-scheme:dark");
765   auto* light_declaration = ParseDeclarationBlock("color-scheme:light");
766 
767   EXPECT_FALSE(style->HasNonInheritedLightDarkValue());
768 
769   StyleCascade cascade1(state);
770   cascade1.MutableMatchResult().AddMatchedProperties(bgimage_declaration);
771   cascade1.MutableMatchResult().AddMatchedProperties(dark_declaration);
772   cascade1.Apply();
773   EXPECT_TRUE(style->HasBackgroundImage());
774   EXPECT_TRUE(style->HasNonInheritedLightDarkValue());
775 
776   style = ComputedStyle::Create();
777   state.SetStyle(style);
778 
779   StyleCascade cascade2(state);
780   cascade2.MutableMatchResult().AddMatchedProperties(bgimage_declaration);
781   cascade2.MutableMatchResult().AddMatchedProperties(light_declaration);
782   cascade2.Apply();
783   EXPECT_FALSE(style->HasBackgroundImage());
784   EXPECT_TRUE(style->HasNonInheritedLightDarkValue());
785 }
786 
TEST(ComputedStyleTest,StrokeWidthZoomAndCalc)787 TEST(ComputedStyleTest, StrokeWidthZoomAndCalc) {
788   std::unique_ptr<DummyPageHolder> dummy_page_holder_ =
789       std::make_unique<DummyPageHolder>(IntSize(0, 0), nullptr);
790 
791   const ComputedStyle* initial = &ComputedStyle::InitialStyle();
792 
793   StyleResolverState state(dummy_page_holder_->GetDocument(),
794                            *dummy_page_holder_->GetDocument().documentElement(),
795                            initial, initial);
796 
797   scoped_refptr<ComputedStyle> style = ComputedStyle::Create();
798   style->SetEffectiveZoom(1.5);
799   state.SetStyle(style);
800 
801   auto* calc_value =
802       CSSMathFunctionValue::Create(CSSMathExpressionNumericLiteral::Create(
803           CSSNumericLiteralValue::Create(10,
804                                          CSSPrimitiveValue::UnitType::kNumber),
805           true));
806 
807   To<Longhand>(GetCSSPropertyStrokeWidth()).ApplyValue(state, *calc_value);
808   auto* computed_value =
809       To<Longhand>(GetCSSPropertyStrokeWidth())
810           .CSSValueFromComputedStyleInternal(*style, style->SvgStyle(),
811                                              nullptr /* layout_object */,
812                                              false /* allow_visited_style */);
813   ASSERT_TRUE(computed_value);
814   auto* numeric_value = DynamicTo<CSSNumericLiteralValue>(computed_value);
815   ASSERT_TRUE(numeric_value);
816   EXPECT_TRUE(numeric_value->IsPx());
817   EXPECT_EQ(10, numeric_value->DoubleValue());
818 }
819 
TEST(ComputedStyleTest,InitialVariableNamesEmpty)820 TEST(ComputedStyleTest, InitialVariableNamesEmpty) {
821   scoped_refptr<ComputedStyle> style = ComputedStyle::Create();
822   EXPECT_TRUE(style->GetVariableNames().IsEmpty());
823 }
824 
TEST(ComputedStyleTest,InitialVariableNames)825 TEST(ComputedStyleTest, InitialVariableNames) {
826   using css_test_helpers::CreateLengthRegistration;
827 
828   scoped_refptr<ComputedStyle> style = ComputedStyle::Create();
829 
830   PropertyRegistry* registry = MakeGarbageCollected<PropertyRegistry>();
831   registry->RegisterProperty("--x", *CreateLengthRegistration("--x", 1));
832   registry->RegisterProperty("--y", *CreateLengthRegistration("--y", 2));
833   style->SetInitialData(StyleInitialData::Create(*registry));
834 
835   EXPECT_EQ(2u, style->GetVariableNames().size());
836   EXPECT_TRUE(style->GetVariableNames().Contains("--x"));
837   EXPECT_TRUE(style->GetVariableNames().Contains("--y"));
838 }
839 
TEST(ComputedStyleTest,InheritedVariableNames)840 TEST(ComputedStyleTest, InheritedVariableNames) {
841   using css_test_helpers::CreateVariableData;
842 
843   scoped_refptr<ComputedStyle> style = ComputedStyle::Create();
844 
845   const bool inherited = true;
846   style->SetVariableData("--a", CreateVariableData("foo"), inherited);
847   style->SetVariableData("--b", CreateVariableData("bar"), inherited);
848 
849   EXPECT_EQ(2u, style->GetVariableNames().size());
850   EXPECT_TRUE(style->GetVariableNames().Contains("--a"));
851   EXPECT_TRUE(style->GetVariableNames().Contains("--b"));
852 }
853 
TEST(ComputedStyleTest,NonInheritedVariableNames)854 TEST(ComputedStyleTest, NonInheritedVariableNames) {
855   using css_test_helpers::CreateVariableData;
856 
857   scoped_refptr<ComputedStyle> style = ComputedStyle::Create();
858 
859   const bool inherited = true;
860   style->SetVariableData("--a", CreateVariableData("foo"), !inherited);
861   style->SetVariableData("--b", CreateVariableData("bar"), !inherited);
862 
863   EXPECT_EQ(2u, style->GetVariableNames().size());
864   EXPECT_TRUE(style->GetVariableNames().Contains("--a"));
865   EXPECT_TRUE(style->GetVariableNames().Contains("--b"));
866 }
867 
TEST(ComputedStyleTest,InheritedAndNonInheritedVariableNames)868 TEST(ComputedStyleTest, InheritedAndNonInheritedVariableNames) {
869   using css_test_helpers::CreateVariableData;
870 
871   scoped_refptr<ComputedStyle> style = ComputedStyle::Create();
872 
873   const bool inherited = true;
874   style->SetVariableData("--a", CreateVariableData("foo"), inherited);
875   style->SetVariableData("--b", CreateVariableData("bar"), inherited);
876   style->SetVariableData("--d", CreateVariableData("foz"), !inherited);
877   style->SetVariableData("--c", CreateVariableData("baz"), !inherited);
878 
879   EXPECT_EQ(4u, style->GetVariableNames().size());
880   EXPECT_TRUE(style->GetVariableNames().Contains("--a"));
881   EXPECT_TRUE(style->GetVariableNames().Contains("--b"));
882   EXPECT_TRUE(style->GetVariableNames().Contains("--c"));
883   EXPECT_TRUE(style->GetVariableNames().Contains("--d"));
884 }
885 
TEST(ComputedStyleTest,InitialAndInheritedAndNonInheritedVariableNames)886 TEST(ComputedStyleTest, InitialAndInheritedAndNonInheritedVariableNames) {
887   using css_test_helpers::CreateLengthRegistration;
888   using css_test_helpers::CreateVariableData;
889 
890   scoped_refptr<ComputedStyle> style = ComputedStyle::Create();
891 
892   PropertyRegistry* registry = MakeGarbageCollected<PropertyRegistry>();
893   registry->RegisterProperty("--b", *CreateLengthRegistration("--b", 1));
894   registry->RegisterProperty("--e", *CreateLengthRegistration("--e", 2));
895   style->SetInitialData(StyleInitialData::Create(*registry));
896 
897   const bool inherited = true;
898   style->SetVariableData("--a", CreateVariableData("foo"), inherited);
899   style->SetVariableData("--b", CreateVariableData("bar"), inherited);
900   style->SetVariableData("--d", CreateVariableData("foz"), !inherited);
901   style->SetVariableData("--c", CreateVariableData("baz"), !inherited);
902 
903   EXPECT_EQ(5u, style->GetVariableNames().size());
904   EXPECT_TRUE(style->GetVariableNames().Contains("--a"));
905   EXPECT_TRUE(style->GetVariableNames().Contains("--b"));
906   EXPECT_TRUE(style->GetVariableNames().Contains("--c"));
907   EXPECT_TRUE(style->GetVariableNames().Contains("--d"));
908   EXPECT_TRUE(style->GetVariableNames().Contains("--e"));
909 }
910 
TEST(ComputedStyleTest,BorderWidthZoom)911 TEST(ComputedStyleTest, BorderWidthZoom) {
912   std::unique_ptr<DummyPageHolder> dummy_page_holder_ =
913       std::make_unique<DummyPageHolder>(IntSize(0, 0), nullptr);
914 
915   const ComputedStyle* initial = &ComputedStyle::InitialStyle();
916 
917   StyleResolverState state(dummy_page_holder_->GetDocument(),
918                            *dummy_page_holder_->GetDocument().documentElement(),
919                            initial, initial);
920 
921   scoped_refptr<ComputedStyle> style = ComputedStyle::Create();
922   style->SetEffectiveZoom(2);
923   style->SetBorderLeftStyle(EBorderStyle::kSolid);
924   style->SetOutlineStyle(EBorderStyle::kSolid);
925   style->SetColumnRuleStyle(EBorderStyle::kSolid);
926   state.SetStyle(style);
927 
928   const struct {
929     CSSIdentifierValue* css_value;
930     double expected_px;
931     STACK_ALLOCATED();
932   } tests[] = {
933       {CSSIdentifierValue::Create(CSSValueID::kThin), 1.0},
934       {CSSIdentifierValue::Create(CSSValueID::kMedium), 3.0},
935       {CSSIdentifierValue::Create(CSSValueID::kThick), 5.0},
936   };
937 
938   for (const auto& test : tests) {
939     for (const auto* property :
940          {&GetCSSPropertyBorderLeftWidth(), &GetCSSPropertyOutlineWidth(),
941           &GetCSSPropertyColumnRuleWidth()}) {
942       const Longhand& longhand = To<Longhand>(*property);
943       longhand.ApplyValue(state, *test.css_value);
944       auto* computed_value = longhand.CSSValueFromComputedStyleInternal(
945           *style, style->SvgStyle(), nullptr /* layout_object */,
946           false /* allow_visited_style */);
947       AtomicString prop_name = longhand.GetCSSPropertyName().ToAtomicString();
948       ASSERT_TRUE(computed_value) << prop_name;
949       auto* numeric_value = DynamicTo<CSSNumericLiteralValue>(computed_value);
950       ASSERT_TRUE(numeric_value) << prop_name;
951       EXPECT_TRUE(numeric_value->IsPx()) << prop_name;
952       EXPECT_EQ(test.expected_px, numeric_value->DoubleValue()) << prop_name;
953     }
954   }
955 }
956 
TEST(ComputedStyleTest,TextDecorationEqualDoesNotRequireRecomputeInkOverflow)957 TEST(ComputedStyleTest, TextDecorationEqualDoesNotRequireRecomputeInkOverflow) {
958   using css_test_helpers::ParseDeclarationBlock;
959 
960   std::unique_ptr<DummyPageHolder> dummy_page_holder_ =
961       std::make_unique<DummyPageHolder>(IntSize(0, 0), nullptr);
962   const ComputedStyle* initial = &ComputedStyle::InitialStyle();
963 
964   StyleResolverState state(dummy_page_holder_->GetDocument(),
965                            *dummy_page_holder_->GetDocument().documentElement(),
966                            initial, initial);
967 
968   scoped_refptr<ComputedStyle> style = ComputedStyle::Create();
969 
970   // Set up the initial text decoration properties
971   style->SetTextDecorationStyle(ETextDecorationStyle::kSolid);
972   style->SetTextDecorationColor(StyleColor(CSSValueID::kGreen));
973   style->SetTextDecoration(TextDecoration::kUnderline);
974   style->SetTextDecorationThickness(
975       TextDecorationThickness(Length(5, Length::Type::kFixed)));
976   style->SetTextUnderlineOffset(Length(2, Length::Type::kFixed));
977   style->SetTextUnderlinePosition(kTextUnderlinePositionUnder);
978   state.SetStyle(style);
979   StyleAdjuster::AdjustComputedStyle(state, nullptr /* element */);
980   EXPECT_EQ(TextDecoration::kUnderline, style->TextDecorationsInEffect());
981 
982   scoped_refptr<ComputedStyle> other = ComputedStyle::Clone(*style);
983   StyleDifference diff1;
984   style->UpdatePropertySpecificDifferences(*other, diff1);
985   EXPECT_FALSE(diff1.NeedsRecomputeVisualOverflow());
986 
987   // Change the color, and it should not invalidate
988   other->SetTextDecorationColor(StyleColor(CSSValueID::kBlue));
989   state.SetStyle(other);
990   StyleAdjuster::AdjustComputedStyle(state, nullptr /* element */);
991   StyleDifference diff2;
992   style->UpdatePropertySpecificDifferences(*other, diff2);
993   EXPECT_FALSE(diff2.NeedsRecomputeVisualOverflow());
994 }
995 
TEST(ComputedStyleTest,TextDecorationNotEqualRequiresRecomputeInkOverflow)996 TEST(ComputedStyleTest, TextDecorationNotEqualRequiresRecomputeInkOverflow) {
997   using css_test_helpers::ParseDeclarationBlock;
998 
999   std::unique_ptr<DummyPageHolder> dummy_page_holder_ =
1000       std::make_unique<DummyPageHolder>(IntSize(0, 0), nullptr);
1001   const ComputedStyle* initial = &ComputedStyle::InitialStyle();
1002 
1003   StyleResolverState state(dummy_page_holder_->GetDocument(),
1004                            *dummy_page_holder_->GetDocument().documentElement(),
1005                            initial, initial);
1006 
1007   scoped_refptr<ComputedStyle> style = ComputedStyle::Create();
1008 
1009   // Set up the initial text decoration properties
1010   style->SetTextDecorationStyle(ETextDecorationStyle::kSolid);
1011   style->SetTextDecorationColor(StyleColor(CSSValueID::kGreen));
1012   style->SetTextDecoration(TextDecoration::kUnderline);
1013   style->SetTextDecorationThickness(
1014       TextDecorationThickness(Length(5, Length::Type::kFixed)));
1015   style->SetTextUnderlineOffset(Length(2, Length::Type::kFixed));
1016   style->SetTextUnderlinePosition(kTextUnderlinePositionUnder);
1017   state.SetStyle(style);
1018   StyleAdjuster::AdjustComputedStyle(state, nullptr /* element */);
1019 
1020   // Change decoration style
1021   scoped_refptr<ComputedStyle> other = ComputedStyle::Clone(*style);
1022   other->SetTextDecorationStyle(ETextDecorationStyle::kWavy);
1023   state.SetStyle(other);
1024   StyleAdjuster::AdjustComputedStyle(state, nullptr /* element */);
1025   StyleDifference diff_decoration_style;
1026   style->UpdatePropertySpecificDifferences(*other, diff_decoration_style);
1027   EXPECT_TRUE(diff_decoration_style.NeedsRecomputeVisualOverflow());
1028 
1029   // Change decoration line
1030   other = ComputedStyle::Clone(*style);
1031   other->SetTextDecoration(TextDecoration::kOverline);
1032   state.SetStyle(other);
1033   StyleAdjuster::AdjustComputedStyle(state, nullptr /* element */);
1034   StyleDifference diff_decoration_line;
1035   style->UpdatePropertySpecificDifferences(*other, diff_decoration_line);
1036   EXPECT_TRUE(diff_decoration_line.NeedsRecomputeVisualOverflow());
1037 
1038   // Change decoration thickness
1039   other = ComputedStyle::Clone(*style);
1040   other->SetTextDecorationThickness(
1041       TextDecorationThickness(Length(3, Length::Type::kFixed)));
1042   state.SetStyle(other);
1043   StyleAdjuster::AdjustComputedStyle(state, nullptr /* element */);
1044   StyleDifference diff_decoration_thickness;
1045   style->UpdatePropertySpecificDifferences(*other, diff_decoration_thickness);
1046   EXPECT_TRUE(diff_decoration_thickness.NeedsRecomputeVisualOverflow());
1047 
1048   // Change underline offset
1049   other = ComputedStyle::Clone(*style);
1050   other->SetTextUnderlineOffset(Length(4, Length::Type::kFixed));
1051   state.SetStyle(other);
1052   StyleAdjuster::AdjustComputedStyle(state, nullptr /* element */);
1053   StyleDifference diff_underline_offset;
1054   style->UpdatePropertySpecificDifferences(*other, diff_underline_offset);
1055   EXPECT_TRUE(diff_underline_offset.NeedsRecomputeVisualOverflow());
1056 
1057   // Change underline position
1058   other = ComputedStyle::Clone(*style);
1059   other->SetTextUnderlinePosition(kTextUnderlinePositionLeft);
1060   state.SetStyle(other);
1061   StyleAdjuster::AdjustComputedStyle(state, nullptr /* element */);
1062   StyleDifference diff_underline_position;
1063   style->UpdatePropertySpecificDifferences(*other, diff_underline_position);
1064   EXPECT_TRUE(diff_underline_position.NeedsRecomputeVisualOverflow());
1065 }
1066 
1067 // Verify that cloned ComputedStyle is independent from source, i.e.
1068 // copy-on-write works as expected.
TEST(ComputedStyleTest,ClonedStyleAnimationsAreIndependent)1069 TEST(ComputedStyleTest, ClonedStyleAnimationsAreIndependent) {
1070   scoped_refptr<ComputedStyle> style = ComputedStyle::Create();
1071 
1072   auto& animations = style->AccessAnimations();
1073   animations.DelayList().clear();
1074   animations.DelayList().push_back(CSSAnimationData::InitialDelay());
1075   EXPECT_EQ(1u, style->Animations()->DelayList().size());
1076 
1077   scoped_refptr<ComputedStyle> cloned_style = ComputedStyle::Clone(*style);
1078   auto& cloned_style_animations = cloned_style->AccessAnimations();
1079   EXPECT_EQ(1u, cloned_style_animations.DelayList().size());
1080   cloned_style_animations.DelayList().push_back(
1081       CSSAnimationData::InitialDelay());
1082 
1083   EXPECT_EQ(2u, cloned_style->Animations()->DelayList().size());
1084   EXPECT_EQ(1u, style->Animations()->DelayList().size());
1085 }
1086 
TEST(ComputedStyleTest,ClonedStyleTransitionsAreIndependent)1087 TEST(ComputedStyleTest, ClonedStyleTransitionsAreIndependent) {
1088   scoped_refptr<ComputedStyle> style = ComputedStyle::Create();
1089 
1090   auto& transitions = style->AccessTransitions();
1091   transitions.PropertyList().clear();
1092   transitions.PropertyList().push_back(CSSTransitionData::InitialProperty());
1093   EXPECT_EQ(1u, style->Transitions()->PropertyList().size());
1094 
1095   scoped_refptr<ComputedStyle> cloned_style = ComputedStyle::Clone(*style);
1096   auto& cloned_style_transitions = cloned_style->AccessTransitions();
1097   EXPECT_EQ(1u, cloned_style_transitions.PropertyList().size());
1098   cloned_style_transitions.PropertyList().push_back(
1099       CSSTransitionData::InitialProperty());
1100 
1101   EXPECT_EQ(2u, cloned_style->Transitions()->PropertyList().size());
1102   EXPECT_EQ(1u, style->Transitions()->PropertyList().size());
1103 }
1104 
TEST(ComputedStyleTest,ApplyInitialAnimationNameAndTransitionProperty)1105 TEST(ComputedStyleTest, ApplyInitialAnimationNameAndTransitionProperty) {
1106   std::unique_ptr<DummyPageHolder> dummy_page_holder_ =
1107       std::make_unique<DummyPageHolder>(IntSize(0, 0), nullptr);
1108 
1109   const ComputedStyle* initial = &ComputedStyle::InitialStyle();
1110   StyleResolverState state(dummy_page_holder_->GetDocument(),
1111                            *dummy_page_holder_->GetDocument().documentElement(),
1112                            initial, initial);
1113 
1114   scoped_refptr<ComputedStyle> style = ComputedStyle::Create();
1115   state.SetStyle(style);
1116   EXPECT_FALSE(style->Animations());
1117   EXPECT_FALSE(style->Transitions());
1118 
1119   To<Longhand>(GetCSSPropertyAnimationName()).ApplyInitial(state);
1120   To<Longhand>(GetCSSPropertyTransitionProperty()).ApplyInitial(state);
1121   EXPECT_FALSE(style->Animations());
1122   EXPECT_FALSE(style->Transitions());
1123 }
1124 
1125 }  // namespace blink
1126