1 // Copyright 2014 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.
6 #include "core/paint/ViewDisplayList.h"
8 #include "core/paint/ClipRecorder.h"
9 #include "core/paint/DrawingRecorder.h"
10 #include "core/rendering/RenderView.h"
11 #include "core/rendering/RenderingTestHelper.h"
12 #include "core/rendering/compositing/RenderLayerCompositor.h"
13 #include "platform/graphics/GraphicsContext.h"
14 #include <gtest/gtest.h>
19 class ViewDisplayListTest : public RenderingTest {
21 ViewDisplayListTest() : m_renderView(nullptr) { }
24 RenderView* renderView() { return m_renderView; }
27 virtual void SetUp() override
29 RuntimeEnabledFeatures::setSlimmingPaintEnabled(true);
31 RenderingTest::SetUp();
33 m_renderView = document().view()->renderView();
34 ASSERT_TRUE(m_renderView);
37 RenderView* m_renderView;
40 void drawRect(GraphicsContext* context, RenderObject* renderer, PaintPhase phase, const FloatRect& bound)
42 DrawingRecorder drawingRecorder(context, renderer, phase, bound);
43 IntRect rect(0, 0, 10, 10);
44 context->drawRect(rect);
47 void drawClippedRect(GraphicsContext* context, RenderView* renderView, PaintPhase phase, const FloatRect& bound)
49 IntRect rect(1, 1, 9, 9);
50 ClipRect clipRect(rect);
51 ClipRecorder clipRecorder(renderView->compositor()->rootRenderLayer(), context, DisplayItem::ClipLayerForeground, clipRect);
52 drawRect(context, renderView, phase, bound);
55 TEST_F(ViewDisplayListTest, ViewDisplayListTest_NestedRecorders)
57 GraphicsContext* context = new GraphicsContext(nullptr);
58 FloatRect bound = renderView()->viewRect();
60 drawClippedRect(context, renderView(), PaintPhaseForeground, bound);
61 EXPECT_EQ((size_t)3, renderView()->viewDisplayList().paintList().size());
63 // TODO(schenney): Check that the IDs are what we expect.
66 TEST_F(ViewDisplayListTest, ViewDisplayListTest_UpdateBasic)
68 setBodyInnerHTML("<div id='first'><div id='second'></div></div>");
69 RenderObject* first = document().body()->firstChild()->renderer();
70 RenderObject* second = document().body()->firstChild()->firstChild()->renderer();
71 GraphicsContext* context = new GraphicsContext(nullptr);
73 drawRect(context, first, PaintPhaseBlockBackground, FloatRect(100, 100, 300, 300));
74 drawRect(context, second, PaintPhaseChildBlockBackground, FloatRect(100, 100, 200, 200));
75 drawRect(context, first, PaintPhaseOutline, FloatRect(100, 100, 300, 300));
77 EXPECT_EQ((size_t)3, renderView()->viewDisplayList().paintList().size());
79 renderView()->viewDisplayList().invalidate(second);
80 drawRect(context, first, PaintPhaseBlockBackground, FloatRect(100, 100, 300, 300));
81 drawRect(context, first, PaintPhaseOutline, FloatRect(100, 100, 300, 300));
82 EXPECT_EQ((size_t)2, renderView()->viewDisplayList().paintList().size());
85 TEST_F(ViewDisplayListTest, ViewDisplayListTest_UpdateSwapOrder)
87 setBodyInnerHTML("<div id='first'><div id='second'></div></div><div id='unaffected'></div>");
88 RenderObject* first = document().body()->firstChild()->renderer();
89 RenderObject* second = document().body()->firstChild()->firstChild()->renderer();
90 RenderObject* unaffected = document().body()->firstChild()->nextSibling()->renderer();
91 GraphicsContext* context = new GraphicsContext(nullptr);
93 drawRect(context, first, PaintPhaseBlockBackground, FloatRect(100, 100, 100, 100));
94 drawRect(context, second, PaintPhaseBlockBackground, FloatRect(100, 100, 50, 200));
95 drawRect(context, unaffected, PaintPhaseBlockBackground, FloatRect(300, 300, 10, 10));
97 const PaintList& firstList = renderView()->viewDisplayList().paintList();
98 EXPECT_EQ((size_t)3, firstList.size());
99 EXPECT_EQ(first, firstList[0]->renderer());
100 EXPECT_EQ(second, firstList[1]->renderer());
101 EXPECT_EQ(unaffected, firstList[2]->renderer());
103 renderView()->viewDisplayList().invalidate(second);
104 drawRect(context, second, PaintPhaseBlockBackground, FloatRect(100, 100, 50, 200));
105 drawRect(context, first, PaintPhaseBlockBackground, FloatRect(100, 100, 100, 100));
107 const PaintList& secondList = renderView()->viewDisplayList().paintList();
108 EXPECT_EQ((size_t)3, secondList.size());
109 EXPECT_EQ(second, secondList[0]->renderer());
110 EXPECT_EQ(first, secondList[1]->renderer());
111 EXPECT_EQ(unaffected, secondList[2]->renderer());
114 TEST_F(ViewDisplayListTest, ViewDisplayListTest_UpdateNewItemInMiddle)
116 setBodyInnerHTML("<div id='first'><div id='second'><div id='third'></div></div></div>");
117 RenderObject* first = document().body()->firstChild()->renderer();
118 RenderObject* second = document().body()->firstChild()->firstChild()->renderer();
119 RenderObject* third = document().body()->firstChild()->firstChild()->firstChild()->renderer();
120 GraphicsContext* context = new GraphicsContext(nullptr);
122 drawRect(context, first, PaintPhaseBlockBackground, FloatRect(100, 100, 100, 100));
123 drawRect(context, second, PaintPhaseBlockBackground, FloatRect(100, 100, 50, 200));
125 const PaintList& firstList = renderView()->viewDisplayList().paintList();
126 EXPECT_EQ((size_t)2, firstList.size());
127 EXPECT_EQ(first, firstList[0]->renderer());
128 EXPECT_EQ(second, firstList[1]->renderer());
130 renderView()->viewDisplayList().invalidate(third);
131 drawRect(context, first, PaintPhaseBlockBackground, FloatRect(100, 100, 100, 100));
132 drawRect(context, third, PaintPhaseBlockBackground, FloatRect(125, 100, 200, 50));
133 drawRect(context, second, PaintPhaseBlockBackground, FloatRect(100, 100, 50, 200));
135 const PaintList& secondList = renderView()->viewDisplayList().paintList();
136 EXPECT_EQ((size_t)3, secondList.size());
137 EXPECT_EQ(first, secondList[0]->renderer());
138 EXPECT_EQ(third, secondList[1]->renderer());
139 EXPECT_EQ(second, secondList[2]->renderer());
142 TEST_F(ViewDisplayListTest, ViewDisplayListTest_UpdateInvalidationWithPhases)
144 setBodyInnerHTML("<div id='first'><div id='second'></div></div><div id='third'></div>");
145 RenderObject* first = document().body()->firstChild()->renderer();
146 RenderObject* second = document().body()->firstChild()->firstChild()->renderer();
147 RenderObject* third = document().body()->firstChild()->nextSibling()->renderer();
148 GraphicsContext* context = new GraphicsContext(nullptr);
150 drawRect(context, first, PaintPhaseBlockBackground, FloatRect(100, 100, 100, 100));
151 drawRect(context, second, PaintPhaseBlockBackground, FloatRect(100, 100, 50, 200));
152 drawRect(context, third, PaintPhaseBlockBackground, FloatRect(300, 100, 50, 50));
153 drawRect(context, first, PaintPhaseForeground, FloatRect(100, 100, 100, 100));
154 drawRect(context, second, PaintPhaseForeground, FloatRect(100, 100, 50, 200));
155 drawRect(context, third, PaintPhaseForeground, FloatRect(300, 100, 50, 50));
156 drawRect(context, first, PaintPhaseOutline, FloatRect(100, 100, 100, 100));
157 drawRect(context, second, PaintPhaseOutline, FloatRect(100, 100, 50, 200));
158 drawRect(context, third, PaintPhaseOutline, FloatRect(300, 100, 50, 50));
160 const PaintList& firstList = renderView()->viewDisplayList().paintList();
161 EXPECT_EQ((size_t)9, firstList.size());
162 for (int item = 0; item < 9; item += 3) {
163 EXPECT_EQ(first, firstList[item % 3 + 0]->renderer());
164 EXPECT_EQ(second, firstList[item % 3 + 1]->renderer());
165 EXPECT_EQ(third, firstList[item % 3 + 2]->renderer());
168 renderView()->viewDisplayList().invalidate(second);
169 drawRect(context, first, PaintPhaseBlockBackground, FloatRect(100, 100, 100, 100));
170 drawRect(context, second, PaintPhaseBlockBackground, FloatRect(100, 100, 50, 200));
171 drawRect(context, first, PaintPhaseForeground, FloatRect(100, 100, 100, 100));
172 drawRect(context, second, PaintPhaseForeground, FloatRect(100, 100, 50, 200));
173 drawRect(context, first, PaintPhaseOutline, FloatRect(100, 100, 100, 100));
174 drawRect(context, second, PaintPhaseOutline, FloatRect(100, 100, 50, 200));
176 const PaintList& secondList = renderView()->viewDisplayList().paintList();
177 EXPECT_EQ((size_t)9, secondList.size());
178 for (int item = 0; item < 9; item += 3) {
179 EXPECT_EQ(first, secondList[item % 3 + 0]->renderer());
180 EXPECT_EQ(second, secondList[item % 3 + 1]->renderer());
181 EXPECT_EQ(third, secondList[item % 3 + 2]->renderer());
184 renderView()->viewDisplayList().invalidate(second);
185 const PaintList& thirdList = renderView()->viewDisplayList().paintList();
186 EXPECT_EQ((size_t)6, thirdList.size());
187 for (int item = 0; item < 6; item += 2) {
188 EXPECT_EQ(first, thirdList[item % 2 + 0]->renderer());
189 EXPECT_EQ(third, thirdList[item % 2 + 1]->renderer());
193 TEST_F(ViewDisplayListTest, ViewDisplayListTest_UpdateAddFirstNoOverlap)
195 setBodyInnerHTML("<div id='first'></div><div id='second'></div>");
196 RenderObject* first = document().body()->firstChild()->renderer();
197 RenderObject* second = document().body()->firstChild()->nextSibling()->renderer();
198 GraphicsContext* context = new GraphicsContext(nullptr);
200 drawRect(context, second, PaintPhaseBlockBackground, FloatRect(200, 200, 50, 50));
201 drawRect(context, second, PaintPhaseOutline, FloatRect(200, 200, 50, 50));
203 const PaintList& firstList = renderView()->viewDisplayList().paintList();
204 EXPECT_EQ((size_t)2, firstList.size());
205 EXPECT_EQ(second, firstList[0]->renderer());
206 EXPECT_EQ(second, firstList[1]->renderer());
208 renderView()->viewDisplayList().invalidate(first);
209 drawRect(context, first, PaintPhaseBlockBackground, FloatRect(100, 100, 50, 50));
210 drawRect(context, first, PaintPhaseOutline, FloatRect(100, 100, 50, 50));
212 const PaintList& secondList = renderView()->viewDisplayList().paintList();
213 EXPECT_EQ((size_t)4, secondList.size());
214 EXPECT_EQ(first, secondList[0]->renderer());
215 EXPECT_EQ(first, secondList[1]->renderer());
216 EXPECT_EQ(second, secondList[2]->renderer());
217 EXPECT_EQ(second, secondList[3]->renderer());
219 renderView()->viewDisplayList().invalidate(first);
220 const PaintList& thirdList = renderView()->viewDisplayList().paintList();
221 EXPECT_EQ((size_t)2, thirdList.size());
222 EXPECT_EQ(second, thirdList[0]->renderer());
223 EXPECT_EQ(second, thirdList[1]->renderer());
226 TEST_F(ViewDisplayListTest, ViewDisplayListTest_UpdateAddFirstOverlap)
228 setBodyInnerHTML("<div id='first'></div><div id='second'></div>");
229 RenderObject* first = document().body()->firstChild()->renderer();
230 RenderObject* second = document().body()->firstChild()->nextSibling()->renderer();
231 GraphicsContext* context = new GraphicsContext(nullptr);
233 drawRect(context, second, PaintPhaseBlockBackground, FloatRect(200, 200, 50, 50));
234 drawRect(context, second, PaintPhaseOutline, FloatRect(200, 200, 50, 50));
236 const PaintList& firstList = renderView()->viewDisplayList().paintList();
237 EXPECT_EQ((size_t)2, firstList.size());
238 EXPECT_EQ(second, firstList[0]->renderer());
239 EXPECT_EQ(second, firstList[1]->renderer());
241 renderView()->viewDisplayList().invalidate(first);
242 renderView()->viewDisplayList().invalidate(second);
243 drawRect(context, first, PaintPhaseBlockBackground, FloatRect(100, 100, 150, 150));
244 drawRect(context, first, PaintPhaseOutline, FloatRect(100, 100, 150, 150));
245 drawRect(context, second, PaintPhaseBlockBackground, FloatRect(200, 200, 50, 50));
246 drawRect(context, second, PaintPhaseOutline, FloatRect(200, 200, 50, 50));
248 const PaintList& secondList = renderView()->viewDisplayList().paintList();
249 EXPECT_EQ((size_t)4, secondList.size());
250 EXPECT_EQ(first, secondList[0]->renderer());
251 EXPECT_EQ(first, secondList[1]->renderer());
252 EXPECT_EQ(second, secondList[2]->renderer());
253 EXPECT_EQ(second, secondList[3]->renderer());
255 renderView()->viewDisplayList().invalidate(first);
256 drawRect(context, second, PaintPhaseBlockBackground, FloatRect(200, 200, 50, 50));
257 drawRect(context, second, PaintPhaseOutline, FloatRect(200, 200, 50, 50));
259 const PaintList& thirdList = renderView()->viewDisplayList().paintList();
260 EXPECT_EQ((size_t)2, thirdList.size());
261 EXPECT_EQ(second, thirdList[0]->renderer());
262 EXPECT_EQ(second, thirdList[1]->renderer());
265 TEST_F(ViewDisplayListTest, ViewDisplayListTest_UpdateAddLastNoOverlap)
267 setBodyInnerHTML("<div id='first'></div><div id='second'></div>");
268 RenderObject* first = document().body()->firstChild()->renderer();
269 RenderObject* second = document().body()->firstChild()->nextSibling()->renderer();
270 GraphicsContext* context = new GraphicsContext(nullptr);
272 drawRect(context, first, PaintPhaseBlockBackground, FloatRect(100, 100, 50, 50));
273 drawRect(context, first, PaintPhaseOutline, FloatRect(100, 100, 50, 50));
275 const PaintList& firstList = renderView()->viewDisplayList().paintList();
276 EXPECT_EQ((size_t)2, firstList.size());
277 EXPECT_EQ(first, firstList[0]->renderer());
278 EXPECT_EQ(first, firstList[1]->renderer());
280 renderView()->viewDisplayList().invalidate(second);
281 drawRect(context, second, PaintPhaseBlockBackground, FloatRect(200, 200, 50, 50));
282 drawRect(context, second, PaintPhaseOutline, FloatRect(200, 200, 50, 50));
284 const PaintList& secondList = renderView()->viewDisplayList().paintList();
285 EXPECT_EQ((size_t)4, secondList.size());
286 EXPECT_EQ(second, secondList[0]->renderer());
287 EXPECT_EQ(second, secondList[1]->renderer());
288 EXPECT_EQ(first, secondList[2]->renderer());
289 EXPECT_EQ(first, secondList[3]->renderer());
291 renderView()->viewDisplayList().invalidate(second);
292 const PaintList& thirdList = renderView()->viewDisplayList().paintList();
293 EXPECT_EQ((size_t)2, thirdList.size());
294 EXPECT_EQ(first, thirdList[0]->renderer());
295 EXPECT_EQ(first, thirdList[1]->renderer());
298 TEST_F(ViewDisplayListTest, ViewDisplayListTest_UpdateAddLastOverlap)
300 setBodyInnerHTML("<div id='first'></div><div id='second'></div>");
301 RenderObject* first = document().body()->firstChild()->renderer();
302 RenderObject* second = document().body()->firstChild()->nextSibling()->renderer();
303 GraphicsContext* context = new GraphicsContext(nullptr);
305 drawRect(context, first, PaintPhaseBlockBackground, FloatRect(100, 100, 150, 150));
306 drawRect(context, first, PaintPhaseOutline, FloatRect(100, 100, 150, 150));
308 const PaintList& firstList = renderView()->viewDisplayList().paintList();
309 EXPECT_EQ((size_t)2, firstList.size());
310 EXPECT_EQ(first, firstList[0]->renderer());
311 EXPECT_EQ(first, firstList[1]->renderer());
313 renderView()->viewDisplayList().invalidate(first);
314 renderView()->viewDisplayList().invalidate(second);
315 drawRect(context, first, PaintPhaseBlockBackground, FloatRect(100, 100, 150, 150));
316 drawRect(context, first, PaintPhaseOutline, FloatRect(100, 100, 150, 150));
317 drawRect(context, second, PaintPhaseBlockBackground, FloatRect(200, 200, 50, 50));
318 drawRect(context, second, PaintPhaseOutline, FloatRect(200, 200, 50, 50));
320 const PaintList& secondList = renderView()->viewDisplayList().paintList();
321 EXPECT_EQ((size_t)4, secondList.size());
322 EXPECT_EQ(first, secondList[0]->renderer());
323 EXPECT_EQ(first, secondList[1]->renderer());
324 EXPECT_EQ(second, secondList[2]->renderer());
325 EXPECT_EQ(second, secondList[3]->renderer());
327 renderView()->viewDisplayList().invalidate(first);
328 renderView()->viewDisplayList().invalidate(second);
329 drawRect(context, first, PaintPhaseBlockBackground, FloatRect(100, 100, 150, 150));
330 drawRect(context, first, PaintPhaseOutline, FloatRect(100, 100, 150, 150));
332 const PaintList& thirdList = renderView()->viewDisplayList().paintList();
333 EXPECT_EQ((size_t)2, thirdList.size());
334 EXPECT_EQ(first, thirdList[0]->renderer());
335 EXPECT_EQ(first, thirdList[1]->renderer());