1 // Copyright 2012 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.
4 
5 #include "cc/trees/layer_tree_host.h"
6 
7 #include "base/bind.h"
8 #include "base/callback.h"
9 #include "base/location.h"
10 #include "base/time/time.h"
11 #include "cc/layers/solid_color_layer.h"
12 #include "cc/test/fake_content_layer_client.h"
13 #include "cc/test/fake_painted_scrollbar_layer.h"
14 #include "cc/test/fake_picture_layer.h"
15 #include "cc/test/layer_test_common.h"
16 #include "cc/test/layer_tree_test.h"
17 #include "cc/trees/damage_tracker.h"
18 #include "cc/trees/layer_tree_impl.h"
19 
20 namespace cc {
21 namespace {
22 
23 // These tests deal with damage tracking.
24 class LayerTreeHostDamageTest : public LayerTreeTest {};
25 
26 // LayerTreeHost::SetNeedsRedraw should damage the whole viewport.
27 class LayerTreeHostDamageTestSetNeedsRedraw
28     : public LayerTreeHostDamageTest {
SetupTree()29   void SetupTree() override {
30     // Viewport is 10x10.
31     scoped_refptr<FakePictureLayer> root = FakePictureLayer::Create(&client_);
32     root->SetBounds(gfx::Size(10, 10));
33 
34     layer_tree_host()->SetRootLayer(root);
35     LayerTreeHostDamageTest::SetupTree();
36     client_.set_bounds(root->bounds());
37   }
38 
BeginTest()39   void BeginTest() override {
40     draw_count_ = 0;
41     PostSetNeedsCommitToMainThread();
42   }
43 
DidCommitAndDrawFrame()44   void DidCommitAndDrawFrame() override {
45     switch (layer_tree_host()->SourceFrameNumber()) {
46       case 1:
47         layer_tree_host()->SetNeedsRedrawRect(
48             layer_tree_host()->device_viewport_rect());
49         break;
50     }
51   }
52 
PrepareToDrawOnThread(LayerTreeHostImpl * impl,LayerTreeHostImpl::FrameData * frame_data,DrawResult draw_result)53   DrawResult PrepareToDrawOnThread(LayerTreeHostImpl* impl,
54                                    LayerTreeHostImpl::FrameData* frame_data,
55                                    DrawResult draw_result) override {
56     EXPECT_EQ(DRAW_SUCCESS, draw_result);
57 
58     RenderSurfaceImpl* root_surface =
59         GetRenderSurface(impl->active_tree()->root_layer());
60     gfx::Rect root_damage;
61     EXPECT_TRUE(
62         root_surface->damage_tracker()->GetDamageRectIfValid(&root_damage));
63 
64     switch (draw_count_) {
65       case 0:
66         // The first frame has full damage.
67         EXPECT_EQ(gfx::Rect(10, 10), root_damage);
68         break;
69       case 1:
70         // The second frame has full damage.
71         EXPECT_EQ(gfx::Rect(10, 10), root_damage);
72         EndTest();
73         break;
74       case 2:
75         NOTREACHED();
76     }
77 
78     ++draw_count_;
79     return draw_result;
80   }
81 
82   int draw_count_;
83   FakeContentLayerClient client_;
84 };
85 
86 SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostDamageTestSetNeedsRedraw);
87 
88 // LayerTreeHost::SetViewportRectAndScale should damage the whole viewport.
89 class LayerTreeHostDamageTestSetViewportRectAndScale
90     : public LayerTreeHostDamageTest {
SetupTree()91   void SetupTree() override {
92     // Viewport is 10x10.
93     scoped_refptr<FakePictureLayer> root = FakePictureLayer::Create(&client_);
94     root->SetBounds(gfx::Size(10, 10));
95 
96     layer_tree_host()->SetRootLayer(root);
97     LayerTreeHostDamageTest::SetupTree();
98     client_.set_bounds(root->bounds());
99   }
100 
BeginTest()101   void BeginTest() override {
102     draw_count_ = 0;
103     PostSetNeedsCommitToMainThread();
104   }
105 
DidCommitAndDrawFrame()106   void DidCommitAndDrawFrame() override {
107     switch (layer_tree_host()->SourceFrameNumber()) {
108       case 1:
109         layer_tree_host()->SetViewportRectAndScale(gfx::Rect(15, 15), 1.f,
110                                                    GetCurrentLocalSurfaceId());
111         break;
112     }
113   }
114 
PrepareToDrawOnThread(LayerTreeHostImpl * impl,LayerTreeHostImpl::FrameData * frame_data,DrawResult draw_result)115   DrawResult PrepareToDrawOnThread(LayerTreeHostImpl* impl,
116                                    LayerTreeHostImpl::FrameData* frame_data,
117                                    DrawResult draw_result) override {
118     EXPECT_EQ(DRAW_SUCCESS, draw_result);
119 
120     RenderSurfaceImpl* root_surface =
121         GetRenderSurface(impl->active_tree()->root_layer());
122     gfx::Rect root_damage;
123     EXPECT_TRUE(
124         root_surface->damage_tracker()->GetDamageRectIfValid(&root_damage));
125 
126     switch (draw_count_) {
127       case 0:
128         // The first frame has full damage.
129         EXPECT_EQ(gfx::Rect(10, 10), root_damage);
130         break;
131       case 1:
132         // The second frame has full damage.
133         EXPECT_EQ(gfx::Rect(15, 15), root_damage);
134         EndTest();
135         break;
136       case 2:
137         NOTREACHED();
138     }
139 
140     ++draw_count_;
141     return draw_result;
142   }
143 
144   int draw_count_;
145   FakeContentLayerClient client_;
146 };
147 
148 SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostDamageTestSetViewportRectAndScale);
149 
150 class LayerTreeHostDamageTestNoDamageDoesNotSwap
151     : public LayerTreeHostDamageTest {
BeginTest()152   void BeginTest() override {
153     PostSetNeedsCommitToMainThread();
154   }
155 
SetupTree()156   void SetupTree() override {
157     scoped_refptr<FakePictureLayer> root = FakePictureLayer::Create(&client_);
158     root->SetBounds(gfx::Size(10, 10));
159 
160     // Most of the layer isn't visible.
161     content_ = FakePictureLayer::Create(&client_);
162     content_->SetBounds(gfx::Size(2000, 100));
163     root->AddChild(content_);
164 
165     layer_tree_host()->SetRootLayer(root);
166     LayerTreeHostDamageTest::SetupTree();
167     client_.set_bounds(root->bounds());
168   }
169 
PrepareToDrawOnThread(LayerTreeHostImpl * host_impl,LayerTreeHostImpl::FrameData * frame_data,DrawResult draw_result)170   DrawResult PrepareToDrawOnThread(LayerTreeHostImpl* host_impl,
171                                    LayerTreeHostImpl::FrameData* frame_data,
172                                    DrawResult draw_result) override {
173     EXPECT_EQ(DRAW_SUCCESS, draw_result);
174 
175     int source_frame = host_impl->active_tree()->source_frame_number();
176     switch (source_frame) {
177       case 0:
178         // The first frame has damage, so we should draw and swap.
179         EXPECT_FALSE(frame_data->has_no_damage);
180         ++expect_swap_;
181         break;
182       case 1:
183         // The second frame has no damage, so we should not draw and swap.
184         EXPECT_TRUE(frame_data->has_no_damage);
185         break;
186       case 2:
187         // The third frame has damage again, so we should draw and swap.
188         EXPECT_FALSE(frame_data->has_no_damage);
189         ++expect_swap_;
190         break;
191       case 3:
192         // The fourth frame has no visible damage, so we should not draw and
193         // swap.
194         EXPECT_TRUE(frame_data->has_no_damage);
195         EndTest();
196         break;
197     }
198     return draw_result;
199   }
200 
DisplayDidDrawAndSwapOnThread()201   void DisplayDidDrawAndSwapOnThread() override {
202     ++did_swap_;
203     EXPECT_EQ(expect_swap_, did_swap_);
204   }
205 
DidCommit()206   void DidCommit() override {
207     int next_frame = layer_tree_host()->SourceFrameNumber();
208     switch (next_frame) {
209       case 1:
210         layer_tree_host()->SetNeedsCommit();
211         break;
212       case 2:
213         // Cause visible damage.
214         content_->SetNeedsDisplayRect(
215             layer_tree_host()->device_viewport_rect());
216         break;
217       case 3:
218         // Cause non-visible damage.
219         content_->SetNeedsDisplayRect(gfx::Rect(1990, 1990, 10, 10));
220         layer_tree_host()->SetNeedsCommit();
221         break;
222     }
223   }
224 
AfterTest()225   void AfterTest() override {
226     EXPECT_EQ(2, expect_swap_);
227     EXPECT_EQ(expect_swap_, did_swap_);
228   }
229 
230   FakeContentLayerClient client_;
231   scoped_refptr<FakePictureLayer> content_;
232   int expect_swap_ = 0;
233   int did_swap_ = 0;
234 };
235 
236 SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostDamageTestNoDamageDoesNotSwap);
237 
238 class LayerTreeHostDamageTestForcedFullDamage : public LayerTreeHostDamageTest {
BeginTest()239   void BeginTest() override { PostSetNeedsCommitToMainThread(); }
240 
SetupTree()241   void SetupTree() override {
242     root_ = FakePictureLayer::Create(&client_);
243     child_ = FakePictureLayer::Create(&client_);
244 
245     root_->SetBounds(gfx::Size(500, 500));
246     child_->SetPosition(gfx::PointF(100.f, 100.f));
247     child_->SetBounds(gfx::Size(30, 30));
248 
249     root_->AddChild(child_);
250     layer_tree_host()->SetRootLayer(root_);
251     LayerTreeHostDamageTest::SetupTree();
252     client_.set_bounds(root_->bounds());
253   }
254 
PrepareToDrawOnThread(LayerTreeHostImpl * host_impl,LayerTreeHostImpl::FrameData * frame_data,DrawResult draw_result)255   DrawResult PrepareToDrawOnThread(LayerTreeHostImpl* host_impl,
256                                    LayerTreeHostImpl::FrameData* frame_data,
257                                    DrawResult draw_result) override {
258     EXPECT_EQ(DRAW_SUCCESS, draw_result);
259 
260     RenderSurfaceImpl* root_surface =
261         GetRenderSurface(host_impl->active_tree()->root_layer());
262     gfx::Rect root_damage;
263     EXPECT_TRUE(
264         root_surface->damage_tracker()->GetDamageRectIfValid(&root_damage));
265     root_damage.Intersect(root_surface->content_rect());
266 
267     int source_frame = host_impl->active_tree()->source_frame_number();
268     switch (source_frame) {
269       case 0:
270         // The first frame draws and clears any damage.
271         EXPECT_EQ(root_surface->content_rect(), root_damage);
272         EXPECT_FALSE(frame_data->has_no_damage);
273         break;
274       case 1:
275         // If we get a frame without damage then we don't draw.
276         EXPECT_EQ(gfx::Rect(), root_damage);
277         EXPECT_TRUE(frame_data->has_no_damage);
278 
279         // Then we set full damage for the next frame.
280         host_impl->SetFullViewportDamage();
281         break;
282       case 2:
283         // The whole frame should be damaged as requested.
284         EXPECT_EQ(root_surface->content_rect(), root_damage);
285         EXPECT_FALSE(frame_data->has_no_damage);
286 
287         // Just a part of the next frame should be damaged.
288         child_damage_rect_ = gfx::Rect(10, 11, 12, 13);
289         break;
290       case 3:
291         // The update rect in the child should be damaged and the damaged area
292         // should match the invalidation.
293         EXPECT_EQ(gfx::Rect(100 + 10, 100 + 11, 12, 13), root_damage);
294         EXPECT_FALSE(frame_data->has_no_damage);
295 
296         // If we damage part of the frame, but also damage the full
297         // frame, then the whole frame should be damaged.
298         child_damage_rect_ = gfx::Rect(10, 11, 12, 13);
299         host_impl->SetFullViewportDamage();
300         break;
301       case 4:
302         // The whole frame is damaged.
303         EXPECT_EQ(root_surface->content_rect(), root_damage);
304         EXPECT_FALSE(frame_data->has_no_damage);
305 
306         EndTest();
307         break;
308     }
309     return draw_result;
310   }
311 
DidCommitAndDrawFrame()312   void DidCommitAndDrawFrame() override {
313     if (!TestEnded())
314       layer_tree_host()->SetNeedsCommit();
315 
316     if (!child_damage_rect_.IsEmpty()) {
317       child_->SetNeedsDisplayRect(child_damage_rect_);
318       child_damage_rect_ = gfx::Rect();
319     }
320   }
321 
322   FakeContentLayerClient client_;
323   scoped_refptr<FakePictureLayer> root_;
324   scoped_refptr<FakePictureLayer> child_;
325   gfx::Rect child_damage_rect_;
326 };
327 
328 SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostDamageTestForcedFullDamage);
329 
330 class LayerTreeHostScrollbarDamageTest : public LayerTreeHostDamageTest {
SetupTree()331   void SetupTree() override {
332     scoped_refptr<Layer> root_layer = Layer::Create();
333     root_layer->SetBounds(gfx::Size(400, 400));
334     root_layer->SetMasksToBounds(true);
335     layer_tree_host()->SetRootLayer(root_layer);
336 
337     content_layer_ = FakePictureLayer::Create(&client_);
338     content_layer_->SetElementId(
339         LayerIdToElementIdForTesting(content_layer_->id()));
340     content_layer_->SetScrollable(root_layer->bounds());
341     content_layer_->SetScrollOffset(gfx::ScrollOffset(10, 20));
342     content_layer_->SetBounds(gfx::Size(100, 200));
343     content_layer_->SetIsDrawable(true);
344     root_layer->AddChild(content_layer_);
345 
346     scoped_refptr<Layer> scrollbar_layer = FakePaintedScrollbarLayer::Create(
347         false, true, content_layer_->element_id());
348     scrollbar_layer->SetPosition(gfx::PointF(300.f, 300.f));
349     scrollbar_layer->SetBounds(gfx::Size(10, 100));
350     root_layer->AddChild(scrollbar_layer);
351 
352     gfx::RectF content_rect(content_layer_->position(),
353                             gfx::SizeF(content_layer_->bounds()));
354     gfx::RectF scrollbar_rect(scrollbar_layer->position(),
355                               gfx::SizeF(scrollbar_layer->bounds()));
356     EXPECT_FALSE(content_rect.Intersects(scrollbar_rect));
357 
358     LayerTreeHostDamageTest::SetupTree();
359     client_.set_bounds(root_layer->bounds());
360   }
361 
362  private:
363   FakeContentLayerClient client_;
364 
365  protected:
366   scoped_refptr<Layer> content_layer_;
367 };
368 
369 class LayerTreeHostDamageTestScrollbarDoesDamage
370     : public LayerTreeHostScrollbarDamageTest {
BeginTest()371   void BeginTest() override {
372     num_draws_ = 0;
373     PostSetNeedsCommitToMainThread();
374   }
375 
PrepareToDrawOnThread(LayerTreeHostImpl * host_impl,LayerTreeHostImpl::FrameData * frame_data,DrawResult draw_result)376   DrawResult PrepareToDrawOnThread(LayerTreeHostImpl* host_impl,
377                                    LayerTreeHostImpl::FrameData* frame_data,
378                                    DrawResult draw_result) override {
379     EXPECT_EQ(DRAW_SUCCESS, draw_result);
380     RenderSurfaceImpl* root_surface =
381         GetRenderSurface(host_impl->active_tree()->root_layer());
382     gfx::Rect root_damage;
383     EXPECT_TRUE(
384         root_surface->damage_tracker()->GetDamageRectIfValid(&root_damage));
385     root_damage.Intersect(root_surface->content_rect());
386     switch (num_draws_) {
387       case 0:
388         // The first frame has damage, so we should draw and swap.
389         break;
390       case 1:
391         // The second frame should not damage the scrollbars.
392         EXPECT_FALSE(root_damage.Intersects(gfx::Rect(300, 300, 10, 100)));
393         break;
394       case 2:
395         // The third frame should damage the scrollbars.
396         EXPECT_TRUE(root_damage.Contains(gfx::Rect(300, 300, 10, 100)));
397         break;
398       case 3:
399         // The fourth frame should damage the scrollbars.
400         EXPECT_TRUE(root_damage.Contains(gfx::Rect(300, 300, 10, 100)));
401         EndTest();
402         break;
403     }
404     return draw_result;
405   }
406 
DrawLayersOnThread(LayerTreeHostImpl * host_impl)407   void DrawLayersOnThread(LayerTreeHostImpl* host_impl) override {
408     ++num_draws_;
409     LayerImpl* scroll_layer =
410         host_impl->active_tree()->LayerById(content_layer_->id());
411     switch (num_draws_) {
412       case 1:
413         // Test that modifying the position of the content layer (not
414         // scrolling) won't damage the scrollbar.
415         MainThreadTaskRunner()->PostTask(
416             FROM_HERE,
417             base::BindOnce(&LayerTreeHostDamageTestScrollbarDoesDamage::
418                                ModifyContentLayerPosition,
419                            base::Unretained(this)));
420         break;
421       case 2:
422         scroll_layer->ScrollBy(gfx::Vector2dF(10.f, 10.f));
423         host_impl->SetNeedsRedraw();
424         break;
425       case 3:
426         // We will resize the content layer, on the main thread.
427         MainThreadTaskRunner()->PostTask(
428             FROM_HERE,
429             base::BindOnce(
430                 &LayerTreeHostDamageTestScrollbarDoesDamage::ResizeScrollLayer,
431                 base::Unretained(this)));
432         break;
433     }
434   }
435 
ModifyContentLayerPosition()436   void ModifyContentLayerPosition() {
437     EXPECT_EQ(1, num_draws_);
438     content_layer_->SetPosition(gfx::PointF(10.f, 10.f));
439   }
440 
ResizeScrollLayer()441   void ResizeScrollLayer() {
442     EXPECT_EQ(3, num_draws_);
443     Layer* root = layer_tree_host()->root_layer();
444     content_layer_->SetBounds(
445         gfx::Size(root->bounds().width() + 60, root->bounds().height() + 100));
446   }
447 
AfterTest()448   void AfterTest() override { EXPECT_EQ(4, num_draws_); }
449 
450   int num_draws_;
451 };
452 
453 MULTI_THREAD_TEST_F(LayerTreeHostDamageTestScrollbarDoesDamage);
454 
455 class LayerTreeHostDamageTestScrollbarCommitDoesNoDamage
456     : public LayerTreeHostScrollbarDamageTest {
BeginTest()457   void BeginTest() override {
458     num_draws_ = 0;
459     PostSetNeedsCommitToMainThread();
460   }
461 
PrepareToDrawOnThread(LayerTreeHostImpl * host_impl,LayerTreeHostImpl::FrameData * frame_data,DrawResult draw_result)462   DrawResult PrepareToDrawOnThread(LayerTreeHostImpl* host_impl,
463                                    LayerTreeHostImpl::FrameData* frame_data,
464                                    DrawResult draw_result) override {
465     EXPECT_EQ(DRAW_SUCCESS, draw_result);
466     RenderSurfaceImpl* root_surface =
467         GetRenderSurface(host_impl->active_tree()->root_layer());
468     gfx::Rect root_damage;
469     EXPECT_TRUE(
470         root_surface->damage_tracker()->GetDamageRectIfValid(&root_damage));
471     root_damage.Intersect(root_surface->content_rect());
472     int frame = host_impl->active_tree()->source_frame_number();
473     switch (num_draws_) {
474       case 0:
475         // The first frame has damage, so we should draw and swap.
476         EXPECT_EQ(0, frame);
477         break;
478       case 1:
479         // The second frame has scrolled, so the scrollbar should be damaged.
480         EXPECT_EQ(0, frame);
481         EXPECT_TRUE(root_damage.Contains(gfx::Rect(300, 300, 10, 100)));
482         break;
483       case 2:
484         // The third frame (after the commit) has no changes, so it shouldn't.
485         EXPECT_EQ(1, frame);
486         EXPECT_FALSE(root_damage.Intersects(gfx::Rect(300, 300, 10, 100)));
487         break;
488       default:
489         NOTREACHED();
490         break;
491     }
492     return draw_result;
493   }
494 
DrawLayersOnThread(LayerTreeHostImpl * host_impl)495   void DrawLayersOnThread(LayerTreeHostImpl* host_impl) override {
496     ++num_draws_;
497     LayerImpl* scroll_layer =
498         host_impl->active_tree()->LayerById(content_layer_->id());
499     switch (num_draws_) {
500       case 1:
501         // Scroll on the thread.  This should damage the scrollbar for the
502         // next draw on the thread.
503         scroll_layer->ScrollBy(gfx::Vector2dF(10.f, 10.f));
504         host_impl->SetNeedsRedraw();
505         break;
506       case 2:
507         // Forcibly send the scroll to the main thread.
508         PostSetNeedsCommitToMainThread();
509         break;
510       case 3:
511         // First swap after second commit.
512         EndTest();
513         break;
514       default:
515         NOTREACHED();
516         break;
517     }
518   }
519 
AfterTest()520   void AfterTest() override { EXPECT_EQ(3, num_draws_); }
521 
522   int num_draws_;
523 };
524 
525 MULTI_THREAD_TEST_F(LayerTreeHostDamageTestScrollbarCommitDoesNoDamage);
526 
527 }  // namespace
528 }  // namespace cc
529