Fix build break
[chromium-blink-merge.git] / cc / trees / layer_tree_host_impl_unittest.cc
blob301bf27799b71768f3c92a65a0acfb38aba37b2f
1 // Copyright 2011 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.
5 #include "cc/trees/layer_tree_host_impl.h"
7 #include <cmath>
9 #include "base/bind.h"
10 #include "base/command_line.h"
11 #include "base/hash_tables.h"
12 #include "cc/base/math_util.h"
13 #include "cc/input/top_controls_manager.h"
14 #include "cc/layers/delegated_renderer_layer_impl.h"
15 #include "cc/layers/heads_up_display_layer_impl.h"
16 #include "cc/layers/io_surface_layer_impl.h"
17 #include "cc/layers/layer_impl.h"
18 #include "cc/layers/quad_sink.h"
19 #include "cc/layers/render_surface_impl.h"
20 #include "cc/layers/scrollbar_geometry_fixed_thumb.h"
21 #include "cc/layers/scrollbar_layer_impl.h"
22 #include "cc/layers/solid_color_layer_impl.h"
23 #include "cc/layers/texture_layer_impl.h"
24 #include "cc/layers/tiled_layer_impl.h"
25 #include "cc/layers/video_layer_impl.h"
26 #include "cc/output/compositor_frame_metadata.h"
27 #include "cc/output/gl_renderer.h"
28 #include "cc/quads/render_pass_draw_quad.h"
29 #include "cc/quads/solid_color_draw_quad.h"
30 #include "cc/quads/texture_draw_quad.h"
31 #include "cc/quads/tile_draw_quad.h"
32 #include "cc/resources/layer_tiling_data.h"
33 #include "cc/test/animation_test_common.h"
34 #include "cc/test/fake_output_surface.h"
35 #include "cc/test/fake_proxy.h"
36 #include "cc/test/fake_rendering_stats_instrumentation.h"
37 #include "cc/test/fake_video_frame_provider.h"
38 #include "cc/test/fake_web_scrollbar_theme_geometry.h"
39 #include "cc/test/geometry_test_utils.h"
40 #include "cc/test/layer_test_common.h"
41 #include "cc/test/render_pass_test_common.h"
42 #include "cc/test/test_web_graphics_context_3d.h"
43 #include "cc/trees/layer_tree_impl.h"
44 #include "cc/trees/single_thread_proxy.h"
45 #include "media/base/media.h"
46 #include "testing/gmock/include/gmock/gmock.h"
47 #include "testing/gtest/include/gtest/gtest.h"
48 #include "ui/gfx/size_conversions.h"
49 #include "ui/gfx/vector2d_conversions.h"
51 using ::testing::Mock;
52 using ::testing::Return;
53 using ::testing::AnyNumber;
54 using ::testing::AtLeast;
55 using ::testing::_;
56 using media::VideoFrame;
58 namespace cc {
59 namespace {
61 class LayerTreeHostImplTest : public testing::Test,
62 public LayerTreeHostImplClient {
63 public:
64 LayerTreeHostImplTest()
65 : proxy_(scoped_ptr<Thread>(NULL)),
66 always_impl_thread_(&proxy_),
67 always_main_thread_blocked_(&proxy_),
68 on_can_draw_state_changed_called_(false),
69 has_pending_tree_(false),
70 did_request_commit_(false),
71 did_request_redraw_(false),
72 did_upload_visible_tile_(false),
73 reduce_memory_result_(true) {
74 media::InitializeMediaLibraryForTesting();
77 virtual void SetUp() OVERRIDE {
78 LayerTreeSettings settings;
79 settings.minimum_occlusion_tracking_size = gfx::Size();
81 host_impl_ = LayerTreeHostImpl::Create(settings,
82 this,
83 &proxy_,
84 &stats_instrumentation_);
85 host_impl_->InitializeRenderer(CreateOutputSurface());
86 host_impl_->SetViewportSize(gfx::Size(10, 10));
89 virtual void TearDown() OVERRIDE {}
91 virtual void DidLoseOutputSurfaceOnImplThread() OVERRIDE {}
92 virtual void OnSwapBuffersCompleteOnImplThread() OVERRIDE {}
93 virtual void OnVSyncParametersChanged(base::TimeTicks timebase,
94 base::TimeDelta interval) OVERRIDE {}
95 virtual void DidVSync(base::TimeTicks frame_time) OVERRIDE {}
96 virtual void OnCanDrawStateChanged(bool can_draw) OVERRIDE {
97 on_can_draw_state_changed_called_ = true;
99 virtual void OnHasPendingTreeStateChanged(bool has_pending_tree) OVERRIDE {
100 has_pending_tree_ = has_pending_tree;
102 virtual void SetNeedsRedrawOnImplThread() OVERRIDE {
103 did_request_redraw_ = true;
105 virtual void DidInitializeVisibleTileOnImplThread() OVERRIDE {
106 did_upload_visible_tile_ = true;
108 virtual void SetNeedsCommitOnImplThread() OVERRIDE {
109 did_request_commit_ = true;
111 virtual void SetNeedsManageTilesOnImplThread() OVERRIDE {}
112 virtual void PostAnimationEventsToMainThreadOnImplThread(
113 scoped_ptr<AnimationEventsVector> events,
114 base::Time wall_clock_time) OVERRIDE {}
115 virtual bool ReduceContentsTextureMemoryOnImplThread(
116 size_t limit_bytes, int priority_cutoff) OVERRIDE {
117 return reduce_memory_result_;
119 virtual void ReduceWastedContentsTextureMemoryOnImplThread() OVERRIDE {}
120 virtual void SendManagedMemoryStats() OVERRIDE {}
121 virtual bool IsInsideDraw() OVERRIDE { return false; }
122 virtual void RenewTreePriority() OVERRIDE {}
123 virtual void RequestScrollbarAnimationOnImplThread(base::TimeDelta delay)
124 OVERRIDE {}
126 void set_reduce_memory_result(bool reduce_memory_result) {
127 reduce_memory_result_ = reduce_memory_result;
130 void CreateLayerTreeHost(bool partial_swap,
131 scoped_ptr<OutputSurface> output_surface) {
132 LayerTreeSettings settings;
133 settings.minimum_occlusion_tracking_size = gfx::Size();
134 settings.partial_swap_enabled = partial_swap;
136 host_impl_ = LayerTreeHostImpl::Create(settings,
137 this,
138 &proxy_,
139 &stats_instrumentation_);
141 host_impl_->InitializeRenderer(output_surface.Pass());
142 host_impl_->SetViewportSize(gfx::Size(10, 10));
145 void SetupRootLayerImpl(scoped_ptr<LayerImpl> root) {
146 root->SetAnchorPoint(gfx::PointF());
147 root->SetPosition(gfx::PointF());
148 root->SetBounds(gfx::Size(10, 10));
149 root->SetContentBounds(gfx::Size(10, 10));
150 root->SetDrawsContent(true);
151 root->draw_properties().visible_content_rect = gfx::Rect(0, 0, 10, 10);
152 host_impl_->active_tree()->SetRootLayer(root.Pass());
155 static void ExpectClearedScrollDeltasRecursive(LayerImpl* layer) {
156 ASSERT_EQ(layer->scroll_delta(), gfx::Vector2d());
157 for (size_t i = 0; i < layer->children().size(); ++i)
158 ExpectClearedScrollDeltasRecursive(layer->children()[i]);
161 static void ExpectContains(const ScrollAndScaleSet& scroll_info,
162 int id,
163 gfx::Vector2d scroll_delta) {
164 int times_encountered = 0;
166 for (size_t i = 0; i < scroll_info.scrolls.size(); ++i) {
167 if (scroll_info.scrolls[i].layer_id != id)
168 continue;
169 EXPECT_VECTOR_EQ(scroll_delta, scroll_info.scrolls[i].scroll_delta);
170 times_encountered++;
173 ASSERT_EQ(times_encountered, 1);
176 static void ExpectNone(const ScrollAndScaleSet& scroll_info, int id) {
177 int times_encountered = 0;
179 for (size_t i = 0; i < scroll_info.scrolls.size(); ++i) {
180 if (scroll_info.scrolls[i].layer_id != id)
181 continue;
182 times_encountered++;
185 ASSERT_EQ(0, times_encountered);
188 void SetupScrollAndContentsLayers(gfx::Size content_size) {
189 scoped_ptr<LayerImpl> root =
190 LayerImpl::Create(host_impl_->active_tree(), 1);
191 root->SetScrollable(true);
192 root->SetScrollOffset(gfx::Vector2d());
193 root->SetMaxScrollOffset(gfx::Vector2d(content_size.width(),
194 content_size.height()));
195 root->SetBounds(content_size);
196 root->SetContentBounds(content_size);
197 root->SetPosition(gfx::PointF());
198 root->SetAnchorPoint(gfx::PointF());
200 scoped_ptr<LayerImpl> contents =
201 LayerImpl::Create(host_impl_->active_tree(), 2);
202 contents->SetDrawsContent(true);
203 contents->SetBounds(content_size);
204 contents->SetContentBounds(content_size);
205 contents->SetPosition(gfx::PointF());
206 contents->SetAnchorPoint(gfx::PointF());
207 root->AddChild(contents.Pass());
208 host_impl_->active_tree()->SetRootLayer(root.Pass());
209 host_impl_->active_tree()->DidBecomeActive();
212 scoped_ptr<LayerImpl> CreateScrollableLayer(int id, gfx::Size size) {
213 scoped_ptr<LayerImpl> layer =
214 LayerImpl::Create(host_impl_->active_tree(), id);
215 layer->SetScrollable(true);
216 layer->SetDrawsContent(true);
217 layer->SetBounds(size);
218 layer->SetContentBounds(size);
219 layer->SetMaxScrollOffset(gfx::Vector2d(size.width() * 2,
220 size.height() * 2));
221 return layer.Pass();
224 void InitializeRendererAndDrawFrame() {
225 host_impl_->InitializeRenderer(CreateOutputSurface());
226 LayerTreeHostImpl::FrameData frame;
227 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
228 host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
229 host_impl_->DidDrawAllLayers(frame);
232 void pinch_zoom_pan_viewport_forces_commit_redraw(float device_scale_factor);
233 void pinch_zoom_pan_viewport_test(float device_scale_factor);
234 void pinch_zoom_pan_viewport_and_scroll_test(float device_scale_factor);
235 void pinch_zoom_pan_viewport_and_scroll_boundary_test(
236 float device_scale_factor);
238 protected:
239 virtual scoped_ptr<OutputSurface> CreateOutputSurface() {
240 return CreateFakeOutputSurface();
243 void DrawOneFrame() {
244 LayerTreeHostImpl::FrameData frame_data;
245 host_impl_->PrepareToDraw(&frame_data, gfx::Rect());
246 host_impl_->DidDrawAllLayers(frame_data);
249 FakeProxy proxy_;
250 DebugScopedSetImplThread always_impl_thread_;
251 DebugScopedSetMainThreadBlocked always_main_thread_blocked_;
253 scoped_ptr<LayerTreeHostImpl> host_impl_;
254 FakeRenderingStatsInstrumentation stats_instrumentation_;
255 bool on_can_draw_state_changed_called_;
256 bool has_pending_tree_;
257 bool did_request_commit_;
258 bool did_request_redraw_;
259 bool did_upload_visible_tile_;
260 bool reduce_memory_result_;
263 class TestWebGraphicsContext3DMakeCurrentFails
264 : public TestWebGraphicsContext3D {
265 public:
266 virtual bool makeContextCurrent() OVERRIDE { return false; }
269 TEST_F(LayerTreeHostImplTest, NotifyIfCanDrawChanged) {
270 // Note: It is not possible to disable the renderer once it has been set,
271 // so we do not need to test that disabling the renderer notifies us
272 // that can_draw changed.
273 EXPECT_FALSE(host_impl_->CanDraw());
274 on_can_draw_state_changed_called_ = false;
276 SetupScrollAndContentsLayers(gfx::Size(100, 100));
277 EXPECT_TRUE(host_impl_->CanDraw());
278 EXPECT_TRUE(on_can_draw_state_changed_called_);
279 on_can_draw_state_changed_called_ = false;
281 // Toggle the root layer to make sure it toggles can_draw
282 host_impl_->active_tree()->SetRootLayer(scoped_ptr<LayerImpl>());
283 EXPECT_FALSE(host_impl_->CanDraw());
284 EXPECT_TRUE(on_can_draw_state_changed_called_);
285 on_can_draw_state_changed_called_ = false;
287 SetupScrollAndContentsLayers(gfx::Size(100, 100));
288 EXPECT_TRUE(host_impl_->CanDraw());
289 EXPECT_TRUE(on_can_draw_state_changed_called_);
290 on_can_draw_state_changed_called_ = false;
292 // Toggle the device viewport size to make sure it toggles can_draw.
293 host_impl_->SetViewportSize(gfx::Size());
294 EXPECT_FALSE(host_impl_->CanDraw());
295 EXPECT_TRUE(on_can_draw_state_changed_called_);
296 on_can_draw_state_changed_called_ = false;
298 host_impl_->SetViewportSize(gfx::Size(100, 100));
299 EXPECT_TRUE(host_impl_->CanDraw());
300 EXPECT_TRUE(on_can_draw_state_changed_called_);
301 on_can_draw_state_changed_called_ = false;
303 // Toggle contents textures purged without causing any evictions,
304 // and make sure that it does not change can_draw.
305 set_reduce_memory_result(false);
306 host_impl_->SetManagedMemoryPolicy(ManagedMemoryPolicy(
307 host_impl_->memory_allocation_limit_bytes() - 1));
308 EXPECT_TRUE(host_impl_->CanDraw());
309 EXPECT_FALSE(on_can_draw_state_changed_called_);
310 on_can_draw_state_changed_called_ = false;
312 // Toggle contents textures purged to make sure it toggles can_draw.
313 set_reduce_memory_result(true);
314 host_impl_->SetManagedMemoryPolicy(ManagedMemoryPolicy(
315 host_impl_->memory_allocation_limit_bytes() - 1));
316 EXPECT_FALSE(host_impl_->CanDraw());
317 EXPECT_TRUE(on_can_draw_state_changed_called_);
318 on_can_draw_state_changed_called_ = false;
320 host_impl_->active_tree()->ResetContentsTexturesPurged();
321 EXPECT_TRUE(host_impl_->CanDraw());
322 EXPECT_TRUE(on_can_draw_state_changed_called_);
323 on_can_draw_state_changed_called_ = false;
326 TEST_F(LayerTreeHostImplTest, ScrollDeltaNoLayers) {
327 ASSERT_FALSE(host_impl_->active_tree()->root_layer());
329 scoped_ptr<ScrollAndScaleSet> scroll_info = host_impl_->ProcessScrollDeltas();
330 ASSERT_EQ(scroll_info->scrolls.size(), 0u);
333 TEST_F(LayerTreeHostImplTest, ScrollDeltaTreeButNoChanges) {
335 scoped_ptr<LayerImpl> root =
336 LayerImpl::Create(host_impl_->active_tree(), 1);
337 root->AddChild(LayerImpl::Create(host_impl_->active_tree(), 2));
338 root->AddChild(LayerImpl::Create(host_impl_->active_tree(), 3));
339 root->children()[1]->AddChild(
340 LayerImpl::Create(host_impl_->active_tree(), 4));
341 root->children()[1]->AddChild(
342 LayerImpl::Create(host_impl_->active_tree(), 5));
343 root->children()[1]->children()[0]->AddChild(
344 LayerImpl::Create(host_impl_->active_tree(), 6));
345 host_impl_->active_tree()->SetRootLayer(root.Pass());
347 LayerImpl* root = host_impl_->active_tree()->root_layer();
349 ExpectClearedScrollDeltasRecursive(root);
351 scoped_ptr<ScrollAndScaleSet> scroll_info;
353 scroll_info = host_impl_->ProcessScrollDeltas();
354 ASSERT_EQ(scroll_info->scrolls.size(), 0u);
355 ExpectClearedScrollDeltasRecursive(root);
357 scroll_info = host_impl_->ProcessScrollDeltas();
358 ASSERT_EQ(scroll_info->scrolls.size(), 0u);
359 ExpectClearedScrollDeltasRecursive(root);
362 TEST_F(LayerTreeHostImplTest, ScrollDeltaRepeatedScrolls) {
363 gfx::Vector2d scroll_offset(20, 30);
364 gfx::Vector2d scroll_delta(11, -15);
366 scoped_ptr<LayerImpl> root =
367 LayerImpl::Create(host_impl_->active_tree(), 1);
368 root->SetScrollOffset(scroll_offset);
369 root->SetScrollable(true);
370 root->SetMaxScrollOffset(gfx::Vector2d(100, 100));
371 root->ScrollBy(scroll_delta);
372 host_impl_->active_tree()->SetRootLayer(root.Pass());
374 LayerImpl* root = host_impl_->active_tree()->root_layer();
376 scoped_ptr<ScrollAndScaleSet> scroll_info;
378 scroll_info = host_impl_->ProcessScrollDeltas();
379 ASSERT_EQ(scroll_info->scrolls.size(), 1u);
380 EXPECT_VECTOR_EQ(root->sent_scroll_delta(), scroll_delta);
381 ExpectContains(*scroll_info, root->id(), scroll_delta);
383 gfx::Vector2d scroll_delta2(-5, 27);
384 root->ScrollBy(scroll_delta2);
385 scroll_info = host_impl_->ProcessScrollDeltas();
386 ASSERT_EQ(scroll_info->scrolls.size(), 1u);
387 EXPECT_VECTOR_EQ(root->sent_scroll_delta(), scroll_delta + scroll_delta2);
388 ExpectContains(*scroll_info, root->id(), scroll_delta + scroll_delta2);
390 root->ScrollBy(gfx::Vector2d());
391 scroll_info = host_impl_->ProcessScrollDeltas();
392 EXPECT_EQ(root->sent_scroll_delta(), scroll_delta + scroll_delta2);
395 TEST_F(LayerTreeHostImplTest, ScrollRootCallsCommitAndRedraw) {
396 SetupScrollAndContentsLayers(gfx::Size(100, 100));
397 host_impl_->SetViewportSize(gfx::Size(50, 50));
398 InitializeRendererAndDrawFrame();
400 EXPECT_EQ(InputHandlerClient::ScrollStarted,
401 host_impl_->ScrollBegin(gfx::Point(), InputHandlerClient::Wheel));
402 host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, 10));
403 host_impl_->ScrollEnd();
404 EXPECT_TRUE(did_request_redraw_);
405 EXPECT_TRUE(did_request_commit_);
408 TEST_F(LayerTreeHostImplTest, ScrollWithoutRootLayer) {
409 // We should not crash when trying to scroll an empty layer tree.
410 EXPECT_EQ(InputHandlerClient::ScrollIgnored,
411 host_impl_->ScrollBegin(gfx::Point(), InputHandlerClient::Wheel));
414 TEST_F(LayerTreeHostImplTest, ScrollWithoutRenderer) {
415 LayerTreeSettings settings;
416 host_impl_ = LayerTreeHostImpl::Create(settings,
417 this,
418 &proxy_,
419 &stats_instrumentation_);
421 // Initialization will fail here.
422 host_impl_->InitializeRenderer(FakeOutputSurface::Create3d(
423 scoped_ptr<WebKit::WebGraphicsContext3D>(
424 new TestWebGraphicsContext3DMakeCurrentFails))
425 .PassAs<OutputSurface>());
426 host_impl_->SetViewportSize(gfx::Size(10, 10));
428 SetupScrollAndContentsLayers(gfx::Size(100, 100));
430 // We should not crash when trying to scroll after the renderer initialization
431 // fails.
432 EXPECT_EQ(InputHandlerClient::ScrollIgnored,
433 host_impl_->ScrollBegin(gfx::Point(), InputHandlerClient::Wheel));
436 TEST_F(LayerTreeHostImplTest, ReplaceTreeWhileScrolling) {
437 int scroll_layer_id = 1;
439 SetupScrollAndContentsLayers(gfx::Size(100, 100));
440 host_impl_->SetViewportSize(gfx::Size(50, 50));
441 InitializeRendererAndDrawFrame();
443 // We should not crash if the tree is replaced while we are scrolling.
444 EXPECT_EQ(InputHandlerClient::ScrollStarted,
445 host_impl_->ScrollBegin(gfx::Point(), InputHandlerClient::Wheel));
446 host_impl_->active_tree()->DetachLayerTree();
448 SetupScrollAndContentsLayers(gfx::Size(100, 100));
450 // We should still be scrolling, because the scrolled layer also exists in the
451 // new tree.
452 gfx::Vector2d scroll_delta(0, 10);
453 host_impl_->ScrollBy(gfx::Point(), scroll_delta);
454 host_impl_->ScrollEnd();
455 scoped_ptr<ScrollAndScaleSet> scroll_info = host_impl_->ProcessScrollDeltas();
456 ExpectContains(*scroll_info, scroll_layer_id, scroll_delta);
459 TEST_F(LayerTreeHostImplTest, ClearRootRenderSurfaceAndScroll) {
460 SetupScrollAndContentsLayers(gfx::Size(100, 100));
461 host_impl_->SetViewportSize(gfx::Size(50, 50));
462 InitializeRendererAndDrawFrame();
464 // We should be able to scroll even if the root layer loses its render surface
465 // after the most recent render.
466 host_impl_->active_tree()->root_layer()->ClearRenderSurface();
467 host_impl_->active_tree()->set_needs_update_draw_properties();
469 EXPECT_EQ(InputHandlerClient::ScrollStarted,
470 host_impl_->ScrollBegin(gfx::Point(), InputHandlerClient::Wheel));
473 TEST_F(LayerTreeHostImplTest, WheelEventHandlers) {
474 SetupScrollAndContentsLayers(gfx::Size(100, 100));
475 host_impl_->SetViewportSize(gfx::Size(50, 50));
476 InitializeRendererAndDrawFrame();
477 LayerImpl* root = host_impl_->active_tree()->root_layer();
479 root->SetHaveWheelEventHandlers(true);
481 // With registered event handlers, wheel scrolls have to go to the main
482 // thread.
483 EXPECT_EQ(InputHandlerClient::ScrollOnMainThread,
484 host_impl_->ScrollBegin(gfx::Point(), InputHandlerClient::Wheel));
486 // But gesture scrolls can still be handled.
487 EXPECT_EQ(InputHandlerClient::ScrollStarted,
488 host_impl_->ScrollBegin(gfx::Point(), InputHandlerClient::Gesture));
491 TEST_F(LayerTreeHostImplTest, ShouldScrollOnMainThread) {
492 SetupScrollAndContentsLayers(gfx::Size(100, 100));
493 host_impl_->SetViewportSize(gfx::Size(50, 50));
494 InitializeRendererAndDrawFrame();
495 LayerImpl* root = host_impl_->active_tree()->root_layer();
497 root->SetShouldScrollOnMainThread(true);
499 EXPECT_EQ(InputHandlerClient::ScrollOnMainThread,
500 host_impl_->ScrollBegin(gfx::Point(), InputHandlerClient::Wheel));
501 EXPECT_EQ(InputHandlerClient::ScrollOnMainThread,
502 host_impl_->ScrollBegin(gfx::Point(), InputHandlerClient::Gesture));
505 TEST_F(LayerTreeHostImplTest, NonFastScrollableRegionBasic) {
506 SetupScrollAndContentsLayers(gfx::Size(200, 200));
507 host_impl_->SetViewportSize(gfx::Size(100, 100));
509 LayerImpl* root = host_impl_->active_tree()->root_layer();
510 root->SetContentsScale(2.f, 2.f);
511 root->SetNonFastScrollableRegion(gfx::Rect(0, 0, 50, 50));
513 InitializeRendererAndDrawFrame();
515 // All scroll types inside the non-fast scrollable region should fail.
516 EXPECT_EQ(InputHandlerClient::ScrollOnMainThread,
517 host_impl_->ScrollBegin(gfx::Point(25, 25),
518 InputHandlerClient::Wheel));
519 EXPECT_EQ(InputHandlerClient::ScrollOnMainThread,
520 host_impl_->ScrollBegin(gfx::Point(25, 25),
521 InputHandlerClient::Gesture));
523 // All scroll types outside this region should succeed.
524 EXPECT_EQ(InputHandlerClient::ScrollStarted,
525 host_impl_->ScrollBegin(gfx::Point(75, 75),
526 InputHandlerClient::Wheel));
527 host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, 10));
528 host_impl_->ScrollEnd();
529 EXPECT_EQ(InputHandlerClient::ScrollStarted,
530 host_impl_->ScrollBegin(gfx::Point(75, 75),
531 InputHandlerClient::Gesture));
532 host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, 10));
533 host_impl_->ScrollEnd();
536 TEST_F(LayerTreeHostImplTest, NonFastScrollableRegionWithOffset) {
537 SetupScrollAndContentsLayers(gfx::Size(200, 200));
538 host_impl_->SetViewportSize(gfx::Size(100, 100));
540 LayerImpl* root = host_impl_->active_tree()->root_layer();
541 root->SetContentsScale(2.f, 2.f);
542 root->SetNonFastScrollableRegion(gfx::Rect(0, 0, 50, 50));
543 root->SetPosition(gfx::PointF(-25.f, 0.f));
545 InitializeRendererAndDrawFrame();
547 // This point would fall into the non-fast scrollable region except that we've
548 // moved the layer down by 25 pixels.
549 EXPECT_EQ(InputHandlerClient::ScrollStarted,
550 host_impl_->ScrollBegin(gfx::Point(40, 10),
551 InputHandlerClient::Wheel));
552 host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, 1));
553 host_impl_->ScrollEnd();
555 // This point is still inside the non-fast region.
556 EXPECT_EQ(InputHandlerClient::ScrollOnMainThread,
557 host_impl_->ScrollBegin(gfx::Point(10, 10),
558 InputHandlerClient::Wheel));
561 TEST_F(LayerTreeHostImplTest, ScrollByReturnsCorrectValue) {
562 SetupScrollAndContentsLayers(gfx::Size(200, 200));
563 host_impl_->SetViewportSize(gfx::Size(100, 100));
565 InitializeRendererAndDrawFrame();
567 EXPECT_EQ(InputHandlerClient::ScrollStarted,
568 host_impl_->ScrollBegin(gfx::Point(), InputHandlerClient::Gesture));
570 // Trying to scroll to the left/top will not succeed.
571 EXPECT_FALSE(host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(-10, 0)));
572 EXPECT_FALSE(host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, -10)));
573 EXPECT_FALSE(host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(-10, -10)));
575 // Scrolling to the right/bottom will succeed.
576 EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(10, 0)));
577 EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, 10)));
578 EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(10, 10)));
580 // Scrolling to left/top will now succeed.
581 EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(-10, 0)));
582 EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, -10)));
583 EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(-10, -10)));
585 // Scrolling diagonally against an edge will succeed.
586 EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(10, -10)));
587 EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(-10, 0)));
588 EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(-10, 10)));
590 // Trying to scroll more than the available space will also succeed.
591 EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(5000, 5000)));
594 TEST_F(LayerTreeHostImplTest, ScrollVerticallyByPageReturnsCorrectValue) {
595 SetupScrollAndContentsLayers(gfx::Size(200, 2000));
596 host_impl_->SetViewportSize(gfx::Size(100, 1000));
598 InitializeRendererAndDrawFrame();
600 EXPECT_EQ(InputHandlerClient::ScrollStarted,
601 host_impl_->ScrollBegin(gfx::Point(),
602 InputHandlerClient::Wheel));
604 // Trying to scroll without a vertical scrollbar will fail.
605 EXPECT_FALSE(host_impl_->ScrollVerticallyByPage(
606 gfx::Point(), WebKit::WebScrollbar::ScrollForward));
607 EXPECT_FALSE(host_impl_->ScrollVerticallyByPage(
608 gfx::Point(), WebKit::WebScrollbar::ScrollBackward));
610 scoped_ptr<cc::ScrollbarLayerImpl> vertical_scrollbar(
611 cc::ScrollbarLayerImpl::Create(
612 host_impl_->active_tree(),
614 scoped_ptr<ScrollbarGeometryFixedThumb>()));
615 vertical_scrollbar->SetBounds(gfx::Size(15, 1000));
616 host_impl_->RootScrollLayer()->SetVerticalScrollbarLayer(
617 vertical_scrollbar.get());
619 // Trying to scroll with a vertical scrollbar will succeed.
620 EXPECT_TRUE(host_impl_->ScrollVerticallyByPage(
621 gfx::Point(), WebKit::WebScrollbar::ScrollForward));
622 EXPECT_FLOAT_EQ(875.f, host_impl_->RootScrollLayer()->scroll_delta().y());
623 EXPECT_TRUE(host_impl_->ScrollVerticallyByPage(
624 gfx::Point(), WebKit::WebScrollbar::ScrollBackward));
627 TEST_F(LayerTreeHostImplTest,
628 ClearRootRenderSurfaceAndHitTestTouchHandlerRegion) {
629 SetupScrollAndContentsLayers(gfx::Size(100, 100));
630 host_impl_->SetViewportSize(gfx::Size(50, 50));
631 InitializeRendererAndDrawFrame();
633 // We should be able to hit test for touch event handlers even if the root
634 // layer loses its render surface after the most recent render.
635 host_impl_->active_tree()->root_layer()->ClearRenderSurface();
636 host_impl_->active_tree()->set_needs_update_draw_properties();
638 EXPECT_EQ(host_impl_->HaveTouchEventHandlersAt(gfx::Point()), false);
641 TEST_F(LayerTreeHostImplTest, ImplPinchZoom) {
642 SetupScrollAndContentsLayers(gfx::Size(100, 100));
643 host_impl_->SetViewportSize(gfx::Size(50, 50));
644 InitializeRendererAndDrawFrame();
646 LayerImpl* scroll_layer = host_impl_->RootScrollLayer();
647 DCHECK(scroll_layer);
649 float min_page_scale = 1.f, max_page_scale = 4.f;
650 gfx::Transform identity_scale_transform;
652 // The impl-based pinch zoom should adjust the max scroll position.
654 host_impl_->active_tree()->SetPageScaleFactorAndLimits(1.f,
655 min_page_scale,
656 max_page_scale);
657 host_impl_->active_tree()->SetPageScaleDelta(1.f);
658 scroll_layer->SetImplTransform(identity_scale_transform);
659 scroll_layer->SetScrollDelta(gfx::Vector2d());
661 float page_scale_delta = 2.f;
662 host_impl_->PinchGestureBegin();
663 host_impl_->PinchGestureUpdate(page_scale_delta, gfx::Point(50, 50));
664 host_impl_->PinchGestureEnd();
665 EXPECT_TRUE(did_request_redraw_);
666 EXPECT_TRUE(did_request_commit_);
668 scoped_ptr<ScrollAndScaleSet> scroll_info =
669 host_impl_->ProcessScrollDeltas();
670 EXPECT_EQ(scroll_info->page_scale_delta, page_scale_delta);
672 EXPECT_EQ(gfx::Vector2d(75, 75),
673 host_impl_->active_tree()->root_layer()->max_scroll_offset());
676 // Scrolling after a pinch gesture should always be in local space. The
677 // scroll deltas do not have the page scale factor applied.
679 host_impl_->active_tree()->SetPageScaleFactorAndLimits(1.f,
680 min_page_scale,
681 max_page_scale);
682 host_impl_->active_tree()->SetPageScaleDelta(1.f);
683 scroll_layer->SetImplTransform(identity_scale_transform);
684 scroll_layer->SetScrollDelta(gfx::Vector2d());
686 float page_scale_delta = 2.f;
687 host_impl_->PinchGestureBegin();
688 host_impl_->PinchGestureUpdate(page_scale_delta, gfx::Point());
689 host_impl_->PinchGestureEnd();
691 gfx::Vector2d scroll_delta(0, 10);
692 EXPECT_EQ(InputHandlerClient::ScrollStarted,
693 host_impl_->ScrollBegin(gfx::Point(5, 5),
694 InputHandlerClient::Wheel));
695 host_impl_->ScrollBy(gfx::Point(), scroll_delta);
696 host_impl_->ScrollEnd();
698 scoped_ptr<ScrollAndScaleSet> scroll_info =
699 host_impl_->ProcessScrollDeltas();
700 ExpectContains(*scroll_info.get(),
701 host_impl_->active_tree()->root_layer()->id(),
702 scroll_delta);
706 TEST_F(LayerTreeHostImplTest, PinchGesture) {
707 SetupScrollAndContentsLayers(gfx::Size(100, 100));
708 host_impl_->SetViewportSize(gfx::Size(50, 50));
709 InitializeRendererAndDrawFrame();
711 LayerImpl* scroll_layer = host_impl_->RootScrollLayer();
712 DCHECK(scroll_layer);
714 float min_page_scale = 1.f;
715 float max_page_scale = 4.f;
716 gfx::Transform identity_scale_transform;
718 // Basic pinch zoom in gesture
720 host_impl_->active_tree()->SetPageScaleFactorAndLimits(1.f,
721 min_page_scale,
722 max_page_scale);
723 scroll_layer->SetImplTransform(identity_scale_transform);
724 scroll_layer->SetScrollDelta(gfx::Vector2d());
726 float page_scale_delta = 2.f;
727 host_impl_->PinchGestureBegin();
728 host_impl_->PinchGestureUpdate(page_scale_delta, gfx::Point(50, 50));
729 host_impl_->PinchGestureEnd();
730 EXPECT_TRUE(did_request_redraw_);
731 EXPECT_TRUE(did_request_commit_);
733 scoped_ptr<ScrollAndScaleSet> scroll_info =
734 host_impl_->ProcessScrollDeltas();
735 EXPECT_EQ(scroll_info->page_scale_delta, page_scale_delta);
738 // Zoom-in clamping
740 host_impl_->active_tree()->SetPageScaleFactorAndLimits(1.f,
741 min_page_scale,
742 max_page_scale);
743 scroll_layer->SetImplTransform(identity_scale_transform);
744 scroll_layer->SetScrollDelta(gfx::Vector2d());
745 float page_scale_delta = 10.f;
747 host_impl_->PinchGestureBegin();
748 host_impl_->PinchGestureUpdate(page_scale_delta, gfx::Point(50, 50));
749 host_impl_->PinchGestureEnd();
751 scoped_ptr<ScrollAndScaleSet> scroll_info =
752 host_impl_->ProcessScrollDeltas();
753 EXPECT_EQ(scroll_info->page_scale_delta, max_page_scale);
756 // Zoom-out clamping
758 host_impl_->active_tree()->SetPageScaleFactorAndLimits(1.f,
759 min_page_scale,
760 max_page_scale);
761 scroll_layer->SetImplTransform(identity_scale_transform);
762 scroll_layer->SetScrollDelta(gfx::Vector2d());
763 scroll_layer->SetScrollOffset(gfx::Vector2d(50, 50));
765 float page_scale_delta = 0.1f;
766 host_impl_->PinchGestureBegin();
767 host_impl_->PinchGestureUpdate(page_scale_delta, gfx::Point());
768 host_impl_->PinchGestureEnd();
770 scoped_ptr<ScrollAndScaleSet> scroll_info =
771 host_impl_->ProcessScrollDeltas();
772 EXPECT_EQ(scroll_info->page_scale_delta, min_page_scale);
774 EXPECT_TRUE(scroll_info->scrolls.empty());
777 // Two-finger panning should not happen based on pinch events only
779 host_impl_->active_tree()->SetPageScaleFactorAndLimits(1.f,
780 min_page_scale,
781 max_page_scale);
782 scroll_layer->SetImplTransform(identity_scale_transform);
783 scroll_layer->SetScrollDelta(gfx::Vector2d());
784 scroll_layer->SetScrollOffset(gfx::Vector2d(20, 20));
786 float page_scale_delta = 1.f;
787 host_impl_->PinchGestureBegin();
788 host_impl_->PinchGestureUpdate(page_scale_delta, gfx::Point(10, 10));
789 host_impl_->PinchGestureUpdate(page_scale_delta, gfx::Point(20, 20));
790 host_impl_->PinchGestureEnd();
792 scoped_ptr<ScrollAndScaleSet> scroll_info =
793 host_impl_->ProcessScrollDeltas();
794 EXPECT_EQ(scroll_info->page_scale_delta, page_scale_delta);
795 EXPECT_TRUE(scroll_info->scrolls.empty());
798 // Two-finger panning should work with interleaved scroll events
800 host_impl_->active_tree()->SetPageScaleFactorAndLimits(1.f,
801 min_page_scale,
802 max_page_scale);
803 scroll_layer->SetImplTransform(identity_scale_transform);
804 scroll_layer->SetScrollDelta(gfx::Vector2d());
805 scroll_layer->SetScrollOffset(gfx::Vector2d(20, 20));
807 float page_scale_delta = 1.f;
808 host_impl_->ScrollBegin(gfx::Point(10, 10), InputHandlerClient::Wheel);
809 host_impl_->PinchGestureBegin();
810 host_impl_->PinchGestureUpdate(page_scale_delta, gfx::Point(10, 10));
811 host_impl_->ScrollBy(gfx::Point(10, 10), gfx::Vector2d(-10, -10));
812 host_impl_->PinchGestureUpdate(page_scale_delta, gfx::Point(20, 20));
813 host_impl_->PinchGestureEnd();
814 host_impl_->ScrollEnd();
816 scoped_ptr<ScrollAndScaleSet> scroll_info =
817 host_impl_->ProcessScrollDeltas();
818 EXPECT_EQ(scroll_info->page_scale_delta, page_scale_delta);
819 ExpectContains(*scroll_info, scroll_layer->id(), gfx::Vector2d(-10, -10));
823 TEST_F(LayerTreeHostImplTest, PageScaleAnimation) {
824 SetupScrollAndContentsLayers(gfx::Size(100, 100));
825 host_impl_->SetViewportSize(gfx::Size(50, 50));
826 InitializeRendererAndDrawFrame();
828 LayerImpl* scroll_layer = host_impl_->RootScrollLayer();
829 DCHECK(scroll_layer);
831 float min_page_scale = 0.5f;
832 float max_page_scale = 4.f;
833 base::TimeTicks start_time = base::TimeTicks() +
834 base::TimeDelta::FromSeconds(1);
835 base::TimeDelta duration = base::TimeDelta::FromMilliseconds(100);
836 base::TimeTicks halfway_through_animation = start_time + duration / 2;
837 base::TimeTicks end_time = start_time + duration;
838 gfx::Transform identity_scale_transform;
840 // Non-anchor zoom-in
842 host_impl_->active_tree()->SetPageScaleFactorAndLimits(1.f,
843 min_page_scale,
844 max_page_scale);
845 scroll_layer->SetImplTransform(identity_scale_transform);
846 scroll_layer->SetScrollOffset(gfx::Vector2d(50, 50));
848 host_impl_->StartPageScaleAnimation(gfx::Vector2d(),
849 false,
850 2.f,
851 start_time,
852 duration);
853 host_impl_->Animate(halfway_through_animation, base::Time());
854 EXPECT_TRUE(did_request_redraw_);
855 host_impl_->Animate(end_time, base::Time());
856 EXPECT_TRUE(did_request_commit_);
858 scoped_ptr<ScrollAndScaleSet> scroll_info =
859 host_impl_->ProcessScrollDeltas();
860 EXPECT_EQ(scroll_info->page_scale_delta, 2);
861 ExpectContains(*scroll_info, scroll_layer->id(), gfx::Vector2d(-50, -50));
864 // Anchor zoom-out
866 host_impl_->active_tree()->SetPageScaleFactorAndLimits(1.f,
867 min_page_scale,
868 max_page_scale);
869 scroll_layer->SetImplTransform(identity_scale_transform);
870 scroll_layer->SetScrollOffset(gfx::Vector2d(50, 50));
872 host_impl_->StartPageScaleAnimation(gfx::Vector2d(25, 25),
873 true,
874 min_page_scale,
875 start_time, duration);
876 host_impl_->Animate(end_time, base::Time());
877 EXPECT_TRUE(did_request_redraw_);
878 EXPECT_TRUE(did_request_commit_);
880 scoped_ptr<ScrollAndScaleSet> scroll_info =
881 host_impl_->ProcessScrollDeltas();
882 EXPECT_EQ(scroll_info->page_scale_delta, min_page_scale);
883 // Pushed to (0,0) via clamping against contents layer size.
884 ExpectContains(*scroll_info, scroll_layer->id(), gfx::Vector2d(-50, -50));
888 TEST_F(LayerTreeHostImplTest, PageScaleAnimationNoOp) {
889 SetupScrollAndContentsLayers(gfx::Size(100, 100));
890 host_impl_->SetViewportSize(gfx::Size(50, 50));
891 InitializeRendererAndDrawFrame();
893 LayerImpl* scroll_layer = host_impl_->RootScrollLayer();
894 DCHECK(scroll_layer);
896 float min_page_scale = 0.5f;
897 float max_page_scale = 4.f;
898 base::TimeTicks start_time = base::TimeTicks() +
899 base::TimeDelta::FromSeconds(1);
900 base::TimeDelta duration = base::TimeDelta::FromMilliseconds(100);
901 base::TimeTicks halfway_through_animation = start_time + duration / 2;
902 base::TimeTicks end_time = start_time + duration;
903 gfx::Transform identity_scale_transform;
905 // Anchor zoom with unchanged page scale should not change scroll or scale.
907 host_impl_->active_tree()->SetPageScaleFactorAndLimits(1.f,
908 min_page_scale,
909 max_page_scale);
910 scroll_layer->SetImplTransform(identity_scale_transform);
911 scroll_layer->SetScrollOffset(gfx::Vector2d(50, 50));
913 host_impl_->StartPageScaleAnimation(gfx::Vector2d(),
914 true,
915 1.f,
916 start_time,
917 duration);
918 host_impl_->Animate(halfway_through_animation, base::Time());
919 EXPECT_TRUE(did_request_redraw_);
920 host_impl_->Animate(end_time, base::Time());
921 EXPECT_TRUE(did_request_commit_);
923 scoped_ptr<ScrollAndScaleSet> scroll_info =
924 host_impl_->ProcessScrollDeltas();
925 EXPECT_EQ(scroll_info->page_scale_delta, 1);
926 ExpectNone(*scroll_info, scroll_layer->id());
930 TEST_F(LayerTreeHostImplTest, CompositorFrameMetadata) {
931 SetupScrollAndContentsLayers(gfx::Size(100, 100));
932 host_impl_->SetViewportSize(gfx::Size(50, 50));
933 host_impl_->active_tree()->SetPageScaleFactorAndLimits(1.f, 0.5f, 4.f);
934 InitializeRendererAndDrawFrame();
936 CompositorFrameMetadata metadata =
937 host_impl_->MakeCompositorFrameMetadata();
938 EXPECT_EQ(gfx::Vector2dF(), metadata.root_scroll_offset);
939 EXPECT_EQ(1.f, metadata.page_scale_factor);
940 EXPECT_EQ(gfx::SizeF(50.f, 50.f), metadata.viewport_size);
941 EXPECT_EQ(gfx::SizeF(100.f, 100.f), metadata.root_layer_size);
942 EXPECT_EQ(0.5f, metadata.min_page_scale_factor);
943 EXPECT_EQ(4.f, metadata.max_page_scale_factor);
946 // Scrolling should update metadata immediately.
947 EXPECT_EQ(InputHandlerClient::ScrollStarted,
948 host_impl_->ScrollBegin(gfx::Point(), InputHandlerClient::Wheel));
949 host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, 10));
951 CompositorFrameMetadata metadata =
952 host_impl_->MakeCompositorFrameMetadata();
953 EXPECT_EQ(gfx::Vector2dF(0.f, 10.f), metadata.root_scroll_offset);
955 host_impl_->ScrollEnd();
957 CompositorFrameMetadata metadata =
958 host_impl_->MakeCompositorFrameMetadata();
959 EXPECT_EQ(gfx::Vector2dF(0.f, 10.f), metadata.root_scroll_offset);
962 // Page scale should update metadata correctly (shrinking only the viewport).
963 host_impl_->PinchGestureBegin();
964 host_impl_->PinchGestureUpdate(2.f, gfx::Point());
965 host_impl_->PinchGestureEnd();
967 CompositorFrameMetadata metadata =
968 host_impl_->MakeCompositorFrameMetadata();
969 EXPECT_EQ(gfx::Vector2dF(0.f, 10.f), metadata.root_scroll_offset);
970 EXPECT_EQ(2.f, metadata.page_scale_factor);
971 EXPECT_EQ(gfx::SizeF(25.f, 25.f), metadata.viewport_size);
972 EXPECT_EQ(gfx::SizeF(100.f, 100.f), metadata.root_layer_size);
973 EXPECT_EQ(0.5f, metadata.min_page_scale_factor);
974 EXPECT_EQ(4.f, metadata.max_page_scale_factor);
977 // Likewise if set from the main thread.
978 host_impl_->ProcessScrollDeltas();
979 host_impl_->active_tree()->SetPageScaleFactorAndLimits(4.f, 0.5f, 4.f);
980 host_impl_->active_tree()->SetPageScaleDelta(1.f);
982 CompositorFrameMetadata metadata =
983 host_impl_->MakeCompositorFrameMetadata();
984 EXPECT_EQ(gfx::Vector2dF(0.f, 10.f), metadata.root_scroll_offset);
985 EXPECT_EQ(4.f, metadata.page_scale_factor);
986 EXPECT_EQ(gfx::SizeF(12.5f, 12.5f), metadata.viewport_size);
987 EXPECT_EQ(gfx::SizeF(100.f, 100.f), metadata.root_layer_size);
988 EXPECT_EQ(0.5f, metadata.min_page_scale_factor);
989 EXPECT_EQ(4.f, metadata.max_page_scale_factor);
993 class DidDrawCheckLayer : public TiledLayerImpl {
994 public:
995 static scoped_ptr<LayerImpl> Create(LayerTreeImpl* tree_impl, int id) {
996 return scoped_ptr<LayerImpl>(new DidDrawCheckLayer(tree_impl, id));
999 virtual void DidDraw(ResourceProvider* provider) OVERRIDE {
1000 did_draw_called_ = true;
1003 virtual void WillDraw(ResourceProvider* provider) OVERRIDE {
1004 will_draw_called_ = true;
1007 bool did_draw_called() const { return did_draw_called_; }
1008 bool will_draw_called() const { return will_draw_called_; }
1010 void ClearDidDrawCheck() {
1011 did_draw_called_ = false;
1012 will_draw_called_ = false;
1015 protected:
1016 DidDrawCheckLayer(LayerTreeImpl* tree_impl, int id)
1017 : TiledLayerImpl(tree_impl, id),
1018 did_draw_called_(false),
1019 will_draw_called_(false) {
1020 SetAnchorPoint(gfx::PointF());
1021 SetBounds(gfx::Size(10, 10));
1022 SetContentBounds(gfx::Size(10, 10));
1023 SetDrawsContent(true);
1024 set_skips_draw(false);
1025 draw_properties().visible_content_rect = gfx::Rect(0, 0, 10, 10);
1027 scoped_ptr<LayerTilingData> tiler =
1028 LayerTilingData::Create(gfx::Size(100, 100),
1029 LayerTilingData::HAS_BORDER_TEXELS);
1030 tiler->SetBounds(content_bounds());
1031 SetTilingData(*tiler.get());
1034 private:
1035 bool did_draw_called_;
1036 bool will_draw_called_;
1039 TEST_F(LayerTreeHostImplTest, DidDrawNotCalledOnHiddenLayer) {
1040 // The root layer is always drawn, so run this test on a child layer that
1041 // will be masked out by the root layer's bounds.
1042 host_impl_->active_tree()->SetRootLayer(
1043 DidDrawCheckLayer::Create(host_impl_->active_tree(), 1));
1044 DidDrawCheckLayer* root = static_cast<DidDrawCheckLayer*>(
1045 host_impl_->active_tree()->root_layer());
1046 root->SetMasksToBounds(true);
1048 root->AddChild(DidDrawCheckLayer::Create(host_impl_->active_tree(), 2));
1049 DidDrawCheckLayer* layer =
1050 static_cast<DidDrawCheckLayer*>(root->children()[0]);
1051 // Ensure visible_content_rect for layer is empty.
1052 layer->SetPosition(gfx::PointF(100.f, 100.f));
1053 layer->SetBounds(gfx::Size(10, 10));
1054 layer->SetContentBounds(gfx::Size(10, 10));
1056 LayerTreeHostImpl::FrameData frame;
1058 EXPECT_FALSE(layer->will_draw_called());
1059 EXPECT_FALSE(layer->did_draw_called());
1061 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
1062 host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
1063 host_impl_->DidDrawAllLayers(frame);
1065 EXPECT_FALSE(layer->will_draw_called());
1066 EXPECT_FALSE(layer->did_draw_called());
1068 EXPECT_TRUE(layer->visible_content_rect().IsEmpty());
1070 // Ensure visible_content_rect for layer is not empty
1071 layer->SetPosition(gfx::PointF());
1073 EXPECT_FALSE(layer->will_draw_called());
1074 EXPECT_FALSE(layer->did_draw_called());
1076 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
1077 host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
1078 host_impl_->DidDrawAllLayers(frame);
1080 EXPECT_TRUE(layer->will_draw_called());
1081 EXPECT_TRUE(layer->did_draw_called());
1083 EXPECT_FALSE(layer->visible_content_rect().IsEmpty());
1086 TEST_F(LayerTreeHostImplTest, WillDrawNotCalledOnOccludedLayer) {
1087 gfx::Size big_size(1000, 1000);
1088 host_impl_->SetViewportSize(big_size);
1090 host_impl_->active_tree()->SetRootLayer(
1091 DidDrawCheckLayer::Create(host_impl_->active_tree(), 1));
1092 DidDrawCheckLayer* root =
1093 static_cast<DidDrawCheckLayer*>(host_impl_->active_tree()->root_layer());
1095 root->AddChild(DidDrawCheckLayer::Create(host_impl_->active_tree(), 2));
1096 DidDrawCheckLayer* occluded_layer =
1097 static_cast<DidDrawCheckLayer*>(root->children()[0]);
1099 root->AddChild(DidDrawCheckLayer::Create(host_impl_->active_tree(), 3));
1100 DidDrawCheckLayer* top_layer =
1101 static_cast<DidDrawCheckLayer*>(root->children()[1]);
1102 // This layer covers the occluded_layer above. Make this layer large so it can
1103 // occlude.
1104 top_layer->SetBounds(big_size);
1105 top_layer->SetContentBounds(big_size);
1106 top_layer->SetContentsOpaque(true);
1108 LayerTreeHostImpl::FrameData frame;
1110 EXPECT_FALSE(occluded_layer->will_draw_called());
1111 EXPECT_FALSE(occluded_layer->did_draw_called());
1112 EXPECT_FALSE(top_layer->will_draw_called());
1113 EXPECT_FALSE(top_layer->did_draw_called());
1115 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
1116 host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
1117 host_impl_->DidDrawAllLayers(frame);
1119 EXPECT_FALSE(occluded_layer->will_draw_called());
1120 EXPECT_FALSE(occluded_layer->did_draw_called());
1121 EXPECT_TRUE(top_layer->will_draw_called());
1122 EXPECT_TRUE(top_layer->did_draw_called());
1125 TEST_F(LayerTreeHostImplTest, DidDrawCalledOnAllLayers) {
1126 host_impl_->active_tree()->SetRootLayer(
1127 DidDrawCheckLayer::Create(host_impl_->active_tree(), 1));
1128 DidDrawCheckLayer* root =
1129 static_cast<DidDrawCheckLayer*>(host_impl_->active_tree()->root_layer());
1131 root->AddChild(DidDrawCheckLayer::Create(host_impl_->active_tree(), 2));
1132 DidDrawCheckLayer* layer1 =
1133 static_cast<DidDrawCheckLayer*>(root->children()[0]);
1135 layer1->AddChild(DidDrawCheckLayer::Create(host_impl_->active_tree(), 3));
1136 DidDrawCheckLayer* layer2 =
1137 static_cast<DidDrawCheckLayer*>(layer1->children()[0]);
1139 layer1->SetOpacity(0.3f);
1140 layer1->SetPreserves3d(false);
1142 EXPECT_FALSE(root->did_draw_called());
1143 EXPECT_FALSE(layer1->did_draw_called());
1144 EXPECT_FALSE(layer2->did_draw_called());
1146 LayerTreeHostImpl::FrameData frame;
1147 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
1148 host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
1149 host_impl_->DidDrawAllLayers(frame);
1151 EXPECT_TRUE(root->did_draw_called());
1152 EXPECT_TRUE(layer1->did_draw_called());
1153 EXPECT_TRUE(layer2->did_draw_called());
1155 EXPECT_NE(root->render_surface(), layer1->render_surface());
1156 EXPECT_TRUE(!!layer1->render_surface());
1159 class MissingTextureAnimatingLayer : public DidDrawCheckLayer {
1160 public:
1161 static scoped_ptr<LayerImpl> Create(LayerTreeImpl* tree_impl,
1162 int id,
1163 bool tile_missing,
1164 bool skips_draw,
1165 bool animating,
1166 ResourceProvider* resource_provider) {
1167 return scoped_ptr<LayerImpl>(new MissingTextureAnimatingLayer(
1168 tree_impl,
1170 tile_missing,
1171 skips_draw,
1172 animating,
1173 resource_provider));
1176 private:
1177 MissingTextureAnimatingLayer(LayerTreeImpl* tree_impl,
1178 int id,
1179 bool tile_missing,
1180 bool skips_draw,
1181 bool animating,
1182 ResourceProvider* resource_provider)
1183 : DidDrawCheckLayer(tree_impl, id) {
1184 scoped_ptr<LayerTilingData> tiling_data =
1185 LayerTilingData::Create(gfx::Size(10, 10),
1186 LayerTilingData::NO_BORDER_TEXELS);
1187 tiling_data->SetBounds(bounds());
1188 SetTilingData(*tiling_data.get());
1189 set_skips_draw(skips_draw);
1190 if (!tile_missing) {
1191 ResourceProvider::ResourceId resource =
1192 resource_provider->CreateResource(gfx::Size(),
1193 GL_RGBA,
1194 ResourceProvider::TextureUsageAny);
1195 resource_provider->AllocateForTesting(resource);
1196 PushTileProperties(0, 0, resource, gfx::Rect(), false);
1198 if (animating)
1199 AddAnimatedTransformToLayer(this, 10.0, 3, 0);
1203 TEST_F(LayerTreeHostImplTest, PrepareToDrawFailsWhenAnimationUsesCheckerboard) {
1204 // When the texture is not missing, we draw as usual.
1205 host_impl_->active_tree()->SetRootLayer(
1206 DidDrawCheckLayer::Create(host_impl_->active_tree(), 1));
1207 DidDrawCheckLayer* root =
1208 static_cast<DidDrawCheckLayer*>(host_impl_->active_tree()->root_layer());
1209 root->AddChild(
1210 MissingTextureAnimatingLayer::Create(host_impl_->active_tree(),
1212 false,
1213 false,
1214 true,
1215 host_impl_->resource_provider()));
1217 LayerTreeHostImpl::FrameData frame;
1219 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
1220 host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
1221 host_impl_->DidDrawAllLayers(frame);
1223 // When a texture is missing and we're not animating, we draw as usual with
1224 // checkerboarding.
1225 host_impl_->active_tree()->SetRootLayer(
1226 DidDrawCheckLayer::Create(host_impl_->active_tree(), 3));
1227 root =
1228 static_cast<DidDrawCheckLayer*>(host_impl_->active_tree()->root_layer());
1229 root->AddChild(
1230 MissingTextureAnimatingLayer::Create(host_impl_->active_tree(),
1232 true,
1233 false,
1234 false,
1235 host_impl_->resource_provider()));
1237 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
1238 host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
1239 host_impl_->DidDrawAllLayers(frame);
1241 // When a texture is missing and we're animating, we don't want to draw
1242 // anything.
1243 host_impl_->active_tree()->SetRootLayer(
1244 DidDrawCheckLayer::Create(host_impl_->active_tree(), 5));
1245 root =
1246 static_cast<DidDrawCheckLayer*>(host_impl_->active_tree()->root_layer());
1247 root->AddChild(
1248 MissingTextureAnimatingLayer::Create(host_impl_->active_tree(),
1250 true,
1251 false,
1252 true,
1253 host_impl_->resource_provider()));
1255 EXPECT_FALSE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
1256 host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
1257 host_impl_->DidDrawAllLayers(frame);
1259 // When the layer skips draw and we're animating, we still draw the frame.
1260 host_impl_->active_tree()->SetRootLayer(
1261 DidDrawCheckLayer::Create(host_impl_->active_tree(), 7));
1262 root =
1263 static_cast<DidDrawCheckLayer*>(host_impl_->active_tree()->root_layer());
1264 root->AddChild(
1265 MissingTextureAnimatingLayer::Create(host_impl_->active_tree(),
1267 false,
1268 true,
1269 true,
1270 host_impl_->resource_provider()));
1272 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
1273 host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
1274 host_impl_->DidDrawAllLayers(frame);
1277 TEST_F(LayerTreeHostImplTest, ScrollRootIgnored) {
1278 scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl_->active_tree(), 1);
1279 root->SetScrollable(false);
1280 host_impl_->active_tree()->SetRootLayer(root.Pass());
1281 InitializeRendererAndDrawFrame();
1283 // Scroll event is ignored because layer is not scrollable.
1284 EXPECT_EQ(InputHandlerClient::ScrollIgnored,
1285 host_impl_->ScrollBegin(gfx::Point(), InputHandlerClient::Wheel));
1286 EXPECT_FALSE(did_request_redraw_);
1287 EXPECT_FALSE(did_request_commit_);
1290 TEST_F(LayerTreeHostImplTest, ScrollNonScrollableRootWithTopControls) {
1291 LayerTreeSettings settings;
1292 settings.calculate_top_controls_position = true;
1293 settings.top_controls_height = 50;
1295 host_impl_ = LayerTreeHostImpl::Create(settings,
1296 this,
1297 &proxy_,
1298 &stats_instrumentation_);
1299 host_impl_->InitializeRenderer(CreateOutputSurface());
1300 host_impl_->SetViewportSize(gfx::Size(10, 10));
1302 gfx::Size layer_size(5, 5);
1303 scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl_->active_tree(), 1);
1304 root->SetScrollable(true);
1305 root->SetMaxScrollOffset(gfx::Vector2d(layer_size.width(),
1306 layer_size.height()));
1307 root->SetBounds(layer_size);
1308 root->SetContentBounds(layer_size);
1309 root->SetPosition(gfx::PointF());
1310 root->SetAnchorPoint(gfx::PointF());
1311 root->SetDrawsContent(false);
1312 host_impl_->active_tree()->SetRootLayer(root.Pass());
1313 host_impl_->active_tree()->FindRootScrollLayer();
1314 InitializeRendererAndDrawFrame();
1316 EXPECT_EQ(InputHandlerClient::ScrollIgnored,
1317 host_impl_->ScrollBegin(gfx::Point(), InputHandlerClient::Gesture));
1319 host_impl_->top_controls_manager()->ScrollBegin();
1320 host_impl_->top_controls_manager()->ScrollBy(gfx::Vector2dF(0.f, 50.f));
1321 host_impl_->top_controls_manager()->ScrollEnd();
1322 EXPECT_EQ(host_impl_->top_controls_manager()->content_top_offset(), 0.f);
1324 EXPECT_EQ(InputHandlerClient::ScrollStarted,
1325 host_impl_->ScrollBegin(gfx::Point(),
1326 InputHandlerClient::Gesture));
1329 TEST_F(LayerTreeHostImplTest, ScrollNonCompositedRoot) {
1330 // Test the configuration where a non-composited root layer is embedded in a
1331 // scrollable outer layer.
1332 gfx::Size surface_size(10, 10);
1334 scoped_ptr<LayerImpl> content_layer =
1335 LayerImpl::Create(host_impl_->active_tree(), 1);
1336 content_layer->SetDrawsContent(true);
1337 content_layer->SetPosition(gfx::PointF());
1338 content_layer->SetAnchorPoint(gfx::PointF());
1339 content_layer->SetBounds(surface_size);
1340 content_layer->SetContentBounds(gfx::Size(surface_size.width() * 2,
1341 surface_size.height() * 2));
1342 content_layer->SetContentsScale(2.f, 2.f);
1344 scoped_ptr<LayerImpl> scroll_layer =
1345 LayerImpl::Create(host_impl_->active_tree(), 2);
1346 scroll_layer->SetScrollable(true);
1347 scroll_layer->SetMaxScrollOffset(gfx::Vector2d(surface_size.width(),
1348 surface_size.height()));
1349 scroll_layer->SetBounds(surface_size);
1350 scroll_layer->SetContentBounds(surface_size);
1351 scroll_layer->SetPosition(gfx::PointF());
1352 scroll_layer->SetAnchorPoint(gfx::PointF());
1353 scroll_layer->AddChild(content_layer.Pass());
1355 host_impl_->active_tree()->SetRootLayer(scroll_layer.Pass());
1356 host_impl_->SetViewportSize(surface_size);
1357 InitializeRendererAndDrawFrame();
1359 EXPECT_EQ(InputHandlerClient::ScrollStarted,
1360 host_impl_->ScrollBegin(gfx::Point(5, 5),
1361 InputHandlerClient::Wheel));
1362 host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, 10));
1363 host_impl_->ScrollEnd();
1364 EXPECT_TRUE(did_request_redraw_);
1365 EXPECT_TRUE(did_request_commit_);
1368 TEST_F(LayerTreeHostImplTest, ScrollChildCallsCommitAndRedraw) {
1369 gfx::Size surface_size(10, 10);
1370 scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl_->active_tree(), 1);
1371 root->SetBounds(surface_size);
1372 root->SetContentBounds(surface_size);
1373 root->AddChild(CreateScrollableLayer(2, surface_size));
1374 host_impl_->active_tree()->SetRootLayer(root.Pass());
1375 host_impl_->SetViewportSize(surface_size);
1376 InitializeRendererAndDrawFrame();
1378 EXPECT_EQ(InputHandlerClient::ScrollStarted,
1379 host_impl_->ScrollBegin(gfx::Point(5, 5),
1380 InputHandlerClient::Wheel));
1381 host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, 10));
1382 host_impl_->ScrollEnd();
1383 EXPECT_TRUE(did_request_redraw_);
1384 EXPECT_TRUE(did_request_commit_);
1387 TEST_F(LayerTreeHostImplTest, ScrollMissesChild) {
1388 gfx::Size surface_size(10, 10);
1389 scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl_->active_tree(), 1);
1390 root->AddChild(CreateScrollableLayer(2, surface_size));
1391 host_impl_->active_tree()->SetRootLayer(root.Pass());
1392 host_impl_->SetViewportSize(surface_size);
1393 InitializeRendererAndDrawFrame();
1395 // Scroll event is ignored because the input coordinate is outside the layer
1396 // boundaries.
1397 EXPECT_EQ(InputHandlerClient::ScrollIgnored,
1398 host_impl_->ScrollBegin(gfx::Point(15, 5),
1399 InputHandlerClient::Wheel));
1400 EXPECT_FALSE(did_request_redraw_);
1401 EXPECT_FALSE(did_request_commit_);
1404 TEST_F(LayerTreeHostImplTest, ScrollMissesBackfacingChild) {
1405 gfx::Size surface_size(10, 10);
1406 scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl_->active_tree(), 1);
1407 scoped_ptr<LayerImpl> child = CreateScrollableLayer(2, surface_size);
1408 host_impl_->SetViewportSize(surface_size);
1410 gfx::Transform matrix;
1411 matrix.RotateAboutXAxis(180.0);
1412 child->SetTransform(matrix);
1413 child->SetDoubleSided(false);
1415 root->AddChild(child.Pass());
1416 host_impl_->active_tree()->SetRootLayer(root.Pass());
1417 InitializeRendererAndDrawFrame();
1419 // Scroll event is ignored because the scrollable layer is not facing the
1420 // viewer and there is nothing scrollable behind it.
1421 EXPECT_EQ(InputHandlerClient::ScrollIgnored,
1422 host_impl_->ScrollBegin(gfx::Point(5, 5),
1423 InputHandlerClient::Wheel));
1424 EXPECT_FALSE(did_request_redraw_);
1425 EXPECT_FALSE(did_request_commit_);
1428 TEST_F(LayerTreeHostImplTest, ScrollBlockedByContentLayer) {
1429 gfx::Size surface_size(10, 10);
1430 scoped_ptr<LayerImpl> content_layer = CreateScrollableLayer(1, surface_size);
1431 content_layer->SetShouldScrollOnMainThread(true);
1432 content_layer->SetScrollable(false);
1434 scoped_ptr<LayerImpl> scroll_layer = CreateScrollableLayer(2, surface_size);
1435 scroll_layer->AddChild(content_layer.Pass());
1437 host_impl_->active_tree()->SetRootLayer(scroll_layer.Pass());
1438 host_impl_->SetViewportSize(surface_size);
1439 InitializeRendererAndDrawFrame();
1441 // Scrolling fails because the content layer is asking to be scrolled on the
1442 // main thread.
1443 EXPECT_EQ(InputHandlerClient::ScrollOnMainThread,
1444 host_impl_->ScrollBegin(gfx::Point(5, 5),
1445 InputHandlerClient::Wheel));
1448 TEST_F(LayerTreeHostImplTest, ScrollRootAndChangePageScaleOnMainThread) {
1449 gfx::Size surface_size(10, 10);
1450 float page_scale = 2.f;
1451 scoped_ptr<LayerImpl> root = CreateScrollableLayer(1, surface_size);
1452 host_impl_->active_tree()->SetRootLayer(root.Pass());
1453 host_impl_->active_tree()->DidBecomeActive();
1454 host_impl_->SetViewportSize(surface_size);
1455 InitializeRendererAndDrawFrame();
1457 gfx::Vector2d scroll_delta(0, 10);
1458 gfx::Vector2d expected_scroll_delta = scroll_delta;
1459 gfx::Vector2d expected_max_scroll =
1460 host_impl_->active_tree()->root_layer()->max_scroll_offset();
1461 EXPECT_EQ(InputHandlerClient::ScrollStarted,
1462 host_impl_->ScrollBegin(gfx::Point(5, 5),
1463 InputHandlerClient::Wheel));
1464 host_impl_->ScrollBy(gfx::Point(), scroll_delta);
1465 host_impl_->ScrollEnd();
1467 // Set new page scale from main thread.
1468 host_impl_->active_tree()->SetPageScaleFactorAndLimits(page_scale,
1469 page_scale,
1470 page_scale);
1472 scoped_ptr<ScrollAndScaleSet> scroll_info = host_impl_->ProcessScrollDeltas();
1473 ExpectContains(*scroll_info.get(),
1474 host_impl_->active_tree()->root_layer()->id(),
1475 expected_scroll_delta);
1477 // The scroll range should also have been updated.
1478 EXPECT_EQ(expected_max_scroll,
1479 host_impl_->active_tree()->root_layer()->max_scroll_offset());
1481 // The page scale delta remains constant because the impl thread did not
1482 // scale.
1483 // TODO(shawnsingh): If possible, use gfx::Transform() or Skia equality
1484 // functions. At the moment we avoid that because skia does exact bit-wise
1485 // equality checking that does not consider -0 == +0.
1486 // http://code.google.com/p/chromium/issues/detail?id=162747
1487 EXPECT_EQ(1.0,
1488 host_impl_->active_tree()->root_layer()->
1489 impl_transform().matrix().getDouble(0, 0));
1490 EXPECT_EQ(0.0,
1491 host_impl_->active_tree()->root_layer()->
1492 impl_transform().matrix().getDouble(0, 1));
1493 EXPECT_EQ(0.0,
1494 host_impl_->active_tree()->root_layer()->
1495 impl_transform().matrix().getDouble(0, 2));
1496 EXPECT_EQ(0.0,
1497 host_impl_->active_tree()->root_layer()->
1498 impl_transform().matrix().getDouble(0, 3));
1499 EXPECT_EQ(0.0,
1500 host_impl_->active_tree()->root_layer()->
1501 impl_transform().matrix().getDouble(1, 0));
1502 EXPECT_EQ(1.0,
1503 host_impl_->active_tree()->root_layer()->
1504 impl_transform().matrix().getDouble(1, 1));
1505 EXPECT_EQ(0.0,
1506 host_impl_->active_tree()->root_layer()->
1507 impl_transform().matrix().getDouble(1, 2));
1508 EXPECT_EQ(0.0,
1509 host_impl_->active_tree()->root_layer()->
1510 impl_transform().matrix().getDouble(1, 3));
1511 EXPECT_EQ(0.0,
1512 host_impl_->active_tree()->root_layer()->
1513 impl_transform().matrix().getDouble(2, 0));
1514 EXPECT_EQ(0.0,
1515 host_impl_->active_tree()->root_layer()->
1516 impl_transform().matrix().getDouble(2, 1));
1517 EXPECT_EQ(1.0,
1518 host_impl_->active_tree()->root_layer()->
1519 impl_transform().matrix().getDouble(2, 2));
1520 EXPECT_EQ(0.0,
1521 host_impl_->active_tree()->root_layer()->
1522 impl_transform().matrix().getDouble(2, 3));
1523 EXPECT_EQ(0.0,
1524 host_impl_->active_tree()->root_layer()->
1525 impl_transform().matrix().getDouble(3, 0));
1526 EXPECT_EQ(0.0,
1527 host_impl_->active_tree()->root_layer()->
1528 impl_transform().matrix().getDouble(3, 1));
1529 EXPECT_EQ(0.0,
1530 host_impl_->active_tree()->root_layer()->
1531 impl_transform().matrix().getDouble(3, 2));
1532 EXPECT_EQ(1.0,
1533 host_impl_->active_tree()->root_layer()->
1534 impl_transform().matrix().getDouble(3, 3));
1537 TEST_F(LayerTreeHostImplTest, ScrollRootAndChangePageScaleOnImplThread) {
1538 gfx::Size surface_size(10, 10);
1539 float page_scale = 2.f;
1540 scoped_ptr<LayerImpl> root = CreateScrollableLayer(1, surface_size);
1541 host_impl_->active_tree()->SetRootLayer(root.Pass());
1542 host_impl_->active_tree()->DidBecomeActive();
1543 host_impl_->SetViewportSize(surface_size);
1544 host_impl_->active_tree()->SetPageScaleFactorAndLimits(1.f, 1.f, page_scale);
1545 InitializeRendererAndDrawFrame();
1547 gfx::Vector2d scroll_delta(0, 10);
1548 gfx::Vector2d expected_scroll_delta = scroll_delta;
1549 gfx::Vector2d expected_max_scroll =
1550 host_impl_->active_tree()->root_layer()->max_scroll_offset();
1551 EXPECT_EQ(InputHandlerClient::ScrollStarted,
1552 host_impl_->ScrollBegin(gfx::Point(5, 5),
1553 InputHandlerClient::Wheel));
1554 host_impl_->ScrollBy(gfx::Point(), scroll_delta);
1555 host_impl_->ScrollEnd();
1557 // Set new page scale on impl thread by pinching.
1558 host_impl_->PinchGestureBegin();
1559 host_impl_->PinchGestureUpdate(page_scale, gfx::Point());
1560 host_impl_->PinchGestureEnd();
1561 DrawOneFrame();
1563 // The scroll delta is not scaled because the main thread did not scale.
1564 scoped_ptr<ScrollAndScaleSet> scroll_info = host_impl_->ProcessScrollDeltas();
1565 ExpectContains(*scroll_info.get(),
1566 host_impl_->active_tree()->root_layer()->id(),
1567 expected_scroll_delta);
1569 // The scroll range should also have been updated.
1570 EXPECT_EQ(expected_max_scroll,
1571 host_impl_->active_tree()->root_layer()->max_scroll_offset());
1573 // The page scale delta should match the new scale on the impl side.
1574 gfx::Transform expected_scale;
1575 expected_scale.Scale(page_scale, page_scale);
1576 EXPECT_EQ(expected_scale,
1577 host_impl_->active_tree()->root_layer()->impl_transform());
1580 TEST_F(LayerTreeHostImplTest, PageScaleDeltaAppliedToRootScrollLayerOnly) {
1581 gfx::Size surface_size(10, 10);
1582 float default_page_scale = 1.f;
1583 gfx::Transform default_page_scale_matrix;
1584 default_page_scale_matrix.Scale(default_page_scale, default_page_scale);
1586 float new_page_scale = 2.f;
1587 gfx::Transform new_page_scale_matrix;
1588 new_page_scale_matrix.Scale(new_page_scale, new_page_scale);
1590 // Create a normal scrollable root layer and another scrollable child layer.
1591 SetupScrollAndContentsLayers(surface_size);
1592 LayerImpl* root = host_impl_->active_tree()->root_layer();
1593 LayerImpl* child = root->children()[0];
1595 scoped_ptr<LayerImpl> scrollable_child =
1596 CreateScrollableLayer(3, surface_size);
1597 child->AddChild(scrollable_child.Pass());
1598 LayerImpl* grand_child = child->children()[0];
1600 // Set new page scale on impl thread by pinching.
1601 host_impl_->PinchGestureBegin();
1602 host_impl_->PinchGestureUpdate(new_page_scale, gfx::Point());
1603 host_impl_->PinchGestureEnd();
1604 DrawOneFrame();
1606 // The page scale delta should only be applied to the scrollable root layer.
1607 EXPECT_EQ(root->impl_transform(), new_page_scale_matrix);
1608 EXPECT_EQ(child->impl_transform(), default_page_scale_matrix);
1609 EXPECT_EQ(grand_child->impl_transform(), default_page_scale_matrix);
1611 // Make sure all the layers are drawn with the page scale delta applied, i.e.,
1612 // the page scale delta on the root layer is applied hierarchically.
1613 LayerTreeHostImpl::FrameData frame;
1614 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
1615 host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
1616 host_impl_->DidDrawAllLayers(frame);
1618 EXPECT_EQ(new_page_scale, root->draw_transform().matrix().getDouble(0, 0));
1619 EXPECT_EQ(new_page_scale, root->draw_transform().matrix().getDouble(1, 1));
1620 EXPECT_EQ(new_page_scale, child->draw_transform().matrix().getDouble(0, 0));
1621 EXPECT_EQ(new_page_scale, child->draw_transform().matrix().getDouble(1, 1));
1622 EXPECT_EQ(new_page_scale,
1623 grand_child->draw_transform().matrix().getDouble(0, 0));
1624 EXPECT_EQ(new_page_scale,
1625 grand_child->draw_transform().matrix().getDouble(1, 1));
1628 TEST_F(LayerTreeHostImplTest, ScrollChildAndChangePageScaleOnMainThread) {
1629 gfx::Size surface_size(10, 10);
1630 scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl_->active_tree(), 1);
1631 root->SetBounds(surface_size);
1632 root->SetContentBounds(surface_size);
1633 // Also mark the root scrollable so it becomes the root scroll layer.
1634 root->SetScrollable(true);
1635 int scroll_layer_id = 2;
1636 root->AddChild(CreateScrollableLayer(scroll_layer_id, surface_size));
1637 host_impl_->active_tree()->SetRootLayer(root.Pass());
1638 host_impl_->active_tree()->DidBecomeActive();
1639 host_impl_->SetViewportSize(surface_size);
1640 InitializeRendererAndDrawFrame();
1642 LayerImpl* child = host_impl_->active_tree()->root_layer()->children()[0];
1644 gfx::Vector2d scroll_delta(0, 10);
1645 gfx::Vector2d expected_scroll_delta(scroll_delta);
1646 gfx::Vector2d expected_max_scroll(child->max_scroll_offset());
1647 EXPECT_EQ(InputHandlerClient::ScrollStarted,
1648 host_impl_->ScrollBegin(gfx::Point(5, 5),
1649 InputHandlerClient::Wheel));
1650 host_impl_->ScrollBy(gfx::Point(), scroll_delta);
1651 host_impl_->ScrollEnd();
1653 float page_scale = 2.f;
1654 host_impl_->active_tree()->SetPageScaleFactorAndLimits(page_scale,
1655 1.f,
1656 page_scale);
1658 DrawOneFrame();
1660 scoped_ptr<ScrollAndScaleSet> scroll_info = host_impl_->ProcessScrollDeltas();
1661 ExpectContains(*scroll_info.get(), scroll_layer_id, expected_scroll_delta);
1663 // The scroll range should not have changed.
1664 EXPECT_EQ(child->max_scroll_offset(), expected_max_scroll);
1666 // The page scale delta remains constant because the impl thread did not
1667 // scale.
1668 gfx::Transform identity_transform;
1669 EXPECT_EQ(child->impl_transform(), gfx::Transform());
1672 TEST_F(LayerTreeHostImplTest, ScrollChildBeyondLimit) {
1673 // Scroll a child layer beyond its maximum scroll range and make sure the
1674 // parent layer is scrolled on the axis on which the child was unable to
1675 // scroll.
1676 gfx::Size surface_size(10, 10);
1677 scoped_ptr<LayerImpl> root = CreateScrollableLayer(1, surface_size);
1679 scoped_ptr<LayerImpl> grand_child = CreateScrollableLayer(3, surface_size);
1680 grand_child->SetScrollOffset(gfx::Vector2d(0, 5));
1682 scoped_ptr<LayerImpl> child = CreateScrollableLayer(2, surface_size);
1683 child->SetScrollOffset(gfx::Vector2d(3, 0));
1684 child->AddChild(grand_child.Pass());
1686 root->AddChild(child.Pass());
1687 host_impl_->active_tree()->SetRootLayer(root.Pass());
1688 host_impl_->active_tree()->DidBecomeActive();
1689 host_impl_->SetViewportSize(surface_size);
1690 InitializeRendererAndDrawFrame();
1692 gfx::Vector2d scroll_delta(-8, -7);
1693 EXPECT_EQ(InputHandlerClient::ScrollStarted,
1694 host_impl_->ScrollBegin(gfx::Point(5, 5),
1695 InputHandlerClient::Wheel));
1696 host_impl_->ScrollBy(gfx::Point(), scroll_delta);
1697 host_impl_->ScrollEnd();
1699 scoped_ptr<ScrollAndScaleSet> scroll_info =
1700 host_impl_->ProcessScrollDeltas();
1702 // The grand child should have scrolled up to its limit.
1703 LayerImpl* child = host_impl_->active_tree()->root_layer()->children()[0];
1704 LayerImpl* grand_child = child->children()[0];
1705 ExpectContains(*scroll_info.get(), grand_child->id(), gfx::Vector2d(0, -5));
1707 // The child should have only scrolled on the other axis.
1708 ExpectContains(*scroll_info.get(), child->id(), gfx::Vector2d(-3, 0));
1712 TEST_F(LayerTreeHostImplTest, ScrollWithoutBubbling) {
1713 // Scroll a child layer beyond its maximum scroll range and make sure the
1714 // the scroll doesn't bubble up to the parent layer.
1715 gfx::Size surface_size(10, 10);
1716 scoped_ptr<LayerImpl> root = CreateScrollableLayer(1, surface_size);
1718 scoped_ptr<LayerImpl> grand_child = CreateScrollableLayer(3, surface_size);
1719 grand_child->SetScrollOffset(gfx::Vector2d(0, 2));
1721 scoped_ptr<LayerImpl> child = CreateScrollableLayer(2, surface_size);
1722 child->SetScrollOffset(gfx::Vector2d(0, 3));
1723 child->AddChild(grand_child.Pass());
1725 root->AddChild(child.Pass());
1726 host_impl_->active_tree()->SetRootLayer(root.Pass());
1727 host_impl_->active_tree()->DidBecomeActive();
1728 host_impl_->SetViewportSize(surface_size);
1729 InitializeRendererAndDrawFrame();
1731 gfx::Vector2d scroll_delta(0, -10);
1732 EXPECT_EQ(InputHandlerClient::ScrollStarted,
1733 host_impl_->ScrollBegin(gfx::Point(5, 5),
1734 InputHandlerClient::NonBubblingGesture));
1735 host_impl_->ScrollBy(gfx::Point(), scroll_delta);
1736 host_impl_->ScrollEnd();
1738 scoped_ptr<ScrollAndScaleSet> scroll_info =
1739 host_impl_->ProcessScrollDeltas();
1741 // The grand child should have scrolled up to its limit.
1742 LayerImpl* child = host_impl_->active_tree()->root_layer()->children()[0];
1743 LayerImpl* grand_child = child->children()[0];
1744 ExpectContains(*scroll_info.get(), grand_child->id(), gfx::Vector2d(0, -2));
1746 // The child should not have scrolled.
1747 ExpectNone(*scroll_info.get(), child->id());
1749 // The next time we scroll we should only scroll the parent.
1750 scroll_delta = gfx::Vector2d(0, -3);
1751 EXPECT_EQ(InputHandlerClient::ScrollStarted,
1752 host_impl_->ScrollBegin(gfx::Point(5, 5),
1753 InputHandlerClient::NonBubblingGesture));
1754 EXPECT_EQ(host_impl_->CurrentlyScrollingLayer(), grand_child);
1755 host_impl_->ScrollBy(gfx::Point(), scroll_delta);
1756 EXPECT_EQ(host_impl_->CurrentlyScrollingLayer(), child);
1757 host_impl_->ScrollEnd();
1759 scroll_info = host_impl_->ProcessScrollDeltas();
1761 // The child should have scrolled up to its limit.
1762 ExpectContains(*scroll_info.get(), child->id(), gfx::Vector2d(0, -3));
1764 // The grand child should not have scrolled.
1765 ExpectContains(*scroll_info.get(), grand_child->id(), gfx::Vector2d(0, -2));
1767 // After scrolling the parent, another scroll on the opposite direction
1768 // should still scroll the child.
1769 scroll_delta = gfx::Vector2d(0, 7);
1770 EXPECT_EQ(InputHandlerClient::ScrollStarted,
1771 host_impl_->ScrollBegin(gfx::Point(5, 5),
1772 InputHandlerClient::NonBubblingGesture));
1773 EXPECT_EQ(host_impl_->CurrentlyScrollingLayer(), grand_child);
1774 host_impl_->ScrollBy(gfx::Point(), scroll_delta);
1775 EXPECT_EQ(host_impl_->CurrentlyScrollingLayer(), grand_child);
1776 host_impl_->ScrollEnd();
1778 scroll_info = host_impl_->ProcessScrollDeltas();
1780 // The grand child should have scrolled.
1781 ExpectContains(*scroll_info.get(), grand_child->id(), gfx::Vector2d(0, 5));
1783 // The child should not have scrolled.
1784 ExpectContains(*scroll_info.get(), child->id(), gfx::Vector2d(0, -3));
1787 // Scrolling should be adjusted from viewport space.
1788 host_impl_->active_tree()->SetPageScaleFactorAndLimits(2.f, 2.f, 2.f);
1789 host_impl_->active_tree()->SetPageScaleDelta(1.f);
1790 gfx::Transform scale_transform;
1791 scale_transform.Scale(2.f, 2.f);
1792 host_impl_->active_tree()->root_layer()->SetImplTransform(scale_transform);
1794 scroll_delta = gfx::Vector2d(0, -2);
1795 EXPECT_EQ(InputHandlerClient::ScrollStarted,
1796 host_impl_->ScrollBegin(gfx::Point(1, 1),
1797 InputHandlerClient::NonBubblingGesture));
1798 EXPECT_EQ(grand_child, host_impl_->CurrentlyScrollingLayer());
1799 host_impl_->ScrollBy(gfx::Point(), scroll_delta);
1800 host_impl_->ScrollEnd();
1802 scroll_info = host_impl_->ProcessScrollDeltas();
1804 // Should have scrolled by half the amount in layer space (5 - 2/2)
1805 ExpectContains(*scroll_info.get(), grand_child->id(), gfx::Vector2d(0, 4));
1809 TEST_F(LayerTreeHostImplTest, ScrollEventBubbling) {
1810 // When we try to scroll a non-scrollable child layer, the scroll delta
1811 // should be applied to one of its ancestors if possible.
1812 gfx::Size surface_size(10, 10);
1813 gfx::Size content_size(20, 20);
1814 scoped_ptr<LayerImpl> root = CreateScrollableLayer(1, content_size);
1815 scoped_ptr<LayerImpl> child = CreateScrollableLayer(2, content_size);
1817 child->SetScrollable(false);
1818 root->AddChild(child.Pass());
1820 host_impl_->SetViewportSize(surface_size);
1821 host_impl_->active_tree()->SetRootLayer(root.Pass());
1822 host_impl_->active_tree()->DidBecomeActive();
1823 InitializeRendererAndDrawFrame();
1825 gfx::Vector2d scroll_delta(0, 4);
1826 EXPECT_EQ(InputHandlerClient::ScrollStarted,
1827 host_impl_->ScrollBegin(gfx::Point(5, 5),
1828 InputHandlerClient::Wheel));
1829 host_impl_->ScrollBy(gfx::Point(), scroll_delta);
1830 host_impl_->ScrollEnd();
1832 scoped_ptr<ScrollAndScaleSet> scroll_info =
1833 host_impl_->ProcessScrollDeltas();
1835 // Only the root should have scrolled.
1836 ASSERT_EQ(scroll_info->scrolls.size(), 1u);
1837 ExpectContains(*scroll_info.get(),
1838 host_impl_->active_tree()->root_layer()->id(),
1839 scroll_delta);
1843 TEST_F(LayerTreeHostImplTest, ScrollBeforeRedraw) {
1844 gfx::Size surface_size(10, 10);
1845 host_impl_->active_tree()->SetRootLayer(
1846 CreateScrollableLayer(1, surface_size));
1847 host_impl_->active_tree()->DidBecomeActive();
1848 host_impl_->SetViewportSize(surface_size);
1850 // Draw one frame and then immediately rebuild the layer tree to mimic a tree
1851 // synchronization.
1852 InitializeRendererAndDrawFrame();
1853 host_impl_->active_tree()->DetachLayerTree();
1854 host_impl_->active_tree()->SetRootLayer(
1855 CreateScrollableLayer(2, surface_size));
1856 host_impl_->active_tree()->DidBecomeActive();
1858 // Scrolling should still work even though we did not draw yet.
1859 EXPECT_EQ(InputHandlerClient::ScrollStarted,
1860 host_impl_->ScrollBegin(gfx::Point(5, 5),
1861 InputHandlerClient::Wheel));
1864 TEST_F(LayerTreeHostImplTest, ScrollAxisAlignedRotatedLayer) {
1865 SetupScrollAndContentsLayers(gfx::Size(100, 100));
1867 // Rotate the root layer 90 degrees counter-clockwise about its center.
1868 gfx::Transform rotate_transform;
1869 rotate_transform.Rotate(-90.0);
1870 host_impl_->active_tree()->root_layer()->SetTransform(rotate_transform);
1872 gfx::Size surface_size(50, 50);
1873 host_impl_->SetViewportSize(surface_size);
1874 InitializeRendererAndDrawFrame();
1876 // Scroll to the right in screen coordinates with a gesture.
1877 gfx::Vector2d gesture_scroll_delta(10, 0);
1878 EXPECT_EQ(InputHandlerClient::ScrollStarted,
1879 host_impl_->ScrollBegin(gfx::Point(),
1880 InputHandlerClient::Gesture));
1881 host_impl_->ScrollBy(gfx::Point(), gesture_scroll_delta);
1882 host_impl_->ScrollEnd();
1884 // The layer should have scrolled down in its local coordinates.
1885 scoped_ptr<ScrollAndScaleSet> scroll_info = host_impl_->ProcessScrollDeltas();
1886 ExpectContains(*scroll_info.get(),
1887 host_impl_->active_tree()->root_layer()->id(),
1888 gfx::Vector2d(0, gesture_scroll_delta.x()));
1890 // Reset and scroll down with the wheel.
1891 host_impl_->active_tree()->root_layer()->SetScrollDelta(gfx::Vector2dF());
1892 gfx::Vector2d wheel_scroll_delta(0, 10);
1893 EXPECT_EQ(InputHandlerClient::ScrollStarted,
1894 host_impl_->ScrollBegin(gfx::Point(),
1895 InputHandlerClient::Wheel));
1896 host_impl_->ScrollBy(gfx::Point(), wheel_scroll_delta);
1897 host_impl_->ScrollEnd();
1899 // The layer should have scrolled down in its local coordinates.
1900 scroll_info = host_impl_->ProcessScrollDeltas();
1901 ExpectContains(*scroll_info.get(),
1902 host_impl_->active_tree()->root_layer()->id(),
1903 wheel_scroll_delta);
1906 TEST_F(LayerTreeHostImplTest, ScrollNonAxisAlignedRotatedLayer) {
1907 SetupScrollAndContentsLayers(gfx::Size(100, 100));
1908 int child_layer_id = 3;
1909 float child_layer_angle = -20.f;
1911 // Create a child layer that is rotated to a non-axis-aligned angle.
1912 scoped_ptr<LayerImpl> child = CreateScrollableLayer(
1913 child_layer_id,
1914 host_impl_->active_tree()->root_layer()->content_bounds());
1915 gfx::Transform rotate_transform;
1916 rotate_transform.Translate(-50.0, -50.0);
1917 rotate_transform.Rotate(child_layer_angle);
1918 rotate_transform.Translate(50.0, 50.0);
1919 child->SetTransform(rotate_transform);
1921 // Only allow vertical scrolling.
1922 child->SetMaxScrollOffset(gfx::Vector2d(0, child->content_bounds().height()));
1923 host_impl_->active_tree()->root_layer()->AddChild(child.Pass());
1925 gfx::Size surface_size(50, 50);
1926 host_impl_->SetViewportSize(surface_size);
1927 InitializeRendererAndDrawFrame();
1929 // Scroll down in screen coordinates with a gesture.
1930 gfx::Vector2d gesture_scroll_delta(0, 10);
1931 EXPECT_EQ(InputHandlerClient::ScrollStarted,
1932 host_impl_->ScrollBegin(gfx::Point(),
1933 InputHandlerClient::Gesture));
1934 host_impl_->ScrollBy(gfx::Point(), gesture_scroll_delta);
1935 host_impl_->ScrollEnd();
1937 // The child layer should have scrolled down in its local coordinates an
1938 // amount proportional to the angle between it and the input scroll delta.
1939 gfx::Vector2d expected_scroll_delta(
1941 gesture_scroll_delta.y() *
1942 std::cos(MathUtil::Deg2Rad(child_layer_angle)));
1943 scoped_ptr<ScrollAndScaleSet> scroll_info =
1944 host_impl_->ProcessScrollDeltas();
1945 ExpectContains(*scroll_info.get(), child_layer_id, expected_scroll_delta);
1947 // The root layer should not have scrolled, because the input delta was
1948 // close to the layer's axis of movement.
1949 EXPECT_EQ(scroll_info->scrolls.size(), 1u);
1952 // Now reset and scroll the same amount horizontally.
1953 host_impl_->active_tree()->root_layer()->children()[1]->SetScrollDelta(
1954 gfx::Vector2dF());
1955 gfx::Vector2d gesture_scroll_delta(10, 0);
1956 EXPECT_EQ(InputHandlerClient::ScrollStarted,
1957 host_impl_->ScrollBegin(gfx::Point(),
1958 InputHandlerClient::Gesture));
1959 host_impl_->ScrollBy(gfx::Point(), gesture_scroll_delta);
1960 host_impl_->ScrollEnd();
1962 // The child layer should have scrolled down in its local coordinates an
1963 // amount proportional to the angle between it and the input scroll delta.
1964 gfx::Vector2d expected_scroll_delta(
1966 -gesture_scroll_delta.x() *
1967 std::sin(MathUtil::Deg2Rad(child_layer_angle)));
1968 scoped_ptr<ScrollAndScaleSet> scroll_info =
1969 host_impl_->ProcessScrollDeltas();
1970 ExpectContains(*scroll_info.get(), child_layer_id, expected_scroll_delta);
1972 // The root layer should have scrolled more, since the input scroll delta
1973 // was mostly orthogonal to the child layer's vertical scroll axis.
1974 gfx::Vector2d expected_root_scroll_delta(
1975 gesture_scroll_delta.x() *
1976 std::pow(std::cos(MathUtil::Deg2Rad(child_layer_angle)), 2),
1978 ExpectContains(*scroll_info.get(),
1979 host_impl_->active_tree()->root_layer()->id(),
1980 expected_root_scroll_delta);
1984 TEST_F(LayerTreeHostImplTest, ScrollScaledLayer) {
1985 SetupScrollAndContentsLayers(gfx::Size(100, 100));
1987 // Scale the layer to twice its normal size.
1988 int scale = 2;
1989 gfx::Transform scale_transform;
1990 scale_transform.Scale(scale, scale);
1991 host_impl_->active_tree()->root_layer()->SetTransform(scale_transform);
1993 gfx::Size surface_size(50, 50);
1994 host_impl_->SetViewportSize(surface_size);
1995 InitializeRendererAndDrawFrame();
1997 // Scroll down in screen coordinates with a gesture.
1998 gfx::Vector2d scroll_delta(0, 10);
1999 EXPECT_EQ(InputHandlerClient::ScrollStarted,
2000 host_impl_->ScrollBegin(gfx::Point(), InputHandlerClient::Gesture));
2001 host_impl_->ScrollBy(gfx::Point(), scroll_delta);
2002 host_impl_->ScrollEnd();
2004 // The layer should have scrolled down in its local coordinates, but half the
2005 // amount.
2006 scoped_ptr<ScrollAndScaleSet> scroll_info = host_impl_->ProcessScrollDeltas();
2007 ExpectContains(*scroll_info.get(),
2008 host_impl_->active_tree()->root_layer()->id(),
2009 gfx::Vector2d(0, scroll_delta.y() / scale));
2011 // Reset and scroll down with the wheel.
2012 host_impl_->active_tree()->root_layer()->SetScrollDelta(gfx::Vector2dF());
2013 gfx::Vector2d wheel_scroll_delta(0, 10);
2014 EXPECT_EQ(InputHandlerClient::ScrollStarted,
2015 host_impl_->ScrollBegin(gfx::Point(), InputHandlerClient::Wheel));
2016 host_impl_->ScrollBy(gfx::Point(), wheel_scroll_delta);
2017 host_impl_->ScrollEnd();
2019 // The scale should not have been applied to the scroll delta.
2020 scroll_info = host_impl_->ProcessScrollDeltas();
2021 ExpectContains(*scroll_info.get(),
2022 host_impl_->active_tree()->root_layer()->id(),
2023 wheel_scroll_delta);
2026 class BlendStateTrackerContext: public TestWebGraphicsContext3D {
2027 public:
2028 BlendStateTrackerContext() : blend_(false) {}
2030 virtual void enable(WebKit::WGC3Denum cap) OVERRIDE {
2031 if (cap == GL_BLEND)
2032 blend_ = true;
2035 virtual void disable(WebKit::WGC3Denum cap) OVERRIDE {
2036 if (cap == GL_BLEND)
2037 blend_ = false;
2040 bool blend() const { return blend_; }
2042 private:
2043 bool blend_;
2046 class BlendStateCheckLayer : public LayerImpl {
2047 public:
2048 static scoped_ptr<LayerImpl> Create(LayerTreeImpl* tree_impl,
2049 int id,
2050 ResourceProvider* resource_provider) {
2051 return scoped_ptr<LayerImpl>(new BlendStateCheckLayer(tree_impl,
2053 resource_provider));
2056 virtual void AppendQuads(QuadSink* quad_sink,
2057 AppendQuadsData* append_quads_data) OVERRIDE {
2058 quads_appended_ = true;
2060 gfx::Rect opaque_rect;
2061 if (contents_opaque())
2062 opaque_rect = quad_rect_;
2063 else
2064 opaque_rect = opaque_content_rect_;
2066 SharedQuadState* shared_quad_state =
2067 quad_sink->UseSharedQuadState(CreateSharedQuadState());
2068 scoped_ptr<TileDrawQuad> test_blending_draw_quad = TileDrawQuad::Create();
2069 test_blending_draw_quad->SetNew(shared_quad_state,
2070 quad_rect_,
2071 opaque_rect,
2072 resource_id_,
2073 gfx::RectF(0.f, 0.f, 1.f, 1.f),
2074 gfx::Size(1, 1),
2075 false);
2076 test_blending_draw_quad->visible_rect = quad_visible_rect_;
2077 EXPECT_EQ(blend_, test_blending_draw_quad->ShouldDrawWithBlending());
2078 EXPECT_EQ(has_render_surface_, !!render_surface());
2079 quad_sink->Append(test_blending_draw_quad.PassAs<DrawQuad>(),
2080 append_quads_data);
2083 void SetExpectation(bool blend, bool has_render_surface) {
2084 blend_ = blend;
2085 has_render_surface_ = has_render_surface;
2086 quads_appended_ = false;
2089 bool quads_appended() const { return quads_appended_; }
2091 void SetQuadRect(gfx::Rect rect) { quad_rect_ = rect; }
2092 void SetQuadVisibleRect(gfx::Rect rect) { quad_visible_rect_ = rect; }
2093 void SetOpaqueContentRect(gfx::Rect rect) { opaque_content_rect_ = rect; }
2095 private:
2096 BlendStateCheckLayer(LayerTreeImpl* tree_impl,
2097 int id,
2098 ResourceProvider* resource_provider)
2099 : LayerImpl(tree_impl, id),
2100 blend_(false),
2101 has_render_surface_(false),
2102 quads_appended_(false),
2103 quad_rect_(5, 5, 5, 5),
2104 quad_visible_rect_(5, 5, 5, 5),
2105 resource_id_(resource_provider->CreateResource(
2106 gfx::Size(1, 1),
2107 GL_RGBA,
2108 ResourceProvider::TextureUsageAny)) {
2109 resource_provider->AllocateForTesting(resource_id_);
2110 SetAnchorPoint(gfx::PointF());
2111 SetBounds(gfx::Size(10, 10));
2112 SetContentBounds(gfx::Size(10, 10));
2113 SetDrawsContent(true);
2116 bool blend_;
2117 bool has_render_surface_;
2118 bool quads_appended_;
2119 gfx::Rect quad_rect_;
2120 gfx::Rect opaque_content_rect_;
2121 gfx::Rect quad_visible_rect_;
2122 ResourceProvider::ResourceId resource_id_;
2125 TEST_F(LayerTreeHostImplTest, BlendingOffWhenDrawingOpaqueLayers) {
2127 scoped_ptr<LayerImpl> root =
2128 LayerImpl::Create(host_impl_->active_tree(), 1);
2129 root->SetAnchorPoint(gfx::PointF());
2130 root->SetBounds(gfx::Size(10, 10));
2131 root->SetContentBounds(root->bounds());
2132 root->SetDrawsContent(false);
2133 host_impl_->active_tree()->SetRootLayer(root.Pass());
2135 LayerImpl* root = host_impl_->active_tree()->root_layer();
2137 root->AddChild(
2138 BlendStateCheckLayer::Create(host_impl_->active_tree(),
2140 host_impl_->resource_provider()));
2141 BlendStateCheckLayer* layer1 =
2142 static_cast<BlendStateCheckLayer*>(root->children()[0]);
2143 layer1->SetPosition(gfx::PointF(2.f, 2.f));
2145 LayerTreeHostImpl::FrameData frame;
2147 // Opaque layer, drawn without blending.
2148 layer1->SetContentsOpaque(true);
2149 layer1->SetExpectation(false, false);
2150 layer1->set_update_rect(gfx::RectF(layer1->content_bounds()));
2151 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
2152 host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
2153 EXPECT_TRUE(layer1->quads_appended());
2154 host_impl_->DidDrawAllLayers(frame);
2156 // Layer with translucent content and painting, so drawn with blending.
2157 layer1->SetContentsOpaque(false);
2158 layer1->SetExpectation(true, false);
2159 layer1->set_update_rect(gfx::RectF(layer1->content_bounds()));
2160 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
2161 host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
2162 EXPECT_TRUE(layer1->quads_appended());
2163 host_impl_->DidDrawAllLayers(frame);
2165 // Layer with translucent opacity, drawn with blending.
2166 layer1->SetContentsOpaque(true);
2167 layer1->SetOpacity(0.5f);
2168 layer1->SetExpectation(true, false);
2169 layer1->set_update_rect(gfx::RectF(layer1->content_bounds()));
2170 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
2171 host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
2172 EXPECT_TRUE(layer1->quads_appended());
2173 host_impl_->DidDrawAllLayers(frame);
2175 // Layer with translucent opacity and painting, drawn with blending.
2176 layer1->SetContentsOpaque(true);
2177 layer1->SetOpacity(0.5f);
2178 layer1->SetExpectation(true, false);
2179 layer1->set_update_rect(gfx::RectF(layer1->content_bounds()));
2180 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
2181 host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
2182 EXPECT_TRUE(layer1->quads_appended());
2183 host_impl_->DidDrawAllLayers(frame);
2185 layer1->AddChild(
2186 BlendStateCheckLayer::Create(host_impl_->active_tree(),
2188 host_impl_->resource_provider()));
2189 BlendStateCheckLayer* layer2 =
2190 static_cast<BlendStateCheckLayer*>(layer1->children()[0]);
2191 layer2->SetPosition(gfx::PointF(4.f, 4.f));
2193 // 2 opaque layers, drawn without blending.
2194 layer1->SetContentsOpaque(true);
2195 layer1->SetOpacity(1.f);
2196 layer1->SetExpectation(false, false);
2197 layer1->set_update_rect(gfx::RectF(layer1->content_bounds()));
2198 layer2->SetContentsOpaque(true);
2199 layer2->SetOpacity(1.f);
2200 layer2->SetExpectation(false, false);
2201 layer2->set_update_rect(gfx::RectF(layer1->content_bounds()));
2202 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
2203 host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
2204 EXPECT_TRUE(layer1->quads_appended());
2205 EXPECT_TRUE(layer2->quads_appended());
2206 host_impl_->DidDrawAllLayers(frame);
2208 // Parent layer with translucent content, drawn with blending.
2209 // Child layer with opaque content, drawn without blending.
2210 layer1->SetContentsOpaque(false);
2211 layer1->SetExpectation(true, false);
2212 layer1->set_update_rect(gfx::RectF(layer1->content_bounds()));
2213 layer2->SetExpectation(false, false);
2214 layer2->set_update_rect(gfx::RectF(layer1->content_bounds()));
2215 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
2216 host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
2217 EXPECT_TRUE(layer1->quads_appended());
2218 EXPECT_TRUE(layer2->quads_appended());
2219 host_impl_->DidDrawAllLayers(frame);
2221 // Parent layer with translucent content but opaque painting, drawn without
2222 // blending.
2223 // Child layer with opaque content, drawn without blending.
2224 layer1->SetContentsOpaque(true);
2225 layer1->SetExpectation(false, false);
2226 layer1->set_update_rect(gfx::RectF(layer1->content_bounds()));
2227 layer2->SetExpectation(false, false);
2228 layer2->set_update_rect(gfx::RectF(layer1->content_bounds()));
2229 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
2230 host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
2231 EXPECT_TRUE(layer1->quads_appended());
2232 EXPECT_TRUE(layer2->quads_appended());
2233 host_impl_->DidDrawAllLayers(frame);
2235 // Parent layer with translucent opacity and opaque content. Since it has a
2236 // drawing child, it's drawn to a render surface which carries the opacity,
2237 // so it's itself drawn without blending.
2238 // Child layer with opaque content, drawn without blending (parent surface
2239 // carries the inherited opacity).
2240 layer1->SetContentsOpaque(true);
2241 layer1->SetOpacity(0.5f);
2242 layer1->SetExpectation(false, true);
2243 layer1->set_update_rect(gfx::RectF(layer1->content_bounds()));
2244 layer2->SetExpectation(false, false);
2245 layer2->set_update_rect(gfx::RectF(layer1->content_bounds()));
2246 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
2247 host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
2248 EXPECT_TRUE(layer1->quads_appended());
2249 EXPECT_TRUE(layer2->quads_appended());
2250 host_impl_->DidDrawAllLayers(frame);
2252 // Draw again, but with child non-opaque, to make sure
2253 // layer1 not culled.
2254 layer1->SetContentsOpaque(true);
2255 layer1->SetOpacity(1.f);
2256 layer1->SetExpectation(false, false);
2257 layer1->set_update_rect(gfx::RectF(layer1->content_bounds()));
2258 layer2->SetContentsOpaque(true);
2259 layer2->SetOpacity(0.5f);
2260 layer2->SetExpectation(true, false);
2261 layer2->set_update_rect(gfx::RectF(layer1->content_bounds()));
2262 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
2263 host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
2264 EXPECT_TRUE(layer1->quads_appended());
2265 EXPECT_TRUE(layer2->quads_appended());
2266 host_impl_->DidDrawAllLayers(frame);
2268 // A second way of making the child non-opaque.
2269 layer1->SetContentsOpaque(true);
2270 layer1->SetOpacity(1.f);
2271 layer1->SetExpectation(false, false);
2272 layer1->set_update_rect(gfx::RectF(layer1->content_bounds()));
2273 layer2->SetContentsOpaque(false);
2274 layer2->SetOpacity(1.f);
2275 layer2->SetExpectation(true, false);
2276 layer2->set_update_rect(gfx::RectF(layer1->content_bounds()));
2277 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
2278 host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
2279 EXPECT_TRUE(layer1->quads_appended());
2280 EXPECT_TRUE(layer2->quads_appended());
2281 host_impl_->DidDrawAllLayers(frame);
2283 // And when the layer says its not opaque but is painted opaque, it is not
2284 // blended.
2285 layer1->SetContentsOpaque(true);
2286 layer1->SetOpacity(1.f);
2287 layer1->SetExpectation(false, false);
2288 layer1->set_update_rect(gfx::RectF(layer1->content_bounds()));
2289 layer2->SetContentsOpaque(true);
2290 layer2->SetOpacity(1.f);
2291 layer2->SetExpectation(false, false);
2292 layer2->set_update_rect(gfx::RectF(layer1->content_bounds()));
2293 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
2294 host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
2295 EXPECT_TRUE(layer1->quads_appended());
2296 EXPECT_TRUE(layer2->quads_appended());
2297 host_impl_->DidDrawAllLayers(frame);
2299 // Layer with partially opaque contents, drawn with blending.
2300 layer1->SetContentsOpaque(false);
2301 layer1->SetQuadRect(gfx::Rect(5, 5, 5, 5));
2302 layer1->SetQuadVisibleRect(gfx::Rect(5, 5, 5, 5));
2303 layer1->SetOpaqueContentRect(gfx::Rect(5, 5, 2, 5));
2304 layer1->SetExpectation(true, false);
2305 layer1->set_update_rect(gfx::RectF(layer1->content_bounds()));
2306 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
2307 host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
2308 EXPECT_TRUE(layer1->quads_appended());
2309 host_impl_->DidDrawAllLayers(frame);
2311 // Layer with partially opaque contents partially culled, drawn with blending.
2312 layer1->SetContentsOpaque(false);
2313 layer1->SetQuadRect(gfx::Rect(5, 5, 5, 5));
2314 layer1->SetQuadVisibleRect(gfx::Rect(5, 5, 5, 2));
2315 layer1->SetOpaqueContentRect(gfx::Rect(5, 5, 2, 5));
2316 layer1->SetExpectation(true, false);
2317 layer1->set_update_rect(gfx::RectF(layer1->content_bounds()));
2318 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
2319 host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
2320 EXPECT_TRUE(layer1->quads_appended());
2321 host_impl_->DidDrawAllLayers(frame);
2323 // Layer with partially opaque contents culled, drawn with blending.
2324 layer1->SetContentsOpaque(false);
2325 layer1->SetQuadRect(gfx::Rect(5, 5, 5, 5));
2326 layer1->SetQuadVisibleRect(gfx::Rect(7, 5, 3, 5));
2327 layer1->SetOpaqueContentRect(gfx::Rect(5, 5, 2, 5));
2328 layer1->SetExpectation(true, false);
2329 layer1->set_update_rect(gfx::RectF(layer1->content_bounds()));
2330 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
2331 host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
2332 EXPECT_TRUE(layer1->quads_appended());
2333 host_impl_->DidDrawAllLayers(frame);
2335 // Layer with partially opaque contents and translucent contents culled, drawn
2336 // without blending.
2337 layer1->SetContentsOpaque(false);
2338 layer1->SetQuadRect(gfx::Rect(5, 5, 5, 5));
2339 layer1->SetQuadVisibleRect(gfx::Rect(5, 5, 2, 5));
2340 layer1->SetOpaqueContentRect(gfx::Rect(5, 5, 2, 5));
2341 layer1->SetExpectation(false, false);
2342 layer1->set_update_rect(gfx::RectF(layer1->content_bounds()));
2343 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
2344 host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
2345 EXPECT_TRUE(layer1->quads_appended());
2346 host_impl_->DidDrawAllLayers(frame);
2349 TEST_F(LayerTreeHostImplTest, ViewportCovered) {
2350 host_impl_->InitializeRenderer(CreateOutputSurface());
2351 host_impl_->active_tree()->set_background_color(SK_ColorGRAY);
2353 gfx::Size viewport_size(1000, 1000);
2354 host_impl_->SetViewportSize(viewport_size);
2356 host_impl_->active_tree()->SetRootLayer(
2357 LayerImpl::Create(host_impl_->active_tree(), 1));
2358 host_impl_->active_tree()->root_layer()->AddChild(
2359 BlendStateCheckLayer::Create(host_impl_->active_tree(),
2361 host_impl_->resource_provider()));
2362 BlendStateCheckLayer* child = static_cast<BlendStateCheckLayer*>(
2363 host_impl_->active_tree()->root_layer()->children()[0]);
2364 child->SetExpectation(false, false);
2365 child->SetContentsOpaque(true);
2367 // No gutter rects
2369 gfx::Rect layer_rect(0, 0, 1000, 1000);
2370 child->SetPosition(layer_rect.origin());
2371 child->SetBounds(layer_rect.size());
2372 child->SetContentBounds(layer_rect.size());
2373 child->SetQuadRect(gfx::Rect(layer_rect.size()));
2374 child->SetQuadVisibleRect(gfx::Rect(layer_rect.size()));
2376 LayerTreeHostImpl::FrameData frame;
2377 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
2378 ASSERT_EQ(1u, frame.render_passes.size());
2380 size_t num_gutter_quads = 0;
2381 for (size_t i = 0; i < frame.render_passes[0]->quad_list.size(); ++i)
2382 num_gutter_quads += (frame.render_passes[0]->quad_list[i]->material ==
2383 DrawQuad::SOLID_COLOR) ? 1 : 0;
2384 EXPECT_EQ(0u, num_gutter_quads);
2385 EXPECT_EQ(1u, frame.render_passes[0]->quad_list.size());
2387 LayerTestCommon::VerifyQuadsExactlyCoverRect(
2388 frame.render_passes[0]->quad_list, gfx::Rect(viewport_size));
2389 host_impl_->DidDrawAllLayers(frame);
2392 // Empty visible content area (fullscreen gutter rect)
2394 gfx::Rect layer_rect(0, 0, 0, 0);
2395 child->SetPosition(layer_rect.origin());
2396 child->SetBounds(layer_rect.size());
2397 child->SetContentBounds(layer_rect.size());
2398 child->SetQuadRect(gfx::Rect(layer_rect.size()));
2399 child->SetQuadVisibleRect(gfx::Rect(layer_rect.size()));
2401 LayerTreeHostImpl::FrameData frame;
2402 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
2403 ASSERT_EQ(1u, frame.render_passes.size());
2405 size_t num_gutter_quads = 0;
2406 for (size_t i = 0; i < frame.render_passes[0]->quad_list.size(); ++i)
2407 num_gutter_quads += (frame.render_passes[0]->quad_list[i]->material ==
2408 DrawQuad::SOLID_COLOR) ? 1 : 0;
2409 EXPECT_EQ(1u, num_gutter_quads);
2410 EXPECT_EQ(1u, frame.render_passes[0]->quad_list.size());
2412 LayerTestCommon::VerifyQuadsExactlyCoverRect(
2413 frame.render_passes[0]->quad_list, gfx::Rect(viewport_size));
2414 host_impl_->DidDrawAllLayers(frame);
2417 // Content area in middle of clip rect (four surrounding gutter rects)
2419 gfx::Rect layer_rect(500, 500, 200, 200);
2420 child->SetPosition(layer_rect.origin());
2421 child->SetBounds(layer_rect.size());
2422 child->SetContentBounds(layer_rect.size());
2423 child->SetQuadRect(gfx::Rect(layer_rect.size()));
2424 child->SetQuadVisibleRect(gfx::Rect(layer_rect.size()));
2426 LayerTreeHostImpl::FrameData frame;
2427 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
2428 ASSERT_EQ(1u, frame.render_passes.size());
2430 size_t num_gutter_quads = 0;
2431 for (size_t i = 0; i < frame.render_passes[0]->quad_list.size(); ++i)
2432 num_gutter_quads += (frame.render_passes[0]->quad_list[i]->material ==
2433 DrawQuad::SOLID_COLOR) ? 1 : 0;
2434 EXPECT_EQ(4u, num_gutter_quads);
2435 EXPECT_EQ(5u, frame.render_passes[0]->quad_list.size());
2437 LayerTestCommon::VerifyQuadsExactlyCoverRect(
2438 frame.render_passes[0]->quad_list, gfx::Rect(viewport_size));
2439 host_impl_->DidDrawAllLayers(frame);
2444 class ReshapeTrackerContext: public TestWebGraphicsContext3D {
2445 public:
2446 ReshapeTrackerContext() : reshape_called_(false) {}
2448 virtual void reshape(int width, int height) OVERRIDE {
2449 reshape_called_ = true;
2452 bool reshape_called() const { return reshape_called_; }
2454 private:
2455 bool reshape_called_;
2458 class FakeDrawableLayerImpl: public LayerImpl {
2459 public:
2460 static scoped_ptr<LayerImpl> Create(LayerTreeImpl* tree_impl, int id) {
2461 return scoped_ptr<LayerImpl>(new FakeDrawableLayerImpl(tree_impl, id));
2463 protected:
2464 FakeDrawableLayerImpl(LayerTreeImpl* tree_impl, int id)
2465 : LayerImpl(tree_impl, id) {}
2468 // Only reshape when we know we are going to draw. Otherwise, the reshape
2469 // can leave the window at the wrong size if we never draw and the proper
2470 // viewport size is never set.
2471 TEST_F(LayerTreeHostImplTest, ReshapeNotCalledUntilDraw) {
2472 scoped_ptr<OutputSurface> output_surface = FakeOutputSurface::Create3d(
2473 scoped_ptr<WebKit::WebGraphicsContext3D>(new ReshapeTrackerContext))
2474 .PassAs<OutputSurface>();
2475 ReshapeTrackerContext* reshape_tracker =
2476 static_cast<ReshapeTrackerContext*>(output_surface->context3d());
2477 host_impl_->InitializeRenderer(output_surface.Pass());
2479 scoped_ptr<LayerImpl> root =
2480 FakeDrawableLayerImpl::Create(host_impl_->active_tree(), 1);
2481 root->SetAnchorPoint(gfx::PointF());
2482 root->SetBounds(gfx::Size(10, 10));
2483 root->SetContentBounds(gfx::Size(10, 10));
2484 root->SetDrawsContent(true);
2485 host_impl_->active_tree()->SetRootLayer(root.Pass());
2486 EXPECT_FALSE(reshape_tracker->reshape_called());
2488 LayerTreeHostImpl::FrameData frame;
2489 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
2490 host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
2491 EXPECT_TRUE(reshape_tracker->reshape_called());
2492 host_impl_->DidDrawAllLayers(frame);
2495 class PartialSwapTrackerContext : public TestWebGraphicsContext3D {
2496 public:
2497 virtual void postSubBufferCHROMIUM(int x, int y, int width, int height)
2498 OVERRIDE {
2499 partial_swap_rect_ = gfx::Rect(x, y, width, height);
2502 virtual WebKit::WebString getString(WebKit::WGC3Denum name) OVERRIDE {
2503 if (name == GL_EXTENSIONS) {
2504 return WebKit::WebString(
2505 "GL_CHROMIUM_post_sub_buffer GL_CHROMIUM_set_visibility");
2508 return WebKit::WebString();
2511 gfx::Rect partial_swap_rect() const { return partial_swap_rect_; }
2513 private:
2514 gfx::Rect partial_swap_rect_;
2517 // Make sure damage tracking propagates all the way to the graphics context,
2518 // where it should request to swap only the sub-buffer that is damaged.
2519 TEST_F(LayerTreeHostImplTest, PartialSwapReceivesDamageRect) {
2520 scoped_ptr<OutputSurface> output_surface =
2521 FakeOutputSurface::Create3d(scoped_ptr<WebKit::WebGraphicsContext3D>(
2522 new PartialSwapTrackerContext)).PassAs<OutputSurface>();
2523 PartialSwapTrackerContext* partial_swap_tracker =
2524 static_cast<PartialSwapTrackerContext*>(output_surface->context3d());
2526 // This test creates its own LayerTreeHostImpl, so
2527 // that we can force partial swap enabled.
2528 LayerTreeSettings settings;
2529 settings.partial_swap_enabled = true;
2530 scoped_ptr<LayerTreeHostImpl> layer_tree_host_impl =
2531 LayerTreeHostImpl::Create(settings,
2532 this,
2533 &proxy_,
2534 &stats_instrumentation_);
2535 layer_tree_host_impl->InitializeRenderer(output_surface.Pass());
2536 layer_tree_host_impl->SetViewportSize(gfx::Size(500, 500));
2538 scoped_ptr<LayerImpl> root =
2539 FakeDrawableLayerImpl::Create(layer_tree_host_impl->active_tree(), 1);
2540 scoped_ptr<LayerImpl> child =
2541 FakeDrawableLayerImpl::Create(layer_tree_host_impl->active_tree(), 2);
2542 child->SetPosition(gfx::PointF(12.f, 13.f));
2543 child->SetAnchorPoint(gfx::PointF());
2544 child->SetBounds(gfx::Size(14, 15));
2545 child->SetContentBounds(gfx::Size(14, 15));
2546 child->SetDrawsContent(true);
2547 root->SetAnchorPoint(gfx::PointF());
2548 root->SetBounds(gfx::Size(500, 500));
2549 root->SetContentBounds(gfx::Size(500, 500));
2550 root->SetDrawsContent(true);
2551 root->AddChild(child.Pass());
2552 layer_tree_host_impl->active_tree()->SetRootLayer(root.Pass());
2554 LayerTreeHostImpl::FrameData frame;
2556 // First frame, the entire screen should get swapped.
2557 EXPECT_TRUE(layer_tree_host_impl->PrepareToDraw(&frame, gfx::Rect()));
2558 layer_tree_host_impl->DrawLayers(&frame, base::TimeTicks::Now());
2559 layer_tree_host_impl->DidDrawAllLayers(frame);
2560 layer_tree_host_impl->SwapBuffers(frame);
2561 gfx::Rect actual_swap_rect = partial_swap_tracker->partial_swap_rect();
2562 gfx::Rect expected_swap_rect = gfx::Rect(0, 0, 500, 500);
2563 EXPECT_EQ(expected_swap_rect.x(), actual_swap_rect.x());
2564 EXPECT_EQ(expected_swap_rect.y(), actual_swap_rect.y());
2565 EXPECT_EQ(expected_swap_rect.width(), actual_swap_rect.width());
2566 EXPECT_EQ(expected_swap_rect.height(), actual_swap_rect.height());
2568 // Second frame, only the damaged area should get swapped. Damage should be
2569 // the union of old and new child rects.
2570 // expected damage rect: gfx::Rect(26, 28);
2571 // expected swap rect: vertically flipped, with origin at bottom left corner.
2572 layer_tree_host_impl->active_tree()->root_layer()->children()[0]->SetPosition(
2573 gfx::PointF());
2574 EXPECT_TRUE(layer_tree_host_impl->PrepareToDraw(&frame, gfx::Rect()));
2575 layer_tree_host_impl->DrawLayers(&frame, base::TimeTicks::Now());
2576 host_impl_->DidDrawAllLayers(frame);
2577 layer_tree_host_impl->SwapBuffers(frame);
2578 actual_swap_rect = partial_swap_tracker->partial_swap_rect();
2579 expected_swap_rect = gfx::Rect(0, 500-28, 26, 28);
2580 EXPECT_EQ(expected_swap_rect.x(), actual_swap_rect.x());
2581 EXPECT_EQ(expected_swap_rect.y(), actual_swap_rect.y());
2582 EXPECT_EQ(expected_swap_rect.width(), actual_swap_rect.width());
2583 EXPECT_EQ(expected_swap_rect.height(), actual_swap_rect.height());
2585 // Make sure that partial swap is constrained to the viewport dimensions
2586 // expected damage rect: gfx::Rect(500, 500);
2587 // expected swap rect: flipped damage rect, but also clamped to viewport
2588 layer_tree_host_impl->SetViewportSize(gfx::Size(10, 10));
2589 // This will damage everything.
2590 layer_tree_host_impl->active_tree()->root_layer()->SetOpacity(0.7f);
2591 EXPECT_TRUE(layer_tree_host_impl->PrepareToDraw(&frame, gfx::Rect()));
2592 layer_tree_host_impl->DrawLayers(&frame, base::TimeTicks::Now());
2593 host_impl_->DidDrawAllLayers(frame);
2594 layer_tree_host_impl->SwapBuffers(frame);
2595 actual_swap_rect = partial_swap_tracker->partial_swap_rect();
2596 expected_swap_rect = gfx::Rect(10, 10);
2597 EXPECT_EQ(expected_swap_rect.x(), actual_swap_rect.x());
2598 EXPECT_EQ(expected_swap_rect.y(), actual_swap_rect.y());
2599 EXPECT_EQ(expected_swap_rect.width(), actual_swap_rect.width());
2600 EXPECT_EQ(expected_swap_rect.height(), actual_swap_rect.height());
2603 TEST_F(LayerTreeHostImplTest, RootLayerDoesntCreateExtraSurface) {
2604 scoped_ptr<LayerImpl> root =
2605 FakeDrawableLayerImpl::Create(host_impl_->active_tree(), 1);
2606 scoped_ptr<LayerImpl> child =
2607 FakeDrawableLayerImpl::Create(host_impl_->active_tree(), 2);
2608 child->SetAnchorPoint(gfx::PointF());
2609 child->SetBounds(gfx::Size(10, 10));
2610 child->SetContentBounds(gfx::Size(10, 10));
2611 child->SetDrawsContent(true);
2612 root->SetAnchorPoint(gfx::PointF());
2613 root->SetBounds(gfx::Size(10, 10));
2614 root->SetContentBounds(gfx::Size(10, 10));
2615 root->SetDrawsContent(true);
2616 root->SetOpacity(0.7f);
2617 root->AddChild(child.Pass());
2619 host_impl_->active_tree()->SetRootLayer(root.Pass());
2621 LayerTreeHostImpl::FrameData frame;
2623 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
2624 EXPECT_EQ(1u, frame.render_surface_layer_list->size());
2625 EXPECT_EQ(1u, frame.render_passes.size());
2626 host_impl_->DidDrawAllLayers(frame);
2629 class FakeLayerWithQuads : public LayerImpl {
2630 public:
2631 static scoped_ptr<LayerImpl> Create(LayerTreeImpl* tree_impl, int id) {
2632 return scoped_ptr<LayerImpl>(new FakeLayerWithQuads(tree_impl, id));
2635 virtual void AppendQuads(QuadSink* quad_sink,
2636 AppendQuadsData* append_quads_data) OVERRIDE {
2637 SharedQuadState* shared_quad_state =
2638 quad_sink->UseSharedQuadState(CreateSharedQuadState());
2640 SkColor gray = SkColorSetRGB(100, 100, 100);
2641 gfx::Rect quad_rect(content_bounds());
2642 scoped_ptr<SolidColorDrawQuad> my_quad = SolidColorDrawQuad::Create();
2643 my_quad->SetNew(shared_quad_state, quad_rect, gray);
2644 quad_sink->Append(my_quad.PassAs<DrawQuad>(), append_quads_data);
2647 private:
2648 FakeLayerWithQuads(LayerTreeImpl* tree_impl, int id)
2649 : LayerImpl(tree_impl, id) {}
2652 class MockContext : public TestWebGraphicsContext3D {
2653 public:
2654 MOCK_METHOD1(useProgram, void(WebKit::WebGLId program));
2655 MOCK_METHOD5(uniform4f, void(WebKit::WGC3Dint location,
2656 WebKit::WGC3Dfloat x,
2657 WebKit::WGC3Dfloat y,
2658 WebKit::WGC3Dfloat z,
2659 WebKit::WGC3Dfloat w));
2660 MOCK_METHOD4(uniformMatrix4fv, void(WebKit::WGC3Dint location,
2661 WebKit::WGC3Dsizei count,
2662 WebKit::WGC3Dboolean transpose,
2663 const WebKit::WGC3Dfloat* value));
2664 MOCK_METHOD4(drawElements, void(WebKit::WGC3Denum mode,
2665 WebKit::WGC3Dsizei count,
2666 WebKit::WGC3Denum type,
2667 WebKit::WGC3Dintptr offset));
2668 MOCK_METHOD1(getString, WebKit::WebString(WebKit::WGC3Denum name));
2669 MOCK_METHOD0(getRequestableExtensionsCHROMIUM, WebKit::WebString());
2670 MOCK_METHOD1(enable, void(WebKit::WGC3Denum cap));
2671 MOCK_METHOD1(disable, void(WebKit::WGC3Denum cap));
2672 MOCK_METHOD4(scissor, void(WebKit::WGC3Dint x,
2673 WebKit::WGC3Dint y,
2674 WebKit::WGC3Dsizei width,
2675 WebKit::WGC3Dsizei height));
2678 class MockContextHarness {
2679 private:
2680 MockContext* context_;
2682 public:
2683 explicit MockContextHarness(MockContext* context)
2684 : context_(context) {
2685 // Catch "uninteresting" calls
2686 EXPECT_CALL(*context_, useProgram(_))
2687 .Times(0);
2689 EXPECT_CALL(*context_, drawElements(_, _, _, _))
2690 .Times(0);
2692 // These are not asserted
2693 EXPECT_CALL(*context_, uniformMatrix4fv(_, _, _, _))
2694 .WillRepeatedly(Return());
2696 EXPECT_CALL(*context_, uniform4f(_, _, _, _, _))
2697 .WillRepeatedly(Return());
2699 // Any other strings are empty
2700 EXPECT_CALL(*context_, getString(_))
2701 .WillRepeatedly(Return(WebKit::WebString()));
2703 // Support for partial swap, if needed
2704 EXPECT_CALL(*context_, getString(GL_EXTENSIONS))
2705 .WillRepeatedly(Return(
2706 WebKit::WebString("GL_CHROMIUM_post_sub_buffer")));
2708 EXPECT_CALL(*context_, getRequestableExtensionsCHROMIUM())
2709 .WillRepeatedly(Return(
2710 WebKit::WebString("GL_CHROMIUM_post_sub_buffer")));
2712 // Any un-sanctioned calls to enable() are OK
2713 EXPECT_CALL(*context_, enable(_))
2714 .WillRepeatedly(Return());
2716 // Any un-sanctioned calls to disable() are OK
2717 EXPECT_CALL(*context_, disable(_))
2718 .WillRepeatedly(Return());
2721 void MustDrawSolidQuad() {
2722 EXPECT_CALL(*context_, drawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, 0))
2723 .WillOnce(Return())
2724 .RetiresOnSaturation();
2726 EXPECT_CALL(*context_, useProgram(_))
2727 .WillOnce(Return())
2728 .RetiresOnSaturation();
2731 void MustSetScissor(int x, int y, int width, int height) {
2732 EXPECT_CALL(*context_, enable(GL_SCISSOR_TEST))
2733 .WillRepeatedly(Return());
2735 EXPECT_CALL(*context_, scissor(x, y, width, height))
2736 .Times(AtLeast(1))
2737 .WillRepeatedly(Return());
2740 void MustSetNoScissor() {
2741 EXPECT_CALL(*context_, disable(GL_SCISSOR_TEST))
2742 .WillRepeatedly(Return());
2744 EXPECT_CALL(*context_, enable(GL_SCISSOR_TEST))
2745 .Times(0);
2747 EXPECT_CALL(*context_, scissor(_, _, _, _))
2748 .Times(0);
2752 TEST_F(LayerTreeHostImplTest, NoPartialSwap) {
2753 scoped_ptr<OutputSurface> output_surface =
2754 FakeOutputSurface::Create3d(scoped_ptr<WebKit::WebGraphicsContext3D>(
2755 new MockContext)).PassAs<OutputSurface>();
2756 MockContext* mock_context =
2757 static_cast<MockContext*>(output_surface->context3d());
2758 MockContextHarness harness(mock_context);
2760 // Run test case
2761 CreateLayerTreeHost(false, output_surface.Pass());
2762 SetupRootLayerImpl(FakeLayerWithQuads::Create(host_impl_->active_tree(), 1));
2764 // Without partial swap, and no clipping, no scissor is set.
2765 harness.MustDrawSolidQuad();
2766 harness.MustSetNoScissor();
2768 LayerTreeHostImpl::FrameData frame;
2769 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
2770 host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
2771 host_impl_->DidDrawAllLayers(frame);
2773 Mock::VerifyAndClearExpectations(&mock_context);
2775 // Without partial swap, but a layer does clip its subtree, one scissor is
2776 // set.
2777 host_impl_->active_tree()->root_layer()->SetMasksToBounds(true);
2778 harness.MustDrawSolidQuad();
2779 harness.MustSetScissor(0, 0, 10, 10);
2781 LayerTreeHostImpl::FrameData frame;
2782 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
2783 host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
2784 host_impl_->DidDrawAllLayers(frame);
2786 Mock::VerifyAndClearExpectations(&mock_context);
2789 TEST_F(LayerTreeHostImplTest, PartialSwap) {
2790 scoped_ptr<OutputSurface> output_surface =
2791 FakeOutputSurface::Create3d(scoped_ptr<WebKit::WebGraphicsContext3D>(
2792 new MockContext)).PassAs<OutputSurface>();
2793 MockContext* mock_context =
2794 static_cast<MockContext*>(output_surface->context3d());
2795 MockContextHarness harness(mock_context);
2797 CreateLayerTreeHost(true, output_surface.Pass());
2798 SetupRootLayerImpl(FakeLayerWithQuads::Create(host_impl_->active_tree(), 1));
2800 // The first frame is not a partially-swapped one.
2801 harness.MustSetScissor(0, 0, 10, 10);
2802 harness.MustDrawSolidQuad();
2804 LayerTreeHostImpl::FrameData frame;
2805 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
2806 host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
2807 host_impl_->DidDrawAllLayers(frame);
2809 Mock::VerifyAndClearExpectations(&mock_context);
2811 // Damage a portion of the frame.
2812 host_impl_->active_tree()->root_layer()->set_update_rect(
2813 gfx::Rect(0, 0, 2, 3));
2815 // The second frame will be partially-swapped (the y coordinates are flipped).
2816 harness.MustSetScissor(0, 7, 2, 3);
2817 harness.MustDrawSolidQuad();
2819 LayerTreeHostImpl::FrameData frame;
2820 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
2821 host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
2822 host_impl_->DidDrawAllLayers(frame);
2824 Mock::VerifyAndClearExpectations(&mock_context);
2827 class PartialSwapContext : public TestWebGraphicsContext3D {
2828 public:
2829 virtual WebKit::WebString getString(WebKit::WGC3Denum name) OVERRIDE {
2830 if (name == GL_EXTENSIONS)
2831 return WebKit::WebString("GL_CHROMIUM_post_sub_buffer");
2832 return WebKit::WebString();
2835 virtual WebKit::WebString getRequestableExtensionsCHROMIUM() OVERRIDE {
2836 return WebKit::WebString("GL_CHROMIUM_post_sub_buffer");
2839 // Unlimited texture size.
2840 virtual void getIntegerv(WebKit::WGC3Denum pname, WebKit::WGC3Dint* value)
2841 OVERRIDE {
2842 if (pname == GL_MAX_TEXTURE_SIZE)
2843 *value = 8192;
2847 static scoped_ptr<LayerTreeHostImpl> SetupLayersForOpacity(
2848 bool partial_swap,
2849 LayerTreeHostImplClient* client,
2850 Proxy* proxy,
2851 RenderingStatsInstrumentation* stats_instrumentation) {
2852 scoped_ptr<OutputSurface> output_surface =
2853 FakeOutputSurface::Create3d(scoped_ptr<WebKit::WebGraphicsContext3D>(
2854 new PartialSwapContext)).PassAs<OutputSurface>();
2856 LayerTreeSettings settings;
2857 settings.partial_swap_enabled = partial_swap;
2858 scoped_ptr<LayerTreeHostImpl> my_host_impl =
2859 LayerTreeHostImpl::Create(settings, client, proxy, stats_instrumentation);
2860 my_host_impl->InitializeRenderer(output_surface.Pass());
2861 my_host_impl->SetViewportSize(gfx::Size(100, 100));
2864 Layers are created as follows:
2866 +--------------------+
2867 | 1 |
2868 | +-----------+ |
2869 | | 2 | |
2870 | | +-------------------+
2871 | | | 3 |
2872 | | +-------------------+
2873 | | | |
2874 | +-----------+ |
2877 +--------------------+
2879 Layers 1, 2 have render surfaces
2881 scoped_ptr<LayerImpl> root =
2882 LayerImpl::Create(my_host_impl->active_tree(), 1);
2883 scoped_ptr<LayerImpl> child =
2884 LayerImpl::Create(my_host_impl->active_tree(), 2);
2885 scoped_ptr<LayerImpl> grand_child =
2886 FakeLayerWithQuads::Create(my_host_impl->active_tree(), 3);
2888 gfx::Rect root_rect(0, 0, 100, 100);
2889 gfx::Rect child_rect(10, 10, 50, 50);
2890 gfx::Rect grand_child_rect(5, 5, 150, 150);
2892 root->CreateRenderSurface();
2893 root->SetAnchorPoint(gfx::PointF());
2894 root->SetPosition(root_rect.origin());
2895 root->SetBounds(root_rect.size());
2896 root->SetContentBounds(root->bounds());
2897 root->draw_properties().visible_content_rect = root_rect;
2898 root->SetDrawsContent(false);
2899 root->render_surface()->SetContentRect(gfx::Rect(root_rect.size()));
2901 child->SetAnchorPoint(gfx::PointF());
2902 child->SetPosition(gfx::PointF(child_rect.x(), child_rect.y()));
2903 child->SetOpacity(0.5f);
2904 child->SetBounds(gfx::Size(child_rect.width(), child_rect.height()));
2905 child->SetContentBounds(child->bounds());
2906 child->draw_properties().visible_content_rect = child_rect;
2907 child->SetDrawsContent(false);
2908 child->SetForceRenderSurface(true);
2910 grand_child->SetAnchorPoint(gfx::PointF());
2911 grand_child->SetPosition(grand_child_rect.origin());
2912 grand_child->SetBounds(grand_child_rect.size());
2913 grand_child->SetContentBounds(grand_child->bounds());
2914 grand_child->draw_properties().visible_content_rect = grand_child_rect;
2915 grand_child->SetDrawsContent(true);
2917 child->AddChild(grand_child.Pass());
2918 root->AddChild(child.Pass());
2920 my_host_impl->active_tree()->SetRootLayer(root.Pass());
2921 return my_host_impl.Pass();
2924 TEST_F(LayerTreeHostImplTest, ContributingLayerEmptyScissorPartialSwap) {
2925 scoped_ptr<LayerTreeHostImpl> my_host_impl =
2926 SetupLayersForOpacity(true, this, &proxy_, &stats_instrumentation_);
2928 LayerTreeHostImpl::FrameData frame;
2929 EXPECT_TRUE(my_host_impl->PrepareToDraw(&frame, gfx::Rect()));
2931 // Verify all quads have been computed
2932 ASSERT_EQ(2U, frame.render_passes.size());
2933 ASSERT_EQ(1U, frame.render_passes[0]->quad_list.size());
2934 ASSERT_EQ(1U, frame.render_passes[1]->quad_list.size());
2935 EXPECT_EQ(DrawQuad::SOLID_COLOR,
2936 frame.render_passes[0]->quad_list[0]->material);
2937 EXPECT_EQ(DrawQuad::RENDER_PASS,
2938 frame.render_passes[1]->quad_list[0]->material);
2940 my_host_impl->DrawLayers(&frame, base::TimeTicks::Now());
2941 my_host_impl->DidDrawAllLayers(frame);
2945 TEST_F(LayerTreeHostImplTest, ContributingLayerEmptyScissorNoPartialSwap) {
2946 scoped_ptr<LayerTreeHostImpl> my_host_impl =
2947 SetupLayersForOpacity(false, this, &proxy_, &stats_instrumentation_);
2949 LayerTreeHostImpl::FrameData frame;
2950 EXPECT_TRUE(my_host_impl->PrepareToDraw(&frame, gfx::Rect()));
2952 // Verify all quads have been computed
2953 ASSERT_EQ(2U, frame.render_passes.size());
2954 ASSERT_EQ(1U, frame.render_passes[0]->quad_list.size());
2955 ASSERT_EQ(1U, frame.render_passes[1]->quad_list.size());
2956 EXPECT_EQ(DrawQuad::SOLID_COLOR,
2957 frame.render_passes[0]->quad_list[0]->material);
2958 EXPECT_EQ(DrawQuad::RENDER_PASS,
2959 frame.render_passes[1]->quad_list[0]->material);
2961 my_host_impl->DrawLayers(&frame, base::TimeTicks::Now());
2962 my_host_impl->DidDrawAllLayers(frame);
2966 // Fake WebKit::WebGraphicsContext3D that tracks the number of textures in use.
2967 class TrackingWebGraphicsContext3D : public TestWebGraphicsContext3D {
2968 public:
2969 TrackingWebGraphicsContext3D()
2970 : TestWebGraphicsContext3D(),
2971 num_textures_(0) {}
2973 virtual WebKit::WebGLId createTexture() OVERRIDE {
2974 WebKit::WebGLId id = TestWebGraphicsContext3D::createTexture();
2976 textures_[id] = true;
2977 ++num_textures_;
2978 return id;
2981 virtual void deleteTexture(WebKit::WebGLId id) OVERRIDE {
2982 if (textures_.find(id) == textures_.end())
2983 return;
2985 textures_[id] = false;
2986 --num_textures_;
2989 virtual WebKit::WebString getString(WebKit::WGC3Denum name) OVERRIDE {
2990 if (name == GL_EXTENSIONS) {
2991 return WebKit::WebString(
2992 "GL_CHROMIUM_iosurface GL_ARB_texture_rectangle");
2995 return WebKit::WebString();
2998 unsigned num_textures() const { return num_textures_; }
3000 private:
3001 base::hash_map<WebKit::WebGLId, bool> textures_;
3002 unsigned num_textures_;
3005 TEST_F(LayerTreeHostImplTest, LayersFreeTextures) {
3006 scoped_ptr<TestWebGraphicsContext3D> context =
3007 TestWebGraphicsContext3D::Create();
3008 TestWebGraphicsContext3D* context3d = context.get();
3009 scoped_ptr<OutputSurface> output_surface = FakeOutputSurface::Create3d(
3010 context.PassAs<WebKit::WebGraphicsContext3D>()).PassAs<OutputSurface>();
3011 host_impl_->InitializeRenderer(output_surface.Pass());
3013 scoped_ptr<LayerImpl> root_layer =
3014 LayerImpl::Create(host_impl_->active_tree(), 1);
3015 root_layer->SetBounds(gfx::Size(10, 10));
3016 root_layer->SetAnchorPoint(gfx::PointF());
3018 scoped_refptr<VideoFrame> softwareFrame =
3019 media::VideoFrame::CreateColorFrame(
3020 gfx::Size(4, 4), 0x80, 0x80, 0x80, base::TimeDelta());
3021 FakeVideoFrameProvider provider;
3022 provider.set_frame(softwareFrame);
3023 scoped_ptr<VideoLayerImpl> video_layer =
3024 VideoLayerImpl::Create(host_impl_->active_tree(), 4, &provider);
3025 video_layer->SetBounds(gfx::Size(10, 10));
3026 video_layer->SetAnchorPoint(gfx::PointF());
3027 video_layer->SetContentBounds(gfx::Size(10, 10));
3028 video_layer->SetDrawsContent(true);
3029 root_layer->AddChild(video_layer.PassAs<LayerImpl>());
3031 scoped_ptr<IOSurfaceLayerImpl> io_surface_layer =
3032 IOSurfaceLayerImpl::Create(host_impl_->active_tree(), 5);
3033 io_surface_layer->SetBounds(gfx::Size(10, 10));
3034 io_surface_layer->SetAnchorPoint(gfx::PointF());
3035 io_surface_layer->SetContentBounds(gfx::Size(10, 10));
3036 io_surface_layer->SetDrawsContent(true);
3037 io_surface_layer->SetIOSurfaceProperties(1, gfx::Size(10, 10));
3038 root_layer->AddChild(io_surface_layer.PassAs<LayerImpl>());
3040 host_impl_->active_tree()->SetRootLayer(root_layer.Pass());
3042 EXPECT_EQ(0u, context3d->NumTextures());
3044 LayerTreeHostImpl::FrameData frame;
3045 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
3046 host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
3047 host_impl_->DidDrawAllLayers(frame);
3048 host_impl_->SwapBuffers(frame);
3050 EXPECT_GT(context3d->NumTextures(), 0u);
3052 // Kill the layer tree.
3053 host_impl_->active_tree()->SetRootLayer(
3054 LayerImpl::Create(host_impl_->active_tree(), 100));
3055 // There should be no textures left in use after.
3056 EXPECT_EQ(0u, context3d->NumTextures());
3059 class MockDrawQuadsToFillScreenContext : public TestWebGraphicsContext3D {
3060 public:
3061 MOCK_METHOD1(useProgram, void(WebKit::WebGLId program));
3062 MOCK_METHOD4(drawElements, void(WebKit::WGC3Denum mode,
3063 WebKit::WGC3Dsizei count,
3064 WebKit::WGC3Denum type,
3065 WebKit::WGC3Dintptr offset));
3068 TEST_F(LayerTreeHostImplTest, HasTransparentBackground) {
3069 scoped_ptr<OutputSurface> output_surface =
3070 FakeOutputSurface::Create3d(scoped_ptr<WebKit::WebGraphicsContext3D>(
3071 new MockDrawQuadsToFillScreenContext)).PassAs<OutputSurface>();
3072 MockDrawQuadsToFillScreenContext* mock_context =
3073 static_cast<MockDrawQuadsToFillScreenContext*>(
3074 output_surface->context3d());
3076 // Run test case
3077 CreateLayerTreeHost(false, output_surface.Pass());
3078 SetupRootLayerImpl(LayerImpl::Create(host_impl_->active_tree(), 1));
3079 host_impl_->active_tree()->set_background_color(SK_ColorWHITE);
3081 // Verify one quad is drawn when transparent background set is not set.
3082 host_impl_->active_tree()->set_has_transparent_background(false);
3083 EXPECT_CALL(*mock_context, useProgram(_))
3084 .Times(1);
3085 EXPECT_CALL(*mock_context, drawElements(_, _, _, _))
3086 .Times(1);
3087 LayerTreeHostImpl::FrameData frame;
3088 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
3089 host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
3090 host_impl_->DidDrawAllLayers(frame);
3091 Mock::VerifyAndClearExpectations(&mock_context);
3093 // Verify no quads are drawn when transparent background is set.
3094 host_impl_->active_tree()->set_has_transparent_background(true);
3095 host_impl_->SetFullRootLayerDamage();
3096 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
3097 host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
3098 host_impl_->DidDrawAllLayers(frame);
3099 Mock::VerifyAndClearExpectations(&mock_context);
3102 static void AddDrawingLayerTo(LayerImpl* parent,
3103 int id,
3104 gfx::Rect layer_rect,
3105 LayerImpl** result) {
3106 scoped_ptr<LayerImpl> layer =
3107 FakeLayerWithQuads::Create(parent->layer_tree_impl(), id);
3108 LayerImpl* layer_ptr = layer.get();
3109 layer_ptr->SetAnchorPoint(gfx::PointF());
3110 layer_ptr->SetPosition(gfx::PointF(layer_rect.origin()));
3111 layer_ptr->SetBounds(layer_rect.size());
3112 layer_ptr->SetContentBounds(layer_rect.size());
3113 layer_ptr->SetDrawsContent(true); // only children draw content
3114 layer_ptr->SetContentsOpaque(true);
3115 parent->AddChild(layer.Pass());
3116 if (result)
3117 *result = layer_ptr;
3120 static void SetupLayersForTextureCaching(
3121 LayerTreeHostImpl* layer_tree_host_impl,
3122 LayerImpl*& root_ptr,
3123 LayerImpl*& intermediate_layer_ptr,
3124 LayerImpl*& surface_layer_ptr,
3125 LayerImpl*& child_ptr,
3126 gfx::Size root_size) {
3127 scoped_ptr<OutputSurface> output_surface =
3128 FakeOutputSurface::Create3d(scoped_ptr<WebKit::WebGraphicsContext3D>(
3129 new PartialSwapContext)).PassAs<OutputSurface>();
3131 layer_tree_host_impl->InitializeRenderer(output_surface.Pass());
3132 layer_tree_host_impl->SetViewportSize(root_size);
3134 scoped_ptr<LayerImpl> root =
3135 LayerImpl::Create(layer_tree_host_impl->active_tree(), 1);
3136 root_ptr = root.get();
3138 root->SetAnchorPoint(gfx::PointF());
3139 root->SetPosition(gfx::PointF());
3140 root->SetBounds(root_size);
3141 root->SetContentBounds(root_size);
3142 root->SetDrawsContent(true);
3143 layer_tree_host_impl->active_tree()->SetRootLayer(root.Pass());
3145 AddDrawingLayerTo(root_ptr,
3147 gfx::Rect(10, 10, root_size.width(), root_size.height()),
3148 &intermediate_layer_ptr);
3149 // Only children draw content.
3150 intermediate_layer_ptr->SetDrawsContent(false);
3152 // Surface layer is the layer that changes its opacity
3153 // It will contain other layers that draw content.
3154 AddDrawingLayerTo(intermediate_layer_ptr,
3156 gfx::Rect(10, 10, root_size.width(), root_size.height()),
3157 &surface_layer_ptr);
3158 // Only children draw content.
3159 surface_layer_ptr->SetDrawsContent(false);
3160 surface_layer_ptr->SetOpacity(0.5f);
3161 surface_layer_ptr->SetForceRenderSurface(true);
3163 // Child of the surface layer will produce some quads
3164 AddDrawingLayerTo(surface_layer_ptr,
3166 gfx::Rect(5,
3168 root_size.width() - 25,
3169 root_size.height() - 25),
3170 &child_ptr);
3173 class GLRendererWithReleaseTextures : public GLRenderer {
3174 public:
3175 using GLRenderer::ReleaseRenderPassTextures;
3178 TEST_F(LayerTreeHostImplTest, TextureCachingWithOcclusion) {
3179 LayerTreeSettings settings;
3180 settings.minimum_occlusion_tracking_size = gfx::Size();
3181 settings.cache_render_pass_contents = true;
3182 scoped_ptr<LayerTreeHostImpl> my_host_impl =
3183 LayerTreeHostImpl::Create(settings,
3184 this,
3185 &proxy_,
3186 &stats_instrumentation_);
3188 // Layers are structure as follows:
3190 // R +-- S1 +- L10 (owning)
3191 // | +- L11
3192 // | +- L12
3193 // |
3194 // +-- S2 +- L20 (owning)
3195 // +- L21
3197 // Occlusion:
3198 // L12 occludes L11 (internal)
3199 // L20 occludes L10 (external)
3200 // L21 occludes L20 (internal)
3202 LayerImpl* root_ptr;
3203 LayerImpl* layer_s1_ptr;
3204 LayerImpl* layer_s2_ptr;
3206 scoped_ptr<OutputSurface> output_surface =
3207 FakeOutputSurface::Create3d(scoped_ptr<WebKit::WebGraphicsContext3D>(
3208 new PartialSwapContext)).PassAs<OutputSurface>();
3210 gfx::Size root_size(1000, 1000);
3212 my_host_impl->InitializeRenderer(output_surface.Pass());
3213 my_host_impl->SetViewportSize(root_size);
3215 scoped_ptr<LayerImpl> root =
3216 LayerImpl::Create(my_host_impl->active_tree(), 1);
3217 root_ptr = root.get();
3219 root->SetAnchorPoint(gfx::PointF());
3220 root->SetPosition(gfx::PointF());
3221 root->SetBounds(root_size);
3222 root->SetContentBounds(root_size);
3223 root->SetDrawsContent(true);
3224 root->SetMasksToBounds(true);
3225 my_host_impl->active_tree()->SetRootLayer(root.Pass());
3227 AddDrawingLayerTo(root_ptr, 2, gfx::Rect(300, 300, 300, 300), &layer_s1_ptr);
3228 layer_s1_ptr->SetForceRenderSurface(true);
3230 AddDrawingLayerTo(layer_s1_ptr, 3, gfx::Rect(10, 10, 10, 10), 0); // L11
3231 AddDrawingLayerTo(layer_s1_ptr, 4, gfx::Rect(0, 0, 30, 30), 0); // L12
3233 AddDrawingLayerTo(root_ptr, 5, gfx::Rect(550, 250, 300, 400), &layer_s2_ptr);
3234 layer_s2_ptr->SetForceRenderSurface(true);
3236 AddDrawingLayerTo(layer_s2_ptr, 6, gfx::Rect(20, 20, 5, 5), 0); // L21
3238 // Initial draw - must receive all quads
3240 LayerTreeHostImpl::FrameData frame;
3241 EXPECT_TRUE(my_host_impl->PrepareToDraw(&frame, gfx::Rect()));
3243 // Must receive 3 render passes.
3244 // For Root, there are 2 quads; for S1, there are 2 quads (1 is occluded);
3245 // for S2, there is 2 quads.
3246 ASSERT_EQ(3U, frame.render_passes.size());
3248 EXPECT_EQ(2U, frame.render_passes[0]->quad_list.size());
3249 EXPECT_EQ(2U, frame.render_passes[1]->quad_list.size());
3250 EXPECT_EQ(2U, frame.render_passes[2]->quad_list.size());
3252 my_host_impl->DrawLayers(&frame, base::TimeTicks::Now());
3253 my_host_impl->DidDrawAllLayers(frame);
3256 // "Unocclude" surface S1 and repeat draw.
3257 // Must remove S2's render pass since it's cached;
3258 // Must keep S1 quads because texture contained external occlusion.
3259 gfx::Transform transform = layer_s2_ptr->transform();
3260 transform.Translate(150.0, 150.0);
3261 layer_s2_ptr->SetTransform(transform);
3263 LayerTreeHostImpl::FrameData frame;
3264 EXPECT_TRUE(my_host_impl->PrepareToDraw(&frame, gfx::Rect()));
3266 // Must receive 2 render passes.
3267 // For Root, there are 2 quads
3268 // For S1, the number of quads depends on what got unoccluded, so not
3269 // asserted beyond being positive.
3270 // For S2, there is no render pass
3271 ASSERT_EQ(2U, frame.render_passes.size());
3273 EXPECT_GT(frame.render_passes[0]->quad_list.size(), 0U);
3274 EXPECT_EQ(2U, frame.render_passes[1]->quad_list.size());
3276 my_host_impl->DrawLayers(&frame, base::TimeTicks::Now());
3277 my_host_impl->DidDrawAllLayers(frame);
3280 // "Re-occlude" surface S1 and repeat draw.
3281 // Must remove S1's render pass since it is now available in full.
3282 // S2 has no change so must also be removed.
3283 transform = layer_s2_ptr->transform();
3284 transform.Translate(-15.0, -15.0);
3285 layer_s2_ptr->SetTransform(transform);
3287 LayerTreeHostImpl::FrameData frame;
3288 EXPECT_TRUE(my_host_impl->PrepareToDraw(&frame, gfx::Rect()));
3290 // Must receive 1 render pass - for the root.
3291 ASSERT_EQ(1U, frame.render_passes.size());
3293 EXPECT_EQ(2U, frame.render_passes[0]->quad_list.size());
3295 my_host_impl->DrawLayers(&frame, base::TimeTicks::Now());
3296 my_host_impl->DidDrawAllLayers(frame);
3300 TEST_F(LayerTreeHostImplTest, TextureCachingWithOcclusionEarlyOut) {
3301 LayerTreeSettings settings;
3302 settings.minimum_occlusion_tracking_size = gfx::Size();
3303 settings.cache_render_pass_contents = true;
3304 scoped_ptr<LayerTreeHostImpl> my_host_impl =
3305 LayerTreeHostImpl::Create(settings,
3306 this,
3307 &proxy_,
3308 &stats_instrumentation_);
3310 // Layers are structure as follows:
3312 // R +-- S1 +- L10 (owning, non drawing)
3313 // | +- L11 (corner, unoccluded)
3314 // | +- L12 (corner, unoccluded)
3315 // | +- L13 (corner, unoccluded)
3316 // | +- L14 (corner, entirely occluded)
3317 // |
3318 // +-- S2 +- L20 (owning, drawing)
3321 LayerImpl* root_ptr;
3322 LayerImpl* layer_s1_ptr;
3323 LayerImpl* layer_s2_ptr;
3325 scoped_ptr<OutputSurface> output_surface =
3326 FakeOutputSurface::Create3d(scoped_ptr<WebKit::WebGraphicsContext3D>(
3327 new PartialSwapContext)).PassAs<OutputSurface>();
3329 gfx::Size root_size(1000, 1000);
3331 my_host_impl->InitializeRenderer(output_surface.Pass());
3332 my_host_impl->SetViewportSize(root_size);
3334 scoped_ptr<LayerImpl> root =
3335 LayerImpl::Create(my_host_impl->active_tree(), 1);
3336 root_ptr = root.get();
3338 root->SetAnchorPoint(gfx::PointF());
3339 root->SetPosition(gfx::PointF());
3340 root->SetBounds(root_size);
3341 root->SetContentBounds(root_size);
3342 root->SetDrawsContent(true);
3343 root->SetMasksToBounds(true);
3344 my_host_impl->active_tree()->SetRootLayer(root.Pass());
3346 AddDrawingLayerTo(root_ptr, 2, gfx::Rect(0, 0, 800, 800), &layer_s1_ptr);
3347 layer_s1_ptr->SetForceRenderSurface(true);
3348 layer_s1_ptr->SetDrawsContent(false);
3350 AddDrawingLayerTo(layer_s1_ptr, 3, gfx::Rect(0, 0, 300, 300), 0); // L11
3351 AddDrawingLayerTo(layer_s1_ptr, 4, gfx::Rect(0, 500, 300, 300), 0); // L12
3352 AddDrawingLayerTo(layer_s1_ptr, 5, gfx::Rect(500, 0, 300, 300), 0); // L13
3353 AddDrawingLayerTo(layer_s1_ptr, 6, gfx::Rect(500, 500, 300, 300), 0); // L14
3354 AddDrawingLayerTo(layer_s1_ptr, 9, gfx::Rect(500, 500, 300, 300), 0); // L14
3356 AddDrawingLayerTo(root_ptr, 7, gfx::Rect(450, 450, 450, 450), &layer_s2_ptr);
3357 layer_s2_ptr->SetForceRenderSurface(true);
3359 // Initial draw - must receive all quads
3361 LayerTreeHostImpl::FrameData frame;
3362 EXPECT_TRUE(my_host_impl->PrepareToDraw(&frame, gfx::Rect()));
3364 // Must receive 3 render passes.
3365 // For Root, there are 2 quads; for S1, there are 3 quads; for S2, there is
3366 // 1 quad.
3367 ASSERT_EQ(3U, frame.render_passes.size());
3369 EXPECT_EQ(1U, frame.render_passes[0]->quad_list.size());
3371 // L14 is culled, so only 3 quads.
3372 EXPECT_EQ(3U, frame.render_passes[1]->quad_list.size());
3373 EXPECT_EQ(2U, frame.render_passes[2]->quad_list.size());
3375 my_host_impl->DrawLayers(&frame, base::TimeTicks::Now());
3376 my_host_impl->DidDrawAllLayers(frame);
3379 // "Unocclude" surface S1 and repeat draw.
3380 // Must remove S2's render pass since it's cached;
3381 // Must keep S1 quads because texture contained external occlusion.
3382 gfx::Transform transform = layer_s2_ptr->transform();
3383 transform.Translate(100.0, 100.0);
3384 layer_s2_ptr->SetTransform(transform);
3386 LayerTreeHostImpl::FrameData frame;
3387 EXPECT_TRUE(my_host_impl->PrepareToDraw(&frame, gfx::Rect()));
3389 // Must receive 2 render passes.
3390 // For Root, there are 2 quads
3391 // For S1, the number of quads depends on what got unoccluded, so not
3392 // asserted beyond being positive.
3393 // For S2, there is no render pass
3394 ASSERT_EQ(2U, frame.render_passes.size());
3396 EXPECT_GT(frame.render_passes[0]->quad_list.size(), 0U);
3397 EXPECT_EQ(2U, frame.render_passes[1]->quad_list.size());
3399 my_host_impl->DrawLayers(&frame, base::TimeTicks::Now());
3400 my_host_impl->DidDrawAllLayers(frame);
3403 // "Re-occlude" surface S1 and repeat draw.
3404 // Must remove S1's render pass since it is now available in full.
3405 // S2 has no change so must also be removed.
3406 transform = layer_s2_ptr->transform();
3407 transform.Translate(-15.0, -15.0);
3408 layer_s2_ptr->SetTransform(transform);
3410 LayerTreeHostImpl::FrameData frame;
3411 EXPECT_TRUE(my_host_impl->PrepareToDraw(&frame, gfx::Rect()));
3413 // Must receive 1 render pass - for the root.
3414 ASSERT_EQ(1U, frame.render_passes.size());
3416 EXPECT_EQ(2U, frame.render_passes[0]->quad_list.size());
3418 my_host_impl->DrawLayers(&frame, base::TimeTicks::Now());
3419 my_host_impl->DidDrawAllLayers(frame);
3423 TEST_F(LayerTreeHostImplTest, TextureCachingWithOcclusionExternalOverInternal) {
3424 LayerTreeSettings settings;
3425 settings.minimum_occlusion_tracking_size = gfx::Size();
3426 settings.cache_render_pass_contents = true;
3427 scoped_ptr<LayerTreeHostImpl> my_host_impl =
3428 LayerTreeHostImpl::Create(settings,
3429 this,
3430 &proxy_,
3431 &stats_instrumentation_);
3433 // Layers are structured as follows:
3435 // R +-- S1 +- L10 (owning, drawing)
3436 // | +- L11 (corner, occluded by L12)
3437 // | +- L12 (opposite corner)
3438 // |
3439 // +-- S2 +- L20 (owning, drawing)
3442 LayerImpl* root_ptr;
3443 LayerImpl* layer_s1_ptr;
3444 LayerImpl* layer_s2_ptr;
3446 scoped_ptr<OutputSurface> output_surface =
3447 FakeOutputSurface::Create3d(scoped_ptr<WebKit::WebGraphicsContext3D>(
3448 new PartialSwapContext)).PassAs<OutputSurface>();
3450 gfx::Size root_size(1000, 1000);
3452 my_host_impl->InitializeRenderer(output_surface.Pass());
3453 my_host_impl->SetViewportSize(root_size);
3455 scoped_ptr<LayerImpl> root =
3456 LayerImpl::Create(my_host_impl->active_tree(), 1);
3457 root_ptr = root.get();
3459 root->SetAnchorPoint(gfx::PointF());
3460 root->SetPosition(gfx::PointF());
3461 root->SetBounds(root_size);
3462 root->SetContentBounds(root_size);
3463 root->SetDrawsContent(true);
3464 root->SetMasksToBounds(true);
3465 my_host_impl->active_tree()->SetRootLayer(root.Pass());
3467 AddDrawingLayerTo(root_ptr, 2, gfx::Rect(0, 0, 400, 400), &layer_s1_ptr);
3468 layer_s1_ptr->SetForceRenderSurface(true);
3470 AddDrawingLayerTo(layer_s1_ptr, 3, gfx::Rect(0, 0, 300, 300), 0); // L11
3471 AddDrawingLayerTo(layer_s1_ptr, 4, gfx::Rect(100, 0, 300, 300), 0); // L12
3473 AddDrawingLayerTo(root_ptr, 7, gfx::Rect(200, 0, 300, 300), &layer_s2_ptr);
3474 layer_s2_ptr->SetForceRenderSurface(true);
3476 // Initial draw - must receive all quads
3478 LayerTreeHostImpl::FrameData frame;
3479 EXPECT_TRUE(my_host_impl->PrepareToDraw(&frame, gfx::Rect()));
3481 // Must receive 3 render passes.
3482 // For Root, there are 2 quads; for S1, there are 3 quads; for S2, there is
3483 // 1 quad.
3484 ASSERT_EQ(3U, frame.render_passes.size());
3486 EXPECT_EQ(1U, frame.render_passes[0]->quad_list.size());
3487 EXPECT_EQ(3U, frame.render_passes[1]->quad_list.size());
3488 EXPECT_EQ(2U, frame.render_passes[2]->quad_list.size());
3490 my_host_impl->DrawLayers(&frame, base::TimeTicks::Now());
3491 my_host_impl->DidDrawAllLayers(frame);
3494 // "Unocclude" surface S1 and repeat draw.
3495 // Must remove S2's render pass since it's cached;
3496 // Must keep S1 quads because texture contained external occlusion.
3497 gfx::Transform transform = layer_s2_ptr->transform();
3498 transform.Translate(300.0, 0.0);
3499 layer_s2_ptr->SetTransform(transform);
3501 LayerTreeHostImpl::FrameData frame;
3502 EXPECT_TRUE(my_host_impl->PrepareToDraw(&frame, gfx::Rect()));
3504 // Must receive 2 render passes.
3505 // For Root, there are 2 quads
3506 // For S1, the number of quads depends on what got unoccluded, so not
3507 // asserted beyond being positive.
3508 // For S2, there is no render pass
3509 ASSERT_EQ(2U, frame.render_passes.size());
3511 EXPECT_GT(frame.render_passes[0]->quad_list.size(), 0U);
3512 EXPECT_EQ(2U, frame.render_passes[1]->quad_list.size());
3514 my_host_impl->DrawLayers(&frame, base::TimeTicks::Now());
3515 my_host_impl->DidDrawAllLayers(frame);
3519 TEST_F(LayerTreeHostImplTest, TextureCachingWithOcclusionExternalNotAligned) {
3520 LayerTreeSettings settings;
3521 settings.cache_render_pass_contents = true;
3522 scoped_ptr<LayerTreeHostImpl> my_host_impl =
3523 LayerTreeHostImpl::Create(settings,
3524 this,
3525 &proxy_,
3526 &stats_instrumentation_);
3528 // Layers are structured as follows:
3530 // R +-- S1 +- L10 (rotated, drawing)
3531 // +- L11 (occupies half surface)
3533 LayerImpl* root_ptr;
3534 LayerImpl* layer_s1_ptr;
3536 scoped_ptr<OutputSurface> output_surface =
3537 FakeOutputSurface::Create3d(scoped_ptr<WebKit::WebGraphicsContext3D>(
3538 new PartialSwapContext)).PassAs<OutputSurface>();
3540 gfx::Size root_size(1000, 1000);
3542 my_host_impl->InitializeRenderer(output_surface.Pass());
3543 my_host_impl->SetViewportSize(root_size);
3545 scoped_ptr<LayerImpl> root =
3546 LayerImpl::Create(my_host_impl->active_tree(), 1);
3547 root_ptr = root.get();
3549 root->SetAnchorPoint(gfx::PointF());
3550 root->SetPosition(gfx::PointF());
3551 root->SetBounds(root_size);
3552 root->SetContentBounds(root_size);
3553 root->SetDrawsContent(true);
3554 root->SetMasksToBounds(true);
3555 my_host_impl->active_tree()->SetRootLayer(root.Pass());
3557 AddDrawingLayerTo(root_ptr, 2, gfx::Rect(0, 0, 400, 400), &layer_s1_ptr);
3558 layer_s1_ptr->SetForceRenderSurface(true);
3559 gfx::Transform transform = layer_s1_ptr->transform();
3560 transform.Translate(200.0, 200.0);
3561 transform.Rotate(45.0);
3562 transform.Translate(-200.0, -200.0);
3563 layer_s1_ptr->SetTransform(transform);
3565 AddDrawingLayerTo(layer_s1_ptr, 3, gfx::Rect(200, 0, 200, 400), 0); // L11
3567 // Initial draw - must receive all quads
3569 LayerTreeHostImpl::FrameData frame;
3570 EXPECT_TRUE(my_host_impl->PrepareToDraw(&frame, gfx::Rect()));
3572 // Must receive 2 render passes.
3573 ASSERT_EQ(2U, frame.render_passes.size());
3575 EXPECT_EQ(2U, frame.render_passes[0]->quad_list.size());
3576 EXPECT_EQ(1U, frame.render_passes[1]->quad_list.size());
3578 my_host_impl->DrawLayers(&frame, base::TimeTicks::Now());
3579 my_host_impl->DidDrawAllLayers(frame);
3582 // Change opacity and draw. Verify we used cached texture.
3583 layer_s1_ptr->SetOpacity(0.2f);
3585 LayerTreeHostImpl::FrameData frame;
3586 EXPECT_TRUE(my_host_impl->PrepareToDraw(&frame, gfx::Rect()));
3588 // One render pass must be gone due to cached texture.
3589 ASSERT_EQ(1U, frame.render_passes.size());
3591 EXPECT_EQ(1U, frame.render_passes[0]->quad_list.size());
3593 my_host_impl->DrawLayers(&frame, base::TimeTicks::Now());
3594 my_host_impl->DidDrawAllLayers(frame);
3598 TEST_F(LayerTreeHostImplTest, TextureCachingWithOcclusionPartialSwap) {
3599 LayerTreeSettings settings;
3600 settings.minimum_occlusion_tracking_size = gfx::Size();
3601 settings.partial_swap_enabled = true;
3602 settings.cache_render_pass_contents = true;
3603 scoped_ptr<LayerTreeHostImpl> my_host_impl =
3604 LayerTreeHostImpl::Create(settings,
3605 this,
3606 &proxy_,
3607 &stats_instrumentation_);
3609 // Layers are structure as follows:
3611 // R +-- S1 +- L10 (owning)
3612 // | +- L11
3613 // | +- L12
3614 // |
3615 // +-- S2 +- L20 (owning)
3616 // +- L21
3618 // Occlusion:
3619 // L12 occludes L11 (internal)
3620 // L20 occludes L10 (external)
3621 // L21 occludes L20 (internal)
3623 LayerImpl* root_ptr;
3624 LayerImpl* layer_s1_ptr;
3625 LayerImpl* layer_s2_ptr;
3627 scoped_ptr<OutputSurface> output_surface =
3628 FakeOutputSurface::Create3d(scoped_ptr<WebKit::WebGraphicsContext3D>(
3629 new PartialSwapContext)).PassAs<OutputSurface>();
3631 gfx::Size root_size(1000, 1000);
3633 my_host_impl->InitializeRenderer(output_surface.Pass());
3634 my_host_impl->SetViewportSize(root_size);
3636 scoped_ptr<LayerImpl> root =
3637 LayerImpl::Create(my_host_impl->active_tree(), 1);
3638 root_ptr = root.get();
3640 root->SetAnchorPoint(gfx::PointF());
3641 root->SetPosition(gfx::PointF());
3642 root->SetBounds(root_size);
3643 root->SetContentBounds(root_size);
3644 root->SetDrawsContent(true);
3645 root->SetMasksToBounds(true);
3646 my_host_impl->active_tree()->SetRootLayer(root.Pass());
3648 AddDrawingLayerTo(root_ptr, 2, gfx::Rect(300, 300, 300, 300), &layer_s1_ptr);
3649 layer_s1_ptr->SetForceRenderSurface(true);
3651 AddDrawingLayerTo(layer_s1_ptr, 3, gfx::Rect(10, 10, 10, 10), 0); // L11
3652 AddDrawingLayerTo(layer_s1_ptr, 4, gfx::Rect(0, 0, 30, 30), 0); // L12
3654 AddDrawingLayerTo(root_ptr, 5, gfx::Rect(550, 250, 300, 400), &layer_s2_ptr);
3655 layer_s2_ptr->SetForceRenderSurface(true);
3657 AddDrawingLayerTo(layer_s2_ptr, 6, gfx::Rect(20, 20, 5, 5), 0); // L21
3659 // Initial draw - must receive all quads
3661 LayerTreeHostImpl::FrameData frame;
3662 EXPECT_TRUE(my_host_impl->PrepareToDraw(&frame, gfx::Rect()));
3664 // Must receive 3 render passes.
3665 // For Root, there are 2 quads; for S1, there are 2 quads (one is occluded);
3666 // for S2, there is 2 quads.
3667 ASSERT_EQ(3U, frame.render_passes.size());
3669 EXPECT_EQ(2U, frame.render_passes[0]->quad_list.size());
3670 EXPECT_EQ(2U, frame.render_passes[1]->quad_list.size());
3671 EXPECT_EQ(2U, frame.render_passes[2]->quad_list.size());
3673 my_host_impl->DrawLayers(&frame, base::TimeTicks::Now());
3674 my_host_impl->DidDrawAllLayers(frame);
3677 // "Unocclude" surface S1 and repeat draw.
3678 // Must remove S2's render pass since it's cached;
3679 // Must keep S1 quads because texture contained external occlusion.
3680 gfx::Transform transform = layer_s2_ptr->transform();
3681 transform.Translate(150.0, 150.0);
3682 layer_s2_ptr->SetTransform(transform);
3684 LayerTreeHostImpl::FrameData frame;
3685 EXPECT_TRUE(my_host_impl->PrepareToDraw(&frame, gfx::Rect()));
3687 // Must receive 2 render passes.
3688 // For Root, there are 2 quads.
3689 // For S1, there are 2 quads.
3690 // For S2, there is no render pass
3691 ASSERT_EQ(2U, frame.render_passes.size());
3693 EXPECT_EQ(2U, frame.render_passes[0]->quad_list.size());
3694 EXPECT_EQ(2U, frame.render_passes[1]->quad_list.size());
3696 my_host_impl->DrawLayers(&frame, base::TimeTicks::Now());
3697 my_host_impl->DidDrawAllLayers(frame);
3700 // "Re-occlude" surface S1 and repeat draw.
3701 // Must remove S1's render pass since it is now available in full.
3702 // S2 has no change so must also be removed.
3703 transform = layer_s2_ptr->transform();
3704 transform.Translate(-15.0, -15.0);
3705 layer_s2_ptr->SetTransform(transform);
3707 LayerTreeHostImpl::FrameData frame;
3708 EXPECT_TRUE(my_host_impl->PrepareToDraw(&frame, gfx::Rect()));
3710 // Root render pass only.
3711 ASSERT_EQ(1U, frame.render_passes.size());
3713 my_host_impl->DrawLayers(&frame, base::TimeTicks::Now());
3714 my_host_impl->DidDrawAllLayers(frame);
3718 TEST_F(LayerTreeHostImplTest, TextureCachingWithScissor) {
3719 LayerTreeSettings settings;
3720 settings.minimum_occlusion_tracking_size = gfx::Size();
3721 settings.cache_render_pass_contents = true;
3722 scoped_ptr<LayerTreeHostImpl> my_host_impl =
3723 LayerTreeHostImpl::Create(settings,
3724 this,
3725 &proxy_,
3726 &stats_instrumentation_);
3729 Layers are created as follows:
3731 +--------------------+
3732 | 1 |
3733 | +-----------+ |
3734 | | 2 | |
3735 | | +-------------------+
3736 | | | 3 |
3737 | | +-------------------+
3738 | | | |
3739 | +-----------+ |
3742 +--------------------+
3744 Layers 1, 2 have render surfaces
3746 scoped_ptr<LayerImpl> root =
3747 LayerImpl::Create(my_host_impl->active_tree(), 1);
3748 scoped_ptr<TiledLayerImpl> child =
3749 TiledLayerImpl::Create(my_host_impl->active_tree(), 2);
3750 scoped_ptr<LayerImpl> grand_child =
3751 LayerImpl::Create(my_host_impl->active_tree(), 3);
3753 gfx::Rect root_rect(0, 0, 100, 100);
3754 gfx::Rect child_rect(10, 10, 50, 50);
3755 gfx::Rect grand_child_rect(5, 5, 150, 150);
3757 scoped_ptr<OutputSurface> output_surface =
3758 FakeOutputSurface::Create3d(scoped_ptr<WebKit::WebGraphicsContext3D>(
3759 new PartialSwapContext)).PassAs<OutputSurface>();
3760 my_host_impl->InitializeRenderer(output_surface.Pass());
3762 root->SetAnchorPoint(gfx::PointF());
3763 root->SetPosition(gfx::PointF(root_rect.x(), root_rect.y()));
3764 root->SetBounds(gfx::Size(root_rect.width(), root_rect.height()));
3765 root->SetContentBounds(root->bounds());
3766 root->SetDrawsContent(true);
3767 root->SetMasksToBounds(true);
3769 child->SetAnchorPoint(gfx::PointF());
3770 child->SetPosition(gfx::PointF(child_rect.x(), child_rect.y()));
3771 child->SetOpacity(0.5f);
3772 child->SetBounds(gfx::Size(child_rect.width(), child_rect.height()));
3773 child->SetContentBounds(child->bounds());
3774 child->SetDrawsContent(true);
3775 child->set_skips_draw(false);
3777 // child layer has 10x10 tiles.
3778 scoped_ptr<LayerTilingData> tiler =
3779 LayerTilingData::Create(gfx::Size(10, 10),
3780 LayerTilingData::HAS_BORDER_TEXELS);
3781 tiler->SetBounds(child->content_bounds());
3782 child->SetTilingData(*tiler.get());
3784 grand_child->SetAnchorPoint(gfx::PointF());
3785 grand_child->SetPosition(grand_child_rect.origin());
3786 grand_child->SetBounds(grand_child_rect.size());
3787 grand_child->SetContentBounds(grand_child->bounds());
3788 grand_child->SetDrawsContent(true);
3790 TiledLayerImpl* child_ptr = child.get();
3791 RenderPass::Id child_pass_id(child_ptr->id(), 0);
3793 child->AddChild(grand_child.Pass());
3794 root->AddChild(child.PassAs<LayerImpl>());
3795 my_host_impl->active_tree()->SetRootLayer(root.Pass());
3796 my_host_impl->SetViewportSize(root_rect.size());
3798 EXPECT_FALSE(my_host_impl->renderer()->HaveCachedResourcesForRenderPassId(
3799 child_pass_id));
3801 LayerTreeHostImpl::FrameData frame;
3802 host_impl_->SetFullRootLayerDamage();
3803 EXPECT_TRUE(my_host_impl->PrepareToDraw(&frame, gfx::Rect()));
3804 my_host_impl->DrawLayers(&frame, base::TimeTicks::Now());
3805 my_host_impl->DidDrawAllLayers(frame);
3808 // We should have cached textures for surface 2.
3809 EXPECT_TRUE(my_host_impl->renderer()->HaveCachedResourcesForRenderPassId(
3810 child_pass_id));
3812 LayerTreeHostImpl::FrameData frame;
3813 host_impl_->SetFullRootLayerDamage();
3814 EXPECT_TRUE(my_host_impl->PrepareToDraw(&frame, gfx::Rect()));
3815 my_host_impl->DrawLayers(&frame, base::TimeTicks::Now());
3816 my_host_impl->DidDrawAllLayers(frame);
3819 // We should still have cached textures for surface 2 after drawing with no
3820 // damage.
3821 EXPECT_TRUE(my_host_impl->renderer()->HaveCachedResourcesForRenderPassId(
3822 child_pass_id));
3824 // Damage a single tile of surface 2.
3825 child_ptr->set_update_rect(gfx::Rect(10, 10, 10, 10));
3827 LayerTreeHostImpl::FrameData frame;
3828 host_impl_->SetFullRootLayerDamage();
3829 EXPECT_TRUE(my_host_impl->PrepareToDraw(&frame, gfx::Rect()));
3830 my_host_impl->DrawLayers(&frame, base::TimeTicks::Now());
3831 my_host_impl->DidDrawAllLayers(frame);
3834 // We should have a cached texture for surface 2 again even though it was
3835 // damaged.
3836 EXPECT_TRUE(my_host_impl->renderer()->HaveCachedResourcesForRenderPassId(
3837 child_pass_id));
3840 TEST_F(LayerTreeHostImplTest, SurfaceTextureCaching) {
3841 LayerTreeSettings settings;
3842 settings.minimum_occlusion_tracking_size = gfx::Size();
3843 settings.partial_swap_enabled = true;
3844 settings.cache_render_pass_contents = true;
3845 scoped_ptr<LayerTreeHostImpl> my_host_impl =
3846 LayerTreeHostImpl::Create(settings,
3847 this,
3848 &proxy_,
3849 &stats_instrumentation_);
3851 LayerImpl* root_ptr;
3852 LayerImpl* intermediate_layer_ptr;
3853 LayerImpl* surface_layer_ptr;
3854 LayerImpl* child_ptr;
3856 SetupLayersForTextureCaching(my_host_impl.get(),
3857 root_ptr,
3858 intermediate_layer_ptr,
3859 surface_layer_ptr,
3860 child_ptr,
3861 gfx::Size(100, 100));
3863 LayerTreeHostImpl::FrameData frame;
3864 EXPECT_TRUE(my_host_impl->PrepareToDraw(&frame, gfx::Rect()));
3866 // Must receive two render passes, each with one quad
3867 ASSERT_EQ(2U, frame.render_passes.size());
3868 EXPECT_EQ(1U, frame.render_passes[0]->quad_list.size());
3869 EXPECT_EQ(1U, frame.render_passes[1]->quad_list.size());
3871 EXPECT_EQ(DrawQuad::RENDER_PASS,
3872 frame.render_passes[1]->quad_list[0]->material);
3873 const RenderPassDrawQuad* quad =
3874 RenderPassDrawQuad::MaterialCast(frame.render_passes[1]->quad_list[0]);
3875 RenderPass* target_pass = frame.render_passes_by_id[quad->render_pass_id];
3876 ASSERT_TRUE(target_pass);
3877 EXPECT_FALSE(target_pass->damage_rect.IsEmpty());
3879 my_host_impl->DrawLayers(&frame, base::TimeTicks::Now());
3880 my_host_impl->DidDrawAllLayers(frame);
3883 // Draw without any change
3885 LayerTreeHostImpl::FrameData frame;
3886 my_host_impl->SetFullRootLayerDamage();
3887 EXPECT_TRUE(my_host_impl->PrepareToDraw(&frame, gfx::Rect()));
3889 // Must receive one render pass, as the other one should be culled
3890 ASSERT_EQ(1U, frame.render_passes.size());
3892 EXPECT_EQ(1U, frame.render_passes[0]->quad_list.size());
3893 EXPECT_EQ(DrawQuad::RENDER_PASS,
3894 frame.render_passes[0]->quad_list[0]->material);
3895 const RenderPassDrawQuad* quad =
3896 RenderPassDrawQuad::MaterialCast(frame.render_passes[0]->quad_list[0]);
3897 EXPECT_TRUE(frame.render_passes_by_id.find(quad->render_pass_id) ==
3898 frame.render_passes_by_id.end());
3900 my_host_impl->DrawLayers(&frame, base::TimeTicks::Now());
3901 my_host_impl->DidDrawAllLayers(frame);
3904 // Change opacity and draw
3905 surface_layer_ptr->SetOpacity(0.6f);
3907 LayerTreeHostImpl::FrameData frame;
3908 EXPECT_TRUE(my_host_impl->PrepareToDraw(&frame, gfx::Rect()));
3910 // Must receive one render pass, as the other one should be culled
3911 ASSERT_EQ(1U, frame.render_passes.size());
3913 EXPECT_EQ(1U, frame.render_passes[0]->quad_list.size());
3914 EXPECT_EQ(DrawQuad::RENDER_PASS,
3915 frame.render_passes[0]->quad_list[0]->material);
3916 const RenderPassDrawQuad* quad =
3917 RenderPassDrawQuad::MaterialCast(frame.render_passes[0]->quad_list[0]);
3918 EXPECT_TRUE(frame.render_passes_by_id.find(quad->render_pass_id) ==
3919 frame.render_passes_by_id.end());
3921 my_host_impl->DrawLayers(&frame, base::TimeTicks::Now());
3922 my_host_impl->DidDrawAllLayers(frame);
3925 // Change less benign property and draw - should have contents changed flag
3926 surface_layer_ptr->SetStackingOrderChanged(true);
3928 LayerTreeHostImpl::FrameData frame;
3929 EXPECT_TRUE(my_host_impl->PrepareToDraw(&frame, gfx::Rect()));
3931 // Must receive two render passes, each with one quad
3932 ASSERT_EQ(2U, frame.render_passes.size());
3934 EXPECT_EQ(1U, frame.render_passes[0]->quad_list.size());
3935 EXPECT_EQ(DrawQuad::SOLID_COLOR,
3936 frame.render_passes[0]->quad_list[0]->material);
3938 EXPECT_EQ(DrawQuad::RENDER_PASS,
3939 frame.render_passes[1]->quad_list[0]->material);
3940 const RenderPassDrawQuad* quad =
3941 RenderPassDrawQuad::MaterialCast(frame.render_passes[1]->quad_list[0]);
3942 RenderPass* target_pass = frame.render_passes_by_id[quad->render_pass_id];
3943 ASSERT_TRUE(target_pass);
3944 EXPECT_FALSE(target_pass->damage_rect.IsEmpty());
3946 my_host_impl->DrawLayers(&frame, base::TimeTicks::Now());
3947 my_host_impl->DidDrawAllLayers(frame);
3950 // Change opacity again, and evict the cached surface texture.
3951 surface_layer_ptr->SetOpacity(0.5f);
3952 static_cast<GLRendererWithReleaseTextures*>(
3953 my_host_impl->renderer())->ReleaseRenderPassTextures();
3955 // Change opacity and draw
3956 surface_layer_ptr->SetOpacity(0.6f);
3958 LayerTreeHostImpl::FrameData frame;
3959 EXPECT_TRUE(my_host_impl->PrepareToDraw(&frame, gfx::Rect()));
3961 // Must receive two render passes
3962 ASSERT_EQ(2U, frame.render_passes.size());
3964 // Even though not enough properties changed, the entire thing must be
3965 // redrawn as we don't have cached textures
3966 EXPECT_EQ(1U, frame.render_passes[0]->quad_list.size());
3967 EXPECT_EQ(1U, frame.render_passes[1]->quad_list.size());
3969 EXPECT_EQ(DrawQuad::RENDER_PASS,
3970 frame.render_passes[1]->quad_list[0]->material);
3971 const RenderPassDrawQuad* quad =
3972 RenderPassDrawQuad::MaterialCast(frame.render_passes[1]->quad_list[0]);
3973 RenderPass* target_pass = frame.render_passes_by_id[quad->render_pass_id];
3974 ASSERT_TRUE(target_pass);
3975 EXPECT_TRUE(target_pass->damage_rect.IsEmpty());
3977 // Was our surface evicted?
3978 EXPECT_FALSE(my_host_impl->renderer()->HaveCachedResourcesForRenderPassId(
3979 target_pass->id));
3981 my_host_impl->DrawLayers(&frame, base::TimeTicks::Now());
3982 my_host_impl->DidDrawAllLayers(frame);
3985 // Draw without any change, to make sure the state is clear
3987 LayerTreeHostImpl::FrameData frame;
3988 my_host_impl->SetFullRootLayerDamage();
3989 EXPECT_TRUE(my_host_impl->PrepareToDraw(&frame, gfx::Rect()));
3991 // Must receive one render pass, as the other one should be culled
3992 ASSERT_EQ(1U, frame.render_passes.size());
3994 EXPECT_EQ(1U, frame.render_passes[0]->quad_list.size());
3995 EXPECT_EQ(DrawQuad::RENDER_PASS,
3996 frame.render_passes[0]->quad_list[0]->material);
3997 const RenderPassDrawQuad* quad =
3998 RenderPassDrawQuad::MaterialCast(frame.render_passes[0]->quad_list[0]);
3999 EXPECT_TRUE(frame.render_passes_by_id.find(quad->render_pass_id) ==
4000 frame.render_passes_by_id.end());
4002 my_host_impl->DrawLayers(&frame, base::TimeTicks::Now());
4003 my_host_impl->DidDrawAllLayers(frame);
4006 // Change location of the intermediate layer
4007 gfx::Transform transform = intermediate_layer_ptr->transform();
4008 transform.matrix().setDouble(0, 3, 1.0001);
4009 intermediate_layer_ptr->SetTransform(transform);
4011 LayerTreeHostImpl::FrameData frame;
4012 EXPECT_TRUE(my_host_impl->PrepareToDraw(&frame, gfx::Rect()));
4014 // Must receive one render pass, as the other one should be culled.
4015 ASSERT_EQ(1U, frame.render_passes.size());
4016 EXPECT_EQ(1U, frame.render_passes[0]->quad_list.size());
4018 EXPECT_EQ(DrawQuad::RENDER_PASS,
4019 frame.render_passes[0]->quad_list[0]->material);
4020 const RenderPassDrawQuad* quad =
4021 RenderPassDrawQuad::MaterialCast(frame.render_passes[0]->quad_list[0]);
4022 EXPECT_TRUE(frame.render_passes_by_id.find(quad->render_pass_id) ==
4023 frame.render_passes_by_id.end());
4025 my_host_impl->DrawLayers(&frame, base::TimeTicks::Now());
4026 my_host_impl->DidDrawAllLayers(frame);
4030 TEST_F(LayerTreeHostImplTest, SurfaceTextureCachingNoPartialSwap) {
4031 LayerTreeSettings settings;
4032 settings.minimum_occlusion_tracking_size = gfx::Size();
4033 settings.cache_render_pass_contents = true;
4034 scoped_ptr<LayerTreeHostImpl> my_host_impl =
4035 LayerTreeHostImpl::Create(settings,
4036 this,
4037 &proxy_,
4038 &stats_instrumentation_);
4040 LayerImpl* root_ptr;
4041 LayerImpl* intermediate_layer_ptr;
4042 LayerImpl* surface_layer_ptr;
4043 LayerImpl* child_ptr;
4045 SetupLayersForTextureCaching(my_host_impl.get(),
4046 root_ptr,
4047 intermediate_layer_ptr,
4048 surface_layer_ptr,
4049 child_ptr,
4050 gfx::Size(100, 100));
4052 LayerTreeHostImpl::FrameData frame;
4053 EXPECT_TRUE(my_host_impl->PrepareToDraw(&frame, gfx::Rect()));
4055 // Must receive two render passes, each with one quad
4056 ASSERT_EQ(2U, frame.render_passes.size());
4057 EXPECT_EQ(1U, frame.render_passes[0]->quad_list.size());
4058 EXPECT_EQ(1U, frame.render_passes[1]->quad_list.size());
4060 EXPECT_EQ(DrawQuad::RENDER_PASS,
4061 frame.render_passes[1]->quad_list[0]->material);
4062 const RenderPassDrawQuad* quad =
4063 RenderPassDrawQuad::MaterialCast(frame.render_passes[1]->quad_list[0]);
4064 RenderPass* target_pass = frame.render_passes_by_id[quad->render_pass_id];
4065 EXPECT_FALSE(target_pass->damage_rect.IsEmpty());
4067 EXPECT_FALSE(frame.render_passes[0]->damage_rect.IsEmpty());
4068 EXPECT_FALSE(frame.render_passes[1]->damage_rect.IsEmpty());
4070 EXPECT_FALSE(
4071 frame.render_passes[0]->has_occlusion_from_outside_target_surface);
4072 EXPECT_FALSE(
4073 frame.render_passes[1]->has_occlusion_from_outside_target_surface);
4075 my_host_impl->DrawLayers(&frame, base::TimeTicks::Now());
4076 my_host_impl->DidDrawAllLayers(frame);
4079 // Draw without any change
4081 LayerTreeHostImpl::FrameData frame;
4082 my_host_impl->SetFullRootLayerDamage();
4083 EXPECT_TRUE(my_host_impl->PrepareToDraw(&frame, gfx::Rect()));
4085 // Even though there was no change, we set the damage to entire viewport.
4086 // One of the passes should be culled as a result, since contents didn't
4087 // change and we have cached texture.
4088 ASSERT_EQ(1U, frame.render_passes.size());
4089 EXPECT_EQ(1U, frame.render_passes[0]->quad_list.size());
4091 my_host_impl->DrawLayers(&frame, base::TimeTicks::Now());
4092 my_host_impl->DidDrawAllLayers(frame);
4095 // Change opacity and draw
4096 surface_layer_ptr->SetOpacity(0.6f);
4098 LayerTreeHostImpl::FrameData frame;
4099 EXPECT_TRUE(my_host_impl->PrepareToDraw(&frame, gfx::Rect()));
4101 // Must receive one render pass, as the other one should be culled
4102 ASSERT_EQ(1U, frame.render_passes.size());
4104 EXPECT_EQ(1U, frame.render_passes[0]->quad_list.size());
4105 EXPECT_EQ(DrawQuad::RENDER_PASS,
4106 frame.render_passes[0]->quad_list[0]->material);
4107 const RenderPassDrawQuad* quad =
4108 RenderPassDrawQuad::MaterialCast(frame.render_passes[0]->quad_list[0]);
4109 EXPECT_TRUE(frame.render_passes_by_id.find(quad->render_pass_id) ==
4110 frame.render_passes_by_id.end());
4112 my_host_impl->DrawLayers(&frame, base::TimeTicks::Now());
4113 my_host_impl->DidDrawAllLayers(frame);
4116 // Change less benign property and draw - should have contents changed flag
4117 surface_layer_ptr->SetStackingOrderChanged(true);
4119 LayerTreeHostImpl::FrameData frame;
4120 EXPECT_TRUE(my_host_impl->PrepareToDraw(&frame, gfx::Rect()));
4122 // Must receive two render passes, each with one quad
4123 ASSERT_EQ(2U, frame.render_passes.size());
4125 EXPECT_EQ(1U, frame.render_passes[0]->quad_list.size());
4126 EXPECT_EQ(DrawQuad::SOLID_COLOR,
4127 frame.render_passes[0]->quad_list[0]->material);
4129 EXPECT_EQ(DrawQuad::RENDER_PASS,
4130 frame.render_passes[1]->quad_list[0]->material);
4131 const RenderPassDrawQuad* quad =
4132 RenderPassDrawQuad::MaterialCast(frame.render_passes[1]->quad_list[0]);
4133 RenderPass* target_pass = frame.render_passes_by_id[quad->render_pass_id];
4134 ASSERT_TRUE(target_pass);
4135 EXPECT_FALSE(target_pass->damage_rect.IsEmpty());
4137 my_host_impl->DrawLayers(&frame, base::TimeTicks::Now());
4138 my_host_impl->DidDrawAllLayers(frame);
4141 // Change opacity again, and evict the cached surface texture.
4142 surface_layer_ptr->SetOpacity(0.5f);
4143 static_cast<GLRendererWithReleaseTextures*>(
4144 my_host_impl->renderer())->ReleaseRenderPassTextures();
4146 // Change opacity and draw
4147 surface_layer_ptr->SetOpacity(0.6f);
4149 LayerTreeHostImpl::FrameData frame;
4150 EXPECT_TRUE(my_host_impl->PrepareToDraw(&frame, gfx::Rect()));
4152 // Must receive two render passes
4153 ASSERT_EQ(2U, frame.render_passes.size());
4155 // Even though not enough properties changed, the entire thing must be
4156 // redrawn as we don't have cached textures
4157 EXPECT_EQ(1U, frame.render_passes[0]->quad_list.size());
4158 EXPECT_EQ(1U, frame.render_passes[1]->quad_list.size());
4160 EXPECT_EQ(DrawQuad::RENDER_PASS,
4161 frame.render_passes[1]->quad_list[0]->material);
4162 const RenderPassDrawQuad* quad =
4163 RenderPassDrawQuad::MaterialCast(frame.render_passes[1]->quad_list[0]);
4164 RenderPass* target_pass = frame.render_passes_by_id[quad->render_pass_id];
4165 ASSERT_TRUE(target_pass);
4166 EXPECT_TRUE(target_pass->damage_rect.IsEmpty());
4168 // Was our surface evicted?
4169 EXPECT_FALSE(my_host_impl->renderer()->HaveCachedResourcesForRenderPassId(
4170 target_pass->id));
4172 my_host_impl->DrawLayers(&frame, base::TimeTicks::Now());
4173 my_host_impl->DidDrawAllLayers(frame);
4176 // Draw without any change, to make sure the state is clear
4178 LayerTreeHostImpl::FrameData frame;
4179 my_host_impl->SetFullRootLayerDamage();
4180 EXPECT_TRUE(my_host_impl->PrepareToDraw(&frame, gfx::Rect()));
4182 // Even though there was no change, we set the damage to entire viewport.
4183 // One of the passes should be culled as a result, since contents didn't
4184 // change and we have cached texture.
4185 ASSERT_EQ(1U, frame.render_passes.size());
4186 EXPECT_EQ(1U, frame.render_passes[0]->quad_list.size());
4188 my_host_impl->DrawLayers(&frame, base::TimeTicks::Now());
4189 my_host_impl->DidDrawAllLayers(frame);
4192 // Change location of the intermediate layer
4193 gfx::Transform transform = intermediate_layer_ptr->transform();
4194 transform.matrix().setDouble(0, 3, 1.0001);
4195 intermediate_layer_ptr->SetTransform(transform);
4197 LayerTreeHostImpl::FrameData frame;
4198 EXPECT_TRUE(my_host_impl->PrepareToDraw(&frame, gfx::Rect()));
4200 // Must receive one render pass, as the other one should be culled.
4201 ASSERT_EQ(1U, frame.render_passes.size());
4202 EXPECT_EQ(1U, frame.render_passes[0]->quad_list.size());
4204 EXPECT_EQ(DrawQuad::RENDER_PASS,
4205 frame.render_passes[0]->quad_list[0]->material);
4206 const RenderPassDrawQuad* quad =
4207 RenderPassDrawQuad::MaterialCast(frame.render_passes[0]->quad_list[0]);
4208 EXPECT_TRUE(frame.render_passes_by_id.find(quad->render_pass_id) ==
4209 frame.render_passes_by_id.end());
4211 my_host_impl->DrawLayers(&frame, base::TimeTicks::Now());
4212 my_host_impl->DidDrawAllLayers(frame);
4216 TEST_F(LayerTreeHostImplTest, ReleaseContentsTextureShouldTriggerCommit) {
4217 set_reduce_memory_result(false);
4219 // If changing the memory limit wouldn't result in changing what was
4220 // committed, then no commit should be requested.
4221 set_reduce_memory_result(false);
4222 host_impl_->set_max_memory_needed_bytes(
4223 host_impl_->memory_allocation_limit_bytes() - 1);
4224 host_impl_->SetManagedMemoryPolicy(ManagedMemoryPolicy(
4225 host_impl_->memory_allocation_limit_bytes() - 1));
4226 EXPECT_FALSE(did_request_commit_);
4227 did_request_commit_ = false;
4229 // If changing the memory limit would result in changing what was
4230 // committed, then a commit should be requested, even though nothing was
4231 // evicted.
4232 set_reduce_memory_result(false);
4233 host_impl_->set_max_memory_needed_bytes(
4234 host_impl_->memory_allocation_limit_bytes());
4235 host_impl_->SetManagedMemoryPolicy(ManagedMemoryPolicy(
4236 host_impl_->memory_allocation_limit_bytes() - 1));
4237 EXPECT_TRUE(did_request_commit_);
4238 did_request_commit_ = false;
4240 // Especially if changing the memory limit caused evictions, we need
4241 // to re-commit.
4242 set_reduce_memory_result(true);
4243 host_impl_->set_max_memory_needed_bytes(1);
4244 host_impl_->SetManagedMemoryPolicy(ManagedMemoryPolicy(
4245 host_impl_->memory_allocation_limit_bytes() - 1));
4246 EXPECT_TRUE(did_request_commit_);
4247 did_request_commit_ = false;
4249 // But if we set it to the same value that it was before, we shouldn't
4250 // re-commit.
4251 host_impl_->SetManagedMemoryPolicy(ManagedMemoryPolicy(
4252 host_impl_->memory_allocation_limit_bytes()));
4253 EXPECT_FALSE(did_request_commit_);
4256 struct RenderPassRemovalTestData : public LayerTreeHostImpl::FrameData {
4257 ScopedPtrHashMap<RenderPass::Id, TestRenderPass> render_pass_cache;
4258 scoped_ptr<SharedQuadState> shared_quad_state;
4261 class TestRenderer : public GLRenderer, public RendererClient {
4262 public:
4263 static scoped_ptr<TestRenderer> Create(ResourceProvider* resource_provider,
4264 OutputSurface* output_surface,
4265 Proxy* proxy) {
4266 scoped_ptr<TestRenderer> renderer(new TestRenderer(resource_provider,
4267 output_surface,
4268 proxy));
4269 if (!renderer->Initialize())
4270 return scoped_ptr<TestRenderer>();
4272 return renderer.Pass();
4275 void ClearCachedTextures() { textures_.clear(); }
4276 void SetHaveCachedResourcesForRenderPassId(RenderPass::Id id) {
4277 textures_.insert(id);
4280 virtual bool HaveCachedResourcesForRenderPassId(RenderPass::Id id) const
4281 OVERRIDE {
4282 return textures_.count(id);
4285 // RendererClient implementation.
4286 virtual gfx::Size DeviceViewportSize() const OVERRIDE {
4287 return viewport_size_;
4289 virtual const LayerTreeSettings& Settings() const OVERRIDE {
4290 return settings_;
4292 virtual void DidLoseOutputSurface() OVERRIDE {}
4293 virtual void OnSwapBuffersComplete() OVERRIDE {}
4294 virtual void SetFullRootLayerDamage() OVERRIDE {}
4295 virtual void SetManagedMemoryPolicy(const ManagedMemoryPolicy& policy)
4296 OVERRIDE {}
4297 virtual void EnforceManagedMemoryPolicy(const ManagedMemoryPolicy& policy)
4298 OVERRIDE {}
4299 virtual bool HasImplThread() const OVERRIDE { return false; }
4300 virtual bool ShouldClearRootRenderPass() const OVERRIDE { return true; }
4301 virtual CompositorFrameMetadata MakeCompositorFrameMetadata() const
4302 OVERRIDE { return CompositorFrameMetadata(); }
4303 virtual bool AllowPartialSwap() const OVERRIDE {
4304 return true;
4307 protected:
4308 TestRenderer(ResourceProvider* resource_provider,
4309 OutputSurface* output_surface,
4310 Proxy* proxy)
4311 : GLRenderer(this, output_surface, resource_provider, 0) {}
4313 private:
4314 LayerTreeSettings settings_;
4315 gfx::Size viewport_size_;
4316 base::hash_set<RenderPass::Id> textures_;
4319 static void ConfigureRenderPassTestData(const char* test_script,
4320 RenderPassRemovalTestData* test_data,
4321 TestRenderer* renderer) {
4322 renderer->ClearCachedTextures();
4324 // One shared state for all quads - we don't need the correct details
4325 test_data->shared_quad_state = SharedQuadState::Create();
4326 test_data->shared_quad_state->SetAll(gfx::Transform(),
4327 gfx::Size(),
4328 gfx::Rect(),
4329 gfx::Rect(),
4330 false,
4331 1.f);
4333 const char* current_char = test_script;
4335 // Pre-create root pass
4336 RenderPass::Id root_render_pass_id =
4337 RenderPass::Id(test_script[0], test_script[1]);
4338 scoped_ptr<TestRenderPass> pass = TestRenderPass::Create();
4339 pass->SetNew(root_render_pass_id, gfx::Rect(), gfx::Rect(), gfx::Transform());
4340 test_data->render_pass_cache.add(root_render_pass_id, pass.Pass());
4341 while (*current_char) {
4342 int layer_id = *current_char;
4343 current_char++;
4344 ASSERT_TRUE(current_char);
4345 int index = *current_char;
4346 current_char++;
4348 RenderPass::Id render_pass_id = RenderPass::Id(layer_id, index);
4350 bool is_replica = false;
4351 if (!test_data->render_pass_cache.contains(render_pass_id))
4352 is_replica = true;
4354 scoped_ptr<TestRenderPass> render_pass =
4355 test_data->render_pass_cache.take(render_pass_id);
4357 // Cycle through quad data and create all quads.
4358 while (*current_char && *current_char != '\n') {
4359 if (*current_char == 's') {
4360 // Solid color draw quad.
4361 scoped_ptr<SolidColorDrawQuad> quad = SolidColorDrawQuad::Create();
4362 quad->SetNew(test_data->shared_quad_state.get(),
4363 gfx::Rect(0, 0, 10, 10),
4364 SK_ColorWHITE);
4366 render_pass->AppendQuad(quad.PassAs<DrawQuad>());
4367 current_char++;
4368 } else if ((*current_char >= 'A') && (*current_char <= 'Z')) {
4369 // RenderPass draw quad.
4370 int layer_id = *current_char;
4371 current_char++;
4372 ASSERT_TRUE(current_char);
4373 int index = *current_char;
4374 current_char++;
4375 RenderPass::Id new_render_pass_id = RenderPass::Id(layer_id, index);
4376 ASSERT_NE(root_render_pass_id, new_render_pass_id);
4377 bool has_texture = false;
4378 bool contents_changed = true;
4380 if (*current_char == '[') {
4381 current_char++;
4382 while (*current_char && *current_char != ']') {
4383 switch (*current_char) {
4384 case 'c':
4385 contents_changed = false;
4386 break;
4387 case 't':
4388 has_texture = true;
4389 break;
4391 current_char++;
4393 if (*current_char == ']')
4394 current_char++;
4397 if (test_data->render_pass_cache.find(new_render_pass_id) ==
4398 test_data->render_pass_cache.end()) {
4399 if (has_texture)
4400 renderer->SetHaveCachedResourcesForRenderPassId(new_render_pass_id);
4402 scoped_ptr<TestRenderPass> pass = TestRenderPass::Create();
4403 pass->SetNew(new_render_pass_id,
4404 gfx::Rect(),
4405 gfx::Rect(),
4406 gfx::Transform());
4407 test_data->render_pass_cache.add(new_render_pass_id, pass.Pass());
4410 gfx::Rect quad_rect = gfx::Rect(0, 0, 1, 1);
4411 gfx::Rect contents_changed_rect =
4412 contents_changed ? quad_rect : gfx::Rect();
4413 scoped_ptr<RenderPassDrawQuad> quad = RenderPassDrawQuad::Create();
4414 quad->SetNew(test_data->shared_quad_state.get(),
4415 quad_rect,
4416 new_render_pass_id,
4417 is_replica,
4419 contents_changed_rect,
4420 gfx::RectF(0.f, 0.f, 1.f, 1.f),
4421 WebKit::WebFilterOperations(),
4422 skia::RefPtr<SkImageFilter>(),
4423 WebKit::WebFilterOperations());
4424 render_pass->AppendQuad(quad.PassAs<DrawQuad>());
4427 test_data->render_passes_by_id[render_pass_id] = render_pass.get();
4428 test_data->render_passes.insert(test_data->render_passes.begin(),
4429 render_pass.PassAs<RenderPass>());
4430 if (*current_char)
4431 current_char++;
4435 void DumpRenderPassTestData(const RenderPassRemovalTestData& test_data,
4436 char* buffer) {
4437 char* pos = buffer;
4438 for (RenderPassList::const_reverse_iterator it =
4439 test_data.render_passes.rbegin();
4440 it != test_data.render_passes.rend();
4441 ++it) {
4442 const RenderPass* current_pass = *it;
4443 *pos = current_pass->id.layer_id;
4444 pos++;
4445 *pos = current_pass->id.index;
4446 pos++;
4448 QuadList::const_iterator quad_list_iterator =
4449 current_pass->quad_list.begin();
4450 while (quad_list_iterator != current_pass->quad_list.end()) {
4451 DrawQuad* current_quad = *quad_list_iterator;
4452 switch (current_quad->material) {
4453 case DrawQuad::SOLID_COLOR:
4454 *pos = 's';
4455 pos++;
4456 break;
4457 case DrawQuad::RENDER_PASS:
4458 *pos = RenderPassDrawQuad::MaterialCast(current_quad)->
4459 render_pass_id.layer_id;
4460 pos++;
4461 *pos = RenderPassDrawQuad::MaterialCast(current_quad)->
4462 render_pass_id.index;
4463 pos++;
4464 break;
4465 default:
4466 *pos = 'x';
4467 pos++;
4468 break;
4471 quad_list_iterator++;
4473 *pos = '\n';
4474 pos++;
4476 *pos = '\0';
4479 // Each RenderPassList is represented by a string which describes the
4480 // configuration.
4481 // The syntax of the string is as follows:
4483 // RsssssX[c]ssYsssZ[t]ssW[ct]
4484 // Identifies the render pass------------------------^ ^^^ ^ ^ ^ ^ ^
4485 // These are solid color quads--------------------------+ | | | | |
4486 // Identifies RenderPassDrawQuad's RenderPass--------------+ | | | |
4487 // This quad's contents didn't change------------------------+ | | |
4488 // This quad's contents changed and it has no texture------------+ | |
4489 // This quad has texture but its contents changed----------------------+ |
4490 // This quad's contents didn't change and it has texture - will be removed---+
4492 // Expected results have exactly the same syntax, except they do not use square
4493 // brackets, since we only check the structure, not attributes.
4495 // Test case configuration consists of initialization script and expected
4496 // results, all in the same format.
4497 struct TestCase {
4498 const char* name;
4499 const char* init_script;
4500 const char* expected_result;
4503 TestCase remove_render_passes_cases[] = {
4505 "Single root pass",
4506 "R0ssss\n",
4507 "R0ssss\n"
4510 "Single pass - no quads",
4511 "R0\n",
4512 "R0\n"
4515 "Two passes, no removal",
4516 "R0ssssA0sss\n"
4517 "A0ssss\n",
4518 "R0ssssA0sss\n"
4519 "A0ssss\n"
4522 "Two passes, remove last",
4523 "R0ssssA0[ct]sss\n"
4524 "A0ssss\n",
4525 "R0ssssA0sss\n"
4528 "Have texture but contents changed - leave pass",
4529 "R0ssssA0[t]sss\n"
4530 "A0ssss\n",
4531 "R0ssssA0sss\n"
4532 "A0ssss\n"
4535 "Contents didn't change but no texture - leave pass",
4536 "R0ssssA0[c]sss\n"
4537 "A0ssss\n",
4538 "R0ssssA0sss\n"
4539 "A0ssss\n"
4542 "Replica: two quads reference the same pass; remove",
4543 "R0ssssA0[ct]A0[ct]sss\n"
4544 "A0ssss\n",
4545 "R0ssssA0A0sss\n"
4548 "Replica: two quads reference the same pass; leave",
4549 "R0ssssA0[c]A0[c]sss\n"
4550 "A0ssss\n",
4551 "R0ssssA0A0sss\n"
4552 "A0ssss\n",
4555 "Many passes, remove all",
4556 "R0ssssA0[ct]sss\n"
4557 "A0sssB0[ct]C0[ct]s\n"
4558 "B0sssD0[ct]ssE0[ct]F0[ct]\n"
4559 "E0ssssss\n"
4560 "C0G0[ct]\n"
4561 "D0sssssss\n"
4562 "F0sssssss\n"
4563 "G0sss\n",
4565 "R0ssssA0sss\n"
4568 "Deep recursion, remove all",
4570 "R0sssssA0[ct]ssss\n"
4571 "A0ssssB0sss\n"
4572 "B0C0\n"
4573 "C0D0\n"
4574 "D0E0\n"
4575 "E0F0\n"
4576 "F0G0\n"
4577 "G0H0\n"
4578 "H0sssI0sss\n"
4579 "I0J0\n"
4580 "J0ssss\n",
4582 "R0sssssA0ssss\n"
4585 "Wide recursion, remove all",
4586 "R0A0[ct]B0[ct]C0[ct]D0[ct]E0[ct]F0[ct]G0[ct]H0[ct]I0[ct]J0[ct]\n"
4587 "A0s\n"
4588 "B0s\n"
4589 "C0ssss\n"
4590 "D0ssss\n"
4591 "E0s\n"
4592 "F0\n"
4593 "G0s\n"
4594 "H0s\n"
4595 "I0s\n"
4596 "J0ssss\n",
4598 "R0A0B0C0D0E0F0G0H0I0J0\n"
4601 "Remove passes regardless of cache state",
4602 "R0ssssA0[ct]sss\n"
4603 "A0sssB0C0s\n"
4604 "B0sssD0[c]ssE0[t]F0\n"
4605 "E0ssssss\n"
4606 "C0G0\n"
4607 "D0sssssss\n"
4608 "F0sssssss\n"
4609 "G0sss\n",
4611 "R0ssssA0sss\n"
4614 "Leave some passes, remove others",
4616 "R0ssssA0[c]sss\n"
4617 "A0sssB0[t]C0[ct]s\n"
4618 "B0sssD0[c]ss\n"
4619 "C0G0\n"
4620 "D0sssssss\n"
4621 "G0sss\n",
4623 "R0ssssA0sss\n"
4624 "A0sssB0C0s\n"
4625 "B0sssD0ss\n"
4626 "D0sssssss\n"
4629 0, 0, 0
4633 static void VerifyRenderPassTestData(
4634 const TestCase& test_case,
4635 const RenderPassRemovalTestData& test_data) {
4636 char actual_result[1024];
4637 DumpRenderPassTestData(test_data, actual_result);
4638 EXPECT_STREQ(test_case.expected_result, actual_result) << "In test case: " <<
4639 test_case.name;
4642 TEST_F(LayerTreeHostImplTest, TestRemoveRenderPasses) {
4643 scoped_ptr<OutputSurface> output_surface(CreateOutputSurface());
4644 ASSERT_TRUE(output_surface->context3d());
4645 scoped_ptr<ResourceProvider> resource_provider =
4646 ResourceProvider::Create(output_surface.get(), 0);
4648 scoped_ptr<TestRenderer> renderer =
4649 TestRenderer::Create(resource_provider.get(),
4650 output_surface.get(),
4651 &proxy_);
4653 int test_case_index = 0;
4654 while (remove_render_passes_cases[test_case_index].name) {
4655 RenderPassRemovalTestData test_data;
4656 ConfigureRenderPassTestData(
4657 remove_render_passes_cases[test_case_index].init_script,
4658 &test_data,
4659 renderer.get());
4660 LayerTreeHostImpl::RemoveRenderPasses(
4661 LayerTreeHostImpl::CullRenderPassesWithCachedTextures(renderer.get()),
4662 &test_data);
4663 VerifyRenderPassTestData(remove_render_passes_cases[test_case_index],
4664 test_data);
4665 test_case_index++;
4669 class LayerTreeHostImplTestWithDelegatingRenderer
4670 : public LayerTreeHostImplTest {
4671 protected:
4672 virtual scoped_ptr<OutputSurface> CreateOutputSurface() OVERRIDE {
4673 return FakeOutputSurface::CreateDelegating3d().PassAs<OutputSurface>();
4676 void DrawFrameAndTestDamage(const gfx::RectF& expected_damage) {
4677 bool expect_to_draw = !expected_damage.IsEmpty();
4679 LayerTreeHostImpl::FrameData frame;
4680 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
4682 if (!expect_to_draw) {
4683 // With no damage, we don't draw, and no quads are created.
4684 ASSERT_EQ(0u, frame.render_passes.size());
4685 } else {
4686 ASSERT_EQ(1u, frame.render_passes.size());
4688 // Verify the damage rect for the root render pass.
4689 const RenderPass* root_render_pass = frame.render_passes.back();
4690 EXPECT_RECT_EQ(expected_damage, root_render_pass->damage_rect);
4692 // Verify the root and child layers' quads are generated and not being
4693 // culled.
4694 ASSERT_EQ(2u, root_render_pass->quad_list.size());
4696 LayerImpl* child = host_impl_->active_tree()->root_layer()->children()[0];
4697 gfx::RectF expected_child_visible_rect(child->content_bounds());
4698 EXPECT_RECT_EQ(expected_child_visible_rect,
4699 root_render_pass->quad_list[0]->visible_rect);
4701 LayerImpl* root = host_impl_->active_tree()->root_layer();
4702 gfx::RectF expected_root_visible_rect(root->content_bounds());
4703 EXPECT_RECT_EQ(expected_root_visible_rect,
4704 root_render_pass->quad_list[1]->visible_rect);
4707 host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
4708 host_impl_->DidDrawAllLayers(frame);
4709 EXPECT_EQ(expect_to_draw, host_impl_->SwapBuffers(frame));
4713 TEST_F(LayerTreeHostImplTestWithDelegatingRenderer, FrameIncludesDamageRect) {
4714 scoped_ptr<SolidColorLayerImpl> root =
4715 SolidColorLayerImpl::Create(host_impl_->active_tree(), 1);
4716 root->SetAnchorPoint(gfx::PointF());
4717 root->SetPosition(gfx::PointF());
4718 root->SetBounds(gfx::Size(10, 10));
4719 root->SetContentBounds(gfx::Size(10, 10));
4720 root->SetDrawsContent(true);
4722 // Child layer is in the bottom right corner.
4723 scoped_ptr<SolidColorLayerImpl> child =
4724 SolidColorLayerImpl::Create(host_impl_->active_tree(), 2);
4725 child->SetAnchorPoint(gfx::PointF(0.f, 0.f));
4726 child->SetPosition(gfx::PointF(9.f, 9.f));
4727 child->SetBounds(gfx::Size(1, 1));
4728 child->SetContentBounds(gfx::Size(1, 1));
4729 child->SetDrawsContent(true);
4730 root->AddChild(child.PassAs<LayerImpl>());
4732 host_impl_->active_tree()->SetRootLayer(root.PassAs<LayerImpl>());
4734 // Draw a frame. In the first frame, the entire viewport should be damaged.
4735 gfx::Rect full_frame_damage = gfx::Rect(host_impl_->device_viewport_size());
4736 DrawFrameAndTestDamage(full_frame_damage);
4738 // The second frame has damage that doesn't touch the child layer. Its quads
4739 // should still be generated.
4740 gfx::Rect small_damage = gfx::Rect(0, 0, 1, 1);
4741 host_impl_->active_tree()->root_layer()->set_update_rect(small_damage);
4742 DrawFrameAndTestDamage(small_damage);
4744 // The third frame should have no damage, so no quads should be generated.
4745 gfx::Rect no_damage;
4746 DrawFrameAndTestDamage(no_damage);
4749 class FakeMaskLayerImpl : public LayerImpl {
4750 public:
4751 static scoped_ptr<FakeMaskLayerImpl> Create(LayerTreeImpl* tree_impl,
4752 int id) {
4753 return make_scoped_ptr(new FakeMaskLayerImpl(tree_impl, id));
4756 virtual ResourceProvider::ResourceId ContentsResourceId() const OVERRIDE {
4757 return 0;
4760 private:
4761 FakeMaskLayerImpl(LayerTreeImpl* tree_impl, int id)
4762 : LayerImpl(tree_impl, id) {}
4765 TEST_F(LayerTreeHostImplTest, MaskLayerWithScaling) {
4766 // Root
4767 // |
4768 // +-- Scaling Layer (adds a 2x scale)
4769 // |
4770 // +-- Content Layer
4771 // +--Mask
4772 scoped_ptr<LayerImpl> scoped_root =
4773 LayerImpl::Create(host_impl_->active_tree(), 1);
4774 LayerImpl* root = scoped_root.get();
4775 host_impl_->active_tree()->SetRootLayer(scoped_root.Pass());
4777 scoped_ptr<LayerImpl> scoped_scaling_layer =
4778 LayerImpl::Create(host_impl_->active_tree(), 2);
4779 LayerImpl* scaling_layer = scoped_scaling_layer.get();
4780 root->AddChild(scoped_scaling_layer.Pass());
4782 scoped_ptr<LayerImpl> scoped_content_layer =
4783 LayerImpl::Create(host_impl_->active_tree(), 3);
4784 LayerImpl* content_layer = scoped_content_layer.get();
4785 scaling_layer->AddChild(scoped_content_layer.Pass());
4787 scoped_ptr<FakeMaskLayerImpl> scoped_mask_layer =
4788 FakeMaskLayerImpl::Create(host_impl_->active_tree(), 4);
4789 FakeMaskLayerImpl* mask_layer = scoped_mask_layer.get();
4790 content_layer->SetMaskLayer(scoped_mask_layer.PassAs<LayerImpl>());
4792 gfx::Size root_size(100, 100);
4793 root->SetBounds(root_size);
4794 root->SetContentBounds(root_size);
4795 root->SetPosition(gfx::PointF());
4796 root->SetAnchorPoint(gfx::PointF());
4798 gfx::Size scaling_layer_size(50, 50);
4799 scaling_layer->SetBounds(scaling_layer_size);
4800 scaling_layer->SetContentBounds(scaling_layer_size);
4801 scaling_layer->SetPosition(gfx::PointF());
4802 scaling_layer->SetAnchorPoint(gfx::PointF());
4803 gfx::Transform scale;
4804 scale.Scale(2.f, 2.f);
4805 scaling_layer->SetTransform(scale);
4807 content_layer->SetBounds(scaling_layer_size);
4808 content_layer->SetContentBounds(scaling_layer_size);
4809 content_layer->SetPosition(gfx::PointF());
4810 content_layer->SetAnchorPoint(gfx::PointF());
4811 content_layer->SetDrawsContent(true);
4813 mask_layer->SetBounds(scaling_layer_size);
4814 mask_layer->SetContentBounds(scaling_layer_size);
4815 mask_layer->SetPosition(gfx::PointF());
4816 mask_layer->SetAnchorPoint(gfx::PointF());
4817 mask_layer->SetDrawsContent(true);
4820 // Check that the tree scaling is correctly taken into account for the mask,
4821 // that should fully map onto the quad.
4822 float device_scale_factor = 1.f;
4823 host_impl_->SetViewportSize(root_size);
4824 host_impl_->SetDeviceScaleFactor(device_scale_factor);
4826 LayerTreeHostImpl::FrameData frame;
4827 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
4829 ASSERT_EQ(1u, frame.render_passes.size());
4830 ASSERT_EQ(1u, frame.render_passes[0]->quad_list.size());
4831 ASSERT_EQ(DrawQuad::RENDER_PASS,
4832 frame.render_passes[0]->quad_list[0]->material);
4833 const RenderPassDrawQuad* render_pass_quad =
4834 RenderPassDrawQuad::MaterialCast(frame.render_passes[0]->quad_list[0]);
4835 EXPECT_EQ(gfx::Rect(0, 0, 100, 100).ToString(),
4836 render_pass_quad->rect.ToString());
4837 EXPECT_EQ(gfx::RectF(0.f, 0.f, 1.f, 1.f).ToString(),
4838 render_pass_quad->mask_uv_rect.ToString());
4840 host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
4841 host_impl_->DidDrawAllLayers(frame);
4845 // Applying a DSF should change the render surface size, but won't affect
4846 // which part of the mask is used.
4847 device_scale_factor = 2.f;
4848 gfx::Size device_viewport =
4849 gfx::ToFlooredSize(gfx::ScaleSize(root_size, device_scale_factor));
4850 host_impl_->SetViewportSize(device_viewport);
4851 host_impl_->SetDeviceScaleFactor(device_scale_factor);
4852 host_impl_->active_tree()->set_needs_update_draw_properties();
4854 LayerTreeHostImpl::FrameData frame;
4855 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
4857 ASSERT_EQ(1u, frame.render_passes.size());
4858 ASSERT_EQ(1u, frame.render_passes[0]->quad_list.size());
4859 ASSERT_EQ(DrawQuad::RENDER_PASS,
4860 frame.render_passes[0]->quad_list[0]->material);
4861 const RenderPassDrawQuad* render_pass_quad =
4862 RenderPassDrawQuad::MaterialCast(frame.render_passes[0]->quad_list[0]);
4863 EXPECT_EQ(gfx::Rect(0, 0, 200, 200).ToString(),
4864 render_pass_quad->rect.ToString());
4865 EXPECT_EQ(gfx::RectF(0.f, 0.f, 1.f, 1.f).ToString(),
4866 render_pass_quad->mask_uv_rect.ToString());
4868 host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
4869 host_impl_->DidDrawAllLayers(frame);
4873 // Applying an equivalent content scale on the content layer and the mask
4874 // should still result in the same part of the mask being used.
4875 gfx::Size content_bounds =
4876 gfx::ToRoundedSize(gfx::ScaleSize(scaling_layer_size,
4877 device_scale_factor));
4878 content_layer->SetContentBounds(content_bounds);
4879 content_layer->SetContentsScale(device_scale_factor, device_scale_factor);
4880 mask_layer->SetContentBounds(content_bounds);
4881 mask_layer->SetContentsScale(device_scale_factor, device_scale_factor);
4882 host_impl_->active_tree()->set_needs_update_draw_properties();
4884 LayerTreeHostImpl::FrameData frame;
4885 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
4887 ASSERT_EQ(1u, frame.render_passes.size());
4888 ASSERT_EQ(1u, frame.render_passes[0]->quad_list.size());
4889 ASSERT_EQ(DrawQuad::RENDER_PASS,
4890 frame.render_passes[0]->quad_list[0]->material);
4891 const RenderPassDrawQuad* render_pass_quad =
4892 RenderPassDrawQuad::MaterialCast(frame.render_passes[0]->quad_list[0]);
4893 EXPECT_EQ(gfx::Rect(0, 0, 200, 200).ToString(),
4894 render_pass_quad->rect.ToString());
4895 EXPECT_EQ(gfx::RectF(0.f, 0.f, 1.f, 1.f).ToString(),
4896 render_pass_quad->mask_uv_rect.ToString());
4898 host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
4899 host_impl_->DidDrawAllLayers(frame);
4903 TEST_F(LayerTreeHostImplTest, MaskLayerWithDifferentBounds) {
4904 // The mask layer has bounds 100x100 but is attached to a layer with bounds
4905 // 50x50.
4907 scoped_ptr<LayerImpl> scoped_root =
4908 LayerImpl::Create(host_impl_->active_tree(), 1);
4909 LayerImpl* root = scoped_root.get();
4910 host_impl_->active_tree()->SetRootLayer(scoped_root.Pass());
4912 scoped_ptr<LayerImpl> scoped_content_layer =
4913 LayerImpl::Create(host_impl_->active_tree(), 3);
4914 LayerImpl* content_layer = scoped_content_layer.get();
4915 root->AddChild(scoped_content_layer.Pass());
4917 scoped_ptr<FakeMaskLayerImpl> scoped_mask_layer =
4918 FakeMaskLayerImpl::Create(host_impl_->active_tree(), 4);
4919 FakeMaskLayerImpl* mask_layer = scoped_mask_layer.get();
4920 content_layer->SetMaskLayer(scoped_mask_layer.PassAs<LayerImpl>());
4922 gfx::Size root_size(100, 100);
4923 root->SetBounds(root_size);
4924 root->SetContentBounds(root_size);
4925 root->SetPosition(gfx::PointF());
4926 root->SetAnchorPoint(gfx::PointF());
4928 gfx::Size layer_size(50, 50);
4929 content_layer->SetBounds(layer_size);
4930 content_layer->SetContentBounds(layer_size);
4931 content_layer->SetPosition(gfx::PointF());
4932 content_layer->SetAnchorPoint(gfx::PointF());
4933 content_layer->SetDrawsContent(true);
4935 gfx::Size mask_size(100, 100);
4936 mask_layer->SetBounds(mask_size);
4937 mask_layer->SetContentBounds(mask_size);
4938 mask_layer->SetPosition(gfx::PointF());
4939 mask_layer->SetAnchorPoint(gfx::PointF());
4940 mask_layer->SetDrawsContent(true);
4943 // Check that the mask fills the surface.
4944 float device_scale_factor = 1.f;
4945 host_impl_->SetViewportSize(root_size);
4946 host_impl_->SetDeviceScaleFactor(device_scale_factor);
4948 LayerTreeHostImpl::FrameData frame;
4949 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
4951 ASSERT_EQ(1u, frame.render_passes.size());
4952 ASSERT_EQ(1u, frame.render_passes[0]->quad_list.size());
4953 ASSERT_EQ(DrawQuad::RENDER_PASS,
4954 frame.render_passes[0]->quad_list[0]->material);
4955 const RenderPassDrawQuad* render_pass_quad =
4956 RenderPassDrawQuad::MaterialCast(frame.render_passes[0]->quad_list[0]);
4957 EXPECT_EQ(gfx::Rect(0, 0, 50, 50).ToString(),
4958 render_pass_quad->rect.ToString());
4959 EXPECT_EQ(gfx::RectF(0.f, 0.f, 1.f, 1.f).ToString(),
4960 render_pass_quad->mask_uv_rect.ToString());
4962 host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
4963 host_impl_->DidDrawAllLayers(frame);
4967 // Applying a DSF should change the render surface size, but won't affect
4968 // which part of the mask is used.
4969 device_scale_factor = 2.f;
4970 gfx::Size device_viewport =
4971 gfx::ToFlooredSize(gfx::ScaleSize(root_size, device_scale_factor));
4972 host_impl_->SetViewportSize(device_viewport);
4973 host_impl_->SetDeviceScaleFactor(device_scale_factor);
4974 host_impl_->active_tree()->set_needs_update_draw_properties();
4976 LayerTreeHostImpl::FrameData frame;
4977 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
4979 ASSERT_EQ(1u, frame.render_passes.size());
4980 ASSERT_EQ(1u, frame.render_passes[0]->quad_list.size());
4981 ASSERT_EQ(DrawQuad::RENDER_PASS,
4982 frame.render_passes[0]->quad_list[0]->material);
4983 const RenderPassDrawQuad* render_pass_quad =
4984 RenderPassDrawQuad::MaterialCast(frame.render_passes[0]->quad_list[0]);
4985 EXPECT_EQ(gfx::Rect(0, 0, 100, 100).ToString(),
4986 render_pass_quad->rect.ToString());
4987 EXPECT_EQ(gfx::RectF(0.f, 0.f, 1.f, 1.f).ToString(),
4988 render_pass_quad->mask_uv_rect.ToString());
4990 host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
4991 host_impl_->DidDrawAllLayers(frame);
4995 // Applying an equivalent content scale on the content layer and the mask
4996 // should still result in the same part of the mask being used.
4997 gfx::Size layer_size_large =
4998 gfx::ToRoundedSize(gfx::ScaleSize(layer_size, device_scale_factor));
4999 content_layer->SetContentBounds(layer_size_large);
5000 content_layer->SetContentsScale(device_scale_factor, device_scale_factor);
5001 gfx::Size mask_size_large =
5002 gfx::ToRoundedSize(gfx::ScaleSize(mask_size, device_scale_factor));
5003 mask_layer->SetContentBounds(mask_size_large);
5004 mask_layer->SetContentsScale(device_scale_factor, device_scale_factor);
5005 host_impl_->active_tree()->set_needs_update_draw_properties();
5007 LayerTreeHostImpl::FrameData frame;
5008 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
5010 ASSERT_EQ(1u, frame.render_passes.size());
5011 ASSERT_EQ(1u, frame.render_passes[0]->quad_list.size());
5012 ASSERT_EQ(DrawQuad::RENDER_PASS,
5013 frame.render_passes[0]->quad_list[0]->material);
5014 const RenderPassDrawQuad* render_pass_quad =
5015 RenderPassDrawQuad::MaterialCast(frame.render_passes[0]->quad_list[0]);
5016 EXPECT_EQ(gfx::Rect(0, 0, 100, 100).ToString(),
5017 render_pass_quad->rect.ToString());
5018 EXPECT_EQ(gfx::RectF(0.f, 0.f, 1.f, 1.f).ToString(),
5019 render_pass_quad->mask_uv_rect.ToString());
5021 host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
5022 host_impl_->DidDrawAllLayers(frame);
5025 // Applying a different contents scale to the mask layer will still result
5026 // in the mask covering the owning layer.
5027 mask_layer->SetContentBounds(mask_size);
5028 mask_layer->SetContentsScale(device_scale_factor, device_scale_factor);
5029 host_impl_->active_tree()->set_needs_update_draw_properties();
5031 LayerTreeHostImpl::FrameData frame;
5032 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
5034 ASSERT_EQ(1u, frame.render_passes.size());
5035 ASSERT_EQ(1u, frame.render_passes[0]->quad_list.size());
5036 ASSERT_EQ(DrawQuad::RENDER_PASS,
5037 frame.render_passes[0]->quad_list[0]->material);
5038 const RenderPassDrawQuad* render_pass_quad =
5039 RenderPassDrawQuad::MaterialCast(frame.render_passes[0]->quad_list[0]);
5040 EXPECT_EQ(gfx::Rect(0, 0, 100, 100).ToString(),
5041 render_pass_quad->rect.ToString());
5042 EXPECT_EQ(gfx::RectF(0.f, 0.f, 1.f, 1.f).ToString(),
5043 render_pass_quad->mask_uv_rect.ToString());
5045 host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
5046 host_impl_->DidDrawAllLayers(frame);
5050 } // namespace
5051 } // namespace cc