1 // Copyright 2020 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/matched_properties_cache.h"
6
7 #include "third_party/blink/renderer/core/css/css_property_name.h"
8 #include "third_party/blink/renderer/core/css/css_test_helpers.h"
9 #include "third_party/blink/renderer/core/css/resolver/style_resolver.h"
10 #include "third_party/blink/renderer/core/html/html_element.h"
11 #include "third_party/blink/renderer/core/style/computed_style.h"
12 #include "third_party/blink/renderer/core/testing/page_test_base.h"
13 #include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h"
14
15 namespace blink {
16
17 using css_test_helpers::CreateVariableData;
18
19 class MatchedPropertiesCacheTestKey {
20 STACK_ALLOCATED();
21
22 public:
MatchedPropertiesCacheTestKey(String block_text,unsigned hash,const TreeScope & tree_scope)23 explicit MatchedPropertiesCacheTestKey(String block_text,
24 unsigned hash,
25 const TreeScope& tree_scope)
26 : key_(ParseBlock(block_text, tree_scope), hash) {}
27
InnerKey() const28 const MatchedPropertiesCache::Key& InnerKey() const { return key_; }
29
30 private:
ParseBlock(String block_text,const TreeScope & tree_scope)31 const MatchResult& ParseBlock(String block_text,
32 const TreeScope& tree_scope) {
33 result_.FinishAddingUARules();
34 result_.FinishAddingUserRules();
35 auto* set = css_test_helpers::ParseDeclarationBlock(block_text);
36 result_.AddMatchedProperties(set);
37 result_.FinishAddingAuthorRulesForTreeScope(tree_scope);
38 return result_;
39 }
40
41 MatchResult result_;
42 MatchedPropertiesCache::Key key_;
43 };
44
45 using TestKey = MatchedPropertiesCacheTestKey;
46
47 class MatchedPropertiesCacheTestCache {
48 STACK_ALLOCATED();
49
50 public:
MatchedPropertiesCacheTestCache(Document & document)51 explicit MatchedPropertiesCacheTestCache(Document& document)
52 : document_(document) {}
53
~MatchedPropertiesCacheTestCache()54 ~MatchedPropertiesCacheTestCache() {
55 // Required by DCHECK in ~MatchedPropertiesCache.
56 cache_.Clear();
57 }
58
Add(const TestKey & key,const ComputedStyle & style,const ComputedStyle & parent_style,const Vector<String> & dependencies=Vector<String> ())59 void Add(const TestKey& key,
60 const ComputedStyle& style,
61 const ComputedStyle& parent_style,
62 const Vector<String>& dependencies = Vector<String>()) {
63 HashSet<CSSPropertyName> set;
64 for (String name_string : dependencies) {
65 set.insert(
66 *CSSPropertyName::From(document_.GetExecutionContext(), name_string));
67 }
68 cache_.Add(key.InnerKey(), style, parent_style, set);
69 }
70
Find(const TestKey & key,const ComputedStyle & style,const ComputedStyle & parent_style)71 const CachedMatchedProperties* Find(const TestKey& key,
72 const ComputedStyle& style,
73 const ComputedStyle& parent_style) {
74 StyleResolverState state(document_, *document_.body(), &parent_style,
75 &parent_style);
76 state.SetStyle(ComputedStyle::Clone(style));
77 return cache_.Find(key.InnerKey(), state);
78 }
79
80 private:
81 MatchedPropertiesCache cache_;
82 Document& document_;
83 };
84
85 using TestCache = MatchedPropertiesCacheTestCache;
86
87 class MatchedPropertiesCacheTest
88 : public PageTestBase,
89 private ScopedCSSMatchedPropertiesCacheDependenciesForTest {
90 public:
MatchedPropertiesCacheTest()91 MatchedPropertiesCacheTest()
92 : ScopedCSSMatchedPropertiesCacheDependenciesForTest(true) {}
93
CreateStyle()94 scoped_refptr<ComputedStyle> CreateStyle() {
95 return StyleResolver::InitialStyleForElement(GetDocument());
96 }
97 };
98
TEST_F(MatchedPropertiesCacheTest,ClearEntry)99 TEST_F(MatchedPropertiesCacheTest, ClearEntry) {
100 MatchResult result;
101 result.AddMatchedProperties(
102 css_test_helpers::ParseDeclarationBlock("top:inherit"));
103
104 auto style = CreateStyle();
105 auto parent = CreateStyle();
106
107 HashSet<CSSPropertyName> dependencies;
108 dependencies.insert(CSSPropertyName(CSSPropertyID::kTop));
109
110 auto* entry = MakeGarbageCollected<CachedMatchedProperties>();
111 entry->Set(*style, *parent, result.GetMatchedProperties(), dependencies);
112
113 EXPECT_TRUE(entry->computed_style);
114 EXPECT_TRUE(entry->parent_computed_style);
115 EXPECT_FALSE(entry->matched_properties.IsEmpty());
116 EXPECT_FALSE(entry->matched_properties_types.IsEmpty());
117 EXPECT_TRUE(entry->dependencies);
118
119 entry->Clear();
120
121 EXPECT_FALSE(entry->computed_style);
122 EXPECT_FALSE(entry->parent_computed_style);
123 EXPECT_TRUE(entry->matched_properties.IsEmpty());
124 EXPECT_TRUE(entry->matched_properties_types.IsEmpty());
125 EXPECT_FALSE(entry->dependencies);
126 }
127
TEST_F(MatchedPropertiesCacheTest,NoDependencies)128 TEST_F(MatchedPropertiesCacheTest, NoDependencies) {
129 MatchResult result;
130 auto style = CreateStyle();
131 auto parent = CreateStyle();
132
133 HashSet<CSSPropertyName> dependencies;
134
135 auto* entry = MakeGarbageCollected<CachedMatchedProperties>();
136 entry->Set(*style, *parent, result.GetMatchedProperties(), dependencies);
137
138 EXPECT_FALSE(entry->dependencies);
139 }
140
TEST_F(MatchedPropertiesCacheTest,OneDependency)141 TEST_F(MatchedPropertiesCacheTest, OneDependency) {
142 MatchResult result;
143 auto style = CreateStyle();
144 auto parent = CreateStyle();
145
146 HashSet<CSSPropertyName> dependencies;
147 dependencies.insert(CSSPropertyName(CSSPropertyID::kTop));
148
149 auto* entry = MakeGarbageCollected<CachedMatchedProperties>();
150 entry->Set(*style, *parent, result.GetMatchedProperties(), dependencies);
151
152 ASSERT_TRUE(entry->dependencies);
153 EXPECT_EQ("top", entry->dependencies[0]);
154 EXPECT_EQ(g_null_atom, entry->dependencies[1]);
155 }
156
TEST_F(MatchedPropertiesCacheTest,TwoDependencies)157 TEST_F(MatchedPropertiesCacheTest, TwoDependencies) {
158 MatchResult result;
159 auto style = CreateStyle();
160 auto parent = CreateStyle();
161
162 HashSet<CSSPropertyName> dependencies;
163 dependencies.insert(CSSPropertyName(CSSPropertyID::kTop));
164 dependencies.insert(CSSPropertyName(CSSPropertyID::kLeft));
165
166 auto* entry = MakeGarbageCollected<CachedMatchedProperties>();
167 entry->Set(*style, *parent, result.GetMatchedProperties(), dependencies);
168
169 ASSERT_TRUE(entry->dependencies);
170 EXPECT_TRUE(entry->dependencies[0] == "top" ||
171 entry->dependencies[0] == "left");
172 EXPECT_TRUE(entry->dependencies[1] == "top" ||
173 entry->dependencies[1] == "left");
174 EXPECT_NE(entry->dependencies[0], entry->dependencies[1]);
175 EXPECT_TRUE(entry->dependencies[2] == g_null_atom);
176 }
177
TEST_F(MatchedPropertiesCacheTest,AllowedKeyValues)178 TEST_F(MatchedPropertiesCacheTest, AllowedKeyValues) {
179 unsigned empty = HashTraits<unsigned>::EmptyValue();
180 unsigned deleted = std::numeric_limits<unsigned>::max();
181
182 ASSERT_EQ(0u, HashTraits<unsigned>::EmptyValue());
183 ASSERT_TRUE(HashTraits<unsigned>::IsDeletedValue(deleted));
184
185 EXPECT_FALSE(TestKey("left:0", empty, GetDocument()).InnerKey().IsValid());
186 EXPECT_TRUE(TestKey("left:0", empty + 1, GetDocument()).InnerKey().IsValid());
187 EXPECT_TRUE(
188 TestKey("left:0", deleted - 1, GetDocument()).InnerKey().IsValid());
189 EXPECT_FALSE(TestKey("left:0", deleted, GetDocument()).InnerKey().IsValid());
190 }
191
TEST_F(MatchedPropertiesCacheTest,InvalidKeyForUncacheableMatchResult)192 TEST_F(MatchedPropertiesCacheTest, InvalidKeyForUncacheableMatchResult) {
193 MatchResult result;
194 result.SetIsCacheable(false);
195 EXPECT_FALSE(MatchedPropertiesCache::Key(result).IsValid());
196 }
197
TEST_F(MatchedPropertiesCacheTest,Miss)198 TEST_F(MatchedPropertiesCacheTest, Miss) {
199 TestCache cache(GetDocument());
200 TestKey key("color:red", 1, GetDocument());
201
202 auto style = CreateStyle();
203 auto parent = CreateStyle();
204
205 EXPECT_FALSE(cache.Find(key, *style, *parent));
206 }
207
TEST_F(MatchedPropertiesCacheTest,Hit)208 TEST_F(MatchedPropertiesCacheTest, Hit) {
209 TestCache cache(GetDocument());
210 TestKey key("color:red", 1, GetDocument());
211
212 auto style = CreateStyle();
213 auto parent = CreateStyle();
214
215 cache.Add(key, *style, *parent);
216 EXPECT_TRUE(cache.Find(key, *style, *parent));
217 }
218
TEST_F(MatchedPropertiesCacheTest,HitOnlyForAddedEntry)219 TEST_F(MatchedPropertiesCacheTest, HitOnlyForAddedEntry) {
220 TestCache cache(GetDocument());
221
222 auto style = CreateStyle();
223 auto parent = CreateStyle();
224
225 TestKey key1("color:red", 1, GetDocument());
226 TestKey key2("display:block", 2, GetDocument());
227
228 cache.Add(key1, *style, *parent);
229
230 EXPECT_TRUE(cache.Find(key1, *style, *parent));
231 EXPECT_FALSE(cache.Find(key2, *style, *parent));
232 }
233
TEST_F(MatchedPropertiesCacheTest,HitWithStandardDependency)234 TEST_F(MatchedPropertiesCacheTest, HitWithStandardDependency) {
235 TestCache cache(GetDocument());
236
237 auto style = CreateStyle();
238 auto parent = CreateStyle();
239
240 TestKey key("top:inherit", 1, GetDocument());
241
242 cache.Add(key, *style, *parent, Vector<String>{"top"});
243 EXPECT_TRUE(cache.Find(key, *style, *parent));
244 }
245
TEST_F(MatchedPropertiesCacheTest,MissWithStandardDependency)246 TEST_F(MatchedPropertiesCacheTest, MissWithStandardDependency) {
247 TestCache cache(GetDocument());
248
249 auto style = CreateStyle();
250
251 auto parent1 = CreateStyle();
252 parent1->SetTop(Length(1, Length::kFixed));
253
254 auto parent2 = CreateStyle();
255 parent2->SetTop(Length(2, Length::kFixed));
256
257 TestKey key("top:inherit", 1, GetDocument());
258 cache.Add(key, *style, *parent1, Vector<String>{"top"});
259 EXPECT_TRUE(cache.Find(key, *style, *parent1));
260 EXPECT_FALSE(cache.Find(key, *style, *parent2));
261 }
262
TEST_F(MatchedPropertiesCacheTest,HitWithCustomDependency)263 TEST_F(MatchedPropertiesCacheTest, HitWithCustomDependency) {
264 TestCache cache(GetDocument());
265
266 auto style = CreateStyle();
267
268 auto parent = CreateStyle();
269 parent->SetVariableData("--x", CreateVariableData("1px"), true);
270
271 TestKey key("top:var(--x)", 1, GetDocument());
272
273 cache.Add(key, *style, *parent, Vector<String>{"--x"});
274 EXPECT_TRUE(cache.Find(key, *style, *parent));
275 }
276
TEST_F(MatchedPropertiesCacheTest,MissWithCustomDependency)277 TEST_F(MatchedPropertiesCacheTest, MissWithCustomDependency) {
278 TestCache cache(GetDocument());
279
280 auto style = CreateStyle();
281
282 auto parent1 = CreateStyle();
283 parent1->SetVariableData("--x", CreateVariableData("1px"), true);
284
285 auto parent2 = CreateStyle();
286 parent2->SetVariableData("--x", CreateVariableData("2px"), true);
287
288 TestKey key("top:var(--x)", 1, GetDocument());
289
290 cache.Add(key, *style, *parent1, Vector<String>{"--x"});
291 EXPECT_FALSE(cache.Find(key, *style, *parent2));
292 }
293
TEST_F(MatchedPropertiesCacheTest,HitWithMultipleCustomDependencies)294 TEST_F(MatchedPropertiesCacheTest, HitWithMultipleCustomDependencies) {
295 TestCache cache(GetDocument());
296
297 auto style = CreateStyle();
298
299 auto parent1 = CreateStyle();
300 parent1->SetVariableData("--x", CreateVariableData("1px"), true);
301 parent1->SetVariableData("--y", CreateVariableData("2px"), true);
302 parent1->SetVariableData("--z", CreateVariableData("3px"), true);
303
304 auto parent2 = ComputedStyle::Clone(*parent1);
305 parent2->SetVariableData("--z", CreateVariableData("4px"), true);
306
307 TestKey key("top:var(--x);left:var(--y)", 1, GetDocument());
308
309 // Does not depend on --z, so doesn't matter that --z changed.
310 cache.Add(key, *style, *parent1, Vector<String>{"--x", "--y"});
311 EXPECT_TRUE(cache.Find(key, *style, *parent2));
312 }
313
TEST_F(MatchedPropertiesCacheTest,MissWithMultipleCustomDependencies)314 TEST_F(MatchedPropertiesCacheTest, MissWithMultipleCustomDependencies) {
315 TestCache cache(GetDocument());
316
317 auto style = CreateStyle();
318
319 auto parent1 = CreateStyle();
320 parent1->SetVariableData("--x", CreateVariableData("1px"), true);
321 parent1->SetVariableData("--y", CreateVariableData("2px"), true);
322
323 auto parent2 = ComputedStyle::Clone(*parent1);
324 parent2->SetVariableData("--y", CreateVariableData("3px"), true);
325
326 TestKey key("top:var(--x);left:var(--y)", 1, GetDocument());
327
328 cache.Add(key, *style, *parent1, Vector<String>{"--x", "--y"});
329 EXPECT_FALSE(cache.Find(key, *style, *parent2));
330 }
331
TEST_F(MatchedPropertiesCacheTest,HitWithMixedDependencies)332 TEST_F(MatchedPropertiesCacheTest, HitWithMixedDependencies) {
333 TestCache cache(GetDocument());
334
335 auto style = CreateStyle();
336
337 auto parent1 = CreateStyle();
338 parent1->SetVariableData("--x", CreateVariableData("1px"), true);
339 parent1->SetVariableData("--y", CreateVariableData("2px"), true);
340 parent1->SetLeft(Length(3, Length::kFixed));
341 parent1->SetRight(Length(4, Length::kFixed));
342
343 auto parent2 = ComputedStyle::Clone(*parent1);
344 parent2->SetVariableData("--y", CreateVariableData("5px"), true);
345 parent2->SetRight(Length(6, Length::kFixed));
346
347 TestKey key("left:inherit;top:var(--x)", 1, GetDocument());
348
349 cache.Add(key, *style, *parent1, Vector<String>{"left", "--x"});
350 EXPECT_TRUE(cache.Find(key, *style, *parent2));
351 }
352
TEST_F(MatchedPropertiesCacheTest,ExplicitlyInheritedCacheable)353 TEST_F(MatchedPropertiesCacheTest, ExplicitlyInheritedCacheable) {
354 ASSERT_TRUE(GetCSSPropertyVerticalAlign().IsComputedValueComparable());
355
356 TestCache cache(GetDocument());
357
358 auto style = CreateStyle();
359 auto parent = CreateStyle();
360 parent->SetChildHasExplicitInheritance();
361
362 StyleResolverState state(GetDocument(), *GetDocument().body(), parent.get(),
363 parent.get());
364 state.SetStyle(style);
365 // Simulate explicit inheritance on vertical-align.
366 state.MarkDependency(GetCSSPropertyVerticalAlign());
367
368 EXPECT_TRUE(MatchedPropertiesCache::IsCacheable(state));
369 }
370
TEST_F(MatchedPropertiesCacheTest,NotCacheableWithIncomparableDependency)371 TEST_F(MatchedPropertiesCacheTest, NotCacheableWithIncomparableDependency) {
372 const CSSProperty& incomparable = GetCSSPropertyInternalEmptyLineHeight();
373 ASSERT_FALSE(incomparable.IsComputedValueComparable());
374
375 TestCache cache(GetDocument());
376
377 auto style = CreateStyle();
378 auto parent = CreateStyle();
379 parent->SetChildHasExplicitInheritance();
380
381 StyleResolverState state(GetDocument(), *GetDocument().body(), parent.get(),
382 parent.get());
383 state.SetStyle(style);
384 // Simulate explicit inheritance on the incomparable property.
385 state.MarkDependency(incomparable);
386
387 EXPECT_FALSE(MatchedPropertiesCache::IsCacheable(state));
388 }
389
TEST_F(MatchedPropertiesCacheTest,WritingModeCacheable)390 TEST_F(MatchedPropertiesCacheTest, WritingModeCacheable) {
391 ASSERT_NE(WritingMode::kVerticalRl,
392 ComputedStyleInitialValues::InitialWritingMode());
393
394 TestCache cache(GetDocument());
395
396 auto style = CreateStyle();
397 auto parent = CreateStyle();
398 style->SetWritingMode(WritingMode::kVerticalRl);
399
400 StyleResolverState state(GetDocument(), *GetDocument().body(), parent.get(),
401 parent.get());
402 state.SetStyle(style);
403
404 EXPECT_TRUE(MatchedPropertiesCache::IsCacheable(state));
405 }
406
TEST_F(MatchedPropertiesCacheTest,DirectionCacheable)407 TEST_F(MatchedPropertiesCacheTest, DirectionCacheable) {
408 ASSERT_NE(TextDirection::kRtl,
409 ComputedStyleInitialValues::InitialDirection());
410
411 TestCache cache(GetDocument());
412
413 auto style = CreateStyle();
414 auto parent = CreateStyle();
415 style->SetDirection(TextDirection::kRtl);
416
417 StyleResolverState state(GetDocument(), *GetDocument().body(), parent.get(),
418 parent.get());
419 state.SetStyle(style);
420
421 EXPECT_TRUE(MatchedPropertiesCache::IsCacheable(state));
422 }
423
TEST_F(MatchedPropertiesCacheTest,VarInNonInheritedPropertyCachable)424 TEST_F(MatchedPropertiesCacheTest, VarInNonInheritedPropertyCachable) {
425 TestCache cache(GetDocument());
426
427 auto style = CreateStyle();
428 // Simulate non-inherited-property: var(--my-prop)
429 style->SetHasVariableReferenceFromNonInheritedProperty();
430
431 auto parent = CreateStyle();
432
433 StyleResolverState state(GetDocument(), *GetDocument().body(), parent.get(),
434 parent.get());
435 state.SetStyle(style);
436
437 EXPECT_TRUE(MatchedPropertiesCache::IsCacheable(state));
438 }
439
TEST_F(MatchedPropertiesCacheTest,MaxDependencies)440 TEST_F(MatchedPropertiesCacheTest, MaxDependencies) {
441 TestCache cache(GetDocument());
442
443 auto style = CreateStyle();
444 auto parent = CreateStyle();
445
446 StyleResolverState state(GetDocument(), *GetDocument().body(), parent.get(),
447 parent.get());
448 state.SetStyle(style);
449 for (size_t i = 0; i < StyleResolverState::kMaxDependencies; i++) {
450 CustomProperty property(AtomicString(String::Format("--x%zu", i)),
451 GetDocument());
452 state.MarkDependency(property);
453 EXPECT_TRUE(MatchedPropertiesCache::IsCacheable(state));
454 }
455 CustomProperty property("--y", GetDocument());
456 state.MarkDependency(property);
457 // Limit exceeded.
458 EXPECT_FALSE(MatchedPropertiesCache::IsCacheable(state));
459 }
460
TEST_F(MatchedPropertiesCacheTest,ExplicitlyInheritedNotCacheableWithoutFeature)461 TEST_F(MatchedPropertiesCacheTest,
462 ExplicitlyInheritedNotCacheableWithoutFeature) {
463 ScopedCSSMatchedPropertiesCacheDependenciesForTest scoped_feature(false);
464
465 TestCache cache(GetDocument());
466
467 auto style = CreateStyle();
468 auto parent = CreateStyle();
469 parent->SetChildHasExplicitInheritance();
470
471 StyleResolverState state(GetDocument(), *GetDocument().body(), parent.get(),
472 parent.get());
473 state.SetStyle(style);
474
475 EXPECT_FALSE(MatchedPropertiesCache::IsCacheable(state));
476 }
477
TEST_F(MatchedPropertiesCacheTest,VarInNonInheritedPropertyNotCachableWithoutFeature)478 TEST_F(MatchedPropertiesCacheTest,
479 VarInNonInheritedPropertyNotCachableWithoutFeature) {
480 ScopedCSSMatchedPropertiesCacheDependenciesForTest scoped_feature(false);
481
482 TestCache cache(GetDocument());
483
484 auto style = CreateStyle();
485 auto parent = CreateStyle();
486 // Simulate non-inherited-property: var(--my-prop)
487 style->SetHasVariableReferenceFromNonInheritedProperty();
488
489 StyleResolverState state(GetDocument(), *GetDocument().body(), parent.get(),
490 parent.get());
491 state.SetStyle(style);
492
493 EXPECT_FALSE(MatchedPropertiesCache::IsCacheable(state));
494 }
495
TEST_F(MatchedPropertiesCacheTest,WritingModeNotCacheableWithoutFeature)496 TEST_F(MatchedPropertiesCacheTest, WritingModeNotCacheableWithoutFeature) {
497 ScopedCSSMatchedPropertiesCacheDependenciesForTest scoped_feature(false);
498
499 ASSERT_NE(WritingMode::kVerticalRl,
500 ComputedStyleInitialValues::InitialWritingMode());
501
502 TestCache cache(GetDocument());
503
504 auto style = CreateStyle();
505 auto parent = CreateStyle();
506 style->SetWritingMode(WritingMode::kVerticalRl);
507
508 StyleResolverState state(GetDocument(), *GetDocument().body(), parent.get(),
509 parent.get());
510 state.SetStyle(style);
511
512 EXPECT_FALSE(MatchedPropertiesCache::IsCacheable(state));
513 }
514
TEST_F(MatchedPropertiesCacheTest,DirectionNotCacheableWithoutFeature)515 TEST_F(MatchedPropertiesCacheTest, DirectionNotCacheableWithoutFeature) {
516 ScopedCSSMatchedPropertiesCacheDependenciesForTest scoped_feature(false);
517
518 ASSERT_NE(TextDirection::kRtl,
519 ComputedStyleInitialValues::InitialDirection());
520
521 TestCache cache(GetDocument());
522
523 auto style = CreateStyle();
524 auto parent = CreateStyle();
525 style->SetDirection(TextDirection::kRtl);
526
527 StyleResolverState state(GetDocument(), *GetDocument().body(), parent.get(),
528 parent.get());
529 state.SetStyle(style);
530
531 EXPECT_FALSE(MatchedPropertiesCache::IsCacheable(state));
532 }
533
TEST_F(MatchedPropertiesCacheTest,EnsuredInDisplayNone)534 TEST_F(MatchedPropertiesCacheTest, EnsuredInDisplayNone) {
535 TestCache cache(GetDocument());
536
537 auto style = CreateStyle();
538 auto parent = CreateStyle();
539 auto ensured_parent = CreateStyle();
540 ensured_parent->SetIsEnsuredInDisplayNone();
541
542 TestKey key1("display:block", 1, GetDocument());
543
544 cache.Add(key1, *style, *parent);
545 EXPECT_TRUE(cache.Find(key1, *style, *parent));
546 EXPECT_TRUE(cache.Find(key1, *style, *ensured_parent));
547
548 cache.Add(key1, *style, *ensured_parent);
549 EXPECT_FALSE(cache.Find(key1, *style, *parent));
550 EXPECT_TRUE(cache.Find(key1, *style, *ensured_parent));
551 }
552
TEST_F(MatchedPropertiesCacheTest,EnsuredOutsideFlatTree)553 TEST_F(MatchedPropertiesCacheTest, EnsuredOutsideFlatTree) {
554 TestCache cache(GetDocument());
555
556 auto style = CreateStyle();
557 auto parent = CreateStyle();
558 auto ensured_style = CreateStyle();
559 ensured_style->SetIsEnsuredOutsideFlatTree();
560
561 TestKey key1("display:block", 1, GetDocument());
562
563 cache.Add(key1, *style, *parent);
564 EXPECT_TRUE(cache.Find(key1, *style, *parent));
565 EXPECT_TRUE(cache.Find(key1, *ensured_style, *parent));
566
567 cache.Add(key1, *ensured_style, *parent);
568 EXPECT_FALSE(cache.Find(key1, *style, *parent));
569 EXPECT_TRUE(cache.Find(key1, *ensured_style, *parent));
570 }
571
TEST_F(MatchedPropertiesCacheTest,EnsuredOutsideFlatTreeAndDisplayNone)572 TEST_F(MatchedPropertiesCacheTest, EnsuredOutsideFlatTreeAndDisplayNone) {
573 TestCache cache(GetDocument());
574
575 auto parent = CreateStyle();
576 auto parent_none = CreateStyle();
577 auto style = CreateStyle();
578 auto style_flat = CreateStyle();
579 parent_none->SetIsEnsuredInDisplayNone();
580 style_flat->SetIsEnsuredOutsideFlatTree();
581
582 TestKey key1("display:block", 1, GetDocument());
583
584 cache.Add(key1, *style, *parent_none);
585 EXPECT_TRUE(cache.Find(key1, *style_flat, *parent));
586
587 cache.Add(key1, *style_flat, *parent);
588 EXPECT_TRUE(cache.Find(key1, *style, *parent_none));
589 }
590
591 } // namespace blink
592