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/layer_tree_host_impl.h"
10 #include "base/command_line.h"
11 #include "base/hash_tables.h"
12 #include "cc/delegated_renderer_layer_impl.h"
13 #include "cc/gl_renderer.h"
14 #include "cc/heads_up_display_layer_impl.h"
15 #include "cc/io_surface_layer_impl.h"
16 #include "cc/layer_impl.h"
17 #include "cc/layer_tiling_data.h"
18 #include "cc/math_util.h"
19 #include "cc/quad_sink.h"
20 #include "cc/render_pass_draw_quad.h"
21 #include "cc/scrollbar_geometry_fixed_thumb.h"
22 #include "cc/scrollbar_layer_impl.h"
23 #include "cc/single_thread_proxy.h"
24 #include "cc/solid_color_draw_quad.h"
25 #include "cc/test/animation_test_common.h"
26 #include "cc/test/fake_proxy.h"
27 #include "cc/test/fake_web_compositor_output_surface.h"
28 #include "cc/test/fake_web_graphics_context_3d.h"
29 #include "cc/test/fake_web_scrollbar_theme_geometry.h"
30 #include "cc/test/geometry_test_utils.h"
31 #include "cc/test/layer_test_common.h"
32 #include "cc/test/render_pass_test_common.h"
33 #include "cc/texture_draw_quad.h"
34 #include "cc/texture_layer_impl.h"
35 #include "cc/tile_draw_quad.h"
36 #include "cc/tiled_layer_impl.h"
37 #include "cc/video_layer_impl.h"
38 #include "media/base/media.h"
39 #include "media/base/video_frame.h"
40 #include "testing/gmock/include/gmock/gmock.h"
41 #include "testing/gtest/include/gtest/gtest.h"
42 #include "ui/gfx/size_conversions.h"
43 #include "ui/gfx/vector2d_conversions.h"
44 #include <public/WebVideoFrame.h>
45 #include <public/WebVideoFrameProvider.h>
47 using namespace LayerTestCommon
;
48 using namespace WebKit
;
49 using namespace WebKitTests
;
51 using media::VideoFrame
;
52 using ::testing::Mock
;
53 using ::testing::Return
;
54 using ::testing::AnyNumber
;
55 using ::testing::AtLeast
;
61 // This test is parametrized to run all tests with the
62 // m_settings.pageScalePinchZoomEnabled field enabled and disabled.
63 class LayerTreeHostImplTest
: public testing::TestWithParam
<bool>,
64 public LayerTreeHostImplClient
{
66 LayerTreeHostImplTest()
67 : m_proxy(scoped_ptr
<Thread
>(NULL
))
68 , m_alwaysImplThread(&m_proxy
)
69 , m_alwaysMainThreadBlocked(&m_proxy
)
70 , m_onCanDrawStateChangedCalled(false)
71 , m_didRequestCommit(false)
72 , m_didRequestRedraw(false)
73 , m_reduceMemoryResult(true)
75 media::InitializeMediaLibraryForTesting();
80 LayerTreeSettings settings
;
81 settings
.minimumOcclusionTrackingSize
= gfx::Size();
82 settings
.pageScalePinchZoomEnabled
= GetParam();
84 m_hostImpl
= LayerTreeHostImpl::create(settings
, this, &m_proxy
);
85 m_hostImpl
->initializeRenderer(createContext());
86 m_hostImpl
->setViewportSize(gfx::Size(10, 10), gfx::Size(10, 10));
89 virtual void TearDown()
93 virtual void didLoseContextOnImplThread() OVERRIDE
{ }
94 virtual void onSwapBuffersCompleteOnImplThread() OVERRIDE
{ }
95 virtual void onVSyncParametersChanged(base::TimeTicks
, base::TimeDelta
) OVERRIDE
{ }
96 virtual void onCanDrawStateChanged(bool canDraw
) OVERRIDE
{ m_onCanDrawStateChangedCalled
= true; }
97 virtual void setNeedsRedrawOnImplThread() OVERRIDE
{ m_didRequestRedraw
= true; }
98 virtual void setNeedsCommitOnImplThread() OVERRIDE
{ m_didRequestCommit
= true; }
99 virtual void setNeedsManageTilesOnImplThread() OVERRIDE
{ }
100 virtual void postAnimationEventsToMainThreadOnImplThread(scoped_ptr
<AnimationEventsVector
>, base::Time wallClockTime
) OVERRIDE
{ }
101 virtual bool reduceContentsTextureMemoryOnImplThread(size_t limitBytes
, int priorityCutoff
) OVERRIDE
{ return m_reduceMemoryResult
; }
102 virtual void sendManagedMemoryStats() OVERRIDE
{ }
104 void setReduceMemoryResult(bool reduceMemoryResult
) { m_reduceMemoryResult
= reduceMemoryResult
; }
106 scoped_ptr
<LayerTreeHostImpl
> createLayerTreeHost(bool partialSwap
, scoped_ptr
<GraphicsContext
> graphicsContext
, scoped_ptr
<LayerImpl
> root
)
108 LayerTreeSettings settings
;
109 settings
.minimumOcclusionTrackingSize
= gfx::Size();
110 settings
.partialSwapEnabled
= partialSwap
;
112 scoped_ptr
<LayerTreeHostImpl
> myHostImpl
= LayerTreeHostImpl::create(settings
, this, &m_proxy
);
114 myHostImpl
->initializeRenderer(graphicsContext
.Pass());
115 myHostImpl
->setViewportSize(gfx::Size(10, 10), gfx::Size(10, 10));
117 root
->setAnchorPoint(gfx::PointF(0, 0));
118 root
->setPosition(gfx::PointF(0, 0));
119 root
->setBounds(gfx::Size(10, 10));
120 root
->setContentBounds(gfx::Size(10, 10));
121 root
->setVisibleContentRect(gfx::Rect(0, 0, 10, 10));
122 root
->setDrawsContent(true);
123 myHostImpl
->setRootLayer(root
.Pass());
124 return myHostImpl
.Pass();
127 static void expectClearedScrollDeltasRecursive(LayerImpl
* layer
)
129 ASSERT_EQ(layer
->scrollDelta(), gfx::Vector2d());
130 for (size_t i
= 0; i
< layer
->children().size(); ++i
)
131 expectClearedScrollDeltasRecursive(layer
->children()[i
]);
134 static void expectContains(const ScrollAndScaleSet
& scrollInfo
, int id
, const gfx::Vector2d
& scrollDelta
)
136 int timesEncountered
= 0;
138 for (size_t i
= 0; i
< scrollInfo
.scrolls
.size(); ++i
) {
139 if (scrollInfo
.scrolls
[i
].layerId
!= id
)
141 EXPECT_VECTOR_EQ(scrollDelta
, scrollInfo
.scrolls
[i
].scrollDelta
);
145 ASSERT_EQ(timesEncountered
, 1);
148 static void expectNone(const ScrollAndScaleSet
& scrollInfo
, int id
)
150 int timesEncountered
= 0;
152 for (size_t i
= 0; i
< scrollInfo
.scrolls
.size(); ++i
) {
153 if (scrollInfo
.scrolls
[i
].layerId
!= id
)
158 ASSERT_EQ(0, timesEncountered
);
161 void setupScrollAndContentsLayers(const gfx::Size
& contentSize
)
163 scoped_ptr
<LayerImpl
> root
= LayerImpl::create(1);
164 root
->setScrollable(true);
165 root
->setScrollOffset(gfx::Vector2d(0, 0));
166 root
->setMaxScrollOffset(gfx::Vector2d(contentSize
.width(), contentSize
.height()));
167 root
->setBounds(contentSize
);
168 root
->setContentBounds(contentSize
);
169 root
->setPosition(gfx::PointF(0, 0));
170 root
->setAnchorPoint(gfx::PointF(0, 0));
172 scoped_ptr
<LayerImpl
> contents
= LayerImpl::create(2);
173 contents
->setDrawsContent(true);
174 contents
->setBounds(contentSize
);
175 contents
->setContentBounds(contentSize
);
176 contents
->setPosition(gfx::PointF(0, 0));
177 contents
->setAnchorPoint(gfx::PointF(0, 0));
178 root
->addChild(contents
.Pass());
179 m_hostImpl
->setRootLayer(root
.Pass());
182 static scoped_ptr
<LayerImpl
> createScrollableLayer(int id
, const gfx::Size
& size
)
184 scoped_ptr
<LayerImpl
> layer
= LayerImpl::create(id
);
185 layer
->setScrollable(true);
186 layer
->setDrawsContent(true);
187 layer
->setBounds(size
);
188 layer
->setContentBounds(size
);
189 layer
->setMaxScrollOffset(gfx::Vector2d(size
.width() * 2, size
.height() * 2));
193 void initializeRendererAndDrawFrame()
195 m_hostImpl
->initializeRenderer(createContext());
196 LayerTreeHostImpl::FrameData frame
;
197 EXPECT_TRUE(m_hostImpl
->prepareToDraw(frame
));
198 m_hostImpl
->drawLayers(frame
);
199 m_hostImpl
->didDrawAllLayers(frame
);
202 void pinchZoomPanViewportForcesCommitRedraw(const float deviceScaleFactor
);
203 void pinchZoomPanViewportTest(const float deviceScaleFactor
);
204 void pinchZoomPanViewportAndScrollTest(const float deviceScaleFactor
);
205 void pinchZoomPanViewportAndScrollBoundaryTest(const float deviceScaleFactor
);
208 scoped_ptr
<GraphicsContext
> createContext()
210 return FakeWebCompositorOutputSurface::create(scoped_ptr
<WebKit::WebGraphicsContext3D
>(new FakeWebGraphicsContext3D
)).PassAs
<GraphicsContext
>();
214 DebugScopedSetImplThread m_alwaysImplThread
;
215 DebugScopedSetMainThreadBlocked m_alwaysMainThreadBlocked
;
217 scoped_ptr
<LayerTreeHostImpl
> m_hostImpl
;
218 bool m_onCanDrawStateChangedCalled
;
219 bool m_didRequestCommit
;
220 bool m_didRequestRedraw
;
221 bool m_reduceMemoryResult
;
224 class FakeWebGraphicsContext3DMakeCurrentFails
: public FakeWebGraphicsContext3D
{
226 virtual bool makeContextCurrent() { return false; }
229 TEST_P(LayerTreeHostImplTest
, notifyIfCanDrawChanged
)
231 // Note: It is not possible to disable the renderer once it has been set,
232 // so we do not need to test that disabling the renderer notifies us
233 // that canDraw changed.
234 EXPECT_FALSE(m_hostImpl
->canDraw());
235 m_onCanDrawStateChangedCalled
= false;
237 setupScrollAndContentsLayers(gfx::Size(100, 100));
238 EXPECT_TRUE(m_hostImpl
->canDraw());
239 EXPECT_TRUE(m_onCanDrawStateChangedCalled
);
240 m_onCanDrawStateChangedCalled
= false;
242 // Toggle the root layer to make sure it toggles canDraw
243 m_hostImpl
->setRootLayer(scoped_ptr
<LayerImpl
>());
244 EXPECT_FALSE(m_hostImpl
->canDraw());
245 EXPECT_TRUE(m_onCanDrawStateChangedCalled
);
246 m_onCanDrawStateChangedCalled
= false;
248 setupScrollAndContentsLayers(gfx::Size(100, 100));
249 EXPECT_TRUE(m_hostImpl
->canDraw());
250 EXPECT_TRUE(m_onCanDrawStateChangedCalled
);
251 m_onCanDrawStateChangedCalled
= false;
253 // Toggle the device viewport size to make sure it toggles canDraw.
254 m_hostImpl
->setViewportSize(gfx::Size(100, 100), gfx::Size(0, 0));
255 EXPECT_FALSE(m_hostImpl
->canDraw());
256 EXPECT_TRUE(m_onCanDrawStateChangedCalled
);
257 m_onCanDrawStateChangedCalled
= false;
259 m_hostImpl
->setViewportSize(gfx::Size(100, 100), gfx::Size(100, 100));
260 EXPECT_TRUE(m_hostImpl
->canDraw());
261 EXPECT_TRUE(m_onCanDrawStateChangedCalled
);
262 m_onCanDrawStateChangedCalled
= false;
264 // Toggle contents textures purged without causing any evictions,
265 // and make sure that it does not change canDraw.
266 setReduceMemoryResult(false);
267 m_hostImpl
->setManagedMemoryPolicy(ManagedMemoryPolicy(
268 m_hostImpl
->memoryAllocationLimitBytes() - 1));
269 EXPECT_TRUE(m_hostImpl
->canDraw());
270 EXPECT_FALSE(m_onCanDrawStateChangedCalled
);
271 m_onCanDrawStateChangedCalled
= false;
273 // Toggle contents textures purged to make sure it toggles canDraw.
274 setReduceMemoryResult(true);
275 m_hostImpl
->setManagedMemoryPolicy(ManagedMemoryPolicy(
276 m_hostImpl
->memoryAllocationLimitBytes() - 1));
277 EXPECT_FALSE(m_hostImpl
->canDraw());
278 EXPECT_TRUE(m_onCanDrawStateChangedCalled
);
279 m_onCanDrawStateChangedCalled
= false;
281 m_hostImpl
->resetContentsTexturesPurged();
282 EXPECT_TRUE(m_hostImpl
->canDraw());
283 EXPECT_TRUE(m_onCanDrawStateChangedCalled
);
284 m_onCanDrawStateChangedCalled
= false;
287 TEST_P(LayerTreeHostImplTest
, scrollDeltaNoLayers
)
289 ASSERT_FALSE(m_hostImpl
->rootLayer());
291 scoped_ptr
<ScrollAndScaleSet
> scrollInfo
= m_hostImpl
->processScrollDeltas();
292 ASSERT_EQ(scrollInfo
->scrolls
.size(), 0u);
295 TEST_P(LayerTreeHostImplTest
, scrollDeltaTreeButNoChanges
)
298 scoped_ptr
<LayerImpl
> root
= LayerImpl::create(1);
299 root
->addChild(LayerImpl::create(2));
300 root
->addChild(LayerImpl::create(3));
301 root
->children()[1]->addChild(LayerImpl::create(4));
302 root
->children()[1]->addChild(LayerImpl::create(5));
303 root
->children()[1]->children()[0]->addChild(LayerImpl::create(6));
304 m_hostImpl
->setRootLayer(root
.Pass());
306 LayerImpl
* root
= m_hostImpl
->rootLayer();
308 expectClearedScrollDeltasRecursive(root
);
310 scoped_ptr
<ScrollAndScaleSet
> scrollInfo
;
312 scrollInfo
= m_hostImpl
->processScrollDeltas();
313 ASSERT_EQ(scrollInfo
->scrolls
.size(), 0u);
314 expectClearedScrollDeltasRecursive(root
);
316 scrollInfo
= m_hostImpl
->processScrollDeltas();
317 ASSERT_EQ(scrollInfo
->scrolls
.size(), 0u);
318 expectClearedScrollDeltasRecursive(root
);
321 TEST_P(LayerTreeHostImplTest
, scrollDeltaRepeatedScrolls
)
323 gfx::Vector2d
scrollOffset(20, 30);
324 gfx::Vector2d
scrollDelta(11, -15);
326 scoped_ptr
<LayerImpl
> root
= LayerImpl::create(1);
327 root
->setScrollOffset(scrollOffset
);
328 root
->setScrollable(true);
329 root
->setMaxScrollOffset(gfx::Vector2d(100, 100));
330 root
->scrollBy(scrollDelta
);
331 m_hostImpl
->setRootLayer(root
.Pass());
333 LayerImpl
* root
= m_hostImpl
->rootLayer();
335 scoped_ptr
<ScrollAndScaleSet
> scrollInfo
;
337 scrollInfo
= m_hostImpl
->processScrollDeltas();
338 ASSERT_EQ(scrollInfo
->scrolls
.size(), 1u);
339 EXPECT_VECTOR_EQ(root
->sentScrollDelta(), scrollDelta
);
340 expectContains(*scrollInfo
, root
->id(), scrollDelta
);
342 gfx::Vector2d
scrollDelta2(-5, 27);
343 root
->scrollBy(scrollDelta2
);
344 scrollInfo
= m_hostImpl
->processScrollDeltas();
345 ASSERT_EQ(scrollInfo
->scrolls
.size(), 1u);
346 EXPECT_VECTOR_EQ(root
->sentScrollDelta(), scrollDelta
+ scrollDelta2
);
347 expectContains(*scrollInfo
, root
->id(), scrollDelta
+ scrollDelta2
);
349 root
->scrollBy(gfx::Vector2d());
350 scrollInfo
= m_hostImpl
->processScrollDeltas();
351 EXPECT_EQ(root
->sentScrollDelta(), scrollDelta
+ scrollDelta2
);
354 TEST_P(LayerTreeHostImplTest
, scrollRootCallsCommitAndRedraw
)
356 setupScrollAndContentsLayers(gfx::Size(100, 100));
357 m_hostImpl
->setViewportSize(gfx::Size(50, 50), gfx::Size(50, 50));
358 initializeRendererAndDrawFrame();
360 EXPECT_EQ(m_hostImpl
->scrollBegin(gfx::Point(0, 0), InputHandlerClient::Wheel
), InputHandlerClient::ScrollStarted
);
361 m_hostImpl
->scrollBy(gfx::Point(), gfx::Vector2d(0, 10));
362 m_hostImpl
->scrollEnd();
363 EXPECT_TRUE(m_didRequestRedraw
);
364 EXPECT_TRUE(m_didRequestCommit
);
367 TEST_P(LayerTreeHostImplTest
, scrollWithoutRootLayer
)
369 // We should not crash when trying to scroll an empty layer tree.
370 EXPECT_EQ(m_hostImpl
->scrollBegin(gfx::Point(0, 0), InputHandlerClient::Wheel
), InputHandlerClient::ScrollIgnored
);
373 TEST_P(LayerTreeHostImplTest
, scrollWithoutRenderer
)
375 LayerTreeSettings settings
;
376 m_hostImpl
= LayerTreeHostImpl::create(settings
, this, &m_proxy
);
378 // Initialization will fail here.
379 m_hostImpl
->initializeRenderer(FakeWebCompositorOutputSurface::create(scoped_ptr
<WebKit::WebGraphicsContext3D
>(new FakeWebGraphicsContext3DMakeCurrentFails
)).PassAs
<GraphicsContext
>());
380 m_hostImpl
->setViewportSize(gfx::Size(10, 10), gfx::Size(10, 10));
382 setupScrollAndContentsLayers(gfx::Size(100, 100));
384 // We should not crash when trying to scroll after the renderer initialization fails.
385 EXPECT_EQ(m_hostImpl
->scrollBegin(gfx::Point(0, 0), InputHandlerClient::Wheel
), InputHandlerClient::ScrollIgnored
);
388 TEST_P(LayerTreeHostImplTest
, replaceTreeWhileScrolling
)
390 const int scrollLayerId
= 1;
392 setupScrollAndContentsLayers(gfx::Size(100, 100));
393 m_hostImpl
->setViewportSize(gfx::Size(50, 50), gfx::Size(50, 50));
394 initializeRendererAndDrawFrame();
396 // We should not crash if the tree is replaced while we are scrolling.
397 EXPECT_EQ(m_hostImpl
->scrollBegin(gfx::Point(0, 0), InputHandlerClient::Wheel
), InputHandlerClient::ScrollStarted
);
398 m_hostImpl
->detachLayerTree();
400 setupScrollAndContentsLayers(gfx::Size(100, 100));
402 // We should still be scrolling, because the scrolled layer also exists in the new tree.
403 gfx::Vector2d
scrollDelta(0, 10);
404 m_hostImpl
->scrollBy(gfx::Point(), scrollDelta
);
405 m_hostImpl
->scrollEnd();
406 scoped_ptr
<ScrollAndScaleSet
> scrollInfo
= m_hostImpl
->processScrollDeltas();
407 expectContains(*scrollInfo
, scrollLayerId
, scrollDelta
);
410 TEST_P(LayerTreeHostImplTest
, clearRootRenderSurfaceAndScroll
)
412 setupScrollAndContentsLayers(gfx::Size(100, 100));
413 m_hostImpl
->setViewportSize(gfx::Size(50, 50), gfx::Size(50, 50));
414 initializeRendererAndDrawFrame();
416 // We should be able to scroll even if the root layer loses its render surface after the most
418 m_hostImpl
->rootLayer()->clearRenderSurface();
419 EXPECT_EQ(m_hostImpl
->scrollBegin(gfx::Point(0, 0), InputHandlerClient::Wheel
), InputHandlerClient::ScrollStarted
);
422 TEST_P(LayerTreeHostImplTest
, wheelEventHandlers
)
424 setupScrollAndContentsLayers(gfx::Size(100, 100));
425 m_hostImpl
->setViewportSize(gfx::Size(50, 50), gfx::Size(50, 50));
426 initializeRendererAndDrawFrame();
427 LayerImpl
* root
= m_hostImpl
->rootLayer();
429 root
->setHaveWheelEventHandlers(true);
431 // With registered event handlers, wheel scrolls have to go to the main thread.
432 EXPECT_EQ(m_hostImpl
->scrollBegin(gfx::Point(0, 0), InputHandlerClient::Wheel
), InputHandlerClient::ScrollOnMainThread
);
434 // But gesture scrolls can still be handled.
435 EXPECT_EQ(m_hostImpl
->scrollBegin(gfx::Point(0, 0), InputHandlerClient::Gesture
), InputHandlerClient::ScrollStarted
);
438 TEST_P(LayerTreeHostImplTest
, shouldScrollOnMainThread
)
440 setupScrollAndContentsLayers(gfx::Size(100, 100));
441 m_hostImpl
->setViewportSize(gfx::Size(50, 50), gfx::Size(50, 50));
442 initializeRendererAndDrawFrame();
443 LayerImpl
* root
= m_hostImpl
->rootLayer();
445 root
->setShouldScrollOnMainThread(true);
447 EXPECT_EQ(m_hostImpl
->scrollBegin(gfx::Point(0, 0), InputHandlerClient::Wheel
), InputHandlerClient::ScrollOnMainThread
);
448 EXPECT_EQ(m_hostImpl
->scrollBegin(gfx::Point(0, 0), InputHandlerClient::Gesture
), InputHandlerClient::ScrollOnMainThread
);
451 TEST_P(LayerTreeHostImplTest
, nonFastScrollableRegionBasic
)
453 setupScrollAndContentsLayers(gfx::Size(200, 200));
454 m_hostImpl
->setViewportSize(gfx::Size(100, 100), gfx::Size(100, 100));
456 LayerImpl
* root
= m_hostImpl
->rootLayer();
457 root
->setContentsScale(2, 2);
458 root
->setNonFastScrollableRegion(gfx::Rect(0, 0, 50, 50));
460 initializeRendererAndDrawFrame();
462 // All scroll types inside the non-fast scrollable region should fail.
463 EXPECT_EQ(m_hostImpl
->scrollBegin(gfx::Point(25, 25), InputHandlerClient::Wheel
), InputHandlerClient::ScrollOnMainThread
);
464 EXPECT_EQ(m_hostImpl
->scrollBegin(gfx::Point(25, 25), InputHandlerClient::Gesture
), InputHandlerClient::ScrollOnMainThread
);
466 // All scroll types outside this region should succeed.
467 EXPECT_EQ(m_hostImpl
->scrollBegin(gfx::Point(75, 75), InputHandlerClient::Wheel
), InputHandlerClient::ScrollStarted
);
468 m_hostImpl
->scrollBy(gfx::Point(), gfx::Vector2d(0, 10));
469 m_hostImpl
->scrollEnd();
470 EXPECT_EQ(m_hostImpl
->scrollBegin(gfx::Point(75, 75), InputHandlerClient::Gesture
), InputHandlerClient::ScrollStarted
);
471 m_hostImpl
->scrollBy(gfx::Point(), gfx::Vector2d(0, 10));
472 m_hostImpl
->scrollEnd();
475 TEST_P(LayerTreeHostImplTest
, nonFastScrollableRegionWithOffset
)
477 setupScrollAndContentsLayers(gfx::Size(200, 200));
478 m_hostImpl
->setViewportSize(gfx::Size(100, 100), gfx::Size(100, 100));
480 LayerImpl
* root
= m_hostImpl
->rootLayer();
481 root
->setContentsScale(2, 2);
482 root
->setNonFastScrollableRegion(gfx::Rect(0, 0, 50, 50));
483 root
->setPosition(gfx::PointF(-25, 0));
485 initializeRendererAndDrawFrame();
487 // This point would fall into the non-fast scrollable region except that we've moved the layer down by 25 pixels.
488 EXPECT_EQ(m_hostImpl
->scrollBegin(gfx::Point(40, 10), InputHandlerClient::Wheel
), InputHandlerClient::ScrollStarted
);
489 m_hostImpl
->scrollBy(gfx::Point(), gfx::Vector2d(0, 1));
490 m_hostImpl
->scrollEnd();
492 // This point is still inside the non-fast region.
493 EXPECT_EQ(m_hostImpl
->scrollBegin(gfx::Point(10, 10), InputHandlerClient::Wheel
), InputHandlerClient::ScrollOnMainThread
);
496 TEST_P(LayerTreeHostImplTest
, scrollByReturnsCorrectValue
)
498 setupScrollAndContentsLayers(gfx::Size(200, 200));
499 m_hostImpl
->setViewportSize(gfx::Size(100, 100), gfx::Size(100, 100));
501 initializeRendererAndDrawFrame();
503 EXPECT_EQ(InputHandlerClient::ScrollStarted
,
504 m_hostImpl
->scrollBegin(gfx::Point(0, 0), InputHandlerClient::Gesture
));
506 // Trying to scroll to the left/top will not succeed.
507 EXPECT_FALSE(m_hostImpl
->scrollBy(gfx::Point(), gfx::Vector2d(-10, 0)));
508 EXPECT_FALSE(m_hostImpl
->scrollBy(gfx::Point(), gfx::Vector2d(0, -10)));
509 EXPECT_FALSE(m_hostImpl
->scrollBy(gfx::Point(), gfx::Vector2d(-10, -10)));
511 // Scrolling to the right/bottom will succeed.
512 EXPECT_TRUE(m_hostImpl
->scrollBy(gfx::Point(), gfx::Vector2d(10, 0)));
513 EXPECT_TRUE(m_hostImpl
->scrollBy(gfx::Point(), gfx::Vector2d(0, 10)));
514 EXPECT_TRUE(m_hostImpl
->scrollBy(gfx::Point(), gfx::Vector2d(10, 10)));
516 // Scrolling to left/top will now succeed.
517 EXPECT_TRUE(m_hostImpl
->scrollBy(gfx::Point(), gfx::Vector2d(-10, 0)));
518 EXPECT_TRUE(m_hostImpl
->scrollBy(gfx::Point(), gfx::Vector2d(0, -10)));
519 EXPECT_TRUE(m_hostImpl
->scrollBy(gfx::Point(), gfx::Vector2d(-10, -10)));
521 // Trying to scroll more than the available space will also succeed.
522 EXPECT_TRUE(m_hostImpl
->scrollBy(gfx::Point(), gfx::Vector2d(5000, 5000)));
525 TEST_P(LayerTreeHostImplTest
, maxScrollOffsetChangedByDeviceScaleFactor
)
527 setupScrollAndContentsLayers(gfx::Size(100, 100));
529 float deviceScaleFactor
= 2;
530 gfx::Size
layoutViewport(25, 25);
531 gfx::Size
deviceViewport(gfx::ToFlooredSize(gfx::ScaleSize(layoutViewport
, deviceScaleFactor
)));
532 m_hostImpl
->setViewportSize(layoutViewport
, deviceViewport
);
533 m_hostImpl
->setDeviceScaleFactor(deviceScaleFactor
);
534 EXPECT_EQ(m_hostImpl
->rootLayer()->maxScrollOffset(), gfx::Vector2d(25, 25));
536 deviceScaleFactor
= 1;
537 m_hostImpl
->setViewportSize(layoutViewport
, layoutViewport
);
538 m_hostImpl
->setDeviceScaleFactor(deviceScaleFactor
);
539 EXPECT_EQ(m_hostImpl
->rootLayer()->maxScrollOffset(), gfx::Vector2d(75, 75));
542 TEST_P(LayerTreeHostImplTest
, implPinchZoom
)
544 // This test is specific to the page-scale based pinch zoom.
545 if (!m_hostImpl
->settings().pageScalePinchZoomEnabled
)
548 setupScrollAndContentsLayers(gfx::Size(100, 100));
549 m_hostImpl
->setViewportSize(gfx::Size(50, 50), gfx::Size(50, 50));
550 initializeRendererAndDrawFrame();
552 LayerImpl
* scrollLayer
= m_hostImpl
->rootScrollLayer();
555 const float minPageScale
= 1, maxPageScale
= 4;
556 const gfx::Transform identityScaleTransform
;
558 // The impl-based pinch zoom should not adjust the max scroll position.
560 m_hostImpl
->setPageScaleFactorAndLimits(1, minPageScale
, maxPageScale
);
561 scrollLayer
->setImplTransform(identityScaleTransform
);
562 scrollLayer
->setScrollDelta(gfx::Vector2d());
564 float pageScaleDelta
= 2;
565 m_hostImpl
->pinchGestureBegin();
566 m_hostImpl
->pinchGestureUpdate(pageScaleDelta
, gfx::Point(50, 50));
567 m_hostImpl
->pinchGestureEnd();
568 EXPECT_TRUE(m_didRequestRedraw
);
569 EXPECT_TRUE(m_didRequestCommit
);
571 scoped_ptr
<ScrollAndScaleSet
> scrollInfo
= m_hostImpl
->processScrollDeltas();
572 EXPECT_EQ(scrollInfo
->pageScaleDelta
, pageScaleDelta
);
574 EXPECT_EQ(m_hostImpl
->rootLayer()->maxScrollOffset(), gfx::Vector2d(50, 50));
577 // Scrolling after a pinch gesture should always be in local space. The scroll deltas do not
578 // have the page scale factor applied.
580 m_hostImpl
->setPageScaleFactorAndLimits(1, minPageScale
, maxPageScale
);
581 scrollLayer
->setImplTransform(identityScaleTransform
);
582 scrollLayer
->setScrollDelta(gfx::Vector2d());
584 float pageScaleDelta
= 2;
585 m_hostImpl
->pinchGestureBegin();
586 m_hostImpl
->pinchGestureUpdate(pageScaleDelta
, gfx::Point(0, 0));
587 m_hostImpl
->pinchGestureEnd();
589 gfx::Vector2d
scrollDelta(0, 10);
590 EXPECT_EQ(m_hostImpl
->scrollBegin(gfx::Point(5, 5), InputHandlerClient::Wheel
), InputHandlerClient::ScrollStarted
);
591 m_hostImpl
->scrollBy(gfx::Point(), scrollDelta
);
592 m_hostImpl
->scrollEnd();
594 scoped_ptr
<ScrollAndScaleSet
> scrollInfo
= m_hostImpl
->processScrollDeltas();
595 expectContains(*scrollInfo
.get(), m_hostImpl
->rootLayer()->id(), scrollDelta
);
599 TEST_P(LayerTreeHostImplTest
, pinchGesture
)
601 setupScrollAndContentsLayers(gfx::Size(100, 100));
602 m_hostImpl
->setViewportSize(gfx::Size(50, 50), gfx::Size(50, 50));
603 initializeRendererAndDrawFrame();
605 LayerImpl
* scrollLayer
= m_hostImpl
->rootScrollLayer();
608 const float minPageScale
= m_hostImpl
->settings().pageScalePinchZoomEnabled
? 1 : 0.5;
609 const float maxPageScale
= 4;
610 const gfx::Transform identityScaleTransform
;
612 // Basic pinch zoom in gesture
614 m_hostImpl
->setPageScaleFactorAndLimits(1, minPageScale
, maxPageScale
);
615 scrollLayer
->setImplTransform(identityScaleTransform
);
616 scrollLayer
->setScrollDelta(gfx::Vector2d());
618 float pageScaleDelta
= 2;
619 m_hostImpl
->pinchGestureBegin();
620 m_hostImpl
->pinchGestureUpdate(pageScaleDelta
, gfx::Point(50, 50));
621 m_hostImpl
->pinchGestureEnd();
622 EXPECT_TRUE(m_didRequestRedraw
);
623 EXPECT_TRUE(m_didRequestCommit
);
625 scoped_ptr
<ScrollAndScaleSet
> scrollInfo
= m_hostImpl
->processScrollDeltas();
626 EXPECT_EQ(scrollInfo
->pageScaleDelta
, pageScaleDelta
);
631 m_hostImpl
->setPageScaleFactorAndLimits(1, minPageScale
, maxPageScale
);
632 scrollLayer
->setImplTransform(identityScaleTransform
);
633 scrollLayer
->setScrollDelta(gfx::Vector2d());
634 float pageScaleDelta
= 10;
636 m_hostImpl
->pinchGestureBegin();
637 m_hostImpl
->pinchGestureUpdate(pageScaleDelta
, gfx::Point(50, 50));
638 m_hostImpl
->pinchGestureEnd();
640 scoped_ptr
<ScrollAndScaleSet
> scrollInfo
= m_hostImpl
->processScrollDeltas();
641 EXPECT_EQ(scrollInfo
->pageScaleDelta
, maxPageScale
);
646 m_hostImpl
->setPageScaleFactorAndLimits(1, minPageScale
, maxPageScale
);
647 scrollLayer
->setImplTransform(identityScaleTransform
);
648 scrollLayer
->setScrollDelta(gfx::Vector2d());
649 scrollLayer
->setScrollOffset(gfx::Vector2d(50, 50));
651 float pageScaleDelta
= 0.1f
;
652 m_hostImpl
->pinchGestureBegin();
653 m_hostImpl
->pinchGestureUpdate(pageScaleDelta
, gfx::Point(0, 0));
654 m_hostImpl
->pinchGestureEnd();
656 scoped_ptr
<ScrollAndScaleSet
> scrollInfo
= m_hostImpl
->processScrollDeltas();
657 EXPECT_EQ(scrollInfo
->pageScaleDelta
, minPageScale
);
659 if (!m_hostImpl
->settings().pageScalePinchZoomEnabled
) {
660 // Pushed to (0,0) via clamping against contents layer size.
661 expectContains(*scrollInfo
, scrollLayer
->id(), gfx::Vector2d(-50, -50));
663 EXPECT_TRUE(scrollInfo
->scrolls
.empty());
667 // Two-finger panning should not happen based on pinch events only
669 m_hostImpl
->setPageScaleFactorAndLimits(1, minPageScale
, maxPageScale
);
670 scrollLayer
->setImplTransform(identityScaleTransform
);
671 scrollLayer
->setScrollDelta(gfx::Vector2d());
672 scrollLayer
->setScrollOffset(gfx::Vector2d(20, 20));
674 float pageScaleDelta
= 1;
675 m_hostImpl
->pinchGestureBegin();
676 m_hostImpl
->pinchGestureUpdate(pageScaleDelta
, gfx::Point(10, 10));
677 m_hostImpl
->pinchGestureUpdate(pageScaleDelta
, gfx::Point(20, 20));
678 m_hostImpl
->pinchGestureEnd();
680 scoped_ptr
<ScrollAndScaleSet
> scrollInfo
= m_hostImpl
->processScrollDeltas();
681 EXPECT_EQ(scrollInfo
->pageScaleDelta
, pageScaleDelta
);
682 EXPECT_TRUE(scrollInfo
->scrolls
.empty());
685 // Two-finger panning should work with interleaved scroll events
687 m_hostImpl
->setPageScaleFactorAndLimits(1, minPageScale
, maxPageScale
);
688 scrollLayer
->setImplTransform(identityScaleTransform
);
689 scrollLayer
->setScrollDelta(gfx::Vector2d());
690 scrollLayer
->setScrollOffset(gfx::Vector2d(20, 20));
692 float pageScaleDelta
= 1;
693 m_hostImpl
->scrollBegin(gfx::Point(10, 10), InputHandlerClient::Wheel
);
694 m_hostImpl
->pinchGestureBegin();
695 m_hostImpl
->pinchGestureUpdate(pageScaleDelta
, gfx::Point(10, 10));
696 m_hostImpl
->scrollBy(gfx::Point(10, 10), gfx::Vector2d(-10, -10));
697 m_hostImpl
->pinchGestureUpdate(pageScaleDelta
, gfx::Point(20, 20));
698 m_hostImpl
->pinchGestureEnd();
699 m_hostImpl
->scrollEnd();
701 scoped_ptr
<ScrollAndScaleSet
> scrollInfo
= m_hostImpl
->processScrollDeltas();
702 EXPECT_EQ(scrollInfo
->pageScaleDelta
, pageScaleDelta
);
703 expectContains(*scrollInfo
, scrollLayer
->id(), gfx::Vector2d(-10, -10));
707 TEST_P(LayerTreeHostImplTest
, pageScaleAnimation
)
709 setupScrollAndContentsLayers(gfx::Size(100, 100));
710 m_hostImpl
->setViewportSize(gfx::Size(50, 50), gfx::Size(50, 50));
711 initializeRendererAndDrawFrame();
713 LayerImpl
* scrollLayer
= m_hostImpl
->rootScrollLayer();
716 const float minPageScale
= 0.5;
717 const float maxPageScale
= 4;
718 const base::TimeTicks startTime
= base::TimeTicks() + base::TimeDelta::FromSeconds(1);
719 const base::TimeDelta duration
= base::TimeDelta::FromMilliseconds(100);
720 const base::TimeTicks halfwayThroughAnimation
= startTime
+ duration
/ 2;
721 const base::TimeTicks endTime
= startTime
+ duration
;
722 const gfx::Transform identityScaleTransform
;
724 // Non-anchor zoom-in
726 m_hostImpl
->setPageScaleFactorAndLimits(1, minPageScale
, maxPageScale
);
727 scrollLayer
->setImplTransform(identityScaleTransform
);
728 scrollLayer
->setScrollOffset(gfx::Vector2d(50, 50));
730 m_hostImpl
->startPageScaleAnimation(gfx::Vector2d(0, 0), false, 2, startTime
, duration
);
731 m_hostImpl
->animate(halfwayThroughAnimation
, base::Time());
732 EXPECT_TRUE(m_didRequestRedraw
);
733 m_hostImpl
->animate(endTime
, base::Time());
734 EXPECT_TRUE(m_didRequestCommit
);
736 scoped_ptr
<ScrollAndScaleSet
> scrollInfo
= m_hostImpl
->processScrollDeltas();
737 EXPECT_EQ(scrollInfo
->pageScaleDelta
, 2);
738 expectContains(*scrollInfo
, scrollLayer
->id(), gfx::Vector2d(-50, -50));
743 m_hostImpl
->setPageScaleFactorAndLimits(1, minPageScale
, maxPageScale
);
744 scrollLayer
->setImplTransform(identityScaleTransform
);
745 scrollLayer
->setScrollOffset(gfx::Vector2d(50, 50));
747 m_hostImpl
->startPageScaleAnimation(gfx::Vector2d(25, 25), true, minPageScale
, startTime
, duration
);
748 m_hostImpl
->animate(endTime
, base::Time());
749 EXPECT_TRUE(m_didRequestRedraw
);
750 EXPECT_TRUE(m_didRequestCommit
);
752 scoped_ptr
<ScrollAndScaleSet
> scrollInfo
= m_hostImpl
->processScrollDeltas();
753 EXPECT_EQ(scrollInfo
->pageScaleDelta
, minPageScale
);
754 // Pushed to (0,0) via clamping against contents layer size.
755 expectContains(*scrollInfo
, scrollLayer
->id(), gfx::Vector2d(-50, -50));
759 TEST_P(LayerTreeHostImplTest
, inhibitScrollAndPageScaleUpdatesWhilePinchZooming
)
761 setupScrollAndContentsLayers(gfx::Size(100, 100));
762 m_hostImpl
->setViewportSize(gfx::Size(50, 50), gfx::Size(50, 50));
763 initializeRendererAndDrawFrame();
765 LayerImpl
* scrollLayer
= m_hostImpl
->rootScrollLayer();
768 const float minPageScale
= m_hostImpl
->settings().pageScalePinchZoomEnabled
? 1 : 0.5;
769 const float maxPageScale
= 4;
773 // Start a pinch in gesture at the bottom right corner of the viewport.
774 const float zoomInDelta
= 2;
775 m_hostImpl
->setPageScaleFactorAndLimits(1, minPageScale
, maxPageScale
);
776 m_hostImpl
->pinchGestureBegin();
777 m_hostImpl
->pinchGestureUpdate(zoomInDelta
, gfx::Point(50, 50));
779 // Because we are pinch zooming in, we shouldn't get any scroll or page
781 scoped_ptr
<ScrollAndScaleSet
> scrollInfo
= m_hostImpl
->processScrollDeltas();
782 EXPECT_EQ(scrollInfo
->pageScaleDelta
, 1);
783 EXPECT_EQ(scrollInfo
->scrolls
.size(), 0u);
785 // Once the gesture ends, we get the final scroll and page scale values.
786 m_hostImpl
->pinchGestureEnd();
787 scrollInfo
= m_hostImpl
->processScrollDeltas();
788 EXPECT_EQ(scrollInfo
->pageScaleDelta
, zoomInDelta
);
789 if (!m_hostImpl
->settings().pageScalePinchZoomEnabled
) {
790 expectContains(*scrollInfo
, scrollLayer
->id(), gfx::Vector2d(25, 25));
792 EXPECT_TRUE(scrollInfo
->scrolls
.empty());
798 // Start a pinch out gesture at the bottom right corner of the viewport.
799 const float zoomOutDelta
= 0.75;
800 m_hostImpl
->setPageScaleFactorAndLimits(1, minPageScale
, maxPageScale
);
801 m_hostImpl
->pinchGestureBegin();
802 m_hostImpl
->pinchGestureUpdate(zoomOutDelta
, gfx::Point(50, 50));
804 // Since we are pinch zooming out, we should get an update to zoom all
805 // the way out to the minimum page scale.
806 scoped_ptr
<ScrollAndScaleSet
> scrollInfo
= m_hostImpl
->processScrollDeltas();
807 if (!m_hostImpl
->settings().pageScalePinchZoomEnabled
) {
808 EXPECT_EQ(scrollInfo
->pageScaleDelta
, minPageScale
);
809 expectContains(*scrollInfo
, scrollLayer
->id(), gfx::Vector2d(0, 0));
811 EXPECT_EQ(scrollInfo
->pageScaleDelta
, 1);
812 EXPECT_TRUE(scrollInfo
->scrolls
.empty());
815 // Once the gesture ends, we get the final scroll and page scale values.
816 m_hostImpl
->pinchGestureEnd();
817 scrollInfo
= m_hostImpl
->processScrollDeltas();
818 if (m_hostImpl
->settings().pageScalePinchZoomEnabled
) {
819 EXPECT_EQ(scrollInfo
->pageScaleDelta
, minPageScale
);
820 expectContains(*scrollInfo
, scrollLayer
->id(), gfx::Vector2d(25, 25));
822 EXPECT_EQ(scrollInfo
->pageScaleDelta
, zoomOutDelta
);
823 expectContains(*scrollInfo
, scrollLayer
->id(), gfx::Vector2d(8, 8));
828 TEST_P(LayerTreeHostImplTest
, inhibitScrollAndPageScaleUpdatesWhileAnimatingPageScale
)
830 setupScrollAndContentsLayers(gfx::Size(100, 100));
831 m_hostImpl
->setViewportSize(gfx::Size(50, 50), gfx::Size(50, 50));
832 initializeRendererAndDrawFrame();
834 LayerImpl
* scrollLayer
= m_hostImpl
->rootScrollLayer();
837 const float minPageScale
= 0.5;
838 const float maxPageScale
= 4;
839 const base::TimeTicks startTime
= base::TimeTicks() + base::TimeDelta::FromSeconds(1);
840 const base::TimeDelta duration
= base::TimeDelta::FromMilliseconds(100);
841 const base::TimeTicks halfwayThroughAnimation
= startTime
+ duration
/ 2;
842 const base::TimeTicks endTime
= startTime
+ duration
;
844 const float pageScaleDelta
= 2;
845 gfx::Vector2d
target(25, 25);
846 gfx::Vector2d scaledTarget
= target
;
847 if (!m_hostImpl
->settings().pageScalePinchZoomEnabled
)
848 scaledTarget
= gfx::Vector2d(12, 12);
850 m_hostImpl
->setPageScaleFactorAndLimits(1, minPageScale
, maxPageScale
);
851 m_hostImpl
->startPageScaleAnimation(target
, false, pageScaleDelta
, startTime
, duration
);
853 // We should immediately get the final zoom and scroll values for the
855 m_hostImpl
->animate(halfwayThroughAnimation
, base::Time());
856 scoped_ptr
<ScrollAndScaleSet
> scrollInfo
= m_hostImpl
->processScrollDeltas();
857 EXPECT_EQ(scrollInfo
->pageScaleDelta
, pageScaleDelta
);
858 expectContains(*scrollInfo
, scrollLayer
->id(), scaledTarget
);
860 // Scrolling during the animation is ignored.
861 const gfx::Vector2d
scrollDelta(0, 10);
862 EXPECT_EQ(m_hostImpl
->scrollBegin(gfx::Point(target
.x(), target
.y()), InputHandlerClient::Wheel
), InputHandlerClient::ScrollStarted
);
863 m_hostImpl
->scrollBy(gfx::Point(), scrollDelta
);
864 m_hostImpl
->scrollEnd();
866 // The final page scale and scroll deltas should match what we got
868 m_hostImpl
->animate(endTime
, base::Time());
869 scrollInfo
= m_hostImpl
->processScrollDeltas();
870 EXPECT_EQ(scrollInfo
->pageScaleDelta
, pageScaleDelta
);
871 expectContains(*scrollInfo
, scrollLayer
->id(), scaledTarget
);
874 class DidDrawCheckLayer
: public TiledLayerImpl
{
876 static scoped_ptr
<LayerImpl
> create(int id
) { return scoped_ptr
<LayerImpl
>(new DidDrawCheckLayer(id
)); }
878 virtual void didDraw(ResourceProvider
*) OVERRIDE
880 m_didDrawCalled
= true;
883 virtual void willDraw(ResourceProvider
*) OVERRIDE
885 m_willDrawCalled
= true;
888 bool didDrawCalled() const { return m_didDrawCalled
; }
889 bool willDrawCalled() const { return m_willDrawCalled
; }
891 void clearDidDrawCheck()
893 m_didDrawCalled
= false;
894 m_willDrawCalled
= false;
898 explicit DidDrawCheckLayer(int id
)
900 , m_didDrawCalled(false)
901 , m_willDrawCalled(false)
903 setAnchorPoint(gfx::PointF(0, 0));
904 setBounds(gfx::Size(10, 10));
905 setContentBounds(gfx::Size(10, 10));
906 setDrawsContent(true);
908 setVisibleContentRect(gfx::Rect(0, 0, 10, 10));
910 scoped_ptr
<LayerTilingData
> tiler
= LayerTilingData::create(gfx::Size(100, 100), LayerTilingData::HasBorderTexels
);
911 tiler
->setBounds(contentBounds());
912 setTilingData(*tiler
.get());
916 bool m_didDrawCalled
;
917 bool m_willDrawCalled
;
920 TEST_P(LayerTreeHostImplTest
, didDrawNotCalledOnHiddenLayer
)
922 // The root layer is always drawn, so run this test on a child layer that
923 // will be masked out by the root layer's bounds.
924 m_hostImpl
->setRootLayer(DidDrawCheckLayer::create(1));
925 DidDrawCheckLayer
* root
= static_cast<DidDrawCheckLayer
*>(m_hostImpl
->rootLayer());
926 root
->setMasksToBounds(true);
928 root
->addChild(DidDrawCheckLayer::create(2));
929 DidDrawCheckLayer
* layer
= static_cast<DidDrawCheckLayer
*>(root
->children()[0]);
930 // Ensure visibleContentRect for layer is empty
931 layer
->setPosition(gfx::PointF(100, 100));
932 layer
->setBounds(gfx::Size(10, 10));
933 layer
->setContentBounds(gfx::Size(10, 10));
935 LayerTreeHostImpl::FrameData frame
;
937 EXPECT_FALSE(layer
->willDrawCalled());
938 EXPECT_FALSE(layer
->didDrawCalled());
940 EXPECT_TRUE(m_hostImpl
->prepareToDraw(frame
));
941 m_hostImpl
->drawLayers(frame
);
942 m_hostImpl
->didDrawAllLayers(frame
);
944 EXPECT_FALSE(layer
->willDrawCalled());
945 EXPECT_FALSE(layer
->didDrawCalled());
947 EXPECT_TRUE(layer
->visibleContentRect().IsEmpty());
949 // Ensure visibleContentRect for layer layer is not empty
950 layer
->setPosition(gfx::PointF(0, 0));
952 EXPECT_FALSE(layer
->willDrawCalled());
953 EXPECT_FALSE(layer
->didDrawCalled());
955 EXPECT_TRUE(m_hostImpl
->prepareToDraw(frame
));
956 m_hostImpl
->drawLayers(frame
);
957 m_hostImpl
->didDrawAllLayers(frame
);
959 EXPECT_TRUE(layer
->willDrawCalled());
960 EXPECT_TRUE(layer
->didDrawCalled());
962 EXPECT_FALSE(layer
->visibleContentRect().IsEmpty());
965 TEST_P(LayerTreeHostImplTest
, willDrawNotCalledOnOccludedLayer
)
967 gfx::Size
bigSize(1000, 1000);
968 m_hostImpl
->setViewportSize(bigSize
, bigSize
);
970 m_hostImpl
->setRootLayer(DidDrawCheckLayer::create(1));
971 DidDrawCheckLayer
* root
= static_cast<DidDrawCheckLayer
*>(m_hostImpl
->rootLayer());
973 root
->addChild(DidDrawCheckLayer::create(2));
974 DidDrawCheckLayer
* occludedLayer
= static_cast<DidDrawCheckLayer
*>(root
->children()[0]);
976 root
->addChild(DidDrawCheckLayer::create(3));
977 DidDrawCheckLayer
* topLayer
= static_cast<DidDrawCheckLayer
*>(root
->children()[1]);
978 // This layer covers the occludedLayer above. Make this layer large so it can occlude.
979 topLayer
->setBounds(bigSize
);
980 topLayer
->setContentBounds(bigSize
);
981 topLayer
->setContentsOpaque(true);
983 LayerTreeHostImpl::FrameData frame
;
985 EXPECT_FALSE(occludedLayer
->willDrawCalled());
986 EXPECT_FALSE(occludedLayer
->didDrawCalled());
987 EXPECT_FALSE(topLayer
->willDrawCalled());
988 EXPECT_FALSE(topLayer
->didDrawCalled());
990 EXPECT_TRUE(m_hostImpl
->prepareToDraw(frame
));
991 m_hostImpl
->drawLayers(frame
);
992 m_hostImpl
->didDrawAllLayers(frame
);
994 EXPECT_FALSE(occludedLayer
->willDrawCalled());
995 EXPECT_FALSE(occludedLayer
->didDrawCalled());
996 EXPECT_TRUE(topLayer
->willDrawCalled());
997 EXPECT_TRUE(topLayer
->didDrawCalled());
1000 TEST_P(LayerTreeHostImplTest
, didDrawCalledOnAllLayers
)
1002 m_hostImpl
->setRootLayer(DidDrawCheckLayer::create(1));
1003 DidDrawCheckLayer
* root
= static_cast<DidDrawCheckLayer
*>(m_hostImpl
->rootLayer());
1005 root
->addChild(DidDrawCheckLayer::create(2));
1006 DidDrawCheckLayer
* layer1
= static_cast<DidDrawCheckLayer
*>(root
->children()[0]);
1008 layer1
->addChild(DidDrawCheckLayer::create(3));
1009 DidDrawCheckLayer
* layer2
= static_cast<DidDrawCheckLayer
*>(layer1
->children()[0]);
1011 layer1
->setOpacity(0.3f
);
1012 layer1
->setPreserves3D(false);
1014 EXPECT_FALSE(root
->didDrawCalled());
1015 EXPECT_FALSE(layer1
->didDrawCalled());
1016 EXPECT_FALSE(layer2
->didDrawCalled());
1018 LayerTreeHostImpl::FrameData frame
;
1019 EXPECT_TRUE(m_hostImpl
->prepareToDraw(frame
));
1020 m_hostImpl
->drawLayers(frame
);
1021 m_hostImpl
->didDrawAllLayers(frame
);
1023 EXPECT_TRUE(root
->didDrawCalled());
1024 EXPECT_TRUE(layer1
->didDrawCalled());
1025 EXPECT_TRUE(layer2
->didDrawCalled());
1027 EXPECT_NE(root
->renderSurface(), layer1
->renderSurface());
1028 EXPECT_TRUE(!!layer1
->renderSurface());
1031 class MissingTextureAnimatingLayer
: public DidDrawCheckLayer
{
1033 static scoped_ptr
<LayerImpl
> create(int id
, bool tileMissing
, bool skipsDraw
, bool animating
, ResourceProvider
* resourceProvider
)
1035 return scoped_ptr
<LayerImpl
>(new MissingTextureAnimatingLayer(id
, tileMissing
, skipsDraw
, animating
, resourceProvider
));
1039 explicit MissingTextureAnimatingLayer(int id
, bool tileMissing
, bool skipsDraw
, bool animating
, ResourceProvider
* resourceProvider
)
1040 : DidDrawCheckLayer(id
)
1042 scoped_ptr
<LayerTilingData
> tilingData
= LayerTilingData::create(gfx::Size(10, 10), LayerTilingData::NoBorderTexels
);
1043 tilingData
->setBounds(bounds());
1044 setTilingData(*tilingData
.get());
1045 setSkipsDraw(skipsDraw
);
1047 ResourceProvider::ResourceId resource
= resourceProvider
->createResource(Renderer::ContentPool
, gfx::Size(), GL_RGBA
, ResourceProvider::TextureUsageAny
);
1048 pushTileProperties(0, 0, resource
, gfx::Rect(), false);
1051 addAnimatedTransformToLayer(*this, 10, 3, 0);
1055 TEST_P(LayerTreeHostImplTest
, prepareToDrawFailsWhenAnimationUsesCheckerboard
)
1057 // When the texture is not missing, we draw as usual.
1058 m_hostImpl
->setRootLayer(DidDrawCheckLayer::create(1));
1059 DidDrawCheckLayer
* root
= static_cast<DidDrawCheckLayer
*>(m_hostImpl
->rootLayer());
1060 root
->addChild(MissingTextureAnimatingLayer::create(2, false, false, true, m_hostImpl
->resourceProvider()));
1062 LayerTreeHostImpl::FrameData frame
;
1064 EXPECT_TRUE(m_hostImpl
->prepareToDraw(frame
));
1065 m_hostImpl
->drawLayers(frame
);
1066 m_hostImpl
->didDrawAllLayers(frame
);
1068 // When a texture is missing and we're not animating, we draw as usual with checkerboarding.
1069 m_hostImpl
->setRootLayer(DidDrawCheckLayer::create(1));
1070 root
= static_cast<DidDrawCheckLayer
*>(m_hostImpl
->rootLayer());
1071 root
->addChild(MissingTextureAnimatingLayer::create(2, true, false, false, m_hostImpl
->resourceProvider()));
1073 EXPECT_TRUE(m_hostImpl
->prepareToDraw(frame
));
1074 m_hostImpl
->drawLayers(frame
);
1075 m_hostImpl
->didDrawAllLayers(frame
);
1077 // When a texture is missing and we're animating, we don't want to draw anything.
1078 m_hostImpl
->setRootLayer(DidDrawCheckLayer::create(1));
1079 root
= static_cast<DidDrawCheckLayer
*>(m_hostImpl
->rootLayer());
1080 root
->addChild(MissingTextureAnimatingLayer::create(2, true, false, true, m_hostImpl
->resourceProvider()));
1082 EXPECT_FALSE(m_hostImpl
->prepareToDraw(frame
));
1083 m_hostImpl
->drawLayers(frame
);
1084 m_hostImpl
->didDrawAllLayers(frame
);
1086 // When the layer skips draw and we're animating, we still draw the frame.
1087 m_hostImpl
->setRootLayer(DidDrawCheckLayer::create(1));
1088 root
= static_cast<DidDrawCheckLayer
*>(m_hostImpl
->rootLayer());
1089 root
->addChild(MissingTextureAnimatingLayer::create(2, false, true, true, m_hostImpl
->resourceProvider()));
1091 EXPECT_TRUE(m_hostImpl
->prepareToDraw(frame
));
1092 m_hostImpl
->drawLayers(frame
);
1093 m_hostImpl
->didDrawAllLayers(frame
);
1096 TEST_P(LayerTreeHostImplTest
, scrollRootIgnored
)
1098 scoped_ptr
<LayerImpl
> root
= LayerImpl::create(1);
1099 root
->setScrollable(false);
1100 m_hostImpl
->setRootLayer(root
.Pass());
1101 initializeRendererAndDrawFrame();
1103 // Scroll event is ignored because layer is not scrollable.
1104 EXPECT_EQ(m_hostImpl
->scrollBegin(gfx::Point(0, 0), InputHandlerClient::Wheel
), InputHandlerClient::ScrollIgnored
);
1105 EXPECT_FALSE(m_didRequestRedraw
);
1106 EXPECT_FALSE(m_didRequestCommit
);
1109 TEST_P(LayerTreeHostImplTest
, scrollNonCompositedRoot
)
1111 // Test the configuration where a non-composited root layer is embedded in a
1112 // scrollable outer layer.
1113 gfx::Size
surfaceSize(10, 10);
1115 scoped_ptr
<LayerImpl
> contentLayer
= LayerImpl::create(1);
1116 contentLayer
->setUseLCDText(true);
1117 contentLayer
->setDrawsContent(true);
1118 contentLayer
->setPosition(gfx::PointF(0, 0));
1119 contentLayer
->setAnchorPoint(gfx::PointF(0, 0));
1120 contentLayer
->setBounds(surfaceSize
);
1121 contentLayer
->setContentBounds(gfx::Size(surfaceSize
.width() * 2, surfaceSize
.height() * 2));
1122 contentLayer
->setContentsScale(2, 2);
1124 scoped_ptr
<LayerImpl
> scrollLayer
= LayerImpl::create(2);
1125 scrollLayer
->setScrollable(true);
1126 scrollLayer
->setMaxScrollOffset(gfx::Vector2d(surfaceSize
.width(), surfaceSize
.height()));
1127 scrollLayer
->setBounds(surfaceSize
);
1128 scrollLayer
->setContentBounds(surfaceSize
);
1129 scrollLayer
->setPosition(gfx::PointF(0, 0));
1130 scrollLayer
->setAnchorPoint(gfx::PointF(0, 0));
1131 scrollLayer
->addChild(contentLayer
.Pass());
1133 m_hostImpl
->setRootLayer(scrollLayer
.Pass());
1134 m_hostImpl
->setViewportSize(surfaceSize
, surfaceSize
);
1135 initializeRendererAndDrawFrame();
1137 EXPECT_EQ(m_hostImpl
->scrollBegin(gfx::Point(5, 5), InputHandlerClient::Wheel
), InputHandlerClient::ScrollStarted
);
1138 m_hostImpl
->scrollBy(gfx::Point(), gfx::Vector2d(0, 10));
1139 m_hostImpl
->scrollEnd();
1140 EXPECT_TRUE(m_didRequestRedraw
);
1141 EXPECT_TRUE(m_didRequestCommit
);
1144 TEST_P(LayerTreeHostImplTest
, scrollChildCallsCommitAndRedraw
)
1146 gfx::Size
surfaceSize(10, 10);
1147 scoped_ptr
<LayerImpl
> root
= LayerImpl::create(1);
1148 root
->setBounds(surfaceSize
);
1149 root
->setContentBounds(surfaceSize
);
1150 root
->addChild(createScrollableLayer(2, surfaceSize
));
1151 m_hostImpl
->setRootLayer(root
.Pass());
1152 m_hostImpl
->setViewportSize(surfaceSize
, surfaceSize
);
1153 initializeRendererAndDrawFrame();
1155 EXPECT_EQ(m_hostImpl
->scrollBegin(gfx::Point(5, 5), InputHandlerClient::Wheel
), InputHandlerClient::ScrollStarted
);
1156 m_hostImpl
->scrollBy(gfx::Point(), gfx::Vector2d(0, 10));
1157 m_hostImpl
->scrollEnd();
1158 EXPECT_TRUE(m_didRequestRedraw
);
1159 EXPECT_TRUE(m_didRequestCommit
);
1162 TEST_P(LayerTreeHostImplTest
, scrollMissesChild
)
1164 gfx::Size
surfaceSize(10, 10);
1165 scoped_ptr
<LayerImpl
> root
= LayerImpl::create(1);
1166 root
->addChild(createScrollableLayer(2, surfaceSize
));
1167 m_hostImpl
->setRootLayer(root
.Pass());
1168 m_hostImpl
->setViewportSize(surfaceSize
, surfaceSize
);
1169 initializeRendererAndDrawFrame();
1171 // Scroll event is ignored because the input coordinate is outside the layer boundaries.
1172 EXPECT_EQ(m_hostImpl
->scrollBegin(gfx::Point(15, 5), InputHandlerClient::Wheel
), InputHandlerClient::ScrollIgnored
);
1173 EXPECT_FALSE(m_didRequestRedraw
);
1174 EXPECT_FALSE(m_didRequestCommit
);
1177 TEST_P(LayerTreeHostImplTest
, scrollMissesBackfacingChild
)
1179 gfx::Size
surfaceSize(10, 10);
1180 scoped_ptr
<LayerImpl
> root
= LayerImpl::create(1);
1181 scoped_ptr
<LayerImpl
> child
= createScrollableLayer(2, surfaceSize
);
1182 m_hostImpl
->setViewportSize(surfaceSize
, surfaceSize
);
1184 gfx::Transform matrix
;
1185 MathUtil::rotateEulerAngles(&matrix
, 180, 0, 0);
1186 child
->setTransform(matrix
);
1187 child
->setDoubleSided(false);
1189 root
->addChild(child
.Pass());
1190 m_hostImpl
->setRootLayer(root
.Pass());
1191 initializeRendererAndDrawFrame();
1193 // Scroll event is ignored because the scrollable layer is not facing the viewer and there is
1194 // nothing scrollable behind it.
1195 EXPECT_EQ(m_hostImpl
->scrollBegin(gfx::Point(5, 5), InputHandlerClient::Wheel
), InputHandlerClient::ScrollIgnored
);
1196 EXPECT_FALSE(m_didRequestRedraw
);
1197 EXPECT_FALSE(m_didRequestCommit
);
1200 TEST_P(LayerTreeHostImplTest
, scrollBlockedByContentLayer
)
1202 gfx::Size
surfaceSize(10, 10);
1203 scoped_ptr
<LayerImpl
> contentLayer
= createScrollableLayer(1, surfaceSize
);
1204 contentLayer
->setShouldScrollOnMainThread(true);
1205 contentLayer
->setScrollable(false);
1207 scoped_ptr
<LayerImpl
> scrollLayer
= createScrollableLayer(2, surfaceSize
);
1208 scrollLayer
->addChild(contentLayer
.Pass());
1210 m_hostImpl
->setRootLayer(scrollLayer
.Pass());
1211 m_hostImpl
->setViewportSize(surfaceSize
, surfaceSize
);
1212 initializeRendererAndDrawFrame();
1214 // Scrolling fails because the content layer is asking to be scrolled on the main thread.
1215 EXPECT_EQ(m_hostImpl
->scrollBegin(gfx::Point(5, 5), InputHandlerClient::Wheel
), InputHandlerClient::ScrollOnMainThread
);
1218 TEST_P(LayerTreeHostImplTest
, scrollRootAndChangePageScaleOnMainThread
)
1220 gfx::Size
surfaceSize(10, 10);
1221 float pageScale
= 2;
1222 scoped_ptr
<LayerImpl
> root
= createScrollableLayer(1, surfaceSize
);
1223 m_hostImpl
->setRootLayer(root
.Pass());
1224 m_hostImpl
->setViewportSize(surfaceSize
, surfaceSize
);
1225 initializeRendererAndDrawFrame();
1227 gfx::Vector2d
scrollDelta(0, 10);
1228 gfx::Vector2d
expectedScrollDelta(scrollDelta
);
1229 gfx::Vector2d
expectedMaxScroll(m_hostImpl
->rootLayer()->maxScrollOffset());
1230 EXPECT_EQ(m_hostImpl
->scrollBegin(gfx::Point(5, 5), InputHandlerClient::Wheel
), InputHandlerClient::ScrollStarted
);
1231 m_hostImpl
->scrollBy(gfx::Point(), scrollDelta
);
1232 m_hostImpl
->scrollEnd();
1234 // Set new page scale from main thread.
1235 m_hostImpl
->setPageScaleFactorAndLimits(pageScale
, pageScale
, pageScale
);
1237 if (!m_hostImpl
->settings().pageScalePinchZoomEnabled
) {
1238 // The scale should apply to the scroll delta.
1239 expectedScrollDelta
= gfx::ToFlooredVector2d(gfx::ScaleVector2d(expectedScrollDelta
, pageScale
));
1241 scoped_ptr
<ScrollAndScaleSet
> scrollInfo
= m_hostImpl
->processScrollDeltas();
1242 expectContains(*scrollInfo
.get(), m_hostImpl
->rootLayer()->id(), expectedScrollDelta
);
1244 // The scroll range should also have been updated.
1245 EXPECT_EQ(m_hostImpl
->rootLayer()->maxScrollOffset(), expectedMaxScroll
);
1247 // The page scale delta remains constant because the impl thread did not scale.
1248 // TODO: If possible, use gfx::Transform() or Skia equality functions. At
1249 // the moment we avoid that because skia does exact bit-wise equality
1250 // checking that does not consider -0 == +0.
1251 // http://code.google.com/p/chromium/issues/detail?id=162747
1252 EXPECT_EQ(1.0, m_hostImpl
->rootLayer()->implTransform().matrix().getDouble(0, 0));
1253 EXPECT_EQ(0.0, m_hostImpl
->rootLayer()->implTransform().matrix().getDouble(0, 1));
1254 EXPECT_EQ(0.0, m_hostImpl
->rootLayer()->implTransform().matrix().getDouble(0, 2));
1255 EXPECT_EQ(0.0, m_hostImpl
->rootLayer()->implTransform().matrix().getDouble(0, 3));
1256 EXPECT_EQ(0.0, m_hostImpl
->rootLayer()->implTransform().matrix().getDouble(1, 0));
1257 EXPECT_EQ(1.0, m_hostImpl
->rootLayer()->implTransform().matrix().getDouble(1, 1));
1258 EXPECT_EQ(0.0, m_hostImpl
->rootLayer()->implTransform().matrix().getDouble(1, 2));
1259 EXPECT_EQ(0.0, m_hostImpl
->rootLayer()->implTransform().matrix().getDouble(1, 3));
1260 EXPECT_EQ(0.0, m_hostImpl
->rootLayer()->implTransform().matrix().getDouble(2, 0));
1261 EXPECT_EQ(0.0, m_hostImpl
->rootLayer()->implTransform().matrix().getDouble(2, 1));
1262 EXPECT_EQ(1.0, m_hostImpl
->rootLayer()->implTransform().matrix().getDouble(2, 2));
1263 EXPECT_EQ(0.0, m_hostImpl
->rootLayer()->implTransform().matrix().getDouble(2, 3));
1264 EXPECT_EQ(0.0, m_hostImpl
->rootLayer()->implTransform().matrix().getDouble(3, 0));
1265 EXPECT_EQ(0.0, m_hostImpl
->rootLayer()->implTransform().matrix().getDouble(3, 1));
1266 EXPECT_EQ(0.0, m_hostImpl
->rootLayer()->implTransform().matrix().getDouble(3, 2));
1267 EXPECT_EQ(1.0, m_hostImpl
->rootLayer()->implTransform().matrix().getDouble(3, 3));
1270 TEST_P(LayerTreeHostImplTest
, scrollRootAndChangePageScaleOnImplThread
)
1272 gfx::Size
surfaceSize(10, 10);
1273 float pageScale
= 2;
1274 scoped_ptr
<LayerImpl
> root
= createScrollableLayer(1, surfaceSize
);
1275 m_hostImpl
->setRootLayer(root
.Pass());
1276 m_hostImpl
->setViewportSize(surfaceSize
, surfaceSize
);
1277 m_hostImpl
->setPageScaleFactorAndLimits(1, 1, pageScale
);
1278 initializeRendererAndDrawFrame();
1280 gfx::Vector2d
scrollDelta(0, 10);
1281 gfx::Vector2d
expectedScrollDelta(scrollDelta
);
1282 gfx::Vector2d
expectedMaxScroll(m_hostImpl
->rootLayer()->maxScrollOffset());
1283 EXPECT_EQ(m_hostImpl
->scrollBegin(gfx::Point(5, 5), InputHandlerClient::Wheel
), InputHandlerClient::ScrollStarted
);
1284 m_hostImpl
->scrollBy(gfx::Point(), scrollDelta
);
1285 m_hostImpl
->scrollEnd();
1287 // Set new page scale on impl thread by pinching.
1288 m_hostImpl
->pinchGestureBegin();
1289 m_hostImpl
->pinchGestureUpdate(pageScale
, gfx::Point());
1290 m_hostImpl
->pinchGestureEnd();
1291 m_hostImpl
->updateRootScrollLayerImplTransform();
1293 // The scroll delta is not scaled because the main thread did not scale.
1294 scoped_ptr
<ScrollAndScaleSet
> scrollInfo
= m_hostImpl
->processScrollDeltas();
1295 expectContains(*scrollInfo
.get(), m_hostImpl
->rootLayer()->id(), expectedScrollDelta
);
1297 // The scroll range should also have been updated.
1298 EXPECT_EQ(m_hostImpl
->rootLayer()->maxScrollOffset(), expectedMaxScroll
);
1300 // The page scale delta should match the new scale on the impl side.
1301 gfx::Transform expectedScale
;
1302 expectedScale
.Scale(pageScale
, pageScale
);
1303 EXPECT_EQ(m_hostImpl
->rootLayer()->implTransform(), expectedScale
);
1306 TEST_P(LayerTreeHostImplTest
, pageScaleDeltaAppliedToRootScrollLayerOnly
)
1308 gfx::Size
surfaceSize(10, 10);
1309 float defaultPageScale
= 1;
1310 gfx::Transform defaultPageScaleMatrix
;
1312 float newPageScale
= 2;
1313 gfx::Transform newPageScaleMatrix
;
1314 newPageScaleMatrix
.Scale(newPageScale
, newPageScale
);
1316 // Create a normal scrollable root layer and another scrollable child layer.
1317 setupScrollAndContentsLayers(surfaceSize
);
1318 LayerImpl
* root
= m_hostImpl
->rootLayer();
1319 LayerImpl
* child
= root
->children()[0];
1321 scoped_ptr
<LayerImpl
> scrollableChild
= createScrollableLayer(3, surfaceSize
);
1322 child
->addChild(scrollableChild
.Pass());
1323 LayerImpl
* grandChild
= child
->children()[0];
1325 // Set new page scale on impl thread by pinching.
1326 m_hostImpl
->pinchGestureBegin();
1327 m_hostImpl
->pinchGestureUpdate(newPageScale
, gfx::Point());
1328 m_hostImpl
->pinchGestureEnd();
1329 m_hostImpl
->updateRootScrollLayerImplTransform();
1331 // The page scale delta should only be applied to the scrollable root layer.
1332 EXPECT_EQ(root
->implTransform(), newPageScaleMatrix
);
1333 EXPECT_EQ(child
->implTransform(), defaultPageScaleMatrix
);
1334 EXPECT_EQ(grandChild
->implTransform(), defaultPageScaleMatrix
);
1336 // Make sure all the layers are drawn with the page scale delta applied, i.e., the page scale
1337 // delta on the root layer is applied hierarchically.
1338 LayerTreeHostImpl::FrameData frame
;
1339 EXPECT_TRUE(m_hostImpl
->prepareToDraw(frame
));
1340 m_hostImpl
->drawLayers(frame
);
1341 m_hostImpl
->didDrawAllLayers(frame
);
1343 EXPECT_EQ(root
->drawTransform().matrix().getDouble(0, 0), newPageScale
);
1344 EXPECT_EQ(root
->drawTransform().matrix().getDouble(1, 1), newPageScale
);
1345 EXPECT_EQ(child
->drawTransform().matrix().getDouble(0, 0), newPageScale
);
1346 EXPECT_EQ(child
->drawTransform().matrix().getDouble(1, 1), newPageScale
);
1347 EXPECT_EQ(grandChild
->drawTransform().matrix().getDouble(0, 0), newPageScale
);
1348 EXPECT_EQ(grandChild
->drawTransform().matrix().getDouble(1, 1), newPageScale
);
1351 TEST_P(LayerTreeHostImplTest
, scrollChildAndChangePageScaleOnMainThread
)
1353 gfx::Size
surfaceSize(10, 10);
1354 scoped_ptr
<LayerImpl
> root
= LayerImpl::create(1);
1355 root
->setBounds(surfaceSize
);
1356 root
->setContentBounds(surfaceSize
);
1357 // Also mark the root scrollable so it becomes the root scroll layer.
1358 root
->setScrollable(true);
1359 int scrollLayerId
= 2;
1360 root
->addChild(createScrollableLayer(scrollLayerId
, surfaceSize
));
1361 m_hostImpl
->setRootLayer(root
.Pass());
1362 m_hostImpl
->setViewportSize(surfaceSize
, surfaceSize
);
1363 initializeRendererAndDrawFrame();
1365 LayerImpl
* child
= m_hostImpl
->rootLayer()->children()[0];
1367 gfx::Vector2d
scrollDelta(0, 10);
1368 gfx::Vector2d
expectedScrollDelta(scrollDelta
);
1369 gfx::Vector2d
expectedMaxScroll(child
->maxScrollOffset());
1370 EXPECT_EQ(m_hostImpl
->scrollBegin(gfx::Point(5, 5), InputHandlerClient::Wheel
), InputHandlerClient::ScrollStarted
);
1371 m_hostImpl
->scrollBy(gfx::Point(), scrollDelta
);
1372 m_hostImpl
->scrollEnd();
1374 float pageScale
= 2;
1375 m_hostImpl
->setPageScaleFactorAndLimits(pageScale
, 1, pageScale
);
1377 m_hostImpl
->updateRootScrollLayerImplTransform();
1379 if (!m_hostImpl
->settings().pageScalePinchZoomEnabled
) {
1380 // The scale should apply to the scroll delta.
1381 expectedScrollDelta
= gfx::ToFlooredVector2d(gfx::ScaleVector2d(expectedScrollDelta
, pageScale
));
1383 scoped_ptr
<ScrollAndScaleSet
> scrollInfo
= m_hostImpl
->processScrollDeltas();
1384 expectContains(*scrollInfo
.get(), scrollLayerId
, expectedScrollDelta
);
1386 // The scroll range should not have changed.
1387 EXPECT_EQ(child
->maxScrollOffset(), expectedMaxScroll
);
1389 // The page scale delta remains constant because the impl thread did not scale.
1390 gfx::Transform identityTransform
;
1391 EXPECT_EQ(child
->implTransform(), gfx::Transform());
1394 TEST_P(LayerTreeHostImplTest
, scrollChildBeyondLimit
)
1396 // Scroll a child layer beyond its maximum scroll range and make sure the
1397 // parent layer is scrolled on the axis on which the child was unable to
1399 gfx::Size
surfaceSize(10, 10);
1400 scoped_ptr
<LayerImpl
> root
= createScrollableLayer(1, surfaceSize
);
1402 scoped_ptr
<LayerImpl
> grandChild
= createScrollableLayer(3, surfaceSize
);
1403 grandChild
->setScrollOffset(gfx::Vector2d(0, 5));
1405 scoped_ptr
<LayerImpl
> child
= createScrollableLayer(2, surfaceSize
);
1406 child
->setScrollOffset(gfx::Vector2d(3, 0));
1407 child
->addChild(grandChild
.Pass());
1409 root
->addChild(child
.Pass());
1410 m_hostImpl
->setRootLayer(root
.Pass());
1411 m_hostImpl
->setViewportSize(surfaceSize
, surfaceSize
);
1412 initializeRendererAndDrawFrame();
1414 gfx::Vector2d
scrollDelta(-8, -7);
1415 EXPECT_EQ(m_hostImpl
->scrollBegin(gfx::Point(5, 5), InputHandlerClient::Wheel
), InputHandlerClient::ScrollStarted
);
1416 m_hostImpl
->scrollBy(gfx::Point(), scrollDelta
);
1417 m_hostImpl
->scrollEnd();
1419 scoped_ptr
<ScrollAndScaleSet
> scrollInfo
= m_hostImpl
->processScrollDeltas();
1421 // The grand child should have scrolled up to its limit.
1422 LayerImpl
* child
= m_hostImpl
->rootLayer()->children()[0];
1423 LayerImpl
* grandChild
= child
->children()[0];
1424 expectContains(*scrollInfo
.get(), grandChild
->id(), gfx::Vector2d(0, -5));
1426 // The child should have only scrolled on the other axis.
1427 expectContains(*scrollInfo
.get(), child
->id(), gfx::Vector2d(-3, 0));
1431 TEST_P(LayerTreeHostImplTest
, scrollEventBubbling
)
1433 // When we try to scroll a non-scrollable child layer, the scroll delta
1434 // should be applied to one of its ancestors if possible.
1435 gfx::Size
surfaceSize(10, 10);
1436 scoped_ptr
<LayerImpl
> root
= createScrollableLayer(1, surfaceSize
);
1437 scoped_ptr
<LayerImpl
> child
= createScrollableLayer(2, surfaceSize
);
1439 child
->setScrollable(false);
1440 root
->addChild(child
.Pass());
1442 m_hostImpl
->setRootLayer(root
.Pass());
1443 m_hostImpl
->setViewportSize(surfaceSize
, surfaceSize
);
1444 initializeRendererAndDrawFrame();
1446 gfx::Vector2d
scrollDelta(0, 4);
1447 EXPECT_EQ(m_hostImpl
->scrollBegin(gfx::Point(5, 5), InputHandlerClient::Wheel
), InputHandlerClient::ScrollStarted
);
1448 m_hostImpl
->scrollBy(gfx::Point(), scrollDelta
);
1449 m_hostImpl
->scrollEnd();
1451 scoped_ptr
<ScrollAndScaleSet
> scrollInfo
= m_hostImpl
->processScrollDeltas();
1453 // Only the root should have scrolled.
1454 ASSERT_EQ(scrollInfo
->scrolls
.size(), 1u);
1455 expectContains(*scrollInfo
.get(), m_hostImpl
->rootLayer()->id(), scrollDelta
);
1459 TEST_P(LayerTreeHostImplTest
, scrollBeforeRedraw
)
1461 gfx::Size
surfaceSize(10, 10);
1462 m_hostImpl
->setRootLayer(createScrollableLayer(1, surfaceSize
));
1463 m_hostImpl
->setViewportSize(surfaceSize
, surfaceSize
);
1465 // Draw one frame and then immediately rebuild the layer tree to mimic a tree synchronization.
1466 initializeRendererAndDrawFrame();
1467 m_hostImpl
->detachLayerTree();
1468 m_hostImpl
->setRootLayer(createScrollableLayer(2, surfaceSize
));
1470 // Scrolling should still work even though we did not draw yet.
1471 EXPECT_EQ(m_hostImpl
->scrollBegin(gfx::Point(5, 5), InputHandlerClient::Wheel
), InputHandlerClient::ScrollStarted
);
1474 TEST_P(LayerTreeHostImplTest
, scrollAxisAlignedRotatedLayer
)
1476 setupScrollAndContentsLayers(gfx::Size(100, 100));
1478 // Rotate the root layer 90 degrees counter-clockwise about its center.
1479 gfx::Transform rotateTransform
;
1480 rotateTransform
.Rotate(-90);
1481 m_hostImpl
->rootLayer()->setTransform(rotateTransform
);
1483 gfx::Size
surfaceSize(50, 50);
1484 m_hostImpl
->setViewportSize(surfaceSize
, surfaceSize
);
1485 initializeRendererAndDrawFrame();
1487 // Scroll to the right in screen coordinates with a gesture.
1488 gfx::Vector2d
gestureScrollDelta(10, 0);
1489 EXPECT_EQ(m_hostImpl
->scrollBegin(gfx::Point(0, 0), InputHandlerClient::Gesture
), InputHandlerClient::ScrollStarted
);
1490 m_hostImpl
->scrollBy(gfx::Point(), gestureScrollDelta
);
1491 m_hostImpl
->scrollEnd();
1493 // The layer should have scrolled down in its local coordinates.
1494 scoped_ptr
<ScrollAndScaleSet
> scrollInfo
= m_hostImpl
->processScrollDeltas();
1495 expectContains(*scrollInfo
.get(), m_hostImpl
->rootLayer()->id(), gfx::Vector2d(0, gestureScrollDelta
.x()));
1497 // Reset and scroll down with the wheel.
1498 m_hostImpl
->rootLayer()->setScrollDelta(gfx::Vector2dF());
1499 gfx::Vector2d
wheelScrollDelta(0, 10);
1500 EXPECT_EQ(m_hostImpl
->scrollBegin(gfx::Point(0, 0), InputHandlerClient::Wheel
), InputHandlerClient::ScrollStarted
);
1501 m_hostImpl
->scrollBy(gfx::Point(), wheelScrollDelta
);
1502 m_hostImpl
->scrollEnd();
1504 // The layer should have scrolled down in its local coordinates.
1505 scrollInfo
= m_hostImpl
->processScrollDeltas();
1506 expectContains(*scrollInfo
.get(), m_hostImpl
->rootLayer()->id(), wheelScrollDelta
);
1509 TEST_P(LayerTreeHostImplTest
, scrollNonAxisAlignedRotatedLayer
)
1511 setupScrollAndContentsLayers(gfx::Size(100, 100));
1512 int childLayerId
= 3;
1513 float childLayerAngle
= -20;
1515 // Create a child layer that is rotated to a non-axis-aligned angle.
1516 scoped_ptr
<LayerImpl
> child
= createScrollableLayer(childLayerId
, m_hostImpl
->rootLayer()->contentBounds());
1517 gfx::Transform rotateTransform
;
1518 rotateTransform
.Translate(-50, -50);
1519 rotateTransform
.Rotate(childLayerAngle
);
1520 rotateTransform
.Translate(50, 50);
1521 child
->setTransform(rotateTransform
);
1523 // Only allow vertical scrolling.
1524 child
->setMaxScrollOffset(gfx::Vector2d(0, child
->contentBounds().height()));
1525 m_hostImpl
->rootLayer()->addChild(child
.Pass());
1527 gfx::Size
surfaceSize(50, 50);
1528 m_hostImpl
->setViewportSize(surfaceSize
, surfaceSize
);
1529 initializeRendererAndDrawFrame();
1532 // Scroll down in screen coordinates with a gesture.
1533 gfx::Vector2d
gestureScrollDelta(0, 10);
1534 EXPECT_EQ(m_hostImpl
->scrollBegin(gfx::Point(0, 0), InputHandlerClient::Gesture
), InputHandlerClient::ScrollStarted
);
1535 m_hostImpl
->scrollBy(gfx::Point(), gestureScrollDelta
);
1536 m_hostImpl
->scrollEnd();
1538 // The child layer should have scrolled down in its local coordinates an amount proportional to
1539 // the angle between it and the input scroll delta.
1540 gfx::Vector2d
expectedScrollDelta(0, gestureScrollDelta
.y() * std::cos(MathUtil::Deg2Rad(childLayerAngle
)));
1541 scoped_ptr
<ScrollAndScaleSet
> scrollInfo
= m_hostImpl
->processScrollDeltas();
1542 expectContains(*scrollInfo
.get(), childLayerId
, expectedScrollDelta
);
1544 // The root layer should not have scrolled, because the input delta was close to the layer's
1545 // axis of movement.
1546 EXPECT_EQ(scrollInfo
->scrolls
.size(), 1u);
1550 // Now reset and scroll the same amount horizontally.
1551 m_hostImpl
->rootLayer()->children()[1]->setScrollDelta(gfx::Vector2dF());
1552 gfx::Vector2d
gestureScrollDelta(10, 0);
1553 EXPECT_EQ(m_hostImpl
->scrollBegin(gfx::Point(0, 0), InputHandlerClient::Gesture
), InputHandlerClient::ScrollStarted
);
1554 m_hostImpl
->scrollBy(gfx::Point(), gestureScrollDelta
);
1555 m_hostImpl
->scrollEnd();
1557 // The child layer should have scrolled down in its local coordinates an amount proportional to
1558 // the angle between it and the input scroll delta.
1559 gfx::Vector2d
expectedScrollDelta(0, -gestureScrollDelta
.x() * std::sin(MathUtil::Deg2Rad(childLayerAngle
)));
1560 scoped_ptr
<ScrollAndScaleSet
> scrollInfo
= m_hostImpl
->processScrollDeltas();
1561 expectContains(*scrollInfo
.get(), childLayerId
, expectedScrollDelta
);
1563 // The root layer should have scrolled more, since the input scroll delta was mostly
1564 // orthogonal to the child layer's vertical scroll axis.
1565 gfx::Vector2d
expectedRootScrollDelta(gestureScrollDelta
.x() * std::pow(std::cos(MathUtil::Deg2Rad(childLayerAngle
)), 2), 0);
1566 expectContains(*scrollInfo
.get(), m_hostImpl
->rootLayer()->id(), expectedRootScrollDelta
);
1570 TEST_P(LayerTreeHostImplTest
, scrollScaledLayer
)
1572 setupScrollAndContentsLayers(gfx::Size(100, 100));
1574 // Scale the layer to twice its normal size.
1576 gfx::Transform scaleTransform
;
1577 scaleTransform
.Scale(scale
, scale
);
1578 m_hostImpl
->rootLayer()->setTransform(scaleTransform
);
1580 gfx::Size
surfaceSize(50, 50);
1581 m_hostImpl
->setViewportSize(surfaceSize
, surfaceSize
);
1582 initializeRendererAndDrawFrame();
1584 // Scroll down in screen coordinates with a gesture.
1585 gfx::Vector2d
scrollDelta(0, 10);
1586 EXPECT_EQ(m_hostImpl
->scrollBegin(gfx::Point(0, 0), InputHandlerClient::Gesture
), InputHandlerClient::ScrollStarted
);
1587 m_hostImpl
->scrollBy(gfx::Point(), scrollDelta
);
1588 m_hostImpl
->scrollEnd();
1590 // The layer should have scrolled down in its local coordinates, but half he amount.
1591 scoped_ptr
<ScrollAndScaleSet
> scrollInfo
= m_hostImpl
->processScrollDeltas();
1592 expectContains(*scrollInfo
.get(), m_hostImpl
->rootLayer()->id(), gfx::Vector2d(0, scrollDelta
.y() / scale
));
1594 // Reset and scroll down with the wheel.
1595 m_hostImpl
->rootLayer()->setScrollDelta(gfx::Vector2dF());
1596 gfx::Vector2d
wheelScrollDelta(0, 10);
1597 EXPECT_EQ(m_hostImpl
->scrollBegin(gfx::Point(0, 0), InputHandlerClient::Wheel
), InputHandlerClient::ScrollStarted
);
1598 m_hostImpl
->scrollBy(gfx::Point(), wheelScrollDelta
);
1599 m_hostImpl
->scrollEnd();
1601 // The scale should not have been applied to the scroll delta.
1602 scrollInfo
= m_hostImpl
->processScrollDeltas();
1603 expectContains(*scrollInfo
.get(), m_hostImpl
->rootLayer()->id(), wheelScrollDelta
);
1606 class BlendStateTrackerContext
: public FakeWebGraphicsContext3D
{
1608 BlendStateTrackerContext() : m_blend(false) { }
1610 virtual void enable(WGC3Denum cap
)
1612 if (cap
== GL_BLEND
)
1616 virtual void disable(WGC3Denum cap
)
1618 if (cap
== GL_BLEND
)
1622 bool blend() const { return m_blend
; }
1628 class BlendStateCheckLayer
: public LayerImpl
{
1630 static scoped_ptr
<LayerImpl
> create(int id
, ResourceProvider
* resourceProvider
) { return scoped_ptr
<LayerImpl
>(new BlendStateCheckLayer(id
, resourceProvider
)); }
1632 virtual void appendQuads(QuadSink
& quadSink
, AppendQuadsData
& appendQuadsData
) OVERRIDE
1634 m_quadsAppended
= true;
1636 gfx::Rect opaqueRect
;
1637 if (contentsOpaque())
1638 opaqueRect
= m_quadRect
;
1640 opaqueRect
= m_opaqueContentRect
;
1642 SharedQuadState
* sharedQuadState
= quadSink
.useSharedQuadState(createSharedQuadState());
1643 scoped_ptr
<TileDrawQuad
> testBlendingDrawQuad
= TileDrawQuad::Create();
1644 testBlendingDrawQuad
->SetNew(sharedQuadState
, m_quadRect
, opaqueRect
, m_resourceId
, gfx::RectF(0, 0, 1, 1), gfx::Size(1, 1), false, false, false, false, false);
1645 testBlendingDrawQuad
->visible_rect
= m_quadVisibleRect
;
1646 EXPECT_EQ(m_blend
, testBlendingDrawQuad
->ShouldDrawWithBlending());
1647 EXPECT_EQ(m_hasRenderSurface
, !!renderSurface());
1648 quadSink
.append(testBlendingDrawQuad
.PassAs
<DrawQuad
>(), appendQuadsData
);
1651 void setExpectation(bool blend
, bool hasRenderSurface
)
1654 m_hasRenderSurface
= hasRenderSurface
;
1655 m_quadsAppended
= false;
1658 bool quadsAppended() const { return m_quadsAppended
; }
1660 void setQuadRect(const gfx::Rect
& rect
) { m_quadRect
= rect
; }
1661 void setQuadVisibleRect(const gfx::Rect
& rect
) { m_quadVisibleRect
= rect
; }
1662 void setOpaqueContentRect(const gfx::Rect
& rect
) { m_opaqueContentRect
= rect
; }
1665 explicit BlendStateCheckLayer(int id
, ResourceProvider
* resourceProvider
)
1668 , m_hasRenderSurface(false)
1669 , m_quadsAppended(false)
1670 , m_quadRect(5, 5, 5, 5)
1671 , m_quadVisibleRect(5, 5, 5, 5)
1672 , m_resourceId(resourceProvider
->createResource(Renderer::ContentPool
, gfx::Size(1, 1), GL_RGBA
, ResourceProvider::TextureUsageAny
))
1674 setAnchorPoint(gfx::PointF(0, 0));
1675 setBounds(gfx::Size(10, 10));
1676 setContentBounds(gfx::Size(10, 10));
1677 setDrawsContent(true);
1681 bool m_hasRenderSurface
;
1682 bool m_quadsAppended
;
1683 gfx::Rect m_quadRect
;
1684 gfx::Rect m_opaqueContentRect
;
1685 gfx::Rect m_quadVisibleRect
;
1686 ResourceProvider::ResourceId m_resourceId
;
1689 TEST_P(LayerTreeHostImplTest
, blendingOffWhenDrawingOpaqueLayers
)
1692 scoped_ptr
<LayerImpl
> root
= LayerImpl::create(1);
1693 root
->setAnchorPoint(gfx::PointF(0, 0));
1694 root
->setBounds(gfx::Size(10, 10));
1695 root
->setContentBounds(root
->bounds());
1696 root
->setDrawsContent(false);
1697 m_hostImpl
->setRootLayer(root
.Pass());
1699 LayerImpl
* root
= m_hostImpl
->rootLayer();
1701 root
->addChild(BlendStateCheckLayer::create(2, m_hostImpl
->resourceProvider()));
1702 BlendStateCheckLayer
* layer1
= static_cast<BlendStateCheckLayer
*>(root
->children()[0]);
1703 layer1
->setPosition(gfx::PointF(2, 2));
1705 LayerTreeHostImpl::FrameData frame
;
1707 // Opaque layer, drawn without blending.
1708 layer1
->setContentsOpaque(true);
1709 layer1
->setExpectation(false, false);
1710 EXPECT_TRUE(m_hostImpl
->prepareToDraw(frame
));
1711 m_hostImpl
->drawLayers(frame
);
1712 EXPECT_TRUE(layer1
->quadsAppended());
1713 m_hostImpl
->didDrawAllLayers(frame
);
1715 // Layer with translucent content and painting, so drawn with blending.
1716 layer1
->setContentsOpaque(false);
1717 layer1
->setExpectation(true, false);
1718 EXPECT_TRUE(m_hostImpl
->prepareToDraw(frame
));
1719 m_hostImpl
->drawLayers(frame
);
1720 EXPECT_TRUE(layer1
->quadsAppended());
1721 m_hostImpl
->didDrawAllLayers(frame
);
1723 // Layer with translucent opacity, drawn with blending.
1724 layer1
->setContentsOpaque(true);
1725 layer1
->setOpacity(0.5);
1726 layer1
->setExpectation(true, false);
1727 EXPECT_TRUE(m_hostImpl
->prepareToDraw(frame
));
1728 m_hostImpl
->drawLayers(frame
);
1729 EXPECT_TRUE(layer1
->quadsAppended());
1730 m_hostImpl
->didDrawAllLayers(frame
);
1732 // Layer with translucent opacity and painting, drawn with blending.
1733 layer1
->setContentsOpaque(true);
1734 layer1
->setOpacity(0.5);
1735 layer1
->setExpectation(true, false);
1736 EXPECT_TRUE(m_hostImpl
->prepareToDraw(frame
));
1737 m_hostImpl
->drawLayers(frame
);
1738 EXPECT_TRUE(layer1
->quadsAppended());
1739 m_hostImpl
->didDrawAllLayers(frame
);
1741 layer1
->addChild(BlendStateCheckLayer::create(3, m_hostImpl
->resourceProvider()));
1742 BlendStateCheckLayer
* layer2
= static_cast<BlendStateCheckLayer
*>(layer1
->children()[0]);
1743 layer2
->setPosition(gfx::PointF(4, 4));
1745 // 2 opaque layers, drawn without blending.
1746 layer1
->setContentsOpaque(true);
1747 layer1
->setOpacity(1);
1748 layer1
->setExpectation(false, false);
1749 layer2
->setContentsOpaque(true);
1750 layer2
->setOpacity(1);
1751 layer2
->setExpectation(false, false);
1752 EXPECT_TRUE(m_hostImpl
->prepareToDraw(frame
));
1753 m_hostImpl
->drawLayers(frame
);
1754 EXPECT_TRUE(layer1
->quadsAppended());
1755 EXPECT_TRUE(layer2
->quadsAppended());
1756 m_hostImpl
->didDrawAllLayers(frame
);
1758 // Parent layer with translucent content, drawn with blending.
1759 // Child layer with opaque content, drawn without blending.
1760 layer1
->setContentsOpaque(false);
1761 layer1
->setExpectation(true, false);
1762 layer2
->setExpectation(false, false);
1763 EXPECT_TRUE(m_hostImpl
->prepareToDraw(frame
));
1764 m_hostImpl
->drawLayers(frame
);
1765 EXPECT_TRUE(layer1
->quadsAppended());
1766 EXPECT_TRUE(layer2
->quadsAppended());
1767 m_hostImpl
->didDrawAllLayers(frame
);
1769 // Parent layer with translucent content but opaque painting, drawn without blending.
1770 // Child layer with opaque content, drawn without blending.
1771 layer1
->setContentsOpaque(true);
1772 layer1
->setExpectation(false, false);
1773 layer2
->setExpectation(false, false);
1774 EXPECT_TRUE(m_hostImpl
->prepareToDraw(frame
));
1775 m_hostImpl
->drawLayers(frame
);
1776 EXPECT_TRUE(layer1
->quadsAppended());
1777 EXPECT_TRUE(layer2
->quadsAppended());
1778 m_hostImpl
->didDrawAllLayers(frame
);
1780 // Parent layer with translucent opacity and opaque content. Since it has a
1781 // drawing child, it's drawn to a render surface which carries the opacity,
1782 // so it's itself drawn without blending.
1783 // Child layer with opaque content, drawn without blending (parent surface
1784 // carries the inherited opacity).
1785 layer1
->setContentsOpaque(true);
1786 layer1
->setOpacity(0.5);
1787 layer1
->setExpectation(false, true);
1788 layer2
->setExpectation(false, false);
1789 EXPECT_TRUE(m_hostImpl
->prepareToDraw(frame
));
1790 m_hostImpl
->drawLayers(frame
);
1791 EXPECT_TRUE(layer1
->quadsAppended());
1792 EXPECT_TRUE(layer2
->quadsAppended());
1793 m_hostImpl
->didDrawAllLayers(frame
);
1795 // Draw again, but with child non-opaque, to make sure
1796 // layer1 not culled.
1797 layer1
->setContentsOpaque(true);
1798 layer1
->setOpacity(1);
1799 layer1
->setExpectation(false, false);
1800 layer2
->setContentsOpaque(true);
1801 layer2
->setOpacity(0.5);
1802 layer2
->setExpectation(true, false);
1803 EXPECT_TRUE(m_hostImpl
->prepareToDraw(frame
));
1804 m_hostImpl
->drawLayers(frame
);
1805 EXPECT_TRUE(layer1
->quadsAppended());
1806 EXPECT_TRUE(layer2
->quadsAppended());
1807 m_hostImpl
->didDrawAllLayers(frame
);
1809 // A second way of making the child non-opaque.
1810 layer1
->setContentsOpaque(true);
1811 layer1
->setOpacity(1);
1812 layer1
->setExpectation(false, false);
1813 layer2
->setContentsOpaque(false);
1814 layer2
->setOpacity(1);
1815 layer2
->setExpectation(true, false);
1816 EXPECT_TRUE(m_hostImpl
->prepareToDraw(frame
));
1817 m_hostImpl
->drawLayers(frame
);
1818 EXPECT_TRUE(layer1
->quadsAppended());
1819 EXPECT_TRUE(layer2
->quadsAppended());
1820 m_hostImpl
->didDrawAllLayers(frame
);
1822 // And when the layer says its not opaque but is painted opaque, it is not blended.
1823 layer1
->setContentsOpaque(true);
1824 layer1
->setOpacity(1);
1825 layer1
->setExpectation(false, false);
1826 layer2
->setContentsOpaque(true);
1827 layer2
->setOpacity(1);
1828 layer2
->setExpectation(false, false);
1829 EXPECT_TRUE(m_hostImpl
->prepareToDraw(frame
));
1830 m_hostImpl
->drawLayers(frame
);
1831 EXPECT_TRUE(layer1
->quadsAppended());
1832 EXPECT_TRUE(layer2
->quadsAppended());
1833 m_hostImpl
->didDrawAllLayers(frame
);
1835 // Layer with partially opaque contents, drawn with blending.
1836 layer1
->setContentsOpaque(false);
1837 layer1
->setQuadRect(gfx::Rect(5, 5, 5, 5));
1838 layer1
->setQuadVisibleRect(gfx::Rect(5, 5, 5, 5));
1839 layer1
->setOpaqueContentRect(gfx::Rect(5, 5, 2, 5));
1840 layer1
->setExpectation(true, false);
1841 EXPECT_TRUE(m_hostImpl
->prepareToDraw(frame
));
1842 m_hostImpl
->drawLayers(frame
);
1843 EXPECT_TRUE(layer1
->quadsAppended());
1844 m_hostImpl
->didDrawAllLayers(frame
);
1846 // Layer with partially opaque contents partially culled, drawn with blending.
1847 layer1
->setContentsOpaque(false);
1848 layer1
->setQuadRect(gfx::Rect(5, 5, 5, 5));
1849 layer1
->setQuadVisibleRect(gfx::Rect(5, 5, 5, 2));
1850 layer1
->setOpaqueContentRect(gfx::Rect(5, 5, 2, 5));
1851 layer1
->setExpectation(true, false);
1852 EXPECT_TRUE(m_hostImpl
->prepareToDraw(frame
));
1853 m_hostImpl
->drawLayers(frame
);
1854 EXPECT_TRUE(layer1
->quadsAppended());
1855 m_hostImpl
->didDrawAllLayers(frame
);
1857 // Layer with partially opaque contents culled, drawn with blending.
1858 layer1
->setContentsOpaque(false);
1859 layer1
->setQuadRect(gfx::Rect(5, 5, 5, 5));
1860 layer1
->setQuadVisibleRect(gfx::Rect(7, 5, 3, 5));
1861 layer1
->setOpaqueContentRect(gfx::Rect(5, 5, 2, 5));
1862 layer1
->setExpectation(true, false);
1863 EXPECT_TRUE(m_hostImpl
->prepareToDraw(frame
));
1864 m_hostImpl
->drawLayers(frame
);
1865 EXPECT_TRUE(layer1
->quadsAppended());
1866 m_hostImpl
->didDrawAllLayers(frame
);
1868 // Layer with partially opaque contents and translucent contents culled, drawn without blending.
1869 layer1
->setContentsOpaque(false);
1870 layer1
->setQuadRect(gfx::Rect(5, 5, 5, 5));
1871 layer1
->setQuadVisibleRect(gfx::Rect(5, 5, 2, 5));
1872 layer1
->setOpaqueContentRect(gfx::Rect(5, 5, 2, 5));
1873 layer1
->setExpectation(false, false);
1874 EXPECT_TRUE(m_hostImpl
->prepareToDraw(frame
));
1875 m_hostImpl
->drawLayers(frame
);
1876 EXPECT_TRUE(layer1
->quadsAppended());
1877 m_hostImpl
->didDrawAllLayers(frame
);
1881 TEST_P(LayerTreeHostImplTest
, viewportCovered
)
1883 m_hostImpl
->initializeRenderer(createContext());
1884 m_hostImpl
->setBackgroundColor(SK_ColorGRAY
);
1886 gfx::Size
viewportSize(1000, 1000);
1887 m_hostImpl
->setViewportSize(viewportSize
, viewportSize
);
1889 m_hostImpl
->setRootLayer(LayerImpl::create(1));
1890 m_hostImpl
->rootLayer()->addChild(BlendStateCheckLayer::create(2, m_hostImpl
->resourceProvider()));
1891 BlendStateCheckLayer
* child
= static_cast<BlendStateCheckLayer
*>(m_hostImpl
->rootLayer()->children()[0]);
1892 child
->setExpectation(false, false);
1893 child
->setContentsOpaque(true);
1897 gfx::Rect
layerRect(0, 0, 1000, 1000);
1898 child
->setPosition(layerRect
.origin());
1899 child
->setBounds(layerRect
.size());
1900 child
->setContentBounds(layerRect
.size());
1901 child
->setQuadRect(gfx::Rect(gfx::Point(), layerRect
.size()));
1902 child
->setQuadVisibleRect(gfx::Rect(gfx::Point(), layerRect
.size()));
1904 LayerTreeHostImpl::FrameData frame
;
1905 EXPECT_TRUE(m_hostImpl
->prepareToDraw(frame
));
1906 ASSERT_EQ(1u, frame
.renderPasses
.size());
1908 size_t numGutterQuads
= 0;
1909 for (size_t i
= 0; i
< frame
.renderPasses
[0]->quad_list
.size(); ++i
)
1910 numGutterQuads
+= (frame
.renderPasses
[0]->quad_list
[i
]->material
== DrawQuad::SOLID_COLOR
) ? 1 : 0;
1911 EXPECT_EQ(0u, numGutterQuads
);
1912 EXPECT_EQ(1u, frame
.renderPasses
[0]->quad_list
.size());
1914 verifyQuadsExactlyCoverRect(frame
.renderPasses
[0]->quad_list
, gfx::Rect(gfx::Point(), viewportSize
));
1915 m_hostImpl
->didDrawAllLayers(frame
);
1918 // Empty visible content area (fullscreen gutter rect)
1920 gfx::Rect
layerRect(0, 0, 0, 0);
1921 child
->setPosition(layerRect
.origin());
1922 child
->setBounds(layerRect
.size());
1923 child
->setContentBounds(layerRect
.size());
1924 child
->setQuadRect(gfx::Rect(gfx::Point(), layerRect
.size()));
1925 child
->setQuadVisibleRect(gfx::Rect(gfx::Point(), layerRect
.size()));
1927 LayerTreeHostImpl::FrameData frame
;
1928 EXPECT_TRUE(m_hostImpl
->prepareToDraw(frame
));
1929 ASSERT_EQ(1u, frame
.renderPasses
.size());
1930 m_hostImpl
->didDrawAllLayers(frame
);
1932 size_t numGutterQuads
= 0;
1933 for (size_t i
= 0; i
< frame
.renderPasses
[0]->quad_list
.size(); ++i
)
1934 numGutterQuads
+= (frame
.renderPasses
[0]->quad_list
[i
]->material
== DrawQuad::SOLID_COLOR
) ? 1 : 0;
1935 EXPECT_EQ(1u, numGutterQuads
);
1936 EXPECT_EQ(1u, frame
.renderPasses
[0]->quad_list
.size());
1938 verifyQuadsExactlyCoverRect(frame
.renderPasses
[0]->quad_list
, gfx::Rect(gfx::Point(), viewportSize
));
1939 m_hostImpl
->didDrawAllLayers(frame
);
1942 // Content area in middle of clip rect (four surrounding gutter rects)
1944 gfx::Rect
layerRect(500, 500, 200, 200);
1945 child
->setPosition(layerRect
.origin());
1946 child
->setBounds(layerRect
.size());
1947 child
->setContentBounds(layerRect
.size());
1948 child
->setQuadRect(gfx::Rect(gfx::Point(), layerRect
.size()));
1949 child
->setQuadVisibleRect(gfx::Rect(gfx::Point(), layerRect
.size()));
1951 LayerTreeHostImpl::FrameData frame
;
1952 EXPECT_TRUE(m_hostImpl
->prepareToDraw(frame
));
1953 ASSERT_EQ(1u, frame
.renderPasses
.size());
1955 size_t numGutterQuads
= 0;
1956 for (size_t i
= 0; i
< frame
.renderPasses
[0]->quad_list
.size(); ++i
)
1957 numGutterQuads
+= (frame
.renderPasses
[0]->quad_list
[i
]->material
== DrawQuad::SOLID_COLOR
) ? 1 : 0;
1958 EXPECT_EQ(4u, numGutterQuads
);
1959 EXPECT_EQ(5u, frame
.renderPasses
[0]->quad_list
.size());
1961 verifyQuadsExactlyCoverRect(frame
.renderPasses
[0]->quad_list
, gfx::Rect(gfx::Point(), viewportSize
));
1962 m_hostImpl
->didDrawAllLayers(frame
);
1968 class ReshapeTrackerContext
: public FakeWebGraphicsContext3D
{
1970 ReshapeTrackerContext() : m_reshapeCalled(false) { }
1972 virtual void reshape(int width
, int height
)
1974 m_reshapeCalled
= true;
1977 bool reshapeCalled() const { return m_reshapeCalled
; }
1980 bool m_reshapeCalled
;
1983 class FakeDrawableLayerImpl
: public LayerImpl
{
1985 static scoped_ptr
<LayerImpl
> create(int id
) { return scoped_ptr
<LayerImpl
>(new FakeDrawableLayerImpl(id
)); }
1987 explicit FakeDrawableLayerImpl(int id
) : LayerImpl(id
) { }
1990 // Only reshape when we know we are going to draw. Otherwise, the reshape
1991 // can leave the window at the wrong size if we never draw and the proper
1992 // viewport size is never set.
1993 TEST_P(LayerTreeHostImplTest
, reshapeNotCalledUntilDraw
)
1995 scoped_ptr
<GraphicsContext
> outputSurface
= FakeWebCompositorOutputSurface::create(scoped_ptr
<WebKit::WebGraphicsContext3D
>(new ReshapeTrackerContext
)).PassAs
<GraphicsContext
>();
1996 ReshapeTrackerContext
* reshapeTracker
= static_cast<ReshapeTrackerContext
*>(outputSurface
->context3D());
1997 m_hostImpl
->initializeRenderer(outputSurface
.Pass());
1999 scoped_ptr
<LayerImpl
> root
= FakeDrawableLayerImpl::create(1);
2000 root
->setAnchorPoint(gfx::PointF(0, 0));
2001 root
->setBounds(gfx::Size(10, 10));
2002 root
->setDrawsContent(true);
2003 m_hostImpl
->setRootLayer(root
.Pass());
2004 EXPECT_FALSE(reshapeTracker
->reshapeCalled());
2006 LayerTreeHostImpl::FrameData frame
;
2007 EXPECT_TRUE(m_hostImpl
->prepareToDraw(frame
));
2008 m_hostImpl
->drawLayers(frame
);
2009 EXPECT_TRUE(reshapeTracker
->reshapeCalled());
2010 m_hostImpl
->didDrawAllLayers(frame
);
2013 class PartialSwapTrackerContext
: public FakeWebGraphicsContext3D
{
2015 virtual void postSubBufferCHROMIUM(int x
, int y
, int width
, int height
)
2017 m_partialSwapRect
= gfx::Rect(x
, y
, width
, height
);
2020 virtual WebString
getString(WGC3Denum name
)
2022 if (name
== GL_EXTENSIONS
)
2023 return WebString("GL_CHROMIUM_post_sub_buffer GL_CHROMIUM_set_visibility");
2028 gfx::Rect
partialSwapRect() const { return m_partialSwapRect
; }
2031 gfx::Rect m_partialSwapRect
;
2034 // Make sure damage tracking propagates all the way to the graphics context,
2035 // where it should request to swap only the subBuffer that is damaged.
2036 TEST_P(LayerTreeHostImplTest
, partialSwapReceivesDamageRect
)
2038 scoped_ptr
<GraphicsContext
> outputSurface
= FakeWebCompositorOutputSurface::create(scoped_ptr
<WebKit::WebGraphicsContext3D
>(new PartialSwapTrackerContext
)).PassAs
<GraphicsContext
>();
2039 PartialSwapTrackerContext
* partialSwapTracker
= static_cast<PartialSwapTrackerContext
*>(outputSurface
->context3D());
2041 // This test creates its own LayerTreeHostImpl, so
2042 // that we can force partial swap enabled.
2043 LayerTreeSettings settings
;
2044 settings
.partialSwapEnabled
= true;
2045 scoped_ptr
<LayerTreeHostImpl
> layerTreeHostImpl
= LayerTreeHostImpl::create(settings
, this, &m_proxy
);
2046 layerTreeHostImpl
->initializeRenderer(outputSurface
.Pass());
2047 layerTreeHostImpl
->setViewportSize(gfx::Size(500, 500), gfx::Size(500, 500));
2049 scoped_ptr
<LayerImpl
> root
= FakeDrawableLayerImpl::create(1);
2050 scoped_ptr
<LayerImpl
> child
= FakeDrawableLayerImpl::create(2);
2051 child
->setPosition(gfx::PointF(12, 13));
2052 child
->setAnchorPoint(gfx::PointF(0, 0));
2053 child
->setBounds(gfx::Size(14, 15));
2054 child
->setContentBounds(gfx::Size(14, 15));
2055 child
->setDrawsContent(true);
2056 root
->setAnchorPoint(gfx::PointF(0, 0));
2057 root
->setBounds(gfx::Size(500, 500));
2058 root
->setContentBounds(gfx::Size(500, 500));
2059 root
->setDrawsContent(true);
2060 root
->addChild(child
.Pass());
2061 layerTreeHostImpl
->setRootLayer(root
.Pass());
2063 LayerTreeHostImpl::FrameData frame
;
2065 // First frame, the entire screen should get swapped.
2066 EXPECT_TRUE(layerTreeHostImpl
->prepareToDraw(frame
));
2067 layerTreeHostImpl
->drawLayers(frame
);
2068 layerTreeHostImpl
->didDrawAllLayers(frame
);
2069 layerTreeHostImpl
->swapBuffers();
2070 gfx::Rect actualSwapRect
= partialSwapTracker
->partialSwapRect();
2071 gfx::Rect expectedSwapRect
= gfx::Rect(gfx::Point(), gfx::Size(500, 500));
2072 EXPECT_EQ(expectedSwapRect
.x(), actualSwapRect
.x());
2073 EXPECT_EQ(expectedSwapRect
.y(), actualSwapRect
.y());
2074 EXPECT_EQ(expectedSwapRect
.width(), actualSwapRect
.width());
2075 EXPECT_EQ(expectedSwapRect
.height(), actualSwapRect
.height());
2077 // Second frame, only the damaged area should get swapped. Damage should be the union
2078 // of old and new child rects.
2079 // expected damage rect: gfx::Rect(gfx::Point(), gfx::Size(26, 28));
2080 // expected swap rect: vertically flipped, with origin at bottom left corner.
2081 layerTreeHostImpl
->rootLayer()->children()[0]->setPosition(gfx::PointF(0, 0));
2082 EXPECT_TRUE(layerTreeHostImpl
->prepareToDraw(frame
));
2083 layerTreeHostImpl
->drawLayers(frame
);
2084 m_hostImpl
->didDrawAllLayers(frame
);
2085 layerTreeHostImpl
->swapBuffers();
2086 actualSwapRect
= partialSwapTracker
->partialSwapRect();
2087 expectedSwapRect
= gfx::Rect(gfx::Point(0, 500-28), gfx::Size(26, 28));
2088 EXPECT_EQ(expectedSwapRect
.x(), actualSwapRect
.x());
2089 EXPECT_EQ(expectedSwapRect
.y(), actualSwapRect
.y());
2090 EXPECT_EQ(expectedSwapRect
.width(), actualSwapRect
.width());
2091 EXPECT_EQ(expectedSwapRect
.height(), actualSwapRect
.height());
2093 // Make sure that partial swap is constrained to the viewport dimensions
2094 // expected damage rect: gfx::Rect(gfx::Point(), gfx::Size(500, 500));
2095 // expected swap rect: flipped damage rect, but also clamped to viewport
2096 layerTreeHostImpl
->setViewportSize(gfx::Size(10, 10), gfx::Size(10, 10));
2097 layerTreeHostImpl
->rootLayer()->setOpacity(0.7f
); // this will damage everything
2098 EXPECT_TRUE(layerTreeHostImpl
->prepareToDraw(frame
));
2099 layerTreeHostImpl
->drawLayers(frame
);
2100 m_hostImpl
->didDrawAllLayers(frame
);
2101 layerTreeHostImpl
->swapBuffers();
2102 actualSwapRect
= partialSwapTracker
->partialSwapRect();
2103 expectedSwapRect
= gfx::Rect(gfx::Point(), gfx::Size(10, 10));
2104 EXPECT_EQ(expectedSwapRect
.x(), actualSwapRect
.x());
2105 EXPECT_EQ(expectedSwapRect
.y(), actualSwapRect
.y());
2106 EXPECT_EQ(expectedSwapRect
.width(), actualSwapRect
.width());
2107 EXPECT_EQ(expectedSwapRect
.height(), actualSwapRect
.height());
2110 TEST_P(LayerTreeHostImplTest
, rootLayerDoesntCreateExtraSurface
)
2112 scoped_ptr
<LayerImpl
> root
= FakeDrawableLayerImpl::create(1);
2113 scoped_ptr
<LayerImpl
> child
= FakeDrawableLayerImpl::create(2);
2114 child
->setAnchorPoint(gfx::PointF(0, 0));
2115 child
->setBounds(gfx::Size(10, 10));
2116 child
->setContentBounds(gfx::Size(10, 10));
2117 child
->setDrawsContent(true);
2118 root
->setAnchorPoint(gfx::PointF(0, 0));
2119 root
->setBounds(gfx::Size(10, 10));
2120 root
->setContentBounds(gfx::Size(10, 10));
2121 root
->setDrawsContent(true);
2122 root
->setOpacity(0.7f
);
2123 root
->addChild(child
.Pass());
2125 m_hostImpl
->setRootLayer(root
.Pass());
2127 LayerTreeHostImpl::FrameData frame
;
2129 EXPECT_TRUE(m_hostImpl
->prepareToDraw(frame
));
2130 EXPECT_EQ(1u, frame
.renderSurfaceLayerList
->size());
2131 EXPECT_EQ(1u, frame
.renderPasses
.size());
2132 m_hostImpl
->didDrawAllLayers(frame
);
2137 class FakeLayerWithQuads
: public LayerImpl
{
2139 static scoped_ptr
<LayerImpl
> create(int id
) { return scoped_ptr
<LayerImpl
>(new FakeLayerWithQuads(id
)); }
2141 virtual void appendQuads(QuadSink
& quadSink
, AppendQuadsData
& appendQuadsData
) OVERRIDE
2143 SharedQuadState
* sharedQuadState
= quadSink
.useSharedQuadState(createSharedQuadState());
2145 SkColor gray
= SkColorSetRGB(100, 100, 100);
2146 gfx::Rect
quadRect(gfx::Point(0, 0), contentBounds());
2147 scoped_ptr
<SolidColorDrawQuad
> myQuad
= SolidColorDrawQuad::Create();
2148 myQuad
->SetNew(sharedQuadState
, quadRect
, gray
);
2149 quadSink
.append(myQuad
.PassAs
<DrawQuad
>(), appendQuadsData
);
2153 FakeLayerWithQuads(int id
)
2161 class MockContext
: public FakeWebGraphicsContext3D
{
2163 MOCK_METHOD1(useProgram
, void(WebGLId program
));
2164 MOCK_METHOD5(uniform4f
, void(WGC3Dint location
, WGC3Dfloat x
, WGC3Dfloat y
, WGC3Dfloat z
, WGC3Dfloat w
));
2165 MOCK_METHOD4(uniformMatrix4fv
, void(WGC3Dint location
, WGC3Dsizei count
, WGC3Dboolean transpose
, const WGC3Dfloat
* value
));
2166 MOCK_METHOD4(drawElements
, void(WGC3Denum mode
, WGC3Dsizei count
, WGC3Denum type
, WGC3Dintptr offset
));
2167 MOCK_METHOD1(getString
, WebString(WGC3Denum name
));
2168 MOCK_METHOD0(getRequestableExtensionsCHROMIUM
, WebString());
2169 MOCK_METHOD1(enable
, void(WGC3Denum cap
));
2170 MOCK_METHOD1(disable
, void(WGC3Denum cap
));
2171 MOCK_METHOD4(scissor
, void(WGC3Dint x
, WGC3Dint y
, WGC3Dsizei width
, WGC3Dsizei height
));
2174 class MockContextHarness
{
2176 MockContext
* m_context
;
2178 MockContextHarness(MockContext
* context
)
2179 : m_context(context
)
2181 // Catch "uninteresting" calls
2182 EXPECT_CALL(*m_context
, useProgram(_
))
2185 EXPECT_CALL(*m_context
, drawElements(_
, _
, _
, _
))
2188 // These are not asserted
2189 EXPECT_CALL(*m_context
, uniformMatrix4fv(_
, _
, _
, _
))
2190 .WillRepeatedly(Return());
2192 EXPECT_CALL(*m_context
, uniform4f(_
, _
, _
, _
, _
))
2193 .WillRepeatedly(Return());
2195 // Any other strings are empty
2196 EXPECT_CALL(*m_context
, getString(_
))
2197 .WillRepeatedly(Return(WebString()));
2199 // Support for partial swap, if needed
2200 EXPECT_CALL(*m_context
, getString(GL_EXTENSIONS
))
2201 .WillRepeatedly(Return(WebString("GL_CHROMIUM_post_sub_buffer")));
2203 EXPECT_CALL(*m_context
, getRequestableExtensionsCHROMIUM())
2204 .WillRepeatedly(Return(WebString("GL_CHROMIUM_post_sub_buffer")));
2206 // Any un-sanctioned calls to enable() are OK
2207 EXPECT_CALL(*m_context
, enable(_
))
2208 .WillRepeatedly(Return());
2210 // Any un-sanctioned calls to disable() are OK
2211 EXPECT_CALL(*m_context
, disable(_
))
2212 .WillRepeatedly(Return());
2215 void mustDrawSolidQuad()
2217 EXPECT_CALL(*m_context
, drawElements(GL_TRIANGLES
, 6, GL_UNSIGNED_SHORT
, 0))
2219 .RetiresOnSaturation();
2221 // 1 is hardcoded return value of fake createProgram()
2222 EXPECT_CALL(*m_context
, useProgram(1))
2224 .RetiresOnSaturation();
2228 void mustSetScissor(int x
, int y
, int width
, int height
)
2230 EXPECT_CALL(*m_context
, enable(GL_SCISSOR_TEST
))
2231 .WillRepeatedly(Return());
2233 EXPECT_CALL(*m_context
, scissor(x
, y
, width
, height
))
2235 .WillRepeatedly(Return());
2238 void mustSetNoScissor()
2240 EXPECT_CALL(*m_context
, disable(GL_SCISSOR_TEST
))
2241 .WillRepeatedly(Return());
2243 EXPECT_CALL(*m_context
, enable(GL_SCISSOR_TEST
))
2246 EXPECT_CALL(*m_context
, scissor(_
, _
, _
, _
))
2251 TEST_P(LayerTreeHostImplTest
, noPartialSwap
)
2253 scoped_ptr
<GraphicsContext
> context
= FakeWebCompositorOutputSurface::create(scoped_ptr
<WebGraphicsContext3D
>(new MockContext
)).PassAs
<GraphicsContext
>();
2254 MockContext
* mockContext
= static_cast<MockContext
*>(context
->context3D());
2255 MockContextHarness
harness(mockContext
);
2258 scoped_ptr
<LayerTreeHostImpl
> myHostImpl
= createLayerTreeHost(false, context
.Pass(), FakeLayerWithQuads::create(1));
2260 // without partial swap, and no clipping, no scissor is set.
2261 harness
.mustDrawSolidQuad();
2262 harness
.mustSetNoScissor();
2264 LayerTreeHostImpl::FrameData frame
;
2265 EXPECT_TRUE(myHostImpl
->prepareToDraw(frame
));
2266 myHostImpl
->drawLayers(frame
);
2267 myHostImpl
->didDrawAllLayers(frame
);
2269 Mock::VerifyAndClearExpectations(&mockContext
);
2271 // without partial swap, but a layer does clip its subtree, one scissor is set.
2272 myHostImpl
->rootLayer()->setMasksToBounds(true);
2273 harness
.mustDrawSolidQuad();
2274 harness
.mustSetScissor(0, 0, 10, 10);
2276 LayerTreeHostImpl::FrameData frame
;
2277 EXPECT_TRUE(myHostImpl
->prepareToDraw(frame
));
2278 myHostImpl
->drawLayers(frame
);
2279 myHostImpl
->didDrawAllLayers(frame
);
2281 Mock::VerifyAndClearExpectations(&mockContext
);
2284 TEST_P(LayerTreeHostImplTest
, partialSwap
)
2286 scoped_ptr
<GraphicsContext
> context
= FakeWebCompositorOutputSurface::create(scoped_ptr
<WebKit::WebGraphicsContext3D
>(new MockContext
)).PassAs
<GraphicsContext
>();
2287 MockContext
* mockContext
= static_cast<MockContext
*>(context
->context3D());
2288 MockContextHarness
harness(mockContext
);
2290 scoped_ptr
<LayerTreeHostImpl
> myHostImpl
= createLayerTreeHost(true, context
.Pass(), FakeLayerWithQuads::create(1));
2292 // The first frame is not a partially-swapped one.
2293 harness
.mustSetScissor(0, 0, 10, 10);
2294 harness
.mustDrawSolidQuad();
2296 LayerTreeHostImpl::FrameData frame
;
2297 EXPECT_TRUE(myHostImpl
->prepareToDraw(frame
));
2298 myHostImpl
->drawLayers(frame
);
2299 myHostImpl
->didDrawAllLayers(frame
);
2301 Mock::VerifyAndClearExpectations(&mockContext
);
2303 // Damage a portion of the frame.
2304 myHostImpl
->rootLayer()->setUpdateRect(gfx::Rect(0, 0, 2, 3));
2306 // The second frame will be partially-swapped (the y coordinates are flipped).
2307 harness
.mustSetScissor(0, 7, 2, 3);
2308 harness
.mustDrawSolidQuad();
2310 LayerTreeHostImpl::FrameData frame
;
2311 EXPECT_TRUE(myHostImpl
->prepareToDraw(frame
));
2312 myHostImpl
->drawLayers(frame
);
2313 myHostImpl
->didDrawAllLayers(frame
);
2315 Mock::VerifyAndClearExpectations(&mockContext
);
2318 class PartialSwapContext
: public FakeWebGraphicsContext3D
{
2320 WebString
getString(WGC3Denum name
)
2322 if (name
== GL_EXTENSIONS
)
2323 return WebString("GL_CHROMIUM_post_sub_buffer");
2327 WebString
getRequestableExtensionsCHROMIUM()
2329 return WebString("GL_CHROMIUM_post_sub_buffer");
2332 // Unlimited texture size.
2333 virtual void getIntegerv(WGC3Denum pname
, WGC3Dint
* value
)
2335 if (pname
== GL_MAX_TEXTURE_SIZE
)
2340 static scoped_ptr
<LayerTreeHostImpl
> setupLayersForOpacity(bool partialSwap
, LayerTreeHostImplClient
* client
, Proxy
* proxy
)
2342 scoped_ptr
<GraphicsContext
> context
= FakeWebCompositorOutputSurface::create(scoped_ptr
<WebKit::WebGraphicsContext3D
>(new PartialSwapContext
)).PassAs
<GraphicsContext
>();
2344 LayerTreeSettings settings
;
2345 settings
.partialSwapEnabled
= partialSwap
;
2346 scoped_ptr
<LayerTreeHostImpl
> myHostImpl
= LayerTreeHostImpl::create(settings
, client
, proxy
);
2347 myHostImpl
->initializeRenderer(context
.Pass());
2348 myHostImpl
->setViewportSize(gfx::Size(100, 100), gfx::Size(100, 100));
2351 Layers are created as follows:
2353 +--------------------+
2357 | | +-------------------+
2359 | | +-------------------+
2364 +--------------------+
2366 Layers 1, 2 have render surfaces
2368 scoped_ptr
<LayerImpl
> root
= LayerImpl::create(1);
2369 scoped_ptr
<LayerImpl
> child
= LayerImpl::create(2);
2370 scoped_ptr
<LayerImpl
> grandChild
= FakeLayerWithQuads::create(3);
2372 gfx::Rect
rootRect(0, 0, 100, 100);
2373 gfx::Rect
childRect(10, 10, 50, 50);
2374 gfx::Rect
grandChildRect(5, 5, 150, 150);
2376 root
->createRenderSurface();
2377 root
->setAnchorPoint(gfx::PointF(0, 0));
2378 root
->setPosition(gfx::PointF(rootRect
.x(), rootRect
.y()));
2379 root
->setBounds(gfx::Size(rootRect
.width(), rootRect
.height()));
2380 root
->setContentBounds(root
->bounds());
2381 root
->setVisibleContentRect(rootRect
);
2382 root
->setDrawsContent(false);
2383 root
->renderSurface()->setContentRect(gfx::Rect(gfx::Point(), gfx::Size(rootRect
.width(), rootRect
.height())));
2385 child
->setAnchorPoint(gfx::PointF(0, 0));
2386 child
->setPosition(gfx::PointF(childRect
.x(), childRect
.y()));
2387 child
->setOpacity(0.5f
);
2388 child
->setBounds(gfx::Size(childRect
.width(), childRect
.height()));
2389 child
->setContentBounds(child
->bounds());
2390 child
->setVisibleContentRect(childRect
);
2391 child
->setDrawsContent(false);
2392 child
->setForceRenderSurface(true);
2394 grandChild
->setAnchorPoint(gfx::PointF(0, 0));
2395 grandChild
->setPosition(gfx::Point(grandChildRect
.x(), grandChildRect
.y()));
2396 grandChild
->setBounds(gfx::Size(grandChildRect
.width(), grandChildRect
.height()));
2397 grandChild
->setContentBounds(grandChild
->bounds());
2398 grandChild
->setVisibleContentRect(grandChildRect
);
2399 grandChild
->setDrawsContent(true);
2401 child
->addChild(grandChild
.Pass());
2402 root
->addChild(child
.Pass());
2404 myHostImpl
->setRootLayer(root
.Pass());
2405 return myHostImpl
.Pass();
2408 TEST_P(LayerTreeHostImplTest
, contributingLayerEmptyScissorPartialSwap
)
2410 scoped_ptr
<LayerTreeHostImpl
> myHostImpl
= setupLayersForOpacity(true, this, &m_proxy
);
2413 LayerTreeHostImpl::FrameData frame
;
2414 EXPECT_TRUE(myHostImpl
->prepareToDraw(frame
));
2416 // Just for consistency, the most interesting stuff already happened
2417 myHostImpl
->drawLayers(frame
);
2418 myHostImpl
->didDrawAllLayers(frame
);
2420 // Verify all quads have been computed
2421 ASSERT_EQ(2U, frame
.renderPasses
.size());
2422 ASSERT_EQ(1U, frame
.renderPasses
[0]->quad_list
.size());
2423 ASSERT_EQ(1U, frame
.renderPasses
[1]->quad_list
.size());
2424 EXPECT_EQ(DrawQuad::SOLID_COLOR
, frame
.renderPasses
[0]->quad_list
[0]->material
);
2425 EXPECT_EQ(DrawQuad::RENDER_PASS
, frame
.renderPasses
[1]->quad_list
[0]->material
);
2429 TEST_P(LayerTreeHostImplTest
, contributingLayerEmptyScissorNoPartialSwap
)
2431 scoped_ptr
<LayerTreeHostImpl
> myHostImpl
= setupLayersForOpacity(false, this, &m_proxy
);
2434 LayerTreeHostImpl::FrameData frame
;
2435 EXPECT_TRUE(myHostImpl
->prepareToDraw(frame
));
2437 // Just for consistency, the most interesting stuff already happened
2438 myHostImpl
->drawLayers(frame
);
2439 myHostImpl
->didDrawAllLayers(frame
);
2441 // Verify all quads have been computed
2442 ASSERT_EQ(2U, frame
.renderPasses
.size());
2443 ASSERT_EQ(1U, frame
.renderPasses
[0]->quad_list
.size());
2444 ASSERT_EQ(1U, frame
.renderPasses
[1]->quad_list
.size());
2445 EXPECT_EQ(DrawQuad::SOLID_COLOR
, frame
.renderPasses
[0]->quad_list
[0]->material
);
2446 EXPECT_EQ(DrawQuad::RENDER_PASS
, frame
.renderPasses
[1]->quad_list
[0]->material
);
2450 // Make sure that context lost notifications are propagated through the tree.
2451 class ContextLostNotificationCheckLayer
: public LayerImpl
{
2453 static scoped_ptr
<LayerImpl
> create(int id
) { return scoped_ptr
<LayerImpl
>(new ContextLostNotificationCheckLayer(id
)); }
2455 virtual void didLoseContext() OVERRIDE
2457 m_didLoseContextCalled
= true;
2460 bool didLoseContextCalled() const { return m_didLoseContextCalled
; }
2463 explicit ContextLostNotificationCheckLayer(int id
)
2465 , m_didLoseContextCalled(false)
2469 bool m_didLoseContextCalled
;
2472 TEST_P(LayerTreeHostImplTest
, contextLostAndRestoredNotificationSentToAllLayers
)
2474 m_hostImpl
->setRootLayer(ContextLostNotificationCheckLayer::create(1));
2475 ContextLostNotificationCheckLayer
* root
= static_cast<ContextLostNotificationCheckLayer
*>(m_hostImpl
->rootLayer());
2477 root
->addChild(ContextLostNotificationCheckLayer::create(1));
2478 ContextLostNotificationCheckLayer
* layer1
= static_cast<ContextLostNotificationCheckLayer
*>(root
->children()[0]);
2480 layer1
->addChild(ContextLostNotificationCheckLayer::create(2));
2481 ContextLostNotificationCheckLayer
* layer2
= static_cast<ContextLostNotificationCheckLayer
*>(layer1
->children()[0]);
2483 EXPECT_FALSE(root
->didLoseContextCalled());
2484 EXPECT_FALSE(layer1
->didLoseContextCalled());
2485 EXPECT_FALSE(layer2
->didLoseContextCalled());
2487 m_hostImpl
->initializeRenderer(createContext());
2489 EXPECT_TRUE(root
->didLoseContextCalled());
2490 EXPECT_TRUE(layer1
->didLoseContextCalled());
2491 EXPECT_TRUE(layer2
->didLoseContextCalled());
2494 TEST_P(LayerTreeHostImplTest
, finishAllRenderingAfterContextLost
)
2496 LayerTreeSettings settings
;
2497 m_hostImpl
= LayerTreeHostImpl::create(settings
, this, &m_proxy
);
2499 // The context initialization will fail, but we should still be able to call finishAllRendering() without any ill effects.
2500 m_hostImpl
->initializeRenderer(FakeWebCompositorOutputSurface::create(scoped_ptr
<WebKit::WebGraphicsContext3D
>(new FakeWebGraphicsContext3DMakeCurrentFails
)).PassAs
<GraphicsContext
>());
2501 m_hostImpl
->finishAllRendering();
2504 class FakeWebGraphicsContext3DMakeCurrentFailsEventually
: public FakeWebGraphicsContext3D
{
2506 explicit FakeWebGraphicsContext3DMakeCurrentFailsEventually(unsigned succeedCount
) : m_succeedCount(succeedCount
) { }
2507 virtual bool makeContextCurrent() {
2508 if (!m_succeedCount
)
2515 unsigned m_succeedCount
;
2518 TEST_P(LayerTreeHostImplTest
, contextLostDuringInitialize
)
2520 LayerTreeSettings settings
;
2521 m_hostImpl
= LayerTreeHostImpl::create(settings
, this, &m_proxy
);
2523 // Initialize into a known successful state.
2524 EXPECT_TRUE(m_hostImpl
->initializeRenderer(createContext()));
2525 EXPECT_TRUE(m_hostImpl
->context());
2526 EXPECT_TRUE(m_hostImpl
->renderer());
2527 EXPECT_TRUE(m_hostImpl
->resourceProvider());
2529 // We will make the context get lost after a numer of makeContextCurrent
2530 // calls. The exact number of calls to make it succeed is dependent on the
2531 // implementation and doesn't really matter (i.e. can be changed to make the
2532 // tests pass after some refactoring).
2533 const unsigned kMakeCurrentSuccessesNeededForSuccessfulInitialization
= 3;
2535 for (unsigned i
= 0; i
< kMakeCurrentSuccessesNeededForSuccessfulInitialization
; ++i
) {
2536 // The context will get lost during initialization, we shouldn't crash. We
2537 // should also be in a consistent state.
2538 EXPECT_FALSE(m_hostImpl
->initializeRenderer(FakeWebCompositorOutputSurface::create(scoped_ptr
<WebKit::WebGraphicsContext3D
>(new FakeWebGraphicsContext3DMakeCurrentFailsEventually(i
))).PassAs
<GraphicsContext
>()));
2539 EXPECT_EQ(0, m_hostImpl
->context());
2540 EXPECT_EQ(0, m_hostImpl
->renderer());
2541 EXPECT_EQ(0, m_hostImpl
->resourceProvider());
2542 EXPECT_TRUE(m_hostImpl
->initializeRenderer(createContext()));
2545 EXPECT_TRUE(m_hostImpl
->initializeRenderer(FakeWebCompositorOutputSurface::create(scoped_ptr
<WebKit::WebGraphicsContext3D
>(new FakeWebGraphicsContext3DMakeCurrentFailsEventually(kMakeCurrentSuccessesNeededForSuccessfulInitialization
))).PassAs
<GraphicsContext
>()));
2546 EXPECT_TRUE(m_hostImpl
->context());
2547 EXPECT_TRUE(m_hostImpl
->renderer());
2548 EXPECT_TRUE(m_hostImpl
->resourceProvider());
2551 // Fake WebGraphicsContext3D that will cause a failure if trying to use a
2552 // resource that wasn't created by it (resources created by
2553 // FakeWebGraphicsContext3D have an id of 1).
2554 class StrictWebGraphicsContext3D
: public FakeWebGraphicsContext3D
{
2556 StrictWebGraphicsContext3D()
2557 : FakeWebGraphicsContext3D()
2559 m_nextTextureId
= 8; // Start allocating texture ids larger than any other resource IDs so we can tell if someone's mixing up their resource types.
2562 virtual WebGLId
createBuffer() { return 2; }
2563 virtual WebGLId
createFramebuffer() { return 3; }
2564 virtual WebGLId
createProgram() { return 4; }
2565 virtual WebGLId
createRenderbuffer() { return 5; }
2566 virtual WebGLId
createShader(WGC3Denum
) { return 6; }
2568 static const WebGLId kExternalTextureId
= 7;
2570 virtual void deleteBuffer(WebGLId id
)
2573 ADD_FAILURE() << "Trying to delete buffer id " << id
;
2576 virtual void deleteFramebuffer(WebGLId id
)
2579 ADD_FAILURE() << "Trying to delete framebuffer id " << id
;
2582 virtual void deleteProgram(WebGLId id
)
2585 ADD_FAILURE() << "Trying to delete program id " << id
;
2588 virtual void deleteRenderbuffer(WebGLId id
)
2591 ADD_FAILURE() << "Trying to delete renderbuffer id " << id
;
2594 virtual void deleteShader(WebGLId id
)
2597 ADD_FAILURE() << "Trying to delete shader id " << id
;
2600 virtual WebGLId
createTexture()
2602 unsigned textureId
= FakeWebGraphicsContext3D::createTexture();
2603 m_allocatedTextureIds
.insert(textureId
);
2606 virtual void deleteTexture(WebGLId id
)
2608 if (id
== kExternalTextureId
)
2609 ADD_FAILURE() << "Trying to delete external texture";
2610 if (!ContainsKey(m_allocatedTextureIds
, id
))
2611 ADD_FAILURE() << "Trying to delete texture id " << id
;
2612 m_allocatedTextureIds
.erase(id
);
2615 virtual void bindBuffer(WGC3Denum
, WebGLId id
)
2618 ADD_FAILURE() << "Trying to bind buffer id " << id
;
2621 virtual void bindFramebuffer(WGC3Denum
, WebGLId id
)
2624 ADD_FAILURE() << "Trying to bind framebuffer id " << id
;
2627 virtual void useProgram(WebGLId id
)
2630 ADD_FAILURE() << "Trying to use program id " << id
;
2633 virtual void bindRenderbuffer(WGC3Denum
, WebGLId id
)
2636 ADD_FAILURE() << "Trying to bind renderbuffer id " << id
;
2639 virtual void attachShader(WebGLId program
, WebGLId shader
)
2641 if ((program
!= 4) || (shader
!= 6))
2642 ADD_FAILURE() << "Trying to attach shader id " << shader
<< " to program id " << program
;
2645 virtual void bindTexture(WGC3Denum
, WebGLId id
)
2647 if (id
&& id
!= kExternalTextureId
&& !ContainsKey(m_allocatedTextureIds
, id
))
2648 ADD_FAILURE() << "Trying to bind texture id " << id
;
2652 base::hash_set
<unsigned> m_allocatedTextureIds
;
2655 // Fake WebVideoFrame wrapper of media::VideoFrame.
2656 class FakeVideoFrame
: public WebVideoFrame
{
2658 explicit FakeVideoFrame(const scoped_refptr
<VideoFrame
>& frame
) : m_frame(frame
) { }
2659 virtual ~FakeVideoFrame() { }
2661 virtual Format
format() const { NOTREACHED(); return FormatInvalid
; }
2662 virtual unsigned width() const { NOTREACHED(); return 0; }
2663 virtual unsigned height() const { NOTREACHED(); return 0; }
2664 virtual unsigned planes() const { NOTREACHED(); return 0; }
2665 virtual int stride(unsigned plane
) const { NOTREACHED(); return 0; }
2666 virtual const void* data(unsigned plane
) const { NOTREACHED(); return NULL
; }
2667 virtual unsigned textureId() const { NOTREACHED(); return 0; }
2668 virtual unsigned textureTarget() const { NOTREACHED(); return 0; }
2669 virtual WebKit::WebRect
visibleRect() const { NOTREACHED(); return WebKit::WebRect(0, 0, 0, 0); }
2670 virtual WebKit::WebSize
textureSize() const { NOTREACHED(); return WebKit::WebSize(4, 4); }
2672 static VideoFrame
* toVideoFrame(WebVideoFrame
* web_video_frame
) {
2673 FakeVideoFrame
* wrapped_frame
=
2674 static_cast<FakeVideoFrame
*>(web_video_frame
);
2676 return wrapped_frame
->m_frame
.get();
2681 scoped_refptr
<VideoFrame
> m_frame
;
2684 // Fake video frame provider that always provides the same FakeVideoFrame.
2685 class FakeVideoFrameProvider
: public WebVideoFrameProvider
{
2687 FakeVideoFrameProvider() : m_frame(0), m_client(0) { }
2688 virtual ~FakeVideoFrameProvider()
2691 m_client
->stopUsingProvider();
2694 virtual void setVideoFrameProviderClient(Client
* client
) { m_client
= client
; }
2695 virtual WebVideoFrame
* getCurrentFrame() { return m_frame
; }
2696 virtual void putCurrentFrame(WebVideoFrame
*) { }
2698 void setFrame(WebVideoFrame
* frame
) { m_frame
= frame
; }
2701 WebVideoFrame
* m_frame
;
2705 class StrictWebGraphicsContext3DWithIOSurface
: public StrictWebGraphicsContext3D
{
2707 virtual WebString
getString(WGC3Denum name
) OVERRIDE
2709 if (name
== GL_EXTENSIONS
)
2710 return WebString("GL_CHROMIUM_iosurface GL_ARB_texture_rectangle");
2716 class FakeWebGraphicsContext3DWithIOSurface
: public FakeWebGraphicsContext3D
{
2718 virtual WebString
getString(WGC3Denum name
) OVERRIDE
2720 if (name
== GL_EXTENSIONS
)
2721 return WebString("GL_CHROMIUM_iosurface GL_ARB_texture_rectangle");
2727 class FakeWebScrollbarThemeGeometryNonEmpty
: public FakeWebScrollbarThemeGeometry
{
2728 virtual WebRect
trackRect(WebScrollbar
*) OVERRIDE
{ return WebRect(0, 0, 10, 10); }
2729 virtual WebRect
thumbRect(WebScrollbar
*) OVERRIDE
{ return WebRect(0, 5, 5, 2); }
2730 virtual void splitTrack(WebScrollbar
*, const WebRect
& track
, WebRect
& startTrack
, WebRect
& thumb
, WebRect
& endTrack
) OVERRIDE
2732 thumb
= WebRect(0, 5, 5, 2);
2733 startTrack
= WebRect(0, 5, 0, 5);
2734 endTrack
= WebRect(0, 0, 0, 5);
2738 class FakeScrollbarLayerImpl
: public ScrollbarLayerImpl
{
2740 static scoped_ptr
<FakeScrollbarLayerImpl
> create(int id
)
2742 return make_scoped_ptr(new FakeScrollbarLayerImpl(id
));
2745 void createResources(ResourceProvider
* provider
)
2749 gfx::Size
size(10, 10);
2750 GLenum format
= GL_RGBA
;
2751 ResourceProvider::TextureUsageHint hint
= ResourceProvider::TextureUsageAny
;
2752 setScrollbarGeometry(ScrollbarGeometryFixedThumb::create(FakeWebScrollbarThemeGeometryNonEmpty::create()));
2754 setBackTrackResourceId(provider
->createResource(pool
, size
, format
, hint
));
2755 setForeTrackResourceId(provider
->createResource(pool
, size
, format
, hint
));
2756 setThumbResourceId(provider
->createResource(pool
, size
, format
, hint
));
2760 explicit FakeScrollbarLayerImpl(int id
)
2761 : ScrollbarLayerImpl(id
)
2766 static inline scoped_ptr
<RenderPass
> createRenderPassWithResource(ResourceProvider
* provider
)
2768 ResourceProvider::ResourceId resourceId
= provider
->createResource(0, gfx::Size(1, 1), GL_RGBA
, ResourceProvider::TextureUsageAny
);
2770 scoped_ptr
<TestRenderPass
> pass
= TestRenderPass::Create();
2771 pass
->SetNew(RenderPass::Id(1, 1), gfx::Rect(0, 0, 1, 1), gfx::Rect(0, 0, 1, 1), gfx::Transform());
2772 scoped_ptr
<SharedQuadState
> sharedState
= SharedQuadState::Create();
2773 sharedState
->SetAll(gfx::Transform(), gfx::Rect(0, 0, 1, 1), gfx::Rect(0, 0, 1, 1), gfx::Rect(0, 0, 1, 1), false, 1);
2774 scoped_ptr
<TextureDrawQuad
> quad
= TextureDrawQuad::Create();
2775 quad
->SetNew(sharedState
.get(), gfx::Rect(0, 0, 1, 1), gfx::Rect(0, 0, 1, 1), resourceId
, false, gfx::RectF(0, 0, 1, 1), false);
2777 pass
->AppendSharedQuadState(sharedState
.Pass());
2778 pass
->AppendQuad(quad
.PassAs
<DrawQuad
>());
2780 return pass
.PassAs
<RenderPass
>();
2783 TEST_P(LayerTreeHostImplTest
, dontUseOldResourcesAfterLostContext
)
2787 scoped_ptr
<LayerImpl
> rootLayer(LayerImpl::create(layerId
++));
2788 rootLayer
->setBounds(gfx::Size(10, 10));
2789 rootLayer
->setAnchorPoint(gfx::PointF(0, 0));
2791 scoped_ptr
<TiledLayerImpl
> tileLayer
= TiledLayerImpl::create(layerId
++);
2792 tileLayer
->setBounds(gfx::Size(10, 10));
2793 tileLayer
->setAnchorPoint(gfx::PointF(0, 0));
2794 tileLayer
->setContentBounds(gfx::Size(10, 10));
2795 tileLayer
->setDrawsContent(true);
2796 tileLayer
->setSkipsDraw(false);
2797 scoped_ptr
<LayerTilingData
> tilingData(LayerTilingData::create(gfx::Size(10, 10), LayerTilingData::NoBorderTexels
));
2798 tilingData
->setBounds(gfx::Size(10, 10));
2799 tileLayer
->setTilingData(*tilingData
);
2800 tileLayer
->pushTileProperties(0, 0, 1, gfx::Rect(0, 0, 10, 10), false);
2801 rootLayer
->addChild(tileLayer
.PassAs
<LayerImpl
>());
2803 scoped_ptr
<TextureLayerImpl
> textureLayer
= TextureLayerImpl::create(layerId
++);
2804 textureLayer
->setBounds(gfx::Size(10, 10));
2805 textureLayer
->setAnchorPoint(gfx::PointF(0, 0));
2806 textureLayer
->setContentBounds(gfx::Size(10, 10));
2807 textureLayer
->setDrawsContent(true);
2808 textureLayer
->setTextureId(StrictWebGraphicsContext3D::kExternalTextureId
);
2809 rootLayer
->addChild(textureLayer
.PassAs
<LayerImpl
>());
2811 scoped_ptr
<TiledLayerImpl
> maskLayer
= TiledLayerImpl::create(layerId
++);
2812 maskLayer
->setBounds(gfx::Size(10, 10));
2813 maskLayer
->setAnchorPoint(gfx::PointF(0, 0));
2814 maskLayer
->setContentBounds(gfx::Size(10, 10));
2815 maskLayer
->setDrawsContent(true);
2816 maskLayer
->setSkipsDraw(false);
2817 maskLayer
->setTilingData(*tilingData
);
2818 maskLayer
->pushTileProperties(0, 0, 1, gfx::Rect(0, 0, 10, 10), false);
2820 scoped_ptr
<TextureLayerImpl
> textureLayerWithMask
= TextureLayerImpl::create(layerId
++);
2821 textureLayerWithMask
->setBounds(gfx::Size(10, 10));
2822 textureLayerWithMask
->setAnchorPoint(gfx::PointF(0, 0));
2823 textureLayerWithMask
->setContentBounds(gfx::Size(10, 10));
2824 textureLayerWithMask
->setDrawsContent(true);
2825 textureLayerWithMask
->setTextureId(StrictWebGraphicsContext3D::kExternalTextureId
);
2826 textureLayerWithMask
->setMaskLayer(maskLayer
.PassAs
<LayerImpl
>());
2827 rootLayer
->addChild(textureLayerWithMask
.PassAs
<LayerImpl
>());
2829 FakeVideoFrame
videoFrame(VideoFrame::CreateColorFrame(gfx::Size(4, 4),
2831 base::TimeDelta()));
2832 VideoLayerImpl::FrameUnwrapper unwrapper
=
2833 base::Bind(FakeVideoFrame::toVideoFrame
);
2834 FakeVideoFrameProvider provider
;
2835 provider
.setFrame(&videoFrame
);
2836 scoped_ptr
<VideoLayerImpl
> videoLayer
= VideoLayerImpl::create(layerId
++, &provider
, unwrapper
);
2837 videoLayer
->setBounds(gfx::Size(10, 10));
2838 videoLayer
->setAnchorPoint(gfx::PointF(0, 0));
2839 videoLayer
->setContentBounds(gfx::Size(10, 10));
2840 videoLayer
->setDrawsContent(true);
2841 videoLayer
->setLayerTreeHostImpl(m_hostImpl
.get());
2842 rootLayer
->addChild(videoLayer
.PassAs
<LayerImpl
>());
2844 FakeVideoFrameProvider providerScaled
;
2845 scoped_ptr
<VideoLayerImpl
> videoLayerScaled
= VideoLayerImpl::create(layerId
++, &providerScaled
, unwrapper
);
2846 videoLayerScaled
->setBounds(gfx::Size(10, 10));
2847 videoLayerScaled
->setAnchorPoint(gfx::PointF(0, 0));
2848 videoLayerScaled
->setContentBounds(gfx::Size(10, 10));
2849 videoLayerScaled
->setDrawsContent(true);
2850 videoLayerScaled
->setLayerTreeHostImpl(m_hostImpl
.get());
2851 rootLayer
->addChild(videoLayerScaled
.PassAs
<LayerImpl
>());
2853 FakeVideoFrameProvider hwProvider
;
2854 scoped_ptr
<VideoLayerImpl
> hwVideoLayer
= VideoLayerImpl::create(layerId
++, &hwProvider
, unwrapper
);
2855 hwVideoLayer
->setBounds(gfx::Size(10, 10));
2856 hwVideoLayer
->setAnchorPoint(gfx::PointF(0, 0));
2857 hwVideoLayer
->setContentBounds(gfx::Size(10, 10));
2858 hwVideoLayer
->setDrawsContent(true);
2859 hwVideoLayer
->setLayerTreeHostImpl(m_hostImpl
.get());
2860 rootLayer
->addChild(hwVideoLayer
.PassAs
<LayerImpl
>());
2862 scoped_ptr
<IOSurfaceLayerImpl
> ioSurfaceLayer
= IOSurfaceLayerImpl::create(layerId
++);
2863 ioSurfaceLayer
->setBounds(gfx::Size(10, 10));
2864 ioSurfaceLayer
->setAnchorPoint(gfx::PointF(0, 0));
2865 ioSurfaceLayer
->setContentBounds(gfx::Size(10, 10));
2866 ioSurfaceLayer
->setDrawsContent(true);
2867 ioSurfaceLayer
->setIOSurfaceProperties(1, gfx::Size(10, 10));
2868 ioSurfaceLayer
->setLayerTreeHostImpl(m_hostImpl
.get());
2869 rootLayer
->addChild(ioSurfaceLayer
.PassAs
<LayerImpl
>());
2871 scoped_ptr
<HeadsUpDisplayLayerImpl
> hudLayer
= HeadsUpDisplayLayerImpl::create(layerId
++);
2872 hudLayer
->setBounds(gfx::Size(10, 10));
2873 hudLayer
->setAnchorPoint(gfx::PointF(0, 0));
2874 hudLayer
->setContentBounds(gfx::Size(10, 10));
2875 hudLayer
->setDrawsContent(true);
2876 hudLayer
->setLayerTreeHostImpl(m_hostImpl
.get());
2877 rootLayer
->addChild(hudLayer
.PassAs
<LayerImpl
>());
2879 scoped_ptr
<FakeScrollbarLayerImpl
> scrollbarLayer(FakeScrollbarLayerImpl::create(layerId
++));
2880 scrollbarLayer
->setBounds(gfx::Size(10, 10));
2881 scrollbarLayer
->setContentBounds(gfx::Size(10, 10));
2882 scrollbarLayer
->setDrawsContent(true);
2883 scrollbarLayer
->setLayerTreeHostImpl(m_hostImpl
.get());
2884 scrollbarLayer
->createResources(m_hostImpl
->resourceProvider());
2885 rootLayer
->addChild(scrollbarLayer
.PassAs
<LayerImpl
>());
2887 scoped_ptr
<DelegatedRendererLayerImpl
> delegatedRendererLayer(DelegatedRendererLayerImpl::create(layerId
++));
2888 delegatedRendererLayer
->setBounds(gfx::Size(10, 10));
2889 delegatedRendererLayer
->setContentBounds(gfx::Size(10, 10));
2890 delegatedRendererLayer
->setDrawsContent(true);
2891 delegatedRendererLayer
->setLayerTreeHostImpl(m_hostImpl
.get());
2892 ScopedPtrVector
<RenderPass
> passList
;
2893 passList
.append(createRenderPassWithResource(m_hostImpl
->resourceProvider()));
2894 delegatedRendererLayer
->setRenderPasses(passList
);
2895 EXPECT_TRUE(passList
.isEmpty());
2896 rootLayer
->addChild(delegatedRendererLayer
.PassAs
<LayerImpl
>());
2898 // Use a context that supports IOSurfaces
2899 m_hostImpl
->initializeRenderer(FakeWebCompositorOutputSurface::create(scoped_ptr
<WebKit::WebGraphicsContext3D
>(new FakeWebGraphicsContext3DWithIOSurface
)).PassAs
<GraphicsContext
>());
2901 FakeVideoFrame
hwVideoFrame(
2902 VideoFrame::WrapNativeTexture(
2903 m_hostImpl
->resourceProvider()->graphicsContext3D()->createTexture(),
2905 gfx::Size(4, 4), gfx::Rect(0, 0, 4, 4), gfx::Size(4, 4), base::TimeDelta(),
2906 VideoFrame::ReadPixelsCB(), base::Closure()));
2907 hwProvider
.setFrame(&hwVideoFrame
);
2909 FakeVideoFrame
videoFrameScaled(
2910 VideoFrame::WrapNativeTexture(
2911 m_hostImpl
->resourceProvider()->graphicsContext3D()->createTexture(),
2913 gfx::Size(4, 4), gfx::Rect(0, 0, 3, 2), gfx::Size(4, 4), base::TimeDelta(),
2914 VideoFrame::ReadPixelsCB(), base::Closure()));
2915 providerScaled
.setFrame(&videoFrameScaled
);
2917 m_hostImpl
->setRootLayer(rootLayer
.Pass());
2919 LayerTreeHostImpl::FrameData frame
;
2920 EXPECT_TRUE(m_hostImpl
->prepareToDraw(frame
));
2921 m_hostImpl
->drawLayers(frame
);
2922 m_hostImpl
->didDrawAllLayers(frame
);
2923 m_hostImpl
->swapBuffers();
2925 unsigned numResources
= m_hostImpl
->resourceProvider()->numResources();
2927 // Lose the context, replacing it with a StrictWebGraphicsContext3DWithIOSurface,
2928 // that will warn if any resource from the previous context gets used.
2929 m_hostImpl
->initializeRenderer(FakeWebCompositorOutputSurface::create(scoped_ptr
<WebKit::WebGraphicsContext3D
>(new StrictWebGraphicsContext3DWithIOSurface
)).PassAs
<GraphicsContext
>());
2931 // Create dummy resources so that looking up an old resource will get an
2932 // invalid texture id mapping.
2933 for (unsigned i
= 0; i
< numResources
; ++i
)
2934 m_hostImpl
->resourceProvider()->createResourceFromExternalTexture(StrictWebGraphicsContext3D::kExternalTextureId
);
2936 // The WebVideoFrameProvider is expected to recreate its textures after a
2937 // lost context (or not serve a frame).
2938 hwProvider
.setFrame(0);
2939 providerScaled
.setFrame(0);
2941 EXPECT_TRUE(m_hostImpl
->prepareToDraw(frame
));
2942 m_hostImpl
->drawLayers(frame
);
2943 m_hostImpl
->didDrawAllLayers(frame
);
2944 m_hostImpl
->swapBuffers();
2946 FakeVideoFrame
hwVideoFrame2(
2947 VideoFrame::WrapNativeTexture(
2948 m_hostImpl
->resourceProvider()->graphicsContext3D()->createTexture(),
2950 gfx::Size(4, 4), gfx::Rect(0, 0, 4, 4), gfx::Size(4, 4), base::TimeDelta(),
2951 VideoFrame::ReadPixelsCB(), base::Closure()));
2952 hwProvider
.setFrame(&hwVideoFrame2
);
2954 EXPECT_TRUE(m_hostImpl
->prepareToDraw(frame
));
2955 m_hostImpl
->drawLayers(frame
);
2956 m_hostImpl
->didDrawAllLayers(frame
);
2957 m_hostImpl
->swapBuffers();
2960 // Fake WebGraphicsContext3D that tracks the number of textures in use.
2961 class TrackingWebGraphicsContext3D
: public FakeWebGraphicsContext3D
{
2963 TrackingWebGraphicsContext3D()
2964 : FakeWebGraphicsContext3D()
2968 virtual WebGLId
createTexture() OVERRIDE
2970 WebGLId id
= FakeWebGraphicsContext3D::createTexture();
2972 m_textures
[id
] = true;
2977 virtual void deleteTexture(WebGLId id
) OVERRIDE
2979 if (m_textures
.find(id
) == m_textures
.end())
2982 m_textures
[id
] = false;
2986 virtual WebString
getString(WGC3Denum name
) OVERRIDE
2988 if (name
== GL_EXTENSIONS
)
2989 return WebString("GL_CHROMIUM_iosurface GL_ARB_texture_rectangle");
2994 unsigned numTextures() const { return m_numTextures
; }
2997 base::hash_map
<WebGLId
, bool> m_textures
;
2998 unsigned m_numTextures
;
3001 TEST_P(LayerTreeHostImplTest
, layersFreeTextures
)
3003 scoped_ptr
<LayerImpl
> rootLayer(LayerImpl::create(1));
3004 rootLayer
->setBounds(gfx::Size(10, 10));
3005 rootLayer
->setAnchorPoint(gfx::PointF(0, 0));
3007 scoped_ptr
<TiledLayerImpl
> tileLayer
= TiledLayerImpl::create(2);
3008 tileLayer
->setBounds(gfx::Size(10, 10));
3009 tileLayer
->setAnchorPoint(gfx::PointF(0, 0));
3010 tileLayer
->setContentBounds(gfx::Size(10, 10));
3011 tileLayer
->setDrawsContent(true);
3012 tileLayer
->setSkipsDraw(false);
3013 scoped_ptr
<LayerTilingData
> tilingData(LayerTilingData::create(gfx::Size(10, 10), LayerTilingData::NoBorderTexels
));
3014 tilingData
->setBounds(gfx::Size(10, 10));
3015 tileLayer
->setTilingData(*tilingData
);
3016 tileLayer
->pushTileProperties(0, 0, 1, gfx::Rect(0, 0, 10, 10), false);
3017 rootLayer
->addChild(tileLayer
.PassAs
<LayerImpl
>());
3019 scoped_ptr
<TextureLayerImpl
> textureLayer
= TextureLayerImpl::create(3);
3020 textureLayer
->setBounds(gfx::Size(10, 10));
3021 textureLayer
->setAnchorPoint(gfx::PointF(0, 0));
3022 textureLayer
->setContentBounds(gfx::Size(10, 10));
3023 textureLayer
->setDrawsContent(true);
3024 textureLayer
->setTextureId(1);
3025 rootLayer
->addChild(textureLayer
.PassAs
<LayerImpl
>());
3027 VideoLayerImpl::FrameUnwrapper unwrapper
=
3028 base::Bind(FakeVideoFrame::toVideoFrame
);
3029 FakeVideoFrameProvider provider
;
3030 scoped_ptr
<VideoLayerImpl
> videoLayer
= VideoLayerImpl::create(4, &provider
, unwrapper
);
3031 videoLayer
->setBounds(gfx::Size(10, 10));
3032 videoLayer
->setAnchorPoint(gfx::PointF(0, 0));
3033 videoLayer
->setContentBounds(gfx::Size(10, 10));
3034 videoLayer
->setDrawsContent(true);
3035 videoLayer
->setLayerTreeHostImpl(m_hostImpl
.get());
3036 rootLayer
->addChild(videoLayer
.PassAs
<LayerImpl
>());
3038 scoped_ptr
<IOSurfaceLayerImpl
> ioSurfaceLayer
= IOSurfaceLayerImpl::create(5);
3039 ioSurfaceLayer
->setBounds(gfx::Size(10, 10));
3040 ioSurfaceLayer
->setAnchorPoint(gfx::PointF(0, 0));
3041 ioSurfaceLayer
->setContentBounds(gfx::Size(10, 10));
3042 ioSurfaceLayer
->setDrawsContent(true);
3043 ioSurfaceLayer
->setIOSurfaceProperties(1, gfx::Size(10, 10));
3044 ioSurfaceLayer
->setLayerTreeHostImpl(m_hostImpl
.get());
3045 rootLayer
->addChild(ioSurfaceLayer
.PassAs
<LayerImpl
>());
3047 // Lose the context, replacing it with a TrackingWebGraphicsContext3D (which the LayerTreeHostImpl takes ownership of).
3048 scoped_ptr
<GraphicsContext
> outputSurface(FakeWebCompositorOutputSurface::create(scoped_ptr
<WebKit::WebGraphicsContext3D
>(new TrackingWebGraphicsContext3D
)));
3049 TrackingWebGraphicsContext3D
* trackingWebGraphicsContext
= static_cast<TrackingWebGraphicsContext3D
*>(outputSurface
->context3D());
3050 m_hostImpl
->initializeRenderer(outputSurface
.Pass());
3052 m_hostImpl
->setRootLayer(rootLayer
.Pass());
3054 LayerTreeHostImpl::FrameData frame
;
3055 EXPECT_TRUE(m_hostImpl
->prepareToDraw(frame
));
3056 m_hostImpl
->drawLayers(frame
);
3057 m_hostImpl
->didDrawAllLayers(frame
);
3058 m_hostImpl
->swapBuffers();
3060 EXPECT_GT(trackingWebGraphicsContext
->numTextures(), 0u);
3062 // Kill the layer tree.
3063 m_hostImpl
->setRootLayer(LayerImpl::create(100));
3064 // There should be no textures left in use after.
3065 EXPECT_EQ(0u, trackingWebGraphicsContext
->numTextures());
3068 class MockDrawQuadsToFillScreenContext
: public FakeWebGraphicsContext3D
{
3070 MOCK_METHOD1(useProgram
, void(WebGLId program
));
3071 MOCK_METHOD4(drawElements
, void(WGC3Denum mode
, WGC3Dsizei count
, WGC3Denum type
, WGC3Dintptr offset
));
3074 TEST_P(LayerTreeHostImplTest
, hasTransparentBackground
)
3076 scoped_ptr
<GraphicsContext
> context
= FakeWebCompositorOutputSurface::create(scoped_ptr
<WebKit::WebGraphicsContext3D
>(new MockDrawQuadsToFillScreenContext
)).PassAs
<GraphicsContext
>();
3077 MockDrawQuadsToFillScreenContext
* mockContext
= static_cast<MockDrawQuadsToFillScreenContext
*>(context
->context3D());
3080 scoped_ptr
<LayerTreeHostImpl
> myHostImpl
= createLayerTreeHost(false, context
.Pass(), LayerImpl::create(1));
3081 myHostImpl
->setBackgroundColor(SK_ColorWHITE
);
3083 // Verify one quad is drawn when transparent background set is not set.
3084 myHostImpl
->setHasTransparentBackground(false);
3085 EXPECT_CALL(*mockContext
, useProgram(_
))
3087 EXPECT_CALL(*mockContext
, drawElements(_
, _
, _
, _
))
3089 LayerTreeHostImpl::FrameData frame
;
3090 EXPECT_TRUE(myHostImpl
->prepareToDraw(frame
));
3091 myHostImpl
->drawLayers(frame
);
3092 myHostImpl
->didDrawAllLayers(frame
);
3093 Mock::VerifyAndClearExpectations(&mockContext
);
3095 // Verify no quads are drawn when transparent background is set.
3096 myHostImpl
->setHasTransparentBackground(true);
3097 EXPECT_TRUE(myHostImpl
->prepareToDraw(frame
));
3098 myHostImpl
->drawLayers(frame
);
3099 myHostImpl
->didDrawAllLayers(frame
);
3100 Mock::VerifyAndClearExpectations(&mockContext
);
3103 static void addDrawingLayerTo(LayerImpl
* parent
, int id
, const gfx::Rect
& layerRect
, LayerImpl
** result
)
3105 scoped_ptr
<LayerImpl
> layer
= FakeLayerWithQuads::create(id
);
3106 LayerImpl
* layerPtr
= layer
.get();
3107 layerPtr
->setAnchorPoint(gfx::PointF(0, 0));
3108 layerPtr
->setPosition(gfx::PointF(layerRect
.origin()));
3109 layerPtr
->setBounds(layerRect
.size());
3110 layerPtr
->setContentBounds(layerRect
.size());
3111 layerPtr
->setDrawsContent(true); // only children draw content
3112 layerPtr
->setContentsOpaque(true);
3113 parent
->addChild(layer
.Pass());
3118 static void setupLayersForTextureCaching(LayerTreeHostImpl
* layerTreeHostImpl
, LayerImpl
*& rootPtr
, LayerImpl
*& intermediateLayerPtr
, LayerImpl
*& surfaceLayerPtr
, LayerImpl
*& childPtr
, const gfx::Size
& rootSize
)
3120 scoped_ptr
<GraphicsContext
> context
= FakeWebCompositorOutputSurface::create(scoped_ptr
<WebKit::WebGraphicsContext3D
>(new PartialSwapContext
)).PassAs
<GraphicsContext
>();
3122 layerTreeHostImpl
->initializeRenderer(context
.Pass());
3123 layerTreeHostImpl
->setViewportSize(rootSize
, rootSize
);
3125 scoped_ptr
<LayerImpl
> root
= LayerImpl::create(1);
3126 rootPtr
= root
.get();
3128 root
->setAnchorPoint(gfx::PointF(0, 0));
3129 root
->setPosition(gfx::PointF(0, 0));
3130 root
->setBounds(rootSize
);
3131 root
->setContentBounds(rootSize
);
3132 root
->setDrawsContent(true);
3133 layerTreeHostImpl
->setRootLayer(root
.Pass());
3135 addDrawingLayerTo(rootPtr
, 2, gfx::Rect(10, 10, rootSize
.width(), rootSize
.height()), &intermediateLayerPtr
);
3136 intermediateLayerPtr
->setDrawsContent(false); // only children draw content
3138 // Surface layer is the layer that changes its opacity
3139 // It will contain other layers that draw content.
3140 addDrawingLayerTo(intermediateLayerPtr
, 3, gfx::Rect(10, 10, rootSize
.width(), rootSize
.height()), &surfaceLayerPtr
);
3141 surfaceLayerPtr
->setDrawsContent(false); // only children draw content
3142 surfaceLayerPtr
->setOpacity(0.5f
);
3143 surfaceLayerPtr
->setForceRenderSurface(true); // This will cause it to have a surface
3145 // Child of the surface layer will produce some quads
3146 addDrawingLayerTo(surfaceLayerPtr
, 4, gfx::Rect(5, 5, rootSize
.width() - 25, rootSize
.height() - 25), &childPtr
);
3149 class GLRendererWithReleaseTextures
: public GLRenderer
{
3151 using GLRenderer::releaseRenderPassTextures
;
3154 TEST_P(LayerTreeHostImplTest
, textureCachingWithClipping
)
3156 LayerTreeSettings settings
;
3157 settings
.minimumOcclusionTrackingSize
= gfx::Size();
3158 settings
.partialSwapEnabled
= true;
3159 scoped_ptr
<LayerTreeHostImpl
> myHostImpl
= LayerTreeHostImpl::create(settings
, this, &m_proxy
);
3162 LayerImpl
* surfaceLayerPtr
;
3164 scoped_ptr
<GraphicsContext
> context
= FakeWebCompositorOutputSurface::create(scoped_ptr
<WebKit::WebGraphicsContext3D
>(new PartialSwapContext
)).PassAs
<GraphicsContext
>();
3166 gfx::Size
rootSize(100, 100);
3168 myHostImpl
->initializeRenderer(context
.Pass());
3169 myHostImpl
->setViewportSize(gfx::Size(rootSize
.width(), rootSize
.height()), gfx::Size(rootSize
.width(), rootSize
.height()));
3171 scoped_ptr
<LayerImpl
> root
= LayerImpl::create(1);
3172 rootPtr
= root
.get();
3174 root
->setAnchorPoint(gfx::PointF(0, 0));
3175 root
->setPosition(gfx::PointF(0, 0));
3176 root
->setBounds(rootSize
);
3177 root
->setContentBounds(rootSize
);
3178 root
->setDrawsContent(true);
3179 root
->setMasksToBounds(true);
3180 myHostImpl
->setRootLayer(root
.Pass());
3182 addDrawingLayerTo(rootPtr
, 3, gfx::Rect(0, 0, rootSize
.width(), rootSize
.height()), &surfaceLayerPtr
);
3183 surfaceLayerPtr
->setDrawsContent(false);
3185 // Surface layer is the layer that changes its opacity
3186 // It will contain other layers that draw content.
3187 surfaceLayerPtr
->setOpacity(0.5f
);
3188 surfaceLayerPtr
->setForceRenderSurface(true); // This will cause it to have a surface
3190 addDrawingLayerTo(surfaceLayerPtr
, 4, gfx::Rect(0, 0, 100, 3), 0);
3191 addDrawingLayerTo(surfaceLayerPtr
, 5, gfx::Rect(0, 97, 100, 3), 0);
3193 // Rotation will put part of the child ouside the bounds of the root layer.
3194 // Nevertheless, the child layers should be drawn.
3195 gfx::Transform transform
= surfaceLayerPtr
->transform();
3196 transform
.Translate(50, 50);
3197 transform
.Rotate(35);
3198 transform
.Translate(-50, -50);
3199 surfaceLayerPtr
->setTransform(transform
);
3202 LayerTreeHostImpl::FrameData frame
;
3203 EXPECT_TRUE(myHostImpl
->prepareToDraw(frame
));
3205 // Must receive two render passes, each with one quad
3206 ASSERT_EQ(2U, frame
.renderPasses
.size());
3207 EXPECT_EQ(2U, frame
.renderPasses
[0]->quad_list
.size());
3208 ASSERT_EQ(1U, frame
.renderPasses
[1]->quad_list
.size());
3210 // Verify that the child layers are being clipped.
3211 gfx::Rect quadVisibleRect
= frame
.renderPasses
[0]->quad_list
[0]->visible_rect
;
3212 EXPECT_LT(quadVisibleRect
.width(), 100);
3214 quadVisibleRect
= frame
.renderPasses
[0]->quad_list
[1]->visible_rect
;
3215 EXPECT_LT(quadVisibleRect
.width(), 100);
3217 // Verify that the render surface texture is *not* clipped.
3218 EXPECT_RECT_EQ(gfx::Rect(0, 0, 100, 100), frame
.renderPasses
[0]->output_rect
);
3220 EXPECT_EQ(DrawQuad::RENDER_PASS
, frame
.renderPasses
[1]->quad_list
[0]->material
);
3221 const RenderPassDrawQuad
* quad
= RenderPassDrawQuad::MaterialCast(frame
.renderPasses
[1]->quad_list
[0]);
3222 EXPECT_FALSE(quad
->contents_changed_since_last_frame
.IsEmpty());
3224 myHostImpl
->drawLayers(frame
);
3225 myHostImpl
->didDrawAllLayers(frame
);
3228 transform
= surfaceLayerPtr
->transform();
3229 transform
.Translate(50, 50);
3230 transform
.Rotate(-35);
3231 transform
.Translate(-50, -50);
3232 surfaceLayerPtr
->setTransform(transform
);
3234 // The surface is now aligned again, and the clipped parts are exposed.
3235 // Since the layers were clipped, even though the render surface size
3236 // was not changed, the texture should not be saved.
3238 LayerTreeHostImpl::FrameData frame
;
3239 EXPECT_TRUE(myHostImpl
->prepareToDraw(frame
));
3241 // Must receive two render passes, each with one quad
3242 ASSERT_EQ(2U, frame
.renderPasses
.size());
3243 EXPECT_EQ(2U, frame
.renderPasses
[0]->quad_list
.size());
3244 ASSERT_EQ(1U, frame
.renderPasses
[1]->quad_list
.size());
3246 myHostImpl
->drawLayers(frame
);
3247 myHostImpl
->didDrawAllLayers(frame
);
3251 TEST_P(LayerTreeHostImplTest
, textureCachingWithOcclusion
)
3253 LayerTreeSettings settings
;
3254 settings
.minimumOcclusionTrackingSize
= gfx::Size();
3255 scoped_ptr
<LayerTreeHostImpl
> myHostImpl
= LayerTreeHostImpl::create(settings
, this, &m_proxy
);
3257 // Layers are structure as follows:
3259 // R +-- S1 +- L10 (owning)
3263 // +-- S2 +- L20 (owning)
3267 // L12 occludes L11 (internal)
3268 // L20 occludes L10 (external)
3269 // L21 occludes L20 (internal)
3272 LayerImpl
* layerS1Ptr
;
3273 LayerImpl
* layerS2Ptr
;
3275 scoped_ptr
<GraphicsContext
> context
= FakeWebCompositorOutputSurface::create(scoped_ptr
<WebKit::WebGraphicsContext3D
>(new PartialSwapContext
)).PassAs
<GraphicsContext
>();
3277 gfx::Size
rootSize(1000, 1000);
3279 myHostImpl
->initializeRenderer(context
.Pass());
3280 myHostImpl
->setViewportSize(gfx::Size(rootSize
.width(), rootSize
.height()), gfx::Size(rootSize
.width(), rootSize
.height()));
3282 scoped_ptr
<LayerImpl
> root
= LayerImpl::create(1);
3283 rootPtr
= root
.get();
3285 root
->setAnchorPoint(gfx::PointF(0, 0));
3286 root
->setPosition(gfx::PointF(0, 0));
3287 root
->setBounds(rootSize
);
3288 root
->setContentBounds(rootSize
);
3289 root
->setDrawsContent(true);
3290 root
->setMasksToBounds(true);
3291 myHostImpl
->setRootLayer(root
.Pass());
3293 addDrawingLayerTo(rootPtr
, 2, gfx::Rect(300, 300, 300, 300), &layerS1Ptr
);
3294 layerS1Ptr
->setForceRenderSurface(true);
3296 addDrawingLayerTo(layerS1Ptr
, 3, gfx::Rect(10, 10, 10, 10), 0); // L11
3297 addDrawingLayerTo(layerS1Ptr
, 4, gfx::Rect(0, 0, 30, 30), 0); // L12
3299 addDrawingLayerTo(rootPtr
, 5, gfx::Rect(550, 250, 300, 400), &layerS2Ptr
);
3300 layerS2Ptr
->setForceRenderSurface(true);
3302 addDrawingLayerTo(layerS2Ptr
, 6, gfx::Rect(20, 20, 5, 5), 0); // L21
3304 // Initial draw - must receive all quads
3306 LayerTreeHostImpl::FrameData frame
;
3307 EXPECT_TRUE(myHostImpl
->prepareToDraw(frame
));
3309 // Must receive 3 render passes.
3310 // For Root, there are 2 quads; for S1, there are 2 quads (1 is occluded); for S2, there is 2 quads.
3311 ASSERT_EQ(3U, frame
.renderPasses
.size());
3313 EXPECT_EQ(2U, frame
.renderPasses
[0]->quad_list
.size());
3314 EXPECT_EQ(2U, frame
.renderPasses
[1]->quad_list
.size());
3315 EXPECT_EQ(2U, frame
.renderPasses
[2]->quad_list
.size());
3317 myHostImpl
->drawLayers(frame
);
3318 myHostImpl
->didDrawAllLayers(frame
);
3321 // "Unocclude" surface S1 and repeat draw.
3322 // Must remove S2's render pass since it's cached;
3323 // Must keep S1 quads because texture contained external occlusion.
3324 gfx::Transform transform
= layerS2Ptr
->transform();
3325 transform
.Translate(150, 150);
3326 layerS2Ptr
->setTransform(transform
);
3328 LayerTreeHostImpl::FrameData frame
;
3329 EXPECT_TRUE(myHostImpl
->prepareToDraw(frame
));
3331 // Must receive 2 render passes.
3332 // For Root, there are 2 quads
3333 // For S1, the number of quads depends on what got unoccluded, so not asserted beyond being positive.
3334 // For S2, there is no render pass
3335 ASSERT_EQ(2U, frame
.renderPasses
.size());
3337 EXPECT_GT(frame
.renderPasses
[0]->quad_list
.size(), 0U);
3338 EXPECT_EQ(2U, frame
.renderPasses
[1]->quad_list
.size());
3340 myHostImpl
->drawLayers(frame
);
3341 myHostImpl
->didDrawAllLayers(frame
);
3344 // "Re-occlude" surface S1 and repeat draw.
3345 // Must remove S1's render pass since it is now available in full.
3346 // S2 has no change so must also be removed.
3347 transform
= layerS2Ptr
->transform();
3348 transform
.Translate(-15, -15);
3349 layerS2Ptr
->setTransform(transform
);
3351 LayerTreeHostImpl::FrameData frame
;
3352 EXPECT_TRUE(myHostImpl
->prepareToDraw(frame
));
3354 // Must receive 1 render pass - for the root.
3355 ASSERT_EQ(1U, frame
.renderPasses
.size());
3357 EXPECT_EQ(2U, frame
.renderPasses
[0]->quad_list
.size());
3359 myHostImpl
->drawLayers(frame
);
3360 myHostImpl
->didDrawAllLayers(frame
);
3365 TEST_P(LayerTreeHostImplTest
, textureCachingWithOcclusionEarlyOut
)
3367 LayerTreeSettings settings
;
3368 settings
.minimumOcclusionTrackingSize
= gfx::Size();
3369 scoped_ptr
<LayerTreeHostImpl
> myHostImpl
= LayerTreeHostImpl::create(settings
, this, &m_proxy
);
3371 // Layers are structure as follows:
3373 // R +-- S1 +- L10 (owning, non drawing)
3374 // | +- L11 (corner, unoccluded)
3375 // | +- L12 (corner, unoccluded)
3376 // | +- L13 (corner, unoccluded)
3377 // | +- L14 (corner, entirely occluded)
3379 // +-- S2 +- L20 (owning, drawing)
3383 LayerImpl
* layerS1Ptr
;
3384 LayerImpl
* layerS2Ptr
;
3386 scoped_ptr
<GraphicsContext
> context
= FakeWebCompositorOutputSurface::create(scoped_ptr
<WebKit::WebGraphicsContext3D
>(new PartialSwapContext
)).PassAs
<GraphicsContext
>();
3388 gfx::Size
rootSize(1000, 1000);
3390 myHostImpl
->initializeRenderer(context
.Pass());
3391 myHostImpl
->setViewportSize(gfx::Size(rootSize
.width(), rootSize
.height()), gfx::Size(rootSize
.width(), rootSize
.height()));
3393 scoped_ptr
<LayerImpl
> root
= LayerImpl::create(1);
3394 rootPtr
= root
.get();
3396 root
->setAnchorPoint(gfx::PointF(0, 0));
3397 root
->setPosition(gfx::PointF(0, 0));
3398 root
->setBounds(rootSize
);
3399 root
->setContentBounds(rootSize
);
3400 root
->setDrawsContent(true);
3401 root
->setMasksToBounds(true);
3402 myHostImpl
->setRootLayer(root
.Pass());
3404 addDrawingLayerTo(rootPtr
, 2, gfx::Rect(0, 0, 800, 800), &layerS1Ptr
);
3405 layerS1Ptr
->setForceRenderSurface(true);
3406 layerS1Ptr
->setDrawsContent(false);
3408 addDrawingLayerTo(layerS1Ptr
, 3, gfx::Rect(0, 0, 300, 300), 0); // L11
3409 addDrawingLayerTo(layerS1Ptr
, 4, gfx::Rect(0, 500, 300, 300), 0); // L12
3410 addDrawingLayerTo(layerS1Ptr
, 5, gfx::Rect(500, 0, 300, 300), 0); // L13
3411 addDrawingLayerTo(layerS1Ptr
, 6, gfx::Rect(500, 500, 300, 300), 0); // L14
3412 addDrawingLayerTo(layerS1Ptr
, 9, gfx::Rect(500, 500, 300, 300), 0); // L14
3414 addDrawingLayerTo(rootPtr
, 7, gfx::Rect(450, 450, 450, 450), &layerS2Ptr
);
3415 layerS2Ptr
->setForceRenderSurface(true);
3417 // Initial draw - must receive all quads
3419 LayerTreeHostImpl::FrameData frame
;
3420 EXPECT_TRUE(myHostImpl
->prepareToDraw(frame
));
3422 // Must receive 3 render passes.
3423 // For Root, there are 2 quads; for S1, there are 3 quads; for S2, there is 1 quad.
3424 ASSERT_EQ(3U, frame
.renderPasses
.size());
3426 EXPECT_EQ(1U, frame
.renderPasses
[0]->quad_list
.size());
3428 // L14 is culled, so only 3 quads.
3429 EXPECT_EQ(3U, frame
.renderPasses
[1]->quad_list
.size());
3430 EXPECT_EQ(2U, frame
.renderPasses
[2]->quad_list
.size());
3432 myHostImpl
->drawLayers(frame
);
3433 myHostImpl
->didDrawAllLayers(frame
);
3436 // "Unocclude" surface S1 and repeat draw.
3437 // Must remove S2's render pass since it's cached;
3438 // Must keep S1 quads because texture contained external occlusion.
3439 gfx::Transform transform
= layerS2Ptr
->transform();
3440 transform
.Translate(100, 100);
3441 layerS2Ptr
->setTransform(transform
);
3443 LayerTreeHostImpl::FrameData frame
;
3444 EXPECT_TRUE(myHostImpl
->prepareToDraw(frame
));
3446 // Must receive 2 render passes.
3447 // For Root, there are 2 quads
3448 // For S1, the number of quads depends on what got unoccluded, so not asserted beyond being positive.
3449 // For S2, there is no render pass
3450 ASSERT_EQ(2U, frame
.renderPasses
.size());
3452 EXPECT_GT(frame
.renderPasses
[0]->quad_list
.size(), 0U);
3453 EXPECT_EQ(2U, frame
.renderPasses
[1]->quad_list
.size());
3455 myHostImpl
->drawLayers(frame
);
3456 myHostImpl
->didDrawAllLayers(frame
);
3459 // "Re-occlude" surface S1 and repeat draw.
3460 // Must remove S1's render pass since it is now available in full.
3461 // S2 has no change so must also be removed.
3462 transform
= layerS2Ptr
->transform();
3463 transform
.Translate(-15, -15);
3464 layerS2Ptr
->setTransform(transform
);
3466 LayerTreeHostImpl::FrameData frame
;
3467 EXPECT_TRUE(myHostImpl
->prepareToDraw(frame
));
3469 // Must receive 1 render pass - for the root.
3470 ASSERT_EQ(1U, frame
.renderPasses
.size());
3472 EXPECT_EQ(2U, frame
.renderPasses
[0]->quad_list
.size());
3474 myHostImpl
->drawLayers(frame
);
3475 myHostImpl
->didDrawAllLayers(frame
);
3479 TEST_P(LayerTreeHostImplTest
, textureCachingWithOcclusionExternalOverInternal
)
3481 LayerTreeSettings settings
;
3482 settings
.minimumOcclusionTrackingSize
= gfx::Size();
3483 scoped_ptr
<LayerTreeHostImpl
> myHostImpl
= LayerTreeHostImpl::create(settings
, this, &m_proxy
);
3485 // Layers are structured as follows:
3487 // R +-- S1 +- L10 (owning, drawing)
3488 // | +- L11 (corner, occluded by L12)
3489 // | +- L12 (opposite corner)
3491 // +-- S2 +- L20 (owning, drawing)
3495 LayerImpl
* layerS1Ptr
;
3496 LayerImpl
* layerS2Ptr
;
3498 scoped_ptr
<GraphicsContext
> context
= FakeWebCompositorOutputSurface::create(scoped_ptr
<WebKit::WebGraphicsContext3D
>(new PartialSwapContext
)).PassAs
<GraphicsContext
>();
3500 gfx::Size
rootSize(1000, 1000);
3502 myHostImpl
->initializeRenderer(context
.Pass());
3503 myHostImpl
->setViewportSize(gfx::Size(rootSize
.width(), rootSize
.height()), gfx::Size(rootSize
.width(), rootSize
.height()));
3505 scoped_ptr
<LayerImpl
> root
= LayerImpl::create(1);
3506 rootPtr
= root
.get();
3508 root
->setAnchorPoint(gfx::PointF(0, 0));
3509 root
->setPosition(gfx::PointF(0, 0));
3510 root
->setBounds(rootSize
);
3511 root
->setContentBounds(rootSize
);
3512 root
->setDrawsContent(true);
3513 root
->setMasksToBounds(true);
3514 myHostImpl
->setRootLayer(root
.Pass());
3516 addDrawingLayerTo(rootPtr
, 2, gfx::Rect(0, 0, 400, 400), &layerS1Ptr
);
3517 layerS1Ptr
->setForceRenderSurface(true);
3519 addDrawingLayerTo(layerS1Ptr
, 3, gfx::Rect(0, 0, 300, 300), 0); // L11
3520 addDrawingLayerTo(layerS1Ptr
, 4, gfx::Rect(100, 0, 300, 300), 0); // L12
3522 addDrawingLayerTo(rootPtr
, 7, gfx::Rect(200, 0, 300, 300), &layerS2Ptr
);
3523 layerS2Ptr
->setForceRenderSurface(true);
3525 // Initial draw - must receive all quads
3527 LayerTreeHostImpl::FrameData frame
;
3528 EXPECT_TRUE(myHostImpl
->prepareToDraw(frame
));
3530 // Must receive 3 render passes.
3531 // For Root, there are 2 quads; for S1, there are 3 quads; for S2, there is 1 quad.
3532 ASSERT_EQ(3U, frame
.renderPasses
.size());
3534 EXPECT_EQ(1U, frame
.renderPasses
[0]->quad_list
.size());
3535 EXPECT_EQ(3U, frame
.renderPasses
[1]->quad_list
.size());
3536 EXPECT_EQ(2U, frame
.renderPasses
[2]->quad_list
.size());
3538 myHostImpl
->drawLayers(frame
);
3539 myHostImpl
->didDrawAllLayers(frame
);
3542 // "Unocclude" surface S1 and repeat draw.
3543 // Must remove S2's render pass since it's cached;
3544 // Must keep S1 quads because texture contained external occlusion.
3545 gfx::Transform transform
= layerS2Ptr
->transform();
3546 transform
.Translate(300, 0);
3547 layerS2Ptr
->setTransform(transform
);
3549 LayerTreeHostImpl::FrameData frame
;
3550 EXPECT_TRUE(myHostImpl
->prepareToDraw(frame
));
3552 // Must receive 2 render passes.
3553 // For Root, there are 2 quads
3554 // For S1, the number of quads depends on what got unoccluded, so not asserted beyond being positive.
3555 // For S2, there is no render pass
3556 ASSERT_EQ(2U, frame
.renderPasses
.size());
3558 EXPECT_GT(frame
.renderPasses
[0]->quad_list
.size(), 0U);
3559 EXPECT_EQ(2U, frame
.renderPasses
[1]->quad_list
.size());
3561 myHostImpl
->drawLayers(frame
);
3562 myHostImpl
->didDrawAllLayers(frame
);
3566 TEST_P(LayerTreeHostImplTest
, textureCachingWithOcclusionExternalNotAligned
)
3568 LayerTreeSettings settings
;
3569 scoped_ptr
<LayerTreeHostImpl
> myHostImpl
= LayerTreeHostImpl::create(settings
, this, &m_proxy
);
3571 // Layers are structured as follows:
3573 // R +-- S1 +- L10 (rotated, drawing)
3574 // +- L11 (occupies half surface)
3577 LayerImpl
* layerS1Ptr
;
3579 scoped_ptr
<GraphicsContext
> context
= FakeWebCompositorOutputSurface::create(scoped_ptr
<WebKit::WebGraphicsContext3D
>(new PartialSwapContext
)).PassAs
<GraphicsContext
>();
3581 gfx::Size
rootSize(1000, 1000);
3583 myHostImpl
->initializeRenderer(context
.Pass());
3584 myHostImpl
->setViewportSize(gfx::Size(rootSize
.width(), rootSize
.height()), gfx::Size(rootSize
.width(), rootSize
.height()));
3586 scoped_ptr
<LayerImpl
> root
= LayerImpl::create(1);
3587 rootPtr
= root
.get();
3589 root
->setAnchorPoint(gfx::PointF(0, 0));
3590 root
->setPosition(gfx::PointF(0, 0));
3591 root
->setBounds(rootSize
);
3592 root
->setContentBounds(rootSize
);
3593 root
->setDrawsContent(true);
3594 root
->setMasksToBounds(true);
3595 myHostImpl
->setRootLayer(root
.Pass());
3597 addDrawingLayerTo(rootPtr
, 2, gfx::Rect(0, 0, 400, 400), &layerS1Ptr
);
3598 layerS1Ptr
->setForceRenderSurface(true);
3599 gfx::Transform transform
= layerS1Ptr
->transform();
3600 transform
.Translate(200, 200);
3601 transform
.Rotate(45);
3602 transform
.Translate(-200, -200);
3603 layerS1Ptr
->setTransform(transform
);
3605 addDrawingLayerTo(layerS1Ptr
, 3, gfx::Rect(200, 0, 200, 400), 0); // L11
3607 // Initial draw - must receive all quads
3609 LayerTreeHostImpl::FrameData frame
;
3610 EXPECT_TRUE(myHostImpl
->prepareToDraw(frame
));
3612 // Must receive 2 render passes.
3613 ASSERT_EQ(2U, frame
.renderPasses
.size());
3615 EXPECT_EQ(2U, frame
.renderPasses
[0]->quad_list
.size());
3616 EXPECT_EQ(1U, frame
.renderPasses
[1]->quad_list
.size());
3618 myHostImpl
->drawLayers(frame
);
3619 myHostImpl
->didDrawAllLayers(frame
);
3622 // Change opacity and draw. Verify we used cached texture.
3623 layerS1Ptr
->setOpacity(0.2f
);
3625 LayerTreeHostImpl::FrameData frame
;
3626 EXPECT_TRUE(myHostImpl
->prepareToDraw(frame
));
3628 // One render pass must be gone due to cached texture.
3629 ASSERT_EQ(1U, frame
.renderPasses
.size());
3631 EXPECT_EQ(1U, frame
.renderPasses
[0]->quad_list
.size());
3633 myHostImpl
->drawLayers(frame
);
3634 myHostImpl
->didDrawAllLayers(frame
);
3638 TEST_P(LayerTreeHostImplTest
, textureCachingWithOcclusionPartialSwap
)
3640 LayerTreeSettings settings
;
3641 settings
.minimumOcclusionTrackingSize
= gfx::Size();
3642 settings
.partialSwapEnabled
= true;
3643 scoped_ptr
<LayerTreeHostImpl
> myHostImpl
= LayerTreeHostImpl::create(settings
, this, &m_proxy
);
3645 // Layers are structure as follows:
3647 // R +-- S1 +- L10 (owning)
3651 // +-- S2 +- L20 (owning)
3655 // L12 occludes L11 (internal)
3656 // L20 occludes L10 (external)
3657 // L21 occludes L20 (internal)
3660 LayerImpl
* layerS1Ptr
;
3661 LayerImpl
* layerS2Ptr
;
3663 scoped_ptr
<GraphicsContext
> context
= FakeWebCompositorOutputSurface::create(scoped_ptr
<WebKit::WebGraphicsContext3D
>(new PartialSwapContext
)).PassAs
<GraphicsContext
>();
3665 gfx::Size
rootSize(1000, 1000);
3667 myHostImpl
->initializeRenderer(context
.Pass());
3668 myHostImpl
->setViewportSize(gfx::Size(rootSize
.width(), rootSize
.height()), gfx::Size(rootSize
.width(), rootSize
.height()));
3670 scoped_ptr
<LayerImpl
> root
= LayerImpl::create(1);
3671 rootPtr
= root
.get();
3673 root
->setAnchorPoint(gfx::PointF(0, 0));
3674 root
->setPosition(gfx::PointF(0, 0));
3675 root
->setBounds(rootSize
);
3676 root
->setContentBounds(rootSize
);
3677 root
->setDrawsContent(true);
3678 root
->setMasksToBounds(true);
3679 myHostImpl
->setRootLayer(root
.Pass());
3681 addDrawingLayerTo(rootPtr
, 2, gfx::Rect(300, 300, 300, 300), &layerS1Ptr
);
3682 layerS1Ptr
->setForceRenderSurface(true);
3684 addDrawingLayerTo(layerS1Ptr
, 3, gfx::Rect(10, 10, 10, 10), 0); // L11
3685 addDrawingLayerTo(layerS1Ptr
, 4, gfx::Rect(0, 0, 30, 30), 0); // L12
3687 addDrawingLayerTo(rootPtr
, 5, gfx::Rect(550, 250, 300, 400), &layerS2Ptr
);
3688 layerS2Ptr
->setForceRenderSurface(true);
3690 addDrawingLayerTo(layerS2Ptr
, 6, gfx::Rect(20, 20, 5, 5), 0); // L21
3692 // Initial draw - must receive all quads
3694 LayerTreeHostImpl::FrameData frame
;
3695 EXPECT_TRUE(myHostImpl
->prepareToDraw(frame
));
3697 // Must receive 3 render passes.
3698 // For Root, there are 2 quads; for S1, there are 2 quads (one is occluded); for S2, there is 2 quads.
3699 ASSERT_EQ(3U, frame
.renderPasses
.size());
3701 EXPECT_EQ(2U, frame
.renderPasses
[0]->quad_list
.size());
3702 EXPECT_EQ(2U, frame
.renderPasses
[1]->quad_list
.size());
3703 EXPECT_EQ(2U, frame
.renderPasses
[2]->quad_list
.size());
3705 myHostImpl
->drawLayers(frame
);
3706 myHostImpl
->didDrawAllLayers(frame
);
3709 // "Unocclude" surface S1 and repeat draw.
3710 // Must remove S2's render pass since it's cached;
3711 // Must keep S1 quads because texture contained external occlusion.
3712 gfx::Transform transform
= layerS2Ptr
->transform();
3713 transform
.Translate(150, 150);
3714 layerS2Ptr
->setTransform(transform
);
3716 LayerTreeHostImpl::FrameData frame
;
3717 EXPECT_TRUE(myHostImpl
->prepareToDraw(frame
));
3719 // Must receive 2 render passes.
3720 // For Root, there are 2 quads.
3721 // For S1, there are 2 quads.
3722 // For S2, there is no render pass
3723 ASSERT_EQ(2U, frame
.renderPasses
.size());
3725 EXPECT_EQ(2U, frame
.renderPasses
[0]->quad_list
.size());
3726 EXPECT_EQ(2U, frame
.renderPasses
[1]->quad_list
.size());
3728 myHostImpl
->drawLayers(frame
);
3729 myHostImpl
->didDrawAllLayers(frame
);
3732 // "Re-occlude" surface S1 and repeat draw.
3733 // Must remove S1's render pass since it is now available in full.
3734 // S2 has no change so must also be removed.
3735 transform
= layerS2Ptr
->transform();
3736 transform
.Translate(-15, -15);
3737 layerS2Ptr
->setTransform(transform
);
3739 LayerTreeHostImpl::FrameData frame
;
3740 EXPECT_TRUE(myHostImpl
->prepareToDraw(frame
));
3742 // Root render pass only.
3743 ASSERT_EQ(1U, frame
.renderPasses
.size());
3745 myHostImpl
->drawLayers(frame
);
3746 myHostImpl
->didDrawAllLayers(frame
);
3750 TEST_P(LayerTreeHostImplTest
, textureCachingWithScissor
)
3752 LayerTreeSettings settings
;
3753 settings
.minimumOcclusionTrackingSize
= gfx::Size();
3754 scoped_ptr
<LayerTreeHostImpl
> myHostImpl
= LayerTreeHostImpl::create(settings
, this, &m_proxy
);
3757 Layers are created as follows:
3759 +--------------------+
3763 | | +-------------------+
3765 | | +-------------------+
3770 +--------------------+
3772 Layers 1, 2 have render surfaces
3774 scoped_ptr
<LayerImpl
> root
= LayerImpl::create(1);
3775 scoped_ptr
<TiledLayerImpl
> child
= TiledLayerImpl::create(2);
3776 scoped_ptr
<LayerImpl
> grandChild
= LayerImpl::create(3);
3778 gfx::Rect
rootRect(0, 0, 100, 100);
3779 gfx::Rect
childRect(10, 10, 50, 50);
3780 gfx::Rect
grandChildRect(5, 5, 150, 150);
3782 scoped_ptr
<GraphicsContext
> context
= FakeWebCompositorOutputSurface::create(scoped_ptr
<WebKit::WebGraphicsContext3D
>(new PartialSwapContext
)).PassAs
<GraphicsContext
>();
3783 myHostImpl
->initializeRenderer(context
.Pass());
3785 root
->setAnchorPoint(gfx::PointF(0, 0));
3786 root
->setPosition(gfx::PointF(rootRect
.x(), rootRect
.y()));
3787 root
->setBounds(gfx::Size(rootRect
.width(), rootRect
.height()));
3788 root
->setContentBounds(root
->bounds());
3789 root
->setDrawsContent(true);
3790 root
->setMasksToBounds(true);
3792 child
->setAnchorPoint(gfx::PointF(0, 0));
3793 child
->setPosition(gfx::PointF(childRect
.x(), childRect
.y()));
3794 child
->setOpacity(0.5);
3795 child
->setBounds(gfx::Size(childRect
.width(), childRect
.height()));
3796 child
->setContentBounds(child
->bounds());
3797 child
->setDrawsContent(true);
3798 child
->setSkipsDraw(false);
3800 // child layer has 10x10 tiles.
3801 scoped_ptr
<LayerTilingData
> tiler
= LayerTilingData::create(gfx::Size(10, 10), LayerTilingData::HasBorderTexels
);
3802 tiler
->setBounds(child
->contentBounds());
3803 child
->setTilingData(*tiler
.get());
3805 grandChild
->setAnchorPoint(gfx::PointF(0, 0));
3806 grandChild
->setPosition(gfx::Point(grandChildRect
.x(), grandChildRect
.y()));
3807 grandChild
->setBounds(gfx::Size(grandChildRect
.width(), grandChildRect
.height()));
3808 grandChild
->setContentBounds(grandChild
->bounds());
3809 grandChild
->setDrawsContent(true);
3811 TiledLayerImpl
* childPtr
= child
.get();
3812 RenderPass::Id
childPassId(childPtr
->id(), 0);
3814 child
->addChild(grandChild
.Pass());
3815 root
->addChild(child
.PassAs
<LayerImpl
>());
3816 myHostImpl
->setRootLayer(root
.Pass());
3817 myHostImpl
->setViewportSize(rootRect
.size(), rootRect
.size());
3819 EXPECT_FALSE(myHostImpl
->renderer()->haveCachedResourcesForRenderPassId(childPassId
));
3822 LayerTreeHostImpl::FrameData frame
;
3823 EXPECT_TRUE(myHostImpl
->prepareToDraw(frame
));
3824 myHostImpl
->drawLayers(frame
);
3825 myHostImpl
->didDrawAllLayers(frame
);
3828 // We should have cached textures for surface 2.
3829 EXPECT_TRUE(myHostImpl
->renderer()->haveCachedResourcesForRenderPassId(childPassId
));
3832 LayerTreeHostImpl::FrameData frame
;
3833 EXPECT_TRUE(myHostImpl
->prepareToDraw(frame
));
3834 myHostImpl
->drawLayers(frame
);
3835 myHostImpl
->didDrawAllLayers(frame
);
3838 // We should still have cached textures for surface 2 after drawing with no damage.
3839 EXPECT_TRUE(myHostImpl
->renderer()->haveCachedResourcesForRenderPassId(childPassId
));
3841 // Damage a single tile of surface 2.
3842 childPtr
->setUpdateRect(gfx::Rect(10, 10, 10, 10));
3845 LayerTreeHostImpl::FrameData frame
;
3846 EXPECT_TRUE(myHostImpl
->prepareToDraw(frame
));
3847 myHostImpl
->drawLayers(frame
);
3848 myHostImpl
->didDrawAllLayers(frame
);
3851 // We should have a cached texture for surface 2 again even though it was damaged.
3852 EXPECT_TRUE(myHostImpl
->renderer()->haveCachedResourcesForRenderPassId(childPassId
));
3855 TEST_P(LayerTreeHostImplTest
, surfaceTextureCaching
)
3857 LayerTreeSettings settings
;
3858 settings
.minimumOcclusionTrackingSize
= gfx::Size();
3859 settings
.partialSwapEnabled
= true;
3860 scoped_ptr
<LayerTreeHostImpl
> myHostImpl
= LayerTreeHostImpl::create(settings
, this, &m_proxy
);
3863 LayerImpl
* intermediateLayerPtr
;
3864 LayerImpl
* surfaceLayerPtr
;
3865 LayerImpl
* childPtr
;
3867 setupLayersForTextureCaching(myHostImpl
.get(), rootPtr
, intermediateLayerPtr
, surfaceLayerPtr
, childPtr
, gfx::Size(100, 100));
3870 LayerTreeHostImpl::FrameData frame
;
3871 EXPECT_TRUE(myHostImpl
->prepareToDraw(frame
));
3873 // Must receive two render passes, each with one quad
3874 ASSERT_EQ(2U, frame
.renderPasses
.size());
3875 EXPECT_EQ(1U, frame
.renderPasses
[0]->quad_list
.size());
3876 EXPECT_EQ(1U, frame
.renderPasses
[1]->quad_list
.size());
3878 EXPECT_EQ(DrawQuad::RENDER_PASS
, frame
.renderPasses
[1]->quad_list
[0]->material
);
3879 const RenderPassDrawQuad
* quad
= RenderPassDrawQuad::MaterialCast(frame
.renderPasses
[1]->quad_list
[0]);
3880 RenderPass
* targetPass
= frame
.renderPassesById
.get(quad
->render_pass_id
);
3881 EXPECT_FALSE(targetPass
->damage_rect
.IsEmpty());
3883 myHostImpl
->drawLayers(frame
);
3884 myHostImpl
->didDrawAllLayers(frame
);
3887 // Draw without any change
3889 LayerTreeHostImpl::FrameData frame
;
3890 EXPECT_TRUE(myHostImpl
->prepareToDraw(frame
));
3892 // Must receive one render pass, as the other one should be culled
3893 ASSERT_EQ(1U, frame
.renderPasses
.size());
3895 EXPECT_EQ(1U, frame
.renderPasses
[0]->quad_list
.size());
3896 EXPECT_EQ(DrawQuad::RENDER_PASS
, frame
.renderPasses
[0]->quad_list
[0]->material
);
3897 const RenderPassDrawQuad
* quad
= RenderPassDrawQuad::MaterialCast(frame
.renderPasses
[0]->quad_list
[0]);
3898 RenderPass
* targetPass
= frame
.renderPassesById
.get(quad
->render_pass_id
);
3899 EXPECT_TRUE(targetPass
->damage_rect
.IsEmpty());
3901 myHostImpl
->drawLayers(frame
);
3902 myHostImpl
->didDrawAllLayers(frame
);
3905 // Change opacity and draw
3906 surfaceLayerPtr
->setOpacity(0.6f
);
3908 LayerTreeHostImpl::FrameData frame
;
3909 EXPECT_TRUE(myHostImpl
->prepareToDraw(frame
));
3911 // Must receive one render pass, as the other one should be culled
3912 ASSERT_EQ(1U, frame
.renderPasses
.size());
3914 EXPECT_EQ(1U, frame
.renderPasses
[0]->quad_list
.size());
3915 EXPECT_EQ(DrawQuad::RENDER_PASS
, frame
.renderPasses
[0]->quad_list
[0]->material
);
3916 const RenderPassDrawQuad
* quad
= RenderPassDrawQuad::MaterialCast(frame
.renderPasses
[0]->quad_list
[0]);
3917 RenderPass
* targetPass
= frame
.renderPassesById
.get(quad
->render_pass_id
);
3918 EXPECT_TRUE(targetPass
->damage_rect
.IsEmpty());
3920 myHostImpl
->drawLayers(frame
);
3921 myHostImpl
->didDrawAllLayers(frame
);
3924 // Change less benign property and draw - should have contents changed flag
3925 surfaceLayerPtr
->setStackingOrderChanged(true);
3927 LayerTreeHostImpl::FrameData frame
;
3928 EXPECT_TRUE(myHostImpl
->prepareToDraw(frame
));
3930 // Must receive two render passes, each with one quad
3931 ASSERT_EQ(2U, frame
.renderPasses
.size());
3933 EXPECT_EQ(1U, frame
.renderPasses
[0]->quad_list
.size());
3934 EXPECT_EQ(DrawQuad::SOLID_COLOR
, frame
.renderPasses
[0]->quad_list
[0]->material
);
3936 EXPECT_EQ(DrawQuad::RENDER_PASS
, frame
.renderPasses
[1]->quad_list
[0]->material
);
3937 const RenderPassDrawQuad
* quad
= RenderPassDrawQuad::MaterialCast(frame
.renderPasses
[1]->quad_list
[0]);
3938 RenderPass
* targetPass
= frame
.renderPassesById
.get(quad
->render_pass_id
);
3939 EXPECT_FALSE(targetPass
->damage_rect
.IsEmpty());
3941 myHostImpl
->drawLayers(frame
);
3942 myHostImpl
->didDrawAllLayers(frame
);
3945 // Change opacity again, and evict the cached surface texture.
3946 surfaceLayerPtr
->setOpacity(0.5f
);
3947 static_cast<GLRendererWithReleaseTextures
*>(myHostImpl
->renderer())->releaseRenderPassTextures();
3949 // Change opacity and draw
3950 surfaceLayerPtr
->setOpacity(0.6f
);
3952 LayerTreeHostImpl::FrameData frame
;
3953 EXPECT_TRUE(myHostImpl
->prepareToDraw(frame
));
3955 // Must receive two render passes
3956 ASSERT_EQ(2U, frame
.renderPasses
.size());
3958 // Even though not enough properties changed, the entire thing must be
3959 // redrawn as we don't have cached textures
3960 EXPECT_EQ(1U, frame
.renderPasses
[0]->quad_list
.size());
3961 EXPECT_EQ(1U, frame
.renderPasses
[1]->quad_list
.size());
3963 EXPECT_EQ(DrawQuad::RENDER_PASS
, frame
.renderPasses
[1]->quad_list
[0]->material
);
3964 const RenderPassDrawQuad
* quad
= RenderPassDrawQuad::MaterialCast(frame
.renderPasses
[1]->quad_list
[0]);
3965 RenderPass
* targetPass
= frame
.renderPassesById
.get(quad
->render_pass_id
);
3966 EXPECT_TRUE(targetPass
->damage_rect
.IsEmpty());
3968 // Was our surface evicted?
3969 EXPECT_FALSE(myHostImpl
->renderer()->haveCachedResourcesForRenderPassId(targetPass
->id
));
3971 myHostImpl
->drawLayers(frame
);
3972 myHostImpl
->didDrawAllLayers(frame
);
3975 // Draw without any change, to make sure the state is clear
3977 LayerTreeHostImpl::FrameData frame
;
3978 EXPECT_TRUE(myHostImpl
->prepareToDraw(frame
));
3980 // Must receive one render pass, as the other one should be culled
3981 ASSERT_EQ(1U, frame
.renderPasses
.size());
3983 EXPECT_EQ(1U, frame
.renderPasses
[0]->quad_list
.size());
3984 EXPECT_EQ(DrawQuad::RENDER_PASS
, frame
.renderPasses
[0]->quad_list
[0]->material
);
3985 const RenderPassDrawQuad
* quad
= RenderPassDrawQuad::MaterialCast(frame
.renderPasses
[0]->quad_list
[0]);
3986 RenderPass
* targetPass
= frame
.renderPassesById
.get(quad
->render_pass_id
);
3987 EXPECT_TRUE(targetPass
->damage_rect
.IsEmpty());
3989 myHostImpl
->drawLayers(frame
);
3990 myHostImpl
->didDrawAllLayers(frame
);
3993 // Change location of the intermediate layer
3994 gfx::Transform transform
= intermediateLayerPtr
->transform();
3995 transform
.matrix().setDouble(0, 3, 1.0001);
3996 intermediateLayerPtr
->setTransform(transform
);
3998 LayerTreeHostImpl::FrameData frame
;
3999 EXPECT_TRUE(myHostImpl
->prepareToDraw(frame
));
4001 // Must receive one render pass, as the other one should be culled.
4002 ASSERT_EQ(1U, frame
.renderPasses
.size());
4003 EXPECT_EQ(1U, frame
.renderPasses
[0]->quad_list
.size());
4005 EXPECT_EQ(DrawQuad::RENDER_PASS
, frame
.renderPasses
[0]->quad_list
[0]->material
);
4006 const RenderPassDrawQuad
* quad
= RenderPassDrawQuad::MaterialCast(frame
.renderPasses
[0]->quad_list
[0]);
4007 RenderPass
* targetPass
= frame
.renderPassesById
.get(quad
->render_pass_id
);
4008 EXPECT_TRUE(targetPass
->damage_rect
.IsEmpty());
4010 myHostImpl
->drawLayers(frame
);
4011 myHostImpl
->didDrawAllLayers(frame
);
4015 TEST_P(LayerTreeHostImplTest
, surfaceTextureCachingNoPartialSwap
)
4017 LayerTreeSettings settings
;
4018 settings
.minimumOcclusionTrackingSize
= gfx::Size();
4019 scoped_ptr
<LayerTreeHostImpl
> myHostImpl
= LayerTreeHostImpl::create(settings
, this, &m_proxy
);
4022 LayerImpl
* intermediateLayerPtr
;
4023 LayerImpl
* surfaceLayerPtr
;
4024 LayerImpl
* childPtr
;
4026 setupLayersForTextureCaching(myHostImpl
.get(), rootPtr
, intermediateLayerPtr
, surfaceLayerPtr
, childPtr
, gfx::Size(100, 100));
4029 LayerTreeHostImpl::FrameData frame
;
4030 EXPECT_TRUE(myHostImpl
->prepareToDraw(frame
));
4032 // Must receive two render passes, each with one quad
4033 ASSERT_EQ(2U, frame
.renderPasses
.size());
4034 EXPECT_EQ(1U, frame
.renderPasses
[0]->quad_list
.size());
4035 EXPECT_EQ(1U, frame
.renderPasses
[1]->quad_list
.size());
4037 EXPECT_EQ(DrawQuad::RENDER_PASS
, frame
.renderPasses
[1]->quad_list
[0]->material
);
4038 const RenderPassDrawQuad
* quad
= RenderPassDrawQuad::MaterialCast(frame
.renderPasses
[1]->quad_list
[0]);
4039 RenderPass
* targetPass
= frame
.renderPassesById
.get(quad
->render_pass_id
);
4040 EXPECT_FALSE(targetPass
->damage_rect
.IsEmpty());
4042 EXPECT_FALSE(frame
.renderPasses
[0]->damage_rect
.IsEmpty());
4043 EXPECT_FALSE(frame
.renderPasses
[1]->damage_rect
.IsEmpty());
4045 EXPECT_FALSE(frame
.renderPasses
[0]->has_occlusion_from_outside_target_surface
);
4046 EXPECT_FALSE(frame
.renderPasses
[1]->has_occlusion_from_outside_target_surface
);
4048 myHostImpl
->drawLayers(frame
);
4049 myHostImpl
->didDrawAllLayers(frame
);
4052 // Draw without any change
4054 LayerTreeHostImpl::FrameData frame
;
4055 EXPECT_TRUE(myHostImpl
->prepareToDraw(frame
));
4057 // Even though there was no change, we set the damage to entire viewport.
4058 // One of the passes should be culled as a result, since contents didn't change
4059 // and we have cached texture.
4060 ASSERT_EQ(1U, frame
.renderPasses
.size());
4061 EXPECT_EQ(1U, frame
.renderPasses
[0]->quad_list
.size());
4063 EXPECT_TRUE(frame
.renderPasses
[0]->damage_rect
.IsEmpty());
4065 myHostImpl
->drawLayers(frame
);
4066 myHostImpl
->didDrawAllLayers(frame
);
4069 // Change opacity and draw
4070 surfaceLayerPtr
->setOpacity(0.6f
);
4072 LayerTreeHostImpl::FrameData frame
;
4073 EXPECT_TRUE(myHostImpl
->prepareToDraw(frame
));
4075 // Must receive one render pass, as the other one should be culled
4076 ASSERT_EQ(1U, frame
.renderPasses
.size());
4078 EXPECT_EQ(1U, frame
.renderPasses
[0]->quad_list
.size());
4079 EXPECT_EQ(DrawQuad::RENDER_PASS
, frame
.renderPasses
[0]->quad_list
[0]->material
);
4080 const RenderPassDrawQuad
* quad
= RenderPassDrawQuad::MaterialCast(frame
.renderPasses
[0]->quad_list
[0]);
4081 RenderPass
* targetPass
= frame
.renderPassesById
.get(quad
->render_pass_id
);
4082 EXPECT_TRUE(targetPass
->damage_rect
.IsEmpty());
4084 myHostImpl
->drawLayers(frame
);
4085 myHostImpl
->didDrawAllLayers(frame
);
4088 // Change less benign property and draw - should have contents changed flag
4089 surfaceLayerPtr
->setStackingOrderChanged(true);
4091 LayerTreeHostImpl::FrameData frame
;
4092 EXPECT_TRUE(myHostImpl
->prepareToDraw(frame
));
4094 // Must receive two render passes, each with one quad
4095 ASSERT_EQ(2U, frame
.renderPasses
.size());
4097 EXPECT_EQ(1U, frame
.renderPasses
[0]->quad_list
.size());
4098 EXPECT_EQ(DrawQuad::SOLID_COLOR
, frame
.renderPasses
[0]->quad_list
[0]->material
);
4100 EXPECT_EQ(DrawQuad::RENDER_PASS
, frame
.renderPasses
[1]->quad_list
[0]->material
);
4101 const RenderPassDrawQuad
* quad
= RenderPassDrawQuad::MaterialCast(frame
.renderPasses
[1]->quad_list
[0]);
4102 RenderPass
* targetPass
= frame
.renderPassesById
.get(quad
->render_pass_id
);
4103 EXPECT_FALSE(targetPass
->damage_rect
.IsEmpty());
4105 myHostImpl
->drawLayers(frame
);
4106 myHostImpl
->didDrawAllLayers(frame
);
4109 // Change opacity again, and evict the cached surface texture.
4110 surfaceLayerPtr
->setOpacity(0.5f
);
4111 static_cast<GLRendererWithReleaseTextures
*>(myHostImpl
->renderer())->releaseRenderPassTextures();
4113 // Change opacity and draw
4114 surfaceLayerPtr
->setOpacity(0.6f
);
4116 LayerTreeHostImpl::FrameData frame
;
4117 EXPECT_TRUE(myHostImpl
->prepareToDraw(frame
));
4119 // Must receive two render passes
4120 ASSERT_EQ(2U, frame
.renderPasses
.size());
4122 // Even though not enough properties changed, the entire thing must be
4123 // redrawn as we don't have cached textures
4124 EXPECT_EQ(1U, frame
.renderPasses
[0]->quad_list
.size());
4125 EXPECT_EQ(1U, frame
.renderPasses
[1]->quad_list
.size());
4127 EXPECT_EQ(DrawQuad::RENDER_PASS
, frame
.renderPasses
[1]->quad_list
[0]->material
);
4128 const RenderPassDrawQuad
* quad
= RenderPassDrawQuad::MaterialCast(frame
.renderPasses
[1]->quad_list
[0]);
4129 RenderPass
* targetPass
= frame
.renderPassesById
.get(quad
->render_pass_id
);
4130 EXPECT_TRUE(targetPass
->damage_rect
.IsEmpty());
4132 // Was our surface evicted?
4133 EXPECT_FALSE(myHostImpl
->renderer()->haveCachedResourcesForRenderPassId(targetPass
->id
));
4135 myHostImpl
->drawLayers(frame
);
4136 myHostImpl
->didDrawAllLayers(frame
);
4139 // Draw without any change, to make sure the state is clear
4141 LayerTreeHostImpl::FrameData frame
;
4142 EXPECT_TRUE(myHostImpl
->prepareToDraw(frame
));
4144 // Even though there was no change, we set the damage to entire viewport.
4145 // One of the passes should be culled as a result, since contents didn't change
4146 // and we have cached texture.
4147 ASSERT_EQ(1U, frame
.renderPasses
.size());
4148 EXPECT_EQ(1U, frame
.renderPasses
[0]->quad_list
.size());
4150 myHostImpl
->drawLayers(frame
);
4151 myHostImpl
->didDrawAllLayers(frame
);
4154 // Change location of the intermediate layer
4155 gfx::Transform transform
= intermediateLayerPtr
->transform();
4156 transform
.matrix().setDouble(0, 3, 1.0001);
4157 intermediateLayerPtr
->setTransform(transform
);
4159 LayerTreeHostImpl::FrameData frame
;
4160 EXPECT_TRUE(myHostImpl
->prepareToDraw(frame
));
4162 // Must receive one render pass, as the other one should be culled.
4163 ASSERT_EQ(1U, frame
.renderPasses
.size());
4164 EXPECT_EQ(1U, frame
.renderPasses
[0]->quad_list
.size());
4166 EXPECT_EQ(DrawQuad::RENDER_PASS
, frame
.renderPasses
[0]->quad_list
[0]->material
);
4167 const RenderPassDrawQuad
* quad
= RenderPassDrawQuad::MaterialCast(frame
.renderPasses
[0]->quad_list
[0]);
4168 RenderPass
* targetPass
= frame
.renderPassesById
.get(quad
->render_pass_id
);
4169 EXPECT_TRUE(targetPass
->damage_rect
.IsEmpty());
4171 myHostImpl
->drawLayers(frame
);
4172 myHostImpl
->didDrawAllLayers(frame
);
4176 TEST_P(LayerTreeHostImplTest
, releaseContentsTextureShouldTriggerCommit
)
4178 setReduceMemoryResult(false);
4180 // Even if changing the memory limit didn't result in anything being
4181 // evicted, we need to re-commit because the new value may result in us
4182 // drawing something different than before.
4183 setReduceMemoryResult(false);
4184 m_hostImpl
->setManagedMemoryPolicy(ManagedMemoryPolicy(
4185 m_hostImpl
->memoryAllocationLimitBytes() - 1));
4186 EXPECT_TRUE(m_didRequestCommit
);
4187 m_didRequestCommit
= false;
4189 // Especially if changing the memory limit caused evictions, we need
4191 setReduceMemoryResult(true);
4192 m_hostImpl
->setManagedMemoryPolicy(ManagedMemoryPolicy(
4193 m_hostImpl
->memoryAllocationLimitBytes() - 1));
4194 EXPECT_TRUE(m_didRequestCommit
);
4195 m_didRequestCommit
= false;
4197 // But if we set it to the same value that it was before, we shouldn't
4199 m_hostImpl
->setManagedMemoryPolicy(ManagedMemoryPolicy(
4200 m_hostImpl
->memoryAllocationLimitBytes()));
4201 EXPECT_FALSE(m_didRequestCommit
);
4204 struct RenderPassRemovalTestData
: public LayerTreeHostImpl::FrameData
{
4205 ScopedPtrHashMap
<RenderPass::Id
, TestRenderPass
> renderPassCache
;
4206 scoped_ptr
<SharedQuadState
> sharedQuadState
;
4209 class TestRenderer
: public GLRenderer
, public RendererClient
{
4211 static scoped_ptr
<TestRenderer
> create(ResourceProvider
* resourceProvider
, Proxy
* proxy
)
4213 scoped_ptr
<TestRenderer
> renderer(new TestRenderer(resourceProvider
, proxy
));
4214 if (!renderer
->initialize())
4215 return scoped_ptr
<TestRenderer
>();
4217 return renderer
.Pass();
4220 void clearCachedTextures() { m_textures
.clear(); }
4221 void setHaveCachedResourcesForRenderPassId(RenderPass::Id id
) { m_textures
.insert(id
); }
4223 virtual bool haveCachedResourcesForRenderPassId(RenderPass::Id id
) const OVERRIDE
{ return m_textures
.count(id
); }
4225 // RendererClient implementation.
4226 virtual const gfx::Size
& deviceViewportSize() const OVERRIDE
{ return m_viewportSize
; }
4227 virtual const LayerTreeSettings
& settings() const OVERRIDE
{ return m_settings
; }
4228 virtual void didLoseContext() OVERRIDE
{ }
4229 virtual void onSwapBuffersComplete() OVERRIDE
{ }
4230 virtual void setFullRootLayerDamage() OVERRIDE
{ }
4231 virtual void setManagedMemoryPolicy(const ManagedMemoryPolicy
& policy
) OVERRIDE
{ }
4232 virtual void enforceManagedMemoryPolicy(const ManagedMemoryPolicy
& policy
) OVERRIDE
{ }
4233 virtual bool hasImplThread() const OVERRIDE
{ return false; }
4236 TestRenderer(ResourceProvider
* resourceProvider
, Proxy
* proxy
) : GLRenderer(this, resourceProvider
) { }
4239 LayerTreeSettings m_settings
;
4240 gfx::Size m_viewportSize
;
4241 base::hash_set
<RenderPass::Id
> m_textures
;
4244 static void configureRenderPassTestData(const char* testScript
, RenderPassRemovalTestData
& testData
, TestRenderer
* renderer
)
4246 renderer
->clearCachedTextures();
4248 // One shared state for all quads - we don't need the correct details
4249 testData
.sharedQuadState
= SharedQuadState::Create();
4250 testData
.sharedQuadState
->SetAll(gfx::Transform(), gfx::Rect(), gfx::Rect(), gfx::Rect(), false, 1.0);
4252 const char* currentChar
= testScript
;
4254 // Pre-create root pass
4255 RenderPass::Id rootRenderPassId
= RenderPass::Id(testScript
[0], testScript
[1]);
4256 scoped_ptr
<TestRenderPass
> pass
= TestRenderPass::Create();
4257 pass
->SetNew(rootRenderPassId
, gfx::Rect(), gfx::Rect(), gfx::Transform());
4258 testData
.renderPassCache
.add(rootRenderPassId
, pass
.Pass());
4259 while (*currentChar
) {
4260 int layerId
= *currentChar
;
4262 ASSERT_TRUE(currentChar
);
4263 int index
= *currentChar
;
4266 RenderPass::Id renderPassId
= RenderPass::Id(layerId
, index
);
4268 bool isReplica
= false;
4269 if (!testData
.renderPassCache
.contains(renderPassId
))
4272 scoped_ptr
<TestRenderPass
> renderPass
= testData
.renderPassCache
.take(renderPassId
);
4274 // Cycle through quad data and create all quads
4275 while (*currentChar
&& *currentChar
!= '\n') {
4276 if (*currentChar
== 's') {
4277 // Solid color draw quad
4278 scoped_ptr
<SolidColorDrawQuad
> quad
= SolidColorDrawQuad::Create();
4279 quad
->SetNew(testData
.sharedQuadState
.get(), gfx::Rect(0, 0, 10, 10), SK_ColorWHITE
);
4281 renderPass
->AppendQuad(quad
.PassAs
<DrawQuad
>());
4283 } else if ((*currentChar
>= 'A') && (*currentChar
<= 'Z')) {
4284 // RenderPass draw quad
4285 int layerId
= *currentChar
;
4287 ASSERT_TRUE(currentChar
);
4288 int index
= *currentChar
;
4290 RenderPass::Id newRenderPassId
= RenderPass::Id(layerId
, index
);
4291 ASSERT_NE(rootRenderPassId
, newRenderPassId
);
4292 bool hasTexture
= false;
4293 bool contentsChanged
= true;
4295 if (*currentChar
== '[') {
4297 while (*currentChar
&& *currentChar
!= ']') {
4298 switch (*currentChar
) {
4300 contentsChanged
= false;
4308 if (*currentChar
== ']')
4312 if (testData
.renderPassCache
.find(newRenderPassId
) == testData
.renderPassCache
.end()) {
4314 renderer
->setHaveCachedResourcesForRenderPassId(newRenderPassId
);
4316 scoped_ptr
<TestRenderPass
> pass
= TestRenderPass::Create();
4317 pass
->SetNew(newRenderPassId
, gfx::Rect(), gfx::Rect(), gfx::Transform());
4318 testData
.renderPassCache
.add(newRenderPassId
, pass
.Pass());
4321 gfx::Rect quadRect
= gfx::Rect(0, 0, 1, 1);
4322 gfx::Rect contentsChangedRect
= contentsChanged
? quadRect
: gfx::Rect();
4323 scoped_ptr
<RenderPassDrawQuad
> quad
= RenderPassDrawQuad::Create();
4324 quad
->SetNew(testData
.sharedQuadState
.get(), quadRect
, newRenderPassId
, isReplica
, 1, contentsChangedRect
, 1, 1, 0, 0);
4325 renderPass
->AppendQuad(quad
.PassAs
<DrawQuad
>());
4328 testData
.renderPasses
.insert(testData
.renderPasses
.begin(), renderPass
.get());
4329 testData
.renderPassesById
.add(renderPassId
, renderPass
.PassAs
<RenderPass
>());
4335 void dumpRenderPassTestData(const RenderPassRemovalTestData
& testData
, char* buffer
)
4338 for (RenderPassList::const_reverse_iterator it
= testData
.renderPasses
.rbegin(); it
!= testData
.renderPasses
.rend(); ++it
) {
4339 const RenderPass
* currentPass
= *it
;
4340 *pos
= currentPass
->id
.layer_id
;
4342 *pos
= currentPass
->id
.index
;
4345 QuadList::const_iterator quadListIterator
= currentPass
->quad_list
.begin();
4346 while (quadListIterator
!= currentPass
->quad_list
.end()) {
4347 DrawQuad
* currentQuad
= *quadListIterator
;
4348 switch (currentQuad
->material
) {
4349 case DrawQuad::SOLID_COLOR
:
4353 case DrawQuad::RENDER_PASS
:
4354 *pos
= RenderPassDrawQuad::MaterialCast(currentQuad
)->render_pass_id
.layer_id
;
4356 *pos
= RenderPassDrawQuad::MaterialCast(currentQuad
)->render_pass_id
.index
;
4373 // Each RenderPassList is represented by a string which describes the configuration.
4374 // The syntax of the string is as follows:
4376 // RsssssX[c]ssYsssZ[t]ssW[ct]
4377 // Identifies the render pass---------------------------^ ^^^ ^ ^ ^ ^ ^
4378 // These are solid color quads-----------------------------+ | | | | |
4379 // Identifies RenderPassDrawQuad's RenderPass-----------------+ | | | |
4380 // This quad's contents didn't change---------------------------+ | | |
4381 // This quad's contents changed and it has no texture---------------+ | |
4382 // This quad has texture but its contents changed-------------------------+ |
4383 // This quad's contents didn't change and it has texture - will be removed------+
4385 // Expected results have exactly the same syntax, except they do not use square brackets,
4386 // since we only check the structure, not attributes.
4388 // Test case configuration consists of initialization script and expected results,
4389 // all in the same format.
4392 const char* initScript
;
4393 const char* expectedResult
;
4396 TestCase removeRenderPassesCases
[] =
4403 "Single pass - no quads",
4407 "Two passes, no removal",
4413 "Two passes, remove last",
4418 "Have texture but contents changed - leave pass",
4424 "Contents didn't change but no texture - leave pass",
4430 "Replica: two quads reference the same pass; remove",
4431 "R0ssssA0[ct]A0[ct]sss\n"
4435 "Replica: two quads reference the same pass; leave",
4436 "R0ssssA0[c]A0[c]sss\n"
4441 "Many passes, remove all",
4443 "A0sssB0[ct]C0[ct]s\n"
4444 "B0sssD0[ct]ssE0[ct]F0[ct]\n"
4453 "Deep recursion, remove all",
4455 "R0sssssA0[ct]ssss\n"
4469 "Wide recursion, remove all",
4470 "R0A0[ct]B0[ct]C0[ct]D0[ct]E0[ct]F0[ct]G0[ct]H0[ct]I0[ct]J0[ct]\n"
4482 "R0A0B0C0D0E0F0G0H0I0J0\n"
4484 "Remove passes regardless of cache state",
4487 "B0sssD0[c]ssE0[t]F0\n"
4496 "Leave some passes, remove others",
4499 "A0sssB0[t]C0[ct]s\n"
4514 static void verifyRenderPassTestData(TestCase
& testCase
, RenderPassRemovalTestData
& testData
)
4516 char actualResult
[1024];
4517 dumpRenderPassTestData(testData
, actualResult
);
4518 EXPECT_STREQ(testCase
.expectedResult
, actualResult
) << "In test case: " << testCase
.name
;
4521 TEST_P(LayerTreeHostImplTest
, testRemoveRenderPasses
)
4523 scoped_ptr
<GraphicsContext
> context(createContext());
4524 ASSERT_TRUE(context
->context3D());
4525 scoped_ptr
<ResourceProvider
> resourceProvider(ResourceProvider::create(context
.get()));
4527 scoped_ptr
<TestRenderer
> renderer(TestRenderer::create(resourceProvider
.get(), &m_proxy
));
4529 int testCaseIndex
= 0;
4530 while (removeRenderPassesCases
[testCaseIndex
].name
) {
4531 RenderPassRemovalTestData testData
;
4532 configureRenderPassTestData(removeRenderPassesCases
[testCaseIndex
].initScript
, testData
, renderer
.get());
4533 LayerTreeHostImpl::removeRenderPasses(LayerTreeHostImpl::CullRenderPassesWithCachedTextures(*renderer
), testData
);
4534 verifyRenderPassTestData(removeRenderPassesCases
[testCaseIndex
], testData
);
4539 // Make sure that scrolls that only pan the pinch viewport, and not the document,
4540 // still force redraw/commit.
4541 void LayerTreeHostImplTest::pinchZoomPanViewportForcesCommitRedraw(const float deviceScaleFactor
)
4543 m_hostImpl
->setDeviceScaleFactor(deviceScaleFactor
);
4545 gfx::Size
layoutSurfaceSize(10, 20);
4546 gfx::Size
deviceSurfaceSize(layoutSurfaceSize
.width() * static_cast<int>(deviceScaleFactor
),
4547 layoutSurfaceSize
.height() * static_cast<int>(deviceScaleFactor
));
4548 float pageScale
= 2;
4549 scoped_ptr
<LayerImpl
> root
= createScrollableLayer(1, layoutSurfaceSize
);
4550 // For this test we want to force scrolls to only pan the pinchZoomViewport
4551 // and not the document, we can verify commit/redraw are requested.
4552 root
->setMaxScrollOffset(gfx::Vector2d());
4553 m_hostImpl
->setRootLayer(root
.Pass());
4554 m_hostImpl
->setViewportSize(layoutSurfaceSize
, deviceSurfaceSize
);
4555 m_hostImpl
->setPageScaleFactorAndLimits(1, 1, pageScale
);
4556 initializeRendererAndDrawFrame();
4558 // Set new page scale on impl thread by pinching.
4559 m_hostImpl
->pinchGestureBegin();
4560 m_hostImpl
->pinchGestureUpdate(pageScale
, gfx::Point());
4561 m_hostImpl
->pinchGestureEnd();
4562 m_hostImpl
->updateRootScrollLayerImplTransform();
4564 gfx::Transform expectedImplTransform
;
4565 expectedImplTransform
.Scale(pageScale
, pageScale
);
4567 // Verify the pinch zoom took place.
4568 EXPECT_EQ(expectedImplTransform
, m_hostImpl
->rootLayer()->implTransform());
4570 // The implTransform ignores the scroll if !pageScalePinchZoomEnabled,
4571 // so no point in continuing without it.
4572 if (!m_hostImpl
->settings().pageScalePinchZoomEnabled
)
4575 m_didRequestCommit
= false;
4576 m_didRequestRedraw
= false;
4578 // This scroll will force the viewport to pan horizontally.
4579 gfx::Vector2d
scrollDelta(5, 0);
4580 EXPECT_EQ(InputHandlerClient::ScrollStarted
, m_hostImpl
->scrollBegin(gfx::Point(0, 0), InputHandlerClient::Gesture
));
4581 m_hostImpl
->scrollBy(gfx::Point(), scrollDelta
);
4582 m_hostImpl
->scrollEnd();
4584 EXPECT_EQ(true, m_didRequestCommit
);
4585 EXPECT_EQ(true, m_didRequestRedraw
);
4587 m_didRequestCommit
= false;
4588 m_didRequestRedraw
= false;
4590 // This scroll will force the viewport to pan vertically.
4591 scrollDelta
= gfx::Vector2d(0, 5);
4592 EXPECT_EQ(InputHandlerClient::ScrollStarted
, m_hostImpl
->scrollBegin(gfx::Point(0, 0), InputHandlerClient::Gesture
));
4593 m_hostImpl
->scrollBy(gfx::Point(), scrollDelta
);
4594 m_hostImpl
->scrollEnd();
4596 EXPECT_EQ(true, m_didRequestCommit
);
4597 EXPECT_EQ(true, m_didRequestRedraw
);
4600 TEST_P(LayerTreeHostImplTest
, pinchZoomPanViewportForcesCommitDeviceScaleFactor1
)
4602 pinchZoomPanViewportForcesCommitRedraw(1);
4605 TEST_P(LayerTreeHostImplTest
, pinchZoomPanViewportForcesCommitDeviceScaleFactor2
)
4607 pinchZoomPanViewportForcesCommitRedraw(2);
4610 // The following test confirms correct operation of scroll of the pinchZoomViewport.
4611 // The device scale factor directly affects computation of the implTransform, so
4612 // we test the two most common use cases.
4613 void LayerTreeHostImplTest::pinchZoomPanViewportTest(const float deviceScaleFactor
)
4615 m_hostImpl
->setDeviceScaleFactor(deviceScaleFactor
);
4617 gfx::Size
layoutSurfaceSize(10, 20);
4618 gfx::Size
deviceSurfaceSize(layoutSurfaceSize
.width() * static_cast<int>(deviceScaleFactor
),
4619 layoutSurfaceSize
.height() * static_cast<int>(deviceScaleFactor
));
4620 float pageScale
= 2;
4621 scoped_ptr
<LayerImpl
> root
= createScrollableLayer(1, layoutSurfaceSize
);
4622 // For this test we want to force scrolls to move the pinchZoomViewport so
4623 // we can see the scroll component on the implTransform.
4624 root
->setMaxScrollOffset(gfx::Vector2d());
4625 m_hostImpl
->setRootLayer(root
.Pass());
4626 m_hostImpl
->setViewportSize(layoutSurfaceSize
, deviceSurfaceSize
);
4627 m_hostImpl
->setPageScaleFactorAndLimits(1, 1, pageScale
);
4628 initializeRendererAndDrawFrame();
4630 // Set new page scale on impl thread by pinching.
4631 m_hostImpl
->pinchGestureBegin();
4632 m_hostImpl
->pinchGestureUpdate(pageScale
, gfx::Point());
4633 m_hostImpl
->pinchGestureEnd();
4634 m_hostImpl
->updateRootScrollLayerImplTransform();
4636 gfx::Transform expectedImplTransform
;
4637 expectedImplTransform
.Scale(pageScale
, pageScale
);
4639 EXPECT_EQ(m_hostImpl
->rootLayer()->implTransform(), expectedImplTransform
);
4641 // The implTransform ignores the scroll if !pageScalePinchZoomEnabled,
4642 // so no point in continuing without it.
4643 if (!m_hostImpl
->settings().pageScalePinchZoomEnabled
)
4646 gfx::Vector2d
scrollDelta(5, 0);
4647 gfx::Vector2d
expectedMaxScroll(m_hostImpl
->rootLayer()->maxScrollOffset());
4648 EXPECT_EQ(InputHandlerClient::ScrollStarted
, m_hostImpl
->scrollBegin(gfx::Point(0, 0), InputHandlerClient::Gesture
));
4649 m_hostImpl
->scrollBy(gfx::Point(), scrollDelta
);
4650 m_hostImpl
->scrollEnd();
4651 m_hostImpl
->updateRootScrollLayerImplTransform();
4653 gfx::Vector2dF expectedTranslation
= gfx::ScaleVector2d(scrollDelta
, m_hostImpl
->deviceScaleFactor());
4654 expectedImplTransform
.Translate(-expectedTranslation
.x(), -expectedTranslation
.y());
4656 EXPECT_EQ(expectedImplTransform
, m_hostImpl
->rootLayer()->implTransform());
4657 // No change expected.
4658 EXPECT_EQ(expectedMaxScroll
, m_hostImpl
->rootLayer()->maxScrollOffset());
4659 // None of the scroll delta should have been used for document scroll.
4660 scoped_ptr
<ScrollAndScaleSet
> scrollInfo
= m_hostImpl
->processScrollDeltas();
4661 expectNone(*scrollInfo
.get(), m_hostImpl
->rootLayer()->id());
4663 // Test scroll in y-direction also.
4664 scrollDelta
= gfx::Vector2d(0, 5);
4665 EXPECT_EQ(InputHandlerClient::ScrollStarted
, m_hostImpl
->scrollBegin(gfx::Point(0, 0), InputHandlerClient::Gesture
));
4666 m_hostImpl
->scrollBy(gfx::Point(), scrollDelta
);
4667 m_hostImpl
->scrollEnd();
4668 m_hostImpl
->updateRootScrollLayerImplTransform();
4670 expectedTranslation
= gfx::ScaleVector2d(scrollDelta
, m_hostImpl
->deviceScaleFactor());
4671 expectedImplTransform
.Translate(-expectedTranslation
.x(), -expectedTranslation
.y());
4673 EXPECT_EQ(expectedImplTransform
, m_hostImpl
->rootLayer()->implTransform());
4674 // No change expected.
4675 EXPECT_EQ(expectedMaxScroll
, m_hostImpl
->rootLayer()->maxScrollOffset());
4676 // None of the scroll delta should have been used for document scroll.
4677 scrollInfo
= m_hostImpl
->processScrollDeltas();
4678 expectNone(*scrollInfo
.get(), m_hostImpl
->rootLayer()->id());
4681 TEST_P(LayerTreeHostImplTest
, pinchZoomPanViewportWithDeviceScaleFactor1
)
4683 pinchZoomPanViewportTest(1);
4686 TEST_P(LayerTreeHostImplTest
, pinchZoomPanViewportWithDeviceScaleFactor2
)
4688 pinchZoomPanViewportTest(2);
4691 // This test verifies the correct behaviour of the document-then-pinchZoomViewport
4692 // scrolling model, in both x- and y-directions.
4693 void LayerTreeHostImplTest::pinchZoomPanViewportAndScrollTest(const float deviceScaleFactor
)
4695 m_hostImpl
->setDeviceScaleFactor(deviceScaleFactor
);
4697 gfx::Size
layoutSurfaceSize(10, 20);
4698 gfx::Size
deviceSurfaceSize(layoutSurfaceSize
.width() * static_cast<int>(deviceScaleFactor
),
4699 layoutSurfaceSize
.height() * static_cast<int>(deviceScaleFactor
));
4700 float pageScale
= 2;
4701 scoped_ptr
<LayerImpl
> root
= createScrollableLayer(1, layoutSurfaceSize
);
4702 // For this test we want to scrolls to move both the document and the
4703 // pinchZoomViewport so we can see some scroll component on the implTransform.
4704 root
->setMaxScrollOffset(gfx::Vector2d(3, 4));
4705 m_hostImpl
->setRootLayer(root
.Pass());
4706 m_hostImpl
->setViewportSize(layoutSurfaceSize
, deviceSurfaceSize
);
4707 m_hostImpl
->setPageScaleFactorAndLimits(1, 1, pageScale
);
4708 initializeRendererAndDrawFrame();
4710 // Set new page scale on impl thread by pinching.
4711 m_hostImpl
->pinchGestureBegin();
4712 m_hostImpl
->pinchGestureUpdate(pageScale
, gfx::Point());
4713 m_hostImpl
->pinchGestureEnd();
4714 m_hostImpl
->updateRootScrollLayerImplTransform();
4716 gfx::Transform expectedImplTransform
;
4717 expectedImplTransform
.Scale(pageScale
, pageScale
);
4719 EXPECT_EQ(expectedImplTransform
, m_hostImpl
->rootLayer()->implTransform());
4721 // The implTransform ignores the scroll if !pageScalePinchZoomEnabled,
4722 // so no point in continuing without it.
4723 if (!m_hostImpl
->settings().pageScalePinchZoomEnabled
)
4726 // Scroll document only: scrollDelta chosen to move document horizontally
4727 // to its max scroll offset.
4728 gfx::Vector2d
scrollDelta(3, 0);
4729 gfx::Vector2d
expectedScrollDelta(scrollDelta
);
4730 gfx::Vector2d
expectedMaxScroll(m_hostImpl
->rootLayer()->maxScrollOffset());
4731 EXPECT_EQ(InputHandlerClient::ScrollStarted
, m_hostImpl
->scrollBegin(gfx::Point(0, 0), InputHandlerClient::Gesture
));
4732 m_hostImpl
->scrollBy(gfx::Point(), scrollDelta
);
4733 m_hostImpl
->scrollEnd();
4734 m_hostImpl
->updateRootScrollLayerImplTransform();
4736 // The scroll delta is not scaled because the main thread did not scale.
4737 scoped_ptr
<ScrollAndScaleSet
> scrollInfo
= m_hostImpl
->processScrollDeltas();
4738 expectContains(*scrollInfo
.get(), m_hostImpl
->rootLayer()->id(), expectedScrollDelta
);
4739 EXPECT_EQ(expectedMaxScroll
, m_hostImpl
->rootLayer()->maxScrollOffset());
4741 // Verify we did not change the implTransform this time.
4742 EXPECT_EQ(expectedImplTransform
, m_hostImpl
->rootLayer()->implTransform());
4744 // Further scrolling should move the pinchZoomViewport only.
4745 scrollDelta
= gfx::Vector2d(2, 0);
4746 EXPECT_EQ(InputHandlerClient::ScrollStarted
, m_hostImpl
->scrollBegin(gfx::Point(0, 0), InputHandlerClient::Gesture
));
4747 m_hostImpl
->scrollBy(gfx::Point(), scrollDelta
);
4748 m_hostImpl
->scrollEnd();
4749 m_hostImpl
->updateRootScrollLayerImplTransform();
4751 gfx::Vector2d
expectedPanDelta(scrollDelta
);
4752 gfx::Vector2dF expectedTranslation
= gfx::ScaleVector2d(expectedPanDelta
, m_hostImpl
->deviceScaleFactor());
4753 expectedImplTransform
.Translate(-expectedTranslation
.x(), -expectedTranslation
.y());
4755 EXPECT_EQ(m_hostImpl
->rootLayer()->implTransform(), expectedImplTransform
);
4757 // The scroll delta on the main thread should not have been affected by this.
4758 scrollInfo
= m_hostImpl
->processScrollDeltas();
4759 expectContains(*scrollInfo
.get(), m_hostImpl
->rootLayer()->id(), expectedScrollDelta
);
4760 EXPECT_EQ(expectedMaxScroll
, m_hostImpl
->rootLayer()->maxScrollOffset());
4762 // Perform same test sequence in y-direction also.
4763 // Document only scroll.
4764 scrollDelta
= gfx::Vector2d(0, 4);
4765 expectedScrollDelta
+= scrollDelta
;
4766 EXPECT_EQ(InputHandlerClient::ScrollStarted
, m_hostImpl
->scrollBegin(gfx::Point(0, 0), InputHandlerClient::Gesture
));
4767 m_hostImpl
->scrollBy(gfx::Point(), scrollDelta
);
4768 m_hostImpl
->scrollEnd();
4769 m_hostImpl
->updateRootScrollLayerImplTransform();
4771 // The scroll delta is not scaled because the main thread did not scale.
4772 scrollInfo
= m_hostImpl
->processScrollDeltas();
4773 expectContains(*scrollInfo
.get(), m_hostImpl
->rootLayer()->id(), expectedScrollDelta
);
4774 EXPECT_EQ(expectedMaxScroll
, m_hostImpl
->rootLayer()->maxScrollOffset());
4776 // Verify we did not change the implTransform this time.
4777 EXPECT_EQ(expectedImplTransform
, m_hostImpl
->rootLayer()->implTransform());
4779 // pinchZoomViewport scroll only.
4780 scrollDelta
= gfx::Vector2d(0, 1);
4781 EXPECT_EQ(InputHandlerClient::ScrollStarted
, m_hostImpl
->scrollBegin(gfx::Point(0, 0), InputHandlerClient::Gesture
));
4782 m_hostImpl
->scrollBy(gfx::Point(), scrollDelta
);
4783 m_hostImpl
->scrollEnd();
4784 m_hostImpl
->updateRootScrollLayerImplTransform();
4786 expectedPanDelta
= scrollDelta
;
4787 expectedTranslation
= gfx::ScaleVector2d(expectedPanDelta
, m_hostImpl
->deviceScaleFactor());
4788 expectedImplTransform
.Translate(-expectedTranslation
.x(), -expectedTranslation
.y());
4790 EXPECT_EQ(expectedImplTransform
, m_hostImpl
->rootLayer()->implTransform());
4792 // The scroll delta on the main thread should not have been affected by this.
4793 scrollInfo
= m_hostImpl
->processScrollDeltas();
4794 expectContains(*scrollInfo
.get(), m_hostImpl
->rootLayer()->id(), expectedScrollDelta
);
4795 EXPECT_EQ(expectedMaxScroll
, m_hostImpl
->rootLayer()->maxScrollOffset());
4798 TEST_P(LayerTreeHostImplTest
, pinchZoomPanViewportAndScrollWithDeviceScaleFactor
)
4800 pinchZoomPanViewportAndScrollTest(1);
4803 TEST_P(LayerTreeHostImplTest
, pinchZoomPanViewportAndScrollWithDeviceScaleFactor2
)
4805 pinchZoomPanViewportAndScrollTest(2);
4808 // This test verifies the correct behaviour of the document-then-pinchZoomViewport
4809 // scrolling model, in both x- and y-directions, but this time using a single scroll
4810 // that crosses the 'boundary' of what will cause document-only scroll and what will
4811 // cause both document-scroll and zoomViewport panning.
4812 void LayerTreeHostImplTest::pinchZoomPanViewportAndScrollBoundaryTest(const float deviceScaleFactor
)
4814 m_hostImpl
->setDeviceScaleFactor(deviceScaleFactor
);
4816 gfx::Size
layoutSurfaceSize(10, 20);
4817 gfx::Size
deviceSurfaceSize(layoutSurfaceSize
.width() * static_cast<int>(deviceScaleFactor
),
4818 layoutSurfaceSize
.height() * static_cast<int>(deviceScaleFactor
));
4819 float pageScale
= 2;
4820 scoped_ptr
<LayerImpl
> root
= createScrollableLayer(1, layoutSurfaceSize
);
4821 // For this test we want to scrolls to move both the document and the
4822 // pinchZoomViewport so we can see some scroll component on the implTransform.
4823 root
->setMaxScrollOffset(gfx::Vector2d(3, 4));
4824 m_hostImpl
->setRootLayer(root
.Pass());
4825 m_hostImpl
->setViewportSize(layoutSurfaceSize
, deviceSurfaceSize
);
4826 m_hostImpl
->setPageScaleFactorAndLimits(1, 1, pageScale
);
4827 initializeRendererAndDrawFrame();
4829 // Set new page scale on impl thread by pinching.
4830 m_hostImpl
->pinchGestureBegin();
4831 m_hostImpl
->pinchGestureUpdate(pageScale
, gfx::Point());
4832 m_hostImpl
->pinchGestureEnd();
4833 m_hostImpl
->updateRootScrollLayerImplTransform();
4835 gfx::Transform expectedImplTransform
;
4836 expectedImplTransform
.Scale(pageScale
, pageScale
);
4838 EXPECT_EQ(expectedImplTransform
, m_hostImpl
->rootLayer()->implTransform());
4840 // The implTransform ignores the scroll if !pageScalePinchZoomEnabled,
4841 // so no point in continuing without it.
4842 if (!m_hostImpl
->settings().pageScalePinchZoomEnabled
)
4845 // Scroll document and pann zoomViewport in one scroll-delta.
4846 gfx::Vector2d
scrollDelta(5, 0);
4847 gfx::Vector2d
expectedScrollDelta(gfx::Vector2d(3, 0)); // This component gets handled by document scroll.
4848 gfx::Vector2d
expectedMaxScroll(m_hostImpl
->rootLayer()->maxScrollOffset());
4850 EXPECT_EQ(InputHandlerClient::ScrollStarted
, m_hostImpl
->scrollBegin(gfx::Point(0, 0), InputHandlerClient::Gesture
));
4851 m_hostImpl
->scrollBy(gfx::Point(), scrollDelta
);
4852 m_hostImpl
->scrollEnd();
4853 m_hostImpl
->updateRootScrollLayerImplTransform();
4855 // The scroll delta is not scaled because the main thread did not scale.
4856 scoped_ptr
<ScrollAndScaleSet
> scrollInfo
= m_hostImpl
->processScrollDeltas();
4857 expectContains(*scrollInfo
.get(), m_hostImpl
->rootLayer()->id(), expectedScrollDelta
);
4858 EXPECT_EQ(expectedMaxScroll
, m_hostImpl
->rootLayer()->maxScrollOffset());
4860 gfx::Vector2d
expectedPanDelta(2, 0); // This component gets handled by zoomViewport pan.
4861 gfx::Vector2dF expectedTranslation
= gfx::ScaleVector2d(expectedPanDelta
, m_hostImpl
->deviceScaleFactor());
4862 expectedImplTransform
.Translate(-expectedTranslation
.x(), -expectedTranslation
.y());
4864 EXPECT_EQ(m_hostImpl
->rootLayer()->implTransform(), expectedImplTransform
);
4866 // Perform same test sequence in y-direction also.
4867 scrollDelta
= gfx::Vector2d(0, 5);
4868 expectedScrollDelta
+= gfx::Vector2d(0, 4); // This component gets handled by document scroll.
4869 EXPECT_EQ(InputHandlerClient::ScrollStarted
, m_hostImpl
->scrollBegin(gfx::Point(0, 0), InputHandlerClient::Gesture
));
4870 m_hostImpl
->scrollBy(gfx::Point(), scrollDelta
);
4871 m_hostImpl
->scrollEnd();
4872 m_hostImpl
->updateRootScrollLayerImplTransform();
4874 // The scroll delta is not scaled because the main thread did not scale.
4875 scrollInfo
= m_hostImpl
->processScrollDeltas(); // This component gets handled by zoomViewport pan.
4876 expectContains(*scrollInfo
.get(), m_hostImpl
->rootLayer()->id(), expectedScrollDelta
);
4877 EXPECT_EQ(expectedMaxScroll
, m_hostImpl
->rootLayer()->maxScrollOffset());
4879 expectedPanDelta
= gfx::Vector2d(0, 1);
4880 expectedTranslation
= gfx::ScaleVector2d(expectedPanDelta
, m_hostImpl
->deviceScaleFactor());
4881 expectedImplTransform
.Translate(-expectedTranslation
.x(), -expectedTranslation
.y());
4883 EXPECT_EQ(expectedImplTransform
, m_hostImpl
->rootLayer()->implTransform());
4886 TEST_P(LayerTreeHostImplTest
, pinchZoomPanViewportAndScrollBoundaryWithDeviceScaleFactor
)
4888 pinchZoomPanViewportAndScrollBoundaryTest(1);
4891 TEST_P(LayerTreeHostImplTest
, pinchZoomPanViewportAndScrollBoundaryWithDeviceScaleFactor2
)
4893 pinchZoomPanViewportAndScrollBoundaryTest(2);
4896 INSTANTIATE_TEST_CASE_P(LayerTreeHostImplTests
,
4897 LayerTreeHostImplTest
,
4898 ::testing::Values(false, true));