1 // Copyright 2019 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/css/resolver/style_cascade.h"
6 
7 #include <vector>
8 
9 #include "third_party/blink/renderer/bindings/core/v8/v8_css_style_sheet_init.h"
10 #include "third_party/blink/renderer/core/animation/css/css_animations.h"
11 #include "third_party/blink/renderer/core/css/active_style_sheets.h"
12 #include "third_party/blink/renderer/core/css/css_custom_property_declaration.h"
13 #include "third_party/blink/renderer/core/css/css_initial_color_value.h"
14 #include "third_party/blink/renderer/core/css/css_pending_substitution_value.h"
15 #include "third_party/blink/renderer/core/css/css_primitive_value.h"
16 #include "third_party/blink/renderer/core/css/css_revert_value.h"
17 #include "third_party/blink/renderer/core/css/css_test_helpers.h"
18 #include "third_party/blink/renderer/core/css/css_variable_reference_value.h"
19 #include "third_party/blink/renderer/core/css/document_style_environment_variables.h"
20 #include "third_party/blink/renderer/core/css/media_query_evaluator.h"
21 #include "third_party/blink/renderer/core/css/parser/css_parser_context.h"
22 #include "third_party/blink/renderer/core/css/parser/css_parser_local_context.h"
23 #include "third_party/blink/renderer/core/css/parser/css_parser_token_range.h"
24 #include "third_party/blink/renderer/core/css/parser/css_property_parser.h"
25 #include "third_party/blink/renderer/core/css/parser/css_tokenizer.h"
26 #include "third_party/blink/renderer/core/css/parser/css_variable_parser.h"
27 #include "third_party/blink/renderer/core/css/properties/css_property_instances.h"
28 #include "third_party/blink/renderer/core/css/properties/css_property_ref.h"
29 #include "third_party/blink/renderer/core/css/properties/longhands/custom_property.h"
30 #include "third_party/blink/renderer/core/css/property_registry.h"
31 #include "third_party/blink/renderer/core/css/resolver/cascade_filter.h"
32 #include "third_party/blink/renderer/core/css/resolver/cascade_interpolations.h"
33 #include "third_party/blink/renderer/core/css/resolver/cascade_map.h"
34 #include "third_party/blink/renderer/core/css/resolver/cascade_priority.h"
35 #include "third_party/blink/renderer/core/css/resolver/cascade_resolver.h"
36 #include "third_party/blink/renderer/core/css/resolver/scoped_style_resolver.h"
37 #include "third_party/blink/renderer/core/css/resolver/style_resolver.h"
38 #include "third_party/blink/renderer/core/css/style_engine.h"
39 #include "third_party/blink/renderer/core/css/style_sheet_contents.h"
40 #include "third_party/blink/renderer/core/html/html_element.h"
41 #include "third_party/blink/renderer/core/style/computed_style.h"
42 #include "third_party/blink/renderer/core/style_property_shorthand.h"
43 #include "third_party/blink/renderer/core/testing/color_scheme_helper.h"
44 #include "third_party/blink/renderer/core/testing/page_test_base.h"
45 #include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h"
46 #include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
47 
48 namespace blink {
49 
50 using css_test_helpers::ParseDeclarationBlock;
51 using css_test_helpers::RegisterProperty;
52 using Origin = CascadeOrigin;
53 using Priority = CascadePriority;
54 using UnitType = CSSPrimitiveValue::UnitType;
55 
56 class TestCascadeResolver {
57   STACK_ALLOCATED();
58 
59  public:
TestCascadeResolver(uint8_t generation=0)60   explicit TestCascadeResolver(uint8_t generation = 0)
61       : resolver_(CascadeFilter(), generation) {}
InCycle() const62   bool InCycle() const { return resolver_.InCycle(); }
DetectCycle(const CSSProperty & property)63   bool DetectCycle(const CSSProperty& property) {
64     return resolver_.DetectCycle(property);
65   }
CycleDepth() const66   wtf_size_t CycleDepth() const { return resolver_.cycle_depth_; }
MarkApplied(CascadePriority * priority)67   void MarkApplied(CascadePriority* priority) {
68     resolver_.MarkApplied(priority);
69   }
MarkUnapplied(CascadePriority * priority)70   void MarkUnapplied(CascadePriority* priority) {
71     resolver_.MarkUnapplied(priority);
72   }
GetGeneration()73   uint8_t GetGeneration() { return resolver_.generation_; }
InnerResolver()74   CascadeResolver& InnerResolver() { return resolver_; }
CurrentProperty() const75   const CSSProperty* CurrentProperty() const {
76     return resolver_.CurrentProperty();
77   }
78 
79  private:
80   friend class TestCascadeAutoLock;
81 
82   CascadeResolver resolver_;
83 };
84 
85 class TestCascade {
86   STACK_ALLOCATED();
87 
88  public:
TestCascade(Document & document,Element * target=nullptr)89   TestCascade(Document& document, Element* target = nullptr)
90       : state_(document, target ? *target : *document.body()),
91         cascade_(InitState(state_)) {}
92 
TakeStyle()93   scoped_refptr<ComputedStyle> TakeStyle() { return state_.TakeStyle(); }
94 
State()95   StyleResolverState& State() { return state_; }
InnerCascade()96   StyleCascade& InnerCascade() { return cascade_; }
97 
InheritFrom(scoped_refptr<ComputedStyle> parent)98   void InheritFrom(scoped_refptr<ComputedStyle> parent) {
99     state_.SetParentStyle(parent);
100     state_.StyleRef().InheritFrom(*parent);
101   }
102 
103   //  Note that because of how MatchResult works, declarations must be added
104   //  in "origin order", i.e. UserAgent first, then User, then Author.
105 
Add(String block,CascadeOrigin origin=CascadeOrigin::kAuthor,unsigned link_match_type=CSSSelector::kMatchAll)106   void Add(String block,
107            CascadeOrigin origin = CascadeOrigin::kAuthor,
108            unsigned link_match_type = CSSSelector::kMatchAll) {
109     CSSParserMode mode =
110         origin == CascadeOrigin::kUserAgent ? kUASheetMode : kHTMLStandardMode;
111     Add(ParseDeclarationBlock(block, mode), origin, link_match_type);
112   }
113 
Add(String name,String value,CascadeOrigin origin=Origin::kAuthor)114   void Add(String name, String value, CascadeOrigin origin = Origin::kAuthor) {
115     Add(name + ":" + value, origin);
116   }
117 
Add(const CSSPropertyValueSet * set,CascadeOrigin origin=CascadeOrigin::kAuthor,unsigned link_match_type=CSSSelector::kMatchAll)118   void Add(const CSSPropertyValueSet* set,
119            CascadeOrigin origin = CascadeOrigin::kAuthor,
120            unsigned link_match_type = CSSSelector::kMatchAll) {
121     DCHECK_LE(origin, CascadeOrigin::kAuthor) << "Animations not supported";
122     DCHECK_LE(current_origin_, origin) << "Please add declarations in order";
123     EnsureAtLeast(origin);
124     cascade_.MutableMatchResult().AddMatchedProperties(set, link_match_type);
125   }
126 
Apply(CascadeFilter filter=CascadeFilter ())127   void Apply(CascadeFilter filter = CascadeFilter()) {
128     EnsureAtLeast(CascadeOrigin::kAnimation);
129     cascade_.Apply(filter);
130   }
131 
ApplySingle(const CSSProperty & property)132   void ApplySingle(const CSSProperty& property) {
133     EnsureAtLeast(CascadeOrigin::kAnimation);
134     cascade_.AnalyzeIfNeeded();
135     TestCascadeResolver resolver(++cascade_.generation_);
136     cascade_.LookupAndApply(property, resolver.InnerResolver());
137   }
138 
AnalyzeIfNeeded()139   void AnalyzeIfNeeded() { cascade_.AnalyzeIfNeeded(); }
140 
Resolve(const CSSProperty & property,const CSSValue & value,CascadeOrigin & origin)141   const CSSValue* Resolve(const CSSProperty& property,
142                           const CSSValue& value,
143                           CascadeOrigin& origin) {
144     TestCascadeResolver resolver;
145     return cascade_.Resolve(property, value, origin, resolver.InnerResolver());
146   }
147 
GetImportantSet()148   std::unique_ptr<CSSBitset> GetImportantSet() {
149     return cascade_.GetImportantSet();
150   }
151 
ComputedValue(String name) const152   String ComputedValue(String name) const {
153     CSSPropertyRef ref(name, GetDocument());
154     DCHECK(ref.IsValid());
155     const LayoutObject* layout_object = nullptr;
156     bool allow_visited_style = false;
157     const CSSValue* value = ref.GetProperty().CSSValueFromComputedStyle(
158         *state_.Style(), layout_object, allow_visited_style);
159     return value ? value->CssText() : g_null_atom;
160   }
161 
GetPriority(String name)162   CascadePriority GetPriority(String name) {
163     return GetPriority(
164         *CSSPropertyName::From(GetDocument().GetExecutionContext(), name));
165   }
166 
GetPriority(CSSPropertyName name)167   CascadePriority GetPriority(CSSPropertyName name) {
168     CascadePriority* c = cascade_.map_.Find(name);
169     return c ? *c : CascadePriority();
170   }
171 
GetOrigin(String name)172   CascadeOrigin GetOrigin(String name) { return GetPriority(name).GetOrigin(); }
173 
CalculateTransitionUpdate()174   void CalculateTransitionUpdate() {
175     CSSAnimations::CalculateTransitionUpdate(
176         state_.AnimationUpdate(), CSSAnimations::PropertyPass::kCustom,
177         &state_.GetElement(), *state_.Style());
178     CSSAnimations::CalculateTransitionUpdate(
179         state_.AnimationUpdate(), CSSAnimations::PropertyPass::kStandard,
180         &state_.GetElement(), *state_.Style());
181     AddTransitions();
182   }
183 
CalculateAnimationUpdate()184   void CalculateAnimationUpdate() {
185     CSSAnimations::CalculateAnimationUpdate(
186         state_.AnimationUpdate(), &state_.GetElement(), state_.GetElement(),
187         *state_.Style(), state_.ParentStyle(),
188         &GetDocument().GetStyleResolver());
189     AddAnimations();
190   }
191 
Reset()192   void Reset() {
193     cascade_.Reset();
194     current_origin_ = CascadeOrigin::kUserAgent;
195   }
196 
NeedsMatchResultAnalyze() const197   bool NeedsMatchResultAnalyze() const {
198     return cascade_.needs_match_result_analyze_;
199   }
NeedsInterpolationsAnalyze() const200   bool NeedsInterpolationsAnalyze() const {
201     return cascade_.needs_interpolations_analyze_;
202   }
DependsOnCascadeAffectingProperty() const203   bool DependsOnCascadeAffectingProperty() const {
204     return cascade_.depends_on_cascade_affecting_property_;
205   }
206 
GetCascadedValues() const207   HeapHashMap<CSSPropertyName, Member<const CSSValue>> GetCascadedValues()
208       const {
209     return cascade_.GetCascadedValues();
210   }
211 
212  private:
GetDocument() const213   Document& GetDocument() const { return state_.GetDocument(); }
Body() const214   Element* Body() const { return GetDocument().body(); }
215 
InitState(StyleResolverState & state)216   static StyleResolverState& InitState(StyleResolverState& state) {
217     state.SetStyle(InitialStyle(state.GetDocument()));
218     state.SetParentStyle(InitialStyle(state.GetDocument()));
219     return state;
220   }
221 
InitialStyle(Document & document)222   static scoped_refptr<ComputedStyle> InitialStyle(Document& document) {
223     return StyleResolver::InitialStyleForElement(document);
224   }
225 
FinishOrigin()226   void FinishOrigin() {
227     switch (current_origin_) {
228       case CascadeOrigin::kUserAgent:
229         cascade_.MutableMatchResult().FinishAddingUARules();
230         current_origin_ = CascadeOrigin::kUser;
231         break;
232       case CascadeOrigin::kUser:
233         cascade_.MutableMatchResult().FinishAddingUserRules();
234         current_origin_ = CascadeOrigin::kAuthor;
235         break;
236       case CascadeOrigin::kAuthor:
237         cascade_.MutableMatchResult().FinishAddingAuthorRulesForTreeScope(
238             GetDocument());
239         current_origin_ = CascadeOrigin::kAnimation;
240         break;
241       case CascadeOrigin::kAnimation:
242         break;
243       default:
244         NOTREACHED();
245         break;
246     }
247   }
248 
EnsureAtLeast(CascadeOrigin origin)249   void EnsureAtLeast(CascadeOrigin origin) {
250     while (current_origin_ < origin)
251       FinishOrigin();
252   }
253 
AddAnimations()254   void AddAnimations() {
255     const auto& update = state_.AnimationUpdate();
256     if (update.IsEmpty())
257       return;
258     cascade_.AddInterpolations(
259         &update.ActiveInterpolationsForCustomAnimations(),
260         CascadeOrigin::kAnimation);
261     cascade_.AddInterpolations(
262         &update.ActiveInterpolationsForStandardAnimations(),
263         CascadeOrigin::kAnimation);
264   }
265 
AddTransitions()266   void AddTransitions() {
267     const auto& update = state_.AnimationUpdate();
268     if (update.IsEmpty())
269       return;
270     cascade_.AddInterpolations(
271         &update.ActiveInterpolationsForCustomTransitions(),
272         CascadeOrigin::kTransition);
273     cascade_.AddInterpolations(
274         &update.ActiveInterpolationsForStandardTransitions(),
275         CascadeOrigin::kTransition);
276   }
277 
278   CascadeOrigin current_origin_ = CascadeOrigin::kUserAgent;
279   StyleResolverState state_;
280   StyleCascade cascade_;
281 };
282 
283 class TestCascadeAutoLock {
284   STACK_ALLOCATED();
285 
286  public:
TestCascadeAutoLock(const CSSProperty & property,TestCascadeResolver & resolver)287   TestCascadeAutoLock(const CSSProperty& property,
288                       TestCascadeResolver& resolver)
289       : lock_(property, resolver.resolver_) {}
290 
291  private:
292   CascadeResolver::AutoLock lock_;
293 };
294 
295 class StyleCascadeTest
296     : public PageTestBase,
297       private ScopedCSSMatchedPropertiesCacheDependenciesForTest {
298  public:
StyleCascadeTest()299   StyleCascadeTest()
300       : ScopedCSSMatchedPropertiesCacheDependenciesForTest(true) {}
301 
CreateSheet(const String & css_text)302   CSSStyleSheet* CreateSheet(const String& css_text) {
303     auto* init = MakeGarbageCollected<CSSStyleSheetInit>();
304     DummyExceptionStateForTesting exception_state;
305     CSSStyleSheet* sheet =
306         CSSStyleSheet::Create(GetDocument(), init, exception_state);
307     sheet->replaceSync(css_text, exception_state);
308     sheet->Contents()->EnsureRuleSet(
309         MediaQueryEvaluator(GetDocument().GetFrame()), kRuleHasNoSpecialState);
310     return sheet;
311   }
312 
AppendSheet(const String & css_text)313   void AppendSheet(const String& css_text) {
314     CSSStyleSheet* sheet = CreateSheet(css_text);
315     ASSERT_TRUE(sheet);
316 
317     Element* body = GetDocument().body();
318     ASSERT_TRUE(body->IsInTreeScope());
319     TreeScope& tree_scope = body->GetTreeScope();
320     ScopedStyleResolver& scoped_resolver =
321         tree_scope.EnsureScopedStyleResolver();
322     ActiveStyleSheetVector active_sheets;
323     active_sheets.push_back(
324         std::make_pair(sheet, &sheet->Contents()->GetRuleSet()));
325     scoped_resolver.AppendActiveStyleSheets(0, active_sheets);
326     GetDocument()
327         .GetStyleEngine()
328         .GetDocumentStyleSheetCollection()
329         .AppendActiveStyleSheet(active_sheets[0]);
330   }
331 
DocumentElement() const332   Element* DocumentElement() const { return GetDocument().documentElement(); }
333 
SetRootFont(String value)334   void SetRootFont(String value) {
335     DocumentElement()->SetInlineStyleProperty(CSSPropertyID::kFontSize, value);
336     UpdateAllLifecyclePhasesForTest();
337   }
338 
AnimationTaintedSet(AtomicString name,String value)339   const MutableCSSPropertyValueSet* AnimationTaintedSet(AtomicString name,
340                                                         String value) {
341     CSSParserMode mode = kHTMLStandardMode;
342     auto* set = MakeGarbageCollected<MutableCSSPropertyValueSet>(mode);
343     set->SetProperty(name, value, /* important */ false,
344                      SecureContextMode::kSecureContext,
345                      /* context_style_sheet */ nullptr,
346                      /* is_animation_tainted */ true);
347     return set;
348   }
349 
350   // Temporarily create a CSS Environment Variable.
351   // https://drafts.csswg.org/css-env-1/
352   class AutoEnv {
353     STACK_ALLOCATED();
354 
355    public:
AutoEnv(PageTestBase & test,AtomicString name,String value)356     AutoEnv(PageTestBase& test, AtomicString name, String value)
357         : document_(&test.GetDocument()), name_(name) {
358       EnsureEnvironmentVariables().SetVariable(name, value);
359     }
~AutoEnv()360     ~AutoEnv() { EnsureEnvironmentVariables().RemoveVariable(name_); }
361 
362    private:
EnsureEnvironmentVariables()363     DocumentStyleEnvironmentVariables& EnsureEnvironmentVariables() {
364       return document_->GetStyleEngine().EnsureEnvironmentVariables();
365     }
366 
367     Document* document_;
368     AtomicString name_;
369   };
370 
PropertyName(String name)371   CSSPropertyName PropertyName(String name) {
372     return *CSSPropertyName::From(GetDocument().GetExecutionContext(), name);
373   }
374 
CssTextAt(const HeapHashMap<CSSPropertyName,Member<const CSSValue>> & map,String name)375   String CssTextAt(
376       const HeapHashMap<CSSPropertyName, Member<const CSSValue>>& map,
377       String name) {
378     const CSSValue* value = map.at(PropertyName(name));
379     return value ? value->CssText() : g_null_atom;
380   }
381 };
382 
TEST_F(StyleCascadeTest,ApplySingle)383 TEST_F(StyleCascadeTest, ApplySingle) {
384   TestCascade cascade(GetDocument());
385   cascade.Add("width", "1px", CascadeOrigin::kUserAgent);
386   cascade.Add("width", "2px", CascadeOrigin::kAuthor);
387   cascade.Apply();
388 
389   EXPECT_EQ("2px", cascade.ComputedValue("width"));
390 }
391 
TEST_F(StyleCascadeTest,ApplyImportance)392 TEST_F(StyleCascadeTest, ApplyImportance) {
393   TestCascade cascade(GetDocument());
394   cascade.Add("width:1px !important", CascadeOrigin::kUserAgent);
395   cascade.Add("width:2px", CascadeOrigin::kAuthor);
396   cascade.Apply();
397 
398   EXPECT_EQ("1px", cascade.ComputedValue("width"));
399 }
400 
TEST_F(StyleCascadeTest,ApplyAll)401 TEST_F(StyleCascadeTest, ApplyAll) {
402   TestCascade cascade(GetDocument());
403   cascade.Add("width:1px", CascadeOrigin::kUserAgent);
404   cascade.Add("height:1px", CascadeOrigin::kUserAgent);
405   cascade.Add("all:initial", CascadeOrigin::kAuthor);
406   cascade.Apply();
407 
408   EXPECT_EQ("auto", cascade.ComputedValue("width"));
409   EXPECT_EQ("auto", cascade.ComputedValue("height"));
410 }
411 
TEST_F(StyleCascadeTest,ApplyAllImportance)412 TEST_F(StyleCascadeTest, ApplyAllImportance) {
413   TestCascade cascade(GetDocument());
414   cascade.Add("opacity:0.5", CascadeOrigin::kUserAgent);
415   cascade.Add("display:block !important", CascadeOrigin::kUserAgent);
416   cascade.Add("all:initial", CascadeOrigin::kAuthor);
417   cascade.Apply();
418 
419   EXPECT_EQ("1", cascade.ComputedValue("opacity"));
420   EXPECT_EQ("block", cascade.ComputedValue("display"));
421 }
422 
TEST_F(StyleCascadeTest,ApplyAllWithPhysicalLonghands)423 TEST_F(StyleCascadeTest, ApplyAllWithPhysicalLonghands) {
424   TestCascade cascade(GetDocument());
425   cascade.Add("width:1px", CascadeOrigin::kUserAgent);
426   cascade.Add("height:1px !important", CascadeOrigin::kUserAgent);
427   cascade.Add("all:initial", CascadeOrigin::kAuthor);
428   cascade.Apply();
429   EXPECT_EQ("auto", cascade.ComputedValue("width"));
430   EXPECT_EQ("1px", cascade.ComputedValue("height"));
431 }
432 
TEST_F(StyleCascadeTest,ApplyCustomProperty)433 TEST_F(StyleCascadeTest, ApplyCustomProperty) {
434   TestCascade cascade(GetDocument());
435   cascade.Add("--x", " 10px ");
436   cascade.Add("--y", "nope");
437   cascade.Apply();
438 
439   EXPECT_EQ(" 10px ", cascade.ComputedValue("--x"));
440   EXPECT_EQ("nope", cascade.ComputedValue("--y"));
441 }
442 
TEST_F(StyleCascadeTest,ApplyGenerations)443 TEST_F(StyleCascadeTest, ApplyGenerations) {
444   TestCascade cascade(GetDocument());
445 
446   cascade.Add("--x:10px");
447   cascade.Add("width:20px");
448   cascade.Apply();
449   EXPECT_EQ("10px", cascade.ComputedValue("--x"));
450   EXPECT_EQ("20px", cascade.ComputedValue("width"));
451 
452   cascade.State().StyleRef().SetWidth(Length::Auto());
453   cascade.State().StyleRef().SetVariableData("--x", nullptr, true);
454   EXPECT_EQ(g_null_atom, cascade.ComputedValue("--x"));
455   EXPECT_EQ("auto", cascade.ComputedValue("width"));
456 
457   // Apply again
458   cascade.Apply();
459   EXPECT_EQ("10px", cascade.ComputedValue("--x"));
460   EXPECT_EQ("20px", cascade.ComputedValue("width"));
461 }
462 
TEST_F(StyleCascadeTest,ApplyCustomPropertyVar)463 TEST_F(StyleCascadeTest, ApplyCustomPropertyVar) {
464   // Apply --x first.
465   {
466     TestCascade cascade(GetDocument());
467     cascade.Add("--x", "yes and var(--y)");
468     cascade.Add("--y", "no");
469     cascade.Apply();
470 
471     EXPECT_EQ("yes and no", cascade.ComputedValue("--x"));
472     EXPECT_EQ("no", cascade.ComputedValue("--y"));
473   }
474 
475   // Apply --y first.
476   {
477     TestCascade cascade(GetDocument());
478     cascade.Add("--y", "no");
479     cascade.Add("--x", "yes and var(--y)");
480     cascade.Apply();
481 
482     EXPECT_EQ("yes and no", cascade.ComputedValue("--x"));
483     EXPECT_EQ("no", cascade.ComputedValue("--y"));
484   }
485 }
486 
TEST_F(StyleCascadeTest,InvalidVarReferenceCauseInvalidVariable)487 TEST_F(StyleCascadeTest, InvalidVarReferenceCauseInvalidVariable) {
488   TestCascade cascade(GetDocument());
489   cascade.Add("--x", "nope var(--y)");
490   cascade.Apply();
491 
492   EXPECT_EQ(g_null_atom, cascade.ComputedValue("--x"));
493 }
494 
TEST_F(StyleCascadeTest,ApplyCustomPropertyFallback)495 TEST_F(StyleCascadeTest, ApplyCustomPropertyFallback) {
496   TestCascade cascade(GetDocument());
497   cascade.Add("--x", "yes and var(--y,no)");
498   cascade.Apply();
499 
500   EXPECT_EQ("yes and no", cascade.ComputedValue("--x"));
501 }
502 
TEST_F(StyleCascadeTest,RegisteredPropertyFallback)503 TEST_F(StyleCascadeTest, RegisteredPropertyFallback) {
504   RegisterProperty(GetDocument(), "--x", "<length>", "0px", false);
505 
506   TestCascade cascade(GetDocument());
507   cascade.Add("--x", "var(--y,10px)");
508   cascade.Apply();
509 
510   EXPECT_EQ("10px", cascade.ComputedValue("--x"));
511 }
512 
TEST_F(StyleCascadeTest,RegisteredPropertyFallbackValidation)513 TEST_F(StyleCascadeTest, RegisteredPropertyFallbackValidation) {
514   RegisterProperty(GetDocument(), "--x", "<length>", "0px", false);
515 
516   TestCascade cascade(GetDocument());
517   cascade.Add("--x", "10px");
518   cascade.Add("--y", "var(--x,red)");  // Fallback must be valid <length>.
519   cascade.Add("--z", "var(--y,pass)");
520   cascade.Apply();
521 
522   EXPECT_EQ("pass", cascade.ComputedValue("--z"));
523 }
524 
TEST_F(StyleCascadeTest,VarInFallback)525 TEST_F(StyleCascadeTest, VarInFallback) {
526   TestCascade cascade(GetDocument());
527   cascade.Add("--x", "one var(--z,two var(--y))");
528   cascade.Add("--y", "three");
529   cascade.Apply();
530 
531   EXPECT_EQ("one two three", cascade.ComputedValue("--x"));
532 }
533 
TEST_F(StyleCascadeTest,VarReferenceInNormalProperty)534 TEST_F(StyleCascadeTest, VarReferenceInNormalProperty) {
535   TestCascade cascade(GetDocument());
536   cascade.Add("--x", "10px");
537   cascade.Add("width", "var(--x)");
538   cascade.Apply();
539 
540   EXPECT_EQ("10px", cascade.ComputedValue("width"));
541 }
542 
TEST_F(StyleCascadeTest,MultipleVarRefs)543 TEST_F(StyleCascadeTest, MultipleVarRefs) {
544   TestCascade cascade(GetDocument());
545   cascade.Add("--x", "var(--y) bar var(--y)");
546   cascade.Add("--y", "foo");
547   cascade.Apply();
548 
549   EXPECT_EQ("foo bar foo", cascade.ComputedValue("--x"));
550 }
551 
TEST_F(StyleCascadeTest,RegisteredPropertyComputedValue)552 TEST_F(StyleCascadeTest, RegisteredPropertyComputedValue) {
553   RegisterProperty(GetDocument(), "--x", "<length>", "0px", false);
554 
555   TestCascade cascade(GetDocument());
556   cascade.Add("--x", "1in");
557   cascade.Apply();
558 
559   EXPECT_EQ("96px", cascade.ComputedValue("--x"));
560 }
561 
TEST_F(StyleCascadeTest,RegisteredPropertySyntaxErrorCausesInitial)562 TEST_F(StyleCascadeTest, RegisteredPropertySyntaxErrorCausesInitial) {
563   RegisterProperty(GetDocument(), "--x", "<length>", "10px", false);
564 
565   TestCascade cascade(GetDocument());
566   cascade.Add("--x", "#fefefe");
567   cascade.Add("--y", "var(--x)");
568   cascade.Apply();
569 
570   EXPECT_EQ("10px", cascade.ComputedValue("--x"));
571   EXPECT_EQ("10px", cascade.ComputedValue("--y"));
572 }
573 
TEST_F(StyleCascadeTest,RegisteredPropertySubstitution)574 TEST_F(StyleCascadeTest, RegisteredPropertySubstitution) {
575   RegisterProperty(GetDocument(), "--x", "<length>", "0px", false);
576 
577   TestCascade cascade(GetDocument());
578   cascade.Add("--x", "1in");
579   cascade.Add("--y", "var(--x)");
580   cascade.Apply();
581 
582   EXPECT_EQ("96px", cascade.ComputedValue("--y"));
583 }
584 
TEST_F(StyleCascadeTest,RegisteredPropertyChain)585 TEST_F(StyleCascadeTest, RegisteredPropertyChain) {
586   RegisterProperty(GetDocument(), "--x", "<length>", "0px", false);
587   RegisterProperty(GetDocument(), "--z", "<length>", "0px", false);
588 
589   TestCascade cascade(GetDocument());
590   cascade.Add("--x", "1in");
591   cascade.Add("--y", "var(--x)");
592   cascade.Add("--z", "calc(var(--y) + 1in)");
593   cascade.Apply();
594 
595   EXPECT_EQ("96px", cascade.ComputedValue("--x"));
596   EXPECT_EQ("96px", cascade.ComputedValue("--y"));
597   EXPECT_EQ("192px", cascade.ComputedValue("--z"));
598 }
599 
TEST_F(StyleCascadeTest,BasicShorthand)600 TEST_F(StyleCascadeTest, BasicShorthand) {
601   TestCascade cascade(GetDocument());
602   cascade.Add("margin", "1px 2px 3px 4px");
603   cascade.Apply();
604 
605   EXPECT_EQ("1px", cascade.ComputedValue("margin-top"));
606   EXPECT_EQ("2px", cascade.ComputedValue("margin-right"));
607   EXPECT_EQ("3px", cascade.ComputedValue("margin-bottom"));
608   EXPECT_EQ("4px", cascade.ComputedValue("margin-left"));
609 }
610 
TEST_F(StyleCascadeTest,BasicVarShorthand)611 TEST_F(StyleCascadeTest, BasicVarShorthand) {
612   TestCascade cascade(GetDocument());
613   cascade.Add("margin", "1px var(--x) 3px 4px");
614   cascade.Add("--x", "2px");
615   cascade.Apply();
616 
617   EXPECT_EQ("1px", cascade.ComputedValue("margin-top"));
618   EXPECT_EQ("2px", cascade.ComputedValue("margin-right"));
619   EXPECT_EQ("3px", cascade.ComputedValue("margin-bottom"));
620   EXPECT_EQ("4px", cascade.ComputedValue("margin-left"));
621 }
622 
TEST_F(StyleCascadeTest,ApplyingPendingSubstitutionFirst)623 TEST_F(StyleCascadeTest, ApplyingPendingSubstitutionFirst) {
624   TestCascade cascade(GetDocument());
625   cascade.Add("margin", "1px var(--x) 3px 4px");
626   cascade.Add("--x", "2px");
627   cascade.Add("margin-right", "5px");
628   cascade.Apply();
629 
630   EXPECT_EQ("1px", cascade.ComputedValue("margin-top"));
631   EXPECT_EQ("5px", cascade.ComputedValue("margin-right"));
632   EXPECT_EQ("3px", cascade.ComputedValue("margin-bottom"));
633   EXPECT_EQ("4px", cascade.ComputedValue("margin-left"));
634 }
635 
TEST_F(StyleCascadeTest,ApplyingPendingSubstitutionLast)636 TEST_F(StyleCascadeTest, ApplyingPendingSubstitutionLast) {
637   TestCascade cascade(GetDocument());
638   cascade.Add("margin-right", "5px");
639   cascade.Add("margin", "1px var(--x) 3px 4px");
640   cascade.Add("--x", "2px");
641   cascade.Apply();
642 
643   EXPECT_EQ("1px", cascade.ComputedValue("margin-top"));
644   EXPECT_EQ("2px", cascade.ComputedValue("margin-right"));
645   EXPECT_EQ("3px", cascade.ComputedValue("margin-bottom"));
646   EXPECT_EQ("4px", cascade.ComputedValue("margin-left"));
647 }
648 
TEST_F(StyleCascadeTest,PendingSubstitutionInLogicalShorthand)649 TEST_F(StyleCascadeTest, PendingSubstitutionInLogicalShorthand) {
650   TestCascade cascade(GetDocument());
651   cascade.Add("margin-inline:var(--x)");
652   cascade.Add("--x:10px 20px");
653   cascade.Add("direction:rtl");
654   cascade.Apply();
655 
656   EXPECT_EQ("20px", cascade.ComputedValue("margin-left"));
657   EXPECT_EQ("10px", cascade.ComputedValue("margin-right"));
658 }
659 
TEST_F(StyleCascadeTest,DetectCycleByName)660 TEST_F(StyleCascadeTest, DetectCycleByName) {
661   TestCascade cascade(GetDocument());
662   TestCascadeResolver resolver;
663 
664   // Two different CustomProperty instances with the same name:
665   CustomProperty a1("--a", GetDocument());
666   CustomProperty a2("--a", GetDocument());
667 
668   {
669     TestCascadeAutoLock lock(a1, resolver);
670     EXPECT_FALSE(resolver.InCycle());
671 
672     // This should still be detected as a cycle, even though it's not the same
673     // CustomProperty instance.
674     EXPECT_TRUE(resolver.DetectCycle(a2));
675     EXPECT_TRUE(resolver.InCycle());
676   }
677   EXPECT_FALSE(resolver.InCycle());
678 }
679 
TEST_F(StyleCascadeTest,ResolverDetectCycle)680 TEST_F(StyleCascadeTest, ResolverDetectCycle) {
681   TestCascade cascade(GetDocument());
682   TestCascadeResolver resolver;
683 
684   CustomProperty a("--a", GetDocument());
685   CustomProperty b("--b", GetDocument());
686   CustomProperty c("--c", GetDocument());
687 
688   {
689     TestCascadeAutoLock lock(a, resolver);
690     EXPECT_FALSE(resolver.InCycle());
691     {
692       TestCascadeAutoLock lock(b, resolver);
693       EXPECT_FALSE(resolver.InCycle());
694       {
695         TestCascadeAutoLock lock(c, resolver);
696         EXPECT_FALSE(resolver.InCycle());
697 
698         EXPECT_TRUE(resolver.DetectCycle(a));
699         EXPECT_TRUE(resolver.InCycle());
700       }
701       EXPECT_TRUE(resolver.InCycle());
702     }
703     EXPECT_TRUE(resolver.InCycle());
704   }
705   EXPECT_FALSE(resolver.InCycle());
706 }
707 
TEST_F(StyleCascadeTest,ResolverDetectNoCycle)708 TEST_F(StyleCascadeTest, ResolverDetectNoCycle) {
709   TestCascade cascade(GetDocument());
710   TestCascadeResolver resolver;
711 
712   CustomProperty a("--a", GetDocument());
713   CustomProperty b("--b", GetDocument());
714   CustomProperty c("--c", GetDocument());
715   CustomProperty x("--x", GetDocument());
716 
717   {
718     TestCascadeAutoLock lock(a, resolver);
719     EXPECT_FALSE(resolver.InCycle());
720     {
721       TestCascadeAutoLock lock(b, resolver);
722       EXPECT_FALSE(resolver.InCycle());
723       {
724         TestCascadeAutoLock lock(c, resolver);
725         EXPECT_FALSE(resolver.InCycle());
726 
727         EXPECT_FALSE(resolver.DetectCycle(x));
728         EXPECT_FALSE(resolver.InCycle());
729       }
730       EXPECT_FALSE(resolver.InCycle());
731     }
732     EXPECT_FALSE(resolver.InCycle());
733   }
734   EXPECT_FALSE(resolver.InCycle());
735 }
736 
TEST_F(StyleCascadeTest,ResolverDetectCycleSelf)737 TEST_F(StyleCascadeTest, ResolverDetectCycleSelf) {
738   TestCascade cascade(GetDocument());
739   TestCascadeResolver resolver;
740 
741   CustomProperty a("--a", GetDocument());
742 
743   {
744     TestCascadeAutoLock lock(a, resolver);
745     EXPECT_FALSE(resolver.InCycle());
746 
747     EXPECT_TRUE(resolver.DetectCycle(a));
748     EXPECT_TRUE(resolver.InCycle());
749   }
750   EXPECT_FALSE(resolver.InCycle());
751 }
752 
TEST_F(StyleCascadeTest,ResolverDetectMultiCycle)753 TEST_F(StyleCascadeTest, ResolverDetectMultiCycle) {
754   using AutoLock = TestCascadeAutoLock;
755 
756   TestCascade cascade(GetDocument());
757   TestCascadeResolver resolver;
758 
759   CustomProperty a("--a", GetDocument());
760   CustomProperty b("--b", GetDocument());
761   CustomProperty c("--c", GetDocument());
762   CustomProperty d("--d", GetDocument());
763 
764   {
765     AutoLock lock(a, resolver);
766     EXPECT_FALSE(resolver.InCycle());
767     {
768       AutoLock lock(b, resolver);
769       EXPECT_FALSE(resolver.InCycle());
770       {
771         AutoLock lock(c, resolver);
772         EXPECT_FALSE(resolver.InCycle());
773         {
774           AutoLock lock(d, resolver);
775           EXPECT_FALSE(resolver.InCycle());
776 
777           // Cycle 1 (big cycle):
778           EXPECT_TRUE(resolver.DetectCycle(b));
779           EXPECT_TRUE(resolver.InCycle());
780           EXPECT_EQ(1u, resolver.CycleDepth());
781 
782           // Cycle 2 (small cycle):
783           EXPECT_TRUE(resolver.DetectCycle(c));
784           EXPECT_TRUE(resolver.InCycle());
785           EXPECT_EQ(1u, resolver.CycleDepth());
786         }
787       }
788       EXPECT_TRUE(resolver.InCycle());
789     }
790     EXPECT_FALSE(resolver.InCycle());
791   }
792   EXPECT_FALSE(resolver.InCycle());
793 }
794 
TEST_F(StyleCascadeTest,ResolverDetectMultiCycleReverse)795 TEST_F(StyleCascadeTest, ResolverDetectMultiCycleReverse) {
796   using AutoLock = TestCascadeAutoLock;
797 
798   TestCascade cascade(GetDocument());
799   TestCascadeResolver resolver;
800 
801   CustomProperty a("--a", GetDocument());
802   CustomProperty b("--b", GetDocument());
803   CustomProperty c("--c", GetDocument());
804   CustomProperty d("--d", GetDocument());
805 
806   {
807     AutoLock lock(a, resolver);
808     EXPECT_FALSE(resolver.InCycle());
809     {
810       AutoLock lock(b, resolver);
811       EXPECT_FALSE(resolver.InCycle());
812       {
813         AutoLock lock(c, resolver);
814         EXPECT_FALSE(resolver.InCycle());
815         {
816           AutoLock lock(d, resolver);
817           EXPECT_FALSE(resolver.InCycle());
818 
819           // Cycle 1 (small cycle):
820           EXPECT_TRUE(resolver.DetectCycle(c));
821           EXPECT_TRUE(resolver.InCycle());
822           EXPECT_EQ(2u, resolver.CycleDepth());
823 
824           // Cycle 2 (big cycle):
825           EXPECT_TRUE(resolver.DetectCycle(b));
826           EXPECT_TRUE(resolver.InCycle());
827           EXPECT_EQ(1u, resolver.CycleDepth());
828         }
829       }
830       EXPECT_TRUE(resolver.InCycle());
831     }
832     EXPECT_FALSE(resolver.InCycle());
833   }
834   EXPECT_FALSE(resolver.InCycle());
835 }
836 
TEST_F(StyleCascadeTest,ResolverMarkApplied)837 TEST_F(StyleCascadeTest, ResolverMarkApplied) {
838   TestCascadeResolver resolver(2);
839 
840   CascadePriority priority(CascadeOrigin::kAuthor);
841   EXPECT_EQ(0, priority.GetGeneration());
842 
843   resolver.MarkApplied(&priority);
844   EXPECT_EQ(2, priority.GetGeneration());
845 
846   // Mark a second time to verify observation of the same generation.
847   resolver.MarkApplied(&priority);
848   EXPECT_EQ(2, priority.GetGeneration());
849 }
850 
TEST_F(StyleCascadeTest,CurrentProperty)851 TEST_F(StyleCascadeTest, CurrentProperty) {
852   using AutoLock = TestCascadeAutoLock;
853 
854   TestCascade cascade(GetDocument());
855   TestCascadeResolver resolver;
856 
857   CustomProperty a("--a", GetDocument());
858   CustomProperty b("--b", GetDocument());
859   CustomProperty c("--c", GetDocument());
860 
861   EXPECT_FALSE(resolver.CurrentProperty());
862   {
863     AutoLock lock(a, resolver);
864     EXPECT_EQ(&a, resolver.CurrentProperty());
865     {
866       AutoLock lock(b, resolver);
867       EXPECT_EQ(&b, resolver.CurrentProperty());
868       {
869         AutoLock lock(c, resolver);
870         EXPECT_EQ(&c, resolver.CurrentProperty());
871       }
872       EXPECT_EQ(&b, resolver.CurrentProperty());
873     }
874     EXPECT_EQ(&a, resolver.CurrentProperty());
875   }
876   EXPECT_FALSE(resolver.CurrentProperty());
877 }
878 
TEST_F(StyleCascadeTest,ResolverMarkUnapplied)879 TEST_F(StyleCascadeTest, ResolverMarkUnapplied) {
880   TestCascadeResolver resolver(7);
881 
882   CascadePriority priority(CascadeOrigin::kAuthor);
883   EXPECT_EQ(0, priority.GetGeneration());
884 
885   resolver.MarkApplied(&priority);
886   EXPECT_EQ(7, priority.GetGeneration());
887 
888   resolver.MarkUnapplied(&priority);
889   EXPECT_EQ(0, priority.GetGeneration());
890 
891   // Mark a second time to verify observation of the same generation.
892   resolver.MarkUnapplied(&priority);
893   EXPECT_EQ(0, priority.GetGeneration());
894 }
895 
TEST_F(StyleCascadeTest,BasicCycle)896 TEST_F(StyleCascadeTest, BasicCycle) {
897   TestCascade cascade(GetDocument());
898   cascade.Add("--a", "foo");
899   cascade.Add("--b", "bar");
900   cascade.Apply();
901 
902   EXPECT_EQ("foo", cascade.ComputedValue("--a"));
903   EXPECT_EQ("bar", cascade.ComputedValue("--b"));
904 
905   cascade.Reset();
906   cascade.Add("--a", "var(--b)");
907   cascade.Add("--b", "var(--a)");
908   cascade.Apply();
909 
910   EXPECT_FALSE(cascade.ComputedValue("--a"));
911   EXPECT_FALSE(cascade.ComputedValue("--b"));
912 }
913 
TEST_F(StyleCascadeTest,SelfCycle)914 TEST_F(StyleCascadeTest, SelfCycle) {
915   TestCascade cascade(GetDocument());
916   cascade.Add("--a", "foo");
917   cascade.Apply();
918 
919   EXPECT_EQ("foo", cascade.ComputedValue("--a"));
920 
921   cascade.Reset();
922   cascade.Add("--a", "var(--a)");
923   cascade.Apply();
924 
925   EXPECT_FALSE(cascade.ComputedValue("--a"));
926 }
927 
TEST_F(StyleCascadeTest,SelfCycleInFallback)928 TEST_F(StyleCascadeTest, SelfCycleInFallback) {
929   TestCascade cascade(GetDocument());
930   cascade.Add("--a", "var(--x, var(--a))");
931   cascade.Apply();
932 
933   EXPECT_FALSE(cascade.ComputedValue("--a"));
934 }
935 
TEST_F(StyleCascadeTest,SelfCycleInUnusedFallback)936 TEST_F(StyleCascadeTest, SelfCycleInUnusedFallback) {
937   TestCascade cascade(GetDocument());
938   cascade.Add("--a", "var(--b, var(--a))");
939   cascade.Add("--b", "10px");
940   cascade.Apply();
941 
942   EXPECT_FALSE(cascade.ComputedValue("--a"));
943   EXPECT_EQ("10px", cascade.ComputedValue("--b"));
944 }
945 
TEST_F(StyleCascadeTest,LongCycle)946 TEST_F(StyleCascadeTest, LongCycle) {
947   TestCascade cascade(GetDocument());
948   cascade.Add("--a", "var(--b)");
949   cascade.Add("--b", "var(--c)");
950   cascade.Add("--c", "var(--d)");
951   cascade.Add("--d", "var(--e)");
952   cascade.Add("--e", "var(--a)");
953   cascade.Apply();
954 
955   EXPECT_FALSE(cascade.ComputedValue("--a"));
956   EXPECT_FALSE(cascade.ComputedValue("--b"));
957   EXPECT_FALSE(cascade.ComputedValue("--c"));
958   EXPECT_FALSE(cascade.ComputedValue("--d"));
959   EXPECT_FALSE(cascade.ComputedValue("--e"));
960 }
961 
TEST_F(StyleCascadeTest,PartialCycle)962 TEST_F(StyleCascadeTest, PartialCycle) {
963   TestCascade cascade(GetDocument());
964   cascade.Add("--a", "var(--b)");
965   cascade.Add("--b", "var(--a)");
966   cascade.Add("--c", "bar var(--d) var(--a)");
967   cascade.Add("--d", "foo");
968   cascade.Apply();
969 
970   EXPECT_FALSE(cascade.ComputedValue("--a"));
971   EXPECT_FALSE(cascade.ComputedValue("--b"));
972   EXPECT_FALSE(cascade.ComputedValue("--c"));
973   EXPECT_EQ("foo", cascade.ComputedValue("--d"));
974 }
975 
TEST_F(StyleCascadeTest,VarCycleViaFallback)976 TEST_F(StyleCascadeTest, VarCycleViaFallback) {
977   TestCascade cascade(GetDocument());
978   cascade.Add("--a", "var(--b)");
979   cascade.Add("--b", "var(--x, var(--a))");
980   cascade.Add("--c", "var(--a)");
981   cascade.Apply();
982 
983   EXPECT_FALSE(cascade.ComputedValue("--a"));
984   EXPECT_FALSE(cascade.ComputedValue("--b"));
985   EXPECT_FALSE(cascade.ComputedValue("--c"));
986 }
987 
TEST_F(StyleCascadeTest,FallbackTriggeredByCycle)988 TEST_F(StyleCascadeTest, FallbackTriggeredByCycle) {
989   TestCascade cascade(GetDocument());
990   cascade.Add("--a", "var(--b)");
991   cascade.Add("--b", "var(--a)");
992   cascade.Add("--c", "var(--a,foo)");
993   cascade.Apply();
994 
995   EXPECT_FALSE(cascade.ComputedValue("--a"));
996   EXPECT_FALSE(cascade.ComputedValue("--b"));
997   EXPECT_EQ("foo", cascade.ComputedValue("--c"));
998 }
999 
TEST_F(StyleCascadeTest,RegisteredCycle)1000 TEST_F(StyleCascadeTest, RegisteredCycle) {
1001   RegisterProperty(GetDocument(), "--a", "<length>", "0px", false);
1002   RegisterProperty(GetDocument(), "--b", "<length>", "0px", false);
1003 
1004   TestCascade cascade(GetDocument());
1005   cascade.Add("--a", "var(--b)");
1006   cascade.Add("--b", "var(--a)");
1007   cascade.Apply();
1008 
1009   EXPECT_FALSE(cascade.ComputedValue("--a"));
1010   EXPECT_FALSE(cascade.ComputedValue("--b"));
1011 }
1012 
TEST_F(StyleCascadeTest,PartiallyRegisteredCycle)1013 TEST_F(StyleCascadeTest, PartiallyRegisteredCycle) {
1014   RegisterProperty(GetDocument(), "--a", "<length>", "0px", false);
1015 
1016   TestCascade cascade(GetDocument());
1017   cascade.Add("--a", "var(--b)");
1018   cascade.Add("--b", "var(--a)");
1019   cascade.Apply();
1020 
1021   EXPECT_FALSE(cascade.ComputedValue("--a"));
1022   EXPECT_FALSE(cascade.ComputedValue("--b"));
1023 }
1024 
TEST_F(StyleCascadeTest,FallbackTriggeredByRegisteredCycle)1025 TEST_F(StyleCascadeTest, FallbackTriggeredByRegisteredCycle) {
1026   RegisterProperty(GetDocument(), "--a", "<length>", "0px", false);
1027   RegisterProperty(GetDocument(), "--b", "<length>", "0px", false);
1028 
1029   TestCascade cascade(GetDocument());
1030   // Cycle:
1031   cascade.Add("--a", "var(--b)");
1032   cascade.Add("--b", "var(--a)");
1033   // References to cycle:
1034   cascade.Add("--c", "var(--a,1px)");
1035   cascade.Add("--d", "var(--b,2px)");
1036   cascade.Apply();
1037 
1038   EXPECT_FALSE(cascade.ComputedValue("--a"));
1039   EXPECT_FALSE(cascade.ComputedValue("--b"));
1040   EXPECT_EQ("1px", cascade.ComputedValue("--c"));
1041   EXPECT_EQ("2px", cascade.ComputedValue("--d"));
1042 }
1043 
TEST_F(StyleCascadeTest,CycleStillInvalidWithFallback)1044 TEST_F(StyleCascadeTest, CycleStillInvalidWithFallback) {
1045   TestCascade cascade(GetDocument());
1046   // Cycle:
1047   cascade.Add("--a", "var(--b,red)");
1048   cascade.Add("--b", "var(--a,red)");
1049   // References to cycle:
1050   cascade.Add("--c", "var(--a,green)");
1051   cascade.Add("--d", "var(--b,green)");
1052   cascade.Apply();
1053 
1054   EXPECT_FALSE(cascade.ComputedValue("--a"));
1055   EXPECT_FALSE(cascade.ComputedValue("--b"));
1056   EXPECT_EQ("green", cascade.ComputedValue("--c"));
1057   EXPECT_EQ("green", cascade.ComputedValue("--d"));
1058 }
1059 
TEST_F(StyleCascadeTest,CycleInFallbackStillInvalid)1060 TEST_F(StyleCascadeTest, CycleInFallbackStillInvalid) {
1061   TestCascade cascade(GetDocument());
1062   // Cycle:
1063   cascade.Add("--a", "var(--b,red)");
1064   cascade.Add("--b", "var(--x,var(--a))");
1065   // References to cycle:
1066   cascade.Add("--c", "var(--a,green)");
1067   cascade.Add("--d", "var(--b,green)");
1068   cascade.Apply();
1069 
1070   EXPECT_FALSE(cascade.ComputedValue("--a"));
1071   EXPECT_FALSE(cascade.ComputedValue("--b"));
1072   EXPECT_EQ("green", cascade.ComputedValue("--c"));
1073   EXPECT_EQ("green", cascade.ComputedValue("--d"));
1074 }
1075 
TEST_F(StyleCascadeTest,CycleMultiple)1076 TEST_F(StyleCascadeTest, CycleMultiple) {
1077   TestCascade cascade(GetDocument());
1078   // Cycle:
1079   cascade.Add("--a", "var(--c, red)");
1080   cascade.Add("--b", "var(--c, red)");
1081   cascade.Add("--c", "var(--a, blue) var(--b, blue)");
1082   // References to cycle:
1083   cascade.Add("--d", "var(--a,green)");
1084   cascade.Add("--e", "var(--b,green)");
1085   cascade.Add("--f", "var(--c,green)");
1086   cascade.Apply();
1087 
1088   EXPECT_FALSE(cascade.ComputedValue("--a"));
1089   EXPECT_FALSE(cascade.ComputedValue("--b"));
1090   EXPECT_FALSE(cascade.ComputedValue("--c"));
1091   EXPECT_EQ("green", cascade.ComputedValue("--d"));
1092   EXPECT_EQ("green", cascade.ComputedValue("--e"));
1093   EXPECT_EQ("green", cascade.ComputedValue("--f"));
1094 }
1095 
TEST_F(StyleCascadeTest,CycleMultipleFallback)1096 TEST_F(StyleCascadeTest, CycleMultipleFallback) {
1097   TestCascade cascade(GetDocument());
1098   // Cycle:
1099   cascade.Add("--a", "var(--b, red)");
1100   cascade.Add("--b", "var(--a, var(--c, red))");
1101   cascade.Add("--c", "var(--b, red)");
1102   // References to cycle:
1103   cascade.Add("--d", "var(--a,green)");
1104   cascade.Add("--e", "var(--b,green)");
1105   cascade.Add("--f", "var(--c,green)");
1106   cascade.Apply();
1107 
1108   EXPECT_FALSE(cascade.ComputedValue("--a"));
1109   EXPECT_FALSE(cascade.ComputedValue("--b"));
1110   EXPECT_FALSE(cascade.ComputedValue("--c"));
1111   EXPECT_EQ("green", cascade.ComputedValue("--d"));
1112   EXPECT_EQ("green", cascade.ComputedValue("--e"));
1113   EXPECT_EQ("green", cascade.ComputedValue("--f"));
1114 }
1115 
TEST_F(StyleCascadeTest,CycleMultipleUnusedFallback)1116 TEST_F(StyleCascadeTest, CycleMultipleUnusedFallback) {
1117   TestCascade cascade(GetDocument());
1118   cascade.Add("--a", "red");
1119   // Cycle:
1120   cascade.Add("--b", "var(--c, red)");
1121   cascade.Add("--c", "var(--a, var(--b, red) var(--d, red))");
1122   cascade.Add("--d", "var(--c, red)");
1123   // References to cycle:
1124   cascade.Add("--e", "var(--b,green)");
1125   cascade.Add("--f", "var(--c,green)");
1126   cascade.Add("--g", "var(--d,green)");
1127   cascade.Apply();
1128 
1129   EXPECT_FALSE(cascade.ComputedValue("--b"));
1130   EXPECT_FALSE(cascade.ComputedValue("--c"));
1131   EXPECT_FALSE(cascade.ComputedValue("--d"));
1132   EXPECT_EQ("green", cascade.ComputedValue("--e"));
1133   EXPECT_EQ("green", cascade.ComputedValue("--f"));
1134   EXPECT_EQ("green", cascade.ComputedValue("--g"));
1135 }
1136 
TEST_F(StyleCascadeTest,CycleReferencedFromStandardProperty)1137 TEST_F(StyleCascadeTest, CycleReferencedFromStandardProperty) {
1138   TestCascade cascade(GetDocument());
1139   cascade.Add("--a", "var(--b)");
1140   cascade.Add("--b", "var(--a)");
1141   cascade.Add("color:var(--a,green)");
1142   cascade.Apply();
1143 
1144   EXPECT_FALSE(cascade.ComputedValue("--a"));
1145   EXPECT_FALSE(cascade.ComputedValue("--b"));
1146   EXPECT_EQ("rgb(0, 128, 0)", cascade.ComputedValue("color"));
1147 }
1148 
TEST_F(StyleCascadeTest,CycleReferencedFromShorthand)1149 TEST_F(StyleCascadeTest, CycleReferencedFromShorthand) {
1150   TestCascade cascade(GetDocument());
1151   cascade.Add("--a", "var(--b)");
1152   cascade.Add("--b", "var(--a)");
1153   cascade.Add("background", "var(--a,green)");
1154   cascade.Apply();
1155 
1156   EXPECT_FALSE(cascade.ComputedValue("--a"));
1157   EXPECT_FALSE(cascade.ComputedValue("--b"));
1158   EXPECT_EQ("rgb(0, 128, 0)", cascade.ComputedValue("background-color"));
1159 }
1160 
TEST_F(StyleCascadeTest,EmUnit)1161 TEST_F(StyleCascadeTest, EmUnit) {
1162   TestCascade cascade(GetDocument());
1163   cascade.Add("font-size", "10px");
1164   cascade.Add("width", "10em");
1165   cascade.Apply();
1166 
1167   EXPECT_EQ("100px", cascade.ComputedValue("width"));
1168 }
1169 
TEST_F(StyleCascadeTest,EmUnitCustomProperty)1170 TEST_F(StyleCascadeTest, EmUnitCustomProperty) {
1171   RegisterProperty(GetDocument(), "--x", "<length>", "0px", false);
1172 
1173   TestCascade cascade(GetDocument());
1174   cascade.Add("font-size", "10px");
1175   cascade.Add("--x", "10em");
1176   cascade.Apply();
1177 
1178   EXPECT_EQ("100px", cascade.ComputedValue("--x"));
1179 }
1180 
TEST_F(StyleCascadeTest,EmUnitNonCycle)1181 TEST_F(StyleCascadeTest, EmUnitNonCycle) {
1182   TestCascade parent(GetDocument());
1183   parent.Add("font-size", "10px");
1184   parent.Apply();
1185 
1186   TestCascade cascade(GetDocument());
1187   cascade.InheritFrom(parent.TakeStyle());
1188   cascade.Add("font-size", "var(--x)");
1189   cascade.Add("--x", "10em");
1190   cascade.Apply();
1191 
1192   // Note: Only registered properties can have cycles with font-size.
1193   EXPECT_EQ("100px", cascade.ComputedValue("font-size"));
1194 }
1195 
TEST_F(StyleCascadeTest,EmUnitCycle)1196 TEST_F(StyleCascadeTest, EmUnitCycle) {
1197   RegisterProperty(GetDocument(), "--x", "<length>", "0px", false);
1198 
1199   TestCascade cascade(GetDocument());
1200   cascade.Add("font-size", "var(--x)");
1201   cascade.Add("--x", "10em");
1202   cascade.Apply();
1203 
1204   EXPECT_FALSE(cascade.ComputedValue("--x"));
1205 }
1206 
TEST_F(StyleCascadeTest,SubstitutingEmCycles)1207 TEST_F(StyleCascadeTest, SubstitutingEmCycles) {
1208   RegisterProperty(GetDocument(), "--x", "<length>", "0px", false);
1209 
1210   TestCascade cascade(GetDocument());
1211   cascade.Add("font-size", "var(--x)");
1212   cascade.Add("--x", "10em");
1213   cascade.Add("--y", "var(--x)");
1214   cascade.Add("--z", "var(--x,1px)");
1215   cascade.Apply();
1216 
1217   EXPECT_FALSE(cascade.ComputedValue("--y"));
1218   EXPECT_EQ("1px", cascade.ComputedValue("--z"));
1219 }
1220 
TEST_F(StyleCascadeTest,RemUnit)1221 TEST_F(StyleCascadeTest, RemUnit) {
1222   SetRootFont("10px");
1223   UpdateAllLifecyclePhasesForTest();
1224 
1225   TestCascade cascade(GetDocument());
1226   cascade.Add("width", "10rem");
1227   cascade.Apply();
1228 
1229   EXPECT_EQ("100px", cascade.ComputedValue("width"));
1230 }
1231 
TEST_F(StyleCascadeTest,RemUnitCustomProperty)1232 TEST_F(StyleCascadeTest, RemUnitCustomProperty) {
1233   RegisterProperty(GetDocument(), "--x", "<length>", "0px", false);
1234 
1235   SetRootFont("10px");
1236   UpdateAllLifecyclePhasesForTest();
1237 
1238   TestCascade cascade(GetDocument());
1239   cascade.Add("--x", "10rem");
1240   cascade.Apply();
1241 
1242   EXPECT_EQ("100px", cascade.ComputedValue("--x"));
1243 }
1244 
TEST_F(StyleCascadeTest,RemUnitInFontSize)1245 TEST_F(StyleCascadeTest, RemUnitInFontSize) {
1246   RegisterProperty(GetDocument(), "--x", "<length>", "0px", false);
1247 
1248   SetRootFont("10px");
1249   UpdateAllLifecyclePhasesForTest();
1250 
1251   TestCascade cascade(GetDocument());
1252   cascade.Add("font-size", "1rem");
1253   cascade.Add("--x", "10rem");
1254   cascade.Apply();
1255 
1256   EXPECT_EQ("100px", cascade.ComputedValue("--x"));
1257 }
1258 
TEST_F(StyleCascadeTest,RemUnitInRootFontSizeCycle)1259 TEST_F(StyleCascadeTest, RemUnitInRootFontSizeCycle) {
1260   RegisterProperty(GetDocument(), "--x", "<length>", "0px", false);
1261 
1262   TestCascade cascade(GetDocument(), DocumentElement());
1263   cascade.Add("font-size", "var(--x)");
1264   cascade.Add("--x", "1rem");
1265   cascade.Apply();
1266 
1267   EXPECT_FALSE(cascade.ComputedValue("--x"));
1268 }
1269 
TEST_F(StyleCascadeTest,RemUnitInRootFontSizeNonCycle)1270 TEST_F(StyleCascadeTest, RemUnitInRootFontSizeNonCycle) {
1271   TestCascade cascade(GetDocument(), DocumentElement());
1272   cascade.Add("font-size", "initial");
1273   cascade.Apply();
1274 
1275   String expected = cascade.ComputedValue("font-size");
1276 
1277   cascade.Reset();
1278   cascade.Add("font-size", "var(--x)");
1279   cascade.Add("--x", "1rem");
1280   cascade.Apply();
1281 
1282   // Note: Only registered properties can have cycles with font-size.
1283   EXPECT_EQ("1rem", cascade.ComputedValue("--x"));
1284   EXPECT_EQ(expected, cascade.ComputedValue("font-size"));
1285 }
1286 
TEST_F(StyleCascadeTest,Initial)1287 TEST_F(StyleCascadeTest, Initial) {
1288   TestCascade parent(GetDocument());
1289   parent.Add("--x", "foo");
1290   parent.Apply();
1291 
1292   TestCascade cascade(GetDocument());
1293   cascade.InheritFrom(parent.TakeStyle());
1294   cascade.Add("--y", "foo");
1295   cascade.Apply();
1296 
1297   EXPECT_EQ("foo", cascade.ComputedValue("--x"));
1298   EXPECT_EQ("foo", cascade.ComputedValue("--y"));
1299 
1300   cascade.Reset();
1301   cascade.Add("--x", "initial");
1302   cascade.Add("--y", "initial");
1303   cascade.Apply();
1304 
1305   EXPECT_FALSE(cascade.ComputedValue("--x"));
1306   EXPECT_FALSE(cascade.ComputedValue("--y"));
1307 }
1308 
TEST_F(StyleCascadeTest,Inherit)1309 TEST_F(StyleCascadeTest, Inherit) {
1310   TestCascade parent(GetDocument());
1311   parent.Add("--x", "foo");
1312   parent.Apply();
1313 
1314   TestCascade cascade(GetDocument());
1315   cascade.InheritFrom(parent.TakeStyle());
1316 
1317   EXPECT_EQ("foo", cascade.ComputedValue("--x"));
1318 
1319   cascade.Add("--x", "bar");
1320   cascade.Apply();
1321   EXPECT_EQ("bar", cascade.ComputedValue("--x"));
1322 
1323   cascade.Reset();
1324   cascade.Add("--x", "inherit");
1325   cascade.Apply();
1326   EXPECT_EQ("foo", cascade.ComputedValue("--x"));
1327 }
1328 
TEST_F(StyleCascadeTest,Unset)1329 TEST_F(StyleCascadeTest, Unset) {
1330   TestCascade parent(GetDocument());
1331   parent.Add("--x", "foo");
1332   parent.Apply();
1333 
1334   TestCascade cascade(GetDocument());
1335   cascade.InheritFrom(parent.TakeStyle());
1336   EXPECT_EQ("foo", cascade.ComputedValue("--x"));
1337 
1338   cascade.Add("--x", "bar");
1339   cascade.Apply();
1340   EXPECT_EQ("bar", cascade.ComputedValue("--x"));
1341 
1342   cascade.Reset();
1343   cascade.Add("--x", "unset");
1344   cascade.Apply();
1345   EXPECT_EQ("foo", cascade.ComputedValue("--x"));
1346 }
1347 
TEST_F(StyleCascadeTest,RevertUA)1348 TEST_F(StyleCascadeTest, RevertUA) {
1349   TestCascade cascade(GetDocument());
1350   cascade.Add("display:block", CascadeOrigin::kUserAgent);
1351   cascade.Add("display:revert", CascadeOrigin::kUserAgent);
1352 
1353   cascade.Add("display:block", CascadeOrigin::kUser);
1354   cascade.Add("display:revert", CascadeOrigin::kUser);
1355 
1356   cascade.Add("display:block", CascadeOrigin::kAuthor);
1357   cascade.Add("display:revert", CascadeOrigin::kAuthor);
1358 
1359   cascade.Apply();
1360 
1361   EXPECT_EQ("inline", cascade.ComputedValue("display"));
1362 }
1363 
TEST_F(StyleCascadeTest,RevertStandardProperty)1364 TEST_F(StyleCascadeTest, RevertStandardProperty) {
1365   TestCascade cascade(GetDocument());
1366   cascade.Add("left:10px", CascadeOrigin::kUserAgent);
1367   cascade.Add("right:10px", CascadeOrigin::kUserAgent);
1368 
1369   cascade.Add("right:20px", CascadeOrigin::kUser);
1370   cascade.Add("right:revert", CascadeOrigin::kUser);
1371   cascade.Add("top:20px", CascadeOrigin::kUser);
1372   cascade.Add("bottom:20px", CascadeOrigin::kUser);
1373 
1374   cascade.Add("bottom:30px", CascadeOrigin::kAuthor);
1375   cascade.Add("bottom:revert", CascadeOrigin::kAuthor);
1376   cascade.Add("left:30px", CascadeOrigin::kAuthor);
1377   cascade.Add("left:revert", CascadeOrigin::kAuthor);
1378   cascade.Add("right:revert", CascadeOrigin::kAuthor);
1379   cascade.Apply();
1380 
1381   EXPECT_EQ("20px", cascade.ComputedValue("top"));
1382   EXPECT_EQ("10px", cascade.ComputedValue("right"));
1383   EXPECT_EQ("20px", cascade.ComputedValue("bottom"));
1384   EXPECT_EQ("10px", cascade.ComputedValue("left"));
1385 }
1386 
TEST_F(StyleCascadeTest,RevertCustomProperty)1387 TEST_F(StyleCascadeTest, RevertCustomProperty) {
1388   TestCascade cascade(GetDocument());
1389   cascade.Add("--x:10px", CascadeOrigin::kUser);
1390 
1391   cascade.Add("--y:fail", CascadeOrigin::kAuthor);
1392 
1393   cascade.Add("--x:revert", CascadeOrigin::kAuthor);
1394   cascade.Add("--y:revert", CascadeOrigin::kAuthor);
1395 
1396   cascade.Apply();
1397 
1398   EXPECT_EQ("10px", cascade.ComputedValue("--x"));
1399   EXPECT_FALSE(cascade.ComputedValue("--y"));
1400 }
1401 
TEST_F(StyleCascadeTest,RevertChain)1402 TEST_F(StyleCascadeTest, RevertChain) {
1403   TestCascade cascade(GetDocument());
1404   cascade.Add("width:10px", CascadeOrigin::kUserAgent);
1405 
1406   cascade.Add("width:revert", CascadeOrigin::kUser);
1407   cascade.Add("--x:revert", CascadeOrigin::kUser);
1408 
1409   cascade.Add("width:revert", CascadeOrigin::kAuthor);
1410   cascade.Add("--x:revert", CascadeOrigin::kAuthor);
1411   cascade.Apply();
1412 
1413   EXPECT_EQ("10px", cascade.ComputedValue("width"));
1414   EXPECT_FALSE(cascade.ComputedValue("--x"));
1415 }
1416 
TEST_F(StyleCascadeTest,RevertFromAuthorToUA)1417 TEST_F(StyleCascadeTest, RevertFromAuthorToUA) {
1418   TestCascade cascade(GetDocument());
1419   cascade.Add("width:10px", CascadeOrigin::kUserAgent);
1420   cascade.Add("height:10px", CascadeOrigin::kUserAgent);
1421 
1422   cascade.Add("width:20px", CascadeOrigin::kAuthor);
1423   cascade.Add("height:20px", CascadeOrigin::kAuthor);
1424   cascade.Add("width:revert", CascadeOrigin::kAuthor);
1425   cascade.Add("height:revert", CascadeOrigin::kAuthor);
1426   cascade.Apply();
1427 
1428   EXPECT_EQ("10px", cascade.ComputedValue("width"));
1429   EXPECT_EQ("10px", cascade.ComputedValue("height"));
1430 }
1431 
TEST_F(StyleCascadeTest,RevertInitialFallback)1432 TEST_F(StyleCascadeTest, RevertInitialFallback) {
1433   TestCascade cascade(GetDocument());
1434   cascade.Add("width:20px", CascadeOrigin::kAuthor);
1435   cascade.Add("width:revert", CascadeOrigin::kAuthor);
1436   cascade.Apply();
1437 
1438   EXPECT_EQ("auto", cascade.ComputedValue("width"));
1439 }
1440 
TEST_F(StyleCascadeTest,RevertInheritedFallback)1441 TEST_F(StyleCascadeTest, RevertInheritedFallback) {
1442   TestCascade parent(GetDocument());
1443   parent.Add("color", "red");
1444   parent.Apply();
1445 
1446   TestCascade cascade(GetDocument());
1447   cascade.InheritFrom(parent.TakeStyle());
1448   EXPECT_EQ("rgb(255, 0, 0)", cascade.ComputedValue("color"));
1449 
1450   cascade.Add("color:black", CascadeOrigin::kAuthor);
1451   cascade.Add("color:revert", CascadeOrigin::kAuthor);
1452   cascade.Apply();
1453   EXPECT_EQ("rgb(255, 0, 0)", cascade.ComputedValue("color"));
1454 }
1455 
TEST_F(StyleCascadeTest,RevertRegistered)1456 TEST_F(StyleCascadeTest, RevertRegistered) {
1457   RegisterProperty(GetDocument(), "--x", "<length>", "0px", false);
1458 
1459   TestCascade cascade(GetDocument());
1460   cascade.Add("--x:20px", CascadeOrigin::kUser);
1461   cascade.Add("--x:100px", CascadeOrigin::kAuthor);
1462   cascade.Add("--x:revert", CascadeOrigin::kAuthor);
1463   cascade.Apply();
1464 
1465   EXPECT_EQ("20px", cascade.ComputedValue("--x"));
1466 }
1467 
TEST_F(StyleCascadeTest,RevertRegisteredInitialFallback)1468 TEST_F(StyleCascadeTest, RevertRegisteredInitialFallback) {
1469   RegisterProperty(GetDocument(), "--x", "<length>", "0px", false);
1470 
1471   TestCascade cascade(GetDocument());
1472   cascade.Add("--x:20px", CascadeOrigin::kAuthor);
1473   cascade.Add("--x:revert", CascadeOrigin::kAuthor);
1474   cascade.Apply();
1475 
1476   EXPECT_EQ("0px", cascade.ComputedValue("--x"));
1477 }
1478 
TEST_F(StyleCascadeTest,RevertRegisteredInheritedFallback)1479 TEST_F(StyleCascadeTest, RevertRegisteredInheritedFallback) {
1480   RegisterProperty(GetDocument(), "--x", "<length>", "0px", true);
1481 
1482   TestCascade parent(GetDocument());
1483   parent.Add("--x", "1px");
1484   parent.Apply();
1485 
1486   TestCascade cascade(GetDocument());
1487   cascade.InheritFrom(parent.TakeStyle());
1488   EXPECT_EQ("1px", cascade.ComputedValue("--x"));
1489 
1490   cascade.Add("--x:100px", CascadeOrigin::kAuthor);
1491   cascade.Add("--x:revert", CascadeOrigin::kAuthor);
1492   cascade.Apply();
1493   EXPECT_EQ("1px", cascade.ComputedValue("--x"));
1494 }
1495 
TEST_F(StyleCascadeTest,RevertUASurrogate)1496 TEST_F(StyleCascadeTest, RevertUASurrogate) {
1497   TestCascade cascade(GetDocument());
1498 
1499   // User-agent:
1500 
1501   // Only logical:
1502   cascade.Add("inline-size:10px", CascadeOrigin::kUserAgent);
1503   cascade.Add("min-inline-size:11px", CascadeOrigin::kUserAgent);
1504   // Only physical:
1505   cascade.Add("height:12px", CascadeOrigin::kUserAgent);
1506   cascade.Add("min-height:13px", CascadeOrigin::kUserAgent);
1507   // Physical first:
1508   cascade.Add("margin-left:14px", CascadeOrigin::kUserAgent);
1509   cascade.Add("padding-left:15px", CascadeOrigin::kUserAgent);
1510   cascade.Add("margin-inline-start:16px", CascadeOrigin::kUserAgent);
1511   cascade.Add("padding-inline-start:17px", CascadeOrigin::kUserAgent);
1512   // Logical first:
1513   cascade.Add("margin-inline-end:18px", CascadeOrigin::kUserAgent);
1514   cascade.Add("padding-inline-end:19px", CascadeOrigin::kUserAgent);
1515   cascade.Add("margin-right:20px", CascadeOrigin::kUserAgent);
1516   cascade.Add("padding-right:21px", CascadeOrigin::kUserAgent);
1517 
1518   // Author:
1519 
1520   cascade.Add("width:100px", CascadeOrigin::kAuthor);
1521   cascade.Add("height:101px", CascadeOrigin::kAuthor);
1522   cascade.Add("margin:102px", CascadeOrigin::kAuthor);
1523   cascade.Add("padding:103px", CascadeOrigin::kAuthor);
1524   cascade.Add("min-width:104px", CascadeOrigin::kAuthor);
1525   cascade.Add("min-height:105px", CascadeOrigin::kAuthor);
1526   // Revert via physical:
1527   cascade.Add("width:revert", CascadeOrigin::kAuthor);
1528   cascade.Add("height:revert", CascadeOrigin::kAuthor);
1529   cascade.Add("margin-left:revert", CascadeOrigin::kAuthor);
1530   cascade.Add("margin-right:revert", CascadeOrigin::kAuthor);
1531   // Revert via logical:
1532   cascade.Add("min-inline-size:revert", CascadeOrigin::kAuthor);
1533   cascade.Add("min-block-size:revert", CascadeOrigin::kAuthor);
1534   cascade.Add("padding-inline-start:revert", CascadeOrigin::kAuthor);
1535   cascade.Add("padding-inline-end:revert", CascadeOrigin::kAuthor);
1536 
1537   cascade.Apply();
1538 
1539   EXPECT_EQ("10px", cascade.ComputedValue("width"));
1540   EXPECT_EQ("12px", cascade.ComputedValue("height"));
1541   EXPECT_EQ("11px", cascade.ComputedValue("min-width"));
1542   EXPECT_EQ("13px", cascade.ComputedValue("min-height"));
1543   EXPECT_EQ("102px", cascade.ComputedValue("margin-top"));
1544   EXPECT_EQ("20px", cascade.ComputedValue("margin-right"));
1545   EXPECT_EQ("102px", cascade.ComputedValue("margin-bottom"));
1546   EXPECT_EQ("16px", cascade.ComputedValue("margin-left"));
1547   EXPECT_EQ("103px", cascade.ComputedValue("padding-top"));
1548   EXPECT_EQ("21px", cascade.ComputedValue("padding-right"));
1549   EXPECT_EQ("103px", cascade.ComputedValue("padding-bottom"));
1550   EXPECT_EQ("17px", cascade.ComputedValue("padding-left"));
1551 
1552   EXPECT_EQ("10px", cascade.ComputedValue("inline-size"));
1553   EXPECT_EQ("12px", cascade.ComputedValue("block-size"));
1554   EXPECT_EQ("11px", cascade.ComputedValue("min-inline-size"));
1555   EXPECT_EQ("13px", cascade.ComputedValue("min-block-size"));
1556   EXPECT_EQ("102px", cascade.ComputedValue("margin-block-start"));
1557   EXPECT_EQ("20px", cascade.ComputedValue("margin-inline-end"));
1558   EXPECT_EQ("102px", cascade.ComputedValue("margin-block-end"));
1559   EXPECT_EQ("16px", cascade.ComputedValue("margin-inline-start"));
1560   EXPECT_EQ("103px", cascade.ComputedValue("padding-block-start"));
1561   EXPECT_EQ("21px", cascade.ComputedValue("padding-inline-end"));
1562   EXPECT_EQ("103px", cascade.ComputedValue("padding-block-end"));
1563   EXPECT_EQ("17px", cascade.ComputedValue("padding-inline-start"));
1564 }
1565 
TEST_F(StyleCascadeTest,RevertWithImportantPhysical)1566 TEST_F(StyleCascadeTest, RevertWithImportantPhysical) {
1567   TestCascade cascade(GetDocument());
1568   cascade.Add("inline-size:10px", CascadeOrigin::kUserAgent);
1569   cascade.Add("block-size:11px", CascadeOrigin::kUserAgent);
1570 
1571   cascade.Add("width:100px", CascadeOrigin::kAuthor);
1572   cascade.Add("height:101px", CascadeOrigin::kAuthor);
1573   cascade.Add("width:revert !important", CascadeOrigin::kAuthor);
1574   cascade.Add("inline-size:101px", CascadeOrigin::kAuthor);
1575   cascade.Add("block-size:102px", CascadeOrigin::kAuthor);
1576   cascade.Add("height:revert !important", CascadeOrigin::kAuthor);
1577   cascade.Apply();
1578 
1579   EXPECT_EQ("10px", cascade.ComputedValue("width"));
1580   EXPECT_EQ("11px", cascade.ComputedValue("height"));
1581   EXPECT_EQ("10px", cascade.ComputedValue("inline-size"));
1582   EXPECT_EQ("11px", cascade.ComputedValue("block-size"));
1583 }
1584 
TEST_F(StyleCascadeTest,RevertWithImportantLogical)1585 TEST_F(StyleCascadeTest, RevertWithImportantLogical) {
1586   TestCascade cascade(GetDocument());
1587   cascade.Add("inline-size:10px", CascadeOrigin::kUserAgent);
1588   cascade.Add("block-size:11px", CascadeOrigin::kUserAgent);
1589 
1590   cascade.Add("inline-size:revert !important", CascadeOrigin::kAuthor);
1591   cascade.Add("width:100px", CascadeOrigin::kAuthor);
1592   cascade.Add("height:101px", CascadeOrigin::kAuthor);
1593   cascade.Add("block-size:revert !important", CascadeOrigin::kAuthor);
1594   cascade.Apply();
1595 
1596   EXPECT_EQ("10px", cascade.ComputedValue("width"));
1597   EXPECT_EQ("11px", cascade.ComputedValue("height"));
1598   EXPECT_EQ("10px", cascade.ComputedValue("inline-size"));
1599   EXPECT_EQ("11px", cascade.ComputedValue("block-size"));
1600 }
1601 
TEST_F(StyleCascadeTest,RevertSurrogateChain)1602 TEST_F(StyleCascadeTest, RevertSurrogateChain) {
1603   TestCascade cascade(GetDocument());
1604 
1605   cascade.Add("inline-size:revert", CascadeOrigin::kUserAgent);
1606   cascade.Add("block-size:10px", CascadeOrigin::kUserAgent);
1607   cascade.Add("min-inline-size:11px", CascadeOrigin::kUserAgent);
1608   cascade.Add("min-block-size:12px", CascadeOrigin::kUserAgent);
1609   cascade.Add("margin-inline:13px", CascadeOrigin::kUserAgent);
1610   cascade.Add("margin-block:14px", CascadeOrigin::kUserAgent);
1611   cascade.Add("margin-top:revert", CascadeOrigin::kUserAgent);
1612   cascade.Add("margin-left:15px", CascadeOrigin::kUserAgent);
1613   cascade.Add("margin-bottom:16px", CascadeOrigin::kUserAgent);
1614   cascade.Add("margin-block-end:17px", CascadeOrigin::kUserAgent);
1615 
1616   cascade.Add("inline-size:101px", CascadeOrigin::kUser);
1617   cascade.Add("block-size:102px", CascadeOrigin::kUser);
1618   cascade.Add("width:revert", CascadeOrigin::kUser);
1619   cascade.Add("height:revert", CascadeOrigin::kUser);
1620   cascade.Add("min-inline-size:103px", CascadeOrigin::kUser);
1621   cascade.Add("min-block-size:104px", CascadeOrigin::kUser);
1622   cascade.Add("margin:105px", CascadeOrigin::kUser);
1623   cascade.Add("margin-block-start:revert", CascadeOrigin::kUser);
1624   cascade.Add("margin-inline-start:106px", CascadeOrigin::kUser);
1625   cascade.Add("margin-block-end:revert", CascadeOrigin::kUser);
1626   cascade.Add("margin-right:107px", CascadeOrigin::kUser);
1627 
1628   cascade.Add("inline-size:revert", CascadeOrigin::kAuthor);
1629   cascade.Add("block-size:revert", CascadeOrigin::kAuthor);
1630   cascade.Add("min-inline-size:revert", CascadeOrigin::kAuthor);
1631   cascade.Add("min-block-size:1001px", CascadeOrigin::kAuthor);
1632   cascade.Add("margin:1002px", CascadeOrigin::kAuthor);
1633   cascade.Add("margin-top:revert", CascadeOrigin::kAuthor);
1634   cascade.Add("margin-left:1003px", CascadeOrigin::kAuthor);
1635   cascade.Add("margin-bottom:1004px", CascadeOrigin::kAuthor);
1636   cascade.Add("margin-right:1005px", CascadeOrigin::kAuthor);
1637   cascade.Apply();
1638 
1639   EXPECT_EQ("auto", cascade.ComputedValue("width"));
1640   EXPECT_EQ("10px", cascade.ComputedValue("height"));
1641   EXPECT_EQ("103px", cascade.ComputedValue("min-width"));
1642   EXPECT_EQ("1001px", cascade.ComputedValue("min-height"));
1643   EXPECT_EQ("0px", cascade.ComputedValue("margin-top"));
1644   EXPECT_EQ("1005px", cascade.ComputedValue("margin-right"));
1645   EXPECT_EQ("1004px", cascade.ComputedValue("margin-bottom"));
1646   EXPECT_EQ("1003px", cascade.ComputedValue("margin-left"));
1647 }
1648 
TEST_F(StyleCascadeTest,RevertInKeyframe)1649 TEST_F(StyleCascadeTest, RevertInKeyframe) {
1650   AppendSheet(R"HTML(
1651      @keyframes test {
1652         from { margin-left: 0px; }
1653         to { margin-left: revert; }
1654      }
1655     )HTML");
1656 
1657   TestCascade cascade(GetDocument());
1658 
1659   cascade.Add("margin-left:100px", CascadeOrigin::kUserAgent);
1660   cascade.Add("animation:test linear 1000s -500s");
1661   cascade.Apply();
1662 
1663   cascade.CalculateAnimationUpdate();
1664   cascade.Apply();
1665 
1666   EXPECT_EQ("50px", cascade.ComputedValue("margin-left"));
1667 }
1668 
TEST_F(StyleCascadeTest,RevertToCustomPropertyInKeyframe)1669 TEST_F(StyleCascadeTest, RevertToCustomPropertyInKeyframe) {
1670   RegisterProperty(GetDocument(), "--x", "<length>", "0px", false);
1671 
1672   AppendSheet(R"HTML(
1673      @keyframes test {
1674         from { --x: 0px; }
1675         to { --x: revert; }
1676      }
1677     )HTML");
1678 
1679   TestCascade cascade(GetDocument());
1680 
1681   cascade.Add("--x:100px", CascadeOrigin::kUser);
1682   cascade.Add("--x:1000px", CascadeOrigin::kAuthor);
1683   cascade.Add("animation:test linear 1000s -500s");
1684   cascade.Apply();
1685 
1686   cascade.CalculateAnimationUpdate();
1687   cascade.Apply();
1688 
1689   EXPECT_EQ("50px", cascade.ComputedValue("--x"));
1690 }
1691 
TEST_F(StyleCascadeTest,RevertToCustomPropertyInKeyframeUnset)1692 TEST_F(StyleCascadeTest, RevertToCustomPropertyInKeyframeUnset) {
1693   RegisterProperty(GetDocument(), "--x", "<length>", "0px", false);
1694   RegisterProperty(GetDocument(), "--y", "<length>", "1000px", true);
1695 
1696   AppendSheet(R"HTML(
1697      @keyframes test {
1698         from { --x: 100px; --y: 100px; }
1699         to { --x: revert; --y: revert; }
1700      }
1701     )HTML");
1702 
1703   TestCascade parent(GetDocument());
1704   parent.Add("--y: 0px");
1705   parent.Apply();
1706   EXPECT_EQ("0px", parent.ComputedValue("--y"));
1707 
1708   TestCascade cascade(GetDocument());
1709   cascade.InheritFrom(parent.TakeStyle());
1710   cascade.Add("--x:10000px", CascadeOrigin::kAuthor);
1711   cascade.Add("--y:10000px", CascadeOrigin::kAuthor);
1712   cascade.Add("animation:test linear 1000s -500s");
1713   cascade.Apply();
1714 
1715   cascade.CalculateAnimationUpdate();
1716   cascade.Apply();
1717 
1718   EXPECT_EQ("50px", cascade.ComputedValue("--x"));
1719   EXPECT_EQ("50px", cascade.ComputedValue("--y"));
1720 }
1721 
TEST_F(StyleCascadeTest,RevertToCustomPropertyInKeyframeEmptyInherit)1722 TEST_F(StyleCascadeTest, RevertToCustomPropertyInKeyframeEmptyInherit) {
1723   RegisterProperty(GetDocument(), "--x", "<length>", "0px", true);
1724 
1725   AppendSheet(R"HTML(
1726      @keyframes test {
1727         from { --x: 100px; }
1728         to { --x: revert; }
1729      }
1730     )HTML");
1731 
1732   TestCascade cascade(GetDocument());
1733   cascade.Add("--x:10000px", CascadeOrigin::kAuthor);
1734   cascade.Add("animation:test linear 1000s -500s");
1735   cascade.Apply();
1736 
1737   cascade.CalculateAnimationUpdate();
1738   cascade.Apply();
1739 
1740   EXPECT_EQ("50px", cascade.ComputedValue("--x"));
1741 }
1742 
TEST_F(StyleCascadeTest,RevertInKeyframeResponsive)1743 TEST_F(StyleCascadeTest, RevertInKeyframeResponsive) {
1744   AppendSheet(R"HTML(
1745      @keyframes test {
1746         from { margin-left: 0px; }
1747         to { margin-left: revert; }
1748      }
1749     )HTML");
1750 
1751   TestCascade cascade(GetDocument());
1752 
1753   cascade.Add("--x:100px", CascadeOrigin::kUser);
1754   cascade.Add("margin-left:var(--x)", CascadeOrigin::kUser);
1755   cascade.Add("animation:test linear 1000s -500s");
1756   cascade.Apply();
1757   cascade.CalculateAnimationUpdate();
1758   cascade.Apply();
1759 
1760   EXPECT_EQ("50px", cascade.ComputedValue("margin-left"));
1761 
1762   cascade.Reset();
1763   cascade.Add("--x:100px", CascadeOrigin::kUser);
1764   cascade.Add("margin-left:var(--x)", CascadeOrigin::kUser);
1765   cascade.Add("animation:test linear 1000s -500s");
1766   cascade.Add("--x:80px", CascadeOrigin::kAuthor);
1767   cascade.Apply();
1768   cascade.CalculateAnimationUpdate();
1769   cascade.Apply();
1770 
1771   EXPECT_EQ("40px", cascade.ComputedValue("margin-left"));
1772 }
1773 
TEST_F(StyleCascadeTest,RevertToCycleInKeyframe)1774 TEST_F(StyleCascadeTest, RevertToCycleInKeyframe) {
1775   RegisterProperty(GetDocument(), "--x", "<length>", "0px", false);
1776 
1777   AppendSheet(R"HTML(
1778      @keyframes test {
1779         from { --x: 100px; }
1780         to { --x: revert; }
1781      }
1782     )HTML");
1783 
1784   TestCascade cascade(GetDocument());
1785 
1786   cascade.Add("--x:var(--y)", CascadeOrigin::kUser);
1787   cascade.Add("--y:var(--x)", CascadeOrigin::kUser);
1788   cascade.Add("--x:200px", CascadeOrigin::kAuthor);
1789   cascade.Add("animation:test linear 1000s -500s");
1790   cascade.Apply();
1791 
1792   cascade.CalculateAnimationUpdate();
1793   cascade.Apply();
1794 
1795   EXPECT_EQ("0px", cascade.ComputedValue("--x"));
1796 }
1797 
TEST_F(StyleCascadeTest,RevertCausesTransition)1798 TEST_F(StyleCascadeTest, RevertCausesTransition) {
1799   TestCascade cascade1(GetDocument());
1800   cascade1.Add("width:200px", CascadeOrigin::kUser);
1801   cascade1.Add("width:100px", CascadeOrigin::kAuthor);
1802   cascade1.Add("transition: width 1000s steps(2, end)", CascadeOrigin::kAuthor);
1803   cascade1.Apply();
1804 
1805   GetDocument().body()->SetComputedStyle(cascade1.TakeStyle());
1806 
1807   // Now simulate a new style, with new color values.
1808   TestCascade cascade2(GetDocument());
1809   cascade2.Add("width:200px", CascadeOrigin::kUser);
1810   cascade2.Add("width:100px", CascadeOrigin::kAuthor);
1811   cascade2.Add("width:revert", CascadeOrigin::kAuthor);
1812   cascade2.Add("transition: width 1000s steps(2, start)",
1813                CascadeOrigin::kAuthor);
1814   cascade2.Apply();
1815 
1816   cascade2.CalculateTransitionUpdate();
1817   cascade2.Apply();
1818 
1819   EXPECT_EQ("150px", cascade2.ComputedValue("width"));
1820 }
1821 
TEST_F(StyleCascadeTest,CSSWideKeywordsInFallbacks)1822 TEST_F(StyleCascadeTest, CSSWideKeywordsInFallbacks) {
1823   {
1824     TestCascade cascade(GetDocument());
1825     cascade.Add("display:var(--u,initial)");
1826     cascade.Add("margin:var(--u,initial)");
1827     cascade.Apply();
1828   }
1829   {
1830     TestCascade cascade(GetDocument());
1831     cascade.Add("display:var(--u,inherit)");
1832     cascade.Add("margin:var(--u,inherit)");
1833     cascade.Apply();
1834   }
1835   {
1836     TestCascade cascade(GetDocument());
1837     cascade.Add("display:var(--u,unset)");
1838     cascade.Add("margin:var(--u,unset)");
1839     cascade.Apply();
1840   }
1841   {
1842     TestCascade cascade(GetDocument());
1843     cascade.Add("display:var(--u,revert)");
1844     cascade.Add("margin:var(--u,revert)");
1845     cascade.Apply();
1846   }
1847 
1848   // TODO(crbug.com/1105782): Specs and WPT are currently in conflict
1849   // regarding the correct behavior here. For now this test just verifies
1850   // that we don't crash.
1851 }
1852 
TEST_F(StyleCascadeTest,RegisteredInitial)1853 TEST_F(StyleCascadeTest, RegisteredInitial) {
1854   RegisterProperty(GetDocument(), "--x", "<length>", "0px", false);
1855 
1856   TestCascade cascade(GetDocument());
1857   cascade.Apply();
1858   EXPECT_EQ("0px", cascade.ComputedValue("--x"));
1859 }
1860 
TEST_F(StyleCascadeTest,SubstituteRegisteredImplicitInitialValue)1861 TEST_F(StyleCascadeTest, SubstituteRegisteredImplicitInitialValue) {
1862   RegisterProperty(GetDocument(), "--x", "<length>", "13px", false);
1863 
1864   TestCascade cascade(GetDocument());
1865   cascade.Add("--y", " var(--x) ");
1866   cascade.Apply();
1867   EXPECT_EQ("13px", cascade.ComputedValue("--x"));
1868   EXPECT_EQ(" 13px ", cascade.ComputedValue("--y"));
1869 }
1870 
TEST_F(StyleCascadeTest,SubstituteRegisteredUniversal)1871 TEST_F(StyleCascadeTest, SubstituteRegisteredUniversal) {
1872   RegisterProperty(GetDocument(), "--x", "*", "foo", false);
1873 
1874   TestCascade cascade(GetDocument());
1875   cascade.Add("--x", "bar");
1876   cascade.Add("--y", "var(--x)");
1877   cascade.Apply();
1878   EXPECT_EQ("bar", cascade.ComputedValue("--x"));
1879   EXPECT_EQ("bar", cascade.ComputedValue("--y"));
1880 }
1881 
TEST_F(StyleCascadeTest,SubstituteRegisteredUniversalInvalid)1882 TEST_F(StyleCascadeTest, SubstituteRegisteredUniversalInvalid) {
1883   RegisterProperty(GetDocument(), "--x", "*", base::nullopt, false);
1884 
1885   TestCascade cascade(GetDocument());
1886   cascade.Add("--y", " var(--x) ");
1887   cascade.Apply();
1888   EXPECT_FALSE(cascade.ComputedValue("--x"));
1889   EXPECT_FALSE(cascade.ComputedValue("--y"));
1890 }
1891 
TEST_F(StyleCascadeTest,SubstituteRegisteredUniversalInitial)1892 TEST_F(StyleCascadeTest, SubstituteRegisteredUniversalInitial) {
1893   RegisterProperty(GetDocument(), "--x", "*", "foo", false);
1894 
1895   TestCascade cascade(GetDocument());
1896   cascade.Add("--y", " var(--x) ");
1897   cascade.Apply();
1898   EXPECT_EQ("foo", cascade.ComputedValue("--x"));
1899   EXPECT_EQ(" foo ", cascade.ComputedValue("--y"));
1900 }
1901 
TEST_F(StyleCascadeTest,RegisteredExplicitInitial)1902 TEST_F(StyleCascadeTest, RegisteredExplicitInitial) {
1903   RegisterProperty(GetDocument(), "--x", "<length>", "0px", false);
1904 
1905   TestCascade cascade(GetDocument());
1906   cascade.Add("--x", "10px");
1907   cascade.Apply();
1908   EXPECT_EQ("10px", cascade.ComputedValue("--x"));
1909 
1910   cascade.Reset();
1911   cascade.Add("--x", "initial");
1912   cascade.Add("--y", "var(--x)");
1913   cascade.Apply();
1914   EXPECT_EQ("0px", cascade.ComputedValue("--x"));
1915   EXPECT_EQ("0px", cascade.ComputedValue("--y"));
1916 }
1917 
TEST_F(StyleCascadeTest,RegisteredExplicitInherit)1918 TEST_F(StyleCascadeTest, RegisteredExplicitInherit) {
1919   RegisterProperty(GetDocument(), "--x", "<length>", "0px", false);
1920 
1921   TestCascade parent(GetDocument());
1922   parent.Add("--x", "15px");
1923   parent.Apply();
1924   EXPECT_EQ("15px", parent.ComputedValue("--x"));
1925 
1926   TestCascade cascade(GetDocument());
1927   cascade.InheritFrom(parent.TakeStyle());
1928   cascade.Apply();
1929   EXPECT_EQ("0px", cascade.ComputedValue("--x"));  // Note: inherit==false
1930 
1931   cascade.Reset();
1932   cascade.Add("--x", "inherit");
1933   cascade.Add("--y", "var(--x)");
1934   cascade.Apply();
1935   EXPECT_EQ("15px", cascade.ComputedValue("--x"));
1936   EXPECT_EQ("15px", cascade.ComputedValue("--y"));
1937 }
1938 
TEST_F(StyleCascadeTest,RegisteredExplicitUnset)1939 TEST_F(StyleCascadeTest, RegisteredExplicitUnset) {
1940   RegisterProperty(GetDocument(), "--x", "<length>", "0px", false);
1941   RegisterProperty(GetDocument(), "--y", "<length>", "0px", true);
1942 
1943   TestCascade parent(GetDocument());
1944   parent.Add("--x", "15px");
1945   parent.Add("--y", "15px");
1946   parent.Apply();
1947   EXPECT_EQ("15px", parent.ComputedValue("--x"));
1948   EXPECT_EQ("15px", parent.ComputedValue("--y"));
1949 
1950   TestCascade cascade(GetDocument());
1951   cascade.InheritFrom(parent.TakeStyle());
1952   cascade.Add("--x", "2px");
1953   cascade.Add("--y", "2px");
1954   cascade.Apply();
1955   EXPECT_EQ("2px", cascade.ComputedValue("--x"));
1956   EXPECT_EQ("2px", cascade.ComputedValue("--y"));
1957 
1958   cascade.Reset();
1959   cascade.Add("--x", "unset");
1960   cascade.Add("--y", "unset");
1961   cascade.Add("--z", "var(--x) var(--y)");
1962   cascade.Apply();
1963   EXPECT_EQ("0px", cascade.ComputedValue("--x"));
1964   EXPECT_EQ("15px", cascade.ComputedValue("--y"));
1965   EXPECT_EQ("0px 15px", cascade.ComputedValue("--z"));
1966 }
1967 
TEST_F(StyleCascadeTest,SubstituteAnimationTaintedInCustomProperty)1968 TEST_F(StyleCascadeTest, SubstituteAnimationTaintedInCustomProperty) {
1969   TestCascade cascade(GetDocument());
1970   cascade.Add(AnimationTaintedSet("--x", "15px"));
1971   cascade.Add("--y", "var(--x)");
1972   cascade.Apply();
1973   EXPECT_EQ("15px", cascade.ComputedValue("--x"));
1974   EXPECT_EQ("15px", cascade.ComputedValue("--y"));
1975 }
1976 
TEST_F(StyleCascadeTest,SubstituteAnimationTaintedInStandardProperty)1977 TEST_F(StyleCascadeTest, SubstituteAnimationTaintedInStandardProperty) {
1978   TestCascade cascade(GetDocument());
1979   cascade.Add(AnimationTaintedSet("--x", "15px"));
1980   cascade.Add("width", "var(--x)");
1981   cascade.Apply();
1982   EXPECT_EQ("15px", cascade.ComputedValue("--x"));
1983   EXPECT_EQ("15px", cascade.ComputedValue("width"));
1984 }
1985 
TEST_F(StyleCascadeTest,SubstituteAnimationTaintedInAnimationProperty)1986 TEST_F(StyleCascadeTest, SubstituteAnimationTaintedInAnimationProperty) {
1987   TestCascade cascade(GetDocument());
1988   cascade.Add("--x", "20s");
1989   cascade.Add("animation-duration", "var(--x)");
1990   cascade.Apply();
1991 
1992   EXPECT_EQ("20s", cascade.ComputedValue("--x"));
1993   EXPECT_EQ("20s", cascade.ComputedValue("animation-duration"));
1994 
1995   cascade.Reset();
1996   cascade.Add(AnimationTaintedSet("--y", "20s"));
1997   cascade.Add("animation-duration", "var(--y)");
1998   cascade.Apply();
1999 
2000   EXPECT_EQ("20s", cascade.ComputedValue("--y"));
2001   EXPECT_EQ("0s", cascade.ComputedValue("animation-duration"));
2002 }
2003 
TEST_F(StyleCascadeTest,IndirectlyAnimationTainted)2004 TEST_F(StyleCascadeTest, IndirectlyAnimationTainted) {
2005   TestCascade cascade(GetDocument());
2006   cascade.Add(AnimationTaintedSet("--x", "20s"));
2007   cascade.Add("--y", "var(--x)");
2008   cascade.Add("animation-duration", "var(--y)");
2009   cascade.Apply();
2010 
2011   EXPECT_EQ("20s", cascade.ComputedValue("--x"));
2012   EXPECT_EQ("20s", cascade.ComputedValue("--y"));
2013   EXPECT_EQ("0s", cascade.ComputedValue("animation-duration"));
2014 }
2015 
TEST_F(StyleCascadeTest,AnimationTaintedFallback)2016 TEST_F(StyleCascadeTest, AnimationTaintedFallback) {
2017   TestCascade cascade(GetDocument());
2018   cascade.Add(AnimationTaintedSet("--x", "20s"));
2019   cascade.Add("animation-duration", "var(--x,1s)");
2020   cascade.Apply();
2021 
2022   EXPECT_EQ("20s", cascade.ComputedValue("--x"));
2023   EXPECT_EQ("1s", cascade.ComputedValue("animation-duration"));
2024 }
2025 
TEST_F(StyleCascadeTest,EnvMissingNestedVar)2026 TEST_F(StyleCascadeTest, EnvMissingNestedVar) {
2027   TestCascade cascade(GetDocument());
2028   cascade.Add("--x", "rgb(0, 0, 0)");
2029   cascade.Add("background-color", "env(missing, var(--x))");
2030   cascade.Apply();
2031 
2032   EXPECT_EQ("rgb(0, 0, 0)", cascade.ComputedValue("--x"));
2033   EXPECT_EQ("rgb(0, 0, 0)", cascade.ComputedValue("background-color"));
2034 }
2035 
TEST_F(StyleCascadeTest,EnvMissingNestedVarFallback)2036 TEST_F(StyleCascadeTest, EnvMissingNestedVarFallback) {
2037   TestCascade cascade(GetDocument());
2038   cascade.Add("background-color", "env(missing, var(--missing, blue))");
2039   cascade.Apply();
2040 
2041   EXPECT_EQ("rgb(0, 0, 255)", cascade.ComputedValue("background-color"));
2042 }
2043 
TEST_F(StyleCascadeTest,EnvMissingFallback)2044 TEST_F(StyleCascadeTest, EnvMissingFallback) {
2045   TestCascade cascade(GetDocument());
2046   cascade.Add("background-color", "env(missing, blue)");
2047   cascade.Apply();
2048 
2049   EXPECT_EQ("rgb(0, 0, 255)", cascade.ComputedValue("background-color"));
2050 }
2051 
TEST_F(StyleCascadeTest,ValidEnv)2052 TEST_F(StyleCascadeTest, ValidEnv) {
2053   AutoEnv env(*this, "test", "red");
2054 
2055   TestCascade cascade(GetDocument());
2056   cascade.Add("background-color", "env(test, blue)");
2057   cascade.Apply();
2058 
2059   EXPECT_EQ("rgb(255, 0, 0)", cascade.ComputedValue("background-color"));
2060 }
2061 
TEST_F(StyleCascadeTest,ValidEnvFallback)2062 TEST_F(StyleCascadeTest, ValidEnvFallback) {
2063   AutoEnv env(*this, "test", "red");
2064 
2065   TestCascade cascade(GetDocument());
2066   cascade.Add("background-color", "env(test, blue)");
2067   cascade.Apply();
2068 
2069   EXPECT_EQ("rgb(255, 0, 0)", cascade.ComputedValue("background-color"));
2070 }
2071 
TEST_F(StyleCascadeTest,ValidEnvInUnusedFallback)2072 TEST_F(StyleCascadeTest, ValidEnvInUnusedFallback) {
2073   AutoEnv env(*this, "test", "red");
2074 
2075   TestCascade cascade(GetDocument());
2076   cascade.Add("--x", "rgb(0, 0, 0)");
2077   cascade.Add("background-color", "var(--x, env(test))");
2078   cascade.Apply();
2079 
2080   EXPECT_EQ("rgb(0, 0, 0)", cascade.ComputedValue("--x"));
2081   EXPECT_EQ("rgb(0, 0, 0)", cascade.ComputedValue("background-color"));
2082 }
2083 
TEST_F(StyleCascadeTest,ValidEnvInUsedFallback)2084 TEST_F(StyleCascadeTest, ValidEnvInUsedFallback) {
2085   AutoEnv env(*this, "test", "red");
2086 
2087   TestCascade cascade(GetDocument());
2088   cascade.Add("background-color", "var(--missing, env(test))");
2089   cascade.Apply();
2090 
2091   EXPECT_EQ("rgb(255, 0, 0)", cascade.ComputedValue("background-color"));
2092 }
2093 
TEST_F(StyleCascadeTest,AnimationApplyFilter)2094 TEST_F(StyleCascadeTest, AnimationApplyFilter) {
2095   AppendSheet(R"HTML(
2096      @keyframes test {
2097         from { color: white; background-color: white; }
2098         to { color: gray; background-color: gray; }
2099      }
2100     )HTML");
2101 
2102   TestCascade cascade(GetDocument());
2103 
2104   cascade.Add("animation: test linear 10s -5s");
2105   cascade.Add("color:green");
2106   cascade.Apply();
2107 
2108   cascade.CalculateAnimationUpdate();
2109   cascade.Apply(CascadeFilter(CSSProperty::kInherited, true));
2110 
2111   EXPECT_EQ("rgb(0, 128, 0)", cascade.ComputedValue("color"));
2112   EXPECT_EQ("rgb(192, 192, 192)", cascade.ComputedValue("background-color"));
2113 }
2114 
TEST_F(StyleCascadeTest,TransitionApplyFilter)2115 TEST_F(StyleCascadeTest, TransitionApplyFilter) {
2116   TestCascade cascade1(GetDocument());
2117   cascade1.Add("background-color: white");
2118   cascade1.Add("color: white");
2119   cascade1.Add("transition: all steps(2, start) 100s");
2120   cascade1.Apply();
2121 
2122   // Set the old style on the element, so that the transition
2123   // update detects it.
2124   GetDocument().body()->SetComputedStyle(cascade1.TakeStyle());
2125 
2126   // Now simulate a new style, with new color values.
2127   TestCascade cascade2(GetDocument());
2128   cascade2.Add("background-color: gray");
2129   cascade2.Add("color: gray");
2130   cascade2.Add("transition: all steps(2, start) 100s");
2131   cascade2.Apply();
2132 
2133   cascade2.CalculateTransitionUpdate();
2134   cascade2.Apply(CascadeFilter(CSSProperty::kInherited, true));
2135 
2136   EXPECT_EQ("rgb(128, 128, 128)", cascade2.ComputedValue("color"));
2137   EXPECT_EQ("rgb(192, 192, 192)", cascade2.ComputedValue("background-color"));
2138 }
2139 
TEST_F(StyleCascadeTest,PendingKeyframeAnimation)2140 TEST_F(StyleCascadeTest, PendingKeyframeAnimation) {
2141   RegisterProperty(GetDocument(), "--x", "<length>", "0px", false);
2142 
2143   AppendSheet(R"HTML(
2144      @keyframes test {
2145         from { --x: 10px; }
2146         to { --x: 20px; }
2147      }
2148     )HTML");
2149 
2150   TestCascade cascade(GetDocument());
2151 
2152   cascade.Add("animation-name", "test");
2153   cascade.Add("animation-duration", "1s");
2154   cascade.Apply();
2155 
2156   cascade.CalculateAnimationUpdate();
2157   cascade.Apply();
2158 
2159   EXPECT_EQ(CascadeOrigin::kAnimation, cascade.GetPriority("--x").GetOrigin());
2160 }
2161 
TEST_F(StyleCascadeTest,PendingKeyframeAnimationApply)2162 TEST_F(StyleCascadeTest, PendingKeyframeAnimationApply) {
2163   RegisterProperty(GetDocument(), "--x", "<length>", "0px", false);
2164 
2165   AppendSheet(R"HTML(
2166      @keyframes test {
2167         from { --x: 10px; }
2168         to { --x: 20px; }
2169      }
2170     )HTML");
2171 
2172   TestCascade cascade(GetDocument());
2173 
2174   cascade.Add("animation-name", "test");
2175   cascade.Add("animation-duration", "10s");
2176   cascade.Add("animation-timing-function", "linear");
2177   cascade.Add("animation-delay", "-5s");
2178   cascade.Apply();
2179 
2180   cascade.CalculateAnimationUpdate();
2181   cascade.Apply();
2182 
2183   EXPECT_EQ(CascadeOrigin::kAnimation, cascade.GetPriority("--x").GetOrigin());
2184   EXPECT_EQ("15px", cascade.ComputedValue("--x"));
2185 }
2186 
TEST_F(StyleCascadeTest,TransitionCausesInterpolationValue)2187 TEST_F(StyleCascadeTest, TransitionCausesInterpolationValue) {
2188   RegisterProperty(GetDocument(), "--x", "<length>", "0px", false);
2189 
2190   // First, simulate an "old style".
2191   TestCascade cascade1(GetDocument());
2192   cascade1.Add("--x", "10px");
2193   cascade1.Add("transition", "--x 1s");
2194   cascade1.Apply();
2195 
2196   // Set the old style on the element, so that the animation
2197   // update detects it.
2198   GetDocument().body()->SetComputedStyle(cascade1.TakeStyle());
2199 
2200   // Now simulate a new style, with a new value for --x.
2201   TestCascade cascade2(GetDocument());
2202   cascade2.Add("--x", "20px");
2203   cascade2.Add("transition", "--x 1s");
2204   cascade2.Apply();
2205 
2206   cascade2.CalculateTransitionUpdate();
2207   cascade2.Apply();
2208 
2209   EXPECT_EQ(CascadeOrigin::kTransition,
2210             cascade2.GetPriority("--x").GetOrigin());
2211 }
2212 
TEST_F(StyleCascadeTest,TransitionDetectedForChangedFontSize)2213 TEST_F(StyleCascadeTest, TransitionDetectedForChangedFontSize) {
2214   RegisterProperty(GetDocument(), "--x", "<length>", "0px", false);
2215 
2216   TestCascade cascade1(GetDocument());
2217   cascade1.Add("font-size", "10px");
2218   cascade1.Add("--x", "10em");
2219   cascade1.Add("width", "10em");
2220   cascade1.Add("height", "10px");
2221   cascade1.Add("transition", "--x 1s, width 1s");
2222   cascade1.Apply();
2223 
2224   GetDocument().body()->SetComputedStyle(cascade1.TakeStyle());
2225 
2226   TestCascade cascade2(GetDocument());
2227   cascade2.Add("font-size", "20px");
2228   cascade2.Add("--x", "10em");
2229   cascade2.Add("width", "10em");
2230   cascade2.Add("height", "10px");
2231   cascade2.Add("transition", "--x 1s, width 1s");
2232   cascade2.Apply();
2233 
2234   cascade2.CalculateTransitionUpdate();
2235   cascade2.Apply();
2236 
2237   EXPECT_EQ(CascadeOrigin::kTransition, cascade2.GetOrigin("--x"));
2238   EXPECT_EQ(CascadeOrigin::kTransition, cascade2.GetOrigin("width"));
2239   EXPECT_EQ("10px", cascade2.ComputedValue("height"));
2240 }
2241 
TEST_F(StyleCascadeTest,AnimatingVarReferences)2242 TEST_F(StyleCascadeTest, AnimatingVarReferences) {
2243   RegisterProperty(GetDocument(), "--x", "<length>", "0px", false);
2244 
2245   AppendSheet(R"HTML(
2246      @keyframes test {
2247         from { --x: var(--from); }
2248         to { --x: var(--to); }
2249      }
2250     )HTML");
2251 
2252   TestCascade cascade(GetDocument());
2253 
2254   cascade.Add("animation-name", "test");
2255   cascade.Add("animation-duration", "10s");
2256   cascade.Add("animation-timing-function", "linear");
2257   cascade.Add("animation-delay", "-5s");
2258   cascade.Add("--from", "10px");
2259   cascade.Add("--to", "20px");
2260   cascade.Add("--y", "var(--x)");
2261   cascade.Apply();
2262 
2263   cascade.CalculateAnimationUpdate();
2264   cascade.Apply();
2265 
2266   EXPECT_EQ("15px", cascade.ComputedValue("--x"));
2267   EXPECT_EQ("15px", cascade.ComputedValue("--y"));
2268 }
2269 
TEST_F(StyleCascadeTest,AnimateStandardProperty)2270 TEST_F(StyleCascadeTest, AnimateStandardProperty) {
2271   AppendSheet(R"HTML(
2272      @keyframes test {
2273         from { width: 10px; }
2274         to { width: 20px; }
2275      }
2276     )HTML");
2277 
2278   TestCascade cascade(GetDocument());
2279 
2280   cascade.Add("animation-name", "test");
2281   cascade.Add("animation-duration", "10s");
2282   cascade.Add("animation-timing-function", "linear");
2283   cascade.Add("animation-delay", "-5s");
2284   cascade.Apply();
2285 
2286   cascade.CalculateAnimationUpdate();
2287   cascade.Apply();
2288 
2289   EXPECT_EQ(CascadeOrigin::kAnimation, cascade.GetOrigin("width"));
2290   EXPECT_EQ("15px", cascade.ComputedValue("width"));
2291 }
2292 
TEST_F(StyleCascadeTest,AnimateLogicalProperty)2293 TEST_F(StyleCascadeTest, AnimateLogicalProperty) {
2294   // We don't support smooth interpolation of css-logical properties yet,
2295   // so this test uses a paused animation at t=0.
2296   // TODO(crbug.com/865579): Support animations of css-logical properties
2297 
2298   AppendSheet(R"HTML(
2299      @keyframes test {
2300         from { margin-inline-start: 10px; }
2301         to { margin-inline-start: 20px; }
2302      }
2303     )HTML");
2304 
2305   TestCascade cascade(GetDocument());
2306 
2307   cascade.Add("margin-left:1000px");
2308   cascade.Add("animation:test 1s linear paused");
2309   cascade.Apply();
2310 
2311   cascade.CalculateAnimationUpdate();
2312   cascade.Apply();
2313 
2314   EXPECT_EQ(CascadeOrigin::kAnimation, cascade.GetOrigin("margin-left"));
2315   EXPECT_EQ("10px", cascade.ComputedValue("margin-left"));
2316 }
2317 
TEST_F(StyleCascadeTest,AnimateLogicalPropertyWithLookup)2318 TEST_F(StyleCascadeTest, AnimateLogicalPropertyWithLookup) {
2319   // We don't support smooth interpolation of css-logical properties yet,
2320   // so this test uses a paused animation at t=0.
2321   // TODO(crbug.com/865579): Support animations of css-logical properties
2322 
2323   AppendSheet(R"HTML(
2324      @keyframes test {
2325         from { margin-inline-start: 10px; }
2326         to { margin-inline-start: 20px; }
2327      }
2328     )HTML");
2329 
2330   TestCascade cascade(GetDocument());
2331 
2332   cascade.Add("margin-left:1000px");
2333   cascade.Add("animation:test 1s linear paused");
2334   cascade.Apply();
2335 
2336   cascade.CalculateAnimationUpdate();
2337   cascade.ApplySingle(GetCSSPropertyMarginLeft());
2338 
2339   EXPECT_EQ(CascadeOrigin::kAnimation, cascade.GetOrigin("margin-left"));
2340   EXPECT_EQ("10px", cascade.ComputedValue("margin-left"));
2341 }
2342 
TEST_F(StyleCascadeTest,AuthorImportantWinOverAnimations)2343 TEST_F(StyleCascadeTest, AuthorImportantWinOverAnimations) {
2344   AppendSheet(R"HTML(
2345      @keyframes test {
2346         from { width: 10px; height: 10px; }
2347         to { width: 20px; height: 20px; }
2348      }
2349     )HTML");
2350 
2351   TestCascade cascade(GetDocument());
2352 
2353   cascade.Add("animation-name", "test");
2354   cascade.Add("animation-duration", "10s");
2355   cascade.Add("animation-timing-function", "linear");
2356   cascade.Add("animation-delay", "-5s");
2357   cascade.Add("width:40px");
2358   cascade.Add("height:40px !important");
2359   cascade.Apply();
2360 
2361   cascade.CalculateAnimationUpdate();
2362   cascade.Apply();
2363 
2364   EXPECT_EQ(CascadeOrigin::kAnimation, cascade.GetOrigin("width"));
2365   EXPECT_EQ(CascadeOrigin::kAuthor, cascade.GetOrigin("height"));
2366 
2367   EXPECT_EQ("15px", cascade.ComputedValue("width"));
2368   EXPECT_EQ("40px", cascade.ComputedValue("height"));
2369 }
2370 
TEST_F(StyleCascadeTest,TransitionsWinOverAuthorImportant)2371 TEST_F(StyleCascadeTest, TransitionsWinOverAuthorImportant) {
2372   // First, simulate an "old style".
2373   TestCascade cascade1(GetDocument());
2374   cascade1.Add("width:10px !important");
2375   cascade1.Add("height:10px !important");
2376   cascade1.Add("transition:all 1s");
2377   cascade1.Apply();
2378 
2379   // Set the old style on the element, so that the animation
2380   // update detects it.
2381   GetDocument().body()->SetComputedStyle(cascade1.TakeStyle());
2382 
2383   // Now simulate a new style, with a new value for width/height.
2384   TestCascade cascade2(GetDocument());
2385   cascade2.Add("width:20px !important");
2386   cascade2.Add("height:20px !important");
2387   cascade2.Add("transition:all 1s");
2388   cascade2.Apply();
2389 
2390   cascade2.CalculateTransitionUpdate();
2391   cascade2.Apply();
2392 
2393   EXPECT_EQ(CascadeOrigin::kTransition,
2394             cascade2.GetPriority("width").GetOrigin());
2395   EXPECT_EQ(CascadeOrigin::kTransition,
2396             cascade2.GetPriority("height").GetOrigin());
2397 }
2398 
TEST_F(StyleCascadeTest,EmRespondsToAnimatedFontSize)2399 TEST_F(StyleCascadeTest, EmRespondsToAnimatedFontSize) {
2400   RegisterProperty(GetDocument(), "--x", "<length>", "0px", false);
2401 
2402   AppendSheet(R"HTML(
2403      @keyframes test {
2404         from { font-size: 10px; }
2405         to { font-size: 20px; }
2406      }
2407     )HTML");
2408 
2409   TestCascade cascade(GetDocument());
2410 
2411   cascade.Add("animation-name", "test");
2412   cascade.Add("animation-duration", "10s");
2413   cascade.Add("animation-timing-function", "linear");
2414   cascade.Add("animation-delay", "-5s");
2415   cascade.Add("--x", "2em");
2416   cascade.Add("width", "10em");
2417   cascade.Apply();
2418 
2419   cascade.CalculateAnimationUpdate();
2420   cascade.Apply();
2421 
2422   EXPECT_EQ("30px", cascade.ComputedValue("--x"));
2423   EXPECT_EQ("150px", cascade.ComputedValue("width"));
2424 }
2425 
TEST_F(StyleCascadeTest,AnimateStandardPropertyWithVar)2426 TEST_F(StyleCascadeTest, AnimateStandardPropertyWithVar) {
2427   RegisterProperty(GetDocument(), "--x", "<length>", "0px", false);
2428 
2429   AppendSheet(R"HTML(
2430      @keyframes test {
2431         from { width: var(--from); }
2432         to { width: var(--to); }
2433      }
2434     )HTML");
2435 
2436   TestCascade cascade(GetDocument());
2437 
2438   cascade.Add("animation-name", "test");
2439   cascade.Add("animation-duration", "10s");
2440   cascade.Add("animation-timing-function", "linear");
2441   cascade.Add("animation-delay", "-5s");
2442   cascade.Add("--from", "10px");
2443   cascade.Add("--to", "20px");
2444   cascade.Apply();
2445 
2446   cascade.CalculateAnimationUpdate();
2447   cascade.Apply();
2448 
2449   EXPECT_EQ("15px", cascade.ComputedValue("width"));
2450 }
2451 
TEST_F(StyleCascadeTest,AnimateStandardShorthand)2452 TEST_F(StyleCascadeTest, AnimateStandardShorthand) {
2453   RegisterProperty(GetDocument(), "--x", "<length>", "0px", false);
2454 
2455   AppendSheet(R"HTML(
2456      @keyframes test {
2457         from { margin: 10px; }
2458         to { margin: 20px; }
2459      }
2460     )HTML");
2461 
2462   TestCascade cascade(GetDocument());
2463 
2464   cascade.Add("animation-name", "test");
2465   cascade.Add("animation-duration", "10s");
2466   cascade.Add("animation-timing-function", "linear");
2467   cascade.Add("animation-delay", "-5s");
2468   cascade.Apply();
2469 
2470   cascade.CalculateAnimationUpdate();
2471   cascade.Apply();
2472 
2473   EXPECT_EQ(CascadeOrigin::kAnimation, cascade.GetOrigin("margin-top"));
2474   EXPECT_EQ(CascadeOrigin::kAnimation, cascade.GetOrigin("margin-right"));
2475   EXPECT_EQ(CascadeOrigin::kAnimation, cascade.GetOrigin("margin-bottom"));
2476   EXPECT_EQ(CascadeOrigin::kAnimation, cascade.GetOrigin("margin-left"));
2477 
2478   EXPECT_EQ("15px", cascade.ComputedValue("margin-top"));
2479   EXPECT_EQ("15px", cascade.ComputedValue("margin-right"));
2480   EXPECT_EQ("15px", cascade.ComputedValue("margin-bottom"));
2481   EXPECT_EQ("15px", cascade.ComputedValue("margin-left"));
2482 }
2483 
TEST_F(StyleCascadeTest,AnimatedVisitedImportantOverride)2484 TEST_F(StyleCascadeTest, AnimatedVisitedImportantOverride) {
2485   AppendSheet(R"HTML(
2486      @keyframes test {
2487         from { background-color: rgb(100, 100, 100); }
2488         to { background-color: rgb(200, 200, 200); }
2489      }
2490     )HTML");
2491 
2492   TestCascade cascade(GetDocument());
2493   cascade.State().Style()->SetInsideLink(EInsideLink::kInsideVisitedLink);
2494 
2495   cascade.Add(ParseDeclarationBlock("background-color:red !important"),
2496               CascadeOrigin::kAuthor, CSSSelector::kMatchVisited);
2497   cascade.Add("animation-name:test");
2498   cascade.Add("animation-duration:10s");
2499   cascade.Add("animation-timing-function:linear");
2500   cascade.Add("animation-delay:-5s");
2501   cascade.Apply();
2502 
2503   cascade.CalculateAnimationUpdate();
2504   cascade.Apply();
2505   EXPECT_EQ("rgb(150, 150, 150)", cascade.ComputedValue("background-color"));
2506 
2507   auto style = cascade.TakeStyle();
2508 
2509   style->SetInsideLink(EInsideLink::kInsideVisitedLink);
2510   EXPECT_EQ(Color(255, 0, 0),
2511             style->VisitedDependentColor(GetCSSPropertyBackgroundColor()));
2512 
2513   style->SetInsideLink(EInsideLink::kNotInsideLink);
2514   EXPECT_EQ(Color(150, 150, 150),
2515             style->VisitedDependentColor(GetCSSPropertyBackgroundColor()));
2516 }
2517 
TEST_F(StyleCascadeTest,AnimatedVisitedHighPrio)2518 TEST_F(StyleCascadeTest, AnimatedVisitedHighPrio) {
2519   AppendSheet(R"HTML(
2520      @keyframes test {
2521         from { color: rgb(100, 100, 100); }
2522         to { color: rgb(200, 200, 200); }
2523      }
2524     )HTML");
2525 
2526   TestCascade cascade(GetDocument());
2527   cascade.Add("color:red");
2528   cascade.Add("animation:test 10s -5s linear");
2529   cascade.Apply();
2530 
2531   cascade.CalculateAnimationUpdate();
2532   cascade.Apply();
2533   EXPECT_EQ("rgb(150, 150, 150)", cascade.ComputedValue("color"));
2534 
2535   auto style = cascade.TakeStyle();
2536 
2537   style->SetInsideLink(EInsideLink::kInsideVisitedLink);
2538   EXPECT_EQ(Color(150, 150, 150),
2539             style->VisitedDependentColor(GetCSSPropertyColor()));
2540 
2541   style->SetInsideLink(EInsideLink::kNotInsideLink);
2542   EXPECT_EQ(Color(150, 150, 150),
2543             style->VisitedDependentColor(GetCSSPropertyColor()));
2544 }
2545 
TEST_F(StyleCascadeTest,AnimatePendingSubstitutionValue)2546 TEST_F(StyleCascadeTest, AnimatePendingSubstitutionValue) {
2547   RegisterProperty(GetDocument(), "--x", "<length>", "0px", false);
2548 
2549   AppendSheet(R"HTML(
2550      @keyframes test {
2551         from { margin: var(--from); }
2552         to { margin: var(--to); }
2553      }
2554     )HTML");
2555 
2556   TestCascade cascade(GetDocument());
2557 
2558   cascade.Add("animation-name", "test");
2559   cascade.Add("animation-duration", "10s");
2560   cascade.Add("animation-timing-function", "linear");
2561   cascade.Add("animation-delay", "-5s");
2562   cascade.Add("--from", "10px");
2563   cascade.Add("--to", "20px");
2564   cascade.Apply();
2565 
2566   cascade.CalculateAnimationUpdate();
2567   cascade.Apply();
2568 
2569   EXPECT_EQ(CascadeOrigin::kAnimation, cascade.GetOrigin("margin-top"));
2570   EXPECT_EQ(CascadeOrigin::kAnimation, cascade.GetOrigin("margin-right"));
2571   EXPECT_EQ(CascadeOrigin::kAnimation, cascade.GetOrigin("margin-bottom"));
2572   EXPECT_EQ(CascadeOrigin::kAnimation, cascade.GetOrigin("margin-left"));
2573 
2574   EXPECT_EQ("15px", cascade.ComputedValue("margin-top"));
2575   EXPECT_EQ("15px", cascade.ComputedValue("margin-right"));
2576   EXPECT_EQ("15px", cascade.ComputedValue("margin-bottom"));
2577   EXPECT_EQ("15px", cascade.ComputedValue("margin-left"));
2578 }
2579 
TEST_F(StyleCascadeTest,ZoomCascadeOrder)2580 TEST_F(StyleCascadeTest, ZoomCascadeOrder) {
2581   TestCascade cascade(GetDocument());
2582   cascade.Add("zoom:200%", CascadeOrigin::kUserAgent);
2583   cascade.Add("zoom:normal", CascadeOrigin::kUserAgent);
2584   cascade.Apply();
2585 
2586   EXPECT_EQ(1.0f, cascade.TakeStyle()->EffectiveZoom());
2587 }
2588 
TEST_F(StyleCascadeTest,ZoomVsAll)2589 TEST_F(StyleCascadeTest, ZoomVsAll) {
2590   TestCascade cascade(GetDocument());
2591   cascade.Add("zoom:200%", CascadeOrigin::kUserAgent);
2592   cascade.Add("all:initial");
2593   cascade.Apply();
2594 
2595   EXPECT_EQ(1.0f, cascade.TakeStyle()->EffectiveZoom());
2596 }
2597 
TEST_F(StyleCascadeTest,ZoomReversedCascadeOrder)2598 TEST_F(StyleCascadeTest, ZoomReversedCascadeOrder) {
2599   TestCascade cascade(GetDocument());
2600   cascade.Add("zoom:normal", CascadeOrigin::kUserAgent);
2601   cascade.Add("zoom:200%", CascadeOrigin::kUserAgent);
2602   cascade.Apply();
2603 
2604   EXPECT_EQ(2.0f, cascade.TakeStyle()->EffectiveZoom());
2605 }
2606 
TEST_F(StyleCascadeTest,ZoomImportant)2607 TEST_F(StyleCascadeTest, ZoomImportant) {
2608   TestCascade cascade(GetDocument());
2609   cascade.Add("zoom:200% !important", CascadeOrigin::kUserAgent);
2610   cascade.Add("zoom:normal", CascadeOrigin::kAuthor);
2611   cascade.Apply();
2612 
2613   EXPECT_EQ(2.0f, cascade.TakeStyle()->EffectiveZoom());
2614 }
2615 
TEST_F(StyleCascadeTest,WritingModeCascadeOrder)2616 TEST_F(StyleCascadeTest, WritingModeCascadeOrder) {
2617   TestCascade cascade(GetDocument());
2618   cascade.Add("writing-mode", "vertical-lr");
2619   cascade.Add("-webkit-writing-mode", "vertical-rl");
2620   cascade.Apply();
2621 
2622   EXPECT_EQ("vertical-rl", cascade.ComputedValue("writing-mode"));
2623   EXPECT_EQ("vertical-rl", cascade.ComputedValue("-webkit-writing-mode"));
2624 }
2625 
TEST_F(StyleCascadeTest,WritingModeReversedCascadeOrder)2626 TEST_F(StyleCascadeTest, WritingModeReversedCascadeOrder) {
2627   TestCascade cascade(GetDocument());
2628   cascade.Add("-webkit-writing-mode", "vertical-rl");
2629   cascade.Add("writing-mode", "vertical-lr");
2630   cascade.Apply();
2631 
2632   EXPECT_EQ("vertical-lr", cascade.ComputedValue("writing-mode"));
2633   EXPECT_EQ("vertical-lr", cascade.ComputedValue("-webkit-writing-mode"));
2634 }
2635 
TEST_F(StyleCascadeTest,WritingModePriority)2636 TEST_F(StyleCascadeTest, WritingModePriority) {
2637   TestCascade cascade(GetDocument());
2638   cascade.Add("writing-mode:vertical-lr !important", Origin::kAuthor);
2639   cascade.Add("-webkit-writing-mode:vertical-rl", Origin::kAuthor);
2640   cascade.Apply();
2641 
2642   EXPECT_EQ("vertical-lr", cascade.ComputedValue("writing-mode"));
2643   EXPECT_EQ("vertical-lr", cascade.ComputedValue("-webkit-writing-mode"));
2644 }
2645 
TEST_F(StyleCascadeTest,RubyPositionCascadeOrder)2646 TEST_F(StyleCascadeTest, RubyPositionCascadeOrder) {
2647   TestCascade cascade(GetDocument());
2648   cascade.Add("ruby-position", "over");
2649   cascade.Add("-webkit-ruby-position", "after");
2650   cascade.Apply();
2651 
2652   EXPECT_EQ("under", cascade.ComputedValue("ruby-position"));
2653   EXPECT_EQ("after", cascade.ComputedValue("-webkit-ruby-position"));
2654 }
2655 
TEST_F(StyleCascadeTest,RubyPositionReverseCascadeOrder)2656 TEST_F(StyleCascadeTest, RubyPositionReverseCascadeOrder) {
2657   TestCascade cascade(GetDocument());
2658   cascade.Add("-webkit-ruby-position", "after");
2659   cascade.Add("ruby-position", "over");
2660   cascade.Apply();
2661 
2662   EXPECT_EQ("over", cascade.ComputedValue("ruby-position"));
2663   EXPECT_EQ("before", cascade.ComputedValue("-webkit-ruby-position"));
2664 }
2665 
TEST_F(StyleCascadeTest,RubyPositionSurrogateCanCascadeAsOriginal)2666 TEST_F(StyleCascadeTest, RubyPositionSurrogateCanCascadeAsOriginal) {
2667   // Note: ruby-position is defined as the surrogate, and -webkit-ruby-position
2668   // is the original.
2669   ASSERT_TRUE(GetCSSPropertyRubyPosition().IsSurrogate());
2670   ASSERT_FALSE(GetCSSPropertyWebkitRubyPosition().IsSurrogate());
2671 
2672   const struct {
2673     CSSValueID specified;
2674     const char* webkit_expected;
2675     const char* unprefixed_expected;
2676   } tests[] = {
2677       {CSSValueID::kBefore, "before", "over"},
2678       {CSSValueID::kAfter, "after", "under"},
2679       {CSSValueID::kOver, "before", "over"},
2680       {CSSValueID::kUnder, "after", "under"},
2681   };
2682 
2683   for (const auto& test : tests) {
2684     TestCascade cascade(GetDocument());
2685     auto* set =
2686         MakeGarbageCollected<MutableCSSPropertyValueSet>(kHTMLStandardMode);
2687     set->SetProperty(CSSPropertyID::kWebkitRubyPosition,
2688                      *CSSIdentifierValue::Create(test.specified));
2689     cascade.Add(set);
2690     cascade.Apply();
2691     EXPECT_EQ(test.unprefixed_expected, cascade.ComputedValue("ruby-position"));
2692     EXPECT_EQ(test.webkit_expected,
2693               cascade.ComputedValue("-webkit-ruby-position"));
2694   }
2695 }
2696 
TEST_F(StyleCascadeTest,TextOrientationPriority)2697 TEST_F(StyleCascadeTest, TextOrientationPriority) {
2698   TestCascade cascade(GetDocument());
2699   cascade.Add("text-orientation:upright !important");
2700   cascade.Add("-webkit-text-orientation:sideways");
2701   cascade.Apply();
2702 
2703   EXPECT_EQ("upright", cascade.ComputedValue("text-orientation"));
2704   EXPECT_EQ("upright", cascade.ComputedValue("-webkit-text-orientation"));
2705 }
2706 
TEST_F(StyleCascadeTest,TextOrientationRevert)2707 TEST_F(StyleCascadeTest, TextOrientationRevert) {
2708   TestCascade cascade(GetDocument());
2709   cascade.Add("text-orientation:upright", CascadeOrigin::kUserAgent);
2710   cascade.Add("-webkit-text-orientation:mixed");
2711   cascade.Add("-webkit-text-orientation:revert");
2712   cascade.Apply();
2713 
2714   EXPECT_EQ("upright", cascade.ComputedValue("text-orientation"));
2715   EXPECT_EQ("upright", cascade.ComputedValue("-webkit-text-orientation"));
2716 }
2717 
TEST_F(StyleCascadeTest,TextOrientationLegacyKeyword)2718 TEST_F(StyleCascadeTest, TextOrientationLegacyKeyword) {
2719   TestCascade cascade(GetDocument());
2720   cascade.Add("-webkit-text-orientation:vertical-right");
2721   cascade.Apply();
2722 
2723   EXPECT_EQ("mixed", cascade.ComputedValue("text-orientation"));
2724   EXPECT_EQ("vertical-right",
2725             cascade.ComputedValue("-webkit-text-orientation"));
2726 }
2727 
TEST_F(StyleCascadeTest,WebkitBorderImageCascadeOrder)2728 TEST_F(StyleCascadeTest, WebkitBorderImageCascadeOrder) {
2729   String gradient1("linear-gradient(rgb(0, 0, 0), rgb(0, 128, 0))");
2730   String gradient2("linear-gradient(rgb(0, 0, 0), rgb(0, 200, 0))");
2731 
2732   TestCascade cascade(GetDocument());
2733   cascade.Add("-webkit-border-image", gradient1 + " round 40 / 10px / 20px",
2734               Origin::kAuthor);
2735   cascade.Add("border-image-source", gradient2, Origin::kAuthor);
2736   cascade.Add("border-image-slice", "20", Origin::kAuthor);
2737   cascade.Add("border-image-width", "6px", Origin::kAuthor);
2738   cascade.Add("border-image-outset", "4px", Origin::kAuthor);
2739   cascade.Add("border-image-repeat", "space", Origin::kAuthor);
2740   cascade.Apply();
2741 
2742   EXPECT_EQ(gradient2, cascade.ComputedValue("border-image-source"));
2743   EXPECT_EQ("20", cascade.ComputedValue("border-image-slice"));
2744   EXPECT_EQ("6px", cascade.ComputedValue("border-image-width"));
2745   EXPECT_EQ("4px", cascade.ComputedValue("border-image-outset"));
2746   EXPECT_EQ("space", cascade.ComputedValue("border-image-repeat"));
2747 }
2748 
TEST_F(StyleCascadeTest,WebkitBorderImageReverseCascadeOrder)2749 TEST_F(StyleCascadeTest, WebkitBorderImageReverseCascadeOrder) {
2750   String gradient1("linear-gradient(rgb(0, 0, 0), rgb(0, 128, 0))");
2751   String gradient2("linear-gradient(rgb(0, 0, 0), rgb(0, 200, 0))");
2752 
2753   TestCascade cascade(GetDocument());
2754   cascade.Add("border-image-source", gradient2, Origin::kAuthor);
2755   cascade.Add("border-image-slice", "20", Origin::kAuthor);
2756   cascade.Add("border-image-width", "6px", Origin::kAuthor);
2757   cascade.Add("border-image-outset", "4px", Origin::kAuthor);
2758   cascade.Add("border-image-repeat", "space", Origin::kAuthor);
2759   cascade.Add("-webkit-border-image", gradient1 + " round 40 / 10px / 20px",
2760               Origin::kAuthor);
2761   cascade.Apply();
2762 
2763   EXPECT_EQ(gradient1, cascade.ComputedValue("border-image-source"));
2764   EXPECT_EQ("40 fill", cascade.ComputedValue("border-image-slice"));
2765   EXPECT_EQ("10px", cascade.ComputedValue("border-image-width"));
2766   EXPECT_EQ("20px", cascade.ComputedValue("border-image-outset"));
2767   EXPECT_EQ("round", cascade.ComputedValue("border-image-repeat"));
2768 }
2769 
TEST_F(StyleCascadeTest,WebkitBorderImageMixedOrder)2770 TEST_F(StyleCascadeTest, WebkitBorderImageMixedOrder) {
2771   String gradient1("linear-gradient(rgb(0, 0, 0), rgb(0, 128, 0))");
2772   String gradient2("linear-gradient(rgb(0, 0, 0), rgb(0, 200, 0))");
2773 
2774   TestCascade cascade(GetDocument());
2775   cascade.Add("border-image-source", gradient2, Origin::kAuthor);
2776   cascade.Add("border-image-width", "6px", Origin::kAuthor);
2777   cascade.Add("-webkit-border-image", gradient1 + " round 40 / 10px / 20px",
2778               Origin::kAuthor);
2779   cascade.Add("border-image-slice", "20", Origin::kAuthor);
2780   cascade.Add("border-image-outset", "4px", Origin::kAuthor);
2781   cascade.Add("border-image-repeat", "space", Origin::kAuthor);
2782   cascade.Apply();
2783 
2784   EXPECT_EQ(gradient1, cascade.ComputedValue("border-image-source"));
2785   EXPECT_EQ("20", cascade.ComputedValue("border-image-slice"));
2786   EXPECT_EQ("10px", cascade.ComputedValue("border-image-width"));
2787   EXPECT_EQ("4px", cascade.ComputedValue("border-image-outset"));
2788   EXPECT_EQ("space", cascade.ComputedValue("border-image-repeat"));
2789 }
2790 
TEST_F(StyleCascadeTest,InitialDirection)2791 TEST_F(StyleCascadeTest, InitialDirection) {
2792   TestCascade cascade(GetDocument());
2793   cascade.Add("margin-inline-start:10px");
2794   cascade.Add("margin-inline-end:20px");
2795   cascade.Apply();
2796 
2797   EXPECT_EQ("10px", cascade.ComputedValue("margin-left"));
2798   EXPECT_EQ("20px", cascade.ComputedValue("margin-right"));
2799 }
2800 
TEST_F(StyleCascadeTest,NonInitialDirection)2801 TEST_F(StyleCascadeTest, NonInitialDirection) {
2802   TestCascade cascade(GetDocument());
2803   cascade.Add("margin-inline-start:10px");
2804   cascade.Add("margin-inline-end:20px");
2805   cascade.Add("direction:rtl");
2806   cascade.Apply();
2807 
2808   EXPECT_EQ("20px", cascade.ComputedValue("margin-left"));
2809   EXPECT_EQ("10px", cascade.ComputedValue("margin-right"));
2810 }
2811 
TEST_F(StyleCascadeTest,InitialWritingMode)2812 TEST_F(StyleCascadeTest, InitialWritingMode) {
2813   TestCascade cascade(GetDocument());
2814   cascade.Add("inline-size:10px");
2815   cascade.Add("block-size:20px");
2816   cascade.Apply();
2817 
2818   EXPECT_EQ("10px", cascade.ComputedValue("width"));
2819   EXPECT_EQ("20px", cascade.ComputedValue("height"));
2820 }
2821 
TEST_F(StyleCascadeTest,NonInitialWritingMode)2822 TEST_F(StyleCascadeTest, NonInitialWritingMode) {
2823   TestCascade cascade(GetDocument());
2824   cascade.Add("inline-size:10px");
2825   cascade.Add("block-size:20px");
2826   cascade.Add("writing-mode:vertical-lr");
2827   cascade.Apply();
2828 
2829   EXPECT_EQ("20px", cascade.ComputedValue("width"));
2830   EXPECT_EQ("10px", cascade.ComputedValue("height"));
2831 }
2832 
TEST_F(StyleCascadeTest,DoesNotDependOnCascadeAffectingProperty)2833 TEST_F(StyleCascadeTest, DoesNotDependOnCascadeAffectingProperty) {
2834   TestCascade cascade(GetDocument());
2835   cascade.Add("width:10px");
2836   cascade.Add("height:20px");
2837   cascade.Apply();
2838 
2839   EXPECT_FALSE(cascade.DependsOnCascadeAffectingProperty());
2840   EXPECT_EQ("10px", cascade.ComputedValue("width"));
2841   EXPECT_EQ("20px", cascade.ComputedValue("height"));
2842 }
2843 
TEST_F(StyleCascadeTest,DependsOnCascadeAffectingProperty)2844 TEST_F(StyleCascadeTest, DependsOnCascadeAffectingProperty) {
2845   TestCascade cascade(GetDocument());
2846   cascade.Add("inline-size:10px");
2847   cascade.Add("height:20px");
2848   cascade.Apply();
2849 
2850   EXPECT_TRUE(cascade.DependsOnCascadeAffectingProperty());
2851   EXPECT_EQ("10px", cascade.ComputedValue("width"));
2852   EXPECT_EQ("20px", cascade.ComputedValue("height"));
2853 }
2854 
TEST_F(StyleCascadeTest,ResetDependsOnCascadeAffectingPropertyFlag)2855 TEST_F(StyleCascadeTest, ResetDependsOnCascadeAffectingPropertyFlag) {
2856   TestCascade cascade(GetDocument());
2857   cascade.Add("inline-size:10px");
2858   cascade.Add("height:20px");
2859   cascade.Apply();
2860 
2861   EXPECT_TRUE(cascade.DependsOnCascadeAffectingProperty());
2862   cascade.Reset();
2863   EXPECT_FALSE(cascade.DependsOnCascadeAffectingProperty());
2864 }
2865 
TEST_F(StyleCascadeTest,MarkReferenced)2866 TEST_F(StyleCascadeTest, MarkReferenced) {
2867   RegisterProperty(GetDocument(), "--x", "<length>", "0px", false);
2868   RegisterProperty(GetDocument(), "--y", "<length>", "0px", false);
2869 
2870   TestCascade cascade(GetDocument());
2871   cascade.Add("width", "var(--x)");
2872   cascade.Apply();
2873 
2874   const auto& registry = GetDocument().EnsurePropertyRegistry();
2875 
2876   EXPECT_TRUE(registry.WasReferenced("--x"));
2877   EXPECT_FALSE(registry.WasReferenced("--y"));
2878 }
2879 
TEST_F(StyleCascadeTest,MarkHasVariableReferenceLonghand)2880 TEST_F(StyleCascadeTest, MarkHasVariableReferenceLonghand) {
2881   TestCascade cascade(GetDocument());
2882   cascade.Add("--x", "1px");
2883   cascade.Add("width", "var(--x)");
2884   cascade.Apply();
2885   auto style = cascade.TakeStyle();
2886   EXPECT_TRUE(style->HasVariableReferenceFromNonInheritedProperty());
2887 }
2888 
TEST_F(StyleCascadeTest,MarkHasVariableReferenceShorthand)2889 TEST_F(StyleCascadeTest, MarkHasVariableReferenceShorthand) {
2890   TestCascade cascade(GetDocument());
2891   cascade.Add("--x", "1px");
2892   cascade.Add("margin", "var(--x)");
2893   cascade.Apply();
2894   auto style = cascade.TakeStyle();
2895   EXPECT_TRUE(style->HasVariableReferenceFromNonInheritedProperty());
2896 }
2897 
TEST_F(StyleCascadeTest,MarkHasVariableReferenceLonghandMissingVar)2898 TEST_F(StyleCascadeTest, MarkHasVariableReferenceLonghandMissingVar) {
2899   TestCascade cascade(GetDocument());
2900   cascade.Add("width", "var(--x)");
2901   cascade.Apply();
2902   auto style = cascade.TakeStyle();
2903   EXPECT_TRUE(style->HasVariableReferenceFromNonInheritedProperty());
2904 }
2905 
TEST_F(StyleCascadeTest,MarkHasVariableReferenceShorthandMissingVar)2906 TEST_F(StyleCascadeTest, MarkHasVariableReferenceShorthandMissingVar) {
2907   TestCascade cascade(GetDocument());
2908   cascade.Add("margin", "var(--x)");
2909   cascade.Apply();
2910   auto style = cascade.TakeStyle();
2911   EXPECT_TRUE(style->HasVariableReferenceFromNonInheritedProperty());
2912 }
2913 
TEST_F(StyleCascadeTest,NoMarkHasVariableReferenceInherited)2914 TEST_F(StyleCascadeTest, NoMarkHasVariableReferenceInherited) {
2915   TestCascade cascade(GetDocument());
2916   cascade.Add("color", "var(--x)");
2917   cascade.Apply();
2918   auto style = cascade.TakeStyle();
2919   EXPECT_FALSE(style->HasVariableReferenceFromNonInheritedProperty());
2920 }
2921 
TEST_F(StyleCascadeTest,NoMarkHasVariableReferenceWithoutVar)2922 TEST_F(StyleCascadeTest, NoMarkHasVariableReferenceWithoutVar) {
2923   TestCascade cascade(GetDocument());
2924   cascade.Add("width", "1px");
2925   cascade.Apply();
2926   auto style = cascade.TakeStyle();
2927   EXPECT_FALSE(style->HasVariableReferenceFromNonInheritedProperty());
2928 }
2929 
TEST_F(StyleCascadeTest,InternalVisitedColorLonghand)2930 TEST_F(StyleCascadeTest, InternalVisitedColorLonghand) {
2931   TestCascade cascade(GetDocument());
2932   cascade.Add("color:green", CascadeOrigin::kAuthor);
2933   cascade.Add("color:red", CascadeOrigin::kAuthor, CSSSelector::kMatchVisited);
2934 
2935   cascade.State().Style()->SetInsideLink(EInsideLink::kInsideVisitedLink);
2936   cascade.Apply();
2937 
2938   EXPECT_EQ("rgb(0, 128, 0)", cascade.ComputedValue("color"));
2939 
2940   Color red(255, 0, 0);
2941   const CSSProperty& color = GetCSSPropertyColor();
2942   EXPECT_EQ(red, cascade.TakeStyle()->VisitedDependentColor(color));
2943 }
2944 
TEST_F(StyleCascadeTest,VarInInternalVisitedColorShorthand)2945 TEST_F(StyleCascadeTest, VarInInternalVisitedColorShorthand) {
2946   TestCascade cascade(GetDocument());
2947   cascade.Add("--x:red", CascadeOrigin::kAuthor);
2948   cascade.Add("outline:medium solid var(--x)", CascadeOrigin::kAuthor,
2949               CSSSelector::kMatchVisited);
2950   cascade.Add("outline-color:green", CascadeOrigin::kAuthor,
2951               CSSSelector::kMatchLink);
2952 
2953   cascade.State().Style()->SetInsideLink(EInsideLink::kInsideVisitedLink);
2954   cascade.Apply();
2955 
2956   EXPECT_EQ("rgb(0, 128, 0)", cascade.ComputedValue("outline-color"));
2957 
2958   Color red(255, 0, 0);
2959   const CSSProperty& outline_color = GetCSSPropertyOutlineColor();
2960   EXPECT_EQ(red, cascade.TakeStyle()->VisitedDependentColor(outline_color));
2961 }
2962 
TEST_F(StyleCascadeTest,ApplyWithFilter)2963 TEST_F(StyleCascadeTest, ApplyWithFilter) {
2964   TestCascade cascade(GetDocument());
2965   cascade.Add("color", "blue", Origin::kAuthor);
2966   cascade.Add("background-color", "green", Origin::kAuthor);
2967   cascade.Add("display", "inline", Origin::kAuthor);
2968   cascade.Apply();
2969 
2970   cascade.Reset();
2971   cascade.Add("color", "green", Origin::kAuthor);
2972   cascade.Add("background-color", "red", Origin::kAuthor);
2973   cascade.Add("display", "block", Origin::kAuthor);
2974   cascade.Apply(CascadeFilter(CSSProperty::kInherited, false));
2975   EXPECT_EQ("rgb(0, 128, 0)", cascade.ComputedValue("color"));
2976   EXPECT_EQ("rgb(0, 128, 0)", cascade.ComputedValue("background-color"));
2977   EXPECT_EQ("inline", cascade.ComputedValue("display"));
2978 }
2979 
TEST_F(StyleCascadeTest,HasAuthorBackground)2980 TEST_F(StyleCascadeTest, HasAuthorBackground) {
2981   Vector<String> properties = {"background-attachment", "background-blend-mode",
2982                                "background-clip",       "background-image",
2983                                "background-origin",     "background-position-x",
2984                                "background-position-y", "background-size"};
2985 
2986   for (String property : properties) {
2987     TestCascade cascade(GetDocument());
2988     cascade.Add("-webkit-appearance", "button", Origin::kUserAgent);
2989     cascade.Add(property, "unset", Origin::kAuthor);
2990     cascade.Apply();
2991     EXPECT_TRUE(cascade.TakeStyle()->HasAuthorBackground());
2992   }
2993 }
2994 
TEST_F(StyleCascadeTest,HasAuthorBorder)2995 TEST_F(StyleCascadeTest, HasAuthorBorder) {
2996   Vector<String> properties = {
2997       "border-top-color",          "border-right-color",
2998       "border-bottom-color",       "border-left-color",
2999       "border-top-style",          "border-right-style",
3000       "border-bottom-style",       "border-left-style",
3001       "border-top-width",          "border-right-width",
3002       "border-bottom-width",       "border-left-width",
3003       "border-top-left-radius",    "border-top-right-radius",
3004       "border-bottom-left-radius", "border-bottom-right-radius",
3005       "border-image-source",       "border-image-slice",
3006       "border-image-width",        "border-image-outset",
3007       "border-image-repeat"};
3008 
3009   for (String property : properties) {
3010     TestCascade cascade(GetDocument());
3011     cascade.Add("-webkit-appearance", "button", Origin::kUserAgent);
3012     cascade.Add(property, "unset", Origin::kAuthor);
3013     cascade.Apply();
3014     EXPECT_TRUE(cascade.TakeStyle()->HasAuthorBorder());
3015   }
3016 }
3017 
TEST_F(StyleCascadeTest,HasAuthorBorderLogical)3018 TEST_F(StyleCascadeTest, HasAuthorBorderLogical) {
3019   TestCascade cascade(GetDocument());
3020   cascade.Add("-webkit-appearance", "button", Origin::kUserAgent);
3021   cascade.Add("border-block-start-color", "red", Origin::kUserAgent);
3022   cascade.Add("border-block-start-color", "green", Origin::kAuthor);
3023   cascade.Apply();
3024   auto style = cascade.TakeStyle();
3025   EXPECT_TRUE(style->HasAuthorBorder());
3026 }
3027 
TEST_F(StyleCascadeTest,NoAuthorBackgroundOrBorder)3028 TEST_F(StyleCascadeTest, NoAuthorBackgroundOrBorder) {
3029   TestCascade cascade(GetDocument());
3030   cascade.Add("-webkit-appearance", "button", Origin::kUserAgent);
3031   cascade.Add("background-color", "red", Origin::kUserAgent);
3032   cascade.Add("border-left-color", "green", Origin::kUserAgent);
3033   cascade.Add("background-clip", "padding-box", Origin::kUser);
3034   cascade.Add("border-right-color", "green", Origin::kUser);
3035   cascade.Apply();
3036   auto style = cascade.TakeStyle();
3037   EXPECT_FALSE(style->HasAuthorBackground());
3038   EXPECT_FALSE(style->HasAuthorBorder());
3039 }
3040 
TEST_F(StyleCascadeTest,AuthorBackgroundRevert)3041 TEST_F(StyleCascadeTest, AuthorBackgroundRevert) {
3042   TestCascade cascade(GetDocument());
3043   cascade.Add("-webkit-appearance", "button", Origin::kUserAgent);
3044   cascade.Add("background-color", "red", Origin::kUserAgent);
3045   cascade.Add("background-color", "revert", Origin::kAuthor);
3046   cascade.Apply();
3047   auto style = cascade.TakeStyle();
3048   EXPECT_FALSE(style->HasAuthorBackground());
3049 }
3050 
TEST_F(StyleCascadeTest,AuthorBorderRevert)3051 TEST_F(StyleCascadeTest, AuthorBorderRevert) {
3052   TestCascade cascade(GetDocument());
3053   cascade.Add("-webkit-appearance", "button", Origin::kUserAgent);
3054   cascade.Add("border-top-color", "red", Origin::kUserAgent);
3055   cascade.Add("border-top-color", "revert", Origin::kAuthor);
3056   cascade.Apply();
3057   auto style = cascade.TakeStyle();
3058   EXPECT_FALSE(style->HasAuthorBorder());
3059 }
3060 
TEST_F(StyleCascadeTest,AuthorBorderRevertLogical)3061 TEST_F(StyleCascadeTest, AuthorBorderRevertLogical) {
3062   TestCascade cascade(GetDocument());
3063   cascade.Add("-webkit-appearance", "button", Origin::kUserAgent);
3064   cascade.Add("border-block-start-color", "red", Origin::kUserAgent);
3065   cascade.Add("border-block-start-color", "revert", Origin::kAuthor);
3066   cascade.Apply();
3067   auto style = cascade.TakeStyle();
3068   EXPECT_FALSE(style->HasAuthorBorder());
3069 }
3070 
TEST_F(StyleCascadeTest,AnalyzeMatchResult)3071 TEST_F(StyleCascadeTest, AnalyzeMatchResult) {
3072   auto ua = CascadeOrigin::kUserAgent;
3073   auto author = CascadeOrigin::kAuthor;
3074 
3075   TestCascade cascade(GetDocument());
3076   cascade.Add("display:none;left:5px", ua);
3077   cascade.Add("font-size:1px !important", ua);
3078   cascade.Add("display:block;color:red", author);
3079   cascade.Add("font-size:3px", author);
3080   cascade.Apply();
3081 
3082   EXPECT_EQ(cascade.GetPriority("display").GetOrigin(), author);
3083   EXPECT_EQ(cascade.GetPriority("left").GetOrigin(), ua);
3084   EXPECT_EQ(cascade.GetPriority("color").GetOrigin(), author);
3085   EXPECT_EQ(cascade.GetPriority("font-size").GetOrigin(), ua);
3086 }
3087 
TEST_F(StyleCascadeTest,AnalyzeMatchResultAll)3088 TEST_F(StyleCascadeTest, AnalyzeMatchResultAll) {
3089   auto ua = CascadeOrigin::kUserAgent;
3090   auto author = CascadeOrigin::kAuthor;
3091 
3092   TestCascade cascade(GetDocument());
3093   cascade.Add("display:block", ua);
3094   cascade.Add("font-size:1px !important", ua);
3095   cascade.Add("all:unset", author);
3096   cascade.Apply();
3097 
3098   EXPECT_EQ(cascade.GetPriority("display").GetOrigin(), author);
3099   EXPECT_EQ(cascade.GetPriority("font-size").GetOrigin(), ua);
3100 
3101   // Random sample from another property affected by 'all'.
3102   EXPECT_EQ(cascade.GetPriority("color").GetOrigin(), author);
3103   EXPECT_EQ(cascade.GetPriority("color"), cascade.GetPriority("display"));
3104 }
3105 
TEST_F(StyleCascadeTest,AnalyzeFlagsClean)3106 TEST_F(StyleCascadeTest, AnalyzeFlagsClean) {
3107   AppendSheet(R"HTML(
3108      @keyframes test {
3109         from { top: 0px; }
3110         to { top: 10px; }
3111      }
3112     )HTML");
3113 
3114   TestCascade cascade(GetDocument());
3115 
3116   cascade.Add("bottom:10px");
3117   cascade.Add("animation:test linear 1000s -500s");
3118   cascade.Apply();
3119   EXPECT_FALSE(cascade.NeedsMatchResultAnalyze());
3120   EXPECT_FALSE(cascade.NeedsInterpolationsAnalyze());
3121 
3122   cascade.CalculateAnimationUpdate();
3123   cascade.Apply();
3124   EXPECT_FALSE(cascade.NeedsMatchResultAnalyze());
3125   EXPECT_FALSE(cascade.NeedsInterpolationsAnalyze());
3126 }
3127 
TEST_F(StyleCascadeTest,ApplyMatchResultFilter)3128 TEST_F(StyleCascadeTest, ApplyMatchResultFilter) {
3129   TestCascade cascade(GetDocument());
3130   cascade.Add("display:block");
3131   cascade.Add("color:green");
3132   cascade.Add("font-size:3px");
3133   cascade.Apply();
3134 
3135   cascade.Reset();
3136   cascade.Add("display:inline");
3137   cascade.Add("color:red");
3138   cascade.Apply(CascadeFilter(CSSProperty::kInherited, true));
3139 
3140   EXPECT_EQ("inline", cascade.ComputedValue("display"));
3141   EXPECT_EQ("rgb(0, 128, 0)", cascade.ComputedValue("color"));
3142   EXPECT_EQ("3px", cascade.ComputedValue("font-size"));
3143 }
3144 
TEST_F(StyleCascadeTest,ApplyMatchResultAllFilter)3145 TEST_F(StyleCascadeTest, ApplyMatchResultAllFilter) {
3146   TestCascade cascade(GetDocument());
3147   cascade.Add("color:green");
3148   cascade.Add("display:block");
3149   cascade.Apply();
3150 
3151   cascade.Reset();
3152   cascade.Add("all:unset");
3153   cascade.Apply(CascadeFilter(CSSProperty::kInherited, true));
3154 
3155   EXPECT_EQ("rgb(0, 128, 0)", cascade.ComputedValue("color"));
3156   EXPECT_EQ("inline", cascade.ComputedValue("display"));
3157 }
3158 
TEST_F(StyleCascadeTest,MarkHasReferenceLonghand)3159 TEST_F(StyleCascadeTest, MarkHasReferenceLonghand) {
3160   TestCascade cascade(GetDocument());
3161 
3162   cascade.Add("--x:red");
3163   cascade.Add("background-color:var(--x)");
3164   cascade.Apply();
3165 
3166   EXPECT_TRUE(cascade.State()
3167                   .StyleRef()
3168                   .HasVariableReferenceFromNonInheritedProperty());
3169 }
3170 
TEST_F(StyleCascadeTest,MarkHasReferenceShorthand)3171 TEST_F(StyleCascadeTest, MarkHasReferenceShorthand) {
3172   TestCascade cascade(GetDocument());
3173 
3174   cascade.Add("--x:red");
3175   cascade.Add("background:var(--x)");
3176   cascade.Apply();
3177 
3178   EXPECT_TRUE(cascade.State()
3179                   .StyleRef()
3180                   .HasVariableReferenceFromNonInheritedProperty());
3181 }
3182 
TEST_F(StyleCascadeTest,NoMarkHasReferenceForInherited)3183 TEST_F(StyleCascadeTest, NoMarkHasReferenceForInherited) {
3184   TestCascade cascade(GetDocument());
3185 
3186   cascade.Add("--x:red");
3187   cascade.Add("--y:caption");
3188   cascade.Add("color:var(--x)");
3189   cascade.Add("font:var(--y)");
3190   cascade.Apply();
3191 
3192   EXPECT_FALSE(cascade.State()
3193                    .StyleRef()
3194                    .HasVariableReferenceFromNonInheritedProperty());
3195 }
3196 
TEST_F(StyleCascadeTest,Reset)3197 TEST_F(StyleCascadeTest, Reset) {
3198   TestCascade cascade(GetDocument());
3199 
3200   EXPECT_EQ(CascadePriority(), cascade.GetPriority("color"));
3201   EXPECT_EQ(CascadePriority(), cascade.GetPriority("--x"));
3202 
3203   cascade.Add("color:red");
3204   cascade.Add("--x:red");
3205   cascade.Apply();  // generation=1
3206   cascade.Apply();  // generation=2
3207 
3208   EXPECT_EQ(2u, cascade.GetPriority("color").GetGeneration());
3209   EXPECT_EQ(2u, cascade.GetPriority("--x").GetGeneration());
3210 
3211   cascade.Reset();
3212 
3213   EXPECT_EQ(CascadePriority(), cascade.GetPriority("color"));
3214   EXPECT_EQ(CascadePriority(), cascade.GetPriority("--x"));
3215 }
3216 
TEST_F(StyleCascadeTest,GetImportantSetEmpty)3217 TEST_F(StyleCascadeTest, GetImportantSetEmpty) {
3218   TestCascade cascade(GetDocument());
3219   cascade.Add("color:red");
3220   cascade.Add("width:1px");
3221   cascade.Add("--x:green");
3222   EXPECT_FALSE(cascade.GetImportantSet());
3223 }
3224 
TEST_F(StyleCascadeTest,GetImportantSetSingle)3225 TEST_F(StyleCascadeTest, GetImportantSetSingle) {
3226   TestCascade cascade(GetDocument());
3227   cascade.Add("width:1px !important");
3228   ASSERT_TRUE(cascade.GetImportantSet());
3229   EXPECT_EQ(CSSBitset({CSSPropertyID::kWidth}), *cascade.GetImportantSet());
3230 }
3231 
TEST_F(StyleCascadeTest,GetImportantSetMany)3232 TEST_F(StyleCascadeTest, GetImportantSetMany) {
3233   TestCascade cascade(GetDocument());
3234   cascade.Add("width:1px !important");
3235   cascade.Add("height:1px !important");
3236   cascade.Add("top:1px !important");
3237   ASSERT_TRUE(cascade.GetImportantSet());
3238   EXPECT_EQ(CSSBitset({CSSPropertyID::kWidth, CSSPropertyID::kHeight,
3239                        CSSPropertyID::kTop}),
3240             *cascade.GetImportantSet());
3241 }
3242 
TEST_F(StyleCascadeTest,NoDependenciesPresent)3243 TEST_F(StyleCascadeTest, NoDependenciesPresent) {
3244   TestCascade cascade(GetDocument());
3245   cascade.Add("left:2px");
3246   cascade.Add("top:initial");
3247   cascade.Add("border:1px solid black");
3248   cascade.Add("--x:bar");
3249   cascade.Add("direction:rtl");
3250   cascade.Apply();
3251   const auto& state = cascade.State();
3252   EXPECT_TRUE(state.Dependencies().IsEmpty());
3253   EXPECT_FALSE(state.HasIncomparableDependency());
3254 }
3255 
TEST_F(StyleCascadeTest,ExplicitInheritanceDependencyIsDetected)3256 TEST_F(StyleCascadeTest, ExplicitInheritanceDependencyIsDetected) {
3257   TestCascade cascade(GetDocument());
3258   cascade.Add("left:inherit");
3259   cascade.Add("right:inherit");
3260   cascade.Apply();
3261   const auto& state = cascade.State();
3262   EXPECT_EQ(2u, state.Dependencies().size());
3263   EXPECT_TRUE(state.Dependencies().Contains(PropertyName("left")));
3264   EXPECT_TRUE(state.Dependencies().Contains(PropertyName("right")));
3265   EXPECT_FALSE(state.HasIncomparableDependency());
3266 }
3267 
TEST_F(StyleCascadeTest,IncomparableDependencyDetected)3268 TEST_F(StyleCascadeTest, IncomparableDependencyDetected) {
3269   ASSERT_FALSE(
3270       GetCSSPropertyInternalEmptyLineHeight().IsComputedValueComparable());
3271 
3272   TestCascade cascade(GetDocument());
3273   cascade.Add("-internal-empty-line-height:inherit", CascadeOrigin::kUserAgent);
3274   cascade.Apply();
3275   const auto& state = cascade.State();
3276   EXPECT_EQ(1u, state.Dependencies().size());
3277   EXPECT_TRUE(state.Dependencies().Contains(
3278       CSSPropertyName(CSSPropertyID::kInternalEmptyLineHeight)));
3279   EXPECT_TRUE(state.HasIncomparableDependency());
3280 }
3281 
TEST_F(StyleCascadeTest,CustomPropertyDependencyIsDetected)3282 TEST_F(StyleCascadeTest, CustomPropertyDependencyIsDetected) {
3283   TestCascade cascade(GetDocument());
3284   cascade.Add("left:var(--x,1px)");
3285   cascade.Add("right:var(--x,2px)");
3286   cascade.Apply();
3287   const auto& state = cascade.State();
3288   EXPECT_EQ(1u, state.Dependencies().size());
3289   EXPECT_TRUE(state.Dependencies().Contains(PropertyName("--x")));
3290   EXPECT_FALSE(state.HasIncomparableDependency());
3291 }
3292 
TEST_F(StyleCascadeTest,NonInheritedCustomPropertyIsNoDependency)3293 TEST_F(StyleCascadeTest, NonInheritedCustomPropertyIsNoDependency) {
3294   RegisterProperty(GetDocument(), "--x", "<length>", "0px", false);
3295   TestCascade cascade(GetDocument());
3296   cascade.Add("left:var(--x,1px)");
3297   cascade.Add("right:var(--x,2px)");
3298   cascade.Apply();
3299   const auto& state = cascade.State();
3300   EXPECT_EQ(0u, state.Dependencies().size());
3301 }
3302 
TEST_F(StyleCascadeTest,DirectionAndWritingModeDependenciesAreDetected)3303 TEST_F(StyleCascadeTest, DirectionAndWritingModeDependenciesAreDetected) {
3304   TestCascade cascade(GetDocument());
3305   cascade.Add("margin-inline-start: 2px");
3306   cascade.Apply();
3307   const auto& state = cascade.State();
3308   EXPECT_EQ(2u, state.Dependencies().size());
3309   EXPECT_TRUE(state.Dependencies().Contains(PropertyName("direction")));
3310   EXPECT_TRUE(state.Dependencies().Contains(PropertyName("writing-mode")));
3311   EXPECT_FALSE(state.HasIncomparableDependency());
3312 }
3313 
TEST_F(StyleCascadeTest,RootColorNotModifiedByEmptyCascade)3314 TEST_F(StyleCascadeTest, RootColorNotModifiedByEmptyCascade) {
3315   TestCascade cascade(GetDocument(), GetDocument().documentElement());
3316   cascade.Add("color:red");
3317   cascade.Apply();
3318 
3319   cascade.Reset();
3320   cascade.Add("display:block");
3321   cascade.Apply();  // Should not affect 'color'.
3322 
3323   auto style = cascade.TakeStyle();
3324 
3325   style->SetInsideLink(EInsideLink::kInsideVisitedLink);
3326   EXPECT_EQ(Color(255, 0, 0),
3327             style->VisitedDependentColor(GetCSSPropertyColor()));
3328 
3329   style->SetInsideLink(EInsideLink::kNotInsideLink);
3330   EXPECT_EQ(Color(255, 0, 0),
3331             style->VisitedDependentColor(GetCSSPropertyColor()));
3332 }
3333 
TEST_F(StyleCascadeTest,InitialColor)3334 TEST_F(StyleCascadeTest, InitialColor) {
3335   ColorSchemeHelper color_scheme_helper(GetDocument());
3336   color_scheme_helper.SetPreferredColorScheme(
3337       mojom::blink::PreferredColorScheme::kDark);
3338 
3339   TestCascade cascade(GetDocument(), GetDocument().documentElement());
3340   cascade.Add("color-scheme:dark");
3341 
3342   // CSSInitialColorValue is not reachable via a string, hence we must
3343   // create the CSSPropertyValueSet that contains it manually.
3344   auto* set =
3345       MakeGarbageCollected<MutableCSSPropertyValueSet>(kHTMLStandardMode);
3346   set->SetProperty(CSSPropertyID::kColor, *CSSInitialColorValue::Create());
3347   cascade.Add(set);
3348 
3349   cascade.Apply();
3350 
3351   auto style = cascade.TakeStyle();
3352 
3353   style->SetInsideLink(EInsideLink::kInsideVisitedLink);
3354   EXPECT_EQ(Color::kWhite, style->VisitedDependentColor(GetCSSPropertyColor()));
3355 
3356   style->SetInsideLink(EInsideLink::kNotInsideLink);
3357   EXPECT_EQ(Color::kWhite, style->VisitedDependentColor(GetCSSPropertyColor()));
3358 }
3359 
TEST_F(StyleCascadeTest,MaxSubstitutionTokens)3360 TEST_F(StyleCascadeTest, MaxSubstitutionTokens) {
3361   StringBuilder builder;
3362   for (size_t i = 0; i < StyleCascade::kMaxSubstitutionTokens; ++i)
3363     builder.Append(':');  // <colon-token>
3364 
3365   String at_limit = builder.ToString();
3366   String above_limit = builder.ToString() + ":";
3367 
3368   TestCascade cascade(GetDocument());
3369   cascade.Add("--at-limit", at_limit);
3370   cascade.Add("--above-limit", above_limit);
3371   cascade.Add("--at-limit-reference", "var(--at-limit)");
3372   cascade.Add("--above-limit-reference", "var(--above-limit)");
3373   cascade.Add("--at-limit-reference-fallback",
3374               "var(--unknown,var(--at-limit))");
3375   cascade.Add("--above-limit-reference-fallback",
3376               "var(--unknown,var(--above-limit))");
3377   cascade.Apply();
3378 
3379   EXPECT_EQ(at_limit, cascade.ComputedValue("--at-limit"));
3380   EXPECT_EQ(above_limit, cascade.ComputedValue("--above-limit"));
3381   EXPECT_EQ(at_limit, cascade.ComputedValue("--at-limit-reference"));
3382   EXPECT_EQ(g_null_atom, cascade.ComputedValue("--above-limit-reference"));
3383   EXPECT_EQ(at_limit, cascade.ComputedValue("--at-limit-reference-fallback"));
3384   EXPECT_EQ(g_null_atom,
3385             cascade.ComputedValue("--above-limit-reference-fallback"));
3386 }
3387 
TEST_F(StyleCascadeTest,UseCountSummary)3388 TEST_F(StyleCascadeTest, UseCountSummary) {
3389   const auto feature = WebFeature::kSummaryElementWithDisplayBlockAuthorRule;
3390 
3391   Element* summary = GetDocument().CreateRawElement(html_names::kSummaryTag);
3392   GetDocument().body()->AppendChild(summary);
3393 
3394   {
3395     ASSERT_FALSE(GetDocument().IsUseCounted(feature));
3396 
3397     TestCascade cascade(GetDocument(), summary);
3398     cascade.Apply();
3399     EXPECT_FALSE(GetDocument().IsUseCounted(feature));
3400   }
3401   {
3402     ASSERT_FALSE(GetDocument().IsUseCounted(feature));
3403 
3404     TestCascade cascade(GetDocument(), summary);
3405     cascade.Add("color:green");
3406     cascade.Apply();
3407     EXPECT_FALSE(GetDocument().IsUseCounted(feature));
3408   }
3409   {
3410     ASSERT_FALSE(GetDocument().IsUseCounted(feature));
3411 
3412     TestCascade cascade(GetDocument(), summary);
3413     cascade.Add("display:block", CascadeOrigin::kUserAgent);
3414     cascade.Apply();
3415     EXPECT_FALSE(GetDocument().IsUseCounted(feature));
3416   }
3417   {
3418     ASSERT_FALSE(GetDocument().IsUseCounted(feature));
3419 
3420     TestCascade cascade(GetDocument(), summary);
3421     cascade.Add("display:block", CascadeOrigin::kUser);
3422     cascade.Apply();
3423     EXPECT_TRUE(GetDocument().IsUseCounted(feature));
3424     GetDocument().ClearUseCounterForTesting(feature);
3425   }
3426   {
3427     ASSERT_FALSE(GetDocument().IsUseCounted(feature));
3428 
3429     TestCascade cascade(GetDocument(), summary);
3430     cascade.Add("display:block", CascadeOrigin::kAuthor);
3431     cascade.Apply();
3432     EXPECT_TRUE(GetDocument().IsUseCounted(feature));
3433     GetDocument().ClearUseCounterForTesting(feature);
3434   }
3435 }
3436 
TEST_F(StyleCascadeTest,GetCascadedValues)3437 TEST_F(StyleCascadeTest, GetCascadedValues) {
3438   TestCascade cascade(GetDocument());
3439   cascade.Add("top:1px", CascadeOrigin::kUserAgent);
3440   cascade.Add("right:2px", CascadeOrigin::kUserAgent);
3441   cascade.Add("bottom:3px", CascadeOrigin::kUserAgent);
3442   cascade.Add("left:4px !important", CascadeOrigin::kUserAgent);
3443   cascade.Add("width:5px", CascadeOrigin::kUserAgent);
3444 
3445   cascade.Add("top:10px", CascadeOrigin::kUser);
3446   cascade.Add("right:20px", CascadeOrigin::kUser);
3447   cascade.Add("bottom:30px !important", CascadeOrigin::kUser);
3448   cascade.Add("left:40px", CascadeOrigin::kUser);
3449   cascade.Add("height:60px", CascadeOrigin::kUser);
3450   cascade.Add("height:61px", CascadeOrigin::kUser);
3451   cascade.Add("--x:70px", CascadeOrigin::kUser);
3452   cascade.Add("--y:80px !important", CascadeOrigin::kUser);
3453 
3454   cascade.Add("top:100px", CascadeOrigin::kAuthor);
3455   cascade.Add("right:201px !important", CascadeOrigin::kAuthor);
3456   cascade.Add("right:200px", CascadeOrigin::kAuthor);
3457   cascade.Add("bottom:300px", CascadeOrigin::kAuthor);
3458   cascade.Add("left:400px", CascadeOrigin::kAuthor);
3459   cascade.Add("--x:700px", CascadeOrigin::kAuthor);
3460   cascade.Add("--y:800px", CascadeOrigin::kAuthor);
3461 
3462   cascade.Apply();
3463 
3464   auto map = cascade.GetCascadedValues();
3465   EXPECT_EQ(8u, map.size());
3466 
3467   EXPECT_EQ("100px", CssTextAt(map, "top"));
3468   EXPECT_EQ("201px", CssTextAt(map, "right"));
3469   EXPECT_EQ("30px", CssTextAt(map, "bottom"));
3470   EXPECT_EQ("4px", CssTextAt(map, "left"));
3471   EXPECT_EQ("5px", CssTextAt(map, "width"));
3472   EXPECT_EQ("61px", CssTextAt(map, "height"));
3473   EXPECT_EQ("700px", CssTextAt(map, "--x"));
3474   EXPECT_EQ("80px ", CssTextAt(map, "--y"));
3475 }
3476 
TEST_F(StyleCascadeTest,GetCascadedValuesCssWide)3477 TEST_F(StyleCascadeTest, GetCascadedValuesCssWide) {
3478   TestCascade cascade(GetDocument());
3479   cascade.Add("top:initial");
3480   cascade.Add("right:inherit");
3481   cascade.Add("bottom:unset");
3482   cascade.Add("left:revert");
3483   cascade.Apply();
3484 
3485   auto map = cascade.GetCascadedValues();
3486   EXPECT_EQ(4u, map.size());
3487 
3488   EXPECT_EQ("initial", CssTextAt(map, "top"));
3489   EXPECT_EQ("inherit", CssTextAt(map, "right"));
3490   EXPECT_EQ("unset", CssTextAt(map, "bottom"));
3491   EXPECT_EQ("revert", CssTextAt(map, "left"));
3492 }
3493 
TEST_F(StyleCascadeTest,GetCascadedValuesLogical)3494 TEST_F(StyleCascadeTest, GetCascadedValuesLogical) {
3495   TestCascade cascade(GetDocument());
3496   cascade.Add("margin-inline-start:1px");
3497   cascade.Add("margin-inline-end:2px");
3498   cascade.Apply();
3499 
3500   auto map = cascade.GetCascadedValues();
3501   EXPECT_EQ(2u, map.size());
3502 
3503   EXPECT_EQ("1px", CssTextAt(map, "margin-left"));
3504   EXPECT_EQ("2px", CssTextAt(map, "margin-right"));
3505 }
3506 
TEST_F(StyleCascadeTest,GetCascadedValuesInterpolated)3507 TEST_F(StyleCascadeTest, GetCascadedValuesInterpolated) {
3508   AppendSheet(R"HTML(
3509      @keyframes test {
3510         from { --x: 100px; width: 100px; }
3511         to { --x: 200px; width: 200px; }
3512      }
3513     )HTML");
3514 
3515   TestCascade cascade(GetDocument());
3516 
3517   cascade.Add("animation-name: test");
3518   cascade.Add("animation-timing-function: linear");
3519   cascade.Add("animation-duration: 10s");
3520   cascade.Add("animation-delay: -5s");
3521   cascade.Apply();
3522 
3523   cascade.CalculateAnimationUpdate();
3524   cascade.Apply();
3525 
3526   // Verify that effect values from the animation did apply:
3527   EXPECT_EQ(" 200px", cascade.ComputedValue("--x"));
3528   EXPECT_EQ("150px", cascade.ComputedValue("width"));
3529 
3530   // However, we don't currently support returning interpolated vales from
3531   // GetCascadedValues:
3532   auto map = cascade.GetCascadedValues();
3533   EXPECT_EQ(4u, map.size());
3534 
3535   EXPECT_EQ("test", CssTextAt(map, "animation-name"));
3536   EXPECT_EQ("linear", CssTextAt(map, "animation-timing-function"));
3537   EXPECT_EQ("10s", CssTextAt(map, "animation-duration"));
3538   EXPECT_EQ("-5s", CssTextAt(map, "animation-delay"));
3539 }
3540 
TEST_F(StyleCascadeTest,ForcedVisitedBackgroundColor)3541 TEST_F(StyleCascadeTest, ForcedVisitedBackgroundColor) {
3542   ScopedForcedColorsForTest scoped_feature(true);
3543   ColorSchemeHelper color_scheme_helper(GetDocument());
3544   color_scheme_helper.SetForcedColors(GetDocument(), ForcedColors::kActive);
3545   UpdateAllLifecyclePhasesForTest();
3546 
3547   TestCascade cascade(GetDocument());
3548   cascade.State().Style()->SetInsideLink(EInsideLink::kInsideVisitedLink);
3549   cascade.Add(ParseDeclarationBlock("background-color:#aabbccdd"),
3550               CascadeOrigin::kAuthor, CSSSelector::kMatchVisited);
3551   cascade.Apply();
3552 
3553   Color forced_bg_color =
3554       StyleColor(CSSValueID::kCanvas)
3555           .Resolve(Color(), mojom::blink::ColorScheme::kLight);
3556   Color expected_bg_color =
3557       Color(forced_bg_color.Red(), forced_bg_color.Green(),
3558             forced_bg_color.Blue(), 0xdd);
3559 
3560   // Verify that the visited background color alpha channel is preserved in
3561   // Forced Colors Mode.
3562   EXPECT_EQ(
3563       expected_bg_color,
3564       cascade.State().Style()->InternalVisitedBackgroundColor().GetColor());
3565 }
3566 
TEST_F(StyleCascadeTest,RevertOrigin)3567 TEST_F(StyleCascadeTest, RevertOrigin) {
3568   TestCascade cascade(GetDocument());
3569 
3570   cascade.Add("width", "1px", CascadeOrigin::kUserAgent);
3571   cascade.Add("height", "1px", CascadeOrigin::kUserAgent);
3572   cascade.Add("display", "block", CascadeOrigin::kUserAgent);
3573   cascade.Add("width", "2px", CascadeOrigin::kUser);
3574   cascade.Add("height", "revert", CascadeOrigin::kUser);
3575   cascade.Add("width", "revert", CascadeOrigin::kAuthor);
3576   cascade.Add("height", "revert", CascadeOrigin::kAuthor);
3577   cascade.Add("display", "revert", CascadeOrigin::kAuthor);
3578   cascade.Add("margin-left", "revert", CascadeOrigin::kAuthor);
3579 
3580   cascade.AnalyzeIfNeeded();
3581 
3582   CSSValue* revert_value = cssvalue::CSSRevertValue::Create();
3583 
3584   TestCascadeResolver resolver;
3585 
3586   CascadeOrigin origin = CascadeOrigin::kAuthor;
3587   const CSSValue* resolved_value =
3588       cascade.Resolve(GetCSSPropertyWidth(), *revert_value, origin);
3589   ASSERT_TRUE(resolved_value);
3590   EXPECT_EQ(CascadeOrigin::kUser, origin);
3591   EXPECT_EQ("2px", resolved_value->CssText());
3592 
3593   origin = CascadeOrigin::kAuthor;
3594   resolved_value =
3595       cascade.Resolve(GetCSSPropertyHeight(), *revert_value, origin);
3596   ASSERT_TRUE(resolved_value);
3597   EXPECT_EQ(CascadeOrigin::kUserAgent, origin);
3598   EXPECT_EQ("1px", resolved_value->CssText());
3599 
3600   origin = CascadeOrigin::kAuthor;
3601   resolved_value =
3602       cascade.Resolve(GetCSSPropertyDisplay(), *revert_value, origin);
3603   ASSERT_TRUE(resolved_value);
3604   EXPECT_EQ(CascadeOrigin::kUserAgent, origin);
3605   EXPECT_EQ("block", resolved_value->CssText());
3606 
3607   origin = CascadeOrigin::kAuthor;
3608   resolved_value =
3609       cascade.Resolve(GetCSSPropertyMarginLeft(), *revert_value, origin);
3610   ASSERT_TRUE(resolved_value);
3611   EXPECT_EQ(CascadeOrigin::kNone, origin);
3612   EXPECT_EQ("unset", resolved_value->CssText());
3613 }
3614 
3615 }  // namespace blink
3616