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_pending_substitution_value.h"
14 #include "third_party/blink/renderer/core/css/css_primitive_value.h"
15 #include "third_party/blink/renderer/core/css/css_test_helpers.h"
16 #include "third_party/blink/renderer/core/css/css_variable_reference_value.h"
17 #include "third_party/blink/renderer/core/css/document_style_environment_variables.h"
18 #include "third_party/blink/renderer/core/css/media_query_evaluator.h"
19 #include "third_party/blink/renderer/core/css/parser/css_parser_context.h"
20 #include "third_party/blink/renderer/core/css/parser/css_parser_local_context.h"
21 #include "third_party/blink/renderer/core/css/parser/css_parser_token_range.h"
22 #include "third_party/blink/renderer/core/css/parser/css_property_parser.h"
23 #include "third_party/blink/renderer/core/css/parser/css_tokenizer.h"
24 #include "third_party/blink/renderer/core/css/parser/css_variable_parser.h"
25 #include "third_party/blink/renderer/core/css/properties/css_property_instances.h"
26 #include "third_party/blink/renderer/core/css/properties/css_property_ref.h"
27 #include "third_party/blink/renderer/core/css/properties/longhands/custom_property.h"
28 #include "third_party/blink/renderer/core/css/property_registry.h"
29 #include "third_party/blink/renderer/core/css/resolver/cascade_filter.h"
30 #include "third_party/blink/renderer/core/css/resolver/cascade_interpolations.h"
31 #include "third_party/blink/renderer/core/css/resolver/cascade_map.h"
32 #include "third_party/blink/renderer/core/css/resolver/cascade_priority.h"
33 #include "third_party/blink/renderer/core/css/resolver/cascade_resolver.h"
34 #include "third_party/blink/renderer/core/css/resolver/scoped_style_resolver.h"
35 #include "third_party/blink/renderer/core/css/resolver/style_resolver.h"
36 #include "third_party/blink/renderer/core/css/style_engine.h"
37 #include "third_party/blink/renderer/core/css/style_sheet_contents.h"
38 #include "third_party/blink/renderer/core/html/html_element.h"
39 #include "third_party/blink/renderer/core/style/computed_style.h"
40 #include "third_party/blink/renderer/core/style_property_shorthand.h"
41 #include "third_party/blink/renderer/core/testing/page_test_base.h"
42 #include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h"
43 #include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
44 
45 namespace blink {
46 
47 using css_test_helpers::ParseDeclarationBlock;
48 using css_test_helpers::RegisterProperty;
49 using Origin = CascadeOrigin;
50 using Priority = CascadePriority;
51 using UnitType = CSSPrimitiveValue::UnitType;
52 
53 class TestCascade {
54   STACK_ALLOCATED();
55 
56  public:
TestCascade(Document & document,Element * target=nullptr)57   TestCascade(Document& document, Element* target = nullptr)
58       : state_(document, target ? *target : *document.body()),
59         cascade_(InitState(state_)) {}
60 
TakeStyle()61   scoped_refptr<ComputedStyle> TakeStyle() { return state_.TakeStyle(); }
62 
State()63   StyleResolverState& State() { return state_; }
InnerCascade()64   StyleCascade& InnerCascade() { return cascade_; }
65 
InheritFrom(scoped_refptr<ComputedStyle> parent)66   void InheritFrom(scoped_refptr<ComputedStyle> parent) {
67     state_.SetParentStyle(parent);
68     state_.StyleRef().InheritFrom(*parent);
69   }
70 
71   //  Note that because of how MatchResult works, declarations must be added
72   //  in "origin order", i.e. UserAgent first, then User, then Author.
73 
Add(String block,CascadeOrigin origin=CascadeOrigin::kAuthor,unsigned link_match_type=CSSSelector::kMatchAll)74   void Add(String block,
75            CascadeOrigin origin = CascadeOrigin::kAuthor,
76            unsigned link_match_type = CSSSelector::kMatchAll) {
77     CSSParserMode mode =
78         origin == CascadeOrigin::kUserAgent ? kUASheetMode : kHTMLStandardMode;
79     Add(ParseDeclarationBlock(block, mode), origin, link_match_type);
80   }
81 
Add(String name,String value,CascadeOrigin origin=Origin::kAuthor)82   void Add(String name, String value, CascadeOrigin origin = Origin::kAuthor) {
83     Add(name + ":" + value, origin);
84   }
85 
Add(const CSSPropertyValueSet * set,CascadeOrigin origin=CascadeOrigin::kAuthor,unsigned link_match_type=CSSSelector::kMatchAll)86   void Add(const CSSPropertyValueSet* set,
87            CascadeOrigin origin = CascadeOrigin::kAuthor,
88            unsigned link_match_type = CSSSelector::kMatchAll) {
89     DCHECK_LE(origin, CascadeOrigin::kAuthor) << "Animations not supported";
90     DCHECK_LE(current_origin_, origin) << "Please add declarations in order";
91     EnsureAtLeast(origin);
92     cascade_.MutableMatchResult().AddMatchedProperties(set, link_match_type);
93   }
94 
Apply(CascadeFilter filter=CascadeFilter ())95   void Apply(CascadeFilter filter = CascadeFilter()) {
96     EnsureAtLeast(CascadeOrigin::kAuthor);
97     cascade_.Apply(filter);
98   }
99 
ComputedValue(String name) const100   String ComputedValue(String name) const {
101     CSSPropertyRef ref(name, GetDocument());
102     DCHECK(ref.IsValid());
103     const LayoutObject* layout_object = nullptr;
104     bool allow_visited_style = false;
105     const CSSValue* value = ref.GetProperty().CSSValueFromComputedStyle(
106         *state_.Style(), layout_object, allow_visited_style);
107     return value ? value->CssText() : g_null_atom;
108   }
109 
GetPriority(String name)110   CascadePriority GetPriority(String name) {
111     return GetPriority(
112         *CSSPropertyName::From(GetDocument().GetExecutionContext(), name));
113   }
114 
GetPriority(CSSPropertyName name)115   CascadePriority GetPriority(CSSPropertyName name) {
116     CascadePriority* c = cascade_.map_.Find(name);
117     return c ? *c : CascadePriority();
118   }
119 
GetOrigin(String name)120   CascadeOrigin GetOrigin(String name) { return GetPriority(name).GetOrigin(); }
121 
CalculateTransitionUpdate()122   void CalculateTransitionUpdate() {
123     CSSAnimations::CalculateTransitionUpdate(
124         state_.AnimationUpdate(), CSSAnimations::PropertyPass::kCustom,
125         &state_.GetElement(), *state_.Style());
126     CSSAnimations::CalculateTransitionUpdate(
127         state_.AnimationUpdate(), CSSAnimations::PropertyPass::kStandard,
128         &state_.GetElement(), *state_.Style());
129     AddTransitions();
130   }
131 
CalculateAnimationUpdate()132   void CalculateAnimationUpdate() {
133     CSSAnimations::CalculateAnimationUpdate(
134         state_.AnimationUpdate(), &state_.GetElement(), state_.GetElement(),
135         *state_.Style(), state_.ParentStyle(),
136         &GetDocument().EnsureStyleResolver());
137     AddAnimations();
138   }
139 
Reset()140   void Reset() { cascade_.Reset(); }
141 
142  private:
GetDocument() const143   Document& GetDocument() const { return state_.GetDocument(); }
Body() const144   Element* Body() const { return GetDocument().body(); }
145 
InitState(StyleResolverState & state)146   static StyleResolverState& InitState(StyleResolverState& state) {
147     state.SetStyle(InitialStyle(state.GetDocument()));
148     state.SetParentStyle(InitialStyle(state.GetDocument()));
149     return state;
150   }
151 
InitialStyle(Document & document)152   static scoped_refptr<ComputedStyle> InitialStyle(Document& document) {
153     return StyleResolver::InitialStyleForElement(document);
154   }
155 
FinishOrigin()156   void FinishOrigin() {
157     switch (current_origin_) {
158       case CascadeOrigin::kUserAgent:
159         cascade_.MutableMatchResult().FinishAddingUARules();
160         current_origin_ = CascadeOrigin::kUser;
161         break;
162       case CascadeOrigin::kUser:
163         cascade_.MutableMatchResult().FinishAddingUserRules();
164         current_origin_ = CascadeOrigin::kAuthor;
165         break;
166       case CascadeOrigin::kAuthor:
167       default:
168         NOTREACHED();
169         break;
170     }
171   }
172 
EnsureAtLeast(CascadeOrigin origin)173   void EnsureAtLeast(CascadeOrigin origin) {
174     while (current_origin_ < origin)
175       FinishOrigin();
176   }
177 
AddAnimations()178   void AddAnimations() {
179     const auto& update = state_.AnimationUpdate();
180     if (update.IsEmpty())
181       return;
182     cascade_.AddInterpolations(
183         &update.ActiveInterpolationsForCustomAnimations(),
184         CascadeOrigin::kAnimation);
185     cascade_.AddInterpolations(
186         &update.ActiveInterpolationsForStandardAnimations(),
187         CascadeOrigin::kAnimation);
188   }
189 
AddTransitions()190   void AddTransitions() {
191     const auto& update = state_.AnimationUpdate();
192     if (update.IsEmpty())
193       return;
194     cascade_.AddInterpolations(
195         &update.ActiveInterpolationsForCustomTransitions(),
196         CascadeOrigin::kTransition);
197     cascade_.AddInterpolations(
198         &update.ActiveInterpolationsForStandardTransitions(),
199         CascadeOrigin::kTransition);
200   }
201 
202   CascadeOrigin current_origin_ = CascadeOrigin::kUserAgent;
203   StyleResolverState state_;
204   StyleCascade cascade_;
205 };
206 
207 class TestCascadeResolver {
208   STACK_ALLOCATED();
209 
210  public:
TestCascadeResolver(Document & document,uint8_t generation=0)211   explicit TestCascadeResolver(Document& document, uint8_t generation = 0)
212       : document_(document), resolver_(CascadeFilter(), generation) {}
InCycle() const213   bool InCycle() const { return resolver_.InCycle(); }
DetectCycle(String name)214   bool DetectCycle(String name) {
215     CSSPropertyRef ref(name, document_);
216     DCHECK(ref.IsValid());
217     const CSSProperty& property = ref.GetProperty();
218     return resolver_.DetectCycle(property);
219   }
CycleDepth() const220   wtf_size_t CycleDepth() const { return resolver_.cycle_depth_; }
MarkApplied(CascadePriority * priority)221   void MarkApplied(CascadePriority* priority) {
222     resolver_.MarkApplied(priority);
223   }
MarkUnapplied(CascadePriority * priority)224   void MarkUnapplied(CascadePriority* priority) {
225     resolver_.MarkUnapplied(priority);
226   }
GetGeneration()227   uint8_t GetGeneration() { return resolver_.generation_; }
228 
229  private:
230   friend class TestCascadeAutoLock;
231 
232   Document& document_;
233   CascadeResolver resolver_;
234 };
235 
236 class TestCascadeAutoLock {
237   STACK_ALLOCATED();
238 
239  public:
TestCascadeAutoLock(const CSSPropertyName & name,TestCascadeResolver & resolver)240   TestCascadeAutoLock(const CSSPropertyName& name,
241                       TestCascadeResolver& resolver)
242       : lock_(name, resolver.resolver_) {}
243 
244  private:
245   CascadeResolver::AutoLock lock_;
246 };
247 
248 class StyleCascadeTest : public PageTestBase, private ScopedCSSCascadeForTest {
249  public:
StyleCascadeTest()250   StyleCascadeTest() : ScopedCSSCascadeForTest(true) {}
251 
CreateSheet(const String & css_text)252   CSSStyleSheet* CreateSheet(const String& css_text) {
253     auto* init = MakeGarbageCollected<CSSStyleSheetInit>();
254     DummyExceptionStateForTesting exception_state;
255     CSSStyleSheet* sheet =
256         CSSStyleSheet::Create(GetDocument(), init, exception_state);
257     sheet->replaceSync(css_text, exception_state);
258     sheet->Contents()->EnsureRuleSet(MediaQueryEvaluator(),
259                                      kRuleHasNoSpecialState);
260     return sheet;
261   }
262 
AppendSheet(const String & css_text)263   void AppendSheet(const String& css_text) {
264     CSSStyleSheet* sheet = CreateSheet(css_text);
265     ASSERT_TRUE(sheet);
266 
267     Element* body = GetDocument().body();
268     ASSERT_TRUE(body->IsInTreeScope());
269     TreeScope& tree_scope = body->GetTreeScope();
270     ScopedStyleResolver& scoped_resolver =
271         tree_scope.EnsureScopedStyleResolver();
272     ActiveStyleSheetVector active_sheets;
273     active_sheets.push_back(
274         std::make_pair(sheet, &sheet->Contents()->GetRuleSet()));
275     scoped_resolver.AppendActiveStyleSheets(0, active_sheets);
276   }
277 
DocumentElement() const278   Element* DocumentElement() const { return GetDocument().documentElement(); }
279 
SetRootFont(String value)280   void SetRootFont(String value) {
281     DocumentElement()->SetInlineStyleProperty(CSSPropertyID::kFontSize, value);
282     UpdateAllLifecyclePhasesForTest();
283   }
284 
AnimationTaintedSet(AtomicString name,String value)285   const MutableCSSPropertyValueSet* AnimationTaintedSet(AtomicString name,
286                                                         String value) {
287     CSSParserMode mode = kHTMLStandardMode;
288     auto* set = MakeGarbageCollected<MutableCSSPropertyValueSet>(mode);
289     set->SetProperty(name, value, /* important */ false,
290                      SecureContextMode::kSecureContext,
291                      /* context_style_sheet */ nullptr,
292                      /* is_animation_tainted */ true);
293     return set;
294   }
295 
296   // Temporarily create a CSS Environment Variable.
297   // https://drafts.csswg.org/css-env-1/
298   class AutoEnv {
299     STACK_ALLOCATED();
300 
301    public:
AutoEnv(PageTestBase & test,AtomicString name,String value)302     AutoEnv(PageTestBase& test, AtomicString name, String value)
303         : document_(&test.GetDocument()), name_(name) {
304       EnsureEnvironmentVariables().SetVariable(name, value);
305     }
~AutoEnv()306     ~AutoEnv() { EnsureEnvironmentVariables().RemoveVariable(name_); }
307 
308    private:
EnsureEnvironmentVariables()309     DocumentStyleEnvironmentVariables& EnsureEnvironmentVariables() {
310       return document_->GetStyleEngine().EnsureEnvironmentVariables();
311     }
312 
313     Document* document_;
314     AtomicString name_;
315   };
316 };
317 
TEST_F(StyleCascadeTest,ApplySingle)318 TEST_F(StyleCascadeTest, ApplySingle) {
319   TestCascade cascade(GetDocument());
320   cascade.Add("width", "1px", CascadeOrigin::kUserAgent);
321   cascade.Add("width", "2px", CascadeOrigin::kAuthor);
322   cascade.Apply();
323 
324   EXPECT_EQ("2px", cascade.ComputedValue("width"));
325 }
326 
TEST_F(StyleCascadeTest,ApplyImportance)327 TEST_F(StyleCascadeTest, ApplyImportance) {
328   TestCascade cascade(GetDocument());
329   cascade.Add("width:1px !important", CascadeOrigin::kUserAgent);
330   cascade.Add("width:2px", CascadeOrigin::kAuthor);
331   cascade.Apply();
332 
333   EXPECT_EQ("1px", cascade.ComputedValue("width"));
334 }
335 
TEST_F(StyleCascadeTest,ApplyAll)336 TEST_F(StyleCascadeTest, ApplyAll) {
337   TestCascade cascade(GetDocument());
338   cascade.Add("width:1px", CascadeOrigin::kUserAgent);
339   cascade.Add("height:1px", CascadeOrigin::kUserAgent);
340   cascade.Add("all:initial", CascadeOrigin::kAuthor);
341   cascade.Apply();
342 
343   EXPECT_EQ("auto", cascade.ComputedValue("width"));
344   EXPECT_EQ("auto", cascade.ComputedValue("height"));
345 }
346 
TEST_F(StyleCascadeTest,ApplyAllImportance)347 TEST_F(StyleCascadeTest, ApplyAllImportance) {
348   TestCascade cascade(GetDocument());
349   cascade.Add("opacity:0.5", CascadeOrigin::kUserAgent);
350   cascade.Add("display:block !important", CascadeOrigin::kUserAgent);
351   cascade.Add("all:initial", CascadeOrigin::kAuthor);
352   cascade.Apply();
353 
354   EXPECT_EQ("1", cascade.ComputedValue("opacity"));
355   EXPECT_EQ("block", cascade.ComputedValue("display"));
356 }
357 
TEST_F(StyleCascadeTest,ApplyAllWithPhysicalLonghands)358 TEST_F(StyleCascadeTest, ApplyAllWithPhysicalLonghands) {
359   TestCascade cascade(GetDocument());
360   cascade.Add("width:1px", CascadeOrigin::kUserAgent);
361   cascade.Add("height:1px !important", CascadeOrigin::kUserAgent);
362   cascade.Add("all:initial", CascadeOrigin::kAuthor);
363   cascade.Apply();
364   EXPECT_EQ("auto", cascade.ComputedValue("width"));
365   EXPECT_EQ("1px", cascade.ComputedValue("height"));
366 }
367 
TEST_F(StyleCascadeTest,ApplyCustomProperty)368 TEST_F(StyleCascadeTest, ApplyCustomProperty) {
369   TestCascade cascade(GetDocument());
370   cascade.Add("--x", " 10px ");
371   cascade.Add("--y", "nope");
372   cascade.Apply();
373 
374   EXPECT_EQ(" 10px ", cascade.ComputedValue("--x"));
375   EXPECT_EQ("nope", cascade.ComputedValue("--y"));
376 }
377 
TEST_F(StyleCascadeTest,ApplyGenerations)378 TEST_F(StyleCascadeTest, ApplyGenerations) {
379   TestCascade cascade(GetDocument());
380 
381   cascade.Add("--x:10px");
382   cascade.Add("width:20px");
383   cascade.Apply();
384   EXPECT_EQ("10px", cascade.ComputedValue("--x"));
385   EXPECT_EQ("20px", cascade.ComputedValue("width"));
386 
387   cascade.State().StyleRef().SetWidth(Length::Auto());
388   cascade.State().StyleRef().SetVariableData("--x", nullptr, true);
389   EXPECT_EQ(g_null_atom, cascade.ComputedValue("--x"));
390   EXPECT_EQ("auto", cascade.ComputedValue("width"));
391 
392   // Apply again
393   cascade.Apply();
394   EXPECT_EQ("10px", cascade.ComputedValue("--x"));
395   EXPECT_EQ("20px", cascade.ComputedValue("width"));
396 }
397 
TEST_F(StyleCascadeTest,ApplyCustomPropertyVar)398 TEST_F(StyleCascadeTest, ApplyCustomPropertyVar) {
399   // Apply --x first.
400   {
401     TestCascade cascade(GetDocument());
402     cascade.Add("--x", "yes and var(--y)");
403     cascade.Add("--y", "no");
404     cascade.Apply();
405 
406     EXPECT_EQ("yes and no", cascade.ComputedValue("--x"));
407     EXPECT_EQ("no", cascade.ComputedValue("--y"));
408   }
409 
410   // Apply --y first.
411   {
412     TestCascade cascade(GetDocument());
413     cascade.Add("--y", "no");
414     cascade.Add("--x", "yes and var(--y)");
415     cascade.Apply();
416 
417     EXPECT_EQ("yes and no", cascade.ComputedValue("--x"));
418     EXPECT_EQ("no", cascade.ComputedValue("--y"));
419   }
420 }
421 
TEST_F(StyleCascadeTest,InvalidVarReferenceCauseInvalidVariable)422 TEST_F(StyleCascadeTest, InvalidVarReferenceCauseInvalidVariable) {
423   TestCascade cascade(GetDocument());
424   cascade.Add("--x", "nope var(--y)");
425   cascade.Apply();
426 
427   EXPECT_EQ(g_null_atom, cascade.ComputedValue("--x"));
428 }
429 
TEST_F(StyleCascadeTest,ApplyCustomPropertyFallback)430 TEST_F(StyleCascadeTest, ApplyCustomPropertyFallback) {
431   TestCascade cascade(GetDocument());
432   cascade.Add("--x", "yes and var(--y,no)");
433   cascade.Apply();
434 
435   EXPECT_EQ("yes and no", cascade.ComputedValue("--x"));
436 }
437 
TEST_F(StyleCascadeTest,RegisteredPropertyFallback)438 TEST_F(StyleCascadeTest, RegisteredPropertyFallback) {
439   RegisterProperty(GetDocument(), "--x", "<length>", "0px", false);
440 
441   TestCascade cascade(GetDocument());
442   cascade.Add("--x", "var(--y,10px)");
443   cascade.Apply();
444 
445   EXPECT_EQ("10px", cascade.ComputedValue("--x"));
446 }
447 
TEST_F(StyleCascadeTest,RegisteredPropertyFallbackValidation)448 TEST_F(StyleCascadeTest, RegisteredPropertyFallbackValidation) {
449   RegisterProperty(GetDocument(), "--x", "<length>", "0px", false);
450 
451   TestCascade cascade(GetDocument());
452   cascade.Add("--x", "10px");
453   cascade.Add("--y", "var(--x,red)");  // Fallback must be valid <length>.
454   cascade.Add("--z", "var(--y,pass)");
455   cascade.Apply();
456 
457   EXPECT_EQ("pass", cascade.ComputedValue("--z"));
458 }
459 
TEST_F(StyleCascadeTest,VarInFallback)460 TEST_F(StyleCascadeTest, VarInFallback) {
461   TestCascade cascade(GetDocument());
462   cascade.Add("--x", "one var(--z,two var(--y))");
463   cascade.Add("--y", "three");
464   cascade.Apply();
465 
466   EXPECT_EQ("one two three", cascade.ComputedValue("--x"));
467 }
468 
TEST_F(StyleCascadeTest,VarReferenceInNormalProperty)469 TEST_F(StyleCascadeTest, VarReferenceInNormalProperty) {
470   TestCascade cascade(GetDocument());
471   cascade.Add("--x", "10px");
472   cascade.Add("width", "var(--x)");
473   cascade.Apply();
474 
475   EXPECT_EQ("10px", cascade.ComputedValue("width"));
476 }
477 
TEST_F(StyleCascadeTest,MultipleVarRefs)478 TEST_F(StyleCascadeTest, MultipleVarRefs) {
479   TestCascade cascade(GetDocument());
480   cascade.Add("--x", "var(--y) bar var(--y)");
481   cascade.Add("--y", "foo");
482   cascade.Apply();
483 
484   EXPECT_EQ("foo bar foo", cascade.ComputedValue("--x"));
485 }
486 
TEST_F(StyleCascadeTest,RegisteredPropertyComputedValue)487 TEST_F(StyleCascadeTest, RegisteredPropertyComputedValue) {
488   RegisterProperty(GetDocument(), "--x", "<length>", "0px", false);
489 
490   TestCascade cascade(GetDocument());
491   cascade.Add("--x", "1in");
492   cascade.Apply();
493 
494   EXPECT_EQ("96px", cascade.ComputedValue("--x"));
495 }
496 
TEST_F(StyleCascadeTest,RegisteredPropertySyntaxErrorCausesInitial)497 TEST_F(StyleCascadeTest, RegisteredPropertySyntaxErrorCausesInitial) {
498   RegisterProperty(GetDocument(), "--x", "<length>", "10px", false);
499 
500   TestCascade cascade(GetDocument());
501   cascade.Add("--x", "#fefefe");
502   cascade.Add("--y", "var(--x)");
503   cascade.Apply();
504 
505   EXPECT_EQ("10px", cascade.ComputedValue("--x"));
506   EXPECT_EQ("10px", cascade.ComputedValue("--y"));
507 }
508 
TEST_F(StyleCascadeTest,RegisteredPropertySubstitution)509 TEST_F(StyleCascadeTest, RegisteredPropertySubstitution) {
510   RegisterProperty(GetDocument(), "--x", "<length>", "0px", false);
511 
512   TestCascade cascade(GetDocument());
513   cascade.Add("--x", "1in");
514   cascade.Add("--y", "var(--x)");
515   cascade.Apply();
516 
517   EXPECT_EQ("96px", cascade.ComputedValue("--y"));
518 }
519 
TEST_F(StyleCascadeTest,RegisteredPropertyChain)520 TEST_F(StyleCascadeTest, RegisteredPropertyChain) {
521   RegisterProperty(GetDocument(), "--x", "<length>", "0px", false);
522   RegisterProperty(GetDocument(), "--z", "<length>", "0px", false);
523 
524   TestCascade cascade(GetDocument());
525   cascade.Add("--x", "1in");
526   cascade.Add("--y", "var(--x)");
527   cascade.Add("--z", "calc(var(--y) + 1in)");
528   cascade.Apply();
529 
530   EXPECT_EQ("96px", cascade.ComputedValue("--x"));
531   EXPECT_EQ("96px", cascade.ComputedValue("--y"));
532   EXPECT_EQ("192px", cascade.ComputedValue("--z"));
533 }
534 
TEST_F(StyleCascadeTest,BasicShorthand)535 TEST_F(StyleCascadeTest, BasicShorthand) {
536   TestCascade cascade(GetDocument());
537   cascade.Add("margin", "1px 2px 3px 4px");
538   cascade.Apply();
539 
540   EXPECT_EQ("1px", cascade.ComputedValue("margin-top"));
541   EXPECT_EQ("2px", cascade.ComputedValue("margin-right"));
542   EXPECT_EQ("3px", cascade.ComputedValue("margin-bottom"));
543   EXPECT_EQ("4px", cascade.ComputedValue("margin-left"));
544 }
545 
TEST_F(StyleCascadeTest,BasicVarShorthand)546 TEST_F(StyleCascadeTest, BasicVarShorthand) {
547   TestCascade cascade(GetDocument());
548   cascade.Add("margin", "1px var(--x) 3px 4px");
549   cascade.Add("--x", "2px");
550   cascade.Apply();
551 
552   EXPECT_EQ("1px", cascade.ComputedValue("margin-top"));
553   EXPECT_EQ("2px", cascade.ComputedValue("margin-right"));
554   EXPECT_EQ("3px", cascade.ComputedValue("margin-bottom"));
555   EXPECT_EQ("4px", cascade.ComputedValue("margin-left"));
556 }
557 
TEST_F(StyleCascadeTest,ApplyingPendingSubstitutionFirst)558 TEST_F(StyleCascadeTest, ApplyingPendingSubstitutionFirst) {
559   TestCascade cascade(GetDocument());
560   cascade.Add("margin", "1px var(--x) 3px 4px");
561   cascade.Add("--x", "2px");
562   cascade.Add("margin-right", "5px");
563   cascade.Apply();
564 
565   EXPECT_EQ("1px", cascade.ComputedValue("margin-top"));
566   EXPECT_EQ("5px", cascade.ComputedValue("margin-right"));
567   EXPECT_EQ("3px", cascade.ComputedValue("margin-bottom"));
568   EXPECT_EQ("4px", cascade.ComputedValue("margin-left"));
569 }
570 
TEST_F(StyleCascadeTest,ApplyingPendingSubstitutionLast)571 TEST_F(StyleCascadeTest, ApplyingPendingSubstitutionLast) {
572   TestCascade cascade(GetDocument());
573   cascade.Add("margin-right", "5px");
574   cascade.Add("margin", "1px var(--x) 3px 4px");
575   cascade.Add("--x", "2px");
576   cascade.Apply();
577 
578   EXPECT_EQ("1px", cascade.ComputedValue("margin-top"));
579   EXPECT_EQ("2px", cascade.ComputedValue("margin-right"));
580   EXPECT_EQ("3px", cascade.ComputedValue("margin-bottom"));
581   EXPECT_EQ("4px", cascade.ComputedValue("margin-left"));
582 }
583 
TEST_F(StyleCascadeTest,ResolverDetectCycle)584 TEST_F(StyleCascadeTest, ResolverDetectCycle) {
585   TestCascade cascade(GetDocument());
586   TestCascadeResolver resolver(GetDocument());
587 
588   {
589     TestCascadeAutoLock lock(CSSPropertyName("--a"), resolver);
590     EXPECT_FALSE(resolver.InCycle());
591     {
592       TestCascadeAutoLock lock(CSSPropertyName("--b"), resolver);
593       EXPECT_FALSE(resolver.InCycle());
594       {
595         TestCascadeAutoLock lock(CSSPropertyName("--c"), resolver);
596         EXPECT_FALSE(resolver.InCycle());
597 
598         EXPECT_TRUE(resolver.DetectCycle("--a"));
599         EXPECT_TRUE(resolver.InCycle());
600       }
601       EXPECT_TRUE(resolver.InCycle());
602     }
603     EXPECT_TRUE(resolver.InCycle());
604   }
605   EXPECT_FALSE(resolver.InCycle());
606 }
607 
TEST_F(StyleCascadeTest,ResolverDetectNoCycle)608 TEST_F(StyleCascadeTest, ResolverDetectNoCycle) {
609   TestCascade cascade(GetDocument());
610   TestCascadeResolver resolver(GetDocument());
611 
612   {
613     TestCascadeAutoLock lock(CSSPropertyName("--a"), resolver);
614     EXPECT_FALSE(resolver.InCycle());
615     {
616       TestCascadeAutoLock lock(CSSPropertyName("--b"), resolver);
617       EXPECT_FALSE(resolver.InCycle());
618       {
619         TestCascadeAutoLock lock(CSSPropertyName("--c"), resolver);
620         EXPECT_FALSE(resolver.InCycle());
621 
622         EXPECT_FALSE(resolver.DetectCycle("--x"));
623         EXPECT_FALSE(resolver.InCycle());
624       }
625       EXPECT_FALSE(resolver.InCycle());
626     }
627     EXPECT_FALSE(resolver.InCycle());
628   }
629   EXPECT_FALSE(resolver.InCycle());
630 }
631 
TEST_F(StyleCascadeTest,ResolverDetectCycleSelf)632 TEST_F(StyleCascadeTest, ResolverDetectCycleSelf) {
633   TestCascade cascade(GetDocument());
634   TestCascadeResolver resolver(GetDocument());
635 
636   {
637     TestCascadeAutoLock lock(CSSPropertyName("--a"), resolver);
638     EXPECT_FALSE(resolver.InCycle());
639 
640     EXPECT_TRUE(resolver.DetectCycle("--a"));
641     EXPECT_TRUE(resolver.InCycle());
642   }
643   EXPECT_FALSE(resolver.InCycle());
644 }
645 
TEST_F(StyleCascadeTest,ResolverDetectMultiCycle)646 TEST_F(StyleCascadeTest, ResolverDetectMultiCycle) {
647   using AutoLock = TestCascadeAutoLock;
648 
649   TestCascade cascade(GetDocument());
650   TestCascadeResolver resolver(GetDocument());
651 
652   {
653     AutoLock lock(CSSPropertyName("--a"), resolver);
654     EXPECT_FALSE(resolver.InCycle());
655     {
656       AutoLock lock(CSSPropertyName("--b"), resolver);
657       EXPECT_FALSE(resolver.InCycle());
658       {
659         AutoLock lock(CSSPropertyName("--c"), resolver);
660         EXPECT_FALSE(resolver.InCycle());
661         {
662           AutoLock lock(CSSPropertyName("--d"), resolver);
663           EXPECT_FALSE(resolver.InCycle());
664 
665           // Cycle 1 (big cycle):
666           EXPECT_TRUE(resolver.DetectCycle("--b"));
667           EXPECT_TRUE(resolver.InCycle());
668           EXPECT_EQ(1u, resolver.CycleDepth());
669 
670           // Cycle 2 (small cycle):
671           EXPECT_TRUE(resolver.DetectCycle("--c"));
672           EXPECT_TRUE(resolver.InCycle());
673           EXPECT_EQ(1u, resolver.CycleDepth());
674         }
675       }
676       EXPECT_TRUE(resolver.InCycle());
677     }
678     EXPECT_FALSE(resolver.InCycle());
679   }
680   EXPECT_FALSE(resolver.InCycle());
681 }
682 
TEST_F(StyleCascadeTest,ResolverDetectMultiCycleReverse)683 TEST_F(StyleCascadeTest, ResolverDetectMultiCycleReverse) {
684   using AutoLock = TestCascadeAutoLock;
685 
686   TestCascade cascade(GetDocument());
687   TestCascadeResolver resolver(GetDocument());
688 
689   {
690     AutoLock lock(CSSPropertyName("--a"), resolver);
691     EXPECT_FALSE(resolver.InCycle());
692     {
693       AutoLock lock(CSSPropertyName("--b"), resolver);
694       EXPECT_FALSE(resolver.InCycle());
695       {
696         AutoLock lock(CSSPropertyName("--c"), resolver);
697         EXPECT_FALSE(resolver.InCycle());
698         {
699           AutoLock lock(CSSPropertyName("--d"), resolver);
700           EXPECT_FALSE(resolver.InCycle());
701 
702           // Cycle 1 (small cycle):
703           EXPECT_TRUE(resolver.DetectCycle("--c"));
704           EXPECT_TRUE(resolver.InCycle());
705           EXPECT_EQ(2u, resolver.CycleDepth());
706 
707           // Cycle 2 (big cycle):
708           EXPECT_TRUE(resolver.DetectCycle("--b"));
709           EXPECT_TRUE(resolver.InCycle());
710           EXPECT_EQ(1u, resolver.CycleDepth());
711         }
712       }
713       EXPECT_TRUE(resolver.InCycle());
714     }
715     EXPECT_FALSE(resolver.InCycle());
716   }
717   EXPECT_FALSE(resolver.InCycle());
718 }
719 
TEST_F(StyleCascadeTest,ResolverMarkApplied)720 TEST_F(StyleCascadeTest, ResolverMarkApplied) {
721   TestCascadeResolver resolver(GetDocument(), 2);
722 
723   CascadePriority priority(CascadeOrigin::kAuthor);
724   EXPECT_EQ(0, priority.GetGeneration());
725 
726   resolver.MarkApplied(&priority);
727   EXPECT_EQ(2, priority.GetGeneration());
728 
729   // Mark a second time to verify observation of the same generation.
730   resolver.MarkApplied(&priority);
731   EXPECT_EQ(2, priority.GetGeneration());
732 }
733 
TEST_F(StyleCascadeTest,ResolverMarkUnapplied)734 TEST_F(StyleCascadeTest, ResolverMarkUnapplied) {
735   TestCascadeResolver resolver(GetDocument(), 7);
736 
737   CascadePriority priority(CascadeOrigin::kAuthor);
738   EXPECT_EQ(0, priority.GetGeneration());
739 
740   resolver.MarkApplied(&priority);
741   EXPECT_EQ(7, priority.GetGeneration());
742 
743   resolver.MarkUnapplied(&priority);
744   EXPECT_EQ(0, priority.GetGeneration());
745 
746   // Mark a second time to verify observation of the same generation.
747   resolver.MarkUnapplied(&priority);
748   EXPECT_EQ(0, priority.GetGeneration());
749 }
750 
TEST_F(StyleCascadeTest,BasicCycle)751 TEST_F(StyleCascadeTest, BasicCycle) {
752   TestCascade cascade(GetDocument());
753   cascade.Add("--a", "foo");
754   cascade.Add("--b", "bar");
755   cascade.Apply();
756 
757   EXPECT_EQ("foo", cascade.ComputedValue("--a"));
758   EXPECT_EQ("bar", cascade.ComputedValue("--b"));
759 
760   cascade.Add("--a", "var(--b)");
761   cascade.Add("--b", "var(--a)");
762   cascade.Apply();
763 
764   EXPECT_FALSE(cascade.ComputedValue("--a"));
765   EXPECT_FALSE(cascade.ComputedValue("--b"));
766 }
767 
TEST_F(StyleCascadeTest,SelfCycle)768 TEST_F(StyleCascadeTest, SelfCycle) {
769   TestCascade cascade(GetDocument());
770   cascade.Add("--a", "foo");
771   cascade.Apply();
772 
773   EXPECT_EQ("foo", cascade.ComputedValue("--a"));
774 
775   cascade.Add("--a", "var(--a)");
776   cascade.Apply();
777 
778   EXPECT_FALSE(cascade.ComputedValue("--a"));
779 }
780 
TEST_F(StyleCascadeTest,SelfCycleInFallback)781 TEST_F(StyleCascadeTest, SelfCycleInFallback) {
782   TestCascade cascade(GetDocument());
783   cascade.Add("--a", "var(--x, var(--a))");
784   cascade.Apply();
785 
786   EXPECT_FALSE(cascade.ComputedValue("--a"));
787 }
788 
TEST_F(StyleCascadeTest,SelfCycleInUnusedFallback)789 TEST_F(StyleCascadeTest, SelfCycleInUnusedFallback) {
790   TestCascade cascade(GetDocument());
791   cascade.Add("--a", "var(--b, var(--a))");
792   cascade.Add("--b", "10px");
793   cascade.Apply();
794 
795   EXPECT_FALSE(cascade.ComputedValue("--a"));
796   EXPECT_EQ("10px", cascade.ComputedValue("--b"));
797 }
798 
TEST_F(StyleCascadeTest,LongCycle)799 TEST_F(StyleCascadeTest, LongCycle) {
800   TestCascade cascade(GetDocument());
801   cascade.Add("--a", "var(--b)");
802   cascade.Add("--b", "var(--c)");
803   cascade.Add("--c", "var(--d)");
804   cascade.Add("--d", "var(--e)");
805   cascade.Add("--e", "var(--a)");
806   cascade.Apply();
807 
808   EXPECT_FALSE(cascade.ComputedValue("--a"));
809   EXPECT_FALSE(cascade.ComputedValue("--b"));
810   EXPECT_FALSE(cascade.ComputedValue("--c"));
811   EXPECT_FALSE(cascade.ComputedValue("--d"));
812   EXPECT_FALSE(cascade.ComputedValue("--e"));
813 }
814 
TEST_F(StyleCascadeTest,PartialCycle)815 TEST_F(StyleCascadeTest, PartialCycle) {
816   TestCascade cascade(GetDocument());
817   cascade.Add("--a", "var(--b)");
818   cascade.Add("--b", "var(--a)");
819   cascade.Add("--c", "bar var(--d) var(--a)");
820   cascade.Add("--d", "foo");
821   cascade.Apply();
822 
823   EXPECT_FALSE(cascade.ComputedValue("--a"));
824   EXPECT_FALSE(cascade.ComputedValue("--b"));
825   EXPECT_FALSE(cascade.ComputedValue("--c"));
826   EXPECT_EQ("foo", cascade.ComputedValue("--d"));
827 }
828 
TEST_F(StyleCascadeTest,VarCycleViaFallback)829 TEST_F(StyleCascadeTest, VarCycleViaFallback) {
830   TestCascade cascade(GetDocument());
831   cascade.Add("--a", "var(--b)");
832   cascade.Add("--b", "var(--x, var(--a))");
833   cascade.Add("--c", "var(--a)");
834   cascade.Apply();
835 
836   EXPECT_FALSE(cascade.ComputedValue("--a"));
837   EXPECT_FALSE(cascade.ComputedValue("--b"));
838   EXPECT_FALSE(cascade.ComputedValue("--c"));
839 }
840 
TEST_F(StyleCascadeTest,FallbackTriggeredByCycle)841 TEST_F(StyleCascadeTest, FallbackTriggeredByCycle) {
842   TestCascade cascade(GetDocument());
843   cascade.Add("--a", "var(--b)");
844   cascade.Add("--b", "var(--a)");
845   cascade.Add("--c", "var(--a,foo)");
846   cascade.Apply();
847 
848   EXPECT_FALSE(cascade.ComputedValue("--a"));
849   EXPECT_FALSE(cascade.ComputedValue("--b"));
850   EXPECT_EQ("foo", cascade.ComputedValue("--c"));
851 }
852 
TEST_F(StyleCascadeTest,RegisteredCycle)853 TEST_F(StyleCascadeTest, RegisteredCycle) {
854   RegisterProperty(GetDocument(), "--a", "<length>", "0px", false);
855   RegisterProperty(GetDocument(), "--b", "<length>", "0px", false);
856 
857   TestCascade cascade(GetDocument());
858   cascade.Add("--a", "var(--b)");
859   cascade.Add("--b", "var(--a)");
860   cascade.Apply();
861 
862   EXPECT_FALSE(cascade.ComputedValue("--a"));
863   EXPECT_FALSE(cascade.ComputedValue("--b"));
864 }
865 
TEST_F(StyleCascadeTest,PartiallyRegisteredCycle)866 TEST_F(StyleCascadeTest, PartiallyRegisteredCycle) {
867   RegisterProperty(GetDocument(), "--a", "<length>", "0px", false);
868 
869   TestCascade cascade(GetDocument());
870   cascade.Add("--a", "var(--b)");
871   cascade.Add("--b", "var(--a)");
872   cascade.Apply();
873 
874   EXPECT_FALSE(cascade.ComputedValue("--a"));
875   EXPECT_FALSE(cascade.ComputedValue("--b"));
876 }
877 
TEST_F(StyleCascadeTest,FallbackTriggeredByRegisteredCycle)878 TEST_F(StyleCascadeTest, FallbackTriggeredByRegisteredCycle) {
879   RegisterProperty(GetDocument(), "--a", "<length>", "0px", false);
880   RegisterProperty(GetDocument(), "--b", "<length>", "0px", false);
881 
882   TestCascade cascade(GetDocument());
883   // Cycle:
884   cascade.Add("--a", "var(--b)");
885   cascade.Add("--b", "var(--a)");
886   // References to cycle:
887   cascade.Add("--c", "var(--a,1px)");
888   cascade.Add("--d", "var(--b,2px)");
889   cascade.Apply();
890 
891   EXPECT_FALSE(cascade.ComputedValue("--a"));
892   EXPECT_FALSE(cascade.ComputedValue("--b"));
893   EXPECT_EQ("1px", cascade.ComputedValue("--c"));
894   EXPECT_EQ("2px", cascade.ComputedValue("--d"));
895 }
896 
TEST_F(StyleCascadeTest,CycleStillInvalidWithFallback)897 TEST_F(StyleCascadeTest, CycleStillInvalidWithFallback) {
898   TestCascade cascade(GetDocument());
899   // Cycle:
900   cascade.Add("--a", "var(--b,red)");
901   cascade.Add("--b", "var(--a,red)");
902   // References to cycle:
903   cascade.Add("--c", "var(--a,green)");
904   cascade.Add("--d", "var(--b,green)");
905   cascade.Apply();
906 
907   EXPECT_FALSE(cascade.ComputedValue("--a"));
908   EXPECT_FALSE(cascade.ComputedValue("--b"));
909   EXPECT_EQ("green", cascade.ComputedValue("--c"));
910   EXPECT_EQ("green", cascade.ComputedValue("--d"));
911 }
912 
TEST_F(StyleCascadeTest,CycleInFallbackStillInvalid)913 TEST_F(StyleCascadeTest, CycleInFallbackStillInvalid) {
914   TestCascade cascade(GetDocument());
915   // Cycle:
916   cascade.Add("--a", "var(--b,red)");
917   cascade.Add("--b", "var(--x,var(--a))");
918   // References to cycle:
919   cascade.Add("--c", "var(--a,green)");
920   cascade.Add("--d", "var(--b,green)");
921   cascade.Apply();
922 
923   EXPECT_FALSE(cascade.ComputedValue("--a"));
924   EXPECT_FALSE(cascade.ComputedValue("--b"));
925   EXPECT_EQ("green", cascade.ComputedValue("--c"));
926   EXPECT_EQ("green", cascade.ComputedValue("--d"));
927 }
928 
TEST_F(StyleCascadeTest,CycleMultiple)929 TEST_F(StyleCascadeTest, CycleMultiple) {
930   TestCascade cascade(GetDocument());
931   // Cycle:
932   cascade.Add("--a", "var(--c, red)");
933   cascade.Add("--b", "var(--c, red)");
934   cascade.Add("--c", "var(--a, blue) var(--b, blue)");
935   // References to cycle:
936   cascade.Add("--d", "var(--a,green)");
937   cascade.Add("--e", "var(--b,green)");
938   cascade.Add("--f", "var(--c,green)");
939   cascade.Apply();
940 
941   EXPECT_FALSE(cascade.ComputedValue("--a"));
942   EXPECT_FALSE(cascade.ComputedValue("--b"));
943   EXPECT_FALSE(cascade.ComputedValue("--c"));
944   EXPECT_EQ("green", cascade.ComputedValue("--d"));
945   EXPECT_EQ("green", cascade.ComputedValue("--e"));
946   EXPECT_EQ("green", cascade.ComputedValue("--f"));
947 }
948 
TEST_F(StyleCascadeTest,CycleMultipleFallback)949 TEST_F(StyleCascadeTest, CycleMultipleFallback) {
950   TestCascade cascade(GetDocument());
951   // Cycle:
952   cascade.Add("--a", "var(--b, red)");
953   cascade.Add("--b", "var(--a, var(--c, red))");
954   cascade.Add("--c", "var(--b, red)");
955   // References to cycle:
956   cascade.Add("--d", "var(--a,green)");
957   cascade.Add("--e", "var(--b,green)");
958   cascade.Add("--f", "var(--c,green)");
959   cascade.Apply();
960 
961   EXPECT_FALSE(cascade.ComputedValue("--a"));
962   EXPECT_FALSE(cascade.ComputedValue("--b"));
963   EXPECT_FALSE(cascade.ComputedValue("--c"));
964   EXPECT_EQ("green", cascade.ComputedValue("--d"));
965   EXPECT_EQ("green", cascade.ComputedValue("--e"));
966   EXPECT_EQ("green", cascade.ComputedValue("--f"));
967 }
968 
TEST_F(StyleCascadeTest,CycleMultipleUnusedFallback)969 TEST_F(StyleCascadeTest, CycleMultipleUnusedFallback) {
970   TestCascade cascade(GetDocument());
971   cascade.Add("--a", "red");
972   // Cycle:
973   cascade.Add("--b", "var(--c, red)");
974   cascade.Add("--c", "var(--a, var(--b, red) var(--d, red))");
975   cascade.Add("--d", "var(--c, red)");
976   // References to cycle:
977   cascade.Add("--e", "var(--b,green)");
978   cascade.Add("--f", "var(--c,green)");
979   cascade.Add("--g", "var(--d,green)");
980   cascade.Apply();
981 
982   EXPECT_FALSE(cascade.ComputedValue("--b"));
983   EXPECT_FALSE(cascade.ComputedValue("--c"));
984   EXPECT_FALSE(cascade.ComputedValue("--d"));
985   EXPECT_EQ("green", cascade.ComputedValue("--e"));
986   EXPECT_EQ("green", cascade.ComputedValue("--f"));
987   EXPECT_EQ("green", cascade.ComputedValue("--g"));
988 }
989 
TEST_F(StyleCascadeTest,CycleReferencedFromStandardProperty)990 TEST_F(StyleCascadeTest, CycleReferencedFromStandardProperty) {
991   TestCascade cascade(GetDocument());
992   cascade.Add("--a", "var(--b)");
993   cascade.Add("--b", "var(--a)");
994   cascade.Add("color:var(--a,green)");
995   cascade.Apply();
996 
997   EXPECT_FALSE(cascade.ComputedValue("--a"));
998   EXPECT_FALSE(cascade.ComputedValue("--b"));
999   EXPECT_EQ("rgb(0, 128, 0)", cascade.ComputedValue("color"));
1000 }
1001 
TEST_F(StyleCascadeTest,CycleReferencedFromShorthand)1002 TEST_F(StyleCascadeTest, CycleReferencedFromShorthand) {
1003   TestCascade cascade(GetDocument());
1004   cascade.Add("--a", "var(--b)");
1005   cascade.Add("--b", "var(--a)");
1006   cascade.Add("background", "var(--a,green)");
1007   cascade.Apply();
1008 
1009   EXPECT_FALSE(cascade.ComputedValue("--a"));
1010   EXPECT_FALSE(cascade.ComputedValue("--b"));
1011   EXPECT_EQ("rgb(0, 128, 0)", cascade.ComputedValue("background-color"));
1012 }
1013 
TEST_F(StyleCascadeTest,EmUnit)1014 TEST_F(StyleCascadeTest, EmUnit) {
1015   TestCascade cascade(GetDocument());
1016   cascade.Add("font-size", "10px");
1017   cascade.Add("width", "10em");
1018   cascade.Apply();
1019 
1020   EXPECT_EQ("100px", cascade.ComputedValue("width"));
1021 }
1022 
TEST_F(StyleCascadeTest,EmUnitCustomProperty)1023 TEST_F(StyleCascadeTest, EmUnitCustomProperty) {
1024   RegisterProperty(GetDocument(), "--x", "<length>", "0px", false);
1025 
1026   TestCascade cascade(GetDocument());
1027   cascade.Add("font-size", "10px");
1028   cascade.Add("--x", "10em");
1029   cascade.Apply();
1030 
1031   EXPECT_EQ("100px", cascade.ComputedValue("--x"));
1032 }
1033 
TEST_F(StyleCascadeTest,EmUnitNonCycle)1034 TEST_F(StyleCascadeTest, EmUnitNonCycle) {
1035   TestCascade parent(GetDocument());
1036   parent.Add("font-size", "10px");
1037   parent.Apply();
1038 
1039   TestCascade cascade(GetDocument());
1040   cascade.InheritFrom(parent.TakeStyle());
1041   cascade.Add("font-size", "var(--x)");
1042   cascade.Add("--x", "10em");
1043   cascade.Apply();
1044 
1045   // Note: Only registered properties can have cycles with font-size.
1046   EXPECT_EQ("100px", cascade.ComputedValue("font-size"));
1047 }
1048 
TEST_F(StyleCascadeTest,EmUnitCycle)1049 TEST_F(StyleCascadeTest, EmUnitCycle) {
1050   RegisterProperty(GetDocument(), "--x", "<length>", "0px", false);
1051 
1052   TestCascade cascade(GetDocument());
1053   cascade.Add("font-size", "var(--x)");
1054   cascade.Add("--x", "10em");
1055   cascade.Apply();
1056 
1057   EXPECT_FALSE(cascade.ComputedValue("--x"));
1058 }
1059 
TEST_F(StyleCascadeTest,SubstitutingEmCycles)1060 TEST_F(StyleCascadeTest, SubstitutingEmCycles) {
1061   RegisterProperty(GetDocument(), "--x", "<length>", "0px", false);
1062 
1063   TestCascade cascade(GetDocument());
1064   cascade.Add("font-size", "var(--x)");
1065   cascade.Add("--x", "10em");
1066   cascade.Add("--y", "var(--x)");
1067   cascade.Add("--z", "var(--x,1px)");
1068   cascade.Apply();
1069 
1070   EXPECT_FALSE(cascade.ComputedValue("--y"));
1071   EXPECT_EQ("1px", cascade.ComputedValue("--z"));
1072 }
1073 
TEST_F(StyleCascadeTest,RemUnit)1074 TEST_F(StyleCascadeTest, RemUnit) {
1075   SetRootFont("10px");
1076   UpdateAllLifecyclePhasesForTest();
1077 
1078   TestCascade cascade(GetDocument());
1079   cascade.Add("width", "10rem");
1080   cascade.Apply();
1081 
1082   EXPECT_EQ("100px", cascade.ComputedValue("width"));
1083 }
1084 
TEST_F(StyleCascadeTest,RemUnitCustomProperty)1085 TEST_F(StyleCascadeTest, RemUnitCustomProperty) {
1086   RegisterProperty(GetDocument(), "--x", "<length>", "0px", false);
1087 
1088   SetRootFont("10px");
1089   UpdateAllLifecyclePhasesForTest();
1090 
1091   TestCascade cascade(GetDocument());
1092   cascade.Add("--x", "10rem");
1093   cascade.Apply();
1094 
1095   EXPECT_EQ("100px", cascade.ComputedValue("--x"));
1096 }
1097 
TEST_F(StyleCascadeTest,RemUnitInFontSize)1098 TEST_F(StyleCascadeTest, RemUnitInFontSize) {
1099   RegisterProperty(GetDocument(), "--x", "<length>", "0px", false);
1100 
1101   SetRootFont("10px");
1102   UpdateAllLifecyclePhasesForTest();
1103 
1104   TestCascade cascade(GetDocument());
1105   cascade.Add("font-size", "1rem");
1106   cascade.Add("--x", "10rem");
1107   cascade.Apply();
1108 
1109   EXPECT_EQ("100px", cascade.ComputedValue("--x"));
1110 }
1111 
TEST_F(StyleCascadeTest,RemUnitInRootFontSizeCycle)1112 TEST_F(StyleCascadeTest, RemUnitInRootFontSizeCycle) {
1113   RegisterProperty(GetDocument(), "--x", "<length>", "0px", false);
1114 
1115   TestCascade cascade(GetDocument(), DocumentElement());
1116   cascade.Add("font-size", "var(--x)");
1117   cascade.Add("--x", "1rem");
1118   cascade.Apply();
1119 
1120   EXPECT_FALSE(cascade.ComputedValue("--x"));
1121 }
1122 
TEST_F(StyleCascadeTest,RemUnitInRootFontSizeNonCycle)1123 TEST_F(StyleCascadeTest, RemUnitInRootFontSizeNonCycle) {
1124   TestCascade cascade(GetDocument(), DocumentElement());
1125   cascade.Add("font-size", "initial");
1126   cascade.Apply();
1127 
1128   String expected = cascade.ComputedValue("font-size");
1129 
1130   cascade.Add("font-size", "var(--x)");
1131   cascade.Add("--x", "1rem");
1132   cascade.Apply();
1133 
1134   // Note: Only registered properties can have cycles with font-size.
1135   EXPECT_EQ("1rem", cascade.ComputedValue("--x"));
1136   EXPECT_EQ(expected, cascade.ComputedValue("font-size"));
1137 }
1138 
TEST_F(StyleCascadeTest,Initial)1139 TEST_F(StyleCascadeTest, Initial) {
1140   TestCascade parent(GetDocument());
1141   parent.Add("--x", "foo");
1142   parent.Apply();
1143 
1144   TestCascade cascade(GetDocument());
1145   cascade.InheritFrom(parent.TakeStyle());
1146   cascade.Add("--y", "foo");
1147   cascade.Apply();
1148 
1149   EXPECT_EQ("foo", cascade.ComputedValue("--x"));
1150   EXPECT_EQ("foo", cascade.ComputedValue("--y"));
1151 
1152   cascade.Add("--x", "initial");
1153   cascade.Add("--y", "initial");
1154   cascade.Apply();
1155 
1156   EXPECT_FALSE(cascade.ComputedValue("--x"));
1157   EXPECT_FALSE(cascade.ComputedValue("--y"));
1158 }
1159 
TEST_F(StyleCascadeTest,Inherit)1160 TEST_F(StyleCascadeTest, Inherit) {
1161   TestCascade parent(GetDocument());
1162   parent.Add("--x", "foo");
1163   parent.Apply();
1164 
1165   TestCascade cascade(GetDocument());
1166   cascade.InheritFrom(parent.TakeStyle());
1167 
1168   EXPECT_EQ("foo", cascade.ComputedValue("--x"));
1169 
1170   cascade.Add("--x", "bar");
1171   cascade.Apply();
1172   EXPECT_EQ("bar", cascade.ComputedValue("--x"));
1173 
1174   cascade.Add("--x", "inherit");
1175   cascade.Apply();
1176   EXPECT_EQ("foo", cascade.ComputedValue("--x"));
1177 }
1178 
TEST_F(StyleCascadeTest,Unset)1179 TEST_F(StyleCascadeTest, Unset) {
1180   TestCascade parent(GetDocument());
1181   parent.Add("--x", "foo");
1182   parent.Apply();
1183 
1184   TestCascade cascade(GetDocument());
1185   cascade.InheritFrom(parent.TakeStyle());
1186   EXPECT_EQ("foo", cascade.ComputedValue("--x"));
1187 
1188   cascade.Add("--x", "bar");
1189   cascade.Apply();
1190   EXPECT_EQ("bar", cascade.ComputedValue("--x"));
1191 
1192   cascade.Add("--x", "unset");
1193   cascade.Apply();
1194   EXPECT_EQ("foo", cascade.ComputedValue("--x"));
1195 }
1196 
TEST_F(StyleCascadeTest,RegisteredInitial)1197 TEST_F(StyleCascadeTest, RegisteredInitial) {
1198   RegisterProperty(GetDocument(), "--x", "<length>", "0px", false);
1199 
1200   TestCascade cascade(GetDocument());
1201   cascade.Apply();
1202   EXPECT_EQ("0px", cascade.ComputedValue("--x"));
1203 }
1204 
TEST_F(StyleCascadeTest,SubstituteRegisteredImplicitInitialValue)1205 TEST_F(StyleCascadeTest, SubstituteRegisteredImplicitInitialValue) {
1206   RegisterProperty(GetDocument(), "--x", "<length>", "13px", false);
1207 
1208   TestCascade cascade(GetDocument());
1209   cascade.Add("--y", " var(--x) ");
1210   cascade.Apply();
1211   EXPECT_EQ("13px", cascade.ComputedValue("--x"));
1212   EXPECT_EQ(" 13px ", cascade.ComputedValue("--y"));
1213 }
1214 
TEST_F(StyleCascadeTest,SubstituteRegisteredUniversal)1215 TEST_F(StyleCascadeTest, SubstituteRegisteredUniversal) {
1216   RegisterProperty(GetDocument(), "--x", "*", "foo", false);
1217 
1218   TestCascade cascade(GetDocument());
1219   cascade.Add("--x", "bar");
1220   cascade.Add("--y", "var(--x)");
1221   cascade.Apply();
1222   EXPECT_EQ("bar", cascade.ComputedValue("--x"));
1223   EXPECT_EQ("bar", cascade.ComputedValue("--y"));
1224 }
1225 
TEST_F(StyleCascadeTest,SubstituteRegisteredUniversalInvalid)1226 TEST_F(StyleCascadeTest, SubstituteRegisteredUniversalInvalid) {
1227   RegisterProperty(GetDocument(), "--x", "*", g_null_atom, false);
1228 
1229   TestCascade cascade(GetDocument());
1230   cascade.Add("--y", " var(--x) ");
1231   cascade.Apply();
1232   EXPECT_FALSE(cascade.ComputedValue("--x"));
1233   EXPECT_FALSE(cascade.ComputedValue("--y"));
1234 }
1235 
TEST_F(StyleCascadeTest,SubstituteRegisteredUniversalInitial)1236 TEST_F(StyleCascadeTest, SubstituteRegisteredUniversalInitial) {
1237   RegisterProperty(GetDocument(), "--x", "*", "foo", false);
1238 
1239   TestCascade cascade(GetDocument());
1240   cascade.Add("--y", " var(--x) ");
1241   cascade.Apply();
1242   EXPECT_EQ("foo", cascade.ComputedValue("--x"));
1243   EXPECT_EQ(" foo ", cascade.ComputedValue("--y"));
1244 }
1245 
TEST_F(StyleCascadeTest,RegisteredExplicitInitial)1246 TEST_F(StyleCascadeTest, RegisteredExplicitInitial) {
1247   RegisterProperty(GetDocument(), "--x", "<length>", "0px", false);
1248 
1249   TestCascade cascade(GetDocument());
1250   cascade.Add("--x", "10px");
1251   cascade.Apply();
1252   EXPECT_EQ("10px", cascade.ComputedValue("--x"));
1253 
1254   cascade.Add("--x", "initial");
1255   cascade.Add("--y", "var(--x)");
1256   cascade.Apply();
1257   EXPECT_EQ("0px", cascade.ComputedValue("--x"));
1258   EXPECT_EQ("0px", cascade.ComputedValue("--y"));
1259 }
1260 
TEST_F(StyleCascadeTest,RegisteredExplicitInherit)1261 TEST_F(StyleCascadeTest, RegisteredExplicitInherit) {
1262   RegisterProperty(GetDocument(), "--x", "<length>", "0px", false);
1263 
1264   TestCascade parent(GetDocument());
1265   parent.Add("--x", "15px");
1266   parent.Apply();
1267   EXPECT_EQ("15px", parent.ComputedValue("--x"));
1268 
1269   TestCascade cascade(GetDocument());
1270   cascade.InheritFrom(parent.TakeStyle());
1271   cascade.Apply();
1272   EXPECT_EQ("0px", cascade.ComputedValue("--x"));  // Note: inherit==false
1273 
1274   cascade.Add("--x", "inherit");
1275   cascade.Add("--y", "var(--x)");
1276   cascade.Apply();
1277   EXPECT_EQ("15px", cascade.ComputedValue("--x"));
1278   EXPECT_EQ("15px", cascade.ComputedValue("--y"));
1279 }
1280 
TEST_F(StyleCascadeTest,RegisteredExplicitUnset)1281 TEST_F(StyleCascadeTest, RegisteredExplicitUnset) {
1282   RegisterProperty(GetDocument(), "--x", "<length>", "0px", false);
1283   RegisterProperty(GetDocument(), "--y", "<length>", "0px", true);
1284 
1285   TestCascade parent(GetDocument());
1286   parent.Add("--x", "15px");
1287   parent.Add("--y", "15px");
1288   parent.Apply();
1289   EXPECT_EQ("15px", parent.ComputedValue("--x"));
1290   EXPECT_EQ("15px", parent.ComputedValue("--y"));
1291 
1292   TestCascade cascade(GetDocument());
1293   cascade.InheritFrom(parent.TakeStyle());
1294   cascade.Add("--x", "2px");
1295   cascade.Add("--y", "2px");
1296   cascade.Apply();
1297   EXPECT_EQ("2px", cascade.ComputedValue("--x"));
1298   EXPECT_EQ("2px", cascade.ComputedValue("--y"));
1299 
1300   cascade.Add("--x", "unset");
1301   cascade.Add("--y", "unset");
1302   cascade.Add("--z", "var(--x) var(--y)");
1303   cascade.Apply();
1304   EXPECT_EQ("0px", cascade.ComputedValue("--x"));
1305   EXPECT_EQ("15px", cascade.ComputedValue("--y"));
1306   EXPECT_EQ("0px 15px", cascade.ComputedValue("--z"));
1307 }
1308 
TEST_F(StyleCascadeTest,SubstituteAnimationTaintedInCustomProperty)1309 TEST_F(StyleCascadeTest, SubstituteAnimationTaintedInCustomProperty) {
1310   TestCascade cascade(GetDocument());
1311   cascade.Add(AnimationTaintedSet("--x", "15px"));
1312   cascade.Add("--y", "var(--x)");
1313   cascade.Apply();
1314   EXPECT_EQ("15px", cascade.ComputedValue("--x"));
1315   EXPECT_EQ("15px", cascade.ComputedValue("--y"));
1316 }
1317 
TEST_F(StyleCascadeTest,SubstituteAnimationTaintedInStandardProperty)1318 TEST_F(StyleCascadeTest, SubstituteAnimationTaintedInStandardProperty) {
1319   TestCascade cascade(GetDocument());
1320   cascade.Add(AnimationTaintedSet("--x", "15px"));
1321   cascade.Add("width", "var(--x)");
1322   cascade.Apply();
1323   EXPECT_EQ("15px", cascade.ComputedValue("--x"));
1324   EXPECT_EQ("15px", cascade.ComputedValue("width"));
1325 }
1326 
TEST_F(StyleCascadeTest,SubstituteAnimationTaintedInAnimationProperty)1327 TEST_F(StyleCascadeTest, SubstituteAnimationTaintedInAnimationProperty) {
1328   TestCascade cascade(GetDocument());
1329   cascade.Add("--x", "20s");
1330   cascade.Add("animation-duration", "var(--x)");
1331   cascade.Apply();
1332 
1333   EXPECT_EQ("20s", cascade.ComputedValue("--x"));
1334   EXPECT_EQ("20s", cascade.ComputedValue("animation-duration"));
1335 
1336   cascade.Add(AnimationTaintedSet("--y", "20s"));
1337   cascade.Add("animation-duration", "var(--y)");
1338   cascade.Apply();
1339 
1340   EXPECT_EQ("20s", cascade.ComputedValue("--y"));
1341   EXPECT_EQ("0s", cascade.ComputedValue("animation-duration"));
1342 }
1343 
TEST_F(StyleCascadeTest,IndirectlyAnimationTainted)1344 TEST_F(StyleCascadeTest, IndirectlyAnimationTainted) {
1345   TestCascade cascade(GetDocument());
1346   cascade.Add(AnimationTaintedSet("--x", "20s"));
1347   cascade.Add("--y", "var(--x)");
1348   cascade.Add("animation-duration", "var(--y)");
1349   cascade.Apply();
1350 
1351   EXPECT_EQ("20s", cascade.ComputedValue("--x"));
1352   EXPECT_EQ("20s", cascade.ComputedValue("--y"));
1353   EXPECT_EQ("0s", cascade.ComputedValue("animation-duration"));
1354 }
1355 
TEST_F(StyleCascadeTest,AnimationTaintedFallback)1356 TEST_F(StyleCascadeTest, AnimationTaintedFallback) {
1357   TestCascade cascade(GetDocument());
1358   cascade.Add(AnimationTaintedSet("--x", "20s"));
1359   cascade.Add("animation-duration", "var(--x,1s)");
1360   cascade.Apply();
1361 
1362   EXPECT_EQ("20s", cascade.ComputedValue("--x"));
1363   EXPECT_EQ("1s", cascade.ComputedValue("animation-duration"));
1364 }
1365 
TEST_F(StyleCascadeTest,EnvMissingNestedVar)1366 TEST_F(StyleCascadeTest, EnvMissingNestedVar) {
1367   TestCascade cascade(GetDocument());
1368   cascade.Add("--x", "rgb(0, 0, 0)");
1369   cascade.Add("background-color", "env(missing, var(--x))");
1370   cascade.Apply();
1371 
1372   EXPECT_EQ("rgb(0, 0, 0)", cascade.ComputedValue("--x"));
1373   EXPECT_EQ("rgb(0, 0, 0)", cascade.ComputedValue("background-color"));
1374 }
1375 
TEST_F(StyleCascadeTest,EnvMissingNestedVarFallback)1376 TEST_F(StyleCascadeTest, EnvMissingNestedVarFallback) {
1377   TestCascade cascade(GetDocument());
1378   cascade.Add("background-color", "env(missing, var(--missing, blue))");
1379   cascade.Apply();
1380 
1381   EXPECT_EQ("rgb(0, 0, 255)", cascade.ComputedValue("background-color"));
1382 }
1383 
TEST_F(StyleCascadeTest,EnvMissingFallback)1384 TEST_F(StyleCascadeTest, EnvMissingFallback) {
1385   TestCascade cascade(GetDocument());
1386   cascade.Add("background-color", "env(missing, blue)");
1387   cascade.Apply();
1388 
1389   EXPECT_EQ("rgb(0, 0, 255)", cascade.ComputedValue("background-color"));
1390 }
1391 
TEST_F(StyleCascadeTest,ValidEnv)1392 TEST_F(StyleCascadeTest, ValidEnv) {
1393   AutoEnv env(*this, "test", "red");
1394 
1395   TestCascade cascade(GetDocument());
1396   cascade.Add("background-color", "env(test, blue)");
1397   cascade.Apply();
1398 
1399   EXPECT_EQ("rgb(255, 0, 0)", cascade.ComputedValue("background-color"));
1400 }
1401 
TEST_F(StyleCascadeTest,ValidEnvFallback)1402 TEST_F(StyleCascadeTest, ValidEnvFallback) {
1403   AutoEnv env(*this, "test", "red");
1404 
1405   TestCascade cascade(GetDocument());
1406   cascade.Add("background-color", "env(test, blue)");
1407   cascade.Apply();
1408 
1409   EXPECT_EQ("rgb(255, 0, 0)", cascade.ComputedValue("background-color"));
1410 }
1411 
TEST_F(StyleCascadeTest,ValidEnvInUnusedFallback)1412 TEST_F(StyleCascadeTest, ValidEnvInUnusedFallback) {
1413   AutoEnv env(*this, "test", "red");
1414 
1415   TestCascade cascade(GetDocument());
1416   cascade.Add("--x", "rgb(0, 0, 0)");
1417   cascade.Add("background-color", "var(--x, env(test))");
1418   cascade.Apply();
1419 
1420   EXPECT_EQ("rgb(0, 0, 0)", cascade.ComputedValue("--x"));
1421   EXPECT_EQ("rgb(0, 0, 0)", cascade.ComputedValue("background-color"));
1422 }
1423 
TEST_F(StyleCascadeTest,ValidEnvInUsedFallback)1424 TEST_F(StyleCascadeTest, ValidEnvInUsedFallback) {
1425   AutoEnv env(*this, "test", "red");
1426 
1427   TestCascade cascade(GetDocument());
1428   cascade.Add("background-color", "var(--missing, env(test))");
1429   cascade.Apply();
1430 
1431   EXPECT_EQ("rgb(255, 0, 0)", cascade.ComputedValue("background-color"));
1432 }
1433 
TEST_F(StyleCascadeTest,AnimationApplyFilter)1434 TEST_F(StyleCascadeTest, AnimationApplyFilter) {
1435   AppendSheet(R"HTML(
1436      @keyframes test {
1437         from { color: white; background-color: white; }
1438         to { color: gray; background-color: gray; }
1439      }
1440     )HTML");
1441 
1442   TestCascade cascade(GetDocument());
1443 
1444   cascade.Add("animation: test linear 10s -5s");
1445   cascade.Add("color:green");
1446   cascade.Apply();
1447 
1448   cascade.CalculateAnimationUpdate();
1449   cascade.Apply(CascadeFilter(CSSProperty::kInherited, true));
1450 
1451   EXPECT_EQ("rgb(0, 128, 0)", cascade.ComputedValue("color"));
1452   EXPECT_EQ("rgb(192, 192, 192)", cascade.ComputedValue("background-color"));
1453 }
1454 
TEST_F(StyleCascadeTest,TransitionApplyFilter)1455 TEST_F(StyleCascadeTest, TransitionApplyFilter) {
1456   TestCascade cascade1(GetDocument());
1457   cascade1.Add("background-color: white");
1458   cascade1.Add("color: white");
1459   cascade1.Add("transition: all steps(2, start) 100s");
1460   cascade1.Apply();
1461 
1462   // Set the old style on the element, so that the transition
1463   // update detects it.
1464   GetDocument().body()->SetComputedStyle(cascade1.TakeStyle());
1465 
1466   // Now simulate a new style, with new color values.
1467   TestCascade cascade2(GetDocument());
1468   cascade2.Add("background-color: gray");
1469   cascade2.Add("color: gray");
1470   cascade2.Add("transition: all steps(2, start) 100s");
1471   cascade2.Apply();
1472 
1473   cascade2.CalculateTransitionUpdate();
1474   cascade2.Apply(CascadeFilter(CSSProperty::kInherited, true));
1475 
1476   EXPECT_EQ("rgb(128, 128, 128)", cascade2.ComputedValue("color"));
1477   EXPECT_EQ("rgb(192, 192, 192)", cascade2.ComputedValue("background-color"));
1478 }
1479 
TEST_F(StyleCascadeTest,PendingKeyframeAnimation)1480 TEST_F(StyleCascadeTest, PendingKeyframeAnimation) {
1481   RegisterProperty(GetDocument(), "--x", "<length>", "0px", false);
1482 
1483   AppendSheet(R"HTML(
1484      @keyframes test {
1485         from { --x: 10px; }
1486         to { --x: 20px; }
1487      }
1488     )HTML");
1489 
1490   TestCascade cascade(GetDocument());
1491 
1492   cascade.Add("animation-name", "test");
1493   cascade.Add("animation-duration", "1s");
1494   cascade.Apply();
1495 
1496   cascade.CalculateAnimationUpdate();
1497   cascade.Apply();
1498 
1499   EXPECT_EQ(CascadeOrigin::kAnimation, cascade.GetPriority("--x").GetOrigin());
1500 }
1501 
TEST_F(StyleCascadeTest,PendingKeyframeAnimationApply)1502 TEST_F(StyleCascadeTest, PendingKeyframeAnimationApply) {
1503   RegisterProperty(GetDocument(), "--x", "<length>", "0px", false);
1504 
1505   AppendSheet(R"HTML(
1506      @keyframes test {
1507         from { --x: 10px; }
1508         to { --x: 20px; }
1509      }
1510     )HTML");
1511 
1512   TestCascade cascade(GetDocument());
1513 
1514   cascade.Add("animation-name", "test");
1515   cascade.Add("animation-duration", "10s");
1516   cascade.Add("animation-timing-function", "linear");
1517   cascade.Add("animation-delay", "-5s");
1518   cascade.Apply();
1519 
1520   cascade.CalculateAnimationUpdate();
1521   cascade.Apply();
1522 
1523   EXPECT_EQ(CascadeOrigin::kAnimation, cascade.GetPriority("--x").GetOrigin());
1524   EXPECT_EQ("15px", cascade.ComputedValue("--x"));
1525 }
1526 
TEST_F(StyleCascadeTest,TransitionCausesInterpolationValue)1527 TEST_F(StyleCascadeTest, TransitionCausesInterpolationValue) {
1528   RegisterProperty(GetDocument(), "--x", "<length>", "0px", false);
1529 
1530   // First, simulate an "old style".
1531   TestCascade cascade1(GetDocument());
1532   cascade1.Add("--x", "10px");
1533   cascade1.Add("transition", "--x 1s");
1534   cascade1.Apply();
1535 
1536   // Set the old style on the element, so that the animation
1537   // update detects it.
1538   GetDocument().body()->SetComputedStyle(cascade1.TakeStyle());
1539 
1540   // Now simulate a new style, with a new value for --x.
1541   TestCascade cascade2(GetDocument());
1542   cascade2.Add("--x", "20px");
1543   cascade2.Add("transition", "--x 1s");
1544   cascade2.Apply();
1545 
1546   cascade2.CalculateTransitionUpdate();
1547   cascade2.Apply();
1548 
1549   EXPECT_EQ(CascadeOrigin::kTransition,
1550             cascade2.GetPriority("--x").GetOrigin());
1551 }
1552 
TEST_F(StyleCascadeTest,TransitionDetectedForChangedFontSize)1553 TEST_F(StyleCascadeTest, TransitionDetectedForChangedFontSize) {
1554   RegisterProperty(GetDocument(), "--x", "<length>", "0px", false);
1555 
1556   TestCascade cascade1(GetDocument());
1557   cascade1.Add("font-size", "10px");
1558   cascade1.Add("--x", "10em");
1559   cascade1.Add("width", "10em");
1560   cascade1.Add("height", "10px");
1561   cascade1.Add("transition", "--x 1s, width 1s");
1562   cascade1.Apply();
1563 
1564   GetDocument().body()->SetComputedStyle(cascade1.TakeStyle());
1565 
1566   TestCascade cascade2(GetDocument());
1567   cascade2.Add("font-size", "20px");
1568   cascade2.Add("--x", "10em");
1569   cascade2.Add("width", "10em");
1570   cascade2.Add("height", "10px");
1571   cascade2.Add("transition", "--x 1s, width 1s");
1572   cascade2.Apply();
1573 
1574   cascade2.CalculateTransitionUpdate();
1575   cascade2.Apply();
1576 
1577   EXPECT_EQ(CascadeOrigin::kTransition, cascade2.GetOrigin("--x"));
1578   EXPECT_EQ(CascadeOrigin::kTransition, cascade2.GetOrigin("width"));
1579   EXPECT_EQ("10px", cascade2.ComputedValue("height"));
1580 }
1581 
TEST_F(StyleCascadeTest,AnimatingVarReferences)1582 TEST_F(StyleCascadeTest, AnimatingVarReferences) {
1583   RegisterProperty(GetDocument(), "--x", "<length>", "0px", false);
1584 
1585   AppendSheet(R"HTML(
1586      @keyframes test {
1587         from { --x: var(--from); }
1588         to { --x: var(--to); }
1589      }
1590     )HTML");
1591 
1592   TestCascade cascade(GetDocument());
1593 
1594   cascade.Add("animation-name", "test");
1595   cascade.Add("animation-duration", "10s");
1596   cascade.Add("animation-timing-function", "linear");
1597   cascade.Add("animation-delay", "-5s");
1598   cascade.Apply();
1599 
1600   cascade.CalculateAnimationUpdate();
1601   cascade.Add("--from", "10px");
1602   cascade.Add("--to", "20px");
1603   cascade.Add("--y", "var(--x)");
1604   cascade.Apply();
1605 
1606   EXPECT_EQ("15px", cascade.ComputedValue("--x"));
1607   EXPECT_EQ("15px", cascade.ComputedValue("--y"));
1608 }
1609 
TEST_F(StyleCascadeTest,AnimateStandardProperty)1610 TEST_F(StyleCascadeTest, AnimateStandardProperty) {
1611   AppendSheet(R"HTML(
1612      @keyframes test {
1613         from { width: 10px; }
1614         to { width: 20px; }
1615      }
1616     )HTML");
1617 
1618   TestCascade cascade(GetDocument());
1619 
1620   cascade.Add("animation-name", "test");
1621   cascade.Add("animation-duration", "10s");
1622   cascade.Add("animation-timing-function", "linear");
1623   cascade.Add("animation-delay", "-5s");
1624   cascade.Apply();
1625 
1626   cascade.CalculateAnimationUpdate();
1627   cascade.Apply();
1628 
1629   EXPECT_EQ(CascadeOrigin::kAnimation, cascade.GetOrigin("width"));
1630   EXPECT_EQ("15px", cascade.ComputedValue("width"));
1631 }
1632 
TEST_F(StyleCascadeTest,AuthorImportantWinOverAnimations)1633 TEST_F(StyleCascadeTest, AuthorImportantWinOverAnimations) {
1634   AppendSheet(R"HTML(
1635      @keyframes test {
1636         from { width: 10px; height: 10px; }
1637         to { width: 20px; height: 20px; }
1638      }
1639     )HTML");
1640 
1641   TestCascade cascade(GetDocument());
1642 
1643   cascade.Add("animation-name", "test");
1644   cascade.Add("animation-duration", "10s");
1645   cascade.Add("animation-timing-function", "linear");
1646   cascade.Add("animation-delay", "-5s");
1647   cascade.Add("width:40px");
1648   cascade.Add("height:40px !important");
1649   cascade.Apply();
1650 
1651   cascade.CalculateAnimationUpdate();
1652   cascade.Apply();
1653 
1654   EXPECT_EQ(CascadeOrigin::kAnimation, cascade.GetOrigin("width"));
1655   EXPECT_EQ(CascadeOrigin::kAuthor, cascade.GetOrigin("height"));
1656 
1657   EXPECT_EQ("15px", cascade.ComputedValue("width"));
1658   EXPECT_EQ("40px", cascade.ComputedValue("height"));
1659 }
1660 
TEST_F(StyleCascadeTest,TransitionsWinOverAuthorImportant)1661 TEST_F(StyleCascadeTest, TransitionsWinOverAuthorImportant) {
1662   // First, simulate an "old style".
1663   TestCascade cascade1(GetDocument());
1664   cascade1.Add("width:10px !important");
1665   cascade1.Add("height:10px !important");
1666   cascade1.Add("transition:all 1s");
1667   cascade1.Apply();
1668 
1669   // Set the old style on the element, so that the animation
1670   // update detects it.
1671   GetDocument().body()->SetComputedStyle(cascade1.TakeStyle());
1672 
1673   // Now simulate a new style, with a new value for width/height.
1674   TestCascade cascade2(GetDocument());
1675   cascade2.Add("width:20px !important");
1676   cascade2.Add("height:20px !important");
1677   cascade2.Add("transition:all 1s");
1678   cascade2.Apply();
1679 
1680   cascade2.CalculateTransitionUpdate();
1681   cascade2.Apply();
1682 
1683   EXPECT_EQ(CascadeOrigin::kTransition,
1684             cascade2.GetPriority("width").GetOrigin());
1685   EXPECT_EQ(CascadeOrigin::kTransition,
1686             cascade2.GetPriority("height").GetOrigin());
1687 }
1688 
TEST_F(StyleCascadeTest,EmRespondsToAnimatedFontSize)1689 TEST_F(StyleCascadeTest, EmRespondsToAnimatedFontSize) {
1690   RegisterProperty(GetDocument(), "--x", "<length>", "0px", false);
1691 
1692   AppendSheet(R"HTML(
1693      @keyframes test {
1694         from { font-size: 10px; }
1695         to { font-size: 20px; }
1696      }
1697     )HTML");
1698 
1699   TestCascade cascade(GetDocument());
1700 
1701   cascade.Add("animation-name", "test");
1702   cascade.Add("animation-duration", "10s");
1703   cascade.Add("animation-timing-function", "linear");
1704   cascade.Add("animation-delay", "-5s");
1705   cascade.Apply();
1706 
1707   cascade.CalculateAnimationUpdate();
1708   cascade.Add("--x", "2em");
1709   cascade.Add("width", "10em");
1710 
1711   cascade.Apply();
1712   EXPECT_EQ("30px", cascade.ComputedValue("--x"));
1713   EXPECT_EQ("150px", cascade.ComputedValue("width"));
1714 }
1715 
TEST_F(StyleCascadeTest,AnimateStandardPropertyWithVar)1716 TEST_F(StyleCascadeTest, AnimateStandardPropertyWithVar) {
1717   RegisterProperty(GetDocument(), "--x", "<length>", "0px", false);
1718 
1719   AppendSheet(R"HTML(
1720      @keyframes test {
1721         from { width: var(--from); }
1722         to { width: var(--to); }
1723      }
1724     )HTML");
1725 
1726   TestCascade cascade(GetDocument());
1727 
1728   cascade.Add("animation-name", "test");
1729   cascade.Add("animation-duration", "10s");
1730   cascade.Add("animation-timing-function", "linear");
1731   cascade.Add("animation-delay", "-5s");
1732   cascade.Apply();
1733 
1734   cascade.CalculateAnimationUpdate();
1735   cascade.Add("--from", "10px");
1736   cascade.Add("--to", "20px");
1737 
1738   cascade.Apply();
1739   EXPECT_EQ("15px", cascade.ComputedValue("width"));
1740 }
1741 
TEST_F(StyleCascadeTest,AnimateStandardShorthand)1742 TEST_F(StyleCascadeTest, AnimateStandardShorthand) {
1743   RegisterProperty(GetDocument(), "--x", "<length>", "0px", false);
1744 
1745   AppendSheet(R"HTML(
1746      @keyframes test {
1747         from { margin: 10px; }
1748         to { margin: 20px; }
1749      }
1750     )HTML");
1751 
1752   TestCascade cascade(GetDocument());
1753 
1754   cascade.Add("animation-name", "test");
1755   cascade.Add("animation-duration", "10s");
1756   cascade.Add("animation-timing-function", "linear");
1757   cascade.Add("animation-delay", "-5s");
1758   cascade.Apply();
1759 
1760   cascade.CalculateAnimationUpdate();
1761   cascade.Apply();
1762 
1763   EXPECT_EQ(CascadeOrigin::kAnimation, cascade.GetOrigin("margin-top"));
1764   EXPECT_EQ(CascadeOrigin::kAnimation, cascade.GetOrigin("margin-right"));
1765   EXPECT_EQ(CascadeOrigin::kAnimation, cascade.GetOrigin("margin-bottom"));
1766   EXPECT_EQ(CascadeOrigin::kAnimation, cascade.GetOrigin("margin-left"));
1767 
1768   EXPECT_EQ("15px", cascade.ComputedValue("margin-top"));
1769   EXPECT_EQ("15px", cascade.ComputedValue("margin-right"));
1770   EXPECT_EQ("15px", cascade.ComputedValue("margin-bottom"));
1771   EXPECT_EQ("15px", cascade.ComputedValue("margin-left"));
1772 }
1773 
TEST_F(StyleCascadeTest,AnimatedVisitedImportantOverride)1774 TEST_F(StyleCascadeTest, AnimatedVisitedImportantOverride) {
1775   AppendSheet(R"HTML(
1776      @keyframes test {
1777         from { background-color: rgb(100, 100, 100); }
1778         to { background-color: rgb(200, 200, 200); }
1779      }
1780     )HTML");
1781 
1782   TestCascade cascade(GetDocument());
1783   cascade.State().Style()->SetInsideLink(EInsideLink::kInsideVisitedLink);
1784 
1785   cascade.Add(ParseDeclarationBlock("background-color:red !important"),
1786               CascadeOrigin::kAuthor, CSSSelector::kMatchVisited);
1787   cascade.Add("animation-name:test");
1788   cascade.Add("animation-duration:10s");
1789   cascade.Add("animation-timing-function:linear");
1790   cascade.Add("animation-delay:-5s");
1791   cascade.Apply();
1792 
1793   cascade.CalculateAnimationUpdate();
1794   cascade.Apply();
1795   EXPECT_EQ("rgb(150, 150, 150)", cascade.ComputedValue("background-color"));
1796 
1797   auto style = cascade.TakeStyle();
1798 
1799   style->SetInsideLink(EInsideLink::kInsideVisitedLink);
1800   EXPECT_EQ(Color(255, 0, 0),
1801             style->VisitedDependentColor(GetCSSPropertyBackgroundColor()));
1802 
1803   style->SetInsideLink(EInsideLink::kNotInsideLink);
1804   EXPECT_EQ(Color(150, 150, 150),
1805             style->VisitedDependentColor(GetCSSPropertyBackgroundColor()));
1806 }
1807 
TEST_F(StyleCascadeTest,AnimatedVisitedHighPrio)1808 TEST_F(StyleCascadeTest, AnimatedVisitedHighPrio) {
1809   AppendSheet(R"HTML(
1810      @keyframes test {
1811         from { color: rgb(100, 100, 100); }
1812         to { color: rgb(200, 200, 200); }
1813      }
1814     )HTML");
1815 
1816   TestCascade cascade(GetDocument());
1817   cascade.Add("color:red");
1818   cascade.Add("animation:test 10s -5s linear");
1819   cascade.Apply();
1820 
1821   cascade.CalculateAnimationUpdate();
1822   cascade.Apply();
1823   EXPECT_EQ("rgb(150, 150, 150)", cascade.ComputedValue("color"));
1824 
1825   auto style = cascade.TakeStyle();
1826 
1827   style->SetInsideLink(EInsideLink::kInsideVisitedLink);
1828   EXPECT_EQ(Color(150, 150, 150),
1829             style->VisitedDependentColor(GetCSSPropertyColor()));
1830 
1831   style->SetInsideLink(EInsideLink::kNotInsideLink);
1832   EXPECT_EQ(Color(150, 150, 150),
1833             style->VisitedDependentColor(GetCSSPropertyColor()));
1834 }
1835 
TEST_F(StyleCascadeTest,AnimatedImportantOverrideFlag)1836 TEST_F(StyleCascadeTest, AnimatedImportantOverrideFlag) {
1837   AppendSheet(R"HTML(
1838      @keyframes test {
1839         from { background-color: white; }
1840         to { background-color: gray; }
1841      }
1842     )HTML");
1843 
1844   TestCascade cascade(GetDocument());
1845   cascade.Add("animation:test 10s -5s linear");
1846   cascade.Add("background-color: green !important");
1847   cascade.Apply();
1848   EXPECT_FALSE(cascade.State().HasImportantOverrides());
1849 
1850   cascade.CalculateAnimationUpdate();
1851   cascade.Apply();
1852   EXPECT_TRUE(cascade.State().HasImportantOverrides());
1853 }
1854 
TEST_F(StyleCascadeTest,AnimatedImportantOverrideNoFlag)1855 TEST_F(StyleCascadeTest, AnimatedImportantOverrideNoFlag) {
1856   AppendSheet(R"HTML(
1857      @keyframes test {
1858         from { background-color: white; }
1859         to { background-color: gray; }
1860      }
1861     )HTML");
1862 
1863   TestCascade cascade(GetDocument());
1864   cascade.Add("animation:test 10s -5s linear");
1865   cascade.Add("color:green !important");
1866   cascade.Apply();
1867   EXPECT_FALSE(cascade.State().HasImportantOverrides());
1868 
1869   cascade.CalculateAnimationUpdate();
1870   cascade.Apply();
1871   EXPECT_FALSE(cascade.State().HasImportantOverrides());
1872 }
1873 
TEST_F(StyleCascadeTest,AnimatedImportantOverrideFlagHighPriority)1874 TEST_F(StyleCascadeTest, AnimatedImportantOverrideFlagHighPriority) {
1875   AppendSheet(R"HTML(
1876      @keyframes test {
1877         from { color: white; }
1878         to { color: gray; }
1879      }
1880     )HTML");
1881 
1882   // 'color' is a high priority property, and therefore applied by lookup.
1883   TestCascade cascade(GetDocument());
1884   cascade.Add("animation:test 10s -5s linear");
1885   cascade.Add("color:green !important");
1886   cascade.Apply();
1887   EXPECT_FALSE(cascade.State().HasImportantOverrides());
1888 
1889   cascade.CalculateAnimationUpdate();
1890   cascade.Apply();
1891   EXPECT_TRUE(cascade.State().HasImportantOverrides());
1892 }
1893 
TEST_F(StyleCascadeTest,AnimatedImportantOverrideFlagVisited)1894 TEST_F(StyleCascadeTest, AnimatedImportantOverrideFlagVisited) {
1895   AppendSheet(R"HTML(
1896      @keyframes test {
1897         from { background-color: white; }
1898         to { background-color: gray; }
1899      }
1900     )HTML");
1901 
1902   TestCascade cascade(GetDocument());
1903   cascade.State().Style()->SetInsideLink(EInsideLink::kInsideVisitedLink);
1904 
1905   cascade.Add(ParseDeclarationBlock("background-color:red !important"),
1906               CascadeOrigin::kAuthor, CSSSelector::kMatchVisited);
1907   cascade.Add("animation:test 10s -5s linear");
1908   cascade.Apply();
1909   EXPECT_FALSE(cascade.State().HasImportantOverrides());
1910 
1911   cascade.CalculateAnimationUpdate();
1912   cascade.Apply();
1913   EXPECT_TRUE(cascade.State().HasImportantOverrides());
1914 }
1915 
TEST_F(StyleCascadeTest,AnimatePendingSubstitutionValue)1916 TEST_F(StyleCascadeTest, AnimatePendingSubstitutionValue) {
1917   RegisterProperty(GetDocument(), "--x", "<length>", "0px", false);
1918 
1919   AppendSheet(R"HTML(
1920      @keyframes test {
1921         from { margin: var(--from); }
1922         to { margin: var(--to); }
1923      }
1924     )HTML");
1925 
1926   TestCascade cascade(GetDocument());
1927 
1928   cascade.Add("animation-name", "test");
1929   cascade.Add("animation-duration", "10s");
1930   cascade.Add("animation-timing-function", "linear");
1931   cascade.Add("animation-delay", "-5s");
1932   cascade.Apply();
1933 
1934   cascade.CalculateAnimationUpdate();
1935   cascade.Add("--from", "10px");
1936   cascade.Add("--to", "20px");
1937   cascade.Apply();
1938 
1939   EXPECT_EQ(CascadeOrigin::kAnimation, cascade.GetOrigin("margin-top"));
1940   EXPECT_EQ(CascadeOrigin::kAnimation, cascade.GetOrigin("margin-right"));
1941   EXPECT_EQ(CascadeOrigin::kAnimation, cascade.GetOrigin("margin-bottom"));
1942   EXPECT_EQ(CascadeOrigin::kAnimation, cascade.GetOrigin("margin-left"));
1943 
1944   EXPECT_EQ("15px", cascade.ComputedValue("margin-top"));
1945   EXPECT_EQ("15px", cascade.ComputedValue("margin-right"));
1946   EXPECT_EQ("15px", cascade.ComputedValue("margin-bottom"));
1947   EXPECT_EQ("15px", cascade.ComputedValue("margin-left"));
1948 }
1949 
TEST_F(StyleCascadeTest,ForeignObjectZoomVsEffectiveZoom)1950 TEST_F(StyleCascadeTest, ForeignObjectZoomVsEffectiveZoom) {
1951   GetDocument().body()->setInnerHTML(R"HTML(
1952     <svg>
1953       <foreignObject id='foreign'></foreignObject>
1954     </svg>
1955   )HTML");
1956   UpdateAllLifecyclePhasesForTest();
1957 
1958   Element* foreign_object = GetDocument().getElementById("foreign");
1959   ASSERT_TRUE(foreign_object);
1960 
1961   TestCascade cascade(GetDocument(), foreign_object);
1962   cascade.Add("-internal-effective-zoom:initial !important",
1963               CascadeOrigin::kUserAgent);
1964   cascade.Add("zoom:200%");
1965   cascade.Apply();
1966 
1967   EXPECT_EQ(1.0f, cascade.TakeStyle()->EffectiveZoom());
1968 }
1969 
TEST_F(StyleCascadeTest,ZoomCascadeOrder)1970 TEST_F(StyleCascadeTest, ZoomCascadeOrder) {
1971   TestCascade cascade(GetDocument());
1972   cascade.Add("zoom:200%", CascadeOrigin::kUserAgent);
1973   cascade.Add("-internal-effective-zoom:initial", CascadeOrigin::kUserAgent);
1974   cascade.Apply();
1975 
1976   EXPECT_EQ(1.0f, cascade.TakeStyle()->EffectiveZoom());
1977 }
1978 
TEST_F(StyleCascadeTest,ZoomVsAll)1979 TEST_F(StyleCascadeTest, ZoomVsAll) {
1980   TestCascade cascade(GetDocument());
1981   cascade.Add("zoom:200%", CascadeOrigin::kUserAgent);
1982   cascade.Add("all:initial");
1983   cascade.Apply();
1984 
1985   EXPECT_EQ(1.0f, cascade.TakeStyle()->EffectiveZoom());
1986 }
1987 
TEST_F(StyleCascadeTest,InternalEffectiveZoomVsAll)1988 TEST_F(StyleCascadeTest, InternalEffectiveZoomVsAll) {
1989   TestCascade cascade(GetDocument());
1990   cascade.Add("-internal-effective-zoom:200%", CascadeOrigin::kUserAgent);
1991   cascade.Add("all:initial");
1992   cascade.Apply();
1993 
1994   EXPECT_EQ(1.0f, cascade.TakeStyle()->EffectiveZoom());
1995 }
1996 
TEST_F(StyleCascadeTest,ZoomReversedCascadeOrder)1997 TEST_F(StyleCascadeTest, ZoomReversedCascadeOrder) {
1998   TestCascade cascade(GetDocument());
1999   cascade.Add("-internal-effective-zoom:initial", CascadeOrigin::kUserAgent);
2000   cascade.Add("zoom:200%", CascadeOrigin::kUserAgent);
2001   cascade.Apply();
2002 
2003   EXPECT_EQ(2.0f, cascade.TakeStyle()->EffectiveZoom());
2004 }
2005 
TEST_F(StyleCascadeTest,ZoomImportant)2006 TEST_F(StyleCascadeTest, ZoomImportant) {
2007   TestCascade cascade(GetDocument());
2008   cascade.Add("zoom:200% !important", CascadeOrigin::kUserAgent);
2009   cascade.Add("-internal-effective-zoom:initial", CascadeOrigin::kAuthor);
2010   cascade.Apply();
2011 
2012   EXPECT_EQ(2.0f, cascade.TakeStyle()->EffectiveZoom());
2013 }
2014 
TEST_F(StyleCascadeTest,WritingModeCascadeOrder)2015 TEST_F(StyleCascadeTest, WritingModeCascadeOrder) {
2016   TestCascade cascade(GetDocument());
2017   cascade.Add("writing-mode", "vertical-lr");
2018   cascade.Add("-webkit-writing-mode", "vertical-rl");
2019   cascade.Apply();
2020 
2021   EXPECT_EQ("vertical-rl", cascade.ComputedValue("writing-mode"));
2022   EXPECT_EQ("vertical-rl", cascade.ComputedValue("-webkit-writing-mode"));
2023 }
2024 
TEST_F(StyleCascadeTest,WritingModeReversedCascadeOrder)2025 TEST_F(StyleCascadeTest, WritingModeReversedCascadeOrder) {
2026   TestCascade cascade(GetDocument());
2027   cascade.Add("-webkit-writing-mode", "vertical-rl");
2028   cascade.Add("writing-mode", "vertical-lr");
2029   cascade.Apply();
2030 
2031   EXPECT_EQ("vertical-lr", cascade.ComputedValue("writing-mode"));
2032   EXPECT_EQ("vertical-lr", cascade.ComputedValue("-webkit-writing-mode"));
2033 }
2034 
TEST_F(StyleCascadeTest,WritingModePriority)2035 TEST_F(StyleCascadeTest, WritingModePriority) {
2036   TestCascade cascade(GetDocument());
2037   cascade.Add("writing-mode:vertical-lr !important", Origin::kAuthor);
2038   cascade.Add("-webkit-writing-mode:vertical-rl", Origin::kAuthor);
2039   cascade.Apply();
2040 
2041   EXPECT_EQ("vertical-lr", cascade.ComputedValue("writing-mode"));
2042   EXPECT_EQ("vertical-lr", cascade.ComputedValue("-webkit-writing-mode"));
2043 }
2044 
TEST_F(StyleCascadeTest,WebkitBorderImageCascadeOrder)2045 TEST_F(StyleCascadeTest, WebkitBorderImageCascadeOrder) {
2046   String gradient1("linear-gradient(rgb(0, 0, 0), rgb(0, 128, 0))");
2047   String gradient2("linear-gradient(rgb(0, 0, 0), rgb(0, 200, 0))");
2048 
2049   TestCascade cascade(GetDocument());
2050   cascade.Add("-webkit-border-image", gradient1 + " round 40 / 10px / 20px",
2051               Origin::kAuthor);
2052   cascade.Add("border-image-source", gradient2, Origin::kAuthor);
2053   cascade.Add("border-image-slice", "20", Origin::kAuthor);
2054   cascade.Add("border-image-width", "6px", Origin::kAuthor);
2055   cascade.Add("border-image-outset", "4px", Origin::kAuthor);
2056   cascade.Add("border-image-repeat", "space", Origin::kAuthor);
2057   cascade.Apply();
2058 
2059   EXPECT_EQ(gradient2, cascade.ComputedValue("border-image-source"));
2060   EXPECT_EQ("20", cascade.ComputedValue("border-image-slice"));
2061   EXPECT_EQ("6px", cascade.ComputedValue("border-image-width"));
2062   EXPECT_EQ("4px", cascade.ComputedValue("border-image-outset"));
2063   EXPECT_EQ("space", cascade.ComputedValue("border-image-repeat"));
2064 }
2065 
TEST_F(StyleCascadeTest,WebkitBorderImageReverseCascadeOrder)2066 TEST_F(StyleCascadeTest, WebkitBorderImageReverseCascadeOrder) {
2067   String gradient1("linear-gradient(rgb(0, 0, 0), rgb(0, 128, 0))");
2068   String gradient2("linear-gradient(rgb(0, 0, 0), rgb(0, 200, 0))");
2069 
2070   TestCascade cascade(GetDocument());
2071   cascade.Add("border-image-source", gradient2, Origin::kAuthor);
2072   cascade.Add("border-image-slice", "20", Origin::kAuthor);
2073   cascade.Add("border-image-width", "6px", Origin::kAuthor);
2074   cascade.Add("border-image-outset", "4px", Origin::kAuthor);
2075   cascade.Add("border-image-repeat", "space", Origin::kAuthor);
2076   cascade.Add("-webkit-border-image", gradient1 + " round 40 / 10px / 20px",
2077               Origin::kAuthor);
2078   cascade.Apply();
2079 
2080   EXPECT_EQ(gradient1, cascade.ComputedValue("border-image-source"));
2081   EXPECT_EQ("40 fill", cascade.ComputedValue("border-image-slice"));
2082   EXPECT_EQ("10px", cascade.ComputedValue("border-image-width"));
2083   EXPECT_EQ("20px", cascade.ComputedValue("border-image-outset"));
2084   EXPECT_EQ("round", cascade.ComputedValue("border-image-repeat"));
2085 }
2086 
TEST_F(StyleCascadeTest,WebkitBorderImageMixedOrder)2087 TEST_F(StyleCascadeTest, WebkitBorderImageMixedOrder) {
2088   String gradient1("linear-gradient(rgb(0, 0, 0), rgb(0, 128, 0))");
2089   String gradient2("linear-gradient(rgb(0, 0, 0), rgb(0, 200, 0))");
2090 
2091   TestCascade cascade(GetDocument());
2092   cascade.Add("border-image-source", gradient2, Origin::kAuthor);
2093   cascade.Add("border-image-width", "6px", Origin::kAuthor);
2094   cascade.Add("-webkit-border-image", gradient1 + " round 40 / 10px / 20px",
2095               Origin::kAuthor);
2096   cascade.Add("border-image-slice", "20", Origin::kAuthor);
2097   cascade.Add("border-image-outset", "4px", Origin::kAuthor);
2098   cascade.Add("border-image-repeat", "space", Origin::kAuthor);
2099   cascade.Apply();
2100 
2101   EXPECT_EQ(gradient1, cascade.ComputedValue("border-image-source"));
2102   EXPECT_EQ("20", cascade.ComputedValue("border-image-slice"));
2103   EXPECT_EQ("10px", cascade.ComputedValue("border-image-width"));
2104   EXPECT_EQ("4px", cascade.ComputedValue("border-image-outset"));
2105   EXPECT_EQ("space", cascade.ComputedValue("border-image-repeat"));
2106 }
2107 
TEST_F(StyleCascadeTest,MarkReferenced)2108 TEST_F(StyleCascadeTest, MarkReferenced) {
2109   RegisterProperty(GetDocument(), "--x", "<length>", "0px", false);
2110   RegisterProperty(GetDocument(), "--y", "<length>", "0px", false);
2111 
2112   TestCascade cascade(GetDocument());
2113   cascade.Add("width", "var(--x)");
2114   cascade.Apply();
2115 
2116   const auto* registry = GetDocument().GetPropertyRegistry();
2117   ASSERT_TRUE(registry);
2118 
2119   EXPECT_TRUE(registry->WasReferenced("--x"));
2120   EXPECT_FALSE(registry->WasReferenced("--y"));
2121 }
2122 
TEST_F(StyleCascadeTest,MarkHasVariableReferenceLonghand)2123 TEST_F(StyleCascadeTest, MarkHasVariableReferenceLonghand) {
2124   TestCascade cascade(GetDocument());
2125   cascade.Add("--x", "1px");
2126   cascade.Add("width", "var(--x)");
2127   cascade.Apply();
2128   auto style = cascade.TakeStyle();
2129   EXPECT_TRUE(style->HasVariableReferenceFromNonInheritedProperty());
2130 }
2131 
TEST_F(StyleCascadeTest,MarkHasVariableReferenceShorthand)2132 TEST_F(StyleCascadeTest, MarkHasVariableReferenceShorthand) {
2133   TestCascade cascade(GetDocument());
2134   cascade.Add("--x", "1px");
2135   cascade.Add("margin", "var(--x)");
2136   cascade.Apply();
2137   auto style = cascade.TakeStyle();
2138   EXPECT_TRUE(style->HasVariableReferenceFromNonInheritedProperty());
2139 }
2140 
TEST_F(StyleCascadeTest,MarkHasVariableReferenceLonghandMissingVar)2141 TEST_F(StyleCascadeTest, MarkHasVariableReferenceLonghandMissingVar) {
2142   TestCascade cascade(GetDocument());
2143   cascade.Add("width", "var(--x)");
2144   cascade.Apply();
2145   auto style = cascade.TakeStyle();
2146   EXPECT_TRUE(style->HasVariableReferenceFromNonInheritedProperty());
2147 }
2148 
TEST_F(StyleCascadeTest,MarkHasVariableReferenceShorthandMissingVar)2149 TEST_F(StyleCascadeTest, MarkHasVariableReferenceShorthandMissingVar) {
2150   TestCascade cascade(GetDocument());
2151   cascade.Add("margin", "var(--x)");
2152   cascade.Apply();
2153   auto style = cascade.TakeStyle();
2154   EXPECT_TRUE(style->HasVariableReferenceFromNonInheritedProperty());
2155 }
2156 
TEST_F(StyleCascadeTest,NoMarkHasVariableReferenceInherited)2157 TEST_F(StyleCascadeTest, NoMarkHasVariableReferenceInherited) {
2158   TestCascade cascade(GetDocument());
2159   cascade.Add("color", "var(--x)");
2160   cascade.Apply();
2161   auto style = cascade.TakeStyle();
2162   EXPECT_FALSE(style->HasVariableReferenceFromNonInheritedProperty());
2163 }
2164 
TEST_F(StyleCascadeTest,NoMarkHasVariableReferenceWithoutVar)2165 TEST_F(StyleCascadeTest, NoMarkHasVariableReferenceWithoutVar) {
2166   TestCascade cascade(GetDocument());
2167   cascade.Add("width", "1px");
2168   cascade.Apply();
2169   auto style = cascade.TakeStyle();
2170   EXPECT_FALSE(style->HasVariableReferenceFromNonInheritedProperty());
2171 }
2172 
TEST_F(StyleCascadeTest,InternalVisitedColorLonghand)2173 TEST_F(StyleCascadeTest, InternalVisitedColorLonghand) {
2174   TestCascade cascade(GetDocument());
2175   cascade.Add("color:green", CascadeOrigin::kAuthor);
2176   cascade.Add("color:red", CascadeOrigin::kAuthor, CSSSelector::kMatchVisited);
2177 
2178   cascade.State().Style()->SetInsideLink(EInsideLink::kInsideVisitedLink);
2179   cascade.Apply();
2180 
2181   EXPECT_EQ("rgb(0, 128, 0)", cascade.ComputedValue("color"));
2182 
2183   Color red(255, 0, 0);
2184   const CSSProperty& color = GetCSSPropertyColor();
2185   EXPECT_EQ(red, cascade.TakeStyle()->VisitedDependentColor(color));
2186 }
2187 
TEST_F(StyleCascadeTest,VarInInternalVisitedColorShorthand)2188 TEST_F(StyleCascadeTest, VarInInternalVisitedColorShorthand) {
2189   TestCascade cascade(GetDocument());
2190   cascade.Add("--x:red", CascadeOrigin::kAuthor);
2191   cascade.Add("outline:medium solid var(--x)", CascadeOrigin::kAuthor,
2192               CSSSelector::kMatchVisited);
2193   cascade.Add("outline-color:green", CascadeOrigin::kAuthor,
2194               CSSSelector::kMatchLink);
2195 
2196   cascade.State().Style()->SetInsideLink(EInsideLink::kInsideVisitedLink);
2197   cascade.Apply();
2198 
2199   EXPECT_EQ("rgb(0, 128, 0)", cascade.ComputedValue("outline-color"));
2200 
2201   Color red(255, 0, 0);
2202   const CSSProperty& outline_color = GetCSSPropertyOutlineColor();
2203   EXPECT_EQ(red, cascade.TakeStyle()->VisitedDependentColor(outline_color));
2204 }
2205 
TEST_F(StyleCascadeTest,ApplyWithFilter)2206 TEST_F(StyleCascadeTest, ApplyWithFilter) {
2207   TestCascade cascade(GetDocument());
2208   cascade.Add("color", "blue", Origin::kAuthor);
2209   cascade.Add("background-color", "green", Origin::kAuthor);
2210   cascade.Add("display", "inline", Origin::kAuthor);
2211   cascade.Apply();
2212   cascade.Add("color", "green", Origin::kAuthor);
2213   cascade.Add("background-color", "red", Origin::kAuthor);
2214   cascade.Add("display", "block", Origin::kAuthor);
2215   cascade.Apply(CascadeFilter(CSSProperty::kInherited, false));
2216   EXPECT_EQ("rgb(0, 128, 0)", cascade.ComputedValue("color"));
2217   EXPECT_EQ("rgb(0, 128, 0)", cascade.ComputedValue("background-color"));
2218   EXPECT_EQ("inline", cascade.ComputedValue("display"));
2219 }
2220 
TEST_F(StyleCascadeTest,HasAuthorBackground)2221 TEST_F(StyleCascadeTest, HasAuthorBackground) {
2222   Vector<String> properties = {"background-attachment"/*, "background-blend-mode",
2223                                "background-clip",       "background-image",
2224                                "background-origin",     "background-position-x",
2225                                "background-position-y", "background-size"*/};
2226 
2227   for (String property : properties) {
2228     TestCascade cascade(GetDocument());
2229     cascade.Add("-webkit-appearance", "button", Origin::kUserAgent);
2230     cascade.Add(property, "unset", Origin::kAuthor);
2231     cascade.Apply();
2232     EXPECT_TRUE(cascade.TakeStyle()->HasAuthorBackground());
2233   }
2234 }
2235 
TEST_F(StyleCascadeTest,HasAuthorBorder)2236 TEST_F(StyleCascadeTest, HasAuthorBorder) {
2237   Vector<String> properties = {
2238       "border-top-color",          "border-right-color",
2239       "border-bottom-color",       "border-left-color",
2240       "border-top-style",          "border-right-style",
2241       "border-bottom-style",       "border-left-style",
2242       "border-top-width",          "border-right-width",
2243       "border-bottom-width",       "border-left-width",
2244       "border-top-left-radius",    "border-top-right-radius",
2245       "border-bottom-left-radius", "border-bottom-right-radius",
2246       "border-image-source",       "border-image-slice",
2247       "border-image-width",        "border-image-outset",
2248       "border-image-repeat"};
2249 
2250   for (String property : properties) {
2251     TestCascade cascade(GetDocument());
2252     cascade.Add("-webkit-appearance", "button", Origin::kUserAgent);
2253     cascade.Add(property, "unset", Origin::kAuthor);
2254     cascade.Apply();
2255     EXPECT_TRUE(cascade.TakeStyle()->HasAuthorBorder());
2256   }
2257 }
2258 
TEST_F(StyleCascadeTest,NoAuthorBackgroundOrBorder)2259 TEST_F(StyleCascadeTest, NoAuthorBackgroundOrBorder) {
2260   TestCascade cascade(GetDocument());
2261   cascade.Add("-webkit-appearance", "button", Origin::kUserAgent);
2262   cascade.Add("background-color", "red", Origin::kUserAgent);
2263   cascade.Add("border-left-color", "green", Origin::kUserAgent);
2264   cascade.Add("background-clip", "padding-box", Origin::kUser);
2265   cascade.Add("border-right-color", "green", Origin::kUser);
2266   cascade.Apply();
2267   auto style = cascade.TakeStyle();
2268   EXPECT_FALSE(style->HasAuthorBackground());
2269   EXPECT_FALSE(style->HasAuthorBorder());
2270 }
2271 
TEST_F(StyleCascadeTest,AnalyzeMatchResult)2272 TEST_F(StyleCascadeTest, AnalyzeMatchResult) {
2273   auto ua = CascadeOrigin::kUserAgent;
2274   auto author = CascadeOrigin::kAuthor;
2275 
2276   TestCascade cascade(GetDocument());
2277   cascade.Add("display:none;left:5px", ua);
2278   cascade.Add("font-size:1px !important", ua);
2279   cascade.Add("display:block;color:red", author);
2280   cascade.Add("font-size:3px", author);
2281   cascade.Apply();
2282 
2283   EXPECT_EQ(cascade.GetPriority("display").GetOrigin(), author);
2284   EXPECT_EQ(cascade.GetPriority("left").GetOrigin(), ua);
2285   EXPECT_EQ(cascade.GetPriority("color").GetOrigin(), author);
2286   EXPECT_EQ(cascade.GetPriority("font-size").GetOrigin(), ua);
2287 }
2288 
TEST_F(StyleCascadeTest,AnalyzeMatchResultAll)2289 TEST_F(StyleCascadeTest, AnalyzeMatchResultAll) {
2290   auto ua = CascadeOrigin::kUserAgent;
2291   auto author = CascadeOrigin::kAuthor;
2292 
2293   TestCascade cascade(GetDocument());
2294   cascade.Add("display:block", ua);
2295   cascade.Add("font-size:1px !important", ua);
2296   cascade.Add("all:unset", author);
2297   cascade.Apply();
2298 
2299   EXPECT_EQ(cascade.GetPriority("display").GetOrigin(), author);
2300   EXPECT_EQ(cascade.GetPriority("font-size").GetOrigin(), ua);
2301 
2302   // Random sample from another property affected by 'all'.
2303   EXPECT_EQ(cascade.GetPriority("color").GetOrigin(), author);
2304   EXPECT_EQ(cascade.GetPriority("color"), cascade.GetPriority("display"));
2305 }
2306 
TEST_F(StyleCascadeTest,ApplyMatchResultFilter)2307 TEST_F(StyleCascadeTest, ApplyMatchResultFilter) {
2308   TestCascade cascade(GetDocument());
2309   cascade.Add("display:block");
2310   cascade.Add("color:green");
2311   cascade.Add("font-size:3px");
2312   cascade.Apply();
2313 
2314   cascade.Add("display:inline");
2315   cascade.Add("color:red");
2316   cascade.Apply(CascadeFilter(CSSProperty::kInherited, true));
2317 
2318   EXPECT_EQ("inline", cascade.ComputedValue("display"));
2319   EXPECT_EQ("rgb(0, 128, 0)", cascade.ComputedValue("color"));
2320   EXPECT_EQ("3px", cascade.ComputedValue("font-size"));
2321 }
2322 
TEST_F(StyleCascadeTest,ApplyMatchResultAllFilter)2323 TEST_F(StyleCascadeTest, ApplyMatchResultAllFilter) {
2324   TestCascade cascade(GetDocument());
2325   cascade.Add("color:green");
2326   cascade.Add("display:block");
2327   cascade.Apply();
2328 
2329   cascade.Add("all:unset");
2330   cascade.Apply(CascadeFilter(CSSProperty::kInherited, true));
2331 
2332   EXPECT_EQ("rgb(0, 128, 0)", cascade.ComputedValue("color"));
2333   EXPECT_EQ("inline", cascade.ComputedValue("display"));
2334 }
2335 
TEST_F(StyleCascadeTest,MarkHasReferenceLonghand)2336 TEST_F(StyleCascadeTest, MarkHasReferenceLonghand) {
2337   TestCascade cascade(GetDocument());
2338 
2339   cascade.Add("--x:red");
2340   cascade.Add("background-color:var(--x)");
2341   cascade.Apply();
2342 
2343   EXPECT_TRUE(cascade.State()
2344                   .StyleRef()
2345                   .HasVariableReferenceFromNonInheritedProperty());
2346 }
2347 
TEST_F(StyleCascadeTest,MarkHasReferenceShorthand)2348 TEST_F(StyleCascadeTest, MarkHasReferenceShorthand) {
2349   TestCascade cascade(GetDocument());
2350 
2351   cascade.Add("--x:red");
2352   cascade.Add("background:var(--x)");
2353   cascade.Apply();
2354 
2355   EXPECT_TRUE(cascade.State()
2356                   .StyleRef()
2357                   .HasVariableReferenceFromNonInheritedProperty());
2358 }
2359 
TEST_F(StyleCascadeTest,NoMarkHasReferenceForInherited)2360 TEST_F(StyleCascadeTest, NoMarkHasReferenceForInherited) {
2361   TestCascade cascade(GetDocument());
2362 
2363   cascade.Add("--x:red");
2364   cascade.Add("--y:caption");
2365   cascade.Add("color:var(--x)");
2366   cascade.Add("font:var(--y)");
2367   cascade.Apply();
2368 
2369   EXPECT_FALSE(cascade.State()
2370                    .StyleRef()
2371                    .HasVariableReferenceFromNonInheritedProperty());
2372 }
2373 
TEST_F(StyleCascadeTest,Reset)2374 TEST_F(StyleCascadeTest, Reset) {
2375   TestCascade cascade(GetDocument());
2376 
2377   EXPECT_EQ(CascadePriority(), cascade.GetPriority("color"));
2378   EXPECT_EQ(CascadePriority(), cascade.GetPriority("--x"));
2379 
2380   cascade.Add("color:red");
2381   cascade.Add("--x:red");
2382   cascade.Apply();  // generation=1
2383   cascade.Apply();  // generation=2
2384 
2385   EXPECT_EQ(2u, cascade.GetPriority("color").GetGeneration());
2386   EXPECT_EQ(2u, cascade.GetPriority("--x").GetGeneration());
2387 
2388   cascade.Reset();
2389 
2390   EXPECT_EQ(CascadePriority(), cascade.GetPriority("color"));
2391   EXPECT_EQ(CascadePriority(), cascade.GetPriority("--x"));
2392 }
2393 
2394 }  // namespace blink
2395