Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(111)

Side by Side Diff: third_party/WebKit/Source/core/dom/ElementTest.cpp

Issue 2825343003: Clean compositing inputs for location APIs for sticky-affected elements. (Closed)
Patch Set: Rename EnsureLifecycleValidForLocationAPIsForNode Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 <memory>
8 #include "core/dom/ClientRect.h"
7 #include "core/dom/Document.h" 9 #include "core/dom/Document.h"
10 #include "core/editing/EditingTestBase.h"
8 #include "core/frame/FrameView.h" 11 #include "core/frame/FrameView.h"
9 #include "core/html/HTMLHtmlElement.h" 12 #include "core/html/HTMLHtmlElement.h"
13 #include "core/layout/LayoutBoxModelObject.h"
14 #include "core/paint/PaintLayer.h"
10 #include "core/testing/DummyPageHolder.h" 15 #include "core/testing/DummyPageHolder.h"
11 #include "testing/gtest/include/gtest/gtest.h" 16 #include "testing/gtest/include/gtest/gtest.h"
12 #include <memory>
13 17
14 namespace blink { 18 namespace blink {
15 19
16 TEST(ElementTest, SupportsFocus) { 20 class ElementTest : public EditingTestBase {};
17 std::unique_ptr<DummyPageHolder> page_holder = DummyPageHolder::Create(); 21
18 Document& document = page_holder->GetDocument(); 22 TEST_F(ElementTest, SupportsFocus) {
23 Document& document = GetDocument();
19 DCHECK(isHTMLHtmlElement(document.documentElement())); 24 DCHECK(isHTMLHtmlElement(document.documentElement()));
20 document.setDesignMode("on"); 25 document.setDesignMode("on");
21 document.View()->UpdateAllLifecyclePhases(); 26 document.View()->UpdateAllLifecyclePhases();
22 EXPECT_TRUE(document.documentElement()->SupportsFocus()) 27 EXPECT_TRUE(document.documentElement()->SupportsFocus())
23 << "<html> with designMode=on should be focusable."; 28 << "<html> with designMode=on should be focusable.";
24 } 29 }
25 30
31 TEST_F(ElementTest,
32 GetBoundingClientRectCorrectForStickyElementsAfterInsertion) {
33 Document& document = GetDocument();
34 SetBodyContent(
35 "<style>body { margin: 0 }"
36 "#scroller { overflow: scroll; height: 100px; width: 100px; }"
37 "#sticky { height: 25px; position: sticky; top: 0; left: 25px; }"
38 "#padding { height: 500px; width: 300px; }</style>"
39 "<div id='scroller'><div id='writer'></div><div id='sticky'></div>"
40 "<div id='padding'></div></div>");
41
42 Element* scroller = document.getElementById("scroller");
43 Element* writer = document.getElementById("writer");
44 Element* sticky = document.getElementById("sticky");
45
46 ASSERT_TRUE(scroller);
47 ASSERT_TRUE(writer);
48 ASSERT_TRUE(sticky);
49
50 scroller->scrollTo(50.0, 200.0);
51
52 // The sticky element should remain at (0, 25) relative to the viewport due to
53 // the constraints.
54 ClientRect* bounding_client_rect = sticky->getBoundingClientRect();
55 EXPECT_EQ(0, bounding_client_rect->top());
56 EXPECT_EQ(25, bounding_client_rect->left());
57
58 // Insert a new <div> above the sticky. This will dirty layout and invalidate
59 // the sticky constraints.
60 writer->setInnerHTML("<div style='height: 100px; width: 700px;'></div>");
61 EXPECT_EQ(DocumentLifecycle::kVisualUpdatePending,
62 document.Lifecycle().GetState());
63
64 // Requesting the bounding client rect should cause both layout and
65 // compositing inputs clean to be run, and the sticky result shouldn't change.
66 bounding_client_rect = sticky->getBoundingClientRect();
67 EXPECT_EQ(DocumentLifecycle::kCompositingInputsClean,
68 document.Lifecycle().GetState());
69 EXPECT_FALSE(sticky->GetLayoutBoxModelObject()
70 ->Layer()
71 ->NeedsCompositingInputsUpdate());
72 EXPECT_EQ(0, bounding_client_rect->top());
73 EXPECT_EQ(25, bounding_client_rect->left());
74 }
75
76 TEST_F(ElementTest, OffsetTopAndLeftCorrectForStickyElementsAfterInsertion) {
77 Document& document = GetDocument();
78 SetBodyContent(
79 "<style>body { margin: 0 }"
80 "#scroller { overflow: scroll; height: 100px; width: 100px; }"
81 "#sticky { height: 25px; position: sticky; top: 0; left: 25px; }"
82 "#padding { height: 500px; width: 300px; }</style>"
83 "<div id='scroller'><div id='writer'></div><div id='sticky'></div>"
84 "<div id='padding'></div></div>");
85
86 Element* scroller = document.getElementById("scroller");
87 Element* writer = document.getElementById("writer");
88 Element* sticky = document.getElementById("sticky");
89
90 ASSERT_TRUE(scroller);
91 ASSERT_TRUE(writer);
92 ASSERT_TRUE(sticky);
93
94 scroller->scrollTo(50.0, 200.0);
95
96 // The sticky element should be offset to stay at (0, 25) relative to the
97 // viewport due to the constraints.
98 EXPECT_EQ(scroller->scrollTop(), sticky->OffsetTop());
99 EXPECT_EQ(scroller->scrollLeft() + 25, sticky->OffsetLeft());
100
101 // Insert a new <div> above the sticky. This will dirty layout and invalidate
102 // the sticky constraints.
103 writer->setInnerHTML("<div style='height: 100px; width: 700px;'></div>");
104 EXPECT_EQ(DocumentLifecycle::kVisualUpdatePending,
105 document.Lifecycle().GetState());
106
107 // Requesting either offset should cause both layout and compositing inputs
108 // clean to be run, and the sticky result shouldn't change.
109 EXPECT_EQ(scroller->scrollTop(), sticky->OffsetTop());
110 EXPECT_EQ(DocumentLifecycle::kCompositingInputsClean,
111 document.Lifecycle().GetState());
112 EXPECT_FALSE(sticky->GetLayoutBoxModelObject()
113 ->Layer()
114 ->NeedsCompositingInputsUpdate());
115
116 // Dirty layout again, since |OffsetTop| will have cleaned it.
117 writer->setInnerHTML("<div style='height: 100px; width: 700px;'></div>");
118 EXPECT_EQ(DocumentLifecycle::kVisualUpdatePending,
119 document.Lifecycle().GetState());
120
121 // Again requesting an offset should cause layout and compositing to be clean.
122 EXPECT_EQ(scroller->scrollLeft() + 25, sticky->OffsetLeft());
123 EXPECT_EQ(DocumentLifecycle::kCompositingInputsClean,
124 document.Lifecycle().GetState());
125 EXPECT_FALSE(sticky->GetLayoutBoxModelObject()
126 ->Layer()
127 ->NeedsCompositingInputsUpdate());
128 }
129
130 TEST_F(ElementTest, BoundsInViewportCorrectForStickyElementsAfterInsertion) {
131 Document& document = GetDocument();
132 SetBodyContent(
133 "<style>body { margin: 0 }"
134 "#scroller { overflow: scroll; height: 100px; width: 100px; }"
135 "#sticky { height: 25px; position: sticky; top: 0; left: 25px; }"
136 "#padding { height: 500px; width: 300px; }</style>"
137 "<div id='scroller'><div id='writer'></div><div id='sticky'></div>"
138 "<div id='padding'></div></div>");
139
140 Element* scroller = document.getElementById("scroller");
141 Element* writer = document.getElementById("writer");
142 Element* sticky = document.getElementById("sticky");
143
144 ASSERT_TRUE(scroller);
145 ASSERT_TRUE(writer);
146 ASSERT_TRUE(sticky);
147
148 scroller->scrollTo(50.0, 200.0);
149
150 // The sticky element should remain at (0, 25) relative to the viewport due to
151 // the constraints.
152 IntRect bounds_in_viewport = sticky->BoundsInViewport();
153 EXPECT_EQ(0, bounds_in_viewport.Y());
154 EXPECT_EQ(25, bounds_in_viewport.X());
155
156 // Insert a new <div> above the sticky. This will dirty layout and invalidate
157 // the sticky constraints.
158 writer->setInnerHTML("<div style='height: 100px; width: 700px;'></div>");
159 EXPECT_EQ(DocumentLifecycle::kVisualUpdatePending,
160 document.Lifecycle().GetState());
161
162 // Requesting the bounds in viewport should cause both layout and compositing
163 // inputs clean to be run, and the sticky result shouldn't change.
164 bounds_in_viewport = sticky->BoundsInViewport();
165 EXPECT_EQ(DocumentLifecycle::kCompositingInputsClean,
166 document.Lifecycle().GetState());
167 EXPECT_FALSE(sticky->GetLayoutBoxModelObject()
168 ->Layer()
169 ->NeedsCompositingInputsUpdate());
170 EXPECT_EQ(0, bounds_in_viewport.Y());
171 EXPECT_EQ(25, bounds_in_viewport.X());
172 }
173
174 TEST_F(ElementTest, StickySubtreesAreTrackedCorrectly) {
175 Document& document = GetDocument();
176 SetBodyContent(
177 "<div id='ancestor'>"
178 " <div id='sticky' style='position:sticky;'>"
179 " <div id='stickyChild'>"
180 " <div id='stickyGrandchild'></div>"
181 " </div"
182 " </div>"
183 "</div>");
184
185 LayoutObject* ancestor =
186 document.getElementById("ancestor")->GetLayoutObject();
187 LayoutObject* sticky = document.getElementById("sticky")->GetLayoutObject();
188 LayoutObject* sticky_child =
189 document.getElementById("stickyChild")->GetLayoutObject();
190 LayoutObject* sticky_grandchild =
191 document.getElementById("stickyGrandchild")->GetLayoutObject();
192
193 EXPECT_FALSE(ancestor->StyleRef().IsInStickySubtree());
194 EXPECT_TRUE(sticky->StyleRef().IsInStickySubtree());
195 EXPECT_TRUE(sticky_child->StyleRef().IsInStickySubtree());
196 EXPECT_TRUE(sticky_grandchild->StyleRef().IsInStickySubtree());
197
198 // This forces stickyChild to fork it's StyleRareInheritedData, so that we can
199 // ensure that the sticky subtree update behavior survives forking.
200 document.getElementById("stickyChild")
201 ->SetInlineStyleProperty(CSSPropertyWebkitRubyPosition, CSSValueAfter);
202 document.View()->UpdateAllLifecyclePhases();
203 EXPECT_EQ(DocumentLifecycle::kPaintClean, document.Lifecycle().GetState());
204
205 EXPECT_EQ(kRubyPositionBefore, sticky->StyleRef().GetRubyPosition());
206 EXPECT_EQ(kRubyPositionAfter, sticky_child->StyleRef().GetRubyPosition());
207 EXPECT_EQ(kRubyPositionAfter,
208 sticky_grandchild->StyleRef().GetRubyPosition());
209
210 // Setting a -webkit-ruby value should not have affected the sticky subtree
211 // status.
212 EXPECT_TRUE(sticky->StyleRef().IsInStickySubtree());
213 EXPECT_TRUE(sticky_child->StyleRef().IsInStickySubtree());
214 EXPECT_TRUE(sticky_grandchild->StyleRef().IsInStickySubtree());
215
216 // Now switch the parent back to being non-sticky - all descendants should be
flackr 2017/05/04 14:40:59 What if there is an intermediate sticky element? i
smcgruer 2017/05/04 15:25:32 Done.
217 // updated.
218 document.getElementById("sticky")->SetInlineStyleProperty(CSSPropertyPosition,
219 CSSValueStatic);
220 document.View()->UpdateAllLifecyclePhases();
221 EXPECT_EQ(DocumentLifecycle::kPaintClean, document.Lifecycle().GetState());
222
223 EXPECT_FALSE(sticky->StyleRef().IsInStickySubtree());
224 EXPECT_FALSE(sticky_child->StyleRef().IsInStickySubtree());
225 EXPECT_FALSE(sticky_grandchild->StyleRef().IsInStickySubtree());
226 }
227
26 } // namespace blink 228 } // namespace blink
OLDNEW
« no previous file with comments | « third_party/WebKit/Source/core/dom/Element.cpp ('k') | third_party/WebKit/Source/core/html/HTMLElement.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698