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/Element.h" | 5 #include "core/dom/Element.h" |
6 | 6 |
7 #include "core/dom/Document.h" | 7 #include "core/dom/Document.h" |
8 #include "core/frame/FrameView.h" | 8 #include "core/frame/FrameView.h" |
9 #include "core/html/HTMLHtmlElement.h" | 9 #include "core/html/HTMLHtmlElement.h" |
10 #include "core/layout/LayoutBoxModelObject.h" | |
11 #include "core/paint/PaintLayer.h" | |
10 #include "core/testing/DummyPageHolder.h" | 12 #include "core/testing/DummyPageHolder.h" |
11 #include "testing/gtest/include/gtest/gtest.h" | 13 #include "testing/gtest/include/gtest/gtest.h" |
12 #include <memory> | 14 #include <memory> |
13 | 15 |
14 namespace blink { | 16 namespace blink { |
15 | 17 |
16 TEST(ElementTest, SupportsFocus) { | 18 TEST(ElementTest, SupportsFocus) { |
17 std::unique_ptr<DummyPageHolder> pageHolder = DummyPageHolder::create(); | 19 std::unique_ptr<DummyPageHolder> pageHolder = DummyPageHolder::create(); |
18 Document& document = pageHolder->document(); | 20 Document& document = pageHolder->document(); |
19 DCHECK(isHTMLHtmlElement(document.documentElement())); | 21 DCHECK(isHTMLHtmlElement(document.documentElement())); |
20 document.setDesignMode("on"); | 22 document.setDesignMode("on"); |
21 document.view()->updateAllLifecyclePhases(); | 23 document.view()->updateAllLifecyclePhases(); |
22 EXPECT_TRUE(document.documentElement()->supportsFocus()) | 24 EXPECT_TRUE(document.documentElement()->supportsFocus()) |
23 << "<html> with designMode=on should be focusable."; | 25 << "<html> with designMode=on should be focusable."; |
24 } | 26 } |
25 | 27 |
28 // Verifies that calling getBoundingClientRect cleans compositor inputs. | |
29 // Cleaning the compositor inputs is required so that position:sticky elements | |
30 // and their descendants have the correct location. | |
31 TEST(ElementTest, GetBoundingClientRectUpdatesCompositorInputs) { | |
32 std::unique_ptr<DummyPageHolder> pageHolder = DummyPageHolder::create(); | |
33 Document& document = pageHolder->document(); | |
34 | |
35 document.view()->updateAllLifecyclePhases(); | |
36 EXPECT_EQ(DocumentLifecycle::PaintClean, document.lifecycle().state()); | |
37 | |
38 document.body()->setInnerHTML("<div id='test'></div>"); | |
39 EXPECT_EQ(DocumentLifecycle::VisualUpdatePending, | |
40 document.lifecycle().state()); | |
41 | |
42 document.body()->getBoundingClientRect(); | |
43 EXPECT_EQ(DocumentLifecycle::CompositingClean, document.lifecycle().state()); | |
44 } | |
45 | |
46 // Verifies that calling scrollIntoView* cleans compositor inputs. Cleaning the | |
47 // compositor inputs is required so that position:sticky elements and their | |
48 // descendants have the correct location. | |
49 TEST(ElementTest, ScrollIntoViewUpdatesCompositorInputs) { | |
50 std::unique_ptr<DummyPageHolder> pageHolder = DummyPageHolder::create(); | |
51 Document& document = pageHolder->document(); | |
52 | |
53 document.view()->updateAllLifecyclePhases(); | |
54 EXPECT_EQ(DocumentLifecycle::PaintClean, document.lifecycle().state()); | |
55 | |
56 document.body()->setInnerHTML("<div id='test'></div>"); | |
57 EXPECT_EQ(DocumentLifecycle::VisualUpdatePending, | |
58 document.lifecycle().state()); | |
59 | |
60 document.body()->scrollIntoView(); | |
61 EXPECT_EQ(DocumentLifecycle::CompositingClean, document.lifecycle().state()); | |
62 | |
63 document.body()->setInnerHTML("<div id='test2'></div>"); | |
64 EXPECT_EQ(DocumentLifecycle::VisualUpdatePending, | |
65 document.lifecycle().state()); | |
66 | |
67 document.body()->scrollIntoViewIfNeeded(); | |
68 EXPECT_EQ(DocumentLifecycle::CompositingClean, document.lifecycle().state()); | |
69 } | |
70 | |
71 // Verifies that calling offsetTop/offsetLeft cleans compositor inputs. | |
72 // Cleaning the compositor inputs is required so that position:sticky elements | |
73 // and their descendants have the correct location. | |
74 TEST(ElementTest, OffsetTopAndLeftUpdateCompositorInputs) { | |
75 std::unique_ptr<DummyPageHolder> pageHolder = DummyPageHolder::create(); | |
76 Document& document = pageHolder->document(); | |
77 | |
78 document.view()->updateAllLifecyclePhases(); | |
79 EXPECT_EQ(DocumentLifecycle::PaintClean, document.lifecycle().state()); | |
80 | |
81 document.body()->setInnerHTML("<div id='test'></div>"); | |
82 EXPECT_EQ(DocumentLifecycle::VisualUpdatePending, | |
83 document.lifecycle().state()); | |
84 | |
85 document.body()->offsetTop(); | |
86 EXPECT_EQ(DocumentLifecycle::CompositingClean, document.lifecycle().state()); | |
87 | |
88 document.body()->setInnerHTML("<div id='test2'></div>"); | |
89 EXPECT_EQ(DocumentLifecycle::VisualUpdatePending, | |
90 document.lifecycle().state()); | |
91 | |
92 document.body()->offsetLeft(); | |
93 EXPECT_EQ(DocumentLifecycle::CompositingClean, document.lifecycle().state()); | |
94 } | |
95 | |
96 TEST(ElementTest, OffsetTopAndLeftCorrectForStickyElementsAfterInsertion) { | |
97 std::unique_ptr<DummyPageHolder> pageHolder = DummyPageHolder::create(); | |
98 Document& document = pageHolder->document(); | |
99 | |
100 document.body()->setInnerHTML( | |
101 "<style>body { margin: 0 }" | |
102 "#scroller { overflow: scroll; height: 100px; width: 100px; }" | |
103 "#sticky { height: 25px; position: sticky; top: 0; left: 25px }" | |
flackr
2017/01/24 22:47:16
nit: semicolon after 25px
smcgruer
2017/01/25 20:51:57
Done.
| |
104 "#padding { height: 500px; width: 300px; }</style>" | |
105 "<div id='scroller'><div id='writer'></div><div id='sticky'></div>" | |
106 "<div id='padding'></div></div>"); | |
107 document.view()->updateAllLifecyclePhases(); | |
108 | |
109 Element* scroller = document.getElementById("scroller"); | |
110 Element* writer = document.getElementById("writer"); | |
111 Element* sticky = document.getElementById("sticky"); | |
112 | |
113 ASSERT_TRUE(scroller); | |
114 ASSERT_TRUE(writer); | |
115 ASSERT_TRUE(sticky); | |
116 | |
117 scroller->scrollTo(0, 200.0); | |
118 | |
119 // After scrolling, the position:sticky element should be offset to stay at | |
120 // the top of the viewport. | |
121 EXPECT_EQ(scroller->scrollTop(), sticky->offsetTop()); | |
122 | |
123 // Insert a new <div> above the sticky. This will dirty layout. | |
124 writer->setInnerHTML("<div style='height: 100px;'></div>"); | |
125 EXPECT_EQ(DocumentLifecycle::VisualUpdatePending, | |
126 document.lifecycle().state()); | |
127 | |
128 // Querying the new position of the sticky should now cause both layout and | |
129 // compositing inputs to be clean and should return the correct position. | |
130 // Additionally, repeated calls to offsetTop should give the same value. | |
131 int offsetTop = sticky->offsetTop(); | |
132 EXPECT_EQ(DocumentLifecycle::CompositingClean, document.lifecycle().state()); | |
133 EXPECT_FALSE( | |
134 sticky->layoutBoxModelObject()->layer()->needsCompositingInputsUpdate()); | |
135 EXPECT_EQ(scroller->scrollTop(), sticky->offsetTop()); | |
136 EXPECT_EQ(offsetTop, sticky->offsetTop()); | |
flackr
2017/01/24 22:47:16
Hm, I'm not sure what case I was worried about wit
smcgruer
2017/01/25 20:51:57
Ok, removed.
| |
137 | |
138 scroller->scrollTo(50.0, 0); | |
139 | |
140 // After scrolling, the position:sticky element should be offset to stay 25 | |
141 // pixels from the left of the viewport. | |
142 EXPECT_EQ(scroller->scrollLeft() + 25, sticky->offsetLeft()); | |
143 | |
144 // Insert a new <div> above the sticky. This will dirty layout. | |
145 writer->setInnerHTML("<div style='width: 700px;'></div>"); | |
146 EXPECT_EQ(DocumentLifecycle::VisualUpdatePending, | |
147 document.lifecycle().state()); | |
148 | |
149 // Again, querying the position should cause layout and compositing clean, and | |
150 // should return the correct position repeatedly. | |
151 int offsetLeft = sticky->offsetLeft(); | |
152 EXPECT_EQ(DocumentLifecycle::CompositingClean, document.lifecycle().state()); | |
153 EXPECT_FALSE( | |
154 sticky->layoutBoxModelObject()->layer()->needsCompositingInputsUpdate()); | |
155 EXPECT_EQ(scroller->scrollLeft() + 25, sticky->offsetLeft()); | |
156 EXPECT_EQ(offsetLeft, sticky->offsetLeft()); | |
157 } | |
158 | |
26 } // namespace blink | 159 } // namespace blink |
OLD | NEW |