Add intro to any Chrome app API with no overview docs.
[chromium-blink-merge.git] / cc / layer_tree_host_impl_unittest.cc
blob58e361ed2b31a7329f6e984d15184d1123061e68
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"
7 #include <cmath>
9 #include "base/bind.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;
56 using ::testing::_;
58 namespace cc {
59 namespace {
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 {
65 public:
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();
78 virtual void SetUp()
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)
140 continue;
141 EXPECT_VECTOR_EQ(scrollDelta, scrollInfo.scrolls[i].scrollDelta);
142 timesEncountered++;
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)
154 continue;
155 timesEncountered++;
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));
190 return layer.Pass();
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);
207 protected:
208 scoped_ptr<GraphicsContext> createContext()
210 return FakeWebCompositorOutputSurface::create(scoped_ptr<WebKit::WebGraphicsContext3D>(new FakeWebGraphicsContext3D)).PassAs<GraphicsContext>();
213 FakeProxy m_proxy;
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 {
225 public:
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
417 // recent render.
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)
546 return;
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();
553 DCHECK(scrollLayer);
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();
606 DCHECK(scrollLayer);
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);
629 // Zoom-in clamping
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);
644 // Zoom-out clamping
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));
662 } else {
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();
714 DCHECK(scrollLayer);
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));
741 // Anchor zoom-out
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();
766 DCHECK(scrollLayer);
768 const float minPageScale = m_hostImpl->settings().pageScalePinchZoomEnabled ? 1 : 0.5;
769 const float maxPageScale = 4;
771 // Pinch zoom in.
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
780 // scale deltas.
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));
791 } else {
792 EXPECT_TRUE(scrollInfo->scrolls.empty());
796 // Pinch zoom out.
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));
810 } else {
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));
821 } else {
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();
835 DCHECK(scrollLayer);
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
854 // animation.
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
867 // earlier.
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 {
875 public:
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;
897 protected:
898 explicit DidDrawCheckLayer(int id)
899 : TiledLayerImpl(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);
907 setSkipsDraw(false);
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());
915 private:
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 {
1032 public:
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));
1038 private:
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);
1046 if (!tileMissing) {
1047 ResourceProvider::ResourceId resource = resourceProvider->createResource(Renderer::ContentPool, gfx::Size(), GL_RGBA, ResourceProvider::TextureUsageAny);
1048 pushTileProperties(0, 0, resource, gfx::Rect(), false);
1050 if (animating)
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
1398 // scroll.
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.
1575 int scale = 2;
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 {
1607 public:
1608 BlendStateTrackerContext() : m_blend(false) { }
1610 virtual void enable(WGC3Denum cap)
1612 if (cap == GL_BLEND)
1613 m_blend = true;
1616 virtual void disable(WGC3Denum cap)
1618 if (cap == GL_BLEND)
1619 m_blend = false;
1622 bool blend() const { return m_blend; }
1624 private:
1625 bool m_blend;
1628 class BlendStateCheckLayer : public LayerImpl {
1629 public:
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;
1639 else
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)
1653 m_blend = blend;
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; }
1664 private:
1665 explicit BlendStateCheckLayer(int id, ResourceProvider* resourceProvider)
1666 : LayerImpl(id)
1667 , m_blend(false)
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);
1680 bool m_blend;
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);
1895 // No gutter rects
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 {
1969 public:
1970 ReshapeTrackerContext() : m_reshapeCalled(false) { }
1972 virtual void reshape(int width, int height)
1974 m_reshapeCalled = true;
1977 bool reshapeCalled() const { return m_reshapeCalled; }
1979 private:
1980 bool m_reshapeCalled;
1983 class FakeDrawableLayerImpl: public LayerImpl {
1984 public:
1985 static scoped_ptr<LayerImpl> create(int id) { return scoped_ptr<LayerImpl>(new FakeDrawableLayerImpl(id)); }
1986 protected:
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 {
2014 public:
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");
2025 return WebString();
2028 gfx::Rect partialSwapRect() const { return m_partialSwapRect; }
2030 private:
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);
2135 } // namespace
2137 class FakeLayerWithQuads : public LayerImpl {
2138 public:
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);
2152 private:
2153 FakeLayerWithQuads(int id)
2154 : LayerImpl(id)
2159 namespace {
2161 class MockContext : public FakeWebGraphicsContext3D {
2162 public:
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 {
2175 private:
2176 MockContext* m_context;
2177 public:
2178 MockContextHarness(MockContext* context)
2179 : m_context(context)
2181 // Catch "uninteresting" calls
2182 EXPECT_CALL(*m_context, useProgram(_))
2183 .Times(0);
2185 EXPECT_CALL(*m_context, drawElements(_, _, _, _))
2186 .Times(0);
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))
2218 .WillOnce(Return())
2219 .RetiresOnSaturation();
2221 // 1 is hardcoded return value of fake createProgram()
2222 EXPECT_CALL(*m_context, useProgram(1))
2223 .WillOnce(Return())
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))
2234 .Times(AtLeast(1))
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))
2244 .Times(0);
2246 EXPECT_CALL(*m_context, scissor(_, _, _, _))
2247 .Times(0);
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);
2257 // Run test case
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 {
2319 public:
2320 WebString getString(WGC3Denum name)
2322 if (name == GL_EXTENSIONS)
2323 return WebString("GL_CHROMIUM_post_sub_buffer");
2324 return WebString();
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)
2336 *value = 8192;
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 +--------------------+
2354 | 1 |
2355 | +-----------+ |
2356 | | 2 | |
2357 | | +-------------------+
2358 | | | 3 |
2359 | | +-------------------+
2360 | | | |
2361 | +-----------+ |
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 {
2452 public:
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; }
2462 private:
2463 explicit ContextLostNotificationCheckLayer(int id)
2464 : LayerImpl(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 {
2505 public:
2506 explicit FakeWebGraphicsContext3DMakeCurrentFailsEventually(unsigned succeedCount) : m_succeedCount(succeedCount) { }
2507 virtual bool makeContextCurrent() {
2508 if (!m_succeedCount)
2509 return false;
2510 --m_succeedCount;
2511 return true;
2514 private:
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 {
2555 public:
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)
2572 if (id != 2)
2573 ADD_FAILURE() << "Trying to delete buffer id " << id;
2576 virtual void deleteFramebuffer(WebGLId id)
2578 if (id != 3)
2579 ADD_FAILURE() << "Trying to delete framebuffer id " << id;
2582 virtual void deleteProgram(WebGLId id)
2584 if (id != 4)
2585 ADD_FAILURE() << "Trying to delete program id " << id;
2588 virtual void deleteRenderbuffer(WebGLId id)
2590 if (id != 5)
2591 ADD_FAILURE() << "Trying to delete renderbuffer id " << id;
2594 virtual void deleteShader(WebGLId id)
2596 if (id != 6)
2597 ADD_FAILURE() << "Trying to delete shader id " << id;
2600 virtual WebGLId createTexture()
2602 unsigned textureId = FakeWebGraphicsContext3D::createTexture();
2603 m_allocatedTextureIds.insert(textureId);
2604 return 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)
2617 if (id != 2 && id)
2618 ADD_FAILURE() << "Trying to bind buffer id " << id;
2621 virtual void bindFramebuffer(WGC3Denum, WebGLId id)
2623 if (id != 3 && id)
2624 ADD_FAILURE() << "Trying to bind framebuffer id " << id;
2627 virtual void useProgram(WebGLId id)
2629 if (id != 4)
2630 ADD_FAILURE() << "Trying to use program id " << id;
2633 virtual void bindRenderbuffer(WGC3Denum, WebGLId id)
2635 if (id != 5 && 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;
2651 private:
2652 base::hash_set<unsigned> m_allocatedTextureIds;
2655 // Fake WebVideoFrame wrapper of media::VideoFrame.
2656 class FakeVideoFrame: public WebVideoFrame {
2657 public:
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);
2675 if (wrapped_frame)
2676 return wrapped_frame->m_frame.get();
2677 return NULL;
2680 private:
2681 scoped_refptr<VideoFrame> m_frame;
2684 // Fake video frame provider that always provides the same FakeVideoFrame.
2685 class FakeVideoFrameProvider: public WebVideoFrameProvider {
2686 public:
2687 FakeVideoFrameProvider() : m_frame(0), m_client(0) { }
2688 virtual ~FakeVideoFrameProvider()
2690 if (m_client)
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; }
2700 private:
2701 WebVideoFrame* m_frame;
2702 Client* m_client;
2705 class StrictWebGraphicsContext3DWithIOSurface : public StrictWebGraphicsContext3D {
2706 public:
2707 virtual WebString getString(WGC3Denum name) OVERRIDE
2709 if (name == GL_EXTENSIONS)
2710 return WebString("GL_CHROMIUM_iosurface GL_ARB_texture_rectangle");
2712 return WebString();
2716 class FakeWebGraphicsContext3DWithIOSurface : public FakeWebGraphicsContext3D {
2717 public:
2718 virtual WebString getString(WGC3Denum name) OVERRIDE
2720 if (name == GL_EXTENSIONS)
2721 return WebString("GL_CHROMIUM_iosurface GL_ARB_texture_rectangle");
2723 return WebString();
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 {
2739 public:
2740 static scoped_ptr<FakeScrollbarLayerImpl> create(int id)
2742 return make_scoped_ptr(new FakeScrollbarLayerImpl(id));
2745 void createResources(ResourceProvider* provider)
2747 DCHECK(provider);
2748 int pool = 0;
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));
2759 protected:
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)
2785 int layerId = 1;
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),
2830 0x80, 0x80, 0x80,
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(),
2904 GL_TEXTURE_2D,
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(),
2912 GL_TEXTURE_2D,
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(),
2949 GL_TEXTURE_2D,
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 {
2962 public:
2963 TrackingWebGraphicsContext3D()
2964 : FakeWebGraphicsContext3D()
2965 , m_numTextures(0)
2968 virtual WebGLId createTexture() OVERRIDE
2970 WebGLId id = FakeWebGraphicsContext3D::createTexture();
2972 m_textures[id] = true;
2973 ++m_numTextures;
2974 return id;
2977 virtual void deleteTexture(WebGLId id) OVERRIDE
2979 if (m_textures.find(id) == m_textures.end())
2980 return;
2982 m_textures[id] = false;
2983 --m_numTextures;
2986 virtual WebString getString(WGC3Denum name) OVERRIDE
2988 if (name == GL_EXTENSIONS)
2989 return WebString("GL_CHROMIUM_iosurface GL_ARB_texture_rectangle");
2991 return WebString();
2994 unsigned numTextures() const { return m_numTextures; }
2996 private:
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 {
3069 public:
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());
3079 // Run test case
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(_))
3086 .Times(1);
3087 EXPECT_CALL(*mockContext, drawElements(_, _, _, _))
3088 .Times(1);
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());
3114 if (result)
3115 *result = layerPtr;
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 {
3150 public:
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);
3161 LayerImpl* rootPtr;
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)
3260 // | +- L11
3261 // | +- L12
3262 // |
3263 // +-- S2 +- L20 (owning)
3264 // +- L21
3266 // Occlusion:
3267 // L12 occludes L11 (internal)
3268 // L20 occludes L10 (external)
3269 // L21 occludes L20 (internal)
3271 LayerImpl* rootPtr;
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)
3378 // |
3379 // +-- S2 +- L20 (owning, drawing)
3382 LayerImpl* rootPtr;
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)
3490 // |
3491 // +-- S2 +- L20 (owning, drawing)
3494 LayerImpl* rootPtr;
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)
3576 LayerImpl* rootPtr;
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)
3648 // | +- L11
3649 // | +- L12
3650 // |
3651 // +-- S2 +- L20 (owning)
3652 // +- L21
3654 // Occlusion:
3655 // L12 occludes L11 (internal)
3656 // L20 occludes L10 (external)
3657 // L21 occludes L20 (internal)
3659 LayerImpl* rootPtr;
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 +--------------------+
3760 | 1 |
3761 | +-----------+ |
3762 | | 2 | |
3763 | | +-------------------+
3764 | | | 3 |
3765 | | +-------------------+
3766 | | | |
3767 | +-----------+ |
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);
3862 LayerImpl* rootPtr;
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);
4021 LayerImpl* rootPtr;
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
4190 // to re-commit.
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
4198 // re-commit.
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 {
4210 public:
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; }
4235 protected:
4236 TestRenderer(ResourceProvider* resourceProvider, Proxy* proxy) : GLRenderer(this, resourceProvider) { }
4238 private:
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;
4261 currentChar++;
4262 ASSERT_TRUE(currentChar);
4263 int index = *currentChar;
4264 currentChar++;
4266 RenderPass::Id renderPassId = RenderPass::Id(layerId, index);
4268 bool isReplica = false;
4269 if (!testData.renderPassCache.contains(renderPassId))
4270 isReplica = true;
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>());
4282 currentChar++;
4283 } else if ((*currentChar >= 'A') && (*currentChar <= 'Z')) {
4284 // RenderPass draw quad
4285 int layerId = *currentChar;
4286 currentChar++;
4287 ASSERT_TRUE(currentChar);
4288 int index = *currentChar;
4289 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 == '[') {
4296 currentChar++;
4297 while (*currentChar && *currentChar != ']') {
4298 switch (*currentChar) {
4299 case 'c':
4300 contentsChanged = false;
4301 break;
4302 case 't':
4303 hasTexture = true;
4304 break;
4306 currentChar++;
4308 if (*currentChar == ']')
4309 currentChar++;
4312 if (testData.renderPassCache.find(newRenderPassId) == testData.renderPassCache.end()) {
4313 if (hasTexture)
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>());
4330 if (*currentChar)
4331 currentChar++;
4335 void dumpRenderPassTestData(const RenderPassRemovalTestData& testData, char* buffer)
4337 char* pos = 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;
4341 pos++;
4342 *pos = currentPass->id.index;
4343 pos++;
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:
4350 *pos = 's';
4351 pos++;
4352 break;
4353 case DrawQuad::RENDER_PASS:
4354 *pos = RenderPassDrawQuad::MaterialCast(currentQuad)->render_pass_id.layer_id;
4355 pos++;
4356 *pos = RenderPassDrawQuad::MaterialCast(currentQuad)->render_pass_id.index;
4357 pos++;
4358 break;
4359 default:
4360 *pos = 'x';
4361 pos++;
4362 break;
4365 quadListIterator++;
4367 *pos = '\n';
4368 pos++;
4370 *pos = '\0';
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.
4390 struct TestCase {
4391 const char* name;
4392 const char* initScript;
4393 const char* expectedResult;
4396 TestCase removeRenderPassesCases[] =
4399 "Single root pass",
4400 "R0ssss\n",
4401 "R0ssss\n"
4402 }, {
4403 "Single pass - no quads",
4404 "R0\n",
4405 "R0\n"
4406 }, {
4407 "Two passes, no removal",
4408 "R0ssssA0sss\n"
4409 "A0ssss\n",
4410 "R0ssssA0sss\n"
4411 "A0ssss\n"
4412 }, {
4413 "Two passes, remove last",
4414 "R0ssssA0[ct]sss\n"
4415 "A0ssss\n",
4416 "R0ssssA0sss\n"
4417 }, {
4418 "Have texture but contents changed - leave pass",
4419 "R0ssssA0[t]sss\n"
4420 "A0ssss\n",
4421 "R0ssssA0sss\n"
4422 "A0ssss\n"
4423 }, {
4424 "Contents didn't change but no texture - leave pass",
4425 "R0ssssA0[c]sss\n"
4426 "A0ssss\n",
4427 "R0ssssA0sss\n"
4428 "A0ssss\n"
4429 }, {
4430 "Replica: two quads reference the same pass; remove",
4431 "R0ssssA0[ct]A0[ct]sss\n"
4432 "A0ssss\n",
4433 "R0ssssA0A0sss\n"
4434 }, {
4435 "Replica: two quads reference the same pass; leave",
4436 "R0ssssA0[c]A0[c]sss\n"
4437 "A0ssss\n",
4438 "R0ssssA0A0sss\n"
4439 "A0ssss\n",
4440 }, {
4441 "Many passes, remove all",
4442 "R0ssssA0[ct]sss\n"
4443 "A0sssB0[ct]C0[ct]s\n"
4444 "B0sssD0[ct]ssE0[ct]F0[ct]\n"
4445 "E0ssssss\n"
4446 "C0G0[ct]\n"
4447 "D0sssssss\n"
4448 "F0sssssss\n"
4449 "G0sss\n",
4451 "R0ssssA0sss\n"
4452 }, {
4453 "Deep recursion, remove all",
4455 "R0sssssA0[ct]ssss\n"
4456 "A0ssssB0sss\n"
4457 "B0C0\n"
4458 "C0D0\n"
4459 "D0E0\n"
4460 "E0F0\n"
4461 "F0G0\n"
4462 "G0H0\n"
4463 "H0sssI0sss\n"
4464 "I0J0\n"
4465 "J0ssss\n",
4467 "R0sssssA0ssss\n"
4468 }, {
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"
4471 "A0s\n"
4472 "B0s\n"
4473 "C0ssss\n"
4474 "D0ssss\n"
4475 "E0s\n"
4476 "F0\n"
4477 "G0s\n"
4478 "H0s\n"
4479 "I0s\n"
4480 "J0ssss\n",
4482 "R0A0B0C0D0E0F0G0H0I0J0\n"
4483 }, {
4484 "Remove passes regardless of cache state",
4485 "R0ssssA0[ct]sss\n"
4486 "A0sssB0C0s\n"
4487 "B0sssD0[c]ssE0[t]F0\n"
4488 "E0ssssss\n"
4489 "C0G0\n"
4490 "D0sssssss\n"
4491 "F0sssssss\n"
4492 "G0sss\n",
4494 "R0ssssA0sss\n"
4495 }, {
4496 "Leave some passes, remove others",
4498 "R0ssssA0[c]sss\n"
4499 "A0sssB0[t]C0[ct]s\n"
4500 "B0sssD0[c]ss\n"
4501 "C0G0\n"
4502 "D0sssssss\n"
4503 "G0sss\n",
4505 "R0ssssA0sss\n"
4506 "A0sssB0C0s\n"
4507 "B0sssD0ss\n"
4508 "D0sssssss\n"
4509 }, {
4510 0, 0, 0
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);
4535 testCaseIndex++;
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)
4573 return;
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)
4644 return;
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)
4724 return;
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)
4843 return;
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));
4900 } // namespace
4901 } // namespace cc