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" | |
12 #include "core/testing/DummyPageHolder.h" | 10 #include "core/testing/DummyPageHolder.h" |
13 #include "testing/gtest/include/gtest/gtest.h" | 11 #include "testing/gtest/include/gtest/gtest.h" |
14 #include <memory> | 12 #include <memory> |
15 | 13 |
16 namespace blink { | 14 namespace blink { |
17 | 15 |
18 TEST(ElementTest, SupportsFocus) { | 16 TEST(ElementTest, SupportsFocus) { |
19 std::unique_ptr<DummyPageHolder> pageHolder = DummyPageHolder::create(); | 17 std::unique_ptr<DummyPageHolder> pageHolder = DummyPageHolder::create(); |
20 Document& document = pageHolder->document(); | 18 Document& document = pageHolder->document(); |
21 DCHECK(isHTMLHtmlElement(document.documentElement())); | 19 DCHECK(isHTMLHtmlElement(document.documentElement())); |
22 document.setDesignMode("on"); | 20 document.setDesignMode("on"); |
23 document.view()->updateAllLifecyclePhases(); | 21 document.view()->updateAllLifecyclePhases(); |
24 EXPECT_TRUE(document.documentElement()->supportsFocus()) | 22 EXPECT_TRUE(document.documentElement()->supportsFocus()) |
25 << "<html> with designMode=on should be focusable."; | 23 << "<html> with designMode=on should be focusable."; |
26 } | 24 } |
27 | 25 |
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; }" | |
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 offset of the sticky element should now cause both layout | |
129 // and compositing inputs to be clean and should return the correct offset. | |
130 int offsetTop = sticky->offsetTop(); | |
131 EXPECT_EQ(DocumentLifecycle::CompositingClean, document.lifecycle().state()); | |
132 EXPECT_FALSE( | |
133 sticky->layoutBoxModelObject()->layer()->needsCompositingInputsUpdate()); | |
134 EXPECT_EQ(scroller->scrollTop(), offsetTop); | |
135 | |
136 scroller->scrollTo(50.0, 0); | |
137 | |
138 // After scrolling, the position:sticky element should be offset to stay 25 | |
139 // pixels from the left of the viewport. | |
140 EXPECT_EQ(scroller->scrollLeft() + 25, sticky->offsetLeft()); | |
141 | |
142 // Insert a new <div> above the sticky. This will dirty layout. | |
143 writer->setInnerHTML("<div style='width: 700px;'></div>"); | |
144 EXPECT_EQ(DocumentLifecycle::VisualUpdatePending, | |
145 document.lifecycle().state()); | |
146 | |
147 // Again getting the offset should cause layout and compositing to be clean. | |
148 int offsetLeft = sticky->offsetLeft(); | |
149 EXPECT_EQ(DocumentLifecycle::CompositingClean, document.lifecycle().state()); | |
150 EXPECT_FALSE( | |
151 sticky->layoutBoxModelObject()->layer()->needsCompositingInputsUpdate()); | |
152 EXPECT_EQ(scroller->scrollLeft() + 25, offsetLeft); | |
153 } | |
154 | |
155 } // namespace blink | 26 } // namespace blink |
OLD | NEW |