Add signalSyncPoint to the WebGraphicsContext3D command buffer impls.
[chromium-blink-merge.git] / cc / trees / layer_tree_host_impl_unittest.cc
blob3782a45891010817ea618e00ee59e6c9a786a96a
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_ack.h"
27 #include "cc/output/compositor_frame_metadata.h"
28 #include "cc/output/gl_renderer.h"
29 #include "cc/quads/render_pass_draw_quad.h"
30 #include "cc/quads/solid_color_draw_quad.h"
31 #include "cc/quads/texture_draw_quad.h"
32 #include "cc/quads/tile_draw_quad.h"
33 #include "cc/resources/layer_tiling_data.h"
34 #include "cc/test/animation_test_common.h"
35 #include "cc/test/fake_output_surface.h"
36 #include "cc/test/fake_proxy.h"
37 #include "cc/test/fake_rendering_stats_instrumentation.h"
38 #include "cc/test/fake_video_frame_provider.h"
39 #include "cc/test/fake_web_scrollbar_theme_geometry.h"
40 #include "cc/test/geometry_test_utils.h"
41 #include "cc/test/layer_test_common.h"
42 #include "cc/test/render_pass_test_common.h"
43 #include "cc/test/test_web_graphics_context_3d.h"
44 #include "cc/trees/layer_tree_impl.h"
45 #include "cc/trees/single_thread_proxy.h"
46 #include "media/base/media.h"
47 #include "testing/gmock/include/gmock/gmock.h"
48 #include "testing/gtest/include/gtest/gtest.h"
49 #include "ui/gfx/size_conversions.h"
50 #include "ui/gfx/vector2d_conversions.h"
52 using ::testing::Mock;
53 using ::testing::Return;
54 using ::testing::AnyNumber;
55 using ::testing::AtLeast;
56 using ::testing::_;
57 using media::VideoFrame;
59 namespace cc {
60 namespace {
62 class LayerTreeHostImplTest : public testing::Test,
63 public LayerTreeHostImplClient {
64 public:
65 LayerTreeHostImplTest()
66 : proxy_(scoped_ptr<Thread>(NULL)),
67 always_impl_thread_(&proxy_),
68 always_main_thread_blocked_(&proxy_),
69 on_can_draw_state_changed_called_(false),
70 has_pending_tree_(false),
71 did_request_commit_(false),
72 did_request_redraw_(false),
73 did_upload_visible_tile_(false),
74 reduce_memory_result_(true) {
75 media::InitializeMediaLibraryForTesting();
78 virtual void OverrideSettings(LayerTreeSettings* settings) {}
80 virtual void SetUp() OVERRIDE {
81 LayerTreeSettings settings;
82 settings.minimum_occlusion_tracking_size = gfx::Size();
83 OverrideSettings(&settings);
85 host_impl_ = LayerTreeHostImpl::Create(settings,
86 this,
87 &proxy_,
88 &stats_instrumentation_);
89 host_impl_->InitializeRenderer(CreateOutputSurface());
90 host_impl_->SetViewportSize(gfx::Size(10, 10));
93 virtual void TearDown() OVERRIDE {}
95 virtual void DidLoseOutputSurfaceOnImplThread() OVERRIDE {}
96 virtual void OnSwapBuffersCompleteOnImplThread() OVERRIDE {}
97 virtual void OnVSyncParametersChanged(base::TimeTicks timebase,
98 base::TimeDelta interval) OVERRIDE {}
99 virtual void DidVSync(base::TimeTicks frame_time) OVERRIDE {}
100 virtual void OnCanDrawStateChanged(bool can_draw) OVERRIDE {
101 on_can_draw_state_changed_called_ = true;
103 virtual void OnHasPendingTreeStateChanged(bool has_pending_tree) OVERRIDE {
104 has_pending_tree_ = has_pending_tree;
106 virtual void SetNeedsRedrawOnImplThread() OVERRIDE {
107 did_request_redraw_ = true;
109 virtual void SetNeedsRedrawRectOnImplThread(gfx::Rect damage_rect) OVERRIDE {
110 did_request_redraw_ = true;
112 virtual void DidInitializeVisibleTileOnImplThread() OVERRIDE {
113 did_upload_visible_tile_ = true;
115 virtual void SetNeedsCommitOnImplThread() OVERRIDE {
116 did_request_commit_ = true;
118 virtual void SetNeedsManageTilesOnImplThread() OVERRIDE {}
119 virtual void PostAnimationEventsToMainThreadOnImplThread(
120 scoped_ptr<AnimationEventsVector> events,
121 base::Time wall_clock_time) OVERRIDE {}
122 virtual bool ReduceContentsTextureMemoryOnImplThread(
123 size_t limit_bytes, int priority_cutoff) OVERRIDE {
124 return reduce_memory_result_;
126 virtual void ReduceWastedContentsTextureMemoryOnImplThread() OVERRIDE {}
127 virtual void SendManagedMemoryStats() OVERRIDE {}
128 virtual bool IsInsideDraw() OVERRIDE { return false; }
129 virtual void RenewTreePriority() OVERRIDE {}
130 virtual void RequestScrollbarAnimationOnImplThread(base::TimeDelta delay)
131 OVERRIDE {}
132 virtual void DidReceiveLastInputEventForVSync(base::TimeTicks frame_time)
133 OVERRIDE {}
135 void set_reduce_memory_result(bool reduce_memory_result) {
136 reduce_memory_result_ = reduce_memory_result;
139 void CreateLayerTreeHost(bool partial_swap,
140 scoped_ptr<OutputSurface> output_surface) {
141 LayerTreeSettings settings;
142 settings.minimum_occlusion_tracking_size = gfx::Size();
143 settings.partial_swap_enabled = partial_swap;
145 host_impl_ = LayerTreeHostImpl::Create(settings,
146 this,
147 &proxy_,
148 &stats_instrumentation_);
150 host_impl_->InitializeRenderer(output_surface.Pass());
151 host_impl_->SetViewportSize(gfx::Size(10, 10));
154 void SetupRootLayerImpl(scoped_ptr<LayerImpl> root) {
155 root->SetAnchorPoint(gfx::PointF());
156 root->SetPosition(gfx::PointF());
157 root->SetBounds(gfx::Size(10, 10));
158 root->SetContentBounds(gfx::Size(10, 10));
159 root->SetDrawsContent(true);
160 root->draw_properties().visible_content_rect = gfx::Rect(0, 0, 10, 10);
161 host_impl_->active_tree()->SetRootLayer(root.Pass());
164 static void ExpectClearedScrollDeltasRecursive(LayerImpl* layer) {
165 ASSERT_EQ(layer->scroll_delta(), gfx::Vector2d());
166 for (size_t i = 0; i < layer->children().size(); ++i)
167 ExpectClearedScrollDeltasRecursive(layer->children()[i]);
170 static void ExpectContains(const ScrollAndScaleSet& scroll_info,
171 int id,
172 gfx::Vector2d scroll_delta) {
173 int times_encountered = 0;
175 for (size_t i = 0; i < scroll_info.scrolls.size(); ++i) {
176 if (scroll_info.scrolls[i].layer_id != id)
177 continue;
178 EXPECT_VECTOR_EQ(scroll_delta, scroll_info.scrolls[i].scroll_delta);
179 times_encountered++;
182 ASSERT_EQ(times_encountered, 1);
185 static void ExpectNone(const ScrollAndScaleSet& scroll_info, int id) {
186 int times_encountered = 0;
188 for (size_t i = 0; i < scroll_info.scrolls.size(); ++i) {
189 if (scroll_info.scrolls[i].layer_id != id)
190 continue;
191 times_encountered++;
194 ASSERT_EQ(0, times_encountered);
197 void SetupScrollAndContentsLayers(gfx::Size content_size) {
198 scoped_ptr<LayerImpl> root =
199 LayerImpl::Create(host_impl_->active_tree(), 1);
200 root->SetScrollable(true);
201 root->SetScrollOffset(gfx::Vector2d());
202 root->SetMaxScrollOffset(gfx::Vector2d(content_size.width(),
203 content_size.height()));
204 root->SetBounds(content_size);
205 root->SetContentBounds(content_size);
206 root->SetPosition(gfx::PointF());
207 root->SetAnchorPoint(gfx::PointF());
209 scoped_ptr<LayerImpl> contents =
210 LayerImpl::Create(host_impl_->active_tree(), 2);
211 contents->SetDrawsContent(true);
212 contents->SetBounds(content_size);
213 contents->SetContentBounds(content_size);
214 contents->SetPosition(gfx::PointF());
215 contents->SetAnchorPoint(gfx::PointF());
216 root->AddChild(contents.Pass());
217 host_impl_->active_tree()->SetRootLayer(root.Pass());
218 host_impl_->active_tree()->DidBecomeActive();
221 scoped_ptr<LayerImpl> CreateScrollableLayer(int id, gfx::Size size) {
222 scoped_ptr<LayerImpl> layer =
223 LayerImpl::Create(host_impl_->active_tree(), id);
224 layer->SetScrollable(true);
225 layer->SetDrawsContent(true);
226 layer->SetBounds(size);
227 layer->SetContentBounds(size);
228 layer->SetMaxScrollOffset(gfx::Vector2d(size.width() * 2,
229 size.height() * 2));
230 return layer.Pass();
233 void InitializeRendererAndDrawFrame() {
234 host_impl_->InitializeRenderer(CreateOutputSurface());
235 LayerTreeHostImpl::FrameData frame;
236 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
237 host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
238 host_impl_->DidDrawAllLayers(frame);
241 void pinch_zoom_pan_viewport_forces_commit_redraw(float device_scale_factor);
242 void pinch_zoom_pan_viewport_test(float device_scale_factor);
243 void pinch_zoom_pan_viewport_and_scroll_test(float device_scale_factor);
244 void pinch_zoom_pan_viewport_and_scroll_boundary_test(
245 float device_scale_factor);
247 protected:
248 virtual scoped_ptr<OutputSurface> CreateOutputSurface() {
249 return CreateFakeOutputSurface();
252 void DrawOneFrame() {
253 LayerTreeHostImpl::FrameData frame_data;
254 host_impl_->PrepareToDraw(&frame_data, gfx::Rect());
255 host_impl_->DidDrawAllLayers(frame_data);
258 FakeProxy proxy_;
259 DebugScopedSetImplThread always_impl_thread_;
260 DebugScopedSetMainThreadBlocked always_main_thread_blocked_;
262 scoped_ptr<LayerTreeHostImpl> host_impl_;
263 FakeRenderingStatsInstrumentation stats_instrumentation_;
264 bool on_can_draw_state_changed_called_;
265 bool has_pending_tree_;
266 bool did_request_commit_;
267 bool did_request_redraw_;
268 bool did_upload_visible_tile_;
269 bool reduce_memory_result_;
272 class TestWebGraphicsContext3DMakeCurrentFails
273 : public TestWebGraphicsContext3D {
274 public:
275 virtual bool makeContextCurrent() OVERRIDE { return false; }
278 TEST_F(LayerTreeHostImplTest, NotifyIfCanDrawChanged) {
279 // Note: It is not possible to disable the renderer once it has been set,
280 // so we do not need to test that disabling the renderer notifies us
281 // that can_draw changed.
282 EXPECT_FALSE(host_impl_->CanDraw());
283 on_can_draw_state_changed_called_ = false;
285 SetupScrollAndContentsLayers(gfx::Size(100, 100));
286 EXPECT_TRUE(host_impl_->CanDraw());
287 EXPECT_TRUE(on_can_draw_state_changed_called_);
288 on_can_draw_state_changed_called_ = false;
290 // Toggle the root layer to make sure it toggles can_draw
291 host_impl_->active_tree()->SetRootLayer(scoped_ptr<LayerImpl>());
292 EXPECT_FALSE(host_impl_->CanDraw());
293 EXPECT_TRUE(on_can_draw_state_changed_called_);
294 on_can_draw_state_changed_called_ = false;
296 SetupScrollAndContentsLayers(gfx::Size(100, 100));
297 EXPECT_TRUE(host_impl_->CanDraw());
298 EXPECT_TRUE(on_can_draw_state_changed_called_);
299 on_can_draw_state_changed_called_ = false;
301 // Toggle the device viewport size to make sure it toggles can_draw.
302 host_impl_->SetViewportSize(gfx::Size());
303 EXPECT_FALSE(host_impl_->CanDraw());
304 EXPECT_TRUE(on_can_draw_state_changed_called_);
305 on_can_draw_state_changed_called_ = false;
307 host_impl_->SetViewportSize(gfx::Size(100, 100));
308 EXPECT_TRUE(host_impl_->CanDraw());
309 EXPECT_TRUE(on_can_draw_state_changed_called_);
310 on_can_draw_state_changed_called_ = false;
312 // Toggle contents textures purged without causing any evictions,
313 // and make sure that it does not change can_draw.
314 set_reduce_memory_result(false);
315 host_impl_->SetManagedMemoryPolicy(ManagedMemoryPolicy(
316 host_impl_->memory_allocation_limit_bytes() - 1));
317 EXPECT_TRUE(host_impl_->CanDraw());
318 EXPECT_FALSE(on_can_draw_state_changed_called_);
319 on_can_draw_state_changed_called_ = false;
321 // Toggle contents textures purged to make sure it toggles can_draw.
322 set_reduce_memory_result(true);
323 host_impl_->SetManagedMemoryPolicy(ManagedMemoryPolicy(
324 host_impl_->memory_allocation_limit_bytes() - 1));
325 EXPECT_FALSE(host_impl_->CanDraw());
326 EXPECT_TRUE(on_can_draw_state_changed_called_);
327 on_can_draw_state_changed_called_ = false;
329 host_impl_->active_tree()->ResetContentsTexturesPurged();
330 EXPECT_TRUE(host_impl_->CanDraw());
331 EXPECT_TRUE(on_can_draw_state_changed_called_);
332 on_can_draw_state_changed_called_ = false;
335 TEST_F(LayerTreeHostImplTest, ScrollDeltaNoLayers) {
336 ASSERT_FALSE(host_impl_->active_tree()->root_layer());
338 scoped_ptr<ScrollAndScaleSet> scroll_info = host_impl_->ProcessScrollDeltas();
339 ASSERT_EQ(scroll_info->scrolls.size(), 0u);
342 TEST_F(LayerTreeHostImplTest, ScrollDeltaTreeButNoChanges) {
344 scoped_ptr<LayerImpl> root =
345 LayerImpl::Create(host_impl_->active_tree(), 1);
346 root->AddChild(LayerImpl::Create(host_impl_->active_tree(), 2));
347 root->AddChild(LayerImpl::Create(host_impl_->active_tree(), 3));
348 root->children()[1]->AddChild(
349 LayerImpl::Create(host_impl_->active_tree(), 4));
350 root->children()[1]->AddChild(
351 LayerImpl::Create(host_impl_->active_tree(), 5));
352 root->children()[1]->children()[0]->AddChild(
353 LayerImpl::Create(host_impl_->active_tree(), 6));
354 host_impl_->active_tree()->SetRootLayer(root.Pass());
356 LayerImpl* root = host_impl_->active_tree()->root_layer();
358 ExpectClearedScrollDeltasRecursive(root);
360 scoped_ptr<ScrollAndScaleSet> scroll_info;
362 scroll_info = host_impl_->ProcessScrollDeltas();
363 ASSERT_EQ(scroll_info->scrolls.size(), 0u);
364 ExpectClearedScrollDeltasRecursive(root);
366 scroll_info = host_impl_->ProcessScrollDeltas();
367 ASSERT_EQ(scroll_info->scrolls.size(), 0u);
368 ExpectClearedScrollDeltasRecursive(root);
371 TEST_F(LayerTreeHostImplTest, ScrollDeltaRepeatedScrolls) {
372 gfx::Vector2d scroll_offset(20, 30);
373 gfx::Vector2d scroll_delta(11, -15);
375 scoped_ptr<LayerImpl> root =
376 LayerImpl::Create(host_impl_->active_tree(), 1);
377 root->SetScrollOffset(scroll_offset);
378 root->SetScrollable(true);
379 root->SetMaxScrollOffset(gfx::Vector2d(100, 100));
380 root->ScrollBy(scroll_delta);
381 host_impl_->active_tree()->SetRootLayer(root.Pass());
383 LayerImpl* root = host_impl_->active_tree()->root_layer();
385 scoped_ptr<ScrollAndScaleSet> scroll_info;
387 scroll_info = host_impl_->ProcessScrollDeltas();
388 ASSERT_EQ(scroll_info->scrolls.size(), 1u);
389 EXPECT_VECTOR_EQ(root->sent_scroll_delta(), scroll_delta);
390 ExpectContains(*scroll_info, root->id(), scroll_delta);
392 gfx::Vector2d scroll_delta2(-5, 27);
393 root->ScrollBy(scroll_delta2);
394 scroll_info = host_impl_->ProcessScrollDeltas();
395 ASSERT_EQ(scroll_info->scrolls.size(), 1u);
396 EXPECT_VECTOR_EQ(root->sent_scroll_delta(), scroll_delta + scroll_delta2);
397 ExpectContains(*scroll_info, root->id(), scroll_delta + scroll_delta2);
399 root->ScrollBy(gfx::Vector2d());
400 scroll_info = host_impl_->ProcessScrollDeltas();
401 EXPECT_EQ(root->sent_scroll_delta(), scroll_delta + scroll_delta2);
404 TEST_F(LayerTreeHostImplTest, ScrollRootCallsCommitAndRedraw) {
405 SetupScrollAndContentsLayers(gfx::Size(100, 100));
406 host_impl_->SetViewportSize(gfx::Size(50, 50));
407 InitializeRendererAndDrawFrame();
409 EXPECT_EQ(InputHandlerClient::ScrollStarted,
410 host_impl_->ScrollBegin(gfx::Point(), InputHandlerClient::Wheel));
411 host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, 10));
412 host_impl_->ScrollEnd();
413 EXPECT_TRUE(did_request_redraw_);
414 EXPECT_TRUE(did_request_commit_);
417 TEST_F(LayerTreeHostImplTest, ScrollWithoutRootLayer) {
418 // We should not crash when trying to scroll an empty layer tree.
419 EXPECT_EQ(InputHandlerClient::ScrollIgnored,
420 host_impl_->ScrollBegin(gfx::Point(), InputHandlerClient::Wheel));
423 TEST_F(LayerTreeHostImplTest, ScrollWithoutRenderer) {
424 LayerTreeSettings settings;
425 host_impl_ = LayerTreeHostImpl::Create(settings,
426 this,
427 &proxy_,
428 &stats_instrumentation_);
430 // Initialization will fail here.
431 host_impl_->InitializeRenderer(FakeOutputSurface::Create3d(
432 scoped_ptr<WebKit::WebGraphicsContext3D>(
433 new TestWebGraphicsContext3DMakeCurrentFails))
434 .PassAs<OutputSurface>());
435 host_impl_->SetViewportSize(gfx::Size(10, 10));
437 SetupScrollAndContentsLayers(gfx::Size(100, 100));
439 // We should not crash when trying to scroll after the renderer initialization
440 // fails.
441 EXPECT_EQ(InputHandlerClient::ScrollIgnored,
442 host_impl_->ScrollBegin(gfx::Point(), InputHandlerClient::Wheel));
445 TEST_F(LayerTreeHostImplTest, ReplaceTreeWhileScrolling) {
446 int scroll_layer_id = 1;
448 SetupScrollAndContentsLayers(gfx::Size(100, 100));
449 host_impl_->SetViewportSize(gfx::Size(50, 50));
450 InitializeRendererAndDrawFrame();
452 // We should not crash if the tree is replaced while we are scrolling.
453 EXPECT_EQ(InputHandlerClient::ScrollStarted,
454 host_impl_->ScrollBegin(gfx::Point(), InputHandlerClient::Wheel));
455 host_impl_->active_tree()->DetachLayerTree();
457 SetupScrollAndContentsLayers(gfx::Size(100, 100));
459 // We should still be scrolling, because the scrolled layer also exists in the
460 // new tree.
461 gfx::Vector2d scroll_delta(0, 10);
462 host_impl_->ScrollBy(gfx::Point(), scroll_delta);
463 host_impl_->ScrollEnd();
464 scoped_ptr<ScrollAndScaleSet> scroll_info = host_impl_->ProcessScrollDeltas();
465 ExpectContains(*scroll_info, scroll_layer_id, scroll_delta);
468 TEST_F(LayerTreeHostImplTest, ClearRootRenderSurfaceAndScroll) {
469 SetupScrollAndContentsLayers(gfx::Size(100, 100));
470 host_impl_->SetViewportSize(gfx::Size(50, 50));
471 InitializeRendererAndDrawFrame();
473 // We should be able to scroll even if the root layer loses its render surface
474 // after the most recent render.
475 host_impl_->active_tree()->root_layer()->ClearRenderSurface();
476 host_impl_->active_tree()->set_needs_update_draw_properties();
478 EXPECT_EQ(InputHandlerClient::ScrollStarted,
479 host_impl_->ScrollBegin(gfx::Point(), InputHandlerClient::Wheel));
482 TEST_F(LayerTreeHostImplTest, WheelEventHandlers) {
483 SetupScrollAndContentsLayers(gfx::Size(100, 100));
484 host_impl_->SetViewportSize(gfx::Size(50, 50));
485 InitializeRendererAndDrawFrame();
486 LayerImpl* root = host_impl_->active_tree()->root_layer();
488 root->SetHaveWheelEventHandlers(true);
490 // With registered event handlers, wheel scrolls have to go to the main
491 // thread.
492 EXPECT_EQ(InputHandlerClient::ScrollOnMainThread,
493 host_impl_->ScrollBegin(gfx::Point(), InputHandlerClient::Wheel));
495 // But gesture scrolls can still be handled.
496 EXPECT_EQ(InputHandlerClient::ScrollStarted,
497 host_impl_->ScrollBegin(gfx::Point(), InputHandlerClient::Gesture));
500 TEST_F(LayerTreeHostImplTest, FlingOnlyWhenScrollingTouchscreen) {
501 SetupScrollAndContentsLayers(gfx::Size(100, 100));
502 host_impl_->SetViewportSize(gfx::Size(50, 50));
503 InitializeRendererAndDrawFrame();
505 // Ignore the fling since no layer is being scrolled
506 EXPECT_EQ(InputHandlerClient::ScrollIgnored,
507 host_impl_->FlingScrollBegin());
509 // Start scrolling a layer
510 EXPECT_EQ(InputHandlerClient::ScrollStarted,
511 host_impl_->ScrollBegin(gfx::Point(), InputHandlerClient::Gesture));
513 // Now the fling should go ahead since we've started scrolling a layer
514 EXPECT_EQ(InputHandlerClient::ScrollStarted,
515 host_impl_->FlingScrollBegin());
518 TEST_F(LayerTreeHostImplTest, FlingOnlyWhenScrollingTouchpad) {
519 SetupScrollAndContentsLayers(gfx::Size(100, 100));
520 host_impl_->SetViewportSize(gfx::Size(50, 50));
521 InitializeRendererAndDrawFrame();
523 // Ignore the fling since no layer is being scrolled
524 EXPECT_EQ(InputHandlerClient::ScrollIgnored,
525 host_impl_->FlingScrollBegin());
527 // Start scrolling a layer
528 EXPECT_EQ(InputHandlerClient::ScrollStarted,
529 host_impl_->ScrollBegin(gfx::Point(), InputHandlerClient::Wheel));
531 // Now the fling should go ahead since we've started scrolling a layer
532 EXPECT_EQ(InputHandlerClient::ScrollStarted,
533 host_impl_->FlingScrollBegin());
536 TEST_F(LayerTreeHostImplTest, NoFlingWhenScrollingOnMain) {
537 SetupScrollAndContentsLayers(gfx::Size(100, 100));
538 host_impl_->SetViewportSize(gfx::Size(50, 50));
539 InitializeRendererAndDrawFrame();
540 LayerImpl* root = host_impl_->active_tree()->root_layer();
542 root->SetShouldScrollOnMainThread(true);
544 // Start scrolling a layer
545 EXPECT_EQ(InputHandlerClient::ScrollOnMainThread,
546 host_impl_->ScrollBegin(gfx::Point(), InputHandlerClient::Gesture));
548 // The fling should be ignored since there's no layer being scrolled impl-side
549 EXPECT_EQ(InputHandlerClient::ScrollIgnored,
550 host_impl_->FlingScrollBegin());
553 TEST_F(LayerTreeHostImplTest, ShouldScrollOnMainThread) {
554 SetupScrollAndContentsLayers(gfx::Size(100, 100));
555 host_impl_->SetViewportSize(gfx::Size(50, 50));
556 InitializeRendererAndDrawFrame();
557 LayerImpl* root = host_impl_->active_tree()->root_layer();
559 root->SetShouldScrollOnMainThread(true);
561 EXPECT_EQ(InputHandlerClient::ScrollOnMainThread,
562 host_impl_->ScrollBegin(gfx::Point(), InputHandlerClient::Wheel));
563 EXPECT_EQ(InputHandlerClient::ScrollOnMainThread,
564 host_impl_->ScrollBegin(gfx::Point(), InputHandlerClient::Gesture));
567 TEST_F(LayerTreeHostImplTest, NonFastScrollableRegionBasic) {
568 SetupScrollAndContentsLayers(gfx::Size(200, 200));
569 host_impl_->SetViewportSize(gfx::Size(100, 100));
571 LayerImpl* root = host_impl_->active_tree()->root_layer();
572 root->SetContentsScale(2.f, 2.f);
573 root->SetNonFastScrollableRegion(gfx::Rect(0, 0, 50, 50));
575 InitializeRendererAndDrawFrame();
577 // All scroll types inside the non-fast scrollable region should fail.
578 EXPECT_EQ(InputHandlerClient::ScrollOnMainThread,
579 host_impl_->ScrollBegin(gfx::Point(25, 25),
580 InputHandlerClient::Wheel));
581 EXPECT_EQ(InputHandlerClient::ScrollOnMainThread,
582 host_impl_->ScrollBegin(gfx::Point(25, 25),
583 InputHandlerClient::Gesture));
585 // All scroll types outside this region should succeed.
586 EXPECT_EQ(InputHandlerClient::ScrollStarted,
587 host_impl_->ScrollBegin(gfx::Point(75, 75),
588 InputHandlerClient::Wheel));
589 host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, 10));
590 host_impl_->ScrollEnd();
591 EXPECT_EQ(InputHandlerClient::ScrollStarted,
592 host_impl_->ScrollBegin(gfx::Point(75, 75),
593 InputHandlerClient::Gesture));
594 host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, 10));
595 host_impl_->ScrollEnd();
598 TEST_F(LayerTreeHostImplTest, NonFastScrollableRegionWithOffset) {
599 SetupScrollAndContentsLayers(gfx::Size(200, 200));
600 host_impl_->SetViewportSize(gfx::Size(100, 100));
602 LayerImpl* root = host_impl_->active_tree()->root_layer();
603 root->SetContentsScale(2.f, 2.f);
604 root->SetNonFastScrollableRegion(gfx::Rect(0, 0, 50, 50));
605 root->SetPosition(gfx::PointF(-25.f, 0.f));
607 InitializeRendererAndDrawFrame();
609 // This point would fall into the non-fast scrollable region except that we've
610 // moved the layer down by 25 pixels.
611 EXPECT_EQ(InputHandlerClient::ScrollStarted,
612 host_impl_->ScrollBegin(gfx::Point(40, 10),
613 InputHandlerClient::Wheel));
614 host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, 1));
615 host_impl_->ScrollEnd();
617 // This point is still inside the non-fast region.
618 EXPECT_EQ(InputHandlerClient::ScrollOnMainThread,
619 host_impl_->ScrollBegin(gfx::Point(10, 10),
620 InputHandlerClient::Wheel));
623 TEST_F(LayerTreeHostImplTest, ScrollByReturnsCorrectValue) {
624 SetupScrollAndContentsLayers(gfx::Size(200, 200));
625 host_impl_->SetViewportSize(gfx::Size(100, 100));
627 InitializeRendererAndDrawFrame();
629 EXPECT_EQ(InputHandlerClient::ScrollStarted,
630 host_impl_->ScrollBegin(gfx::Point(), InputHandlerClient::Gesture));
632 // Trying to scroll to the left/top will not succeed.
633 EXPECT_FALSE(host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(-10, 0)));
634 EXPECT_FALSE(host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, -10)));
635 EXPECT_FALSE(host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(-10, -10)));
637 // Scrolling to the right/bottom will succeed.
638 EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(10, 0)));
639 EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, 10)));
640 EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(10, 10)));
642 // Scrolling to left/top will now succeed.
643 EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(-10, 0)));
644 EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, -10)));
645 EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(-10, -10)));
647 // Scrolling diagonally against an edge will succeed.
648 EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(10, -10)));
649 EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(-10, 0)));
650 EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(-10, 10)));
652 // Trying to scroll more than the available space will also succeed.
653 EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(5000, 5000)));
656 TEST_F(LayerTreeHostImplTest, ScrollVerticallyByPageReturnsCorrectValue) {
657 SetupScrollAndContentsLayers(gfx::Size(200, 2000));
658 host_impl_->SetViewportSize(gfx::Size(100, 1000));
660 InitializeRendererAndDrawFrame();
662 EXPECT_EQ(InputHandlerClient::ScrollStarted,
663 host_impl_->ScrollBegin(gfx::Point(),
664 InputHandlerClient::Wheel));
666 // Trying to scroll without a vertical scrollbar will fail.
667 EXPECT_FALSE(host_impl_->ScrollVerticallyByPage(
668 gfx::Point(), WebKit::WebScrollbar::ScrollForward));
669 EXPECT_FALSE(host_impl_->ScrollVerticallyByPage(
670 gfx::Point(), WebKit::WebScrollbar::ScrollBackward));
672 scoped_ptr<cc::ScrollbarLayerImpl> vertical_scrollbar(
673 cc::ScrollbarLayerImpl::Create(
674 host_impl_->active_tree(),
676 scoped_ptr<ScrollbarGeometryFixedThumb>()));
677 vertical_scrollbar->SetBounds(gfx::Size(15, 1000));
678 host_impl_->RootScrollLayer()->SetVerticalScrollbarLayer(
679 vertical_scrollbar.get());
681 // Trying to scroll with a vertical scrollbar will succeed.
682 EXPECT_TRUE(host_impl_->ScrollVerticallyByPage(
683 gfx::Point(), WebKit::WebScrollbar::ScrollForward));
684 EXPECT_FLOAT_EQ(875.f, host_impl_->RootScrollLayer()->scroll_delta().y());
685 EXPECT_TRUE(host_impl_->ScrollVerticallyByPage(
686 gfx::Point(), WebKit::WebScrollbar::ScrollBackward));
689 TEST_F(LayerTreeHostImplTest,
690 ClearRootRenderSurfaceAndHitTestTouchHandlerRegion) {
691 SetupScrollAndContentsLayers(gfx::Size(100, 100));
692 host_impl_->SetViewportSize(gfx::Size(50, 50));
693 InitializeRendererAndDrawFrame();
695 // We should be able to hit test for touch event handlers even if the root
696 // layer loses its render surface after the most recent render.
697 host_impl_->active_tree()->root_layer()->ClearRenderSurface();
698 host_impl_->active_tree()->set_needs_update_draw_properties();
700 EXPECT_EQ(host_impl_->HaveTouchEventHandlersAt(gfx::Point()), false);
703 TEST_F(LayerTreeHostImplTest, ImplPinchZoom) {
704 SetupScrollAndContentsLayers(gfx::Size(100, 100));
705 host_impl_->SetViewportSize(gfx::Size(50, 50));
706 InitializeRendererAndDrawFrame();
708 LayerImpl* scroll_layer = host_impl_->RootScrollLayer();
709 DCHECK(scroll_layer);
711 float min_page_scale = 1.f, max_page_scale = 4.f;
713 // The impl-based pinch zoom should adjust the max scroll position.
715 host_impl_->active_tree()->SetPageScaleFactorAndLimits(1.f,
716 min_page_scale,
717 max_page_scale);
718 host_impl_->active_tree()->SetPageScaleDelta(1.f);
719 scroll_layer->SetScrollDelta(gfx::Vector2d());
721 float page_scale_delta = 2.f;
722 host_impl_->PinchGestureBegin();
723 host_impl_->PinchGestureUpdate(page_scale_delta, gfx::Point(50, 50));
724 host_impl_->PinchGestureEnd();
725 EXPECT_TRUE(did_request_redraw_);
726 EXPECT_TRUE(did_request_commit_);
728 scoped_ptr<ScrollAndScaleSet> scroll_info =
729 host_impl_->ProcessScrollDeltas();
730 EXPECT_EQ(scroll_info->page_scale_delta, page_scale_delta);
732 EXPECT_EQ(gfx::Vector2d(75, 75),
733 host_impl_->active_tree()->root_layer()->max_scroll_offset());
736 // Scrolling after a pinch gesture should always be in local space. The
737 // scroll deltas do not have the page scale factor applied.
739 host_impl_->active_tree()->SetPageScaleFactorAndLimits(1.f,
740 min_page_scale,
741 max_page_scale);
742 host_impl_->active_tree()->SetPageScaleDelta(1.f);
743 scroll_layer->SetScrollDelta(gfx::Vector2d());
745 float page_scale_delta = 2.f;
746 host_impl_->PinchGestureBegin();
747 host_impl_->PinchGestureUpdate(page_scale_delta, gfx::Point());
748 host_impl_->PinchGestureEnd();
750 gfx::Vector2d scroll_delta(0, 10);
751 EXPECT_EQ(InputHandlerClient::ScrollStarted,
752 host_impl_->ScrollBegin(gfx::Point(5, 5),
753 InputHandlerClient::Wheel));
754 host_impl_->ScrollBy(gfx::Point(), scroll_delta);
755 host_impl_->ScrollEnd();
757 scoped_ptr<ScrollAndScaleSet> scroll_info =
758 host_impl_->ProcessScrollDeltas();
759 ExpectContains(*scroll_info.get(),
760 host_impl_->active_tree()->root_layer()->id(),
761 scroll_delta);
765 TEST_F(LayerTreeHostImplTest, PinchGesture) {
766 SetupScrollAndContentsLayers(gfx::Size(100, 100));
767 host_impl_->SetViewportSize(gfx::Size(50, 50));
768 InitializeRendererAndDrawFrame();
770 LayerImpl* scroll_layer = host_impl_->RootScrollLayer();
771 DCHECK(scroll_layer);
773 float min_page_scale = 1.f;
774 float max_page_scale = 4.f;
776 // Basic pinch zoom in gesture
778 host_impl_->active_tree()->SetPageScaleFactorAndLimits(1.f,
779 min_page_scale,
780 max_page_scale);
781 scroll_layer->SetScrollDelta(gfx::Vector2d());
783 float page_scale_delta = 2.f;
784 host_impl_->PinchGestureBegin();
785 host_impl_->PinchGestureUpdate(page_scale_delta, gfx::Point(50, 50));
786 host_impl_->PinchGestureEnd();
787 EXPECT_TRUE(did_request_redraw_);
788 EXPECT_TRUE(did_request_commit_);
790 scoped_ptr<ScrollAndScaleSet> scroll_info =
791 host_impl_->ProcessScrollDeltas();
792 EXPECT_EQ(scroll_info->page_scale_delta, page_scale_delta);
795 // Zoom-in clamping
797 host_impl_->active_tree()->SetPageScaleFactorAndLimits(1.f,
798 min_page_scale,
799 max_page_scale);
800 scroll_layer->SetScrollDelta(gfx::Vector2d());
801 float page_scale_delta = 10.f;
803 host_impl_->PinchGestureBegin();
804 host_impl_->PinchGestureUpdate(page_scale_delta, gfx::Point(50, 50));
805 host_impl_->PinchGestureEnd();
807 scoped_ptr<ScrollAndScaleSet> scroll_info =
808 host_impl_->ProcessScrollDeltas();
809 EXPECT_EQ(scroll_info->page_scale_delta, max_page_scale);
812 // Zoom-out clamping
814 host_impl_->active_tree()->SetPageScaleFactorAndLimits(1.f,
815 min_page_scale,
816 max_page_scale);
817 scroll_layer->SetScrollDelta(gfx::Vector2d());
818 scroll_layer->SetScrollOffset(gfx::Vector2d(50, 50));
820 float page_scale_delta = 0.1f;
821 host_impl_->PinchGestureBegin();
822 host_impl_->PinchGestureUpdate(page_scale_delta, gfx::Point());
823 host_impl_->PinchGestureEnd();
825 scoped_ptr<ScrollAndScaleSet> scroll_info =
826 host_impl_->ProcessScrollDeltas();
827 EXPECT_EQ(scroll_info->page_scale_delta, min_page_scale);
829 EXPECT_TRUE(scroll_info->scrolls.empty());
832 // Two-finger panning should not happen based on pinch events only
834 host_impl_->active_tree()->SetPageScaleFactorAndLimits(1.f,
835 min_page_scale,
836 max_page_scale);
837 scroll_layer->SetScrollDelta(gfx::Vector2d());
838 scroll_layer->SetScrollOffset(gfx::Vector2d(20, 20));
840 float page_scale_delta = 1.f;
841 host_impl_->PinchGestureBegin();
842 host_impl_->PinchGestureUpdate(page_scale_delta, gfx::Point(10, 10));
843 host_impl_->PinchGestureUpdate(page_scale_delta, gfx::Point(20, 20));
844 host_impl_->PinchGestureEnd();
846 scoped_ptr<ScrollAndScaleSet> scroll_info =
847 host_impl_->ProcessScrollDeltas();
848 EXPECT_EQ(scroll_info->page_scale_delta, page_scale_delta);
849 EXPECT_TRUE(scroll_info->scrolls.empty());
852 // Two-finger panning should work with interleaved scroll events
854 host_impl_->active_tree()->SetPageScaleFactorAndLimits(1.f,
855 min_page_scale,
856 max_page_scale);
857 scroll_layer->SetScrollDelta(gfx::Vector2d());
858 scroll_layer->SetScrollOffset(gfx::Vector2d(20, 20));
860 float page_scale_delta = 1.f;
861 host_impl_->ScrollBegin(gfx::Point(10, 10), InputHandlerClient::Wheel);
862 host_impl_->PinchGestureBegin();
863 host_impl_->PinchGestureUpdate(page_scale_delta, gfx::Point(10, 10));
864 host_impl_->ScrollBy(gfx::Point(10, 10), gfx::Vector2d(-10, -10));
865 host_impl_->PinchGestureUpdate(page_scale_delta, gfx::Point(20, 20));
866 host_impl_->PinchGestureEnd();
867 host_impl_->ScrollEnd();
869 scoped_ptr<ScrollAndScaleSet> scroll_info =
870 host_impl_->ProcessScrollDeltas();
871 EXPECT_EQ(scroll_info->page_scale_delta, page_scale_delta);
872 ExpectContains(*scroll_info, scroll_layer->id(), gfx::Vector2d(-10, -10));
876 TEST_F(LayerTreeHostImplTest, PageScaleAnimation) {
877 SetupScrollAndContentsLayers(gfx::Size(100, 100));
878 host_impl_->SetViewportSize(gfx::Size(50, 50));
879 InitializeRendererAndDrawFrame();
881 LayerImpl* scroll_layer = host_impl_->RootScrollLayer();
882 DCHECK(scroll_layer);
884 float min_page_scale = 0.5f;
885 float max_page_scale = 4.f;
886 base::TimeTicks start_time = base::TimeTicks() +
887 base::TimeDelta::FromSeconds(1);
888 base::TimeDelta duration = base::TimeDelta::FromMilliseconds(100);
889 base::TimeTicks halfway_through_animation = start_time + duration / 2;
890 base::TimeTicks end_time = start_time + duration;
892 // Non-anchor zoom-in
894 host_impl_->active_tree()->SetPageScaleFactorAndLimits(1.f,
895 min_page_scale,
896 max_page_scale);
897 scroll_layer->SetScrollOffset(gfx::Vector2d(50, 50));
899 host_impl_->StartPageScaleAnimation(gfx::Vector2d(),
900 false,
901 2.f,
902 start_time,
903 duration);
904 host_impl_->Animate(halfway_through_animation, base::Time());
905 EXPECT_TRUE(did_request_redraw_);
906 host_impl_->Animate(end_time, base::Time());
907 EXPECT_TRUE(did_request_commit_);
909 scoped_ptr<ScrollAndScaleSet> scroll_info =
910 host_impl_->ProcessScrollDeltas();
911 EXPECT_EQ(scroll_info->page_scale_delta, 2);
912 ExpectContains(*scroll_info, scroll_layer->id(), gfx::Vector2d(-50, -50));
915 // Anchor zoom-out
917 host_impl_->active_tree()->SetPageScaleFactorAndLimits(1.f,
918 min_page_scale,
919 max_page_scale);
920 scroll_layer->SetScrollOffset(gfx::Vector2d(50, 50));
922 host_impl_->StartPageScaleAnimation(gfx::Vector2d(25, 25),
923 true,
924 min_page_scale,
925 start_time, duration);
926 host_impl_->Animate(end_time, base::Time());
927 EXPECT_TRUE(did_request_redraw_);
928 EXPECT_TRUE(did_request_commit_);
930 scoped_ptr<ScrollAndScaleSet> scroll_info =
931 host_impl_->ProcessScrollDeltas();
932 EXPECT_EQ(scroll_info->page_scale_delta, min_page_scale);
933 // Pushed to (0,0) via clamping against contents layer size.
934 ExpectContains(*scroll_info, scroll_layer->id(), gfx::Vector2d(-50, -50));
938 TEST_F(LayerTreeHostImplTest, PageScaleAnimationNoOp) {
939 SetupScrollAndContentsLayers(gfx::Size(100, 100));
940 host_impl_->SetViewportSize(gfx::Size(50, 50));
941 InitializeRendererAndDrawFrame();
943 LayerImpl* scroll_layer = host_impl_->RootScrollLayer();
944 DCHECK(scroll_layer);
946 float min_page_scale = 0.5f;
947 float max_page_scale = 4.f;
948 base::TimeTicks start_time = base::TimeTicks() +
949 base::TimeDelta::FromSeconds(1);
950 base::TimeDelta duration = base::TimeDelta::FromMilliseconds(100);
951 base::TimeTicks halfway_through_animation = start_time + duration / 2;
952 base::TimeTicks end_time = start_time + duration;
954 // Anchor zoom with unchanged page scale should not change scroll or scale.
956 host_impl_->active_tree()->SetPageScaleFactorAndLimits(1.f,
957 min_page_scale,
958 max_page_scale);
959 scroll_layer->SetScrollOffset(gfx::Vector2d(50, 50));
961 host_impl_->StartPageScaleAnimation(gfx::Vector2d(),
962 true,
963 1.f,
964 start_time,
965 duration);
966 host_impl_->Animate(halfway_through_animation, base::Time());
967 EXPECT_TRUE(did_request_redraw_);
968 host_impl_->Animate(end_time, base::Time());
969 EXPECT_TRUE(did_request_commit_);
971 scoped_ptr<ScrollAndScaleSet> scroll_info =
972 host_impl_->ProcessScrollDeltas();
973 EXPECT_EQ(scroll_info->page_scale_delta, 1);
974 ExpectNone(*scroll_info, scroll_layer->id());
978 TEST_F(LayerTreeHostImplTest, CompositorFrameMetadata) {
979 SetupScrollAndContentsLayers(gfx::Size(100, 100));
980 host_impl_->SetViewportSize(gfx::Size(50, 50));
981 host_impl_->active_tree()->SetPageScaleFactorAndLimits(1.f, 0.5f, 4.f);
982 InitializeRendererAndDrawFrame();
984 CompositorFrameMetadata metadata =
985 host_impl_->MakeCompositorFrameMetadata();
986 EXPECT_EQ(gfx::Vector2dF(), metadata.root_scroll_offset);
987 EXPECT_EQ(1.f, metadata.page_scale_factor);
988 EXPECT_EQ(gfx::SizeF(50.f, 50.f), metadata.viewport_size);
989 EXPECT_EQ(gfx::SizeF(100.f, 100.f), metadata.root_layer_size);
990 EXPECT_EQ(0.5f, metadata.min_page_scale_factor);
991 EXPECT_EQ(4.f, metadata.max_page_scale_factor);
994 // Scrolling should update metadata immediately.
995 EXPECT_EQ(InputHandlerClient::ScrollStarted,
996 host_impl_->ScrollBegin(gfx::Point(), InputHandlerClient::Wheel));
997 host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, 10));
999 CompositorFrameMetadata metadata =
1000 host_impl_->MakeCompositorFrameMetadata();
1001 EXPECT_EQ(gfx::Vector2dF(0.f, 10.f), metadata.root_scroll_offset);
1003 host_impl_->ScrollEnd();
1005 CompositorFrameMetadata metadata =
1006 host_impl_->MakeCompositorFrameMetadata();
1007 EXPECT_EQ(gfx::Vector2dF(0.f, 10.f), metadata.root_scroll_offset);
1010 // Page scale should update metadata correctly (shrinking only the viewport).
1011 host_impl_->PinchGestureBegin();
1012 host_impl_->PinchGestureUpdate(2.f, gfx::Point());
1013 host_impl_->PinchGestureEnd();
1015 CompositorFrameMetadata metadata =
1016 host_impl_->MakeCompositorFrameMetadata();
1017 EXPECT_EQ(gfx::Vector2dF(0.f, 10.f), metadata.root_scroll_offset);
1018 EXPECT_EQ(2.f, metadata.page_scale_factor);
1019 EXPECT_EQ(gfx::SizeF(25.f, 25.f), metadata.viewport_size);
1020 EXPECT_EQ(gfx::SizeF(100.f, 100.f), metadata.root_layer_size);
1021 EXPECT_EQ(0.5f, metadata.min_page_scale_factor);
1022 EXPECT_EQ(4.f, metadata.max_page_scale_factor);
1025 // Likewise if set from the main thread.
1026 host_impl_->ProcessScrollDeltas();
1027 host_impl_->active_tree()->SetPageScaleFactorAndLimits(4.f, 0.5f, 4.f);
1028 host_impl_->active_tree()->SetPageScaleDelta(1.f);
1030 CompositorFrameMetadata metadata =
1031 host_impl_->MakeCompositorFrameMetadata();
1032 EXPECT_EQ(gfx::Vector2dF(0.f, 10.f), metadata.root_scroll_offset);
1033 EXPECT_EQ(4.f, metadata.page_scale_factor);
1034 EXPECT_EQ(gfx::SizeF(12.5f, 12.5f), metadata.viewport_size);
1035 EXPECT_EQ(gfx::SizeF(100.f, 100.f), metadata.root_layer_size);
1036 EXPECT_EQ(0.5f, metadata.min_page_scale_factor);
1037 EXPECT_EQ(4.f, metadata.max_page_scale_factor);
1041 class DidDrawCheckLayer : public TiledLayerImpl {
1042 public:
1043 static scoped_ptr<LayerImpl> Create(LayerTreeImpl* tree_impl, int id) {
1044 return scoped_ptr<LayerImpl>(new DidDrawCheckLayer(tree_impl, id));
1047 virtual void DidDraw(ResourceProvider* provider) OVERRIDE {
1048 did_draw_called_ = true;
1051 virtual void WillDraw(ResourceProvider* provider) OVERRIDE {
1052 will_draw_called_ = true;
1055 bool did_draw_called() const { return did_draw_called_; }
1056 bool will_draw_called() const { return will_draw_called_; }
1058 void ClearDidDrawCheck() {
1059 did_draw_called_ = false;
1060 will_draw_called_ = false;
1063 protected:
1064 DidDrawCheckLayer(LayerTreeImpl* tree_impl, int id)
1065 : TiledLayerImpl(tree_impl, id),
1066 did_draw_called_(false),
1067 will_draw_called_(false) {
1068 SetAnchorPoint(gfx::PointF());
1069 SetBounds(gfx::Size(10, 10));
1070 SetContentBounds(gfx::Size(10, 10));
1071 SetDrawsContent(true);
1072 set_skips_draw(false);
1073 draw_properties().visible_content_rect = gfx::Rect(0, 0, 10, 10);
1075 scoped_ptr<LayerTilingData> tiler =
1076 LayerTilingData::Create(gfx::Size(100, 100),
1077 LayerTilingData::HAS_BORDER_TEXELS);
1078 tiler->SetBounds(content_bounds());
1079 SetTilingData(*tiler.get());
1082 private:
1083 bool did_draw_called_;
1084 bool will_draw_called_;
1087 TEST_F(LayerTreeHostImplTest, DidDrawNotCalledOnHiddenLayer) {
1088 // The root layer is always drawn, so run this test on a child layer that
1089 // will be masked out by the root layer's bounds.
1090 host_impl_->active_tree()->SetRootLayer(
1091 DidDrawCheckLayer::Create(host_impl_->active_tree(), 1));
1092 DidDrawCheckLayer* root = static_cast<DidDrawCheckLayer*>(
1093 host_impl_->active_tree()->root_layer());
1094 root->SetMasksToBounds(true);
1096 root->AddChild(DidDrawCheckLayer::Create(host_impl_->active_tree(), 2));
1097 DidDrawCheckLayer* layer =
1098 static_cast<DidDrawCheckLayer*>(root->children()[0]);
1099 // Ensure visible_content_rect for layer is empty.
1100 layer->SetPosition(gfx::PointF(100.f, 100.f));
1101 layer->SetBounds(gfx::Size(10, 10));
1102 layer->SetContentBounds(gfx::Size(10, 10));
1104 LayerTreeHostImpl::FrameData frame;
1106 EXPECT_FALSE(layer->will_draw_called());
1107 EXPECT_FALSE(layer->did_draw_called());
1109 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
1110 host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
1111 host_impl_->DidDrawAllLayers(frame);
1113 EXPECT_FALSE(layer->will_draw_called());
1114 EXPECT_FALSE(layer->did_draw_called());
1116 EXPECT_TRUE(layer->visible_content_rect().IsEmpty());
1118 // Ensure visible_content_rect for layer is not empty
1119 layer->SetPosition(gfx::PointF());
1121 EXPECT_FALSE(layer->will_draw_called());
1122 EXPECT_FALSE(layer->did_draw_called());
1124 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
1125 host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
1126 host_impl_->DidDrawAllLayers(frame);
1128 EXPECT_TRUE(layer->will_draw_called());
1129 EXPECT_TRUE(layer->did_draw_called());
1131 EXPECT_FALSE(layer->visible_content_rect().IsEmpty());
1134 TEST_F(LayerTreeHostImplTest, WillDrawNotCalledOnOccludedLayer) {
1135 gfx::Size big_size(1000, 1000);
1136 host_impl_->SetViewportSize(big_size);
1138 host_impl_->active_tree()->SetRootLayer(
1139 DidDrawCheckLayer::Create(host_impl_->active_tree(), 1));
1140 DidDrawCheckLayer* root =
1141 static_cast<DidDrawCheckLayer*>(host_impl_->active_tree()->root_layer());
1143 root->AddChild(DidDrawCheckLayer::Create(host_impl_->active_tree(), 2));
1144 DidDrawCheckLayer* occluded_layer =
1145 static_cast<DidDrawCheckLayer*>(root->children()[0]);
1147 root->AddChild(DidDrawCheckLayer::Create(host_impl_->active_tree(), 3));
1148 DidDrawCheckLayer* top_layer =
1149 static_cast<DidDrawCheckLayer*>(root->children()[1]);
1150 // This layer covers the occluded_layer above. Make this layer large so it can
1151 // occlude.
1152 top_layer->SetBounds(big_size);
1153 top_layer->SetContentBounds(big_size);
1154 top_layer->SetContentsOpaque(true);
1156 LayerTreeHostImpl::FrameData frame;
1158 EXPECT_FALSE(occluded_layer->will_draw_called());
1159 EXPECT_FALSE(occluded_layer->did_draw_called());
1160 EXPECT_FALSE(top_layer->will_draw_called());
1161 EXPECT_FALSE(top_layer->did_draw_called());
1163 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
1164 host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
1165 host_impl_->DidDrawAllLayers(frame);
1167 EXPECT_FALSE(occluded_layer->will_draw_called());
1168 EXPECT_FALSE(occluded_layer->did_draw_called());
1169 EXPECT_TRUE(top_layer->will_draw_called());
1170 EXPECT_TRUE(top_layer->did_draw_called());
1173 TEST_F(LayerTreeHostImplTest, DidDrawCalledOnAllLayers) {
1174 host_impl_->active_tree()->SetRootLayer(
1175 DidDrawCheckLayer::Create(host_impl_->active_tree(), 1));
1176 DidDrawCheckLayer* root =
1177 static_cast<DidDrawCheckLayer*>(host_impl_->active_tree()->root_layer());
1179 root->AddChild(DidDrawCheckLayer::Create(host_impl_->active_tree(), 2));
1180 DidDrawCheckLayer* layer1 =
1181 static_cast<DidDrawCheckLayer*>(root->children()[0]);
1183 layer1->AddChild(DidDrawCheckLayer::Create(host_impl_->active_tree(), 3));
1184 DidDrawCheckLayer* layer2 =
1185 static_cast<DidDrawCheckLayer*>(layer1->children()[0]);
1187 layer1->SetOpacity(0.3f);
1188 layer1->SetPreserves3d(false);
1190 EXPECT_FALSE(root->did_draw_called());
1191 EXPECT_FALSE(layer1->did_draw_called());
1192 EXPECT_FALSE(layer2->did_draw_called());
1194 LayerTreeHostImpl::FrameData frame;
1195 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
1196 host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
1197 host_impl_->DidDrawAllLayers(frame);
1199 EXPECT_TRUE(root->did_draw_called());
1200 EXPECT_TRUE(layer1->did_draw_called());
1201 EXPECT_TRUE(layer2->did_draw_called());
1203 EXPECT_NE(root->render_surface(), layer1->render_surface());
1204 EXPECT_TRUE(!!layer1->render_surface());
1207 class MissingTextureAnimatingLayer : public DidDrawCheckLayer {
1208 public:
1209 static scoped_ptr<LayerImpl> Create(LayerTreeImpl* tree_impl,
1210 int id,
1211 bool tile_missing,
1212 bool skips_draw,
1213 bool animating,
1214 ResourceProvider* resource_provider) {
1215 return scoped_ptr<LayerImpl>(new MissingTextureAnimatingLayer(
1216 tree_impl,
1218 tile_missing,
1219 skips_draw,
1220 animating,
1221 resource_provider));
1224 private:
1225 MissingTextureAnimatingLayer(LayerTreeImpl* tree_impl,
1226 int id,
1227 bool tile_missing,
1228 bool skips_draw,
1229 bool animating,
1230 ResourceProvider* resource_provider)
1231 : DidDrawCheckLayer(tree_impl, id) {
1232 scoped_ptr<LayerTilingData> tiling_data =
1233 LayerTilingData::Create(gfx::Size(10, 10),
1234 LayerTilingData::NO_BORDER_TEXELS);
1235 tiling_data->SetBounds(bounds());
1236 SetTilingData(*tiling_data.get());
1237 set_skips_draw(skips_draw);
1238 if (!tile_missing) {
1239 ResourceProvider::ResourceId resource =
1240 resource_provider->CreateResource(gfx::Size(),
1241 GL_RGBA,
1242 ResourceProvider::TextureUsageAny);
1243 resource_provider->AllocateForTesting(resource);
1244 PushTileProperties(0, 0, resource, gfx::Rect(), false);
1246 if (animating)
1247 AddAnimatedTransformToLayer(this, 10.0, 3, 0);
1251 TEST_F(LayerTreeHostImplTest, PrepareToDrawFailsWhenAnimationUsesCheckerboard) {
1252 // When the texture is not missing, we draw as usual.
1253 host_impl_->active_tree()->SetRootLayer(
1254 DidDrawCheckLayer::Create(host_impl_->active_tree(), 1));
1255 DidDrawCheckLayer* root =
1256 static_cast<DidDrawCheckLayer*>(host_impl_->active_tree()->root_layer());
1257 root->AddChild(
1258 MissingTextureAnimatingLayer::Create(host_impl_->active_tree(),
1260 false,
1261 false,
1262 true,
1263 host_impl_->resource_provider()));
1265 LayerTreeHostImpl::FrameData frame;
1267 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
1268 host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
1269 host_impl_->DidDrawAllLayers(frame);
1271 // When a texture is missing and we're not animating, we draw as usual with
1272 // checkerboarding.
1273 host_impl_->active_tree()->SetRootLayer(
1274 DidDrawCheckLayer::Create(host_impl_->active_tree(), 3));
1275 root =
1276 static_cast<DidDrawCheckLayer*>(host_impl_->active_tree()->root_layer());
1277 root->AddChild(
1278 MissingTextureAnimatingLayer::Create(host_impl_->active_tree(),
1280 true,
1281 false,
1282 false,
1283 host_impl_->resource_provider()));
1285 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
1286 host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
1287 host_impl_->DidDrawAllLayers(frame);
1289 // When a texture is missing and we're animating, we don't want to draw
1290 // anything.
1291 host_impl_->active_tree()->SetRootLayer(
1292 DidDrawCheckLayer::Create(host_impl_->active_tree(), 5));
1293 root =
1294 static_cast<DidDrawCheckLayer*>(host_impl_->active_tree()->root_layer());
1295 root->AddChild(
1296 MissingTextureAnimatingLayer::Create(host_impl_->active_tree(),
1298 true,
1299 false,
1300 true,
1301 host_impl_->resource_provider()));
1303 EXPECT_FALSE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
1304 host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
1305 host_impl_->DidDrawAllLayers(frame);
1307 // When the layer skips draw and we're animating, we still draw the frame.
1308 host_impl_->active_tree()->SetRootLayer(
1309 DidDrawCheckLayer::Create(host_impl_->active_tree(), 7));
1310 root =
1311 static_cast<DidDrawCheckLayer*>(host_impl_->active_tree()->root_layer());
1312 root->AddChild(
1313 MissingTextureAnimatingLayer::Create(host_impl_->active_tree(),
1315 false,
1316 true,
1317 true,
1318 host_impl_->resource_provider()));
1320 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
1321 host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
1322 host_impl_->DidDrawAllLayers(frame);
1325 TEST_F(LayerTreeHostImplTest, ScrollRootIgnored) {
1326 scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl_->active_tree(), 1);
1327 root->SetScrollable(false);
1328 host_impl_->active_tree()->SetRootLayer(root.Pass());
1329 InitializeRendererAndDrawFrame();
1331 // Scroll event is ignored because layer is not scrollable.
1332 EXPECT_EQ(InputHandlerClient::ScrollIgnored,
1333 host_impl_->ScrollBegin(gfx::Point(), InputHandlerClient::Wheel));
1334 EXPECT_FALSE(did_request_redraw_);
1335 EXPECT_FALSE(did_request_commit_);
1338 TEST_F(LayerTreeHostImplTest, ScrollNonScrollableRootWithTopControls) {
1339 LayerTreeSettings settings;
1340 settings.calculate_top_controls_position = true;
1341 settings.top_controls_height = 50;
1343 host_impl_ = LayerTreeHostImpl::Create(settings,
1344 this,
1345 &proxy_,
1346 &stats_instrumentation_);
1347 host_impl_->InitializeRenderer(CreateOutputSurface());
1348 host_impl_->SetViewportSize(gfx::Size(10, 10));
1350 gfx::Size layer_size(5, 5);
1351 scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl_->active_tree(), 1);
1352 root->SetScrollable(true);
1353 root->SetMaxScrollOffset(gfx::Vector2d(layer_size.width(),
1354 layer_size.height()));
1355 root->SetBounds(layer_size);
1356 root->SetContentBounds(layer_size);
1357 root->SetPosition(gfx::PointF());
1358 root->SetAnchorPoint(gfx::PointF());
1359 root->SetDrawsContent(false);
1360 host_impl_->active_tree()->SetRootLayer(root.Pass());
1361 host_impl_->active_tree()->FindRootScrollLayer();
1362 InitializeRendererAndDrawFrame();
1364 EXPECT_EQ(InputHandlerClient::ScrollIgnored,
1365 host_impl_->ScrollBegin(gfx::Point(), InputHandlerClient::Gesture));
1367 host_impl_->top_controls_manager()->ScrollBegin();
1368 host_impl_->top_controls_manager()->ScrollBy(gfx::Vector2dF(0.f, 50.f));
1369 host_impl_->top_controls_manager()->ScrollEnd();
1370 EXPECT_EQ(host_impl_->top_controls_manager()->content_top_offset(), 0.f);
1372 EXPECT_EQ(InputHandlerClient::ScrollStarted,
1373 host_impl_->ScrollBegin(gfx::Point(),
1374 InputHandlerClient::Gesture));
1377 TEST_F(LayerTreeHostImplTest, ScrollNonCompositedRoot) {
1378 // Test the configuration where a non-composited root layer is embedded in a
1379 // scrollable outer layer.
1380 gfx::Size surface_size(10, 10);
1382 scoped_ptr<LayerImpl> content_layer =
1383 LayerImpl::Create(host_impl_->active_tree(), 1);
1384 content_layer->SetDrawsContent(true);
1385 content_layer->SetPosition(gfx::PointF());
1386 content_layer->SetAnchorPoint(gfx::PointF());
1387 content_layer->SetBounds(surface_size);
1388 content_layer->SetContentBounds(gfx::Size(surface_size.width() * 2,
1389 surface_size.height() * 2));
1390 content_layer->SetContentsScale(2.f, 2.f);
1392 scoped_ptr<LayerImpl> scroll_layer =
1393 LayerImpl::Create(host_impl_->active_tree(), 2);
1394 scroll_layer->SetScrollable(true);
1395 scroll_layer->SetMaxScrollOffset(gfx::Vector2d(surface_size.width(),
1396 surface_size.height()));
1397 scroll_layer->SetBounds(surface_size);
1398 scroll_layer->SetContentBounds(surface_size);
1399 scroll_layer->SetPosition(gfx::PointF());
1400 scroll_layer->SetAnchorPoint(gfx::PointF());
1401 scroll_layer->AddChild(content_layer.Pass());
1403 host_impl_->active_tree()->SetRootLayer(scroll_layer.Pass());
1404 host_impl_->SetViewportSize(surface_size);
1405 InitializeRendererAndDrawFrame();
1407 EXPECT_EQ(InputHandlerClient::ScrollStarted,
1408 host_impl_->ScrollBegin(gfx::Point(5, 5),
1409 InputHandlerClient::Wheel));
1410 host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, 10));
1411 host_impl_->ScrollEnd();
1412 EXPECT_TRUE(did_request_redraw_);
1413 EXPECT_TRUE(did_request_commit_);
1416 TEST_F(LayerTreeHostImplTest, ScrollChildCallsCommitAndRedraw) {
1417 gfx::Size surface_size(10, 10);
1418 scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl_->active_tree(), 1);
1419 root->SetBounds(surface_size);
1420 root->SetContentBounds(surface_size);
1421 root->AddChild(CreateScrollableLayer(2, surface_size));
1422 host_impl_->active_tree()->SetRootLayer(root.Pass());
1423 host_impl_->SetViewportSize(surface_size);
1424 InitializeRendererAndDrawFrame();
1426 EXPECT_EQ(InputHandlerClient::ScrollStarted,
1427 host_impl_->ScrollBegin(gfx::Point(5, 5),
1428 InputHandlerClient::Wheel));
1429 host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, 10));
1430 host_impl_->ScrollEnd();
1431 EXPECT_TRUE(did_request_redraw_);
1432 EXPECT_TRUE(did_request_commit_);
1435 TEST_F(LayerTreeHostImplTest, ScrollMissesChild) {
1436 gfx::Size surface_size(10, 10);
1437 scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl_->active_tree(), 1);
1438 root->AddChild(CreateScrollableLayer(2, surface_size));
1439 host_impl_->active_tree()->SetRootLayer(root.Pass());
1440 host_impl_->SetViewportSize(surface_size);
1441 InitializeRendererAndDrawFrame();
1443 // Scroll event is ignored because the input coordinate is outside the layer
1444 // boundaries.
1445 EXPECT_EQ(InputHandlerClient::ScrollIgnored,
1446 host_impl_->ScrollBegin(gfx::Point(15, 5),
1447 InputHandlerClient::Wheel));
1448 EXPECT_FALSE(did_request_redraw_);
1449 EXPECT_FALSE(did_request_commit_);
1452 TEST_F(LayerTreeHostImplTest, ScrollMissesBackfacingChild) {
1453 gfx::Size surface_size(10, 10);
1454 scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl_->active_tree(), 1);
1455 scoped_ptr<LayerImpl> child = CreateScrollableLayer(2, surface_size);
1456 host_impl_->SetViewportSize(surface_size);
1458 gfx::Transform matrix;
1459 matrix.RotateAboutXAxis(180.0);
1460 child->SetTransform(matrix);
1461 child->SetDoubleSided(false);
1463 root->AddChild(child.Pass());
1464 host_impl_->active_tree()->SetRootLayer(root.Pass());
1465 InitializeRendererAndDrawFrame();
1467 // Scroll event is ignored because the scrollable layer is not facing the
1468 // viewer and there is nothing scrollable behind it.
1469 EXPECT_EQ(InputHandlerClient::ScrollIgnored,
1470 host_impl_->ScrollBegin(gfx::Point(5, 5),
1471 InputHandlerClient::Wheel));
1472 EXPECT_FALSE(did_request_redraw_);
1473 EXPECT_FALSE(did_request_commit_);
1476 TEST_F(LayerTreeHostImplTest, ScrollBlockedByContentLayer) {
1477 gfx::Size surface_size(10, 10);
1478 scoped_ptr<LayerImpl> content_layer = CreateScrollableLayer(1, surface_size);
1479 content_layer->SetShouldScrollOnMainThread(true);
1480 content_layer->SetScrollable(false);
1482 scoped_ptr<LayerImpl> scroll_layer = CreateScrollableLayer(2, surface_size);
1483 scroll_layer->AddChild(content_layer.Pass());
1485 host_impl_->active_tree()->SetRootLayer(scroll_layer.Pass());
1486 host_impl_->SetViewportSize(surface_size);
1487 InitializeRendererAndDrawFrame();
1489 // Scrolling fails because the content layer is asking to be scrolled on the
1490 // main thread.
1491 EXPECT_EQ(InputHandlerClient::ScrollOnMainThread,
1492 host_impl_->ScrollBegin(gfx::Point(5, 5),
1493 InputHandlerClient::Wheel));
1496 TEST_F(LayerTreeHostImplTest, ScrollRootAndChangePageScaleOnMainThread) {
1497 gfx::Size surface_size(10, 10);
1498 float page_scale = 2.f;
1499 scoped_ptr<LayerImpl> root = CreateScrollableLayer(1, surface_size);
1500 host_impl_->active_tree()->SetRootLayer(root.Pass());
1501 host_impl_->active_tree()->DidBecomeActive();
1502 host_impl_->SetViewportSize(surface_size);
1503 InitializeRendererAndDrawFrame();
1505 gfx::Vector2d scroll_delta(0, 10);
1506 gfx::Vector2d expected_scroll_delta = scroll_delta;
1507 gfx::Vector2d expected_max_scroll =
1508 host_impl_->active_tree()->root_layer()->max_scroll_offset();
1509 EXPECT_EQ(InputHandlerClient::ScrollStarted,
1510 host_impl_->ScrollBegin(gfx::Point(5, 5),
1511 InputHandlerClient::Wheel));
1512 host_impl_->ScrollBy(gfx::Point(), scroll_delta);
1513 host_impl_->ScrollEnd();
1515 // Set new page scale from main thread.
1516 host_impl_->active_tree()->SetPageScaleFactorAndLimits(page_scale,
1517 page_scale,
1518 page_scale);
1520 scoped_ptr<ScrollAndScaleSet> scroll_info = host_impl_->ProcessScrollDeltas();
1521 ExpectContains(*scroll_info.get(),
1522 host_impl_->active_tree()->root_layer()->id(),
1523 expected_scroll_delta);
1525 // The scroll range should also have been updated.
1526 EXPECT_EQ(expected_max_scroll,
1527 host_impl_->active_tree()->root_layer()->max_scroll_offset());
1529 // The page scale delta remains constant because the impl thread did not
1530 // scale.
1531 EXPECT_EQ(1.f, host_impl_->active_tree()->page_scale_delta());
1534 TEST_F(LayerTreeHostImplTest, ScrollRootAndChangePageScaleOnImplThread) {
1535 gfx::Size surface_size(10, 10);
1536 float page_scale = 2.f;
1537 scoped_ptr<LayerImpl> root = CreateScrollableLayer(1, surface_size);
1538 host_impl_->active_tree()->SetRootLayer(root.Pass());
1539 host_impl_->active_tree()->DidBecomeActive();
1540 host_impl_->SetViewportSize(surface_size);
1541 host_impl_->active_tree()->SetPageScaleFactorAndLimits(1.f, 1.f, page_scale);
1542 InitializeRendererAndDrawFrame();
1544 gfx::Vector2d scroll_delta(0, 10);
1545 gfx::Vector2d expected_scroll_delta = scroll_delta;
1546 gfx::Vector2d expected_max_scroll =
1547 host_impl_->active_tree()->root_layer()->max_scroll_offset();
1548 EXPECT_EQ(InputHandlerClient::ScrollStarted,
1549 host_impl_->ScrollBegin(gfx::Point(5, 5),
1550 InputHandlerClient::Wheel));
1551 host_impl_->ScrollBy(gfx::Point(), scroll_delta);
1552 host_impl_->ScrollEnd();
1554 // Set new page scale on impl thread by pinching.
1555 host_impl_->PinchGestureBegin();
1556 host_impl_->PinchGestureUpdate(page_scale, gfx::Point());
1557 host_impl_->PinchGestureEnd();
1558 DrawOneFrame();
1560 // The scroll delta is not scaled because the main thread did not scale.
1561 scoped_ptr<ScrollAndScaleSet> scroll_info = host_impl_->ProcessScrollDeltas();
1562 ExpectContains(*scroll_info.get(),
1563 host_impl_->active_tree()->root_layer()->id(),
1564 expected_scroll_delta);
1566 // The scroll range should also have been updated.
1567 EXPECT_EQ(expected_max_scroll,
1568 host_impl_->active_tree()->root_layer()->max_scroll_offset());
1570 // The page scale delta should match the new scale on the impl side.
1571 EXPECT_EQ(page_scale, host_impl_->active_tree()->total_page_scale_factor());
1574 TEST_F(LayerTreeHostImplTest, PageScaleDeltaAppliedToRootScrollLayerOnly) {
1575 gfx::Size surface_size(10, 10);
1576 float default_page_scale = 1.f;
1577 gfx::Transform default_page_scale_matrix;
1578 default_page_scale_matrix.Scale(default_page_scale, default_page_scale);
1580 float new_page_scale = 2.f;
1581 gfx::Transform new_page_scale_matrix;
1582 new_page_scale_matrix.Scale(new_page_scale, new_page_scale);
1584 // Create a normal scrollable root layer and another scrollable child layer.
1585 SetupScrollAndContentsLayers(surface_size);
1586 LayerImpl* root = host_impl_->active_tree()->root_layer();
1587 LayerImpl* child = root->children()[0];
1589 scoped_ptr<LayerImpl> scrollable_child =
1590 CreateScrollableLayer(3, surface_size);
1591 child->AddChild(scrollable_child.Pass());
1592 LayerImpl* grand_child = child->children()[0];
1594 // Set new page scale on impl thread by pinching.
1595 host_impl_->PinchGestureBegin();
1596 host_impl_->PinchGestureUpdate(new_page_scale, gfx::Point());
1597 host_impl_->PinchGestureEnd();
1598 DrawOneFrame();
1600 EXPECT_EQ(1.f, root->contents_scale_x());
1601 EXPECT_EQ(1.f, root->contents_scale_y());
1602 EXPECT_EQ(1.f, child->contents_scale_x());
1603 EXPECT_EQ(1.f, child->contents_scale_y());
1604 EXPECT_EQ(1.f, grand_child->contents_scale_x());
1605 EXPECT_EQ(1.f, grand_child->contents_scale_y());
1607 // Make sure all the layers are drawn with the page scale delta applied, i.e.,
1608 // the page scale delta on the root layer is applied hierarchically.
1609 LayerTreeHostImpl::FrameData frame;
1610 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
1611 host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
1612 host_impl_->DidDrawAllLayers(frame);
1614 EXPECT_EQ(new_page_scale, root->draw_transform().matrix().getDouble(0, 0));
1615 EXPECT_EQ(new_page_scale, root->draw_transform().matrix().getDouble(1, 1));
1616 EXPECT_EQ(new_page_scale, child->draw_transform().matrix().getDouble(0, 0));
1617 EXPECT_EQ(new_page_scale, child->draw_transform().matrix().getDouble(1, 1));
1618 EXPECT_EQ(new_page_scale,
1619 grand_child->draw_transform().matrix().getDouble(0, 0));
1620 EXPECT_EQ(new_page_scale,
1621 grand_child->draw_transform().matrix().getDouble(1, 1));
1624 TEST_F(LayerTreeHostImplTest, ScrollChildAndChangePageScaleOnMainThread) {
1625 gfx::Size surface_size(10, 10);
1626 scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl_->active_tree(), 1);
1627 root->SetBounds(surface_size);
1628 root->SetContentBounds(surface_size);
1629 // Also mark the root scrollable so it becomes the root scroll layer.
1630 root->SetScrollable(true);
1631 int scroll_layer_id = 2;
1632 root->AddChild(CreateScrollableLayer(scroll_layer_id, surface_size));
1633 host_impl_->active_tree()->SetRootLayer(root.Pass());
1634 host_impl_->active_tree()->DidBecomeActive();
1635 host_impl_->SetViewportSize(surface_size);
1636 InitializeRendererAndDrawFrame();
1638 LayerImpl* child = host_impl_->active_tree()->root_layer()->children()[0];
1640 gfx::Vector2d scroll_delta(0, 10);
1641 gfx::Vector2d expected_scroll_delta(scroll_delta);
1642 gfx::Vector2d expected_max_scroll(child->max_scroll_offset());
1643 EXPECT_EQ(InputHandlerClient::ScrollStarted,
1644 host_impl_->ScrollBegin(gfx::Point(5, 5),
1645 InputHandlerClient::Wheel));
1646 host_impl_->ScrollBy(gfx::Point(), scroll_delta);
1647 host_impl_->ScrollEnd();
1649 float page_scale = 2.f;
1650 host_impl_->active_tree()->SetPageScaleFactorAndLimits(page_scale,
1651 1.f,
1652 page_scale);
1654 DrawOneFrame();
1656 scoped_ptr<ScrollAndScaleSet> scroll_info = host_impl_->ProcessScrollDeltas();
1657 ExpectContains(*scroll_info.get(), scroll_layer_id, expected_scroll_delta);
1659 // The scroll range should not have changed.
1660 EXPECT_EQ(child->max_scroll_offset(), expected_max_scroll);
1662 // The page scale delta remains constant because the impl thread did not
1663 // scale.
1664 EXPECT_EQ(1.f, host_impl_->active_tree()->page_scale_delta());
1667 TEST_F(LayerTreeHostImplTest, ScrollChildBeyondLimit) {
1668 // Scroll a child layer beyond its maximum scroll range and make sure the
1669 // parent layer is scrolled on the axis on which the child was unable to
1670 // scroll.
1671 gfx::Size surface_size(10, 10);
1672 scoped_ptr<LayerImpl> root = CreateScrollableLayer(1, surface_size);
1674 scoped_ptr<LayerImpl> grand_child = CreateScrollableLayer(3, surface_size);
1675 grand_child->SetScrollOffset(gfx::Vector2d(0, 5));
1677 scoped_ptr<LayerImpl> child = CreateScrollableLayer(2, surface_size);
1678 child->SetScrollOffset(gfx::Vector2d(3, 0));
1679 child->AddChild(grand_child.Pass());
1681 root->AddChild(child.Pass());
1682 host_impl_->active_tree()->SetRootLayer(root.Pass());
1683 host_impl_->active_tree()->DidBecomeActive();
1684 host_impl_->SetViewportSize(surface_size);
1685 InitializeRendererAndDrawFrame();
1687 gfx::Vector2d scroll_delta(-8, -7);
1688 EXPECT_EQ(InputHandlerClient::ScrollStarted,
1689 host_impl_->ScrollBegin(gfx::Point(5, 5),
1690 InputHandlerClient::Wheel));
1691 host_impl_->ScrollBy(gfx::Point(), scroll_delta);
1692 host_impl_->ScrollEnd();
1694 scoped_ptr<ScrollAndScaleSet> scroll_info =
1695 host_impl_->ProcessScrollDeltas();
1697 // The grand child should have scrolled up to its limit.
1698 LayerImpl* child = host_impl_->active_tree()->root_layer()->children()[0];
1699 LayerImpl* grand_child = child->children()[0];
1700 ExpectContains(*scroll_info.get(), grand_child->id(), gfx::Vector2d(0, -5));
1702 // The child should have only scrolled on the other axis.
1703 ExpectContains(*scroll_info.get(), child->id(), gfx::Vector2d(-3, 0));
1707 TEST_F(LayerTreeHostImplTest, ScrollWithoutBubbling) {
1708 // Scroll a child layer beyond its maximum scroll range and make sure the
1709 // the scroll doesn't bubble up to the parent layer.
1710 gfx::Size surface_size(10, 10);
1711 scoped_ptr<LayerImpl> root = CreateScrollableLayer(1, surface_size);
1713 scoped_ptr<LayerImpl> grand_child = CreateScrollableLayer(3, surface_size);
1714 grand_child->SetScrollOffset(gfx::Vector2d(0, 2));
1716 scoped_ptr<LayerImpl> child = CreateScrollableLayer(2, surface_size);
1717 child->SetScrollOffset(gfx::Vector2d(0, 3));
1718 child->AddChild(grand_child.Pass());
1720 root->AddChild(child.Pass());
1721 host_impl_->active_tree()->SetRootLayer(root.Pass());
1722 host_impl_->active_tree()->DidBecomeActive();
1723 host_impl_->SetViewportSize(surface_size);
1724 InitializeRendererAndDrawFrame();
1726 gfx::Vector2d scroll_delta(0, -10);
1727 EXPECT_EQ(InputHandlerClient::ScrollStarted,
1728 host_impl_->ScrollBegin(gfx::Point(5, 5),
1729 InputHandlerClient::NonBubblingGesture));
1730 host_impl_->ScrollBy(gfx::Point(), scroll_delta);
1731 host_impl_->ScrollEnd();
1733 scoped_ptr<ScrollAndScaleSet> scroll_info =
1734 host_impl_->ProcessScrollDeltas();
1736 // The grand child should have scrolled up to its limit.
1737 LayerImpl* child = host_impl_->active_tree()->root_layer()->children()[0];
1738 LayerImpl* grand_child = child->children()[0];
1739 ExpectContains(*scroll_info.get(), grand_child->id(), gfx::Vector2d(0, -2));
1741 // The child should not have scrolled.
1742 ExpectNone(*scroll_info.get(), child->id());
1744 // The next time we scroll we should only scroll the parent.
1745 scroll_delta = gfx::Vector2d(0, -3);
1746 EXPECT_EQ(InputHandlerClient::ScrollStarted,
1747 host_impl_->ScrollBegin(gfx::Point(5, 5),
1748 InputHandlerClient::NonBubblingGesture));
1749 EXPECT_EQ(host_impl_->CurrentlyScrollingLayer(), grand_child);
1750 host_impl_->ScrollBy(gfx::Point(), scroll_delta);
1751 EXPECT_EQ(host_impl_->CurrentlyScrollingLayer(), child);
1752 host_impl_->ScrollEnd();
1754 scroll_info = host_impl_->ProcessScrollDeltas();
1756 // The child should have scrolled up to its limit.
1757 ExpectContains(*scroll_info.get(), child->id(), gfx::Vector2d(0, -3));
1759 // The grand child should not have scrolled.
1760 ExpectContains(*scroll_info.get(), grand_child->id(), gfx::Vector2d(0, -2));
1762 // After scrolling the parent, another scroll on the opposite direction
1763 // should still scroll the child.
1764 scroll_delta = gfx::Vector2d(0, 7);
1765 EXPECT_EQ(InputHandlerClient::ScrollStarted,
1766 host_impl_->ScrollBegin(gfx::Point(5, 5),
1767 InputHandlerClient::NonBubblingGesture));
1768 EXPECT_EQ(host_impl_->CurrentlyScrollingLayer(), grand_child);
1769 host_impl_->ScrollBy(gfx::Point(), scroll_delta);
1770 EXPECT_EQ(host_impl_->CurrentlyScrollingLayer(), grand_child);
1771 host_impl_->ScrollEnd();
1773 scroll_info = host_impl_->ProcessScrollDeltas();
1775 // The grand child should have scrolled.
1776 ExpectContains(*scroll_info.get(), grand_child->id(), gfx::Vector2d(0, 5));
1778 // The child should not have scrolled.
1779 ExpectContains(*scroll_info.get(), child->id(), gfx::Vector2d(0, -3));
1782 // Scrolling should be adjusted from viewport space.
1783 host_impl_->active_tree()->SetPageScaleFactorAndLimits(2.f, 2.f, 2.f);
1784 host_impl_->active_tree()->SetPageScaleDelta(1.f);
1786 scroll_delta = gfx::Vector2d(0, -2);
1787 EXPECT_EQ(InputHandlerClient::ScrollStarted,
1788 host_impl_->ScrollBegin(gfx::Point(1, 1),
1789 InputHandlerClient::NonBubblingGesture));
1790 EXPECT_EQ(grand_child, host_impl_->CurrentlyScrollingLayer());
1791 host_impl_->ScrollBy(gfx::Point(), scroll_delta);
1792 host_impl_->ScrollEnd();
1794 scroll_info = host_impl_->ProcessScrollDeltas();
1796 // Should have scrolled by half the amount in layer space (5 - 2/2)
1797 ExpectContains(*scroll_info.get(), grand_child->id(), gfx::Vector2d(0, 4));
1801 TEST_F(LayerTreeHostImplTest, ScrollEventBubbling) {
1802 // When we try to scroll a non-scrollable child layer, the scroll delta
1803 // should be applied to one of its ancestors if possible.
1804 gfx::Size surface_size(10, 10);
1805 gfx::Size content_size(20, 20);
1806 scoped_ptr<LayerImpl> root = CreateScrollableLayer(1, content_size);
1807 scoped_ptr<LayerImpl> child = CreateScrollableLayer(2, content_size);
1809 child->SetScrollable(false);
1810 root->AddChild(child.Pass());
1812 host_impl_->SetViewportSize(surface_size);
1813 host_impl_->active_tree()->SetRootLayer(root.Pass());
1814 host_impl_->active_tree()->DidBecomeActive();
1815 InitializeRendererAndDrawFrame();
1817 gfx::Vector2d scroll_delta(0, 4);
1818 EXPECT_EQ(InputHandlerClient::ScrollStarted,
1819 host_impl_->ScrollBegin(gfx::Point(5, 5),
1820 InputHandlerClient::Wheel));
1821 host_impl_->ScrollBy(gfx::Point(), scroll_delta);
1822 host_impl_->ScrollEnd();
1824 scoped_ptr<ScrollAndScaleSet> scroll_info =
1825 host_impl_->ProcessScrollDeltas();
1827 // Only the root should have scrolled.
1828 ASSERT_EQ(scroll_info->scrolls.size(), 1u);
1829 ExpectContains(*scroll_info.get(),
1830 host_impl_->active_tree()->root_layer()->id(),
1831 scroll_delta);
1835 TEST_F(LayerTreeHostImplTest, ScrollBeforeRedraw) {
1836 gfx::Size surface_size(10, 10);
1837 host_impl_->active_tree()->SetRootLayer(
1838 CreateScrollableLayer(1, surface_size));
1839 host_impl_->active_tree()->DidBecomeActive();
1840 host_impl_->SetViewportSize(surface_size);
1842 // Draw one frame and then immediately rebuild the layer tree to mimic a tree
1843 // synchronization.
1844 InitializeRendererAndDrawFrame();
1845 host_impl_->active_tree()->DetachLayerTree();
1846 host_impl_->active_tree()->SetRootLayer(
1847 CreateScrollableLayer(2, surface_size));
1848 host_impl_->active_tree()->DidBecomeActive();
1850 // Scrolling should still work even though we did not draw yet.
1851 EXPECT_EQ(InputHandlerClient::ScrollStarted,
1852 host_impl_->ScrollBegin(gfx::Point(5, 5),
1853 InputHandlerClient::Wheel));
1856 TEST_F(LayerTreeHostImplTest, ScrollAxisAlignedRotatedLayer) {
1857 SetupScrollAndContentsLayers(gfx::Size(100, 100));
1859 // Rotate the root layer 90 degrees counter-clockwise about its center.
1860 gfx::Transform rotate_transform;
1861 rotate_transform.Rotate(-90.0);
1862 host_impl_->active_tree()->root_layer()->SetTransform(rotate_transform);
1864 gfx::Size surface_size(50, 50);
1865 host_impl_->SetViewportSize(surface_size);
1866 InitializeRendererAndDrawFrame();
1868 // Scroll to the right in screen coordinates with a gesture.
1869 gfx::Vector2d gesture_scroll_delta(10, 0);
1870 EXPECT_EQ(InputHandlerClient::ScrollStarted,
1871 host_impl_->ScrollBegin(gfx::Point(),
1872 InputHandlerClient::Gesture));
1873 host_impl_->ScrollBy(gfx::Point(), gesture_scroll_delta);
1874 host_impl_->ScrollEnd();
1876 // The layer should have scrolled down in its local coordinates.
1877 scoped_ptr<ScrollAndScaleSet> scroll_info = host_impl_->ProcessScrollDeltas();
1878 ExpectContains(*scroll_info.get(),
1879 host_impl_->active_tree()->root_layer()->id(),
1880 gfx::Vector2d(0, gesture_scroll_delta.x()));
1882 // Reset and scroll down with the wheel.
1883 host_impl_->active_tree()->root_layer()->SetScrollDelta(gfx::Vector2dF());
1884 gfx::Vector2d wheel_scroll_delta(0, 10);
1885 EXPECT_EQ(InputHandlerClient::ScrollStarted,
1886 host_impl_->ScrollBegin(gfx::Point(),
1887 InputHandlerClient::Wheel));
1888 host_impl_->ScrollBy(gfx::Point(), wheel_scroll_delta);
1889 host_impl_->ScrollEnd();
1891 // The layer should have scrolled down in its local coordinates.
1892 scroll_info = host_impl_->ProcessScrollDeltas();
1893 ExpectContains(*scroll_info.get(),
1894 host_impl_->active_tree()->root_layer()->id(),
1895 wheel_scroll_delta);
1898 TEST_F(LayerTreeHostImplTest, ScrollNonAxisAlignedRotatedLayer) {
1899 SetupScrollAndContentsLayers(gfx::Size(100, 100));
1900 int child_layer_id = 3;
1901 float child_layer_angle = -20.f;
1903 // Create a child layer that is rotated to a non-axis-aligned angle.
1904 scoped_ptr<LayerImpl> child = CreateScrollableLayer(
1905 child_layer_id,
1906 host_impl_->active_tree()->root_layer()->content_bounds());
1907 gfx::Transform rotate_transform;
1908 rotate_transform.Translate(-50.0, -50.0);
1909 rotate_transform.Rotate(child_layer_angle);
1910 rotate_transform.Translate(50.0, 50.0);
1911 child->SetTransform(rotate_transform);
1913 // Only allow vertical scrolling.
1914 child->SetMaxScrollOffset(gfx::Vector2d(0, child->content_bounds().height()));
1915 host_impl_->active_tree()->root_layer()->AddChild(child.Pass());
1917 gfx::Size surface_size(50, 50);
1918 host_impl_->SetViewportSize(surface_size);
1919 InitializeRendererAndDrawFrame();
1921 // Scroll down in screen coordinates with a gesture.
1922 gfx::Vector2d gesture_scroll_delta(0, 10);
1923 EXPECT_EQ(InputHandlerClient::ScrollStarted,
1924 host_impl_->ScrollBegin(gfx::Point(),
1925 InputHandlerClient::Gesture));
1926 host_impl_->ScrollBy(gfx::Point(), gesture_scroll_delta);
1927 host_impl_->ScrollEnd();
1929 // The child layer should have scrolled down in its local coordinates an
1930 // amount proportional to the angle between it and the input scroll delta.
1931 gfx::Vector2d expected_scroll_delta(
1933 gesture_scroll_delta.y() *
1934 std::cos(MathUtil::Deg2Rad(child_layer_angle)));
1935 scoped_ptr<ScrollAndScaleSet> scroll_info =
1936 host_impl_->ProcessScrollDeltas();
1937 ExpectContains(*scroll_info.get(), child_layer_id, expected_scroll_delta);
1939 // The root layer should not have scrolled, because the input delta was
1940 // close to the layer's axis of movement.
1941 EXPECT_EQ(scroll_info->scrolls.size(), 1u);
1944 // Now reset and scroll the same amount horizontally.
1945 host_impl_->active_tree()->root_layer()->children()[1]->SetScrollDelta(
1946 gfx::Vector2dF());
1947 gfx::Vector2d gesture_scroll_delta(10, 0);
1948 EXPECT_EQ(InputHandlerClient::ScrollStarted,
1949 host_impl_->ScrollBegin(gfx::Point(),
1950 InputHandlerClient::Gesture));
1951 host_impl_->ScrollBy(gfx::Point(), gesture_scroll_delta);
1952 host_impl_->ScrollEnd();
1954 // The child layer should have scrolled down in its local coordinates an
1955 // amount proportional to the angle between it and the input scroll delta.
1956 gfx::Vector2d expected_scroll_delta(
1958 -gesture_scroll_delta.x() *
1959 std::sin(MathUtil::Deg2Rad(child_layer_angle)));
1960 scoped_ptr<ScrollAndScaleSet> scroll_info =
1961 host_impl_->ProcessScrollDeltas();
1962 ExpectContains(*scroll_info.get(), child_layer_id, expected_scroll_delta);
1964 // The root layer should have scrolled more, since the input scroll delta
1965 // was mostly orthogonal to the child layer's vertical scroll axis.
1966 gfx::Vector2d expected_root_scroll_delta(
1967 gesture_scroll_delta.x() *
1968 std::pow(std::cos(MathUtil::Deg2Rad(child_layer_angle)), 2),
1970 ExpectContains(*scroll_info.get(),
1971 host_impl_->active_tree()->root_layer()->id(),
1972 expected_root_scroll_delta);
1976 TEST_F(LayerTreeHostImplTest, ScrollScaledLayer) {
1977 SetupScrollAndContentsLayers(gfx::Size(100, 100));
1979 // Scale the layer to twice its normal size.
1980 int scale = 2;
1981 gfx::Transform scale_transform;
1982 scale_transform.Scale(scale, scale);
1983 host_impl_->active_tree()->root_layer()->SetTransform(scale_transform);
1985 gfx::Size surface_size(50, 50);
1986 host_impl_->SetViewportSize(surface_size);
1987 InitializeRendererAndDrawFrame();
1989 // Scroll down in screen coordinates with a gesture.
1990 gfx::Vector2d scroll_delta(0, 10);
1991 EXPECT_EQ(InputHandlerClient::ScrollStarted,
1992 host_impl_->ScrollBegin(gfx::Point(), InputHandlerClient::Gesture));
1993 host_impl_->ScrollBy(gfx::Point(), scroll_delta);
1994 host_impl_->ScrollEnd();
1996 // The layer should have scrolled down in its local coordinates, but half the
1997 // amount.
1998 scoped_ptr<ScrollAndScaleSet> scroll_info = host_impl_->ProcessScrollDeltas();
1999 ExpectContains(*scroll_info.get(),
2000 host_impl_->active_tree()->root_layer()->id(),
2001 gfx::Vector2d(0, scroll_delta.y() / scale));
2003 // Reset and scroll down with the wheel.
2004 host_impl_->active_tree()->root_layer()->SetScrollDelta(gfx::Vector2dF());
2005 gfx::Vector2d wheel_scroll_delta(0, 10);
2006 EXPECT_EQ(InputHandlerClient::ScrollStarted,
2007 host_impl_->ScrollBegin(gfx::Point(), InputHandlerClient::Wheel));
2008 host_impl_->ScrollBy(gfx::Point(), wheel_scroll_delta);
2009 host_impl_->ScrollEnd();
2011 // The scale should not have been applied to the scroll delta.
2012 scroll_info = host_impl_->ProcessScrollDeltas();
2013 ExpectContains(*scroll_info.get(),
2014 host_impl_->active_tree()->root_layer()->id(),
2015 wheel_scroll_delta);
2018 class BlendStateTrackerContext: public TestWebGraphicsContext3D {
2019 public:
2020 BlendStateTrackerContext() : blend_(false) {}
2022 virtual void enable(WebKit::WGC3Denum cap) OVERRIDE {
2023 if (cap == GL_BLEND)
2024 blend_ = true;
2027 virtual void disable(WebKit::WGC3Denum cap) OVERRIDE {
2028 if (cap == GL_BLEND)
2029 blend_ = false;
2032 bool blend() const { return blend_; }
2034 private:
2035 bool blend_;
2038 class BlendStateCheckLayer : public LayerImpl {
2039 public:
2040 static scoped_ptr<LayerImpl> Create(LayerTreeImpl* tree_impl,
2041 int id,
2042 ResourceProvider* resource_provider) {
2043 return scoped_ptr<LayerImpl>(new BlendStateCheckLayer(tree_impl,
2045 resource_provider));
2048 virtual void AppendQuads(QuadSink* quad_sink,
2049 AppendQuadsData* append_quads_data) OVERRIDE {
2050 quads_appended_ = true;
2052 gfx::Rect opaque_rect;
2053 if (contents_opaque())
2054 opaque_rect = quad_rect_;
2055 else
2056 opaque_rect = opaque_content_rect_;
2058 SharedQuadState* shared_quad_state =
2059 quad_sink->UseSharedQuadState(CreateSharedQuadState());
2060 scoped_ptr<TileDrawQuad> test_blending_draw_quad = TileDrawQuad::Create();
2061 test_blending_draw_quad->SetNew(shared_quad_state,
2062 quad_rect_,
2063 opaque_rect,
2064 resource_id_,
2065 gfx::RectF(0.f, 0.f, 1.f, 1.f),
2066 gfx::Size(1, 1),
2067 false);
2068 test_blending_draw_quad->visible_rect = quad_visible_rect_;
2069 EXPECT_EQ(blend_, test_blending_draw_quad->ShouldDrawWithBlending());
2070 EXPECT_EQ(has_render_surface_, !!render_surface());
2071 quad_sink->Append(test_blending_draw_quad.PassAs<DrawQuad>(),
2072 append_quads_data);
2075 void SetExpectation(bool blend, bool has_render_surface) {
2076 blend_ = blend;
2077 has_render_surface_ = has_render_surface;
2078 quads_appended_ = false;
2081 bool quads_appended() const { return quads_appended_; }
2083 void SetQuadRect(gfx::Rect rect) { quad_rect_ = rect; }
2084 void SetQuadVisibleRect(gfx::Rect rect) { quad_visible_rect_ = rect; }
2085 void SetOpaqueContentRect(gfx::Rect rect) { opaque_content_rect_ = rect; }
2087 private:
2088 BlendStateCheckLayer(LayerTreeImpl* tree_impl,
2089 int id,
2090 ResourceProvider* resource_provider)
2091 : LayerImpl(tree_impl, id),
2092 blend_(false),
2093 has_render_surface_(false),
2094 quads_appended_(false),
2095 quad_rect_(5, 5, 5, 5),
2096 quad_visible_rect_(5, 5, 5, 5),
2097 resource_id_(resource_provider->CreateResource(
2098 gfx::Size(1, 1),
2099 GL_RGBA,
2100 ResourceProvider::TextureUsageAny)) {
2101 resource_provider->AllocateForTesting(resource_id_);
2102 SetAnchorPoint(gfx::PointF());
2103 SetBounds(gfx::Size(10, 10));
2104 SetContentBounds(gfx::Size(10, 10));
2105 SetDrawsContent(true);
2108 bool blend_;
2109 bool has_render_surface_;
2110 bool quads_appended_;
2111 gfx::Rect quad_rect_;
2112 gfx::Rect opaque_content_rect_;
2113 gfx::Rect quad_visible_rect_;
2114 ResourceProvider::ResourceId resource_id_;
2117 TEST_F(LayerTreeHostImplTest, BlendingOffWhenDrawingOpaqueLayers) {
2119 scoped_ptr<LayerImpl> root =
2120 LayerImpl::Create(host_impl_->active_tree(), 1);
2121 root->SetAnchorPoint(gfx::PointF());
2122 root->SetBounds(gfx::Size(10, 10));
2123 root->SetContentBounds(root->bounds());
2124 root->SetDrawsContent(false);
2125 host_impl_->active_tree()->SetRootLayer(root.Pass());
2127 LayerImpl* root = host_impl_->active_tree()->root_layer();
2129 root->AddChild(
2130 BlendStateCheckLayer::Create(host_impl_->active_tree(),
2132 host_impl_->resource_provider()));
2133 BlendStateCheckLayer* layer1 =
2134 static_cast<BlendStateCheckLayer*>(root->children()[0]);
2135 layer1->SetPosition(gfx::PointF(2.f, 2.f));
2137 LayerTreeHostImpl::FrameData frame;
2139 // Opaque layer, drawn without blending.
2140 layer1->SetContentsOpaque(true);
2141 layer1->SetExpectation(false, false);
2142 layer1->set_update_rect(gfx::RectF(layer1->content_bounds()));
2143 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
2144 host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
2145 EXPECT_TRUE(layer1->quads_appended());
2146 host_impl_->DidDrawAllLayers(frame);
2148 // Layer with translucent content and painting, so drawn with blending.
2149 layer1->SetContentsOpaque(false);
2150 layer1->SetExpectation(true, false);
2151 layer1->set_update_rect(gfx::RectF(layer1->content_bounds()));
2152 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
2153 host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
2154 EXPECT_TRUE(layer1->quads_appended());
2155 host_impl_->DidDrawAllLayers(frame);
2157 // Layer with translucent opacity, drawn with blending.
2158 layer1->SetContentsOpaque(true);
2159 layer1->SetOpacity(0.5f);
2160 layer1->SetExpectation(true, false);
2161 layer1->set_update_rect(gfx::RectF(layer1->content_bounds()));
2162 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
2163 host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
2164 EXPECT_TRUE(layer1->quads_appended());
2165 host_impl_->DidDrawAllLayers(frame);
2167 // Layer with translucent opacity and painting, drawn with blending.
2168 layer1->SetContentsOpaque(true);
2169 layer1->SetOpacity(0.5f);
2170 layer1->SetExpectation(true, false);
2171 layer1->set_update_rect(gfx::RectF(layer1->content_bounds()));
2172 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
2173 host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
2174 EXPECT_TRUE(layer1->quads_appended());
2175 host_impl_->DidDrawAllLayers(frame);
2177 layer1->AddChild(
2178 BlendStateCheckLayer::Create(host_impl_->active_tree(),
2180 host_impl_->resource_provider()));
2181 BlendStateCheckLayer* layer2 =
2182 static_cast<BlendStateCheckLayer*>(layer1->children()[0]);
2183 layer2->SetPosition(gfx::PointF(4.f, 4.f));
2185 // 2 opaque layers, drawn without blending.
2186 layer1->SetContentsOpaque(true);
2187 layer1->SetOpacity(1.f);
2188 layer1->SetExpectation(false, false);
2189 layer1->set_update_rect(gfx::RectF(layer1->content_bounds()));
2190 layer2->SetContentsOpaque(true);
2191 layer2->SetOpacity(1.f);
2192 layer2->SetExpectation(false, false);
2193 layer2->set_update_rect(gfx::RectF(layer1->content_bounds()));
2194 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
2195 host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
2196 EXPECT_TRUE(layer1->quads_appended());
2197 EXPECT_TRUE(layer2->quads_appended());
2198 host_impl_->DidDrawAllLayers(frame);
2200 // Parent layer with translucent content, drawn with blending.
2201 // Child layer with opaque content, drawn without blending.
2202 layer1->SetContentsOpaque(false);
2203 layer1->SetExpectation(true, false);
2204 layer1->set_update_rect(gfx::RectF(layer1->content_bounds()));
2205 layer2->SetExpectation(false, false);
2206 layer2->set_update_rect(gfx::RectF(layer1->content_bounds()));
2207 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
2208 host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
2209 EXPECT_TRUE(layer1->quads_appended());
2210 EXPECT_TRUE(layer2->quads_appended());
2211 host_impl_->DidDrawAllLayers(frame);
2213 // Parent layer with translucent content but opaque painting, drawn without
2214 // blending.
2215 // Child layer with opaque content, drawn without blending.
2216 layer1->SetContentsOpaque(true);
2217 layer1->SetExpectation(false, false);
2218 layer1->set_update_rect(gfx::RectF(layer1->content_bounds()));
2219 layer2->SetExpectation(false, false);
2220 layer2->set_update_rect(gfx::RectF(layer1->content_bounds()));
2221 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
2222 host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
2223 EXPECT_TRUE(layer1->quads_appended());
2224 EXPECT_TRUE(layer2->quads_appended());
2225 host_impl_->DidDrawAllLayers(frame);
2227 // Parent layer with translucent opacity and opaque content. Since it has a
2228 // drawing child, it's drawn to a render surface which carries the opacity,
2229 // so it's itself drawn without blending.
2230 // Child layer with opaque content, drawn without blending (parent surface
2231 // carries the inherited opacity).
2232 layer1->SetContentsOpaque(true);
2233 layer1->SetOpacity(0.5f);
2234 layer1->SetExpectation(false, true);
2235 layer1->set_update_rect(gfx::RectF(layer1->content_bounds()));
2236 layer2->SetExpectation(false, false);
2237 layer2->set_update_rect(gfx::RectF(layer1->content_bounds()));
2238 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
2239 host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
2240 EXPECT_TRUE(layer1->quads_appended());
2241 EXPECT_TRUE(layer2->quads_appended());
2242 host_impl_->DidDrawAllLayers(frame);
2244 // Draw again, but with child non-opaque, to make sure
2245 // layer1 not culled.
2246 layer1->SetContentsOpaque(true);
2247 layer1->SetOpacity(1.f);
2248 layer1->SetExpectation(false, false);
2249 layer1->set_update_rect(gfx::RectF(layer1->content_bounds()));
2250 layer2->SetContentsOpaque(true);
2251 layer2->SetOpacity(0.5f);
2252 layer2->SetExpectation(true, false);
2253 layer2->set_update_rect(gfx::RectF(layer1->content_bounds()));
2254 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
2255 host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
2256 EXPECT_TRUE(layer1->quads_appended());
2257 EXPECT_TRUE(layer2->quads_appended());
2258 host_impl_->DidDrawAllLayers(frame);
2260 // A second way of making the child non-opaque.
2261 layer1->SetContentsOpaque(true);
2262 layer1->SetOpacity(1.f);
2263 layer1->SetExpectation(false, false);
2264 layer1->set_update_rect(gfx::RectF(layer1->content_bounds()));
2265 layer2->SetContentsOpaque(false);
2266 layer2->SetOpacity(1.f);
2267 layer2->SetExpectation(true, false);
2268 layer2->set_update_rect(gfx::RectF(layer1->content_bounds()));
2269 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
2270 host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
2271 EXPECT_TRUE(layer1->quads_appended());
2272 EXPECT_TRUE(layer2->quads_appended());
2273 host_impl_->DidDrawAllLayers(frame);
2275 // And when the layer says its not opaque but is painted opaque, it is not
2276 // blended.
2277 layer1->SetContentsOpaque(true);
2278 layer1->SetOpacity(1.f);
2279 layer1->SetExpectation(false, false);
2280 layer1->set_update_rect(gfx::RectF(layer1->content_bounds()));
2281 layer2->SetContentsOpaque(true);
2282 layer2->SetOpacity(1.f);
2283 layer2->SetExpectation(false, false);
2284 layer2->set_update_rect(gfx::RectF(layer1->content_bounds()));
2285 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
2286 host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
2287 EXPECT_TRUE(layer1->quads_appended());
2288 EXPECT_TRUE(layer2->quads_appended());
2289 host_impl_->DidDrawAllLayers(frame);
2291 // Layer with partially opaque contents, drawn with blending.
2292 layer1->SetContentsOpaque(false);
2293 layer1->SetQuadRect(gfx::Rect(5, 5, 5, 5));
2294 layer1->SetQuadVisibleRect(gfx::Rect(5, 5, 5, 5));
2295 layer1->SetOpaqueContentRect(gfx::Rect(5, 5, 2, 5));
2296 layer1->SetExpectation(true, false);
2297 layer1->set_update_rect(gfx::RectF(layer1->content_bounds()));
2298 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
2299 host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
2300 EXPECT_TRUE(layer1->quads_appended());
2301 host_impl_->DidDrawAllLayers(frame);
2303 // Layer with partially opaque contents partially culled, drawn with blending.
2304 layer1->SetContentsOpaque(false);
2305 layer1->SetQuadRect(gfx::Rect(5, 5, 5, 5));
2306 layer1->SetQuadVisibleRect(gfx::Rect(5, 5, 5, 2));
2307 layer1->SetOpaqueContentRect(gfx::Rect(5, 5, 2, 5));
2308 layer1->SetExpectation(true, false);
2309 layer1->set_update_rect(gfx::RectF(layer1->content_bounds()));
2310 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
2311 host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
2312 EXPECT_TRUE(layer1->quads_appended());
2313 host_impl_->DidDrawAllLayers(frame);
2315 // Layer with partially opaque contents culled, drawn with blending.
2316 layer1->SetContentsOpaque(false);
2317 layer1->SetQuadRect(gfx::Rect(5, 5, 5, 5));
2318 layer1->SetQuadVisibleRect(gfx::Rect(7, 5, 3, 5));
2319 layer1->SetOpaqueContentRect(gfx::Rect(5, 5, 2, 5));
2320 layer1->SetExpectation(true, false);
2321 layer1->set_update_rect(gfx::RectF(layer1->content_bounds()));
2322 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
2323 host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
2324 EXPECT_TRUE(layer1->quads_appended());
2325 host_impl_->DidDrawAllLayers(frame);
2327 // Layer with partially opaque contents and translucent contents culled, drawn
2328 // without blending.
2329 layer1->SetContentsOpaque(false);
2330 layer1->SetQuadRect(gfx::Rect(5, 5, 5, 5));
2331 layer1->SetQuadVisibleRect(gfx::Rect(5, 5, 2, 5));
2332 layer1->SetOpaqueContentRect(gfx::Rect(5, 5, 2, 5));
2333 layer1->SetExpectation(false, false);
2334 layer1->set_update_rect(gfx::RectF(layer1->content_bounds()));
2335 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
2336 host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
2337 EXPECT_TRUE(layer1->quads_appended());
2338 host_impl_->DidDrawAllLayers(frame);
2341 TEST_F(LayerTreeHostImplTest, ViewportCovered) {
2342 host_impl_->InitializeRenderer(CreateOutputSurface());
2343 host_impl_->active_tree()->set_background_color(SK_ColorGRAY);
2345 gfx::Size viewport_size(1000, 1000);
2346 host_impl_->SetViewportSize(viewport_size);
2348 host_impl_->active_tree()->SetRootLayer(
2349 LayerImpl::Create(host_impl_->active_tree(), 1));
2350 host_impl_->active_tree()->root_layer()->AddChild(
2351 BlendStateCheckLayer::Create(host_impl_->active_tree(),
2353 host_impl_->resource_provider()));
2354 BlendStateCheckLayer* child = static_cast<BlendStateCheckLayer*>(
2355 host_impl_->active_tree()->root_layer()->children()[0]);
2356 child->SetExpectation(false, false);
2357 child->SetContentsOpaque(true);
2359 // No gutter rects
2361 gfx::Rect layer_rect(0, 0, 1000, 1000);
2362 child->SetPosition(layer_rect.origin());
2363 child->SetBounds(layer_rect.size());
2364 child->SetContentBounds(layer_rect.size());
2365 child->SetQuadRect(gfx::Rect(layer_rect.size()));
2366 child->SetQuadVisibleRect(gfx::Rect(layer_rect.size()));
2368 LayerTreeHostImpl::FrameData frame;
2369 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
2370 ASSERT_EQ(1u, frame.render_passes.size());
2372 size_t num_gutter_quads = 0;
2373 for (size_t i = 0; i < frame.render_passes[0]->quad_list.size(); ++i)
2374 num_gutter_quads += (frame.render_passes[0]->quad_list[i]->material ==
2375 DrawQuad::SOLID_COLOR) ? 1 : 0;
2376 EXPECT_EQ(0u, num_gutter_quads);
2377 EXPECT_EQ(1u, frame.render_passes[0]->quad_list.size());
2379 LayerTestCommon::VerifyQuadsExactlyCoverRect(
2380 frame.render_passes[0]->quad_list, gfx::Rect(viewport_size));
2381 host_impl_->DidDrawAllLayers(frame);
2384 // Empty visible content area (fullscreen gutter rect)
2386 gfx::Rect layer_rect(0, 0, 0, 0);
2387 child->SetPosition(layer_rect.origin());
2388 child->SetBounds(layer_rect.size());
2389 child->SetContentBounds(layer_rect.size());
2390 child->SetQuadRect(gfx::Rect(layer_rect.size()));
2391 child->SetQuadVisibleRect(gfx::Rect(layer_rect.size()));
2393 LayerTreeHostImpl::FrameData frame;
2394 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
2395 ASSERT_EQ(1u, frame.render_passes.size());
2397 size_t num_gutter_quads = 0;
2398 for (size_t i = 0; i < frame.render_passes[0]->quad_list.size(); ++i)
2399 num_gutter_quads += (frame.render_passes[0]->quad_list[i]->material ==
2400 DrawQuad::SOLID_COLOR) ? 1 : 0;
2401 EXPECT_EQ(1u, num_gutter_quads);
2402 EXPECT_EQ(1u, frame.render_passes[0]->quad_list.size());
2404 LayerTestCommon::VerifyQuadsExactlyCoverRect(
2405 frame.render_passes[0]->quad_list, gfx::Rect(viewport_size));
2406 host_impl_->DidDrawAllLayers(frame);
2409 // Content area in middle of clip rect (four surrounding gutter rects)
2411 gfx::Rect layer_rect(500, 500, 200, 200);
2412 child->SetPosition(layer_rect.origin());
2413 child->SetBounds(layer_rect.size());
2414 child->SetContentBounds(layer_rect.size());
2415 child->SetQuadRect(gfx::Rect(layer_rect.size()));
2416 child->SetQuadVisibleRect(gfx::Rect(layer_rect.size()));
2418 LayerTreeHostImpl::FrameData frame;
2419 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
2420 ASSERT_EQ(1u, frame.render_passes.size());
2422 size_t num_gutter_quads = 0;
2423 for (size_t i = 0; i < frame.render_passes[0]->quad_list.size(); ++i)
2424 num_gutter_quads += (frame.render_passes[0]->quad_list[i]->material ==
2425 DrawQuad::SOLID_COLOR) ? 1 : 0;
2426 EXPECT_EQ(4u, num_gutter_quads);
2427 EXPECT_EQ(5u, frame.render_passes[0]->quad_list.size());
2429 LayerTestCommon::VerifyQuadsExactlyCoverRect(
2430 frame.render_passes[0]->quad_list, gfx::Rect(viewport_size));
2431 host_impl_->DidDrawAllLayers(frame);
2436 class ReshapeTrackerContext: public TestWebGraphicsContext3D {
2437 public:
2438 ReshapeTrackerContext() : reshape_called_(false) {}
2440 virtual void reshape(int width, int height) OVERRIDE {
2441 reshape_called_ = true;
2444 bool reshape_called() const { return reshape_called_; }
2446 private:
2447 bool reshape_called_;
2450 class FakeDrawableLayerImpl: public LayerImpl {
2451 public:
2452 static scoped_ptr<LayerImpl> Create(LayerTreeImpl* tree_impl, int id) {
2453 return scoped_ptr<LayerImpl>(new FakeDrawableLayerImpl(tree_impl, id));
2455 protected:
2456 FakeDrawableLayerImpl(LayerTreeImpl* tree_impl, int id)
2457 : LayerImpl(tree_impl, id) {}
2460 // Only reshape when we know we are going to draw. Otherwise, the reshape
2461 // can leave the window at the wrong size if we never draw and the proper
2462 // viewport size is never set.
2463 TEST_F(LayerTreeHostImplTest, ReshapeNotCalledUntilDraw) {
2464 scoped_ptr<OutputSurface> output_surface = FakeOutputSurface::Create3d(
2465 scoped_ptr<WebKit::WebGraphicsContext3D>(new ReshapeTrackerContext))
2466 .PassAs<OutputSurface>();
2467 ReshapeTrackerContext* reshape_tracker =
2468 static_cast<ReshapeTrackerContext*>(output_surface->context3d());
2469 host_impl_->InitializeRenderer(output_surface.Pass());
2471 scoped_ptr<LayerImpl> root =
2472 FakeDrawableLayerImpl::Create(host_impl_->active_tree(), 1);
2473 root->SetAnchorPoint(gfx::PointF());
2474 root->SetBounds(gfx::Size(10, 10));
2475 root->SetContentBounds(gfx::Size(10, 10));
2476 root->SetDrawsContent(true);
2477 host_impl_->active_tree()->SetRootLayer(root.Pass());
2478 EXPECT_FALSE(reshape_tracker->reshape_called());
2480 LayerTreeHostImpl::FrameData frame;
2481 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
2482 host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
2483 EXPECT_TRUE(reshape_tracker->reshape_called());
2484 host_impl_->DidDrawAllLayers(frame);
2487 class PartialSwapTrackerContext : public TestWebGraphicsContext3D {
2488 public:
2489 virtual void postSubBufferCHROMIUM(int x, int y, int width, int height)
2490 OVERRIDE {
2491 partial_swap_rect_ = gfx::Rect(x, y, width, height);
2494 virtual WebKit::WebString getString(WebKit::WGC3Denum name) OVERRIDE {
2495 if (name == GL_EXTENSIONS) {
2496 return WebKit::WebString(
2497 "GL_CHROMIUM_post_sub_buffer GL_CHROMIUM_set_visibility");
2500 return WebKit::WebString();
2503 gfx::Rect partial_swap_rect() const { return partial_swap_rect_; }
2505 private:
2506 gfx::Rect partial_swap_rect_;
2509 // Make sure damage tracking propagates all the way to the graphics context,
2510 // where it should request to swap only the sub-buffer that is damaged.
2511 TEST_F(LayerTreeHostImplTest, PartialSwapReceivesDamageRect) {
2512 scoped_ptr<OutputSurface> output_surface =
2513 FakeOutputSurface::Create3d(scoped_ptr<WebKit::WebGraphicsContext3D>(
2514 new PartialSwapTrackerContext)).PassAs<OutputSurface>();
2515 PartialSwapTrackerContext* partial_swap_tracker =
2516 static_cast<PartialSwapTrackerContext*>(output_surface->context3d());
2518 // This test creates its own LayerTreeHostImpl, so
2519 // that we can force partial swap enabled.
2520 LayerTreeSettings settings;
2521 settings.partial_swap_enabled = true;
2522 scoped_ptr<LayerTreeHostImpl> layer_tree_host_impl =
2523 LayerTreeHostImpl::Create(settings,
2524 this,
2525 &proxy_,
2526 &stats_instrumentation_);
2527 layer_tree_host_impl->InitializeRenderer(output_surface.Pass());
2528 layer_tree_host_impl->SetViewportSize(gfx::Size(500, 500));
2530 scoped_ptr<LayerImpl> root =
2531 FakeDrawableLayerImpl::Create(layer_tree_host_impl->active_tree(), 1);
2532 scoped_ptr<LayerImpl> child =
2533 FakeDrawableLayerImpl::Create(layer_tree_host_impl->active_tree(), 2);
2534 child->SetPosition(gfx::PointF(12.f, 13.f));
2535 child->SetAnchorPoint(gfx::PointF());
2536 child->SetBounds(gfx::Size(14, 15));
2537 child->SetContentBounds(gfx::Size(14, 15));
2538 child->SetDrawsContent(true);
2539 root->SetAnchorPoint(gfx::PointF());
2540 root->SetBounds(gfx::Size(500, 500));
2541 root->SetContentBounds(gfx::Size(500, 500));
2542 root->SetDrawsContent(true);
2543 root->AddChild(child.Pass());
2544 layer_tree_host_impl->active_tree()->SetRootLayer(root.Pass());
2546 LayerTreeHostImpl::FrameData frame;
2548 // First frame, the entire screen should get swapped.
2549 EXPECT_TRUE(layer_tree_host_impl->PrepareToDraw(&frame, gfx::Rect()));
2550 layer_tree_host_impl->DrawLayers(&frame, base::TimeTicks::Now());
2551 layer_tree_host_impl->DidDrawAllLayers(frame);
2552 layer_tree_host_impl->SwapBuffers(frame);
2553 gfx::Rect actual_swap_rect = partial_swap_tracker->partial_swap_rect();
2554 gfx::Rect expected_swap_rect = gfx::Rect(0, 0, 500, 500);
2555 EXPECT_EQ(expected_swap_rect.x(), actual_swap_rect.x());
2556 EXPECT_EQ(expected_swap_rect.y(), actual_swap_rect.y());
2557 EXPECT_EQ(expected_swap_rect.width(), actual_swap_rect.width());
2558 EXPECT_EQ(expected_swap_rect.height(), actual_swap_rect.height());
2560 // Second frame, only the damaged area should get swapped. Damage should be
2561 // the union of old and new child rects.
2562 // expected damage rect: gfx::Rect(26, 28);
2563 // expected swap rect: vertically flipped, with origin at bottom left corner.
2564 layer_tree_host_impl->active_tree()->root_layer()->children()[0]->SetPosition(
2565 gfx::PointF());
2566 EXPECT_TRUE(layer_tree_host_impl->PrepareToDraw(&frame, gfx::Rect()));
2567 layer_tree_host_impl->DrawLayers(&frame, base::TimeTicks::Now());
2568 host_impl_->DidDrawAllLayers(frame);
2569 layer_tree_host_impl->SwapBuffers(frame);
2570 actual_swap_rect = partial_swap_tracker->partial_swap_rect();
2571 expected_swap_rect = gfx::Rect(0, 500-28, 26, 28);
2572 EXPECT_EQ(expected_swap_rect.x(), actual_swap_rect.x());
2573 EXPECT_EQ(expected_swap_rect.y(), actual_swap_rect.y());
2574 EXPECT_EQ(expected_swap_rect.width(), actual_swap_rect.width());
2575 EXPECT_EQ(expected_swap_rect.height(), actual_swap_rect.height());
2577 // Make sure that partial swap is constrained to the viewport dimensions
2578 // expected damage rect: gfx::Rect(500, 500);
2579 // expected swap rect: flipped damage rect, but also clamped to viewport
2580 layer_tree_host_impl->SetViewportSize(gfx::Size(10, 10));
2581 // This will damage everything.
2582 layer_tree_host_impl->active_tree()->root_layer()->SetOpacity(0.7f);
2583 EXPECT_TRUE(layer_tree_host_impl->PrepareToDraw(&frame, gfx::Rect()));
2584 layer_tree_host_impl->DrawLayers(&frame, base::TimeTicks::Now());
2585 host_impl_->DidDrawAllLayers(frame);
2586 layer_tree_host_impl->SwapBuffers(frame);
2587 actual_swap_rect = partial_swap_tracker->partial_swap_rect();
2588 expected_swap_rect = gfx::Rect(10, 10);
2589 EXPECT_EQ(expected_swap_rect.x(), actual_swap_rect.x());
2590 EXPECT_EQ(expected_swap_rect.y(), actual_swap_rect.y());
2591 EXPECT_EQ(expected_swap_rect.width(), actual_swap_rect.width());
2592 EXPECT_EQ(expected_swap_rect.height(), actual_swap_rect.height());
2595 TEST_F(LayerTreeHostImplTest, RootLayerDoesntCreateExtraSurface) {
2596 scoped_ptr<LayerImpl> root =
2597 FakeDrawableLayerImpl::Create(host_impl_->active_tree(), 1);
2598 scoped_ptr<LayerImpl> child =
2599 FakeDrawableLayerImpl::Create(host_impl_->active_tree(), 2);
2600 child->SetAnchorPoint(gfx::PointF());
2601 child->SetBounds(gfx::Size(10, 10));
2602 child->SetContentBounds(gfx::Size(10, 10));
2603 child->SetDrawsContent(true);
2604 root->SetAnchorPoint(gfx::PointF());
2605 root->SetBounds(gfx::Size(10, 10));
2606 root->SetContentBounds(gfx::Size(10, 10));
2607 root->SetDrawsContent(true);
2608 root->SetOpacity(0.7f);
2609 root->AddChild(child.Pass());
2611 host_impl_->active_tree()->SetRootLayer(root.Pass());
2613 LayerTreeHostImpl::FrameData frame;
2615 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
2616 EXPECT_EQ(1u, frame.render_surface_layer_list->size());
2617 EXPECT_EQ(1u, frame.render_passes.size());
2618 host_impl_->DidDrawAllLayers(frame);
2621 class FakeLayerWithQuads : public LayerImpl {
2622 public:
2623 static scoped_ptr<LayerImpl> Create(LayerTreeImpl* tree_impl, int id) {
2624 return scoped_ptr<LayerImpl>(new FakeLayerWithQuads(tree_impl, id));
2627 virtual void AppendQuads(QuadSink* quad_sink,
2628 AppendQuadsData* append_quads_data) OVERRIDE {
2629 SharedQuadState* shared_quad_state =
2630 quad_sink->UseSharedQuadState(CreateSharedQuadState());
2632 SkColor gray = SkColorSetRGB(100, 100, 100);
2633 gfx::Rect quad_rect(content_bounds());
2634 scoped_ptr<SolidColorDrawQuad> my_quad = SolidColorDrawQuad::Create();
2635 my_quad->SetNew(shared_quad_state, quad_rect, gray);
2636 quad_sink->Append(my_quad.PassAs<DrawQuad>(), append_quads_data);
2639 private:
2640 FakeLayerWithQuads(LayerTreeImpl* tree_impl, int id)
2641 : LayerImpl(tree_impl, id) {}
2644 class MockContext : public TestWebGraphicsContext3D {
2645 public:
2646 MOCK_METHOD1(useProgram, void(WebKit::WebGLId program));
2647 MOCK_METHOD5(uniform4f, void(WebKit::WGC3Dint location,
2648 WebKit::WGC3Dfloat x,
2649 WebKit::WGC3Dfloat y,
2650 WebKit::WGC3Dfloat z,
2651 WebKit::WGC3Dfloat w));
2652 MOCK_METHOD4(uniformMatrix4fv, void(WebKit::WGC3Dint location,
2653 WebKit::WGC3Dsizei count,
2654 WebKit::WGC3Dboolean transpose,
2655 const WebKit::WGC3Dfloat* value));
2656 MOCK_METHOD4(drawElements, void(WebKit::WGC3Denum mode,
2657 WebKit::WGC3Dsizei count,
2658 WebKit::WGC3Denum type,
2659 WebKit::WGC3Dintptr offset));
2660 MOCK_METHOD1(getString, WebKit::WebString(WebKit::WGC3Denum name));
2661 MOCK_METHOD0(getRequestableExtensionsCHROMIUM, WebKit::WebString());
2662 MOCK_METHOD1(enable, void(WebKit::WGC3Denum cap));
2663 MOCK_METHOD1(disable, void(WebKit::WGC3Denum cap));
2664 MOCK_METHOD4(scissor, void(WebKit::WGC3Dint x,
2665 WebKit::WGC3Dint y,
2666 WebKit::WGC3Dsizei width,
2667 WebKit::WGC3Dsizei height));
2670 class MockContextHarness {
2671 private:
2672 MockContext* context_;
2674 public:
2675 explicit MockContextHarness(MockContext* context)
2676 : context_(context) {
2677 // Catch "uninteresting" calls
2678 EXPECT_CALL(*context_, useProgram(_))
2679 .Times(0);
2681 EXPECT_CALL(*context_, drawElements(_, _, _, _))
2682 .Times(0);
2684 // These are not asserted
2685 EXPECT_CALL(*context_, uniformMatrix4fv(_, _, _, _))
2686 .WillRepeatedly(Return());
2688 EXPECT_CALL(*context_, uniform4f(_, _, _, _, _))
2689 .WillRepeatedly(Return());
2691 // Any other strings are empty
2692 EXPECT_CALL(*context_, getString(_))
2693 .WillRepeatedly(Return(WebKit::WebString()));
2695 // Support for partial swap, if needed
2696 EXPECT_CALL(*context_, getString(GL_EXTENSIONS))
2697 .WillRepeatedly(Return(
2698 WebKit::WebString("GL_CHROMIUM_post_sub_buffer")));
2700 EXPECT_CALL(*context_, getRequestableExtensionsCHROMIUM())
2701 .WillRepeatedly(Return(
2702 WebKit::WebString("GL_CHROMIUM_post_sub_buffer")));
2704 // Any un-sanctioned calls to enable() are OK
2705 EXPECT_CALL(*context_, enable(_))
2706 .WillRepeatedly(Return());
2708 // Any un-sanctioned calls to disable() are OK
2709 EXPECT_CALL(*context_, disable(_))
2710 .WillRepeatedly(Return());
2713 void MustDrawSolidQuad() {
2714 EXPECT_CALL(*context_, drawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, 0))
2715 .WillOnce(Return())
2716 .RetiresOnSaturation();
2718 EXPECT_CALL(*context_, useProgram(_))
2719 .WillOnce(Return())
2720 .RetiresOnSaturation();
2723 void MustSetScissor(int x, int y, int width, int height) {
2724 EXPECT_CALL(*context_, enable(GL_SCISSOR_TEST))
2725 .WillRepeatedly(Return());
2727 EXPECT_CALL(*context_, scissor(x, y, width, height))
2728 .Times(AtLeast(1))
2729 .WillRepeatedly(Return());
2732 void MustSetNoScissor() {
2733 EXPECT_CALL(*context_, disable(GL_SCISSOR_TEST))
2734 .WillRepeatedly(Return());
2736 EXPECT_CALL(*context_, enable(GL_SCISSOR_TEST))
2737 .Times(0);
2739 EXPECT_CALL(*context_, scissor(_, _, _, _))
2740 .Times(0);
2744 TEST_F(LayerTreeHostImplTest, NoPartialSwap) {
2745 scoped_ptr<OutputSurface> output_surface =
2746 FakeOutputSurface::Create3d(scoped_ptr<WebKit::WebGraphicsContext3D>(
2747 new MockContext)).PassAs<OutputSurface>();
2748 MockContext* mock_context =
2749 static_cast<MockContext*>(output_surface->context3d());
2750 MockContextHarness harness(mock_context);
2752 // Run test case
2753 CreateLayerTreeHost(false, output_surface.Pass());
2754 SetupRootLayerImpl(FakeLayerWithQuads::Create(host_impl_->active_tree(), 1));
2756 // Without partial swap, and no clipping, no scissor is set.
2757 harness.MustDrawSolidQuad();
2758 harness.MustSetNoScissor();
2760 LayerTreeHostImpl::FrameData frame;
2761 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
2762 host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
2763 host_impl_->DidDrawAllLayers(frame);
2765 Mock::VerifyAndClearExpectations(&mock_context);
2767 // Without partial swap, but a layer does clip its subtree, one scissor is
2768 // set.
2769 host_impl_->active_tree()->root_layer()->SetMasksToBounds(true);
2770 harness.MustDrawSolidQuad();
2771 harness.MustSetScissor(0, 0, 10, 10);
2773 LayerTreeHostImpl::FrameData frame;
2774 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
2775 host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
2776 host_impl_->DidDrawAllLayers(frame);
2778 Mock::VerifyAndClearExpectations(&mock_context);
2781 TEST_F(LayerTreeHostImplTest, PartialSwap) {
2782 scoped_ptr<OutputSurface> output_surface =
2783 FakeOutputSurface::Create3d(scoped_ptr<WebKit::WebGraphicsContext3D>(
2784 new MockContext)).PassAs<OutputSurface>();
2785 MockContext* mock_context =
2786 static_cast<MockContext*>(output_surface->context3d());
2787 MockContextHarness harness(mock_context);
2789 CreateLayerTreeHost(true, output_surface.Pass());
2790 SetupRootLayerImpl(FakeLayerWithQuads::Create(host_impl_->active_tree(), 1));
2792 // The first frame is not a partially-swapped one.
2793 harness.MustSetScissor(0, 0, 10, 10);
2794 harness.MustDrawSolidQuad();
2796 LayerTreeHostImpl::FrameData frame;
2797 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
2798 host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
2799 host_impl_->DidDrawAllLayers(frame);
2801 Mock::VerifyAndClearExpectations(&mock_context);
2803 // Damage a portion of the frame.
2804 host_impl_->active_tree()->root_layer()->set_update_rect(
2805 gfx::Rect(0, 0, 2, 3));
2807 // The second frame will be partially-swapped (the y coordinates are flipped).
2808 harness.MustSetScissor(0, 7, 2, 3);
2809 harness.MustDrawSolidQuad();
2811 LayerTreeHostImpl::FrameData frame;
2812 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
2813 host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
2814 host_impl_->DidDrawAllLayers(frame);
2816 Mock::VerifyAndClearExpectations(&mock_context);
2819 class PartialSwapContext : public TestWebGraphicsContext3D {
2820 public:
2821 virtual WebKit::WebString getString(WebKit::WGC3Denum name) OVERRIDE {
2822 if (name == GL_EXTENSIONS)
2823 return WebKit::WebString("GL_CHROMIUM_post_sub_buffer");
2824 return WebKit::WebString();
2827 virtual WebKit::WebString getRequestableExtensionsCHROMIUM() OVERRIDE {
2828 return WebKit::WebString("GL_CHROMIUM_post_sub_buffer");
2831 // Unlimited texture size.
2832 virtual void getIntegerv(WebKit::WGC3Denum pname, WebKit::WGC3Dint* value)
2833 OVERRIDE {
2834 if (pname == GL_MAX_TEXTURE_SIZE)
2835 *value = 8192;
2839 static scoped_ptr<LayerTreeHostImpl> SetupLayersForOpacity(
2840 bool partial_swap,
2841 LayerTreeHostImplClient* client,
2842 Proxy* proxy,
2843 RenderingStatsInstrumentation* stats_instrumentation) {
2844 scoped_ptr<OutputSurface> output_surface =
2845 FakeOutputSurface::Create3d(scoped_ptr<WebKit::WebGraphicsContext3D>(
2846 new PartialSwapContext)).PassAs<OutputSurface>();
2848 LayerTreeSettings settings;
2849 settings.partial_swap_enabled = partial_swap;
2850 scoped_ptr<LayerTreeHostImpl> my_host_impl =
2851 LayerTreeHostImpl::Create(settings, client, proxy, stats_instrumentation);
2852 my_host_impl->InitializeRenderer(output_surface.Pass());
2853 my_host_impl->SetViewportSize(gfx::Size(100, 100));
2856 Layers are created as follows:
2858 +--------------------+
2859 | 1 |
2860 | +-----------+ |
2861 | | 2 | |
2862 | | +-------------------+
2863 | | | 3 |
2864 | | +-------------------+
2865 | | | |
2866 | +-----------+ |
2869 +--------------------+
2871 Layers 1, 2 have render surfaces
2873 scoped_ptr<LayerImpl> root =
2874 LayerImpl::Create(my_host_impl->active_tree(), 1);
2875 scoped_ptr<LayerImpl> child =
2876 LayerImpl::Create(my_host_impl->active_tree(), 2);
2877 scoped_ptr<LayerImpl> grand_child =
2878 FakeLayerWithQuads::Create(my_host_impl->active_tree(), 3);
2880 gfx::Rect root_rect(0, 0, 100, 100);
2881 gfx::Rect child_rect(10, 10, 50, 50);
2882 gfx::Rect grand_child_rect(5, 5, 150, 150);
2884 root->CreateRenderSurface();
2885 root->SetAnchorPoint(gfx::PointF());
2886 root->SetPosition(root_rect.origin());
2887 root->SetBounds(root_rect.size());
2888 root->SetContentBounds(root->bounds());
2889 root->draw_properties().visible_content_rect = root_rect;
2890 root->SetDrawsContent(false);
2891 root->render_surface()->SetContentRect(gfx::Rect(root_rect.size()));
2893 child->SetAnchorPoint(gfx::PointF());
2894 child->SetPosition(gfx::PointF(child_rect.x(), child_rect.y()));
2895 child->SetOpacity(0.5f);
2896 child->SetBounds(gfx::Size(child_rect.width(), child_rect.height()));
2897 child->SetContentBounds(child->bounds());
2898 child->draw_properties().visible_content_rect = child_rect;
2899 child->SetDrawsContent(false);
2900 child->SetForceRenderSurface(true);
2902 grand_child->SetAnchorPoint(gfx::PointF());
2903 grand_child->SetPosition(grand_child_rect.origin());
2904 grand_child->SetBounds(grand_child_rect.size());
2905 grand_child->SetContentBounds(grand_child->bounds());
2906 grand_child->draw_properties().visible_content_rect = grand_child_rect;
2907 grand_child->SetDrawsContent(true);
2909 child->AddChild(grand_child.Pass());
2910 root->AddChild(child.Pass());
2912 my_host_impl->active_tree()->SetRootLayer(root.Pass());
2913 return my_host_impl.Pass();
2916 TEST_F(LayerTreeHostImplTest, ContributingLayerEmptyScissorPartialSwap) {
2917 scoped_ptr<LayerTreeHostImpl> my_host_impl =
2918 SetupLayersForOpacity(true, this, &proxy_, &stats_instrumentation_);
2920 LayerTreeHostImpl::FrameData frame;
2921 EXPECT_TRUE(my_host_impl->PrepareToDraw(&frame, gfx::Rect()));
2923 // Verify all quads have been computed
2924 ASSERT_EQ(2U, frame.render_passes.size());
2925 ASSERT_EQ(1U, frame.render_passes[0]->quad_list.size());
2926 ASSERT_EQ(1U, frame.render_passes[1]->quad_list.size());
2927 EXPECT_EQ(DrawQuad::SOLID_COLOR,
2928 frame.render_passes[0]->quad_list[0]->material);
2929 EXPECT_EQ(DrawQuad::RENDER_PASS,
2930 frame.render_passes[1]->quad_list[0]->material);
2932 my_host_impl->DrawLayers(&frame, base::TimeTicks::Now());
2933 my_host_impl->DidDrawAllLayers(frame);
2937 TEST_F(LayerTreeHostImplTest, ContributingLayerEmptyScissorNoPartialSwap) {
2938 scoped_ptr<LayerTreeHostImpl> my_host_impl =
2939 SetupLayersForOpacity(false, this, &proxy_, &stats_instrumentation_);
2941 LayerTreeHostImpl::FrameData frame;
2942 EXPECT_TRUE(my_host_impl->PrepareToDraw(&frame, gfx::Rect()));
2944 // Verify all quads have been computed
2945 ASSERT_EQ(2U, frame.render_passes.size());
2946 ASSERT_EQ(1U, frame.render_passes[0]->quad_list.size());
2947 ASSERT_EQ(1U, frame.render_passes[1]->quad_list.size());
2948 EXPECT_EQ(DrawQuad::SOLID_COLOR,
2949 frame.render_passes[0]->quad_list[0]->material);
2950 EXPECT_EQ(DrawQuad::RENDER_PASS,
2951 frame.render_passes[1]->quad_list[0]->material);
2953 my_host_impl->DrawLayers(&frame, base::TimeTicks::Now());
2954 my_host_impl->DidDrawAllLayers(frame);
2958 // Fake WebKit::WebGraphicsContext3D that tracks the number of textures in use.
2959 class TrackingWebGraphicsContext3D : public TestWebGraphicsContext3D {
2960 public:
2961 TrackingWebGraphicsContext3D()
2962 : TestWebGraphicsContext3D(),
2963 num_textures_(0) {}
2965 virtual WebKit::WebGLId createTexture() OVERRIDE {
2966 WebKit::WebGLId id = TestWebGraphicsContext3D::createTexture();
2968 textures_[id] = true;
2969 ++num_textures_;
2970 return id;
2973 virtual void deleteTexture(WebKit::WebGLId id) OVERRIDE {
2974 if (textures_.find(id) == textures_.end())
2975 return;
2977 textures_[id] = false;
2978 --num_textures_;
2981 virtual WebKit::WebString getString(WebKit::WGC3Denum name) OVERRIDE {
2982 if (name == GL_EXTENSIONS) {
2983 return WebKit::WebString(
2984 "GL_CHROMIUM_iosurface GL_ARB_texture_rectangle");
2987 return WebKit::WebString();
2990 unsigned num_textures() const { return num_textures_; }
2992 private:
2993 base::hash_map<WebKit::WebGLId, bool> textures_;
2994 unsigned num_textures_;
2997 TEST_F(LayerTreeHostImplTest, LayersFreeTextures) {
2998 scoped_ptr<TestWebGraphicsContext3D> context =
2999 TestWebGraphicsContext3D::Create();
3000 TestWebGraphicsContext3D* context3d = context.get();
3001 scoped_ptr<OutputSurface> output_surface = FakeOutputSurface::Create3d(
3002 context.PassAs<WebKit::WebGraphicsContext3D>()).PassAs<OutputSurface>();
3003 host_impl_->InitializeRenderer(output_surface.Pass());
3005 scoped_ptr<LayerImpl> root_layer =
3006 LayerImpl::Create(host_impl_->active_tree(), 1);
3007 root_layer->SetBounds(gfx::Size(10, 10));
3008 root_layer->SetAnchorPoint(gfx::PointF());
3010 scoped_refptr<VideoFrame> softwareFrame =
3011 media::VideoFrame::CreateColorFrame(
3012 gfx::Size(4, 4), 0x80, 0x80, 0x80, base::TimeDelta());
3013 FakeVideoFrameProvider provider;
3014 provider.set_frame(softwareFrame);
3015 scoped_ptr<VideoLayerImpl> video_layer =
3016 VideoLayerImpl::Create(host_impl_->active_tree(), 4, &provider);
3017 video_layer->SetBounds(gfx::Size(10, 10));
3018 video_layer->SetAnchorPoint(gfx::PointF());
3019 video_layer->SetContentBounds(gfx::Size(10, 10));
3020 video_layer->SetDrawsContent(true);
3021 root_layer->AddChild(video_layer.PassAs<LayerImpl>());
3023 scoped_ptr<IOSurfaceLayerImpl> io_surface_layer =
3024 IOSurfaceLayerImpl::Create(host_impl_->active_tree(), 5);
3025 io_surface_layer->SetBounds(gfx::Size(10, 10));
3026 io_surface_layer->SetAnchorPoint(gfx::PointF());
3027 io_surface_layer->SetContentBounds(gfx::Size(10, 10));
3028 io_surface_layer->SetDrawsContent(true);
3029 io_surface_layer->SetIOSurfaceProperties(1, gfx::Size(10, 10));
3030 root_layer->AddChild(io_surface_layer.PassAs<LayerImpl>());
3032 host_impl_->active_tree()->SetRootLayer(root_layer.Pass());
3034 EXPECT_EQ(0u, context3d->NumTextures());
3036 LayerTreeHostImpl::FrameData frame;
3037 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
3038 host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
3039 host_impl_->DidDrawAllLayers(frame);
3040 host_impl_->SwapBuffers(frame);
3042 EXPECT_GT(context3d->NumTextures(), 0u);
3044 // Kill the layer tree.
3045 host_impl_->active_tree()->SetRootLayer(
3046 LayerImpl::Create(host_impl_->active_tree(), 100));
3047 // There should be no textures left in use after.
3048 EXPECT_EQ(0u, context3d->NumTextures());
3051 class MockDrawQuadsToFillScreenContext : public TestWebGraphicsContext3D {
3052 public:
3053 MOCK_METHOD1(useProgram, void(WebKit::WebGLId program));
3054 MOCK_METHOD4(drawElements, void(WebKit::WGC3Denum mode,
3055 WebKit::WGC3Dsizei count,
3056 WebKit::WGC3Denum type,
3057 WebKit::WGC3Dintptr offset));
3060 TEST_F(LayerTreeHostImplTest, HasTransparentBackground) {
3061 scoped_ptr<OutputSurface> output_surface =
3062 FakeOutputSurface::Create3d(scoped_ptr<WebKit::WebGraphicsContext3D>(
3063 new MockDrawQuadsToFillScreenContext)).PassAs<OutputSurface>();
3064 MockDrawQuadsToFillScreenContext* mock_context =
3065 static_cast<MockDrawQuadsToFillScreenContext*>(
3066 output_surface->context3d());
3068 // Run test case
3069 CreateLayerTreeHost(false, output_surface.Pass());
3070 SetupRootLayerImpl(LayerImpl::Create(host_impl_->active_tree(), 1));
3071 host_impl_->active_tree()->set_background_color(SK_ColorWHITE);
3073 // Verify one quad is drawn when transparent background set is not set.
3074 host_impl_->active_tree()->set_has_transparent_background(false);
3075 EXPECT_CALL(*mock_context, useProgram(_))
3076 .Times(1);
3077 EXPECT_CALL(*mock_context, drawElements(_, _, _, _))
3078 .Times(1);
3079 LayerTreeHostImpl::FrameData frame;
3080 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
3081 host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
3082 host_impl_->DidDrawAllLayers(frame);
3083 Mock::VerifyAndClearExpectations(&mock_context);
3085 // Verify no quads are drawn when transparent background is set.
3086 host_impl_->active_tree()->set_has_transparent_background(true);
3087 host_impl_->SetFullRootLayerDamage();
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);
3094 static void AddDrawingLayerTo(LayerImpl* parent,
3095 int id,
3096 gfx::Rect layer_rect,
3097 LayerImpl** result) {
3098 scoped_ptr<LayerImpl> layer =
3099 FakeLayerWithQuads::Create(parent->layer_tree_impl(), id);
3100 LayerImpl* layer_ptr = layer.get();
3101 layer_ptr->SetAnchorPoint(gfx::PointF());
3102 layer_ptr->SetPosition(gfx::PointF(layer_rect.origin()));
3103 layer_ptr->SetBounds(layer_rect.size());
3104 layer_ptr->SetContentBounds(layer_rect.size());
3105 layer_ptr->SetDrawsContent(true); // only children draw content
3106 layer_ptr->SetContentsOpaque(true);
3107 parent->AddChild(layer.Pass());
3108 if (result)
3109 *result = layer_ptr;
3112 static void SetupLayersForTextureCaching(
3113 LayerTreeHostImpl* layer_tree_host_impl,
3114 LayerImpl*& root_ptr,
3115 LayerImpl*& intermediate_layer_ptr,
3116 LayerImpl*& surface_layer_ptr,
3117 LayerImpl*& child_ptr,
3118 gfx::Size root_size) {
3119 scoped_ptr<OutputSurface> output_surface =
3120 FakeOutputSurface::Create3d(scoped_ptr<WebKit::WebGraphicsContext3D>(
3121 new PartialSwapContext)).PassAs<OutputSurface>();
3123 layer_tree_host_impl->InitializeRenderer(output_surface.Pass());
3124 layer_tree_host_impl->SetViewportSize(root_size);
3126 scoped_ptr<LayerImpl> root =
3127 LayerImpl::Create(layer_tree_host_impl->active_tree(), 1);
3128 root_ptr = root.get();
3130 root->SetAnchorPoint(gfx::PointF());
3131 root->SetPosition(gfx::PointF());
3132 root->SetBounds(root_size);
3133 root->SetContentBounds(root_size);
3134 root->SetDrawsContent(true);
3135 layer_tree_host_impl->active_tree()->SetRootLayer(root.Pass());
3137 AddDrawingLayerTo(root_ptr,
3139 gfx::Rect(10, 10, root_size.width(), root_size.height()),
3140 &intermediate_layer_ptr);
3141 // Only children draw content.
3142 intermediate_layer_ptr->SetDrawsContent(false);
3144 // Surface layer is the layer that changes its opacity
3145 // It will contain other layers that draw content.
3146 AddDrawingLayerTo(intermediate_layer_ptr,
3148 gfx::Rect(10, 10, root_size.width(), root_size.height()),
3149 &surface_layer_ptr);
3150 // Only children draw content.
3151 surface_layer_ptr->SetDrawsContent(false);
3152 surface_layer_ptr->SetOpacity(0.5f);
3153 surface_layer_ptr->SetForceRenderSurface(true);
3155 // Child of the surface layer will produce some quads
3156 AddDrawingLayerTo(surface_layer_ptr,
3158 gfx::Rect(5,
3160 root_size.width() - 25,
3161 root_size.height() - 25),
3162 &child_ptr);
3165 class GLRendererWithReleaseTextures : public GLRenderer {
3166 public:
3167 using GLRenderer::ReleaseRenderPassTextures;
3170 TEST_F(LayerTreeHostImplTest, TextureCachingWithOcclusion) {
3171 LayerTreeSettings settings;
3172 settings.minimum_occlusion_tracking_size = gfx::Size();
3173 settings.cache_render_pass_contents = true;
3174 scoped_ptr<LayerTreeHostImpl> my_host_impl =
3175 LayerTreeHostImpl::Create(settings,
3176 this,
3177 &proxy_,
3178 &stats_instrumentation_);
3180 // Layers are structure as follows:
3182 // R +-- S1 +- L10 (owning)
3183 // | +- L11
3184 // | +- L12
3185 // |
3186 // +-- S2 +- L20 (owning)
3187 // +- L21
3189 // Occlusion:
3190 // L12 occludes L11 (internal)
3191 // L20 occludes L10 (external)
3192 // L21 occludes L20 (internal)
3194 LayerImpl* root_ptr;
3195 LayerImpl* layer_s1_ptr;
3196 LayerImpl* layer_s2_ptr;
3198 scoped_ptr<OutputSurface> output_surface =
3199 FakeOutputSurface::Create3d(scoped_ptr<WebKit::WebGraphicsContext3D>(
3200 new PartialSwapContext)).PassAs<OutputSurface>();
3202 gfx::Size root_size(1000, 1000);
3204 my_host_impl->InitializeRenderer(output_surface.Pass());
3205 my_host_impl->SetViewportSize(root_size);
3207 scoped_ptr<LayerImpl> root =
3208 LayerImpl::Create(my_host_impl->active_tree(), 1);
3209 root_ptr = root.get();
3211 root->SetAnchorPoint(gfx::PointF());
3212 root->SetPosition(gfx::PointF());
3213 root->SetBounds(root_size);
3214 root->SetContentBounds(root_size);
3215 root->SetDrawsContent(true);
3216 root->SetMasksToBounds(true);
3217 my_host_impl->active_tree()->SetRootLayer(root.Pass());
3219 AddDrawingLayerTo(root_ptr, 2, gfx::Rect(300, 300, 300, 300), &layer_s1_ptr);
3220 layer_s1_ptr->SetForceRenderSurface(true);
3222 AddDrawingLayerTo(layer_s1_ptr, 3, gfx::Rect(10, 10, 10, 10), 0); // L11
3223 AddDrawingLayerTo(layer_s1_ptr, 4, gfx::Rect(0, 0, 30, 30), 0); // L12
3225 AddDrawingLayerTo(root_ptr, 5, gfx::Rect(550, 250, 300, 400), &layer_s2_ptr);
3226 layer_s2_ptr->SetForceRenderSurface(true);
3228 AddDrawingLayerTo(layer_s2_ptr, 6, gfx::Rect(20, 20, 5, 5), 0); // L21
3230 // Initial draw - must receive all quads
3232 LayerTreeHostImpl::FrameData frame;
3233 EXPECT_TRUE(my_host_impl->PrepareToDraw(&frame, gfx::Rect()));
3235 // Must receive 3 render passes.
3236 // For Root, there are 2 quads; for S1, there are 2 quads (1 is occluded);
3237 // for S2, there is 2 quads.
3238 ASSERT_EQ(3U, frame.render_passes.size());
3240 EXPECT_EQ(2U, frame.render_passes[0]->quad_list.size());
3241 EXPECT_EQ(2U, frame.render_passes[1]->quad_list.size());
3242 EXPECT_EQ(2U, frame.render_passes[2]->quad_list.size());
3244 my_host_impl->DrawLayers(&frame, base::TimeTicks::Now());
3245 my_host_impl->DidDrawAllLayers(frame);
3248 // "Unocclude" surface S1 and repeat draw.
3249 // Must remove S2's render pass since it's cached;
3250 // Must keep S1 quads because texture contained external occlusion.
3251 gfx::Transform transform = layer_s2_ptr->transform();
3252 transform.Translate(150.0, 150.0);
3253 layer_s2_ptr->SetTransform(transform);
3255 LayerTreeHostImpl::FrameData frame;
3256 EXPECT_TRUE(my_host_impl->PrepareToDraw(&frame, gfx::Rect()));
3258 // Must receive 2 render passes.
3259 // For Root, there are 2 quads
3260 // For S1, the number of quads depends on what got unoccluded, so not
3261 // asserted beyond being positive.
3262 // For S2, there is no render pass
3263 ASSERT_EQ(2U, frame.render_passes.size());
3265 EXPECT_GT(frame.render_passes[0]->quad_list.size(), 0U);
3266 EXPECT_EQ(2U, frame.render_passes[1]->quad_list.size());
3268 my_host_impl->DrawLayers(&frame, base::TimeTicks::Now());
3269 my_host_impl->DidDrawAllLayers(frame);
3272 // "Re-occlude" surface S1 and repeat draw.
3273 // Must remove S1's render pass since it is now available in full.
3274 // S2 has no change so must also be removed.
3275 transform = layer_s2_ptr->transform();
3276 transform.Translate(-15.0, -15.0);
3277 layer_s2_ptr->SetTransform(transform);
3279 LayerTreeHostImpl::FrameData frame;
3280 EXPECT_TRUE(my_host_impl->PrepareToDraw(&frame, gfx::Rect()));
3282 // Must receive 1 render pass - for the root.
3283 ASSERT_EQ(1U, frame.render_passes.size());
3285 EXPECT_EQ(2U, frame.render_passes[0]->quad_list.size());
3287 my_host_impl->DrawLayers(&frame, base::TimeTicks::Now());
3288 my_host_impl->DidDrawAllLayers(frame);
3292 TEST_F(LayerTreeHostImplTest, TextureCachingWithOcclusionEarlyOut) {
3293 LayerTreeSettings settings;
3294 settings.minimum_occlusion_tracking_size = gfx::Size();
3295 settings.cache_render_pass_contents = true;
3296 scoped_ptr<LayerTreeHostImpl> my_host_impl =
3297 LayerTreeHostImpl::Create(settings,
3298 this,
3299 &proxy_,
3300 &stats_instrumentation_);
3302 // Layers are structure as follows:
3304 // R +-- S1 +- L10 (owning, non drawing)
3305 // | +- L11 (corner, unoccluded)
3306 // | +- L12 (corner, unoccluded)
3307 // | +- L13 (corner, unoccluded)
3308 // | +- L14 (corner, entirely occluded)
3309 // |
3310 // +-- S2 +- L20 (owning, drawing)
3313 LayerImpl* root_ptr;
3314 LayerImpl* layer_s1_ptr;
3315 LayerImpl* layer_s2_ptr;
3317 scoped_ptr<OutputSurface> output_surface =
3318 FakeOutputSurface::Create3d(scoped_ptr<WebKit::WebGraphicsContext3D>(
3319 new PartialSwapContext)).PassAs<OutputSurface>();
3321 gfx::Size root_size(1000, 1000);
3323 my_host_impl->InitializeRenderer(output_surface.Pass());
3324 my_host_impl->SetViewportSize(root_size);
3326 scoped_ptr<LayerImpl> root =
3327 LayerImpl::Create(my_host_impl->active_tree(), 1);
3328 root_ptr = root.get();
3330 root->SetAnchorPoint(gfx::PointF());
3331 root->SetPosition(gfx::PointF());
3332 root->SetBounds(root_size);
3333 root->SetContentBounds(root_size);
3334 root->SetDrawsContent(true);
3335 root->SetMasksToBounds(true);
3336 my_host_impl->active_tree()->SetRootLayer(root.Pass());
3338 AddDrawingLayerTo(root_ptr, 2, gfx::Rect(0, 0, 800, 800), &layer_s1_ptr);
3339 layer_s1_ptr->SetForceRenderSurface(true);
3340 layer_s1_ptr->SetDrawsContent(false);
3342 AddDrawingLayerTo(layer_s1_ptr, 3, gfx::Rect(0, 0, 300, 300), 0); // L11
3343 AddDrawingLayerTo(layer_s1_ptr, 4, gfx::Rect(0, 500, 300, 300), 0); // L12
3344 AddDrawingLayerTo(layer_s1_ptr, 5, gfx::Rect(500, 0, 300, 300), 0); // L13
3345 AddDrawingLayerTo(layer_s1_ptr, 6, gfx::Rect(500, 500, 300, 300), 0); // L14
3346 AddDrawingLayerTo(layer_s1_ptr, 9, gfx::Rect(500, 500, 300, 300), 0); // L14
3348 AddDrawingLayerTo(root_ptr, 7, gfx::Rect(450, 450, 450, 450), &layer_s2_ptr);
3349 layer_s2_ptr->SetForceRenderSurface(true);
3351 // Initial draw - must receive all quads
3353 LayerTreeHostImpl::FrameData frame;
3354 EXPECT_TRUE(my_host_impl->PrepareToDraw(&frame, gfx::Rect()));
3356 // Must receive 3 render passes.
3357 // For Root, there are 2 quads; for S1, there are 3 quads; for S2, there is
3358 // 1 quad.
3359 ASSERT_EQ(3U, frame.render_passes.size());
3361 EXPECT_EQ(1U, frame.render_passes[0]->quad_list.size());
3363 // L14 is culled, so only 3 quads.
3364 EXPECT_EQ(3U, frame.render_passes[1]->quad_list.size());
3365 EXPECT_EQ(2U, frame.render_passes[2]->quad_list.size());
3367 my_host_impl->DrawLayers(&frame, base::TimeTicks::Now());
3368 my_host_impl->DidDrawAllLayers(frame);
3371 // "Unocclude" surface S1 and repeat draw.
3372 // Must remove S2's render pass since it's cached;
3373 // Must keep S1 quads because texture contained external occlusion.
3374 gfx::Transform transform = layer_s2_ptr->transform();
3375 transform.Translate(100.0, 100.0);
3376 layer_s2_ptr->SetTransform(transform);
3378 LayerTreeHostImpl::FrameData frame;
3379 EXPECT_TRUE(my_host_impl->PrepareToDraw(&frame, gfx::Rect()));
3381 // Must receive 2 render passes.
3382 // For Root, there are 2 quads
3383 // For S1, the number of quads depends on what got unoccluded, so not
3384 // asserted beyond being positive.
3385 // For S2, there is no render pass
3386 ASSERT_EQ(2U, frame.render_passes.size());
3388 EXPECT_GT(frame.render_passes[0]->quad_list.size(), 0U);
3389 EXPECT_EQ(2U, frame.render_passes[1]->quad_list.size());
3391 my_host_impl->DrawLayers(&frame, base::TimeTicks::Now());
3392 my_host_impl->DidDrawAllLayers(frame);
3395 // "Re-occlude" surface S1 and repeat draw.
3396 // Must remove S1's render pass since it is now available in full.
3397 // S2 has no change so must also be removed.
3398 transform = layer_s2_ptr->transform();
3399 transform.Translate(-15.0, -15.0);
3400 layer_s2_ptr->SetTransform(transform);
3402 LayerTreeHostImpl::FrameData frame;
3403 EXPECT_TRUE(my_host_impl->PrepareToDraw(&frame, gfx::Rect()));
3405 // Must receive 1 render pass - for the root.
3406 ASSERT_EQ(1U, frame.render_passes.size());
3408 EXPECT_EQ(2U, frame.render_passes[0]->quad_list.size());
3410 my_host_impl->DrawLayers(&frame, base::TimeTicks::Now());
3411 my_host_impl->DidDrawAllLayers(frame);
3415 TEST_F(LayerTreeHostImplTest, TextureCachingWithOcclusionExternalOverInternal) {
3416 LayerTreeSettings settings;
3417 settings.minimum_occlusion_tracking_size = gfx::Size();
3418 settings.cache_render_pass_contents = true;
3419 scoped_ptr<LayerTreeHostImpl> my_host_impl =
3420 LayerTreeHostImpl::Create(settings,
3421 this,
3422 &proxy_,
3423 &stats_instrumentation_);
3425 // Layers are structured as follows:
3427 // R +-- S1 +- L10 (owning, drawing)
3428 // | +- L11 (corner, occluded by L12)
3429 // | +- L12 (opposite corner)
3430 // |
3431 // +-- S2 +- L20 (owning, drawing)
3434 LayerImpl* root_ptr;
3435 LayerImpl* layer_s1_ptr;
3436 LayerImpl* layer_s2_ptr;
3438 scoped_ptr<OutputSurface> output_surface =
3439 FakeOutputSurface::Create3d(scoped_ptr<WebKit::WebGraphicsContext3D>(
3440 new PartialSwapContext)).PassAs<OutputSurface>();
3442 gfx::Size root_size(1000, 1000);
3444 my_host_impl->InitializeRenderer(output_surface.Pass());
3445 my_host_impl->SetViewportSize(root_size);
3447 scoped_ptr<LayerImpl> root =
3448 LayerImpl::Create(my_host_impl->active_tree(), 1);
3449 root_ptr = root.get();
3451 root->SetAnchorPoint(gfx::PointF());
3452 root->SetPosition(gfx::PointF());
3453 root->SetBounds(root_size);
3454 root->SetContentBounds(root_size);
3455 root->SetDrawsContent(true);
3456 root->SetMasksToBounds(true);
3457 my_host_impl->active_tree()->SetRootLayer(root.Pass());
3459 AddDrawingLayerTo(root_ptr, 2, gfx::Rect(0, 0, 400, 400), &layer_s1_ptr);
3460 layer_s1_ptr->SetForceRenderSurface(true);
3462 AddDrawingLayerTo(layer_s1_ptr, 3, gfx::Rect(0, 0, 300, 300), 0); // L11
3463 AddDrawingLayerTo(layer_s1_ptr, 4, gfx::Rect(100, 0, 300, 300), 0); // L12
3465 AddDrawingLayerTo(root_ptr, 7, gfx::Rect(200, 0, 300, 300), &layer_s2_ptr);
3466 layer_s2_ptr->SetForceRenderSurface(true);
3468 // Initial draw - must receive all quads
3470 LayerTreeHostImpl::FrameData frame;
3471 EXPECT_TRUE(my_host_impl->PrepareToDraw(&frame, gfx::Rect()));
3473 // Must receive 3 render passes.
3474 // For Root, there are 2 quads; for S1, there are 3 quads; for S2, there is
3475 // 1 quad.
3476 ASSERT_EQ(3U, frame.render_passes.size());
3478 EXPECT_EQ(1U, frame.render_passes[0]->quad_list.size());
3479 EXPECT_EQ(3U, frame.render_passes[1]->quad_list.size());
3480 EXPECT_EQ(2U, frame.render_passes[2]->quad_list.size());
3482 my_host_impl->DrawLayers(&frame, base::TimeTicks::Now());
3483 my_host_impl->DidDrawAllLayers(frame);
3486 // "Unocclude" surface S1 and repeat draw.
3487 // Must remove S2's render pass since it's cached;
3488 // Must keep S1 quads because texture contained external occlusion.
3489 gfx::Transform transform = layer_s2_ptr->transform();
3490 transform.Translate(300.0, 0.0);
3491 layer_s2_ptr->SetTransform(transform);
3493 LayerTreeHostImpl::FrameData frame;
3494 EXPECT_TRUE(my_host_impl->PrepareToDraw(&frame, gfx::Rect()));
3496 // Must receive 2 render passes.
3497 // For Root, there are 2 quads
3498 // For S1, the number of quads depends on what got unoccluded, so not
3499 // asserted beyond being positive.
3500 // For S2, there is no render pass
3501 ASSERT_EQ(2U, frame.render_passes.size());
3503 EXPECT_GT(frame.render_passes[0]->quad_list.size(), 0U);
3504 EXPECT_EQ(2U, frame.render_passes[1]->quad_list.size());
3506 my_host_impl->DrawLayers(&frame, base::TimeTicks::Now());
3507 my_host_impl->DidDrawAllLayers(frame);
3511 TEST_F(LayerTreeHostImplTest, TextureCachingWithOcclusionExternalNotAligned) {
3512 LayerTreeSettings settings;
3513 settings.cache_render_pass_contents = true;
3514 scoped_ptr<LayerTreeHostImpl> my_host_impl =
3515 LayerTreeHostImpl::Create(settings,
3516 this,
3517 &proxy_,
3518 &stats_instrumentation_);
3520 // Layers are structured as follows:
3522 // R +-- S1 +- L10 (rotated, drawing)
3523 // +- L11 (occupies half surface)
3525 LayerImpl* root_ptr;
3526 LayerImpl* layer_s1_ptr;
3528 scoped_ptr<OutputSurface> output_surface =
3529 FakeOutputSurface::Create3d(scoped_ptr<WebKit::WebGraphicsContext3D>(
3530 new PartialSwapContext)).PassAs<OutputSurface>();
3532 gfx::Size root_size(1000, 1000);
3534 my_host_impl->InitializeRenderer(output_surface.Pass());
3535 my_host_impl->SetViewportSize(root_size);
3537 scoped_ptr<LayerImpl> root =
3538 LayerImpl::Create(my_host_impl->active_tree(), 1);
3539 root_ptr = root.get();
3541 root->SetAnchorPoint(gfx::PointF());
3542 root->SetPosition(gfx::PointF());
3543 root->SetBounds(root_size);
3544 root->SetContentBounds(root_size);
3545 root->SetDrawsContent(true);
3546 root->SetMasksToBounds(true);
3547 my_host_impl->active_tree()->SetRootLayer(root.Pass());
3549 AddDrawingLayerTo(root_ptr, 2, gfx::Rect(0, 0, 400, 400), &layer_s1_ptr);
3550 layer_s1_ptr->SetForceRenderSurface(true);
3551 gfx::Transform transform = layer_s1_ptr->transform();
3552 transform.Translate(200.0, 200.0);
3553 transform.Rotate(45.0);
3554 transform.Translate(-200.0, -200.0);
3555 layer_s1_ptr->SetTransform(transform);
3557 AddDrawingLayerTo(layer_s1_ptr, 3, gfx::Rect(200, 0, 200, 400), 0); // L11
3559 // Initial draw - must receive all quads
3561 LayerTreeHostImpl::FrameData frame;
3562 EXPECT_TRUE(my_host_impl->PrepareToDraw(&frame, gfx::Rect()));
3564 // Must receive 2 render passes.
3565 ASSERT_EQ(2U, frame.render_passes.size());
3567 EXPECT_EQ(2U, frame.render_passes[0]->quad_list.size());
3568 EXPECT_EQ(1U, frame.render_passes[1]->quad_list.size());
3570 my_host_impl->DrawLayers(&frame, base::TimeTicks::Now());
3571 my_host_impl->DidDrawAllLayers(frame);
3574 // Change opacity and draw. Verify we used cached texture.
3575 layer_s1_ptr->SetOpacity(0.2f);
3577 LayerTreeHostImpl::FrameData frame;
3578 EXPECT_TRUE(my_host_impl->PrepareToDraw(&frame, gfx::Rect()));
3580 // One render pass must be gone due to cached texture.
3581 ASSERT_EQ(1U, frame.render_passes.size());
3583 EXPECT_EQ(1U, frame.render_passes[0]->quad_list.size());
3585 my_host_impl->DrawLayers(&frame, base::TimeTicks::Now());
3586 my_host_impl->DidDrawAllLayers(frame);
3590 TEST_F(LayerTreeHostImplTest, TextureCachingWithOcclusionPartialSwap) {
3591 LayerTreeSettings settings;
3592 settings.minimum_occlusion_tracking_size = gfx::Size();
3593 settings.partial_swap_enabled = true;
3594 settings.cache_render_pass_contents = true;
3595 scoped_ptr<LayerTreeHostImpl> my_host_impl =
3596 LayerTreeHostImpl::Create(settings,
3597 this,
3598 &proxy_,
3599 &stats_instrumentation_);
3601 // Layers are structure as follows:
3603 // R +-- S1 +- L10 (owning)
3604 // | +- L11
3605 // | +- L12
3606 // |
3607 // +-- S2 +- L20 (owning)
3608 // +- L21
3610 // Occlusion:
3611 // L12 occludes L11 (internal)
3612 // L20 occludes L10 (external)
3613 // L21 occludes L20 (internal)
3615 LayerImpl* root_ptr;
3616 LayerImpl* layer_s1_ptr;
3617 LayerImpl* layer_s2_ptr;
3619 scoped_ptr<OutputSurface> output_surface =
3620 FakeOutputSurface::Create3d(scoped_ptr<WebKit::WebGraphicsContext3D>(
3621 new PartialSwapContext)).PassAs<OutputSurface>();
3623 gfx::Size root_size(1000, 1000);
3625 my_host_impl->InitializeRenderer(output_surface.Pass());
3626 my_host_impl->SetViewportSize(root_size);
3628 scoped_ptr<LayerImpl> root =
3629 LayerImpl::Create(my_host_impl->active_tree(), 1);
3630 root_ptr = root.get();
3632 root->SetAnchorPoint(gfx::PointF());
3633 root->SetPosition(gfx::PointF());
3634 root->SetBounds(root_size);
3635 root->SetContentBounds(root_size);
3636 root->SetDrawsContent(true);
3637 root->SetMasksToBounds(true);
3638 my_host_impl->active_tree()->SetRootLayer(root.Pass());
3640 AddDrawingLayerTo(root_ptr, 2, gfx::Rect(300, 300, 300, 300), &layer_s1_ptr);
3641 layer_s1_ptr->SetForceRenderSurface(true);
3643 AddDrawingLayerTo(layer_s1_ptr, 3, gfx::Rect(10, 10, 10, 10), 0); // L11
3644 AddDrawingLayerTo(layer_s1_ptr, 4, gfx::Rect(0, 0, 30, 30), 0); // L12
3646 AddDrawingLayerTo(root_ptr, 5, gfx::Rect(550, 250, 300, 400), &layer_s2_ptr);
3647 layer_s2_ptr->SetForceRenderSurface(true);
3649 AddDrawingLayerTo(layer_s2_ptr, 6, gfx::Rect(20, 20, 5, 5), 0); // L21
3651 // Initial draw - must receive all quads
3653 LayerTreeHostImpl::FrameData frame;
3654 EXPECT_TRUE(my_host_impl->PrepareToDraw(&frame, gfx::Rect()));
3656 // Must receive 3 render passes.
3657 // For Root, there are 2 quads; for S1, there are 2 quads (one is occluded);
3658 // for S2, there is 2 quads.
3659 ASSERT_EQ(3U, frame.render_passes.size());
3661 EXPECT_EQ(2U, frame.render_passes[0]->quad_list.size());
3662 EXPECT_EQ(2U, frame.render_passes[1]->quad_list.size());
3663 EXPECT_EQ(2U, frame.render_passes[2]->quad_list.size());
3665 my_host_impl->DrawLayers(&frame, base::TimeTicks::Now());
3666 my_host_impl->DidDrawAllLayers(frame);
3669 // "Unocclude" surface S1 and repeat draw.
3670 // Must remove S2's render pass since it's cached;
3671 // Must keep S1 quads because texture contained external occlusion.
3672 gfx::Transform transform = layer_s2_ptr->transform();
3673 transform.Translate(150.0, 150.0);
3674 layer_s2_ptr->SetTransform(transform);
3676 LayerTreeHostImpl::FrameData frame;
3677 EXPECT_TRUE(my_host_impl->PrepareToDraw(&frame, gfx::Rect()));
3679 // Must receive 2 render passes.
3680 // For Root, there are 2 quads.
3681 // For S1, there are 2 quads.
3682 // For S2, there is no render pass
3683 ASSERT_EQ(2U, frame.render_passes.size());
3685 EXPECT_EQ(2U, frame.render_passes[0]->quad_list.size());
3686 EXPECT_EQ(2U, frame.render_passes[1]->quad_list.size());
3688 my_host_impl->DrawLayers(&frame, base::TimeTicks::Now());
3689 my_host_impl->DidDrawAllLayers(frame);
3692 // "Re-occlude" surface S1 and repeat draw.
3693 // Must remove S1's render pass since it is now available in full.
3694 // S2 has no change so must also be removed.
3695 transform = layer_s2_ptr->transform();
3696 transform.Translate(-15.0, -15.0);
3697 layer_s2_ptr->SetTransform(transform);
3699 LayerTreeHostImpl::FrameData frame;
3700 EXPECT_TRUE(my_host_impl->PrepareToDraw(&frame, gfx::Rect()));
3702 // Root render pass only.
3703 ASSERT_EQ(1U, frame.render_passes.size());
3705 my_host_impl->DrawLayers(&frame, base::TimeTicks::Now());
3706 my_host_impl->DidDrawAllLayers(frame);
3710 TEST_F(LayerTreeHostImplTest, TextureCachingWithScissor) {
3711 LayerTreeSettings settings;
3712 settings.minimum_occlusion_tracking_size = gfx::Size();
3713 settings.cache_render_pass_contents = true;
3714 scoped_ptr<LayerTreeHostImpl> my_host_impl =
3715 LayerTreeHostImpl::Create(settings,
3716 this,
3717 &proxy_,
3718 &stats_instrumentation_);
3721 Layers are created as follows:
3723 +--------------------+
3724 | 1 |
3725 | +-----------+ |
3726 | | 2 | |
3727 | | +-------------------+
3728 | | | 3 |
3729 | | +-------------------+
3730 | | | |
3731 | +-----------+ |
3734 +--------------------+
3736 Layers 1, 2 have render surfaces
3738 scoped_ptr<LayerImpl> root =
3739 LayerImpl::Create(my_host_impl->active_tree(), 1);
3740 scoped_ptr<TiledLayerImpl> child =
3741 TiledLayerImpl::Create(my_host_impl->active_tree(), 2);
3742 scoped_ptr<LayerImpl> grand_child =
3743 LayerImpl::Create(my_host_impl->active_tree(), 3);
3745 gfx::Rect root_rect(0, 0, 100, 100);
3746 gfx::Rect child_rect(10, 10, 50, 50);
3747 gfx::Rect grand_child_rect(5, 5, 150, 150);
3749 scoped_ptr<OutputSurface> output_surface =
3750 FakeOutputSurface::Create3d(scoped_ptr<WebKit::WebGraphicsContext3D>(
3751 new PartialSwapContext)).PassAs<OutputSurface>();
3752 my_host_impl->InitializeRenderer(output_surface.Pass());
3754 root->SetAnchorPoint(gfx::PointF());
3755 root->SetPosition(gfx::PointF(root_rect.x(), root_rect.y()));
3756 root->SetBounds(gfx::Size(root_rect.width(), root_rect.height()));
3757 root->SetContentBounds(root->bounds());
3758 root->SetDrawsContent(true);
3759 root->SetMasksToBounds(true);
3761 child->SetAnchorPoint(gfx::PointF());
3762 child->SetPosition(gfx::PointF(child_rect.x(), child_rect.y()));
3763 child->SetOpacity(0.5f);
3764 child->SetBounds(gfx::Size(child_rect.width(), child_rect.height()));
3765 child->SetContentBounds(child->bounds());
3766 child->SetDrawsContent(true);
3767 child->set_skips_draw(false);
3769 // child layer has 10x10 tiles.
3770 scoped_ptr<LayerTilingData> tiler =
3771 LayerTilingData::Create(gfx::Size(10, 10),
3772 LayerTilingData::HAS_BORDER_TEXELS);
3773 tiler->SetBounds(child->content_bounds());
3774 child->SetTilingData(*tiler.get());
3776 grand_child->SetAnchorPoint(gfx::PointF());
3777 grand_child->SetPosition(grand_child_rect.origin());
3778 grand_child->SetBounds(grand_child_rect.size());
3779 grand_child->SetContentBounds(grand_child->bounds());
3780 grand_child->SetDrawsContent(true);
3782 TiledLayerImpl* child_ptr = child.get();
3783 RenderPass::Id child_pass_id(child_ptr->id(), 0);
3785 child->AddChild(grand_child.Pass());
3786 root->AddChild(child.PassAs<LayerImpl>());
3787 my_host_impl->active_tree()->SetRootLayer(root.Pass());
3788 my_host_impl->SetViewportSize(root_rect.size());
3790 EXPECT_FALSE(my_host_impl->renderer()->HaveCachedResourcesForRenderPassId(
3791 child_pass_id));
3793 LayerTreeHostImpl::FrameData frame;
3794 host_impl_->SetFullRootLayerDamage();
3795 EXPECT_TRUE(my_host_impl->PrepareToDraw(&frame, gfx::Rect()));
3796 my_host_impl->DrawLayers(&frame, base::TimeTicks::Now());
3797 my_host_impl->DidDrawAllLayers(frame);
3800 // We should have cached textures for surface 2.
3801 EXPECT_TRUE(my_host_impl->renderer()->HaveCachedResourcesForRenderPassId(
3802 child_pass_id));
3804 LayerTreeHostImpl::FrameData frame;
3805 host_impl_->SetFullRootLayerDamage();
3806 EXPECT_TRUE(my_host_impl->PrepareToDraw(&frame, gfx::Rect()));
3807 my_host_impl->DrawLayers(&frame, base::TimeTicks::Now());
3808 my_host_impl->DidDrawAllLayers(frame);
3811 // We should still have cached textures for surface 2 after drawing with no
3812 // damage.
3813 EXPECT_TRUE(my_host_impl->renderer()->HaveCachedResourcesForRenderPassId(
3814 child_pass_id));
3816 // Damage a single tile of surface 2.
3817 child_ptr->set_update_rect(gfx::Rect(10, 10, 10, 10));
3819 LayerTreeHostImpl::FrameData frame;
3820 host_impl_->SetFullRootLayerDamage();
3821 EXPECT_TRUE(my_host_impl->PrepareToDraw(&frame, gfx::Rect()));
3822 my_host_impl->DrawLayers(&frame, base::TimeTicks::Now());
3823 my_host_impl->DidDrawAllLayers(frame);
3826 // We should have a cached texture for surface 2 again even though it was
3827 // damaged.
3828 EXPECT_TRUE(my_host_impl->renderer()->HaveCachedResourcesForRenderPassId(
3829 child_pass_id));
3832 TEST_F(LayerTreeHostImplTest, SurfaceTextureCaching) {
3833 LayerTreeSettings settings;
3834 settings.minimum_occlusion_tracking_size = gfx::Size();
3835 settings.partial_swap_enabled = true;
3836 settings.cache_render_pass_contents = true;
3837 scoped_ptr<LayerTreeHostImpl> my_host_impl =
3838 LayerTreeHostImpl::Create(settings,
3839 this,
3840 &proxy_,
3841 &stats_instrumentation_);
3843 LayerImpl* root_ptr;
3844 LayerImpl* intermediate_layer_ptr;
3845 LayerImpl* surface_layer_ptr;
3846 LayerImpl* child_ptr;
3848 SetupLayersForTextureCaching(my_host_impl.get(),
3849 root_ptr,
3850 intermediate_layer_ptr,
3851 surface_layer_ptr,
3852 child_ptr,
3853 gfx::Size(100, 100));
3855 LayerTreeHostImpl::FrameData frame;
3856 EXPECT_TRUE(my_host_impl->PrepareToDraw(&frame, gfx::Rect()));
3858 // Must receive two render passes, each with one quad
3859 ASSERT_EQ(2U, frame.render_passes.size());
3860 EXPECT_EQ(1U, frame.render_passes[0]->quad_list.size());
3861 EXPECT_EQ(1U, frame.render_passes[1]->quad_list.size());
3863 EXPECT_EQ(DrawQuad::RENDER_PASS,
3864 frame.render_passes[1]->quad_list[0]->material);
3865 const RenderPassDrawQuad* quad =
3866 RenderPassDrawQuad::MaterialCast(frame.render_passes[1]->quad_list[0]);
3867 RenderPass* target_pass = frame.render_passes_by_id[quad->render_pass_id];
3868 ASSERT_TRUE(target_pass);
3869 EXPECT_FALSE(target_pass->damage_rect.IsEmpty());
3871 my_host_impl->DrawLayers(&frame, base::TimeTicks::Now());
3872 my_host_impl->DidDrawAllLayers(frame);
3875 // Draw without any change
3877 LayerTreeHostImpl::FrameData frame;
3878 my_host_impl->SetFullRootLayerDamage();
3879 EXPECT_TRUE(my_host_impl->PrepareToDraw(&frame, gfx::Rect()));
3881 // Must receive one render pass, as the other one should be culled
3882 ASSERT_EQ(1U, frame.render_passes.size());
3884 EXPECT_EQ(1U, frame.render_passes[0]->quad_list.size());
3885 EXPECT_EQ(DrawQuad::RENDER_PASS,
3886 frame.render_passes[0]->quad_list[0]->material);
3887 const RenderPassDrawQuad* quad =
3888 RenderPassDrawQuad::MaterialCast(frame.render_passes[0]->quad_list[0]);
3889 EXPECT_TRUE(frame.render_passes_by_id.find(quad->render_pass_id) ==
3890 frame.render_passes_by_id.end());
3892 my_host_impl->DrawLayers(&frame, base::TimeTicks::Now());
3893 my_host_impl->DidDrawAllLayers(frame);
3896 // Change opacity and draw
3897 surface_layer_ptr->SetOpacity(0.6f);
3899 LayerTreeHostImpl::FrameData frame;
3900 EXPECT_TRUE(my_host_impl->PrepareToDraw(&frame, gfx::Rect()));
3902 // Must receive one render pass, as the other one should be culled
3903 ASSERT_EQ(1U, frame.render_passes.size());
3905 EXPECT_EQ(1U, frame.render_passes[0]->quad_list.size());
3906 EXPECT_EQ(DrawQuad::RENDER_PASS,
3907 frame.render_passes[0]->quad_list[0]->material);
3908 const RenderPassDrawQuad* quad =
3909 RenderPassDrawQuad::MaterialCast(frame.render_passes[0]->quad_list[0]);
3910 EXPECT_TRUE(frame.render_passes_by_id.find(quad->render_pass_id) ==
3911 frame.render_passes_by_id.end());
3913 my_host_impl->DrawLayers(&frame, base::TimeTicks::Now());
3914 my_host_impl->DidDrawAllLayers(frame);
3917 // Change less benign property and draw - should have contents changed flag
3918 surface_layer_ptr->SetStackingOrderChanged(true);
3920 LayerTreeHostImpl::FrameData frame;
3921 EXPECT_TRUE(my_host_impl->PrepareToDraw(&frame, gfx::Rect()));
3923 // Must receive two render passes, each with one quad
3924 ASSERT_EQ(2U, frame.render_passes.size());
3926 EXPECT_EQ(1U, frame.render_passes[0]->quad_list.size());
3927 EXPECT_EQ(DrawQuad::SOLID_COLOR,
3928 frame.render_passes[0]->quad_list[0]->material);
3930 EXPECT_EQ(DrawQuad::RENDER_PASS,
3931 frame.render_passes[1]->quad_list[0]->material);
3932 const RenderPassDrawQuad* quad =
3933 RenderPassDrawQuad::MaterialCast(frame.render_passes[1]->quad_list[0]);
3934 RenderPass* target_pass = frame.render_passes_by_id[quad->render_pass_id];
3935 ASSERT_TRUE(target_pass);
3936 EXPECT_FALSE(target_pass->damage_rect.IsEmpty());
3938 my_host_impl->DrawLayers(&frame, base::TimeTicks::Now());
3939 my_host_impl->DidDrawAllLayers(frame);
3942 // Change opacity again, and evict the cached surface texture.
3943 surface_layer_ptr->SetOpacity(0.5f);
3944 static_cast<GLRendererWithReleaseTextures*>(
3945 my_host_impl->renderer())->ReleaseRenderPassTextures();
3947 // Change opacity and draw
3948 surface_layer_ptr->SetOpacity(0.6f);
3950 LayerTreeHostImpl::FrameData frame;
3951 EXPECT_TRUE(my_host_impl->PrepareToDraw(&frame, gfx::Rect()));
3953 // Must receive two render passes
3954 ASSERT_EQ(2U, frame.render_passes.size());
3956 // Even though not enough properties changed, the entire thing must be
3957 // redrawn as we don't have cached textures
3958 EXPECT_EQ(1U, frame.render_passes[0]->quad_list.size());
3959 EXPECT_EQ(1U, frame.render_passes[1]->quad_list.size());
3961 EXPECT_EQ(DrawQuad::RENDER_PASS,
3962 frame.render_passes[1]->quad_list[0]->material);
3963 const RenderPassDrawQuad* quad =
3964 RenderPassDrawQuad::MaterialCast(frame.render_passes[1]->quad_list[0]);
3965 RenderPass* target_pass = frame.render_passes_by_id[quad->render_pass_id];
3966 ASSERT_TRUE(target_pass);
3967 EXPECT_TRUE(target_pass->damage_rect.IsEmpty());
3969 // Was our surface evicted?
3970 EXPECT_FALSE(my_host_impl->renderer()->HaveCachedResourcesForRenderPassId(
3971 target_pass->id));
3973 my_host_impl->DrawLayers(&frame, base::TimeTicks::Now());
3974 my_host_impl->DidDrawAllLayers(frame);
3977 // Draw without any change, to make sure the state is clear
3979 LayerTreeHostImpl::FrameData frame;
3980 my_host_impl->SetFullRootLayerDamage();
3981 EXPECT_TRUE(my_host_impl->PrepareToDraw(&frame, gfx::Rect()));
3983 // Must receive one render pass, as the other one should be culled
3984 ASSERT_EQ(1U, frame.render_passes.size());
3986 EXPECT_EQ(1U, frame.render_passes[0]->quad_list.size());
3987 EXPECT_EQ(DrawQuad::RENDER_PASS,
3988 frame.render_passes[0]->quad_list[0]->material);
3989 const RenderPassDrawQuad* quad =
3990 RenderPassDrawQuad::MaterialCast(frame.render_passes[0]->quad_list[0]);
3991 EXPECT_TRUE(frame.render_passes_by_id.find(quad->render_pass_id) ==
3992 frame.render_passes_by_id.end());
3994 my_host_impl->DrawLayers(&frame, base::TimeTicks::Now());
3995 my_host_impl->DidDrawAllLayers(frame);
3998 // Change location of the intermediate layer
3999 gfx::Transform transform = intermediate_layer_ptr->transform();
4000 transform.matrix().setDouble(0, 3, 1.0001);
4001 intermediate_layer_ptr->SetTransform(transform);
4003 LayerTreeHostImpl::FrameData frame;
4004 EXPECT_TRUE(my_host_impl->PrepareToDraw(&frame, gfx::Rect()));
4006 // Must receive one render pass, as the other one should be culled.
4007 ASSERT_EQ(1U, frame.render_passes.size());
4008 EXPECT_EQ(1U, frame.render_passes[0]->quad_list.size());
4010 EXPECT_EQ(DrawQuad::RENDER_PASS,
4011 frame.render_passes[0]->quad_list[0]->material);
4012 const RenderPassDrawQuad* quad =
4013 RenderPassDrawQuad::MaterialCast(frame.render_passes[0]->quad_list[0]);
4014 EXPECT_TRUE(frame.render_passes_by_id.find(quad->render_pass_id) ==
4015 frame.render_passes_by_id.end());
4017 my_host_impl->DrawLayers(&frame, base::TimeTicks::Now());
4018 my_host_impl->DidDrawAllLayers(frame);
4022 TEST_F(LayerTreeHostImplTest, SurfaceTextureCachingNoPartialSwap) {
4023 LayerTreeSettings settings;
4024 settings.minimum_occlusion_tracking_size = gfx::Size();
4025 settings.cache_render_pass_contents = true;
4026 scoped_ptr<LayerTreeHostImpl> my_host_impl =
4027 LayerTreeHostImpl::Create(settings,
4028 this,
4029 &proxy_,
4030 &stats_instrumentation_);
4032 LayerImpl* root_ptr;
4033 LayerImpl* intermediate_layer_ptr;
4034 LayerImpl* surface_layer_ptr;
4035 LayerImpl* child_ptr;
4037 SetupLayersForTextureCaching(my_host_impl.get(),
4038 root_ptr,
4039 intermediate_layer_ptr,
4040 surface_layer_ptr,
4041 child_ptr,
4042 gfx::Size(100, 100));
4044 LayerTreeHostImpl::FrameData frame;
4045 EXPECT_TRUE(my_host_impl->PrepareToDraw(&frame, gfx::Rect()));
4047 // Must receive two render passes, each with one quad
4048 ASSERT_EQ(2U, frame.render_passes.size());
4049 EXPECT_EQ(1U, frame.render_passes[0]->quad_list.size());
4050 EXPECT_EQ(1U, frame.render_passes[1]->quad_list.size());
4052 EXPECT_EQ(DrawQuad::RENDER_PASS,
4053 frame.render_passes[1]->quad_list[0]->material);
4054 const RenderPassDrawQuad* quad =
4055 RenderPassDrawQuad::MaterialCast(frame.render_passes[1]->quad_list[0]);
4056 RenderPass* target_pass = frame.render_passes_by_id[quad->render_pass_id];
4057 EXPECT_FALSE(target_pass->damage_rect.IsEmpty());
4059 EXPECT_FALSE(frame.render_passes[0]->damage_rect.IsEmpty());
4060 EXPECT_FALSE(frame.render_passes[1]->damage_rect.IsEmpty());
4062 EXPECT_FALSE(
4063 frame.render_passes[0]->has_occlusion_from_outside_target_surface);
4064 EXPECT_FALSE(
4065 frame.render_passes[1]->has_occlusion_from_outside_target_surface);
4067 my_host_impl->DrawLayers(&frame, base::TimeTicks::Now());
4068 my_host_impl->DidDrawAllLayers(frame);
4071 // Draw without any change
4073 LayerTreeHostImpl::FrameData frame;
4074 my_host_impl->SetFullRootLayerDamage();
4075 EXPECT_TRUE(my_host_impl->PrepareToDraw(&frame, gfx::Rect()));
4077 // Even though there was no change, we set the damage to entire viewport.
4078 // One of the passes should be culled as a result, since contents didn't
4079 // change and we have cached texture.
4080 ASSERT_EQ(1U, frame.render_passes.size());
4081 EXPECT_EQ(1U, frame.render_passes[0]->quad_list.size());
4083 my_host_impl->DrawLayers(&frame, base::TimeTicks::Now());
4084 my_host_impl->DidDrawAllLayers(frame);
4087 // Change opacity and draw
4088 surface_layer_ptr->SetOpacity(0.6f);
4090 LayerTreeHostImpl::FrameData frame;
4091 EXPECT_TRUE(my_host_impl->PrepareToDraw(&frame, gfx::Rect()));
4093 // Must receive one render pass, as the other one should be culled
4094 ASSERT_EQ(1U, frame.render_passes.size());
4096 EXPECT_EQ(1U, frame.render_passes[0]->quad_list.size());
4097 EXPECT_EQ(DrawQuad::RENDER_PASS,
4098 frame.render_passes[0]->quad_list[0]->material);
4099 const RenderPassDrawQuad* quad =
4100 RenderPassDrawQuad::MaterialCast(frame.render_passes[0]->quad_list[0]);
4101 EXPECT_TRUE(frame.render_passes_by_id.find(quad->render_pass_id) ==
4102 frame.render_passes_by_id.end());
4104 my_host_impl->DrawLayers(&frame, base::TimeTicks::Now());
4105 my_host_impl->DidDrawAllLayers(frame);
4108 // Change less benign property and draw - should have contents changed flag
4109 surface_layer_ptr->SetStackingOrderChanged(true);
4111 LayerTreeHostImpl::FrameData frame;
4112 EXPECT_TRUE(my_host_impl->PrepareToDraw(&frame, gfx::Rect()));
4114 // Must receive two render passes, each with one quad
4115 ASSERT_EQ(2U, frame.render_passes.size());
4117 EXPECT_EQ(1U, frame.render_passes[0]->quad_list.size());
4118 EXPECT_EQ(DrawQuad::SOLID_COLOR,
4119 frame.render_passes[0]->quad_list[0]->material);
4121 EXPECT_EQ(DrawQuad::RENDER_PASS,
4122 frame.render_passes[1]->quad_list[0]->material);
4123 const RenderPassDrawQuad* quad =
4124 RenderPassDrawQuad::MaterialCast(frame.render_passes[1]->quad_list[0]);
4125 RenderPass* target_pass = frame.render_passes_by_id[quad->render_pass_id];
4126 ASSERT_TRUE(target_pass);
4127 EXPECT_FALSE(target_pass->damage_rect.IsEmpty());
4129 my_host_impl->DrawLayers(&frame, base::TimeTicks::Now());
4130 my_host_impl->DidDrawAllLayers(frame);
4133 // Change opacity again, and evict the cached surface texture.
4134 surface_layer_ptr->SetOpacity(0.5f);
4135 static_cast<GLRendererWithReleaseTextures*>(
4136 my_host_impl->renderer())->ReleaseRenderPassTextures();
4138 // Change opacity and draw
4139 surface_layer_ptr->SetOpacity(0.6f);
4141 LayerTreeHostImpl::FrameData frame;
4142 EXPECT_TRUE(my_host_impl->PrepareToDraw(&frame, gfx::Rect()));
4144 // Must receive two render passes
4145 ASSERT_EQ(2U, frame.render_passes.size());
4147 // Even though not enough properties changed, the entire thing must be
4148 // redrawn as we don't have cached textures
4149 EXPECT_EQ(1U, frame.render_passes[0]->quad_list.size());
4150 EXPECT_EQ(1U, frame.render_passes[1]->quad_list.size());
4152 EXPECT_EQ(DrawQuad::RENDER_PASS,
4153 frame.render_passes[1]->quad_list[0]->material);
4154 const RenderPassDrawQuad* quad =
4155 RenderPassDrawQuad::MaterialCast(frame.render_passes[1]->quad_list[0]);
4156 RenderPass* target_pass = frame.render_passes_by_id[quad->render_pass_id];
4157 ASSERT_TRUE(target_pass);
4158 EXPECT_TRUE(target_pass->damage_rect.IsEmpty());
4160 // Was our surface evicted?
4161 EXPECT_FALSE(my_host_impl->renderer()->HaveCachedResourcesForRenderPassId(
4162 target_pass->id));
4164 my_host_impl->DrawLayers(&frame, base::TimeTicks::Now());
4165 my_host_impl->DidDrawAllLayers(frame);
4168 // Draw without any change, to make sure the state is clear
4170 LayerTreeHostImpl::FrameData frame;
4171 my_host_impl->SetFullRootLayerDamage();
4172 EXPECT_TRUE(my_host_impl->PrepareToDraw(&frame, gfx::Rect()));
4174 // Even though there was no change, we set the damage to entire viewport.
4175 // One of the passes should be culled as a result, since contents didn't
4176 // change and we have cached texture.
4177 ASSERT_EQ(1U, frame.render_passes.size());
4178 EXPECT_EQ(1U, frame.render_passes[0]->quad_list.size());
4180 my_host_impl->DrawLayers(&frame, base::TimeTicks::Now());
4181 my_host_impl->DidDrawAllLayers(frame);
4184 // Change location of the intermediate layer
4185 gfx::Transform transform = intermediate_layer_ptr->transform();
4186 transform.matrix().setDouble(0, 3, 1.0001);
4187 intermediate_layer_ptr->SetTransform(transform);
4189 LayerTreeHostImpl::FrameData frame;
4190 EXPECT_TRUE(my_host_impl->PrepareToDraw(&frame, gfx::Rect()));
4192 // Must receive one render pass, as the other one should be culled.
4193 ASSERT_EQ(1U, frame.render_passes.size());
4194 EXPECT_EQ(1U, frame.render_passes[0]->quad_list.size());
4196 EXPECT_EQ(DrawQuad::RENDER_PASS,
4197 frame.render_passes[0]->quad_list[0]->material);
4198 const RenderPassDrawQuad* quad =
4199 RenderPassDrawQuad::MaterialCast(frame.render_passes[0]->quad_list[0]);
4200 EXPECT_TRUE(frame.render_passes_by_id.find(quad->render_pass_id) ==
4201 frame.render_passes_by_id.end());
4203 my_host_impl->DrawLayers(&frame, base::TimeTicks::Now());
4204 my_host_impl->DidDrawAllLayers(frame);
4208 TEST_F(LayerTreeHostImplTest, ReleaseContentsTextureShouldTriggerCommit) {
4209 set_reduce_memory_result(false);
4211 // If changing the memory limit wouldn't result in changing what was
4212 // committed, then no commit should be requested.
4213 set_reduce_memory_result(false);
4214 host_impl_->set_max_memory_needed_bytes(
4215 host_impl_->memory_allocation_limit_bytes() - 1);
4216 host_impl_->SetManagedMemoryPolicy(ManagedMemoryPolicy(
4217 host_impl_->memory_allocation_limit_bytes() - 1));
4218 EXPECT_FALSE(did_request_commit_);
4219 did_request_commit_ = false;
4221 // If changing the memory limit would result in changing what was
4222 // committed, then a commit should be requested, even though nothing was
4223 // evicted.
4224 set_reduce_memory_result(false);
4225 host_impl_->set_max_memory_needed_bytes(
4226 host_impl_->memory_allocation_limit_bytes());
4227 host_impl_->SetManagedMemoryPolicy(ManagedMemoryPolicy(
4228 host_impl_->memory_allocation_limit_bytes() - 1));
4229 EXPECT_TRUE(did_request_commit_);
4230 did_request_commit_ = false;
4232 // Especially if changing the memory limit caused evictions, we need
4233 // to re-commit.
4234 set_reduce_memory_result(true);
4235 host_impl_->set_max_memory_needed_bytes(1);
4236 host_impl_->SetManagedMemoryPolicy(ManagedMemoryPolicy(
4237 host_impl_->memory_allocation_limit_bytes() - 1));
4238 EXPECT_TRUE(did_request_commit_);
4239 did_request_commit_ = false;
4241 // But if we set it to the same value that it was before, we shouldn't
4242 // re-commit.
4243 host_impl_->SetManagedMemoryPolicy(ManagedMemoryPolicy(
4244 host_impl_->memory_allocation_limit_bytes()));
4245 EXPECT_FALSE(did_request_commit_);
4248 struct RenderPassRemovalTestData : public LayerTreeHostImpl::FrameData {
4249 ScopedPtrHashMap<RenderPass::Id, TestRenderPass> render_pass_cache;
4250 scoped_ptr<SharedQuadState> shared_quad_state;
4253 class TestRenderer : public GLRenderer, public RendererClient {
4254 public:
4255 static scoped_ptr<TestRenderer> Create(ResourceProvider* resource_provider,
4256 OutputSurface* output_surface,
4257 Proxy* proxy) {
4258 scoped_ptr<TestRenderer> renderer(new TestRenderer(resource_provider,
4259 output_surface,
4260 proxy));
4261 if (!renderer->Initialize())
4262 return scoped_ptr<TestRenderer>();
4264 return renderer.Pass();
4267 void ClearCachedTextures() { textures_.clear(); }
4268 void SetHaveCachedResourcesForRenderPassId(RenderPass::Id id) {
4269 textures_.insert(id);
4272 virtual bool HaveCachedResourcesForRenderPassId(RenderPass::Id id) const
4273 OVERRIDE {
4274 return textures_.count(id);
4277 // RendererClient implementation.
4278 virtual gfx::Size DeviceViewportSize() const OVERRIDE {
4279 return viewport_size_;
4281 virtual const LayerTreeSettings& Settings() const OVERRIDE {
4282 return settings_;
4284 virtual void SetFullRootLayerDamage() OVERRIDE {}
4285 virtual void SetManagedMemoryPolicy(const ManagedMemoryPolicy& policy)
4286 OVERRIDE {}
4287 virtual void EnforceManagedMemoryPolicy(const ManagedMemoryPolicy& policy)
4288 OVERRIDE {}
4289 virtual bool HasImplThread() const OVERRIDE { return false; }
4290 virtual bool ShouldClearRootRenderPass() const OVERRIDE { return true; }
4291 virtual CompositorFrameMetadata MakeCompositorFrameMetadata() const
4292 OVERRIDE { return CompositorFrameMetadata(); }
4293 virtual bool AllowPartialSwap() const OVERRIDE {
4294 return true;
4297 protected:
4298 TestRenderer(ResourceProvider* resource_provider,
4299 OutputSurface* output_surface,
4300 Proxy* proxy)
4301 : GLRenderer(this, output_surface, resource_provider, 0) {}
4303 private:
4304 LayerTreeSettings settings_;
4305 gfx::Size viewport_size_;
4306 base::hash_set<RenderPass::Id> textures_;
4309 static void ConfigureRenderPassTestData(const char* test_script,
4310 RenderPassRemovalTestData* test_data,
4311 TestRenderer* renderer) {
4312 renderer->ClearCachedTextures();
4314 // One shared state for all quads - we don't need the correct details
4315 test_data->shared_quad_state = SharedQuadState::Create();
4316 test_data->shared_quad_state->SetAll(gfx::Transform(),
4317 gfx::Size(),
4318 gfx::Rect(),
4319 gfx::Rect(),
4320 false,
4321 1.f);
4323 const char* current_char = test_script;
4325 // Pre-create root pass
4326 RenderPass::Id root_render_pass_id =
4327 RenderPass::Id(test_script[0], test_script[1]);
4328 scoped_ptr<TestRenderPass> pass = TestRenderPass::Create();
4329 pass->SetNew(root_render_pass_id, gfx::Rect(), gfx::Rect(), gfx::Transform());
4330 test_data->render_pass_cache.add(root_render_pass_id, pass.Pass());
4331 while (*current_char) {
4332 int layer_id = *current_char;
4333 current_char++;
4334 ASSERT_TRUE(current_char);
4335 int index = *current_char;
4336 current_char++;
4338 RenderPass::Id render_pass_id = RenderPass::Id(layer_id, index);
4340 bool is_replica = false;
4341 if (!test_data->render_pass_cache.contains(render_pass_id))
4342 is_replica = true;
4344 scoped_ptr<TestRenderPass> render_pass =
4345 test_data->render_pass_cache.take(render_pass_id);
4347 // Cycle through quad data and create all quads.
4348 while (*current_char && *current_char != '\n') {
4349 if (*current_char == 's') {
4350 // Solid color draw quad.
4351 scoped_ptr<SolidColorDrawQuad> quad = SolidColorDrawQuad::Create();
4352 quad->SetNew(test_data->shared_quad_state.get(),
4353 gfx::Rect(0, 0, 10, 10),
4354 SK_ColorWHITE);
4356 render_pass->AppendQuad(quad.PassAs<DrawQuad>());
4357 current_char++;
4358 } else if ((*current_char >= 'A') && (*current_char <= 'Z')) {
4359 // RenderPass draw quad.
4360 int layer_id = *current_char;
4361 current_char++;
4362 ASSERT_TRUE(current_char);
4363 int index = *current_char;
4364 current_char++;
4365 RenderPass::Id new_render_pass_id = RenderPass::Id(layer_id, index);
4366 ASSERT_NE(root_render_pass_id, new_render_pass_id);
4367 bool has_texture = false;
4368 bool contents_changed = true;
4370 if (*current_char == '[') {
4371 current_char++;
4372 while (*current_char && *current_char != ']') {
4373 switch (*current_char) {
4374 case 'c':
4375 contents_changed = false;
4376 break;
4377 case 't':
4378 has_texture = true;
4379 break;
4381 current_char++;
4383 if (*current_char == ']')
4384 current_char++;
4387 if (test_data->render_pass_cache.find(new_render_pass_id) ==
4388 test_data->render_pass_cache.end()) {
4389 if (has_texture)
4390 renderer->SetHaveCachedResourcesForRenderPassId(new_render_pass_id);
4392 scoped_ptr<TestRenderPass> pass = TestRenderPass::Create();
4393 pass->SetNew(new_render_pass_id,
4394 gfx::Rect(),
4395 gfx::Rect(),
4396 gfx::Transform());
4397 test_data->render_pass_cache.add(new_render_pass_id, pass.Pass());
4400 gfx::Rect quad_rect = gfx::Rect(0, 0, 1, 1);
4401 gfx::Rect contents_changed_rect =
4402 contents_changed ? quad_rect : gfx::Rect();
4403 scoped_ptr<RenderPassDrawQuad> quad = RenderPassDrawQuad::Create();
4404 quad->SetNew(test_data->shared_quad_state.get(),
4405 quad_rect,
4406 new_render_pass_id,
4407 is_replica,
4409 contents_changed_rect,
4410 gfx::RectF(0.f, 0.f, 1.f, 1.f),
4411 WebKit::WebFilterOperations(),
4412 skia::RefPtr<SkImageFilter>(),
4413 WebKit::WebFilterOperations());
4414 render_pass->AppendQuad(quad.PassAs<DrawQuad>());
4417 test_data->render_passes_by_id[render_pass_id] = render_pass.get();
4418 test_data->render_passes.insert(test_data->render_passes.begin(),
4419 render_pass.PassAs<RenderPass>());
4420 if (*current_char)
4421 current_char++;
4425 void DumpRenderPassTestData(const RenderPassRemovalTestData& test_data,
4426 char* buffer) {
4427 char* pos = buffer;
4428 for (RenderPassList::const_reverse_iterator it =
4429 test_data.render_passes.rbegin();
4430 it != test_data.render_passes.rend();
4431 ++it) {
4432 const RenderPass* current_pass = *it;
4433 *pos = current_pass->id.layer_id;
4434 pos++;
4435 *pos = current_pass->id.index;
4436 pos++;
4438 QuadList::const_iterator quad_list_iterator =
4439 current_pass->quad_list.begin();
4440 while (quad_list_iterator != current_pass->quad_list.end()) {
4441 DrawQuad* current_quad = *quad_list_iterator;
4442 switch (current_quad->material) {
4443 case DrawQuad::SOLID_COLOR:
4444 *pos = 's';
4445 pos++;
4446 break;
4447 case DrawQuad::RENDER_PASS:
4448 *pos = RenderPassDrawQuad::MaterialCast(current_quad)->
4449 render_pass_id.layer_id;
4450 pos++;
4451 *pos = RenderPassDrawQuad::MaterialCast(current_quad)->
4452 render_pass_id.index;
4453 pos++;
4454 break;
4455 default:
4456 *pos = 'x';
4457 pos++;
4458 break;
4461 quad_list_iterator++;
4463 *pos = '\n';
4464 pos++;
4466 *pos = '\0';
4469 // Each RenderPassList is represented by a string which describes the
4470 // configuration.
4471 // The syntax of the string is as follows:
4473 // RsssssX[c]ssYsssZ[t]ssW[ct]
4474 // Identifies the render pass------------------------^ ^^^ ^ ^ ^ ^ ^
4475 // These are solid color quads--------------------------+ | | | | |
4476 // Identifies RenderPassDrawQuad's RenderPass--------------+ | | | |
4477 // This quad's contents didn't change------------------------+ | | |
4478 // This quad's contents changed and it has no texture------------+ | |
4479 // This quad has texture but its contents changed----------------------+ |
4480 // This quad's contents didn't change and it has texture - will be removed---+
4482 // Expected results have exactly the same syntax, except they do not use square
4483 // brackets, since we only check the structure, not attributes.
4485 // Test case configuration consists of initialization script and expected
4486 // results, all in the same format.
4487 struct TestCase {
4488 const char* name;
4489 const char* init_script;
4490 const char* expected_result;
4493 TestCase remove_render_passes_cases[] = {
4495 "Single root pass",
4496 "R0ssss\n",
4497 "R0ssss\n"
4498 }, {
4499 "Single pass - no quads",
4500 "R0\n",
4501 "R0\n"
4502 }, {
4503 "Two passes, no removal",
4504 "R0ssssA0sss\n"
4505 "A0ssss\n",
4506 "R0ssssA0sss\n"
4507 "A0ssss\n"
4508 }, {
4509 "Two passes, remove last",
4510 "R0ssssA0[ct]sss\n"
4511 "A0ssss\n",
4512 "R0ssssA0sss\n"
4513 }, {
4514 "Have texture but contents changed - leave pass",
4515 "R0ssssA0[t]sss\n"
4516 "A0ssss\n",
4517 "R0ssssA0sss\n"
4518 "A0ssss\n"
4519 }, {
4520 "Contents didn't change but no texture - leave pass",
4521 "R0ssssA0[c]sss\n"
4522 "A0ssss\n",
4523 "R0ssssA0sss\n"
4524 "A0ssss\n"
4525 }, {
4526 "Replica: two quads reference the same pass; remove",
4527 "R0ssssA0[ct]A0[ct]sss\n"
4528 "A0ssss\n",
4529 "R0ssssA0A0sss\n"
4530 }, {
4531 "Replica: two quads reference the same pass; leave",
4532 "R0ssssA0[c]A0[c]sss\n"
4533 "A0ssss\n",
4534 "R0ssssA0A0sss\n"
4535 "A0ssss\n",
4536 }, {
4537 "Many passes, remove all",
4538 "R0ssssA0[ct]sss\n"
4539 "A0sssB0[ct]C0[ct]s\n"
4540 "B0sssD0[ct]ssE0[ct]F0[ct]\n"
4541 "E0ssssss\n"
4542 "C0G0[ct]\n"
4543 "D0sssssss\n"
4544 "F0sssssss\n"
4545 "G0sss\n",
4547 "R0ssssA0sss\n"
4548 }, {
4549 "Deep recursion, remove all",
4551 "R0sssssA0[ct]ssss\n"
4552 "A0ssssB0sss\n"
4553 "B0C0\n"
4554 "C0D0\n"
4555 "D0E0\n"
4556 "E0F0\n"
4557 "F0G0\n"
4558 "G0H0\n"
4559 "H0sssI0sss\n"
4560 "I0J0\n"
4561 "J0ssss\n",
4563 "R0sssssA0ssss\n"
4564 }, {
4565 "Wide recursion, remove all",
4566 "R0A0[ct]B0[ct]C0[ct]D0[ct]E0[ct]F0[ct]G0[ct]H0[ct]I0[ct]J0[ct]\n"
4567 "A0s\n"
4568 "B0s\n"
4569 "C0ssss\n"
4570 "D0ssss\n"
4571 "E0s\n"
4572 "F0\n"
4573 "G0s\n"
4574 "H0s\n"
4575 "I0s\n"
4576 "J0ssss\n",
4578 "R0A0B0C0D0E0F0G0H0I0J0\n"
4579 }, {
4580 "Remove passes regardless of cache state",
4581 "R0ssssA0[ct]sss\n"
4582 "A0sssB0C0s\n"
4583 "B0sssD0[c]ssE0[t]F0\n"
4584 "E0ssssss\n"
4585 "C0G0\n"
4586 "D0sssssss\n"
4587 "F0sssssss\n"
4588 "G0sss\n",
4590 "R0ssssA0sss\n"
4591 }, {
4592 "Leave some passes, remove others",
4594 "R0ssssA0[c]sss\n"
4595 "A0sssB0[t]C0[ct]s\n"
4596 "B0sssD0[c]ss\n"
4597 "C0G0\n"
4598 "D0sssssss\n"
4599 "G0sss\n",
4601 "R0ssssA0sss\n"
4602 "A0sssB0C0s\n"
4603 "B0sssD0ss\n"
4604 "D0sssssss\n"
4605 }, {
4606 0, 0, 0
4610 static void VerifyRenderPassTestData(
4611 const TestCase& test_case,
4612 const RenderPassRemovalTestData& test_data) {
4613 char actual_result[1024];
4614 DumpRenderPassTestData(test_data, actual_result);
4615 EXPECT_STREQ(test_case.expected_result, actual_result) << "In test case: " <<
4616 test_case.name;
4619 TEST_F(LayerTreeHostImplTest, TestRemoveRenderPasses) {
4620 scoped_ptr<OutputSurface> output_surface(CreateOutputSurface());
4621 ASSERT_TRUE(output_surface->context3d());
4622 scoped_ptr<ResourceProvider> resource_provider =
4623 ResourceProvider::Create(output_surface.get(), 0);
4625 scoped_ptr<TestRenderer> renderer =
4626 TestRenderer::Create(resource_provider.get(),
4627 output_surface.get(),
4628 &proxy_);
4630 int test_case_index = 0;
4631 while (remove_render_passes_cases[test_case_index].name) {
4632 RenderPassRemovalTestData test_data;
4633 ConfigureRenderPassTestData(
4634 remove_render_passes_cases[test_case_index].init_script,
4635 &test_data,
4636 renderer.get());
4637 LayerTreeHostImpl::RemoveRenderPasses(
4638 LayerTreeHostImpl::CullRenderPassesWithCachedTextures(renderer.get()),
4639 &test_data);
4640 VerifyRenderPassTestData(remove_render_passes_cases[test_case_index],
4641 test_data);
4642 test_case_index++;
4646 class LayerTreeHostImplTestWithDelegatingRenderer
4647 : public LayerTreeHostImplTest {
4648 protected:
4649 virtual scoped_ptr<OutputSurface> CreateOutputSurface() OVERRIDE {
4650 return FakeOutputSurface::CreateDelegating3d().PassAs<OutputSurface>();
4653 void DrawFrameAndTestDamage(const gfx::RectF& expected_damage) {
4654 bool expect_to_draw = !expected_damage.IsEmpty();
4656 LayerTreeHostImpl::FrameData frame;
4657 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
4659 if (!expect_to_draw) {
4660 // With no damage, we don't draw, and no quads are created.
4661 ASSERT_EQ(0u, frame.render_passes.size());
4662 } else {
4663 ASSERT_EQ(1u, frame.render_passes.size());
4665 // Verify the damage rect for the root render pass.
4666 const RenderPass* root_render_pass = frame.render_passes.back();
4667 EXPECT_RECT_EQ(expected_damage, root_render_pass->damage_rect);
4669 // Verify the root and child layers' quads are generated and not being
4670 // culled.
4671 ASSERT_EQ(2u, root_render_pass->quad_list.size());
4673 LayerImpl* child = host_impl_->active_tree()->root_layer()->children()[0];
4674 gfx::RectF expected_child_visible_rect(child->content_bounds());
4675 EXPECT_RECT_EQ(expected_child_visible_rect,
4676 root_render_pass->quad_list[0]->visible_rect);
4678 LayerImpl* root = host_impl_->active_tree()->root_layer();
4679 gfx::RectF expected_root_visible_rect(root->content_bounds());
4680 EXPECT_RECT_EQ(expected_root_visible_rect,
4681 root_render_pass->quad_list[1]->visible_rect);
4684 host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
4685 host_impl_->DidDrawAllLayers(frame);
4686 EXPECT_EQ(expect_to_draw, host_impl_->SwapBuffers(frame));
4690 TEST_F(LayerTreeHostImplTestWithDelegatingRenderer, FrameIncludesDamageRect) {
4691 scoped_ptr<SolidColorLayerImpl> root =
4692 SolidColorLayerImpl::Create(host_impl_->active_tree(), 1);
4693 root->SetAnchorPoint(gfx::PointF());
4694 root->SetPosition(gfx::PointF());
4695 root->SetBounds(gfx::Size(10, 10));
4696 root->SetContentBounds(gfx::Size(10, 10));
4697 root->SetDrawsContent(true);
4699 // Child layer is in the bottom right corner.
4700 scoped_ptr<SolidColorLayerImpl> child =
4701 SolidColorLayerImpl::Create(host_impl_->active_tree(), 2);
4702 child->SetAnchorPoint(gfx::PointF(0.f, 0.f));
4703 child->SetPosition(gfx::PointF(9.f, 9.f));
4704 child->SetBounds(gfx::Size(1, 1));
4705 child->SetContentBounds(gfx::Size(1, 1));
4706 child->SetDrawsContent(true);
4707 root->AddChild(child.PassAs<LayerImpl>());
4709 host_impl_->active_tree()->SetRootLayer(root.PassAs<LayerImpl>());
4711 // Draw a frame. In the first frame, the entire viewport should be damaged.
4712 gfx::Rect full_frame_damage = gfx::Rect(host_impl_->device_viewport_size());
4713 DrawFrameAndTestDamage(full_frame_damage);
4715 // The second frame has damage that doesn't touch the child layer. Its quads
4716 // should still be generated.
4717 gfx::Rect small_damage = gfx::Rect(0, 0, 1, 1);
4718 host_impl_->active_tree()->root_layer()->set_update_rect(small_damage);
4719 DrawFrameAndTestDamage(small_damage);
4721 // The third frame should have no damage, so no quads should be generated.
4722 gfx::Rect no_damage;
4723 DrawFrameAndTestDamage(no_damage);
4726 class FakeMaskLayerImpl : public LayerImpl {
4727 public:
4728 static scoped_ptr<FakeMaskLayerImpl> Create(LayerTreeImpl* tree_impl,
4729 int id) {
4730 return make_scoped_ptr(new FakeMaskLayerImpl(tree_impl, id));
4733 virtual ResourceProvider::ResourceId ContentsResourceId() const OVERRIDE {
4734 return 0;
4737 private:
4738 FakeMaskLayerImpl(LayerTreeImpl* tree_impl, int id)
4739 : LayerImpl(tree_impl, id) {}
4742 TEST_F(LayerTreeHostImplTest, MaskLayerWithScaling) {
4743 // Root
4744 // |
4745 // +-- Scaling Layer (adds a 2x scale)
4746 // |
4747 // +-- Content Layer
4748 // +--Mask
4749 scoped_ptr<LayerImpl> scoped_root =
4750 LayerImpl::Create(host_impl_->active_tree(), 1);
4751 LayerImpl* root = scoped_root.get();
4752 host_impl_->active_tree()->SetRootLayer(scoped_root.Pass());
4754 scoped_ptr<LayerImpl> scoped_scaling_layer =
4755 LayerImpl::Create(host_impl_->active_tree(), 2);
4756 LayerImpl* scaling_layer = scoped_scaling_layer.get();
4757 root->AddChild(scoped_scaling_layer.Pass());
4759 scoped_ptr<LayerImpl> scoped_content_layer =
4760 LayerImpl::Create(host_impl_->active_tree(), 3);
4761 LayerImpl* content_layer = scoped_content_layer.get();
4762 scaling_layer->AddChild(scoped_content_layer.Pass());
4764 scoped_ptr<FakeMaskLayerImpl> scoped_mask_layer =
4765 FakeMaskLayerImpl::Create(host_impl_->active_tree(), 4);
4766 FakeMaskLayerImpl* mask_layer = scoped_mask_layer.get();
4767 content_layer->SetMaskLayer(scoped_mask_layer.PassAs<LayerImpl>());
4769 gfx::Size root_size(100, 100);
4770 root->SetBounds(root_size);
4771 root->SetContentBounds(root_size);
4772 root->SetPosition(gfx::PointF());
4773 root->SetAnchorPoint(gfx::PointF());
4775 gfx::Size scaling_layer_size(50, 50);
4776 scaling_layer->SetBounds(scaling_layer_size);
4777 scaling_layer->SetContentBounds(scaling_layer_size);
4778 scaling_layer->SetPosition(gfx::PointF());
4779 scaling_layer->SetAnchorPoint(gfx::PointF());
4780 gfx::Transform scale;
4781 scale.Scale(2.f, 2.f);
4782 scaling_layer->SetTransform(scale);
4784 content_layer->SetBounds(scaling_layer_size);
4785 content_layer->SetContentBounds(scaling_layer_size);
4786 content_layer->SetPosition(gfx::PointF());
4787 content_layer->SetAnchorPoint(gfx::PointF());
4788 content_layer->SetDrawsContent(true);
4790 mask_layer->SetBounds(scaling_layer_size);
4791 mask_layer->SetContentBounds(scaling_layer_size);
4792 mask_layer->SetPosition(gfx::PointF());
4793 mask_layer->SetAnchorPoint(gfx::PointF());
4794 mask_layer->SetDrawsContent(true);
4797 // Check that the tree scaling is correctly taken into account for the mask,
4798 // that should fully map onto the quad.
4799 float device_scale_factor = 1.f;
4800 host_impl_->SetViewportSize(root_size);
4801 host_impl_->SetDeviceScaleFactor(device_scale_factor);
4803 LayerTreeHostImpl::FrameData frame;
4804 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
4806 ASSERT_EQ(1u, frame.render_passes.size());
4807 ASSERT_EQ(1u, frame.render_passes[0]->quad_list.size());
4808 ASSERT_EQ(DrawQuad::RENDER_PASS,
4809 frame.render_passes[0]->quad_list[0]->material);
4810 const RenderPassDrawQuad* render_pass_quad =
4811 RenderPassDrawQuad::MaterialCast(frame.render_passes[0]->quad_list[0]);
4812 EXPECT_EQ(gfx::Rect(0, 0, 100, 100).ToString(),
4813 render_pass_quad->rect.ToString());
4814 EXPECT_EQ(gfx::RectF(0.f, 0.f, 1.f, 1.f).ToString(),
4815 render_pass_quad->mask_uv_rect.ToString());
4817 host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
4818 host_impl_->DidDrawAllLayers(frame);
4822 // Applying a DSF should change the render surface size, but won't affect
4823 // which part of the mask is used.
4824 device_scale_factor = 2.f;
4825 gfx::Size device_viewport =
4826 gfx::ToFlooredSize(gfx::ScaleSize(root_size, device_scale_factor));
4827 host_impl_->SetViewportSize(device_viewport);
4828 host_impl_->SetDeviceScaleFactor(device_scale_factor);
4829 host_impl_->active_tree()->set_needs_update_draw_properties();
4831 LayerTreeHostImpl::FrameData frame;
4832 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
4834 ASSERT_EQ(1u, frame.render_passes.size());
4835 ASSERT_EQ(1u, frame.render_passes[0]->quad_list.size());
4836 ASSERT_EQ(DrawQuad::RENDER_PASS,
4837 frame.render_passes[0]->quad_list[0]->material);
4838 const RenderPassDrawQuad* render_pass_quad =
4839 RenderPassDrawQuad::MaterialCast(frame.render_passes[0]->quad_list[0]);
4840 EXPECT_EQ(gfx::Rect(0, 0, 200, 200).ToString(),
4841 render_pass_quad->rect.ToString());
4842 EXPECT_EQ(gfx::RectF(0.f, 0.f, 1.f, 1.f).ToString(),
4843 render_pass_quad->mask_uv_rect.ToString());
4845 host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
4846 host_impl_->DidDrawAllLayers(frame);
4850 // Applying an equivalent content scale on the content layer and the mask
4851 // should still result in the same part of the mask being used.
4852 gfx::Size content_bounds =
4853 gfx::ToRoundedSize(gfx::ScaleSize(scaling_layer_size,
4854 device_scale_factor));
4855 content_layer->SetContentBounds(content_bounds);
4856 content_layer->SetContentsScale(device_scale_factor, device_scale_factor);
4857 mask_layer->SetContentBounds(content_bounds);
4858 mask_layer->SetContentsScale(device_scale_factor, device_scale_factor);
4859 host_impl_->active_tree()->set_needs_update_draw_properties();
4861 LayerTreeHostImpl::FrameData frame;
4862 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
4864 ASSERT_EQ(1u, frame.render_passes.size());
4865 ASSERT_EQ(1u, frame.render_passes[0]->quad_list.size());
4866 ASSERT_EQ(DrawQuad::RENDER_PASS,
4867 frame.render_passes[0]->quad_list[0]->material);
4868 const RenderPassDrawQuad* render_pass_quad =
4869 RenderPassDrawQuad::MaterialCast(frame.render_passes[0]->quad_list[0]);
4870 EXPECT_EQ(gfx::Rect(0, 0, 200, 200).ToString(),
4871 render_pass_quad->rect.ToString());
4872 EXPECT_EQ(gfx::RectF(0.f, 0.f, 1.f, 1.f).ToString(),
4873 render_pass_quad->mask_uv_rect.ToString());
4875 host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
4876 host_impl_->DidDrawAllLayers(frame);
4880 TEST_F(LayerTreeHostImplTest, MaskLayerWithDifferentBounds) {
4881 // The mask layer has bounds 100x100 but is attached to a layer with bounds
4882 // 50x50.
4884 scoped_ptr<LayerImpl> scoped_root =
4885 LayerImpl::Create(host_impl_->active_tree(), 1);
4886 LayerImpl* root = scoped_root.get();
4887 host_impl_->active_tree()->SetRootLayer(scoped_root.Pass());
4889 scoped_ptr<LayerImpl> scoped_content_layer =
4890 LayerImpl::Create(host_impl_->active_tree(), 3);
4891 LayerImpl* content_layer = scoped_content_layer.get();
4892 root->AddChild(scoped_content_layer.Pass());
4894 scoped_ptr<FakeMaskLayerImpl> scoped_mask_layer =
4895 FakeMaskLayerImpl::Create(host_impl_->active_tree(), 4);
4896 FakeMaskLayerImpl* mask_layer = scoped_mask_layer.get();
4897 content_layer->SetMaskLayer(scoped_mask_layer.PassAs<LayerImpl>());
4899 gfx::Size root_size(100, 100);
4900 root->SetBounds(root_size);
4901 root->SetContentBounds(root_size);
4902 root->SetPosition(gfx::PointF());
4903 root->SetAnchorPoint(gfx::PointF());
4905 gfx::Size layer_size(50, 50);
4906 content_layer->SetBounds(layer_size);
4907 content_layer->SetContentBounds(layer_size);
4908 content_layer->SetPosition(gfx::PointF());
4909 content_layer->SetAnchorPoint(gfx::PointF());
4910 content_layer->SetDrawsContent(true);
4912 gfx::Size mask_size(100, 100);
4913 mask_layer->SetBounds(mask_size);
4914 mask_layer->SetContentBounds(mask_size);
4915 mask_layer->SetPosition(gfx::PointF());
4916 mask_layer->SetAnchorPoint(gfx::PointF());
4917 mask_layer->SetDrawsContent(true);
4919 // Check that the mask fills the surface.
4920 float device_scale_factor = 1.f;
4921 host_impl_->SetViewportSize(root_size);
4922 host_impl_->SetDeviceScaleFactor(device_scale_factor);
4924 LayerTreeHostImpl::FrameData frame;
4925 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
4927 ASSERT_EQ(1u, frame.render_passes.size());
4928 ASSERT_EQ(1u, frame.render_passes[0]->quad_list.size());
4929 ASSERT_EQ(DrawQuad::RENDER_PASS,
4930 frame.render_passes[0]->quad_list[0]->material);
4931 const RenderPassDrawQuad* render_pass_quad =
4932 RenderPassDrawQuad::MaterialCast(frame.render_passes[0]->quad_list[0]);
4933 EXPECT_EQ(gfx::Rect(0, 0, 50, 50).ToString(),
4934 render_pass_quad->rect.ToString());
4935 EXPECT_EQ(gfx::RectF(0.f, 0.f, 1.f, 1.f).ToString(),
4936 render_pass_quad->mask_uv_rect.ToString());
4938 host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
4939 host_impl_->DidDrawAllLayers(frame);
4942 // Applying a DSF should change the render surface size, but won't affect
4943 // which part of the mask is used.
4944 device_scale_factor = 2.f;
4945 gfx::Size device_viewport =
4946 gfx::ToFlooredSize(gfx::ScaleSize(root_size, device_scale_factor));
4947 host_impl_->SetViewportSize(device_viewport);
4948 host_impl_->SetDeviceScaleFactor(device_scale_factor);
4949 host_impl_->active_tree()->set_needs_update_draw_properties();
4951 LayerTreeHostImpl::FrameData frame;
4952 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
4954 ASSERT_EQ(1u, frame.render_passes.size());
4955 ASSERT_EQ(1u, frame.render_passes[0]->quad_list.size());
4956 ASSERT_EQ(DrawQuad::RENDER_PASS,
4957 frame.render_passes[0]->quad_list[0]->material);
4958 const RenderPassDrawQuad* render_pass_quad =
4959 RenderPassDrawQuad::MaterialCast(frame.render_passes[0]->quad_list[0]);
4960 EXPECT_EQ(gfx::Rect(0, 0, 100, 100).ToString(),
4961 render_pass_quad->rect.ToString());
4962 EXPECT_EQ(gfx::RectF(0.f, 0.f, 1.f, 1.f).ToString(),
4963 render_pass_quad->mask_uv_rect.ToString());
4965 host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
4966 host_impl_->DidDrawAllLayers(frame);
4969 // Applying an equivalent content scale on the content layer and the mask
4970 // should still result in the same part of the mask being used.
4971 gfx::Size layer_size_large =
4972 gfx::ToRoundedSize(gfx::ScaleSize(layer_size, device_scale_factor));
4973 content_layer->SetContentBounds(layer_size_large);
4974 content_layer->SetContentsScale(device_scale_factor, device_scale_factor);
4975 gfx::Size mask_size_large =
4976 gfx::ToRoundedSize(gfx::ScaleSize(mask_size, device_scale_factor));
4977 mask_layer->SetContentBounds(mask_size_large);
4978 mask_layer->SetContentsScale(device_scale_factor, device_scale_factor);
4979 host_impl_->active_tree()->set_needs_update_draw_properties();
4981 LayerTreeHostImpl::FrameData frame;
4982 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
4984 ASSERT_EQ(1u, frame.render_passes.size());
4985 ASSERT_EQ(1u, frame.render_passes[0]->quad_list.size());
4986 ASSERT_EQ(DrawQuad::RENDER_PASS,
4987 frame.render_passes[0]->quad_list[0]->material);
4988 const RenderPassDrawQuad* render_pass_quad =
4989 RenderPassDrawQuad::MaterialCast(frame.render_passes[0]->quad_list[0]);
4990 EXPECT_EQ(gfx::Rect(0, 0, 100, 100).ToString(),
4991 render_pass_quad->rect.ToString());
4992 EXPECT_EQ(gfx::RectF(0.f, 0.f, 1.f, 1.f).ToString(),
4993 render_pass_quad->mask_uv_rect.ToString());
4995 host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
4996 host_impl_->DidDrawAllLayers(frame);
4999 // Applying a different contents scale to the mask layer means it will have
5000 // a larger texture, but it should use the same tex coords to cover the
5001 // layer it masks.
5002 mask_layer->SetContentBounds(mask_size);
5003 mask_layer->SetContentsScale(1.f, 1.f);
5004 host_impl_->active_tree()->set_needs_update_draw_properties();
5006 LayerTreeHostImpl::FrameData frame;
5007 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
5009 ASSERT_EQ(1u, frame.render_passes.size());
5010 ASSERT_EQ(1u, frame.render_passes[0]->quad_list.size());
5011 ASSERT_EQ(DrawQuad::RENDER_PASS,
5012 frame.render_passes[0]->quad_list[0]->material);
5013 const RenderPassDrawQuad* render_pass_quad =
5014 RenderPassDrawQuad::MaterialCast(frame.render_passes[0]->quad_list[0]);
5015 EXPECT_EQ(gfx::Rect(0, 0, 100, 100).ToString(),
5016 render_pass_quad->rect.ToString());
5017 EXPECT_EQ(gfx::RectF(0.f, 0.f, 1.f, 1.f).ToString(),
5018 render_pass_quad->mask_uv_rect.ToString());
5020 host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
5021 host_impl_->DidDrawAllLayers(frame);
5025 TEST_F(LayerTreeHostImplTest, ReflectionMaskLayerWithDifferentBounds) {
5026 // The replica's mask layer has bounds 100x100 but the replica is of a
5027 // layer with bounds 50x50.
5029 scoped_ptr<LayerImpl> scoped_root =
5030 LayerImpl::Create(host_impl_->active_tree(), 1);
5031 LayerImpl* root = scoped_root.get();
5032 host_impl_->active_tree()->SetRootLayer(scoped_root.Pass());
5034 scoped_ptr<LayerImpl> scoped_content_layer =
5035 LayerImpl::Create(host_impl_->active_tree(), 3);
5036 LayerImpl* content_layer = scoped_content_layer.get();
5037 root->AddChild(scoped_content_layer.Pass());
5039 scoped_ptr<LayerImpl> scoped_replica_layer =
5040 LayerImpl::Create(host_impl_->active_tree(), 2);
5041 LayerImpl* replica_layer = scoped_replica_layer.get();
5042 content_layer->SetReplicaLayer(scoped_replica_layer.Pass());
5044 scoped_ptr<FakeMaskLayerImpl> scoped_mask_layer =
5045 FakeMaskLayerImpl::Create(host_impl_->active_tree(), 4);
5046 FakeMaskLayerImpl* mask_layer = scoped_mask_layer.get();
5047 replica_layer->SetMaskLayer(scoped_mask_layer.PassAs<LayerImpl>());
5049 gfx::Size root_size(100, 100);
5050 root->SetBounds(root_size);
5051 root->SetContentBounds(root_size);
5052 root->SetPosition(gfx::PointF());
5053 root->SetAnchorPoint(gfx::PointF());
5055 gfx::Size layer_size(50, 50);
5056 content_layer->SetBounds(layer_size);
5057 content_layer->SetContentBounds(layer_size);
5058 content_layer->SetPosition(gfx::PointF());
5059 content_layer->SetAnchorPoint(gfx::PointF());
5060 content_layer->SetDrawsContent(true);
5062 gfx::Size mask_size(100, 100);
5063 mask_layer->SetBounds(mask_size);
5064 mask_layer->SetContentBounds(mask_size);
5065 mask_layer->SetPosition(gfx::PointF());
5066 mask_layer->SetAnchorPoint(gfx::PointF());
5067 mask_layer->SetDrawsContent(true);
5069 // Check that the mask fills the surface.
5070 float device_scale_factor = 1.f;
5071 host_impl_->SetViewportSize(root_size);
5072 host_impl_->SetDeviceScaleFactor(device_scale_factor);
5074 LayerTreeHostImpl::FrameData frame;
5075 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
5077 ASSERT_EQ(1u, frame.render_passes.size());
5078 ASSERT_EQ(2u, frame.render_passes[0]->quad_list.size());
5079 ASSERT_EQ(DrawQuad::RENDER_PASS,
5080 frame.render_passes[0]->quad_list[1]->material);
5081 const RenderPassDrawQuad* replica_quad =
5082 RenderPassDrawQuad::MaterialCast(frame.render_passes[0]->quad_list[1]);
5083 EXPECT_TRUE(replica_quad->is_replica);
5084 EXPECT_EQ(gfx::Rect(0, 0, 50, 50).ToString(),
5085 replica_quad->rect.ToString());
5086 EXPECT_EQ(gfx::RectF(0.f, 0.f, 1.f, 1.f).ToString(),
5087 replica_quad->mask_uv_rect.ToString());
5089 host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
5090 host_impl_->DidDrawAllLayers(frame);
5093 // Applying a DSF should change the render surface size, but won't affect
5094 // which part of the mask is used.
5095 device_scale_factor = 2.f;
5096 gfx::Size device_viewport =
5097 gfx::ToFlooredSize(gfx::ScaleSize(root_size, device_scale_factor));
5098 host_impl_->SetViewportSize(device_viewport);
5099 host_impl_->SetDeviceScaleFactor(device_scale_factor);
5100 host_impl_->active_tree()->set_needs_update_draw_properties();
5102 LayerTreeHostImpl::FrameData frame;
5103 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
5105 ASSERT_EQ(1u, frame.render_passes.size());
5106 ASSERT_EQ(2u, frame.render_passes[0]->quad_list.size());
5107 ASSERT_EQ(DrawQuad::RENDER_PASS,
5108 frame.render_passes[0]->quad_list[1]->material);
5109 const RenderPassDrawQuad* replica_quad =
5110 RenderPassDrawQuad::MaterialCast(frame.render_passes[0]->quad_list[1]);
5111 EXPECT_TRUE(replica_quad->is_replica);
5112 EXPECT_EQ(gfx::Rect(0, 0, 100, 100).ToString(),
5113 replica_quad->rect.ToString());
5114 EXPECT_EQ(gfx::RectF(0.f, 0.f, 1.f, 1.f).ToString(),
5115 replica_quad->mask_uv_rect.ToString());
5117 host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
5118 host_impl_->DidDrawAllLayers(frame);
5121 // Applying an equivalent content scale on the content layer and the mask
5122 // should still result in the same part of the mask being used.
5123 gfx::Size layer_size_large =
5124 gfx::ToRoundedSize(gfx::ScaleSize(layer_size, device_scale_factor));
5125 content_layer->SetContentBounds(layer_size_large);
5126 content_layer->SetContentsScale(device_scale_factor, device_scale_factor);
5127 gfx::Size mask_size_large =
5128 gfx::ToRoundedSize(gfx::ScaleSize(mask_size, device_scale_factor));
5129 mask_layer->SetContentBounds(mask_size_large);
5130 mask_layer->SetContentsScale(device_scale_factor, device_scale_factor);
5131 host_impl_->active_tree()->set_needs_update_draw_properties();
5133 LayerTreeHostImpl::FrameData frame;
5134 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
5136 ASSERT_EQ(1u, frame.render_passes.size());
5137 ASSERT_EQ(2u, frame.render_passes[0]->quad_list.size());
5138 ASSERT_EQ(DrawQuad::RENDER_PASS,
5139 frame.render_passes[0]->quad_list[1]->material);
5140 const RenderPassDrawQuad* replica_quad =
5141 RenderPassDrawQuad::MaterialCast(frame.render_passes[0]->quad_list[1]);
5142 EXPECT_TRUE(replica_quad->is_replica);
5143 EXPECT_EQ(gfx::Rect(0, 0, 100, 100).ToString(),
5144 replica_quad->rect.ToString());
5145 EXPECT_EQ(gfx::RectF(0.f, 0.f, 1.f, 1.f).ToString(),
5146 replica_quad->mask_uv_rect.ToString());
5148 host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
5149 host_impl_->DidDrawAllLayers(frame);
5152 // Applying a different contents scale to the mask layer means it will have
5153 // a larger texture, but it should use the same tex coords to cover the
5154 // layer it masks.
5155 mask_layer->SetContentBounds(mask_size);
5156 mask_layer->SetContentsScale(1.f, 1.f);
5157 host_impl_->active_tree()->set_needs_update_draw_properties();
5159 LayerTreeHostImpl::FrameData frame;
5160 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
5162 ASSERT_EQ(1u, frame.render_passes.size());
5163 ASSERT_EQ(2u, frame.render_passes[0]->quad_list.size());
5164 ASSERT_EQ(DrawQuad::RENDER_PASS,
5165 frame.render_passes[0]->quad_list[1]->material);
5166 const RenderPassDrawQuad* replica_quad =
5167 RenderPassDrawQuad::MaterialCast(frame.render_passes[0]->quad_list[1]);
5168 EXPECT_TRUE(replica_quad->is_replica);
5169 EXPECT_EQ(gfx::Rect(0, 0, 100, 100).ToString(),
5170 replica_quad->rect.ToString());
5171 EXPECT_EQ(gfx::RectF(0.f, 0.f, 1.f, 1.f).ToString(),
5172 replica_quad->mask_uv_rect.ToString());
5174 host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
5175 host_impl_->DidDrawAllLayers(frame);
5179 TEST_F(LayerTreeHostImplTest, ReflectionMaskLayerForSurfaceWithUnclippedChild) {
5180 // The replica is of a layer with bounds 50x50, but it has a child that causes
5181 // the surface bounds to be larger.
5183 scoped_ptr<LayerImpl> scoped_root =
5184 LayerImpl::Create(host_impl_->active_tree(), 1);
5185 LayerImpl* root = scoped_root.get();
5186 host_impl_->active_tree()->SetRootLayer(scoped_root.Pass());
5188 scoped_ptr<LayerImpl> scoped_content_layer =
5189 LayerImpl::Create(host_impl_->active_tree(), 2);
5190 LayerImpl* content_layer = scoped_content_layer.get();
5191 root->AddChild(scoped_content_layer.Pass());
5193 scoped_ptr<LayerImpl> scoped_content_child_layer =
5194 LayerImpl::Create(host_impl_->active_tree(), 3);
5195 LayerImpl* content_child_layer = scoped_content_child_layer.get();
5196 content_layer->AddChild(scoped_content_child_layer.Pass());
5198 scoped_ptr<LayerImpl> scoped_replica_layer =
5199 LayerImpl::Create(host_impl_->active_tree(), 4);
5200 LayerImpl* replica_layer = scoped_replica_layer.get();
5201 content_layer->SetReplicaLayer(scoped_replica_layer.Pass());
5203 scoped_ptr<FakeMaskLayerImpl> scoped_mask_layer =
5204 FakeMaskLayerImpl::Create(host_impl_->active_tree(), 5);
5205 FakeMaskLayerImpl* mask_layer = scoped_mask_layer.get();
5206 replica_layer->SetMaskLayer(scoped_mask_layer.PassAs<LayerImpl>());
5208 gfx::Size root_size(100, 100);
5209 root->SetBounds(root_size);
5210 root->SetContentBounds(root_size);
5211 root->SetPosition(gfx::PointF());
5212 root->SetAnchorPoint(gfx::PointF());
5214 gfx::Size layer_size(50, 50);
5215 content_layer->SetBounds(layer_size);
5216 content_layer->SetContentBounds(layer_size);
5217 content_layer->SetPosition(gfx::PointF());
5218 content_layer->SetAnchorPoint(gfx::PointF());
5219 content_layer->SetDrawsContent(true);
5221 gfx::Size child_size(50, 50);
5222 content_child_layer->SetBounds(child_size);
5223 content_child_layer->SetContentBounds(child_size);
5224 content_child_layer->SetPosition(gfx::Point(50, 0));
5225 content_child_layer->SetAnchorPoint(gfx::PointF());
5226 content_child_layer->SetDrawsContent(true);
5228 gfx::Size mask_size(50, 50);
5229 mask_layer->SetBounds(mask_size);
5230 mask_layer->SetContentBounds(mask_size);
5231 mask_layer->SetPosition(gfx::PointF());
5232 mask_layer->SetAnchorPoint(gfx::PointF());
5233 mask_layer->SetDrawsContent(true);
5235 float device_scale_factor = 1.f;
5236 host_impl_->SetViewportSize(root_size);
5237 host_impl_->SetDeviceScaleFactor(device_scale_factor);
5239 LayerTreeHostImpl::FrameData frame;
5240 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
5242 ASSERT_EQ(1u, frame.render_passes.size());
5243 ASSERT_EQ(2u, frame.render_passes[0]->quad_list.size());
5245 // The surface is 100x50.
5246 ASSERT_EQ(DrawQuad::RENDER_PASS,
5247 frame.render_passes[0]->quad_list[0]->material);
5248 const RenderPassDrawQuad* render_pass_quad =
5249 RenderPassDrawQuad::MaterialCast(frame.render_passes[0]->quad_list[0]);
5250 EXPECT_FALSE(render_pass_quad->is_replica);
5251 EXPECT_EQ(gfx::Rect(0, 0, 100, 50).ToString(),
5252 render_pass_quad->rect.ToString());
5254 // The mask covers the owning layer only.
5255 ASSERT_EQ(DrawQuad::RENDER_PASS,
5256 frame.render_passes[0]->quad_list[1]->material);
5257 const RenderPassDrawQuad* replica_quad =
5258 RenderPassDrawQuad::MaterialCast(frame.render_passes[0]->quad_list[1]);
5259 EXPECT_TRUE(replica_quad->is_replica);
5260 EXPECT_EQ(gfx::Rect(0, 0, 100, 50).ToString(),
5261 replica_quad->rect.ToString());
5262 EXPECT_EQ(gfx::RectF(0.f, 0.f, 2.f, 1.f).ToString(),
5263 replica_quad->mask_uv_rect.ToString());
5265 host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
5266 host_impl_->DidDrawAllLayers(frame);
5269 // Move the child to (-50, 0) instead. Now the mask should be moved to still
5270 // cover the layer being replicated.
5271 content_child_layer->SetPosition(gfx::Point(-50, 0));
5273 LayerTreeHostImpl::FrameData frame;
5274 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
5276 ASSERT_EQ(1u, frame.render_passes.size());
5277 ASSERT_EQ(2u, frame.render_passes[0]->quad_list.size());
5279 // The surface is 100x50 with its origin at (-50, 0).
5280 ASSERT_EQ(DrawQuad::RENDER_PASS,
5281 frame.render_passes[0]->quad_list[0]->material);
5282 const RenderPassDrawQuad* render_pass_quad =
5283 RenderPassDrawQuad::MaterialCast(frame.render_passes[0]->quad_list[0]);
5284 EXPECT_FALSE(render_pass_quad->is_replica);
5285 EXPECT_EQ(gfx::Rect(-50, 0, 100, 50).ToString(),
5286 render_pass_quad->rect.ToString());
5288 // The mask covers the owning layer only.
5289 ASSERT_EQ(DrawQuad::RENDER_PASS,
5290 frame.render_passes[0]->quad_list[1]->material);
5291 const RenderPassDrawQuad* replica_quad =
5292 RenderPassDrawQuad::MaterialCast(frame.render_passes[0]->quad_list[1]);
5293 EXPECT_TRUE(replica_quad->is_replica);
5294 EXPECT_EQ(gfx::Rect(-50, 0, 100, 50).ToString(),
5295 replica_quad->rect.ToString());
5296 EXPECT_EQ(gfx::RectF(-1.f, 0.f, 2.f, 1.f).ToString(),
5297 replica_quad->mask_uv_rect.ToString());
5299 host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
5300 host_impl_->DidDrawAllLayers(frame);
5304 TEST_F(LayerTreeHostImplTest, MaskLayerForSurfaceWithClippedLayer) {
5305 // The masked layer has bounds 50x50, but it has a child that causes
5306 // the surface bounds to be larger. It also has a parent that clips the
5307 // masked layer and its surface.
5309 scoped_ptr<LayerImpl> scoped_root =
5310 LayerImpl::Create(host_impl_->active_tree(), 1);
5311 LayerImpl* root = scoped_root.get();
5312 host_impl_->active_tree()->SetRootLayer(scoped_root.Pass());
5314 scoped_ptr<LayerImpl> scoped_clipping_layer =
5315 LayerImpl::Create(host_impl_->active_tree(), 2);
5316 LayerImpl* clipping_layer = scoped_clipping_layer.get();
5317 root->AddChild(scoped_clipping_layer.Pass());
5319 scoped_ptr<LayerImpl> scoped_content_layer =
5320 LayerImpl::Create(host_impl_->active_tree(), 3);
5321 LayerImpl* content_layer = scoped_content_layer.get();
5322 clipping_layer->AddChild(scoped_content_layer.Pass());
5324 scoped_ptr<LayerImpl> scoped_content_child_layer =
5325 LayerImpl::Create(host_impl_->active_tree(), 4);
5326 LayerImpl* content_child_layer = scoped_content_child_layer.get();
5327 content_layer->AddChild(scoped_content_child_layer.Pass());
5329 scoped_ptr<FakeMaskLayerImpl> scoped_mask_layer =
5330 FakeMaskLayerImpl::Create(host_impl_->active_tree(), 6);
5331 FakeMaskLayerImpl* mask_layer = scoped_mask_layer.get();
5332 content_layer->SetMaskLayer(scoped_mask_layer.PassAs<LayerImpl>());
5334 gfx::Size root_size(100, 100);
5335 root->SetBounds(root_size);
5336 root->SetContentBounds(root_size);
5337 root->SetPosition(gfx::PointF());
5338 root->SetAnchorPoint(gfx::PointF());
5340 gfx::Rect clipping_rect(20, 10, 10, 20);
5341 clipping_layer->SetBounds(clipping_rect.size());
5342 clipping_layer->SetContentBounds(clipping_rect.size());
5343 clipping_layer->SetPosition(clipping_rect.origin());
5344 clipping_layer->SetAnchorPoint(gfx::PointF());
5345 clipping_layer->SetMasksToBounds(true);
5347 gfx::Size layer_size(50, 50);
5348 content_layer->SetBounds(layer_size);
5349 content_layer->SetContentBounds(layer_size);
5350 content_layer->SetPosition(gfx::Point() - clipping_rect.OffsetFromOrigin());
5351 content_layer->SetAnchorPoint(gfx::PointF());
5352 content_layer->SetDrawsContent(true);
5354 gfx::Size child_size(50, 50);
5355 content_child_layer->SetBounds(child_size);
5356 content_child_layer->SetContentBounds(child_size);
5357 content_child_layer->SetPosition(gfx::Point(50, 0));
5358 content_child_layer->SetAnchorPoint(gfx::PointF());
5359 content_child_layer->SetDrawsContent(true);
5361 gfx::Size mask_size(100, 100);
5362 mask_layer->SetBounds(mask_size);
5363 mask_layer->SetContentBounds(mask_size);
5364 mask_layer->SetPosition(gfx::PointF());
5365 mask_layer->SetAnchorPoint(gfx::PointF());
5366 mask_layer->SetDrawsContent(true);
5368 float device_scale_factor = 1.f;
5369 host_impl_->SetViewportSize(root_size);
5370 host_impl_->SetDeviceScaleFactor(device_scale_factor);
5372 LayerTreeHostImpl::FrameData frame;
5373 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
5375 ASSERT_EQ(1u, frame.render_passes.size());
5376 ASSERT_EQ(1u, frame.render_passes[0]->quad_list.size());
5378 // The surface is clipped to 10x20.
5379 ASSERT_EQ(DrawQuad::RENDER_PASS,
5380 frame.render_passes[0]->quad_list[0]->material);
5381 const RenderPassDrawQuad* render_pass_quad =
5382 RenderPassDrawQuad::MaterialCast(frame.render_passes[0]->quad_list[0]);
5383 EXPECT_FALSE(render_pass_quad->is_replica);
5384 EXPECT_EQ(gfx::Rect(20, 10, 10, 20).ToString(),
5385 render_pass_quad->rect.ToString());
5387 // The masked layer is 50x50, but the surface size is 10x20. So the texture
5388 // coords in the mask are scaled by 10/50 and 20/50.
5389 // The surface is clipped to (20,10) so the mask texture coords are offset
5390 // by 20/50 and 10/50
5391 EXPECT_EQ(gfx::ScaleRect(gfx::RectF(20.f, 10.f, 10.f, 20.f),
5392 1.f / 50.f).ToString(),
5393 render_pass_quad->mask_uv_rect.ToString());
5395 host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
5396 host_impl_->DidDrawAllLayers(frame);
5400 class CompositorFrameMetadataTest : public LayerTreeHostImplTest {
5401 public:
5402 CompositorFrameMetadataTest()
5403 : swap_buffers_complete_(0) {}
5405 virtual void OverrideSettings(LayerTreeSettings* settings) OVERRIDE {
5406 settings->compositor_frame_message = true;
5408 virtual void OnSwapBuffersCompleteOnImplThread() OVERRIDE {
5409 swap_buffers_complete_++;
5412 int swap_buffers_complete_;
5415 TEST_F(CompositorFrameMetadataTest, CompositorFrameAckCountsAsSwapComplete) {
5416 SetupRootLayerImpl(FakeLayerWithQuads::Create(host_impl_->active_tree(), 1));
5418 LayerTreeHostImpl::FrameData frame;
5419 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
5420 host_impl_->DrawLayers(&frame, base::TimeTicks());
5421 host_impl_->DidDrawAllLayers(frame);
5423 CompositorFrameAck ack;
5424 host_impl_->OnSendFrameToParentCompositorAck(ack);
5425 EXPECT_EQ(swap_buffers_complete_, 1);
5428 } // namespace
5429 } // namespace cc