OLD | NEW |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "core/dom/StyleEngine.h" | 5 #include "core/dom/StyleEngine.h" |
6 | 6 |
7 #include "core/css/StyleSheetContents.h" | 7 #include "core/css/StyleSheetContents.h" |
8 #include "core/dom/Document.h" | 8 #include "core/dom/Document.h" |
9 #include "core/dom/NodeComputedStyle.h" | 9 #include "core/dom/NodeComputedStyle.h" |
| 10 #include "core/dom/shadow/ShadowRootInit.h" |
10 #include "core/frame/FrameView.h" | 11 #include "core/frame/FrameView.h" |
11 #include "core/html/HTMLElement.h" | 12 #include "core/html/HTMLElement.h" |
12 #include "core/html/HTMLStyleElement.h" | 13 #include "core/html/HTMLStyleElement.h" |
13 #include "core/testing/DummyPageHolder.h" | 14 #include "core/testing/DummyPageHolder.h" |
14 #include "platform/heap/Heap.h" | 15 #include "platform/heap/Heap.h" |
15 #include "testing/gtest/include/gtest/gtest.h" | 16 #include "testing/gtest/include/gtest/gtest.h" |
16 #include <memory> | 17 #include <memory> |
17 | 18 |
18 namespace blink { | 19 namespace blink { |
19 | 20 |
20 class StyleEngineTest : public ::testing::Test { | 21 class StyleEngineTest : public ::testing::Test { |
21 protected: | 22 protected: |
22 void SetUp() override; | 23 void SetUp() override; |
23 | 24 |
24 Document& document() { return m_dummyPageHolder->document(); } | 25 Document& document() { return m_dummyPageHolder->document(); } |
25 StyleEngine& styleEngine() { return document().styleEngine(); } | 26 StyleEngine& styleEngine() { return document().styleEngine(); } |
26 | 27 |
27 bool isDocumentStyleSheetCollectionClean() { return !styleEngine().shouldUpd
ateDocumentStyleSheetCollection(AnalyzedStyleUpdate); } | 28 bool isDocumentStyleSheetCollectionClean() { return !styleEngine().shouldUpd
ateDocumentStyleSheetCollection(AnalyzedStyleUpdate); } |
28 | 29 |
| 30 enum RuleSetInvalidation { RuleSetInvalidationsScheduled, RuleSetInvalidatio
nFullRecalc }; |
| 31 RuleSetInvalidation scheduleInvalidationsForRules(TreeScope&, const String&
cssText); |
| 32 |
29 private: | 33 private: |
30 std::unique_ptr<DummyPageHolder> m_dummyPageHolder; | 34 std::unique_ptr<DummyPageHolder> m_dummyPageHolder; |
31 }; | 35 }; |
32 | 36 |
33 void StyleEngineTest::SetUp() | 37 void StyleEngineTest::SetUp() |
34 { | 38 { |
35 m_dummyPageHolder = DummyPageHolder::create(IntSize(800, 600)); | 39 m_dummyPageHolder = DummyPageHolder::create(IntSize(800, 600)); |
36 } | 40 } |
37 | 41 |
| 42 StyleEngineTest::RuleSetInvalidation |
| 43 StyleEngineTest::scheduleInvalidationsForRules(TreeScope& treeScope, const Strin
g& cssText) |
| 44 { |
| 45 StyleSheetContents* sheet = StyleSheetContents::create(CSSParserContext(HTML
StandardMode, nullptr)); |
| 46 sheet->parseString(cssText); |
| 47 HeapVector<Member<const RuleSet>> ruleSets; |
| 48 RuleSet& ruleSet = sheet->ensureRuleSet(MediaQueryEvaluator(), RuleHasDocume
ntSecurityOrigin); |
| 49 ruleSet.compactRulesIfNeeded(); |
| 50 if (ruleSet.needsFullRecalcForRuleSetInvalidation()) |
| 51 return RuleSetInvalidationFullRecalc; |
| 52 ruleSets.append(&ruleSet); |
| 53 styleEngine().scheduleInvalidationsForRuleSets(treeScope, ruleSets); |
| 54 return RuleSetInvalidationsScheduled; |
| 55 } |
| 56 |
38 TEST_F(StyleEngineTest, DocumentDirtyAfterInject) | 57 TEST_F(StyleEngineTest, DocumentDirtyAfterInject) |
39 { | 58 { |
40 StyleSheetContents* parsedSheet = StyleSheetContents::create(CSSParserContex
t(document(), nullptr)); | 59 StyleSheetContents* parsedSheet = StyleSheetContents::create(CSSParserContex
t(document(), nullptr)); |
41 parsedSheet->parseString("div {}"); | 60 parsedSheet->parseString("div {}"); |
42 styleEngine().injectAuthorSheet(parsedSheet); | 61 styleEngine().injectAuthorSheet(parsedSheet); |
43 document().view()->updateAllLifecyclePhases(); | 62 document().view()->updateAllLifecyclePhases(); |
44 | 63 |
45 EXPECT_TRUE(isDocumentStyleSheetCollectionClean()); | 64 EXPECT_TRUE(isDocumentStyleSheetCollectionClean()); |
46 } | 65 } |
47 | 66 |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
95 // Garbage collection should clear the weak reference in the StyleSheetConte
nts cache. | 114 // Garbage collection should clear the weak reference in the StyleSheetConte
nts cache. |
96 ThreadState::current()-> collectAllGarbage(); | 115 ThreadState::current()-> collectAllGarbage(); |
97 | 116 |
98 element = HTMLStyleElement::create(document(), false); | 117 element = HTMLStyleElement::create(document(), false); |
99 sheet1 = styleEngine().createSheet(element, sheetText, minPos, context); | 118 sheet1 = styleEngine().createSheet(element, sheetText, minPos, context); |
100 | 119 |
101 // Check that we did not use a cached StyleSheetContents after the garbage c
ollection. | 120 // Check that we did not use a cached StyleSheetContents after the garbage c
ollection. |
102 EXPECT_FALSE(sheet1->contents()->isUsedFromTextCache()); | 121 EXPECT_FALSE(sheet1->contents()->isUsedFromTextCache()); |
103 } | 122 } |
104 | 123 |
| 124 TEST_F(StyleEngineTest, RuleSetInvalidationTypeSelectors) |
| 125 { |
| 126 document().body()->setInnerHTML( |
| 127 "<div>" |
| 128 " <span></span>" |
| 129 " <div></div>" |
| 130 "</div>", ASSERT_NO_EXCEPTION); |
| 131 |
| 132 document().view()->updateAllLifecyclePhases(); |
| 133 |
| 134 unsigned beforeCount = styleEngine().styleForElementCount(); |
| 135 EXPECT_EQ(scheduleInvalidationsForRules(document(), "span { background: gree
n}"), RuleSetInvalidationsScheduled); |
| 136 document().view()->updateAllLifecyclePhases(); |
| 137 unsigned afterCount = styleEngine().styleForElementCount(); |
| 138 EXPECT_EQ(1u, afterCount - beforeCount); |
| 139 |
| 140 beforeCount = afterCount; |
| 141 EXPECT_EQ(scheduleInvalidationsForRules(document(), "body div { background:
green}"), RuleSetInvalidationsScheduled); |
| 142 document().view()->updateAllLifecyclePhases(); |
| 143 afterCount = styleEngine().styleForElementCount(); |
| 144 EXPECT_EQ(2u, afterCount - beforeCount); |
| 145 |
| 146 EXPECT_EQ(scheduleInvalidationsForRules(document(), "div * { background: gre
en}"), RuleSetInvalidationFullRecalc); |
| 147 } |
| 148 |
| 149 TEST_F(StyleEngineTest, RuleSetInvalidationHost) |
| 150 { |
| 151 document().body()->setInnerHTML("<div id=nohost></div><div id=host></div>",
ASSERT_NO_EXCEPTION); |
| 152 Element* host = document().getElementById("host"); |
| 153 ASSERT_TRUE(host); |
| 154 |
| 155 ShadowRootInit init; |
| 156 init.setMode("open"); |
| 157 ShadowRoot* shadowRoot = host->attachShadow(ScriptState::forMainWorld(docume
nt().frame()), init, ASSERT_NO_EXCEPTION); |
| 158 ASSERT_TRUE(shadowRoot); |
| 159 |
| 160 shadowRoot->setInnerHTML("<div></div><div></div><div></div>", ASSERT_NO_EXCE
PTION); |
| 161 document().view()->updateAllLifecyclePhases(); |
| 162 |
| 163 unsigned beforeCount = styleEngine().styleForElementCount(); |
| 164 EXPECT_EQ(scheduleInvalidationsForRules(*shadowRoot, ":host(#nohost), #nohos
t { background: green}"), RuleSetInvalidationsScheduled); |
| 165 document().view()->updateAllLifecyclePhases(); |
| 166 unsigned afterCount = styleEngine().styleForElementCount(); |
| 167 EXPECT_EQ(0u, afterCount - beforeCount); |
| 168 |
| 169 beforeCount = afterCount; |
| 170 EXPECT_EQ(scheduleInvalidationsForRules(*shadowRoot, ":host(#host) { backgro
und: green}"), RuleSetInvalidationsScheduled); |
| 171 document().view()->updateAllLifecyclePhases(); |
| 172 afterCount = styleEngine().styleForElementCount(); |
| 173 EXPECT_EQ(1u, afterCount - beforeCount); |
| 174 |
| 175 EXPECT_EQ(scheduleInvalidationsForRules(*shadowRoot, ":host(*) { background:
green}"), RuleSetInvalidationFullRecalc); |
| 176 EXPECT_EQ(scheduleInvalidationsForRules(*shadowRoot, ":host(*) :hover { back
ground: green}"), RuleSetInvalidationFullRecalc); |
| 177 } |
| 178 |
| 179 TEST_F(StyleEngineTest, RuleSetInvalidationSlotted) |
| 180 { |
| 181 document().body()->setInnerHTML( |
| 182 "<div id=host>" |
| 183 " <span slot=other class=s1></span>" |
| 184 " <span class=s2></span>" |
| 185 " <span class=s1></span>" |
| 186 " <span></span>" |
| 187 "</div>", ASSERT_NO_EXCEPTION); |
| 188 |
| 189 Element* host = document().getElementById("host"); |
| 190 ASSERT_TRUE(host); |
| 191 |
| 192 ShadowRootInit init; |
| 193 init.setMode("open"); |
| 194 ShadowRoot* shadowRoot = host->attachShadow(ScriptState::forMainWorld(docume
nt().frame()), init, ASSERT_NO_EXCEPTION); |
| 195 ASSERT_TRUE(shadowRoot); |
| 196 |
| 197 shadowRoot->setInnerHTML("<slot name=other></slot><slot></slot>", ASSERT_NO_
EXCEPTION); |
| 198 document().view()->updateAllLifecyclePhases(); |
| 199 |
| 200 unsigned beforeCount = styleEngine().styleForElementCount(); |
| 201 EXPECT_EQ(scheduleInvalidationsForRules(*shadowRoot, "::slotted(.s1) { backg
round: green}"), RuleSetInvalidationsScheduled); |
| 202 document().view()->updateAllLifecyclePhases(); |
| 203 unsigned afterCount = styleEngine().styleForElementCount(); |
| 204 EXPECT_EQ(4u, afterCount - beforeCount); |
| 205 |
| 206 beforeCount = afterCount; |
| 207 EXPECT_EQ(scheduleInvalidationsForRules(*shadowRoot, "::slotted(*) { backgro
und: green}"), RuleSetInvalidationsScheduled); |
| 208 document().view()->updateAllLifecyclePhases(); |
| 209 afterCount = styleEngine().styleForElementCount(); |
| 210 EXPECT_EQ(4u, afterCount - beforeCount); |
| 211 } |
| 212 |
| 213 TEST_F(StyleEngineTest, RuleSetInvalidationHostContext) |
| 214 { |
| 215 document().body()->setInnerHTML("<div id=host></div>", ASSERT_NO_EXCEPTION); |
| 216 Element* host = document().getElementById("host"); |
| 217 ASSERT_TRUE(host); |
| 218 |
| 219 ShadowRootInit init; |
| 220 init.setMode("open"); |
| 221 ShadowRoot* shadowRoot = host->attachShadow(ScriptState::forMainWorld(docume
nt().frame()), init, ASSERT_NO_EXCEPTION); |
| 222 ASSERT_TRUE(shadowRoot); |
| 223 |
| 224 shadowRoot->setInnerHTML("<div></div><div class=a></div><div></div>", ASSERT
_NO_EXCEPTION); |
| 225 document().view()->updateAllLifecyclePhases(); |
| 226 |
| 227 unsigned beforeCount = styleEngine().styleForElementCount(); |
| 228 EXPECT_EQ(scheduleInvalidationsForRules(*shadowRoot, ":host-context(.nomatch
) .a { background: green}"), RuleSetInvalidationsScheduled); |
| 229 document().view()->updateAllLifecyclePhases(); |
| 230 unsigned afterCount = styleEngine().styleForElementCount(); |
| 231 EXPECT_EQ(1u, afterCount - beforeCount); |
| 232 |
| 233 EXPECT_EQ(scheduleInvalidationsForRules(*shadowRoot, ":host-context(:hover)
{ background: green}"), RuleSetInvalidationFullRecalc); |
| 234 EXPECT_EQ(scheduleInvalidationsForRules(*shadowRoot, ":host-context(#host) {
background: green}"), RuleSetInvalidationFullRecalc); |
| 235 } |
| 236 |
| 237 TEST_F(StyleEngineTest, RuleSetInvalidationV0BoundaryCrossing) |
| 238 { |
| 239 document().body()->setInnerHTML("<div id=host></div>", ASSERT_NO_EXCEPTION); |
| 240 Element* host = document().getElementById("host"); |
| 241 ASSERT_TRUE(host); |
| 242 |
| 243 ShadowRootInit init; |
| 244 init.setMode("open"); |
| 245 ShadowRoot* shadowRoot = host->attachShadow(ScriptState::forMainWorld(docume
nt().frame()), init, ASSERT_NO_EXCEPTION); |
| 246 ASSERT_TRUE(shadowRoot); |
| 247 |
| 248 shadowRoot->setInnerHTML("<div></div><div class=a></div><div></div>", ASSERT
_NO_EXCEPTION); |
| 249 document().view()->updateAllLifecyclePhases(); |
| 250 |
| 251 EXPECT_EQ(scheduleInvalidationsForRules(*shadowRoot, ".a ::content span { ba
ckground: green}"), RuleSetInvalidationFullRecalc); |
| 252 EXPECT_EQ(scheduleInvalidationsForRules(*shadowRoot, ".a /deep/ span { backg
round: green}"), RuleSetInvalidationFullRecalc); |
| 253 EXPECT_EQ(scheduleInvalidationsForRules(*shadowRoot, ".a::shadow span { back
ground: green}"), RuleSetInvalidationFullRecalc); |
| 254 } |
| 255 |
105 } // namespace blink | 256 } // namespace blink |
OLD | NEW |