Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(621)

Side by Side Diff: cc/CCLayerTreeHostImplTest.cpp

Issue 11108020: [cc] Change cc_tests.gyp filenames to Chromium style (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Rebase Created 8 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « cc/CCLayerTreeHostCommonTest.cpp ('k') | cc/CCLayerTreeHostTest.cpp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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.
4
5 #include "config.h"
6
7 #include "CCLayerTreeHostImpl.h"
8
9 #include "CCAnimationTestCommon.h"
10 #include "CCDelegatedRendererLayerImpl.h"
11 #include "CCGeometryTestUtils.h"
12 #include "CCHeadsUpDisplayLayerImpl.h"
13 #include "CCIOSurfaceLayerImpl.h"
14 #include "CCLayerImpl.h"
15 #include "CCLayerTestCommon.h"
16 #include "CCLayerTilingData.h"
17 #include "CCQuadSink.h"
18 #include "CCRenderPassDrawQuad.h"
19 #include "CCRenderPassTestCommon.h"
20 #include "CCRendererGL.h"
21 #include "CCScrollbarGeometryFixedThumb.h"
22 #include "CCScrollbarLayerImpl.h"
23 #include "CCSettings.h"
24 #include "CCSingleThreadProxy.h"
25 #include "CCSolidColorDrawQuad.h"
26 #include "CCTestCommon.h"
27 #include "CCTextureDrawQuad.h"
28 #include "CCTextureLayerImpl.h"
29 #include "CCTileDrawQuad.h"
30 #include "CCTiledLayerImpl.h"
31 #include "CCVideoLayerImpl.h"
32 #include "FakeWebCompositorOutputSurface.h"
33 #include "FakeWebGraphicsContext3D.h"
34 #include "FakeWebScrollbarThemeGeometry.h"
35 #include "base/hash_tables.h"
36 #include "testing/gmock/include/gmock/gmock.h"
37 #include "testing/gtest/include/gtest/gtest.h"
38 #include <public/WebVideoFrame.h>
39 #include <public/WebVideoFrameProvider.h>
40
41 using namespace cc;
42 using namespace CCLayerTestCommon;
43 using namespace WebKit;
44 using namespace WebKitTests;
45
46 using ::testing::Mock;
47 using ::testing::Return;
48 using ::testing::AnyNumber;
49 using ::testing::AtLeast;
50 using ::testing::_;
51
52 namespace {
53
54 // This test is parametrized to run all tests with the
55 // CCSettings::pageScalePinchZoomEnabled field enabled and disabled.
56 class CCLayerTreeHostImplTest : public testing::TestWithParam<bool>,
57 public CCLayerTreeHostImplClient {
58 public:
59 CCLayerTreeHostImplTest()
60 : m_onCanDrawStateChangedCalled(false)
61 , m_didRequestCommit(false)
62 , m_didRequestRedraw(false)
63 {
64 }
65
66 virtual void SetUp()
67 {
68 CCSettings::setPageScalePinchZoomEnabled(GetParam());
69 CCLayerTreeSettings settings;
70 settings.minimumOcclusionTrackingSize = IntSize();
71
72 m_hostImpl = CCLayerTreeHostImpl::create(settings, this);
73 m_hostImpl->initializeRenderer(createContext());
74 m_hostImpl->setViewportSize(IntSize(10, 10), IntSize(10, 10));
75 }
76
77 virtual void TearDown()
78 {
79 CCSettings::reset();
80 }
81
82 virtual void didLoseContextOnImplThread() OVERRIDE { }
83 virtual void onSwapBuffersCompleteOnImplThread() OVERRIDE { }
84 virtual void onVSyncParametersChanged(double, double) OVERRIDE { }
85 virtual void onCanDrawStateChanged(bool canDraw) OVERRIDE { m_onCanDrawState ChangedCalled = true; }
86 virtual void setNeedsRedrawOnImplThread() OVERRIDE { m_didRequestRedraw = tr ue; }
87 virtual void setNeedsCommitOnImplThread() OVERRIDE { m_didRequestCommit = tr ue; }
88 virtual void postAnimationEventsToMainThreadOnImplThread(scoped_ptr<CCAnimat ionEventsVector>, double wallClockTime) OVERRIDE { }
89 virtual void releaseContentsTexturesOnImplThread() OVERRIDE { }
90
91 scoped_ptr<CCLayerTreeHostImpl> createLayerTreeHost(bool partialSwap, scoped _ptr<CCGraphicsContext> graphicsContext, scoped_ptr<CCLayerImpl> root)
92 {
93 CCSettings::setPartialSwapEnabled(partialSwap);
94
95 CCLayerTreeSettings settings;
96 settings.minimumOcclusionTrackingSize = IntSize();
97
98 scoped_ptr<CCLayerTreeHostImpl> myHostImpl = CCLayerTreeHostImpl::create (settings, this);
99
100 myHostImpl->initializeRenderer(graphicsContext.Pass());
101 myHostImpl->setViewportSize(IntSize(10, 10), IntSize(10, 10));
102
103 root->setAnchorPoint(FloatPoint(0, 0));
104 root->setPosition(FloatPoint(0, 0));
105 root->setBounds(IntSize(10, 10));
106 root->setContentBounds(IntSize(10, 10));
107 root->setVisibleContentRect(IntRect(0, 0, 10, 10));
108 root->setDrawsContent(true);
109 myHostImpl->setRootLayer(root.Pass());
110 return myHostImpl.Pass();
111 }
112
113 static void expectClearedScrollDeltasRecursive(CCLayerImpl* layer)
114 {
115 ASSERT_EQ(layer->scrollDelta(), IntSize());
116 for (size_t i = 0; i < layer->children().size(); ++i)
117 expectClearedScrollDeltasRecursive(layer->children()[i]);
118 }
119
120 static void expectContains(const CCScrollAndScaleSet& scrollInfo, int id, co nst IntSize& scrollDelta)
121 {
122 int timesEncountered = 0;
123
124 for (size_t i = 0; i < scrollInfo.scrolls.size(); ++i) {
125 if (scrollInfo.scrolls[i].layerId != id)
126 continue;
127 EXPECT_EQ(scrollDelta.width(), scrollInfo.scrolls[i].scrollDelta.wid th());
128 EXPECT_EQ(scrollDelta.height(), scrollInfo.scrolls[i].scrollDelta.he ight());
129 timesEncountered++;
130 }
131
132 ASSERT_EQ(timesEncountered, 1);
133 }
134
135 void setupScrollAndContentsLayers(const IntSize& contentSize)
136 {
137 scoped_ptr<CCLayerImpl> root = CCLayerImpl::create(1);
138 root->setScrollable(true);
139 root->setScrollPosition(IntPoint(0, 0));
140 root->setMaxScrollPosition(contentSize);
141 root->setBounds(contentSize);
142 root->setContentBounds(contentSize);
143 root->setPosition(FloatPoint(0, 0));
144 root->setAnchorPoint(FloatPoint(0, 0));
145
146 scoped_ptr<CCLayerImpl> contents = CCLayerImpl::create(2);
147 contents->setDrawsContent(true);
148 contents->setBounds(contentSize);
149 contents->setContentBounds(contentSize);
150 contents->setPosition(FloatPoint(0, 0));
151 contents->setAnchorPoint(FloatPoint(0, 0));
152 root->addChild(contents.Pass());
153 m_hostImpl->setRootLayer(root.Pass());
154 }
155
156 static scoped_ptr<CCLayerImpl> createScrollableLayer(int id, const IntSize& size)
157 {
158 scoped_ptr<CCLayerImpl> layer = CCLayerImpl::create(id);
159 layer->setScrollable(true);
160 layer->setDrawsContent(true);
161 layer->setBounds(size);
162 layer->setContentBounds(size);
163 layer->setMaxScrollPosition(IntSize(size.width() * 2, size.height() * 2) );
164 return layer.Pass();
165 }
166
167 void initializeRendererAndDrawFrame()
168 {
169 m_hostImpl->initializeRenderer(createContext());
170 CCLayerTreeHostImpl::FrameData frame;
171 EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
172 m_hostImpl->drawLayers(frame);
173 m_hostImpl->didDrawAllLayers(frame);
174 }
175
176 protected:
177 scoped_ptr<CCGraphicsContext> createContext()
178 {
179 return FakeWebCompositorOutputSurface::create(adoptPtr(new FakeWebGraphi csContext3D)).PassAs<CCGraphicsContext>();
180 }
181
182 DebugScopedSetImplThread m_alwaysImplThread;
183 DebugScopedSetMainThreadBlocked m_alwaysMainThreadBlocked;
184
185 scoped_ptr<CCLayerTreeHostImpl> m_hostImpl;
186 bool m_onCanDrawStateChangedCalled;
187 bool m_didRequestCommit;
188 bool m_didRequestRedraw;
189 CCScopedSettings m_scopedSettings;
190 };
191
192 class FakeWebGraphicsContext3DMakeCurrentFails : public FakeWebGraphicsContext3D {
193 public:
194 virtual bool makeContextCurrent() { return false; }
195 };
196
197 TEST_P(CCLayerTreeHostImplTest, notifyIfCanDrawChanged)
198 {
199 // Note: It is not possible to disable the renderer once it has been set,
200 // so we do not need to test that disabling the renderer notifies us
201 // that canDraw changed.
202 EXPECT_FALSE(m_hostImpl->canDraw());
203 m_onCanDrawStateChangedCalled = false;
204
205 setupScrollAndContentsLayers(IntSize(100, 100));
206 EXPECT_TRUE(m_hostImpl->canDraw());
207 EXPECT_TRUE(m_onCanDrawStateChangedCalled);
208 m_onCanDrawStateChangedCalled = false;
209
210 // Toggle the root layer to make sure it toggles canDraw
211 m_hostImpl->setRootLayer(scoped_ptr<CCLayerImpl>());
212 EXPECT_FALSE(m_hostImpl->canDraw());
213 EXPECT_TRUE(m_onCanDrawStateChangedCalled);
214 m_onCanDrawStateChangedCalled = false;
215
216 setupScrollAndContentsLayers(IntSize(100, 100));
217 EXPECT_TRUE(m_hostImpl->canDraw());
218 EXPECT_TRUE(m_onCanDrawStateChangedCalled);
219 m_onCanDrawStateChangedCalled = false;
220
221 // Toggle the device viewport size to make sure it toggles canDraw.
222 m_hostImpl->setViewportSize(IntSize(100, 100), IntSize(0, 0));
223 EXPECT_FALSE(m_hostImpl->canDraw());
224 EXPECT_TRUE(m_onCanDrawStateChangedCalled);
225 m_onCanDrawStateChangedCalled = false;
226
227 m_hostImpl->setViewportSize(IntSize(100, 100), IntSize(100, 100));
228 EXPECT_TRUE(m_hostImpl->canDraw());
229 EXPECT_TRUE(m_onCanDrawStateChangedCalled);
230 m_onCanDrawStateChangedCalled = false;
231
232 // Toggle contents textures purged to make sure it toggles canDraw
233 m_hostImpl->releaseContentsTextures();
234 EXPECT_FALSE(m_hostImpl->canDraw());
235 EXPECT_TRUE(m_onCanDrawStateChangedCalled);
236 m_onCanDrawStateChangedCalled = false;
237
238 m_hostImpl->resetContentsTexturesPurged();
239 EXPECT_TRUE(m_hostImpl->canDraw());
240 EXPECT_TRUE(m_onCanDrawStateChangedCalled);
241 m_onCanDrawStateChangedCalled = false;
242 }
243
244 TEST_P(CCLayerTreeHostImplTest, scrollDeltaNoLayers)
245 {
246 ASSERT_FALSE(m_hostImpl->rootLayer());
247
248 scoped_ptr<CCScrollAndScaleSet> scrollInfo = m_hostImpl->processScrollDeltas ();
249 ASSERT_EQ(scrollInfo->scrolls.size(), 0u);
250 }
251
252 TEST_P(CCLayerTreeHostImplTest, scrollDeltaTreeButNoChanges)
253 {
254 {
255 scoped_ptr<CCLayerImpl> root = CCLayerImpl::create(1);
256 root->addChild(CCLayerImpl::create(2));
257 root->addChild(CCLayerImpl::create(3));
258 root->children()[1]->addChild(CCLayerImpl::create(4));
259 root->children()[1]->addChild(CCLayerImpl::create(5));
260 root->children()[1]->children()[0]->addChild(CCLayerImpl::create(6));
261 m_hostImpl->setRootLayer(root.Pass());
262 }
263 CCLayerImpl* root = m_hostImpl->rootLayer();
264
265 expectClearedScrollDeltasRecursive(root);
266
267 scoped_ptr<CCScrollAndScaleSet> scrollInfo;
268
269 scrollInfo = m_hostImpl->processScrollDeltas();
270 ASSERT_EQ(scrollInfo->scrolls.size(), 0u);
271 expectClearedScrollDeltasRecursive(root);
272
273 scrollInfo = m_hostImpl->processScrollDeltas();
274 ASSERT_EQ(scrollInfo->scrolls.size(), 0u);
275 expectClearedScrollDeltasRecursive(root);
276 }
277
278 TEST_P(CCLayerTreeHostImplTest, scrollDeltaRepeatedScrolls)
279 {
280 IntPoint scrollPosition(20, 30);
281 IntSize scrollDelta(11, -15);
282 {
283 scoped_ptr<CCLayerImpl> root = CCLayerImpl::create(1);
284 root->setScrollPosition(scrollPosition);
285 root->setScrollable(true);
286 root->setMaxScrollPosition(IntSize(100, 100));
287 root->scrollBy(scrollDelta);
288 m_hostImpl->setRootLayer(root.Pass());
289 }
290 CCLayerImpl* root = m_hostImpl->rootLayer();
291
292 scoped_ptr<CCScrollAndScaleSet> scrollInfo;
293
294 scrollInfo = m_hostImpl->processScrollDeltas();
295 ASSERT_EQ(scrollInfo->scrolls.size(), 1u);
296 EXPECT_EQ(root->sentScrollDelta(), scrollDelta);
297 expectContains(*scrollInfo, root->id(), scrollDelta);
298
299 IntSize scrollDelta2(-5, 27);
300 root->scrollBy(scrollDelta2);
301 scrollInfo = m_hostImpl->processScrollDeltas();
302 ASSERT_EQ(scrollInfo->scrolls.size(), 1u);
303 EXPECT_EQ(root->sentScrollDelta(), scrollDelta + scrollDelta2);
304 expectContains(*scrollInfo, root->id(), scrollDelta + scrollDelta2);
305
306 root->scrollBy(IntSize());
307 scrollInfo = m_hostImpl->processScrollDeltas();
308 EXPECT_EQ(root->sentScrollDelta(), scrollDelta + scrollDelta2);
309 }
310
311 TEST_P(CCLayerTreeHostImplTest, scrollRootCallsCommitAndRedraw)
312 {
313 setupScrollAndContentsLayers(IntSize(100, 100));
314 m_hostImpl->setViewportSize(IntSize(50, 50), IntSize(50, 50));
315 initializeRendererAndDrawFrame();
316
317 EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(0, 0), CCInputHandlerClient::Whee l), CCInputHandlerClient::ScrollStarted);
318 m_hostImpl->scrollBy(IntPoint(), IntSize(0, 10));
319 m_hostImpl->scrollEnd();
320 EXPECT_TRUE(m_didRequestRedraw);
321 EXPECT_TRUE(m_didRequestCommit);
322 }
323
324 TEST_P(CCLayerTreeHostImplTest, scrollWithoutRootLayer)
325 {
326 // We should not crash when trying to scroll an empty layer tree.
327 EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(0, 0), CCInputHandlerClient::Whee l), CCInputHandlerClient::ScrollIgnored);
328 }
329
330 TEST_P(CCLayerTreeHostImplTest, scrollWithoutRenderer)
331 {
332 CCLayerTreeSettings settings;
333 m_hostImpl = CCLayerTreeHostImpl::create(settings, this);
334
335 // Initialization will fail here.
336 m_hostImpl->initializeRenderer(FakeWebCompositorOutputSurface::create(adoptP tr(new FakeWebGraphicsContext3DMakeCurrentFails)).PassAs<CCGraphicsContext>());
337 m_hostImpl->setViewportSize(IntSize(10, 10), IntSize(10, 10));
338
339 setupScrollAndContentsLayers(IntSize(100, 100));
340
341 // We should not crash when trying to scroll after the renderer initializati on fails.
342 EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(0, 0), CCInputHandlerClient::Whee l), CCInputHandlerClient::ScrollIgnored);
343 }
344
345 TEST_P(CCLayerTreeHostImplTest, replaceTreeWhileScrolling)
346 {
347 const int scrollLayerId = 1;
348
349 setupScrollAndContentsLayers(IntSize(100, 100));
350 m_hostImpl->setViewportSize(IntSize(50, 50), IntSize(50, 50));
351 initializeRendererAndDrawFrame();
352
353 // We should not crash if the tree is replaced while we are scrolling.
354 EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(0, 0), CCInputHandlerClient::Whee l), CCInputHandlerClient::ScrollStarted);
355 m_hostImpl->detachLayerTree();
356
357 setupScrollAndContentsLayers(IntSize(100, 100));
358
359 // We should still be scrolling, because the scrolled layer also exists in t he new tree.
360 IntSize scrollDelta(0, 10);
361 m_hostImpl->scrollBy(IntPoint(), scrollDelta);
362 m_hostImpl->scrollEnd();
363 scoped_ptr<CCScrollAndScaleSet> scrollInfo = m_hostImpl->processScrollDeltas ();
364 expectContains(*scrollInfo, scrollLayerId, scrollDelta);
365 }
366
367 TEST_P(CCLayerTreeHostImplTest, clearRootRenderSurfaceAndScroll)
368 {
369 setupScrollAndContentsLayers(IntSize(100, 100));
370 m_hostImpl->setViewportSize(IntSize(50, 50), IntSize(50, 50));
371 initializeRendererAndDrawFrame();
372
373 // We should be able to scroll even if the root layer loses its render surfa ce after the most
374 // recent render.
375 m_hostImpl->rootLayer()->clearRenderSurface();
376 EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(0, 0), CCInputHandlerClient::Whee l), CCInputHandlerClient::ScrollStarted);
377 }
378
379 TEST_P(CCLayerTreeHostImplTest, wheelEventHandlers)
380 {
381 setupScrollAndContentsLayers(IntSize(100, 100));
382 m_hostImpl->setViewportSize(IntSize(50, 50), IntSize(50, 50));
383 initializeRendererAndDrawFrame();
384 CCLayerImpl* root = m_hostImpl->rootLayer();
385
386 root->setHaveWheelEventHandlers(true);
387
388 // With registered event handlers, wheel scrolls have to go to the main thre ad.
389 EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(0, 0), CCInputHandlerClient::Whee l), CCInputHandlerClient::ScrollOnMainThread);
390
391 // But gesture scrolls can still be handled.
392 EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(0, 0), CCInputHandlerClient::Gest ure), CCInputHandlerClient::ScrollStarted);
393 }
394
395 TEST_P(CCLayerTreeHostImplTest, shouldScrollOnMainThread)
396 {
397 setupScrollAndContentsLayers(IntSize(100, 100));
398 m_hostImpl->setViewportSize(IntSize(50, 50), IntSize(50, 50));
399 initializeRendererAndDrawFrame();
400 CCLayerImpl* root = m_hostImpl->rootLayer();
401
402 root->setShouldScrollOnMainThread(true);
403
404 EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(0, 0), CCInputHandlerClient::Whee l), CCInputHandlerClient::ScrollOnMainThread);
405 EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(0, 0), CCInputHandlerClient::Gest ure), CCInputHandlerClient::ScrollOnMainThread);
406 }
407
408 TEST_P(CCLayerTreeHostImplTest, nonFastScrollableRegionBasic)
409 {
410 setupScrollAndContentsLayers(IntSize(200, 200));
411 m_hostImpl->setViewportSize(IntSize(100, 100), IntSize(100, 100));
412 initializeRendererAndDrawFrame();
413 CCLayerImpl* root = m_hostImpl->rootLayer();
414
415 root->setNonFastScrollableRegion(IntRect(0, 0, 50, 50));
416
417 // All scroll types inside the non-fast scrollable region should fail.
418 EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(25, 25), CCInputHandlerClient::Wh eel), CCInputHandlerClient::ScrollOnMainThread);
419 EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(25, 25), CCInputHandlerClient::Ge sture), CCInputHandlerClient::ScrollOnMainThread);
420
421 // All scroll types outside this region should succeed.
422 EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(75, 75), CCInputHandlerClient::Wh eel), CCInputHandlerClient::ScrollStarted);
423 m_hostImpl->scrollBy(IntPoint(), IntSize(0, 10));
424 m_hostImpl->scrollEnd();
425 EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(75, 75), CCInputHandlerClient::Ge sture), CCInputHandlerClient::ScrollStarted);
426 m_hostImpl->scrollBy(IntPoint(), IntSize(0, 10));
427 m_hostImpl->scrollEnd();
428 }
429
430 TEST_P(CCLayerTreeHostImplTest, nonFastScrollableRegionWithOffset)
431 {
432 setupScrollAndContentsLayers(IntSize(200, 200));
433 m_hostImpl->setViewportSize(IntSize(100, 100), IntSize(100, 100));
434 CCLayerImpl* root = m_hostImpl->rootLayer();
435
436 root->setNonFastScrollableRegion(IntRect(0, 0, 50, 50));
437 root->setPosition(FloatPoint(-25, 0));
438 initializeRendererAndDrawFrame();
439
440 // This point would fall into the non-fast scrollable region except that we' ve moved the layer down by 25 pixels.
441 EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(40, 10), CCInputHandlerClient::Wh eel), CCInputHandlerClient::ScrollStarted);
442 m_hostImpl->scrollBy(IntPoint(), IntSize(0, 1));
443 m_hostImpl->scrollEnd();
444
445 // This point is still inside the non-fast region.
446 EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(10, 10), CCInputHandlerClient::Wh eel), CCInputHandlerClient::ScrollOnMainThread);
447 }
448
449 TEST_P(CCLayerTreeHostImplTest, maxScrollPositionChangedByDeviceScaleFactor)
450 {
451 setupScrollAndContentsLayers(IntSize(100, 100));
452
453 float deviceScaleFactor = 2;
454 IntSize layoutViewport(25, 25);
455 IntSize deviceViewport(layoutViewport);
456 deviceViewport.scale(deviceScaleFactor);
457 m_hostImpl->setViewportSize(layoutViewport, deviceViewport);
458 m_hostImpl->setDeviceScaleFactor(deviceScaleFactor);
459 EXPECT_EQ(m_hostImpl->rootLayer()->maxScrollPosition(), IntSize(25, 25));
460
461 deviceScaleFactor = 1;
462 m_hostImpl->setViewportSize(layoutViewport, layoutViewport);
463 m_hostImpl->setDeviceScaleFactor(deviceScaleFactor);
464 EXPECT_EQ(m_hostImpl->rootLayer()->maxScrollPosition(), IntSize(75, 75));
465 }
466
467 TEST_P(CCLayerTreeHostImplTest, implPinchZoom)
468 {
469 // This test is specific to the page-scale based pinch zoom.
470 if (!CCSettings::pageScalePinchZoomEnabled())
471 return;
472
473 setupScrollAndContentsLayers(IntSize(100, 100));
474 m_hostImpl->setViewportSize(IntSize(50, 50), IntSize(50, 50));
475 initializeRendererAndDrawFrame();
476
477 CCLayerImpl* scrollLayer = m_hostImpl->rootScrollLayer();
478 ASSERT(scrollLayer);
479
480 const float minPageScale = 1, maxPageScale = 4;
481 const WebTransformationMatrix identityScaleTransform;
482
483 // The impl-based pinch zoome should not adjust the max scroll position.
484 {
485 m_hostImpl->setPageScaleFactorAndLimits(1, minPageScale, maxPageScale);
486 scrollLayer->setImplTransform(identityScaleTransform);
487 scrollLayer->setScrollDelta(IntSize());
488
489 float pageScaleDelta = 2;
490 m_hostImpl->pinchGestureBegin();
491 m_hostImpl->pinchGestureUpdate(pageScaleDelta, IntPoint(50, 50));
492 m_hostImpl->pinchGestureEnd();
493 EXPECT_TRUE(m_didRequestRedraw);
494 EXPECT_TRUE(m_didRequestCommit);
495
496 scoped_ptr<CCScrollAndScaleSet> scrollInfo = m_hostImpl->processScrollDe ltas();
497 EXPECT_EQ(scrollInfo->pageScaleDelta, pageScaleDelta);
498
499 EXPECT_EQ(m_hostImpl->rootLayer()->maxScrollPosition(), IntSize(50, 50)) ;
500 }
501
502 // Scrolling after a pinch gesture should always be in local space. The scr oll deltas do not
503 // have the page scale factor applied.
504 {
505 m_hostImpl->setPageScaleFactorAndLimits(1, minPageScale, maxPageScale);
506 scrollLayer->setImplTransform(identityScaleTransform);
507 scrollLayer->setScrollDelta(IntSize());
508
509 float pageScaleDelta = 2;
510 m_hostImpl->pinchGestureBegin();
511 m_hostImpl->pinchGestureUpdate(pageScaleDelta, IntPoint(0, 0));
512 m_hostImpl->pinchGestureEnd();
513
514 IntSize scrollDelta(0, 10);
515 EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(5, 5), CCInputHandlerClient:: Wheel), CCInputHandlerClient::ScrollStarted);
516 m_hostImpl->scrollBy(IntPoint(), scrollDelta);
517 m_hostImpl->scrollEnd();
518
519 scoped_ptr<CCScrollAndScaleSet> scrollInfo = m_hostImpl->processScrollDe ltas();
520 expectContains(*scrollInfo.get(), m_hostImpl->rootLayer()->id(), scrollD elta);
521 }
522 }
523
524 TEST_P(CCLayerTreeHostImplTest, pinchGesture)
525 {
526 setupScrollAndContentsLayers(IntSize(100, 100));
527 m_hostImpl->setViewportSize(IntSize(50, 50), IntSize(50, 50));
528 initializeRendererAndDrawFrame();
529
530 CCLayerImpl* scrollLayer = m_hostImpl->rootScrollLayer();
531 ASSERT(scrollLayer);
532
533 const float minPageScale = CCSettings::pageScalePinchZoomEnabled() ? 1 : 0.5 ;
534 const float maxPageScale = 4;
535 const WebTransformationMatrix identityScaleTransform;
536
537 // Basic pinch zoom in gesture
538 {
539 m_hostImpl->setPageScaleFactorAndLimits(1, minPageScale, maxPageScale);
540 scrollLayer->setImplTransform(identityScaleTransform);
541 scrollLayer->setScrollDelta(IntSize());
542
543 float pageScaleDelta = 2;
544 m_hostImpl->pinchGestureBegin();
545 m_hostImpl->pinchGestureUpdate(pageScaleDelta, IntPoint(50, 50));
546 m_hostImpl->pinchGestureEnd();
547 EXPECT_TRUE(m_didRequestRedraw);
548 EXPECT_TRUE(m_didRequestCommit);
549
550 scoped_ptr<CCScrollAndScaleSet> scrollInfo = m_hostImpl->processScrollDe ltas();
551 EXPECT_EQ(scrollInfo->pageScaleDelta, pageScaleDelta);
552 }
553
554 // Zoom-in clamping
555 {
556 m_hostImpl->setPageScaleFactorAndLimits(1, minPageScale, maxPageScale);
557 scrollLayer->setImplTransform(identityScaleTransform);
558 scrollLayer->setScrollDelta(IntSize());
559 float pageScaleDelta = 10;
560
561 m_hostImpl->pinchGestureBegin();
562 m_hostImpl->pinchGestureUpdate(pageScaleDelta, IntPoint(50, 50));
563 m_hostImpl->pinchGestureEnd();
564
565 scoped_ptr<CCScrollAndScaleSet> scrollInfo = m_hostImpl->processScrollDe ltas();
566 EXPECT_EQ(scrollInfo->pageScaleDelta, maxPageScale);
567 }
568
569 // Zoom-out clamping
570 {
571 m_hostImpl->setPageScaleFactorAndLimits(1, minPageScale, maxPageScale);
572 scrollLayer->setImplTransform(identityScaleTransform);
573 scrollLayer->setScrollDelta(IntSize());
574 scrollLayer->setScrollPosition(IntPoint(50, 50));
575
576 float pageScaleDelta = 0.1f;
577 m_hostImpl->pinchGestureBegin();
578 m_hostImpl->pinchGestureUpdate(pageScaleDelta, IntPoint(0, 0));
579 m_hostImpl->pinchGestureEnd();
580
581 scoped_ptr<CCScrollAndScaleSet> scrollInfo = m_hostImpl->processScrollDe ltas();
582 EXPECT_EQ(scrollInfo->pageScaleDelta, minPageScale);
583
584 if (!CCSettings::pageScalePinchZoomEnabled()) {
585 // Pushed to (0,0) via clamping against contents layer size.
586 expectContains(*scrollInfo, scrollLayer->id(), IntSize(-50, -50));
587 } else {
588 EXPECT_TRUE(scrollInfo->scrolls.isEmpty());
589 }
590 }
591
592 // Two-finger panning
593 {
594 m_hostImpl->setPageScaleFactorAndLimits(1, minPageScale, maxPageScale);
595 scrollLayer->setImplTransform(identityScaleTransform);
596 scrollLayer->setScrollDelta(IntSize());
597 scrollLayer->setScrollPosition(IntPoint(20, 20));
598
599 float pageScaleDelta = 1;
600 m_hostImpl->pinchGestureBegin();
601 m_hostImpl->pinchGestureUpdate(pageScaleDelta, IntPoint(10, 10));
602 m_hostImpl->pinchGestureUpdate(pageScaleDelta, IntPoint(20, 20));
603 m_hostImpl->pinchGestureEnd();
604
605 scoped_ptr<CCScrollAndScaleSet> scrollInfo = m_hostImpl->processScrollDe ltas();
606 EXPECT_EQ(scrollInfo->pageScaleDelta, pageScaleDelta);
607 expectContains(*scrollInfo, scrollLayer->id(), IntSize(-10, -10));
608 }
609 }
610
611 TEST_P(CCLayerTreeHostImplTest, pageScaleAnimation)
612 {
613 setupScrollAndContentsLayers(IntSize(100, 100));
614 m_hostImpl->setViewportSize(IntSize(50, 50), IntSize(50, 50));
615 initializeRendererAndDrawFrame();
616
617 CCLayerImpl* scrollLayer = m_hostImpl->rootScrollLayer();
618 ASSERT(scrollLayer);
619
620 const float minPageScale = CCSettings::pageScalePinchZoomEnabled() ? 1 : 0.5 ;
621 const float maxPageScale = 4;
622 const double startTime = 1;
623 const double duration = 0.1;
624 const double halfwayThroughAnimation = startTime + duration / 2;
625 const double endTime = startTime + duration;
626 const WebTransformationMatrix identityScaleTransform;
627
628 // Non-anchor zoom-in
629 {
630 m_hostImpl->setPageScaleFactorAndLimits(1, minPageScale, maxPageScale);
631 scrollLayer->setImplTransform(identityScaleTransform);
632 scrollLayer->setScrollPosition(IntPoint(50, 50));
633
634 m_hostImpl->startPageScaleAnimation(IntSize(0, 0), false, 2, startTime, duration);
635 m_hostImpl->animate(halfwayThroughAnimation, halfwayThroughAnimation);
636 EXPECT_TRUE(m_didRequestRedraw);
637 m_hostImpl->animate(endTime, endTime);
638 EXPECT_TRUE(m_didRequestCommit);
639
640 scoped_ptr<CCScrollAndScaleSet> scrollInfo = m_hostImpl->processScrollDe ltas();
641 EXPECT_EQ(scrollInfo->pageScaleDelta, 2);
642 expectContains(*scrollInfo, scrollLayer->id(), IntSize(-50, -50));
643 }
644
645 // Anchor zoom-out
646 {
647 m_hostImpl->setPageScaleFactorAndLimits(1, minPageScale, maxPageScale);
648 scrollLayer->setImplTransform(identityScaleTransform);
649 scrollLayer->setScrollPosition(IntPoint(50, 50));
650
651 m_hostImpl->startPageScaleAnimation(IntSize(25, 25), true, minPageScale, startTime, duration);
652 m_hostImpl->animate(endTime, endTime);
653 EXPECT_TRUE(m_didRequestRedraw);
654 EXPECT_TRUE(m_didRequestCommit);
655
656 scoped_ptr<CCScrollAndScaleSet> scrollInfo = m_hostImpl->processScrollDe ltas();
657 EXPECT_EQ(scrollInfo->pageScaleDelta, minPageScale);
658 // Pushed to (0,0) via clamping against contents layer size.
659 expectContains(*scrollInfo, scrollLayer->id(), IntSize(-50, -50));
660 }
661 }
662
663 TEST_P(CCLayerTreeHostImplTest, inhibitScrollAndPageScaleUpdatesWhilePinchZoomin g)
664 {
665 setupScrollAndContentsLayers(IntSize(100, 100));
666 m_hostImpl->setViewportSize(IntSize(50, 50), IntSize(50, 50));
667 initializeRendererAndDrawFrame();
668
669 CCLayerImpl* scrollLayer = m_hostImpl->rootScrollLayer();
670 ASSERT(scrollLayer);
671
672 const float minPageScale = CCSettings::pageScalePinchZoomEnabled() ? 1 : 0.5 ;
673 const float maxPageScale = 4;
674
675 // Pinch zoom in.
676 {
677 // Start a pinch in gesture at the bottom right corner of the viewport.
678 const float zoomInDelta = 2;
679 m_hostImpl->setPageScaleFactorAndLimits(1, minPageScale, maxPageScale);
680 m_hostImpl->pinchGestureBegin();
681 m_hostImpl->pinchGestureUpdate(zoomInDelta, IntPoint(50, 50));
682
683 // Because we are pinch zooming in, we shouldn't get any scroll or page
684 // scale deltas.
685 scoped_ptr<CCScrollAndScaleSet> scrollInfo = m_hostImpl->processScrollDe ltas();
686 EXPECT_EQ(scrollInfo->pageScaleDelta, 1);
687 EXPECT_EQ(scrollInfo->scrolls.size(), 0u);
688
689 // Once the gesture ends, we get the final scroll and page scale values.
690 m_hostImpl->pinchGestureEnd();
691 scrollInfo = m_hostImpl->processScrollDeltas();
692 EXPECT_EQ(scrollInfo->pageScaleDelta, zoomInDelta);
693 if (!CCSettings::pageScalePinchZoomEnabled()) {
694 expectContains(*scrollInfo, scrollLayer->id(), IntSize(25, 25));
695 } else {
696 EXPECT_TRUE(scrollInfo->scrolls.isEmpty());
697 }
698 }
699
700 // Pinch zoom out.
701 {
702 // Start a pinch out gesture at the bottom right corner of the viewport.
703 const float zoomOutDelta = 0.75;
704 m_hostImpl->setPageScaleFactorAndLimits(1, minPageScale, maxPageScale);
705 m_hostImpl->pinchGestureBegin();
706 m_hostImpl->pinchGestureUpdate(zoomOutDelta, IntPoint(50, 50));
707
708 // Since we are pinch zooming out, we should get an update to zoom all
709 // the way out to the minimum page scale.
710 scoped_ptr<CCScrollAndScaleSet> scrollInfo = m_hostImpl->processScrollDe ltas();
711 if (!CCSettings::pageScalePinchZoomEnabled()) {
712 EXPECT_EQ(scrollInfo->pageScaleDelta, minPageScale);
713 expectContains(*scrollInfo, scrollLayer->id(), IntSize(0, 0));
714 } else {
715 EXPECT_EQ(scrollInfo->pageScaleDelta, 1);
716 EXPECT_TRUE(scrollInfo->scrolls.isEmpty());
717 }
718
719 // Once the gesture ends, we get the final scroll and page scale values.
720 m_hostImpl->pinchGestureEnd();
721 scrollInfo = m_hostImpl->processScrollDeltas();
722 if (CCSettings::pageScalePinchZoomEnabled()) {
723 EXPECT_EQ(scrollInfo->pageScaleDelta, minPageScale);
724 expectContains(*scrollInfo, scrollLayer->id(), IntSize(25, 25));
725 } else {
726 EXPECT_EQ(scrollInfo->pageScaleDelta, zoomOutDelta);
727 expectContains(*scrollInfo, scrollLayer->id(), IntSize(8, 8));
728 }
729 }
730 }
731
732 TEST_P(CCLayerTreeHostImplTest, inhibitScrollAndPageScaleUpdatesWhileAnimatingPa geScale)
733 {
734 setupScrollAndContentsLayers(IntSize(100, 100));
735 m_hostImpl->setViewportSize(IntSize(50, 50), IntSize(50, 50));
736 initializeRendererAndDrawFrame();
737
738 CCLayerImpl* scrollLayer = m_hostImpl->rootScrollLayer();
739 ASSERT(scrollLayer);
740
741 const float minPageScale = CCSettings::pageScalePinchZoomEnabled() ? 1 : 0.5 ;
742 const float maxPageScale = 4;
743 const double startTime = 1;
744 const double duration = 0.1;
745 const double halfwayThroughAnimation = startTime + duration / 2;
746 const double endTime = startTime + duration;
747
748 // Start a page scale animation.
749 const float pageScaleDelta = 2;
750 m_hostImpl->setPageScaleFactorAndLimits(1, minPageScale, maxPageScale);
751 m_hostImpl->startPageScaleAnimation(IntSize(50, 50), false, pageScaleDelta, startTime, duration);
752
753 // We should immediately get the final zoom and scroll values for the
754 // animation.
755 m_hostImpl->animate(halfwayThroughAnimation, halfwayThroughAnimation);
756 scoped_ptr<CCScrollAndScaleSet> scrollInfo = m_hostImpl->processScrollDeltas ();
757
758 if (!CCSettings::pageScalePinchZoomEnabled()) {
759 EXPECT_EQ(scrollInfo->pageScaleDelta, pageScaleDelta);
760 expectContains(*scrollInfo, scrollLayer->id(), IntSize(25, 25));
761 } else {
762 EXPECT_EQ(scrollInfo->pageScaleDelta, 1);
763 EXPECT_TRUE(scrollInfo->scrolls.isEmpty());
764 }
765
766 // Scrolling during the animation is ignored.
767 const IntSize scrollDelta(0, 10);
768 EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(25, 25), CCInputHandlerClient::Wh eel), CCInputHandlerClient::ScrollStarted);
769 m_hostImpl->scrollBy(IntPoint(), scrollDelta);
770 m_hostImpl->scrollEnd();
771
772 // The final page scale and scroll deltas should match what we got
773 // earlier.
774 m_hostImpl->animate(endTime, endTime);
775 scrollInfo = m_hostImpl->processScrollDeltas();
776 EXPECT_EQ(scrollInfo->pageScaleDelta, pageScaleDelta);
777 expectContains(*scrollInfo, scrollLayer->id(), IntSize(25, 25));
778 }
779
780 class DidDrawCheckLayer : public CCTiledLayerImpl {
781 public:
782 static scoped_ptr<CCLayerImpl> create(int id) { return scoped_ptr<CCLayerImp l>(new DidDrawCheckLayer(id)); }
783
784 virtual void didDraw(CCResourceProvider*) OVERRIDE
785 {
786 m_didDrawCalled = true;
787 }
788
789 virtual void willDraw(CCResourceProvider*) OVERRIDE
790 {
791 m_willDrawCalled = true;
792 }
793
794 bool didDrawCalled() const { return m_didDrawCalled; }
795 bool willDrawCalled() const { return m_willDrawCalled; }
796
797 void clearDidDrawCheck()
798 {
799 m_didDrawCalled = false;
800 m_willDrawCalled = false;
801 }
802
803 protected:
804 explicit DidDrawCheckLayer(int id)
805 : CCTiledLayerImpl(id)
806 , m_didDrawCalled(false)
807 , m_willDrawCalled(false)
808 {
809 setAnchorPoint(FloatPoint(0, 0));
810 setBounds(IntSize(10, 10));
811 setContentBounds(IntSize(10, 10));
812 setDrawsContent(true);
813 setSkipsDraw(false);
814 setVisibleContentRect(IntRect(0, 0, 10, 10));
815
816 OwnPtr<CCLayerTilingData> tiler = CCLayerTilingData::create(IntSize(100, 100), CCLayerTilingData::HasBorderTexels);
817 tiler->setBounds(contentBounds());
818 setTilingData(*tiler.get());
819 }
820
821 private:
822 bool m_didDrawCalled;
823 bool m_willDrawCalled;
824 };
825
826 TEST_P(CCLayerTreeHostImplTest, didDrawNotCalledOnHiddenLayer)
827 {
828 // The root layer is always drawn, so run this test on a child layer that
829 // will be masked out by the root layer's bounds.
830 m_hostImpl->setRootLayer(DidDrawCheckLayer::create(1));
831 DidDrawCheckLayer* root = static_cast<DidDrawCheckLayer*>(m_hostImpl->rootLa yer());
832 root->setMasksToBounds(true);
833
834 root->addChild(DidDrawCheckLayer::create(2));
835 DidDrawCheckLayer* layer = static_cast<DidDrawCheckLayer*>(root->children()[ 0]);
836 // Ensure visibleContentRect for layer is empty
837 layer->setPosition(FloatPoint(100, 100));
838 layer->setBounds(IntSize(10, 10));
839 layer->setContentBounds(IntSize(10, 10));
840
841 CCLayerTreeHostImpl::FrameData frame;
842
843 EXPECT_FALSE(layer->willDrawCalled());
844 EXPECT_FALSE(layer->didDrawCalled());
845
846 EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
847 m_hostImpl->drawLayers(frame);
848 m_hostImpl->didDrawAllLayers(frame);
849
850 EXPECT_FALSE(layer->willDrawCalled());
851 EXPECT_FALSE(layer->didDrawCalled());
852
853 EXPECT_TRUE(layer->visibleContentRect().isEmpty());
854
855 // Ensure visibleContentRect for layer layer is not empty
856 layer->setPosition(FloatPoint(0, 0));
857
858 EXPECT_FALSE(layer->willDrawCalled());
859 EXPECT_FALSE(layer->didDrawCalled());
860
861 EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
862 m_hostImpl->drawLayers(frame);
863 m_hostImpl->didDrawAllLayers(frame);
864
865 EXPECT_TRUE(layer->willDrawCalled());
866 EXPECT_TRUE(layer->didDrawCalled());
867
868 EXPECT_FALSE(layer->visibleContentRect().isEmpty());
869 }
870
871 TEST_P(CCLayerTreeHostImplTest, willDrawNotCalledOnOccludedLayer)
872 {
873 IntSize bigSize(1000, 1000);
874 m_hostImpl->setViewportSize(bigSize, bigSize);
875
876 m_hostImpl->setRootLayer(DidDrawCheckLayer::create(1));
877 DidDrawCheckLayer* root = static_cast<DidDrawCheckLayer*>(m_hostImpl->rootLa yer());
878
879 root->addChild(DidDrawCheckLayer::create(2));
880 DidDrawCheckLayer* occludedLayer = static_cast<DidDrawCheckLayer*>(root->chi ldren()[0]);
881
882 root->addChild(DidDrawCheckLayer::create(3));
883 DidDrawCheckLayer* topLayer = static_cast<DidDrawCheckLayer*>(root->children ()[1]);
884 // This layer covers the occludedLayer above. Make this layer large so it ca n occlude.
885 topLayer->setBounds(bigSize);
886 topLayer->setContentBounds(bigSize);
887 topLayer->setContentsOpaque(true);
888
889 CCLayerTreeHostImpl::FrameData frame;
890
891 EXPECT_FALSE(occludedLayer->willDrawCalled());
892 EXPECT_FALSE(occludedLayer->didDrawCalled());
893 EXPECT_FALSE(topLayer->willDrawCalled());
894 EXPECT_FALSE(topLayer->didDrawCalled());
895
896 EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
897 m_hostImpl->drawLayers(frame);
898 m_hostImpl->didDrawAllLayers(frame);
899
900 EXPECT_FALSE(occludedLayer->willDrawCalled());
901 EXPECT_FALSE(occludedLayer->didDrawCalled());
902 EXPECT_TRUE(topLayer->willDrawCalled());
903 EXPECT_TRUE(topLayer->didDrawCalled());
904 }
905
906 TEST_P(CCLayerTreeHostImplTest, didDrawCalledOnAllLayers)
907 {
908 m_hostImpl->setRootLayer(DidDrawCheckLayer::create(1));
909 DidDrawCheckLayer* root = static_cast<DidDrawCheckLayer*>(m_hostImpl->rootLa yer());
910
911 root->addChild(DidDrawCheckLayer::create(2));
912 DidDrawCheckLayer* layer1 = static_cast<DidDrawCheckLayer*>(root->children() [0]);
913
914 layer1->addChild(DidDrawCheckLayer::create(3));
915 DidDrawCheckLayer* layer2 = static_cast<DidDrawCheckLayer*>(layer1->children ()[0]);
916
917 layer1->setOpacity(0.3f);
918 layer1->setPreserves3D(false);
919
920 EXPECT_FALSE(root->didDrawCalled());
921 EXPECT_FALSE(layer1->didDrawCalled());
922 EXPECT_FALSE(layer2->didDrawCalled());
923
924 CCLayerTreeHostImpl::FrameData frame;
925 EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
926 m_hostImpl->drawLayers(frame);
927 m_hostImpl->didDrawAllLayers(frame);
928
929 EXPECT_TRUE(root->didDrawCalled());
930 EXPECT_TRUE(layer1->didDrawCalled());
931 EXPECT_TRUE(layer2->didDrawCalled());
932
933 EXPECT_NE(root->renderSurface(), layer1->renderSurface());
934 EXPECT_TRUE(!!layer1->renderSurface());
935 }
936
937 class MissingTextureAnimatingLayer : public DidDrawCheckLayer {
938 public:
939 static scoped_ptr<CCLayerImpl> create(int id, bool tileMissing, bool skipsDr aw, bool animating, CCResourceProvider* resourceProvider)
940 {
941 return scoped_ptr<CCLayerImpl>(new MissingTextureAnimatingLayer(id, tile Missing, skipsDraw, animating, resourceProvider));
942 }
943
944 private:
945 explicit MissingTextureAnimatingLayer(int id, bool tileMissing, bool skipsDr aw, bool animating, CCResourceProvider* resourceProvider)
946 : DidDrawCheckLayer(id)
947 {
948 OwnPtr<CCLayerTilingData> tilingData = CCLayerTilingData::create(IntSize (10, 10), CCLayerTilingData::NoBorderTexels);
949 tilingData->setBounds(bounds());
950 setTilingData(*tilingData.get());
951 setSkipsDraw(skipsDraw);
952 if (!tileMissing) {
953 CCResourceProvider::ResourceId resource = resourceProvider->createRe source(CCRenderer::ContentPool, IntSize(), GraphicsContext3D::RGBA, CCResourcePr ovider::TextureUsageAny);
954 pushTileProperties(0, 0, resource, IntRect());
955 }
956 if (animating)
957 addAnimatedTransformToLayer(*this, 10, 3, 0);
958 }
959 };
960
961 TEST_P(CCLayerTreeHostImplTest, prepareToDrawFailsWhenAnimationUsesCheckerboard)
962 {
963 // When the texture is not missing, we draw as usual.
964 m_hostImpl->setRootLayer(DidDrawCheckLayer::create(1));
965 DidDrawCheckLayer* root = static_cast<DidDrawCheckLayer*>(m_hostImpl->rootLa yer());
966 root->addChild(MissingTextureAnimatingLayer::create(2, false, false, true, m _hostImpl->resourceProvider()));
967
968 CCLayerTreeHostImpl::FrameData frame;
969
970 EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
971 m_hostImpl->drawLayers(frame);
972 m_hostImpl->didDrawAllLayers(frame);
973
974 // When a texture is missing and we're not animating, we draw as usual with checkerboarding.
975 m_hostImpl->setRootLayer(DidDrawCheckLayer::create(1));
976 root = static_cast<DidDrawCheckLayer*>(m_hostImpl->rootLayer());
977 root->addChild(MissingTextureAnimatingLayer::create(2, true, false, false, m _hostImpl->resourceProvider()));
978
979 EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
980 m_hostImpl->drawLayers(frame);
981 m_hostImpl->didDrawAllLayers(frame);
982
983 // When a texture is missing and we're animating, we don't want to draw anyt hing.
984 m_hostImpl->setRootLayer(DidDrawCheckLayer::create(1));
985 root = static_cast<DidDrawCheckLayer*>(m_hostImpl->rootLayer());
986 root->addChild(MissingTextureAnimatingLayer::create(2, true, false, true, m_ hostImpl->resourceProvider()));
987
988 EXPECT_FALSE(m_hostImpl->prepareToDraw(frame));
989 m_hostImpl->drawLayers(frame);
990 m_hostImpl->didDrawAllLayers(frame);
991
992 // When the layer skips draw and we're animating, we still draw the frame.
993 m_hostImpl->setRootLayer(DidDrawCheckLayer::create(1));
994 root = static_cast<DidDrawCheckLayer*>(m_hostImpl->rootLayer());
995 root->addChild(MissingTextureAnimatingLayer::create(2, false, true, true, m_ hostImpl->resourceProvider()));
996
997 EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
998 m_hostImpl->drawLayers(frame);
999 m_hostImpl->didDrawAllLayers(frame);
1000 }
1001
1002 TEST_P(CCLayerTreeHostImplTest, scrollRootIgnored)
1003 {
1004 scoped_ptr<CCLayerImpl> root = CCLayerImpl::create(1);
1005 root->setScrollable(false);
1006 m_hostImpl->setRootLayer(root.Pass());
1007 initializeRendererAndDrawFrame();
1008
1009 // Scroll event is ignored because layer is not scrollable.
1010 EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(0, 0), CCInputHandlerClient::Whee l), CCInputHandlerClient::ScrollIgnored);
1011 EXPECT_FALSE(m_didRequestRedraw);
1012 EXPECT_FALSE(m_didRequestCommit);
1013 }
1014
1015 TEST_P(CCLayerTreeHostImplTest, scrollNonCompositedRoot)
1016 {
1017 // Test the configuration where a non-composited root layer is embedded in a
1018 // scrollable outer layer.
1019 IntSize surfaceSize(10, 10);
1020
1021 scoped_ptr<CCLayerImpl> contentLayer = CCLayerImpl::create(1);
1022 contentLayer->setUseLCDText(true);
1023 contentLayer->setDrawsContent(true);
1024 contentLayer->setPosition(FloatPoint(0, 0));
1025 contentLayer->setAnchorPoint(FloatPoint(0, 0));
1026 contentLayer->setBounds(surfaceSize);
1027 contentLayer->setContentBounds(IntSize(surfaceSize.width() * 2, surfaceSize. height() * 2));
1028
1029 scoped_ptr<CCLayerImpl> scrollLayer = CCLayerImpl::create(2);
1030 scrollLayer->setScrollable(true);
1031 scrollLayer->setMaxScrollPosition(surfaceSize);
1032 scrollLayer->setBounds(surfaceSize);
1033 scrollLayer->setContentBounds(surfaceSize);
1034 scrollLayer->setPosition(FloatPoint(0, 0));
1035 scrollLayer->setAnchorPoint(FloatPoint(0, 0));
1036 scrollLayer->addChild(contentLayer.Pass());
1037
1038 m_hostImpl->setRootLayer(scrollLayer.Pass());
1039 m_hostImpl->setViewportSize(surfaceSize, surfaceSize);
1040 initializeRendererAndDrawFrame();
1041
1042 EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(5, 5), CCInputHandlerClient::Whee l), CCInputHandlerClient::ScrollStarted);
1043 m_hostImpl->scrollBy(IntPoint(), IntSize(0, 10));
1044 m_hostImpl->scrollEnd();
1045 EXPECT_TRUE(m_didRequestRedraw);
1046 EXPECT_TRUE(m_didRequestCommit);
1047 }
1048
1049 TEST_P(CCLayerTreeHostImplTest, scrollChildCallsCommitAndRedraw)
1050 {
1051 IntSize surfaceSize(10, 10);
1052 scoped_ptr<CCLayerImpl> root = CCLayerImpl::create(1);
1053 root->setBounds(surfaceSize);
1054 root->setContentBounds(surfaceSize);
1055 root->addChild(createScrollableLayer(2, surfaceSize));
1056 m_hostImpl->setRootLayer(root.Pass());
1057 m_hostImpl->setViewportSize(surfaceSize, surfaceSize);
1058 initializeRendererAndDrawFrame();
1059
1060 EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(5, 5), CCInputHandlerClient::Whee l), CCInputHandlerClient::ScrollStarted);
1061 m_hostImpl->scrollBy(IntPoint(), IntSize(0, 10));
1062 m_hostImpl->scrollEnd();
1063 EXPECT_TRUE(m_didRequestRedraw);
1064 EXPECT_TRUE(m_didRequestCommit);
1065 }
1066
1067 TEST_P(CCLayerTreeHostImplTest, scrollMissesChild)
1068 {
1069 IntSize surfaceSize(10, 10);
1070 scoped_ptr<CCLayerImpl> root = CCLayerImpl::create(1);
1071 root->addChild(createScrollableLayer(2, surfaceSize));
1072 m_hostImpl->setRootLayer(root.Pass());
1073 m_hostImpl->setViewportSize(surfaceSize, surfaceSize);
1074 initializeRendererAndDrawFrame();
1075
1076 // Scroll event is ignored because the input coordinate is outside the layer boundaries.
1077 EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(15, 5), CCInputHandlerClient::Whe el), CCInputHandlerClient::ScrollIgnored);
1078 EXPECT_FALSE(m_didRequestRedraw);
1079 EXPECT_FALSE(m_didRequestCommit);
1080 }
1081
1082 TEST_P(CCLayerTreeHostImplTest, scrollMissesBackfacingChild)
1083 {
1084 IntSize surfaceSize(10, 10);
1085 scoped_ptr<CCLayerImpl> root = CCLayerImpl::create(1);
1086 scoped_ptr<CCLayerImpl> child = createScrollableLayer(2, surfaceSize);
1087 m_hostImpl->setViewportSize(surfaceSize, surfaceSize);
1088
1089 WebTransformationMatrix matrix;
1090 matrix.rotate3d(180, 0, 0);
1091 child->setTransform(matrix);
1092 child->setDoubleSided(false);
1093
1094 root->addChild(child.Pass());
1095 m_hostImpl->setRootLayer(root.Pass());
1096 initializeRendererAndDrawFrame();
1097
1098 // Scroll event is ignored because the scrollable layer is not facing the vi ewer and there is
1099 // nothing scrollable behind it.
1100 EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(5, 5), CCInputHandlerClient::Whee l), CCInputHandlerClient::ScrollIgnored);
1101 EXPECT_FALSE(m_didRequestRedraw);
1102 EXPECT_FALSE(m_didRequestCommit);
1103 }
1104
1105 TEST_P(CCLayerTreeHostImplTest, scrollBlockedByContentLayer)
1106 {
1107 IntSize surfaceSize(10, 10);
1108 scoped_ptr<CCLayerImpl> contentLayer = createScrollableLayer(1, surfaceSize) ;
1109 contentLayer->setShouldScrollOnMainThread(true);
1110 contentLayer->setScrollable(false);
1111
1112 scoped_ptr<CCLayerImpl> scrollLayer = createScrollableLayer(2, surfaceSize);
1113 scrollLayer->addChild(contentLayer.Pass());
1114
1115 m_hostImpl->setRootLayer(scrollLayer.Pass());
1116 m_hostImpl->setViewportSize(surfaceSize, surfaceSize);
1117 initializeRendererAndDrawFrame();
1118
1119 // Scrolling fails because the content layer is asking to be scrolled on the main thread.
1120 EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(5, 5), CCInputHandlerClient::Whee l), CCInputHandlerClient::ScrollOnMainThread);
1121 }
1122
1123 TEST_P(CCLayerTreeHostImplTest, scrollRootAndChangePageScaleOnMainThread)
1124 {
1125 IntSize surfaceSize(10, 10);
1126 float pageScale = 2;
1127 scoped_ptr<CCLayerImpl> root = createScrollableLayer(1, surfaceSize);
1128 m_hostImpl->setRootLayer(root.Pass());
1129 m_hostImpl->setViewportSize(surfaceSize, surfaceSize);
1130 initializeRendererAndDrawFrame();
1131
1132 IntSize scrollDelta(0, 10);
1133 IntSize expectedScrollDelta(scrollDelta);
1134 IntSize expectedMaxScroll(m_hostImpl->rootLayer()->maxScrollPosition());
1135 EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(5, 5), CCInputHandlerClient::Whee l), CCInputHandlerClient::ScrollStarted);
1136 m_hostImpl->scrollBy(IntPoint(), scrollDelta);
1137 m_hostImpl->scrollEnd();
1138
1139 // Set new page scale from main thread.
1140 m_hostImpl->setPageScaleFactorAndLimits(pageScale, pageScale, pageScale);
1141
1142 if (!CCSettings::pageScalePinchZoomEnabled()) {
1143 // The scale should apply to the scroll delta.
1144 expectedScrollDelta.scale(pageScale);
1145 }
1146 scoped_ptr<CCScrollAndScaleSet> scrollInfo = m_hostImpl->processScrollDeltas ();
1147 expectContains(*scrollInfo.get(), m_hostImpl->rootLayer()->id(), expectedScr ollDelta);
1148
1149 // The scroll range should also have been updated.
1150 EXPECT_EQ(m_hostImpl->rootLayer()->maxScrollPosition(), expectedMaxScroll);
1151
1152 // The page scale delta remains constant because the impl thread did not sca le.
1153 EXPECT_EQ(m_hostImpl->rootLayer()->implTransform(), WebTransformationMatrix( ));
1154 }
1155
1156 TEST_P(CCLayerTreeHostImplTest, scrollRootAndChangePageScaleOnImplThread)
1157 {
1158 IntSize surfaceSize(10, 10);
1159 float pageScale = 2;
1160 scoped_ptr<CCLayerImpl> root = createScrollableLayer(1, surfaceSize);
1161 m_hostImpl->setRootLayer(root.Pass());
1162 m_hostImpl->setViewportSize(surfaceSize, surfaceSize);
1163 m_hostImpl->setPageScaleFactorAndLimits(1, 1, pageScale);
1164 initializeRendererAndDrawFrame();
1165
1166 IntSize scrollDelta(0, 10);
1167 IntSize expectedScrollDelta(scrollDelta);
1168 IntSize expectedMaxScroll(m_hostImpl->rootLayer()->maxScrollPosition());
1169 EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(5, 5), CCInputHandlerClient::Whee l), CCInputHandlerClient::ScrollStarted);
1170 m_hostImpl->scrollBy(IntPoint(), scrollDelta);
1171 m_hostImpl->scrollEnd();
1172
1173 // Set new page scale on impl thread by pinching.
1174 m_hostImpl->pinchGestureBegin();
1175 m_hostImpl->pinchGestureUpdate(pageScale, IntPoint());
1176 m_hostImpl->pinchGestureEnd();
1177 m_hostImpl->updateRootScrollLayerImplTransform();
1178
1179 // The scroll delta is not scaled because the main thread did not scale.
1180 scoped_ptr<CCScrollAndScaleSet> scrollInfo = m_hostImpl->processScrollDeltas ();
1181 expectContains(*scrollInfo.get(), m_hostImpl->rootLayer()->id(), expectedScr ollDelta);
1182
1183 // The scroll range should also have been updated.
1184 EXPECT_EQ(m_hostImpl->rootLayer()->maxScrollPosition(), expectedMaxScroll);
1185
1186 // The page scale delta should match the new scale on the impl side.
1187 WebTransformationMatrix expectedScale;
1188 expectedScale.scale(pageScale);
1189 EXPECT_EQ(m_hostImpl->rootLayer()->implTransform(), expectedScale);
1190 }
1191
1192 TEST_P(CCLayerTreeHostImplTest, pageScaleDeltaAppliedToRootScrollLayerOnly)
1193 {
1194 IntSize surfaceSize(10, 10);
1195 float defaultPageScale = 1;
1196 WebTransformationMatrix defaultPageScaleMatrix;
1197
1198 float newPageScale = 2;
1199 WebTransformationMatrix newPageScaleMatrix;
1200 newPageScaleMatrix.scale(newPageScale);
1201
1202 // Create a normal scrollable root layer and another scrollable child layer.
1203 setupScrollAndContentsLayers(surfaceSize);
1204 CCLayerImpl* root = m_hostImpl->rootLayer();
1205 CCLayerImpl* child = root->children()[0];
1206
1207 scoped_ptr<CCLayerImpl> scrollableChild = createScrollableLayer(3, surfaceSi ze);
1208 child->addChild(scrollableChild.Pass());
1209 CCLayerImpl* grandChild = child->children()[0];
1210
1211 // Set new page scale on impl thread by pinching.
1212 m_hostImpl->pinchGestureBegin();
1213 m_hostImpl->pinchGestureUpdate(newPageScale, IntPoint());
1214 m_hostImpl->pinchGestureEnd();
1215 m_hostImpl->updateRootScrollLayerImplTransform();
1216
1217 // The page scale delta should only be applied to the scrollable root layer.
1218 EXPECT_EQ(root->implTransform(), newPageScaleMatrix);
1219 EXPECT_EQ(child->implTransform(), defaultPageScaleMatrix);
1220 EXPECT_EQ(grandChild->implTransform(), defaultPageScaleMatrix);
1221
1222 // Make sure all the layers are drawn with the page scale delta applied, i.e ., the page scale
1223 // delta on the root layer is applied hierarchically.
1224 CCLayerTreeHostImpl::FrameData frame;
1225 EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
1226 m_hostImpl->drawLayers(frame);
1227 m_hostImpl->didDrawAllLayers(frame);
1228
1229 EXPECT_EQ(root->drawTransform().m11(), newPageScale);
1230 EXPECT_EQ(root->drawTransform().m22(), newPageScale);
1231 EXPECT_EQ(child->drawTransform().m11(), newPageScale);
1232 EXPECT_EQ(child->drawTransform().m22(), newPageScale);
1233 EXPECT_EQ(grandChild->drawTransform().m11(), newPageScale);
1234 EXPECT_EQ(grandChild->drawTransform().m22(), newPageScale);
1235 }
1236
1237 TEST_P(CCLayerTreeHostImplTest, scrollChildAndChangePageScaleOnMainThread)
1238 {
1239 IntSize surfaceSize(10, 10);
1240 scoped_ptr<CCLayerImpl> root = CCLayerImpl::create(1);
1241 root->setBounds(surfaceSize);
1242 root->setContentBounds(surfaceSize);
1243 // Also mark the root scrollable so it becomes the root scroll layer.
1244 root->setScrollable(true);
1245 int scrollLayerId = 2;
1246 root->addChild(createScrollableLayer(scrollLayerId, surfaceSize));
1247 m_hostImpl->setRootLayer(root.Pass());
1248 m_hostImpl->setViewportSize(surfaceSize, surfaceSize);
1249 initializeRendererAndDrawFrame();
1250
1251 CCLayerImpl* child = m_hostImpl->rootLayer()->children()[0];
1252
1253 IntSize scrollDelta(0, 10);
1254 IntSize expectedScrollDelta(scrollDelta);
1255 IntSize expectedMaxScroll(child->maxScrollPosition());
1256 EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(5, 5), CCInputHandlerClient::Whee l), CCInputHandlerClient::ScrollStarted);
1257 m_hostImpl->scrollBy(IntPoint(), scrollDelta);
1258 m_hostImpl->scrollEnd();
1259
1260 float pageScale = 2;
1261 m_hostImpl->setPageScaleFactorAndLimits(pageScale, 1, pageScale);
1262
1263 m_hostImpl->updateRootScrollLayerImplTransform();
1264
1265 if (!CCSettings::pageScalePinchZoomEnabled()) {
1266 // The scale should apply to the scroll delta.
1267 expectedScrollDelta.scale(pageScale);
1268 }
1269 scoped_ptr<CCScrollAndScaleSet> scrollInfo = m_hostImpl->processScrollDeltas ();
1270 expectContains(*scrollInfo.get(), scrollLayerId, expectedScrollDelta);
1271
1272 // The scroll range should not have changed.
1273 EXPECT_EQ(child->maxScrollPosition(), expectedMaxScroll);
1274
1275 // The page scale delta remains constant because the impl thread did not sca le.
1276 WebTransformationMatrix identityTransform;
1277 EXPECT_EQ(child->implTransform(), WebTransformationMatrix());
1278 }
1279
1280 TEST_P(CCLayerTreeHostImplTest, scrollChildBeyondLimit)
1281 {
1282 // Scroll a child layer beyond its maximum scroll range and make sure the
1283 // parent layer is scrolled on the axis on which the child was unable to
1284 // scroll.
1285 IntSize surfaceSize(10, 10);
1286 scoped_ptr<CCLayerImpl> root = createScrollableLayer(1, surfaceSize);
1287
1288 scoped_ptr<CCLayerImpl> grandChild = createScrollableLayer(3, surfaceSize);
1289 grandChild->setScrollPosition(IntPoint(0, 5));
1290
1291 scoped_ptr<CCLayerImpl> child = createScrollableLayer(2, surfaceSize);
1292 child->setScrollPosition(IntPoint(3, 0));
1293 child->addChild(grandChild.Pass());
1294
1295 root->addChild(child.Pass());
1296 m_hostImpl->setRootLayer(root.Pass());
1297 m_hostImpl->setViewportSize(surfaceSize, surfaceSize);
1298 initializeRendererAndDrawFrame();
1299 {
1300 IntSize scrollDelta(-8, -7);
1301 EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(5, 5), CCInputHandlerClient:: Wheel), CCInputHandlerClient::ScrollStarted);
1302 m_hostImpl->scrollBy(IntPoint(), scrollDelta);
1303 m_hostImpl->scrollEnd();
1304
1305 scoped_ptr<CCScrollAndScaleSet> scrollInfo = m_hostImpl->processScrollDe ltas();
1306
1307 // The grand child should have scrolled up to its limit.
1308 CCLayerImpl* child = m_hostImpl->rootLayer()->children()[0];
1309 CCLayerImpl* grandChild = child->children()[0];
1310 expectContains(*scrollInfo.get(), grandChild->id(), IntSize(0, -5));
1311
1312 // The child should have only scrolled on the other axis.
1313 expectContains(*scrollInfo.get(), child->id(), IntSize(-3, 0));
1314 }
1315 }
1316
1317 TEST_P(CCLayerTreeHostImplTest, scrollEventBubbling)
1318 {
1319 // When we try to scroll a non-scrollable child layer, the scroll delta
1320 // should be applied to one of its ancestors if possible.
1321 IntSize surfaceSize(10, 10);
1322 scoped_ptr<CCLayerImpl> root = createScrollableLayer(1, surfaceSize);
1323 scoped_ptr<CCLayerImpl> child = createScrollableLayer(2, surfaceSize);
1324
1325 child->setScrollable(false);
1326 root->addChild(child.Pass());
1327
1328 m_hostImpl->setRootLayer(root.Pass());
1329 m_hostImpl->setViewportSize(surfaceSize, surfaceSize);
1330 initializeRendererAndDrawFrame();
1331 {
1332 IntSize scrollDelta(0, 4);
1333 EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(5, 5), CCInputHandlerClient:: Wheel), CCInputHandlerClient::ScrollStarted);
1334 m_hostImpl->scrollBy(IntPoint(), scrollDelta);
1335 m_hostImpl->scrollEnd();
1336
1337 scoped_ptr<CCScrollAndScaleSet> scrollInfo = m_hostImpl->processScrollDe ltas();
1338
1339 // Only the root should have scrolled.
1340 ASSERT_EQ(scrollInfo->scrolls.size(), 1u);
1341 expectContains(*scrollInfo.get(), m_hostImpl->rootLayer()->id(), scrollD elta);
1342 }
1343 }
1344
1345 TEST_P(CCLayerTreeHostImplTest, scrollBeforeRedraw)
1346 {
1347 IntSize surfaceSize(10, 10);
1348 m_hostImpl->setRootLayer(createScrollableLayer(1, surfaceSize));
1349 m_hostImpl->setViewportSize(surfaceSize, surfaceSize);
1350
1351 // Draw one frame and then immediately rebuild the layer tree to mimic a tre e synchronization.
1352 initializeRendererAndDrawFrame();
1353 m_hostImpl->detachLayerTree();
1354 m_hostImpl->setRootLayer(createScrollableLayer(2, surfaceSize));
1355
1356 // Scrolling should still work even though we did not draw yet.
1357 EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(5, 5), CCInputHandlerClient::Whee l), CCInputHandlerClient::ScrollStarted);
1358 }
1359
1360 TEST_P(CCLayerTreeHostImplTest, scrollAxisAlignedRotatedLayer)
1361 {
1362 setupScrollAndContentsLayers(IntSize(100, 100));
1363
1364 // Rotate the root layer 90 degrees counter-clockwise about its center.
1365 WebTransformationMatrix rotateTransform;
1366 rotateTransform.rotate(-90);
1367 m_hostImpl->rootLayer()->setTransform(rotateTransform);
1368
1369 IntSize surfaceSize(50, 50);
1370 m_hostImpl->setViewportSize(surfaceSize, surfaceSize);
1371 initializeRendererAndDrawFrame();
1372
1373 // Scroll to the right in screen coordinates with a gesture.
1374 IntSize gestureScrollDelta(10, 0);
1375 EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(0, 0), CCInputHandlerClient::Gest ure), CCInputHandlerClient::ScrollStarted);
1376 m_hostImpl->scrollBy(IntPoint(), gestureScrollDelta);
1377 m_hostImpl->scrollEnd();
1378
1379 // The layer should have scrolled down in its local coordinates.
1380 scoped_ptr<CCScrollAndScaleSet> scrollInfo = m_hostImpl->processScrollDeltas ();
1381 expectContains(*scrollInfo.get(), m_hostImpl->rootLayer()->id(), IntSize(0, gestureScrollDelta.width()));
1382
1383 // Reset and scroll down with the wheel.
1384 m_hostImpl->rootLayer()->setScrollDelta(FloatSize());
1385 IntSize wheelScrollDelta(0, 10);
1386 EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(0, 0), CCInputHandlerClient::Whee l), CCInputHandlerClient::ScrollStarted);
1387 m_hostImpl->scrollBy(IntPoint(), wheelScrollDelta);
1388 m_hostImpl->scrollEnd();
1389
1390 // The layer should have scrolled down in its local coordinates.
1391 scrollInfo = m_hostImpl->processScrollDeltas();
1392 expectContains(*scrollInfo.get(), m_hostImpl->rootLayer()->id(), wheelScroll Delta);
1393 }
1394
1395 TEST_P(CCLayerTreeHostImplTest, scrollNonAxisAlignedRotatedLayer)
1396 {
1397 setupScrollAndContentsLayers(IntSize(100, 100));
1398 int childLayerId = 3;
1399 float childLayerAngle = -20;
1400
1401 // Create a child layer that is rotated to a non-axis-aligned angle.
1402 scoped_ptr<CCLayerImpl> child = createScrollableLayer(childLayerId, m_hostIm pl->rootLayer()->contentBounds());
1403 WebTransformationMatrix rotateTransform;
1404 rotateTransform.translate(-50, -50);
1405 rotateTransform.rotate(childLayerAngle);
1406 rotateTransform.translate(50, 50);
1407 child->setTransform(rotateTransform);
1408
1409 // Only allow vertical scrolling.
1410 child->setMaxScrollPosition(IntSize(0, child->contentBounds().height()));
1411 m_hostImpl->rootLayer()->addChild(child.Pass());
1412
1413 IntSize surfaceSize(50, 50);
1414 m_hostImpl->setViewportSize(surfaceSize, surfaceSize);
1415 initializeRendererAndDrawFrame();
1416
1417 {
1418 // Scroll down in screen coordinates with a gesture.
1419 IntSize gestureScrollDelta(0, 10);
1420 EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(0, 0), CCInputHandlerClient:: Gesture), CCInputHandlerClient::ScrollStarted);
1421 m_hostImpl->scrollBy(IntPoint(), gestureScrollDelta);
1422 m_hostImpl->scrollEnd();
1423
1424 // The child layer should have scrolled down in its local coordinates an amount proportional to
1425 // the angle between it and the input scroll delta.
1426 IntSize expectedScrollDelta(0, gestureScrollDelta.height() * cosf(deg2ra d(childLayerAngle)));
1427 scoped_ptr<CCScrollAndScaleSet> scrollInfo = m_hostImpl->processScrollDe ltas();
1428 expectContains(*scrollInfo.get(), childLayerId, expectedScrollDelta);
1429
1430 // The root layer should not have scrolled, because the input delta was close to the layer's
1431 // axis of movement.
1432 EXPECT_EQ(scrollInfo->scrolls.size(), 1u);
1433 }
1434
1435 {
1436 // Now reset and scroll the same amount horizontally.
1437 m_hostImpl->rootLayer()->children()[1]->setScrollDelta(FloatSize());
1438 IntSize gestureScrollDelta(10, 0);
1439 EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(0, 0), CCInputHandlerClient:: Gesture), CCInputHandlerClient::ScrollStarted);
1440 m_hostImpl->scrollBy(IntPoint(), gestureScrollDelta);
1441 m_hostImpl->scrollEnd();
1442
1443 // The child layer should have scrolled down in its local coordinates an amount proportional to
1444 // the angle between it and the input scroll delta.
1445 IntSize expectedScrollDelta(0, -gestureScrollDelta.width() * sinf(deg2ra d(childLayerAngle)));
1446 scoped_ptr<CCScrollAndScaleSet> scrollInfo = m_hostImpl->processScrollDe ltas();
1447 expectContains(*scrollInfo.get(), childLayerId, expectedScrollDelta);
1448
1449 // The root layer should have scrolled more, since the input scroll delt a was mostly
1450 // orthogonal to the child layer's vertical scroll axis.
1451 IntSize expectedRootScrollDelta(gestureScrollDelta.width() * pow(cosf(de g2rad(childLayerAngle)), 2), 0);
1452 expectContains(*scrollInfo.get(), m_hostImpl->rootLayer()->id(), expecte dRootScrollDelta);
1453 }
1454 }
1455
1456 TEST_P(CCLayerTreeHostImplTest, scrollScaledLayer)
1457 {
1458 setupScrollAndContentsLayers(IntSize(100, 100));
1459
1460 // Scale the layer to twice its normal size.
1461 int scale = 2;
1462 WebTransformationMatrix scaleTransform;
1463 scaleTransform.scale(scale);
1464 m_hostImpl->rootLayer()->setTransform(scaleTransform);
1465
1466 IntSize surfaceSize(50, 50);
1467 m_hostImpl->setViewportSize(surfaceSize, surfaceSize);
1468 initializeRendererAndDrawFrame();
1469
1470 // Scroll down in screen coordinates with a gesture.
1471 IntSize scrollDelta(0, 10);
1472 EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(0, 0), CCInputHandlerClient::Gest ure), CCInputHandlerClient::ScrollStarted);
1473 m_hostImpl->scrollBy(IntPoint(), scrollDelta);
1474 m_hostImpl->scrollEnd();
1475
1476 // The layer should have scrolled down in its local coordinates, but half he amount.
1477 scoped_ptr<CCScrollAndScaleSet> scrollInfo = m_hostImpl->processScrollDeltas ();
1478 expectContains(*scrollInfo.get(), m_hostImpl->rootLayer()->id(), IntSize(0, scrollDelta.height() / scale));
1479
1480 // Reset and scroll down with the wheel.
1481 m_hostImpl->rootLayer()->setScrollDelta(FloatSize());
1482 IntSize wheelScrollDelta(0, 10);
1483 EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(0, 0), CCInputHandlerClient::Whee l), CCInputHandlerClient::ScrollStarted);
1484 m_hostImpl->scrollBy(IntPoint(), wheelScrollDelta);
1485 m_hostImpl->scrollEnd();
1486
1487 // The scale should not have been applied to the scroll delta.
1488 scrollInfo = m_hostImpl->processScrollDeltas();
1489 expectContains(*scrollInfo.get(), m_hostImpl->rootLayer()->id(), wheelScroll Delta);
1490 }
1491
1492 class BlendStateTrackerContext: public FakeWebGraphicsContext3D {
1493 public:
1494 BlendStateTrackerContext() : m_blend(false) { }
1495
1496 virtual void enable(WGC3Denum cap)
1497 {
1498 if (cap == GraphicsContext3D::BLEND)
1499 m_blend = true;
1500 }
1501
1502 virtual void disable(WGC3Denum cap)
1503 {
1504 if (cap == GraphicsContext3D::BLEND)
1505 m_blend = false;
1506 }
1507
1508 bool blend() const { return m_blend; }
1509
1510 private:
1511 bool m_blend;
1512 };
1513
1514 class BlendStateCheckLayer : public CCLayerImpl {
1515 public:
1516 static scoped_ptr<CCLayerImpl> create(int id, CCResourceProvider* resourcePr ovider) { return scoped_ptr<CCLayerImpl>(new BlendStateCheckLayer(id, resourcePr ovider)); }
1517
1518 virtual void appendQuads(CCQuadSink& quadSink, CCAppendQuadsData& appendQuad sData) OVERRIDE
1519 {
1520 m_quadsAppended = true;
1521
1522 IntRect opaqueRect;
1523 if (contentsOpaque())
1524 opaqueRect = m_quadRect;
1525 else
1526 opaqueRect = m_opaqueContentRect;
1527
1528 CCSharedQuadState* sharedQuadState = quadSink.useSharedQuadState(createS haredQuadState());
1529 scoped_ptr<CCTileDrawQuad> testBlendingDrawQuad = CCTileDrawQuad::create (sharedQuadState, m_quadRect, opaqueRect, m_resourceId, IntPoint(), IntSize(1, 1 ), 0, false, false, false, false, false);
1530 testBlendingDrawQuad->setQuadVisibleRect(m_quadVisibleRect);
1531 EXPECT_EQ(m_blend, testBlendingDrawQuad->needsBlending());
1532 EXPECT_EQ(m_hasRenderSurface, !!renderSurface());
1533 quadSink.append(testBlendingDrawQuad.PassAs<CCDrawQuad>(), appendQuadsDa ta);
1534 }
1535
1536 void setExpectation(bool blend, bool hasRenderSurface)
1537 {
1538 m_blend = blend;
1539 m_hasRenderSurface = hasRenderSurface;
1540 m_quadsAppended = false;
1541 }
1542
1543 bool quadsAppended() const { return m_quadsAppended; }
1544
1545 void setQuadRect(const IntRect& rect) { m_quadRect = rect; }
1546 void setQuadVisibleRect(const IntRect& rect) { m_quadVisibleRect = rect; }
1547 void setOpaqueContentRect(const IntRect& rect) { m_opaqueContentRect = rect; }
1548
1549 private:
1550 explicit BlendStateCheckLayer(int id, CCResourceProvider* resourceProvider)
1551 : CCLayerImpl(id)
1552 , m_blend(false)
1553 , m_hasRenderSurface(false)
1554 , m_quadsAppended(false)
1555 , m_quadRect(5, 5, 5, 5)
1556 , m_quadVisibleRect(5, 5, 5, 5)
1557 , m_resourceId(resourceProvider->createResource(CCRenderer::ContentPool, IntSize(1, 1), GraphicsContext3D::RGBA, CCResourceProvider::TextureUsageAny))
1558 {
1559 setAnchorPoint(FloatPoint(0, 0));
1560 setBounds(IntSize(10, 10));
1561 setContentBounds(IntSize(10, 10));
1562 setDrawsContent(true);
1563 }
1564
1565 bool m_blend;
1566 bool m_hasRenderSurface;
1567 bool m_quadsAppended;
1568 IntRect m_quadRect;
1569 IntRect m_opaqueContentRect;
1570 IntRect m_quadVisibleRect;
1571 CCResourceProvider::ResourceId m_resourceId;
1572 };
1573
1574 TEST_P(CCLayerTreeHostImplTest, blendingOffWhenDrawingOpaqueLayers)
1575 {
1576 {
1577 scoped_ptr<CCLayerImpl> root = CCLayerImpl::create(1);
1578 root->setAnchorPoint(FloatPoint(0, 0));
1579 root->setBounds(IntSize(10, 10));
1580 root->setContentBounds(root->bounds());
1581 root->setDrawsContent(false);
1582 m_hostImpl->setRootLayer(root.Pass());
1583 }
1584 CCLayerImpl* root = m_hostImpl->rootLayer();
1585
1586 root->addChild(BlendStateCheckLayer::create(2, m_hostImpl->resourceProvider( )));
1587 BlendStateCheckLayer* layer1 = static_cast<BlendStateCheckLayer*>(root->chil dren()[0]);
1588 layer1->setPosition(FloatPoint(2, 2));
1589
1590 CCLayerTreeHostImpl::FrameData frame;
1591
1592 // Opaque layer, drawn without blending.
1593 layer1->setContentsOpaque(true);
1594 layer1->setExpectation(false, false);
1595 EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
1596 m_hostImpl->drawLayers(frame);
1597 EXPECT_TRUE(layer1->quadsAppended());
1598 m_hostImpl->didDrawAllLayers(frame);
1599
1600 // Layer with translucent content and painting, so drawn with blending.
1601 layer1->setContentsOpaque(false);
1602 layer1->setExpectation(true, false);
1603 EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
1604 m_hostImpl->drawLayers(frame);
1605 EXPECT_TRUE(layer1->quadsAppended());
1606 m_hostImpl->didDrawAllLayers(frame);
1607
1608 // Layer with translucent opacity, drawn with blending.
1609 layer1->setContentsOpaque(true);
1610 layer1->setOpacity(0.5);
1611 layer1->setExpectation(true, false);
1612 EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
1613 m_hostImpl->drawLayers(frame);
1614 EXPECT_TRUE(layer1->quadsAppended());
1615 m_hostImpl->didDrawAllLayers(frame);
1616
1617 // Layer with translucent opacity and painting, drawn with blending.
1618 layer1->setContentsOpaque(true);
1619 layer1->setOpacity(0.5);
1620 layer1->setExpectation(true, false);
1621 EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
1622 m_hostImpl->drawLayers(frame);
1623 EXPECT_TRUE(layer1->quadsAppended());
1624 m_hostImpl->didDrawAllLayers(frame);
1625
1626 layer1->addChild(BlendStateCheckLayer::create(3, m_hostImpl->resourceProvide r()));
1627 BlendStateCheckLayer* layer2 = static_cast<BlendStateCheckLayer*>(layer1->ch ildren()[0]);
1628 layer2->setPosition(FloatPoint(4, 4));
1629
1630 // 2 opaque layers, drawn without blending.
1631 layer1->setContentsOpaque(true);
1632 layer1->setOpacity(1);
1633 layer1->setExpectation(false, false);
1634 layer2->setContentsOpaque(true);
1635 layer2->setOpacity(1);
1636 layer2->setExpectation(false, false);
1637 EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
1638 m_hostImpl->drawLayers(frame);
1639 EXPECT_TRUE(layer1->quadsAppended());
1640 EXPECT_TRUE(layer2->quadsAppended());
1641 m_hostImpl->didDrawAllLayers(frame);
1642
1643 // Parent layer with translucent content, drawn with blending.
1644 // Child layer with opaque content, drawn without blending.
1645 layer1->setContentsOpaque(false);
1646 layer1->setExpectation(true, false);
1647 layer2->setExpectation(false, false);
1648 EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
1649 m_hostImpl->drawLayers(frame);
1650 EXPECT_TRUE(layer1->quadsAppended());
1651 EXPECT_TRUE(layer2->quadsAppended());
1652 m_hostImpl->didDrawAllLayers(frame);
1653
1654 // Parent layer with translucent content but opaque painting, drawn without blending.
1655 // Child layer with opaque content, drawn without blending.
1656 layer1->setContentsOpaque(true);
1657 layer1->setExpectation(false, false);
1658 layer2->setExpectation(false, false);
1659 EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
1660 m_hostImpl->drawLayers(frame);
1661 EXPECT_TRUE(layer1->quadsAppended());
1662 EXPECT_TRUE(layer2->quadsAppended());
1663 m_hostImpl->didDrawAllLayers(frame);
1664
1665 // Parent layer with translucent opacity and opaque content. Since it has a
1666 // drawing child, it's drawn to a render surface which carries the opacity,
1667 // so it's itself drawn without blending.
1668 // Child layer with opaque content, drawn without blending (parent surface
1669 // carries the inherited opacity).
1670 layer1->setContentsOpaque(true);
1671 layer1->setOpacity(0.5);
1672 layer1->setExpectation(false, true);
1673 layer2->setExpectation(false, false);
1674 EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
1675 m_hostImpl->drawLayers(frame);
1676 EXPECT_TRUE(layer1->quadsAppended());
1677 EXPECT_TRUE(layer2->quadsAppended());
1678 m_hostImpl->didDrawAllLayers(frame);
1679
1680 // Draw again, but with child non-opaque, to make sure
1681 // layer1 not culled.
1682 layer1->setContentsOpaque(true);
1683 layer1->setOpacity(1);
1684 layer1->setExpectation(false, false);
1685 layer2->setContentsOpaque(true);
1686 layer2->setOpacity(0.5);
1687 layer2->setExpectation(true, false);
1688 EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
1689 m_hostImpl->drawLayers(frame);
1690 EXPECT_TRUE(layer1->quadsAppended());
1691 EXPECT_TRUE(layer2->quadsAppended());
1692 m_hostImpl->didDrawAllLayers(frame);
1693
1694 // A second way of making the child non-opaque.
1695 layer1->setContentsOpaque(true);
1696 layer1->setOpacity(1);
1697 layer1->setExpectation(false, false);
1698 layer2->setContentsOpaque(false);
1699 layer2->setOpacity(1);
1700 layer2->setExpectation(true, false);
1701 EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
1702 m_hostImpl->drawLayers(frame);
1703 EXPECT_TRUE(layer1->quadsAppended());
1704 EXPECT_TRUE(layer2->quadsAppended());
1705 m_hostImpl->didDrawAllLayers(frame);
1706
1707 // And when the layer says its not opaque but is painted opaque, it is not b lended.
1708 layer1->setContentsOpaque(true);
1709 layer1->setOpacity(1);
1710 layer1->setExpectation(false, false);
1711 layer2->setContentsOpaque(true);
1712 layer2->setOpacity(1);
1713 layer2->setExpectation(false, false);
1714 EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
1715 m_hostImpl->drawLayers(frame);
1716 EXPECT_TRUE(layer1->quadsAppended());
1717 EXPECT_TRUE(layer2->quadsAppended());
1718 m_hostImpl->didDrawAllLayers(frame);
1719
1720 // Layer with partially opaque contents, drawn with blending.
1721 layer1->setContentsOpaque(false);
1722 layer1->setQuadRect(IntRect(5, 5, 5, 5));
1723 layer1->setQuadVisibleRect(IntRect(5, 5, 5, 5));
1724 layer1->setOpaqueContentRect(IntRect(5, 5, 2, 5));
1725 layer1->setExpectation(true, false);
1726 EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
1727 m_hostImpl->drawLayers(frame);
1728 EXPECT_TRUE(layer1->quadsAppended());
1729 m_hostImpl->didDrawAllLayers(frame);
1730
1731 // Layer with partially opaque contents partially culled, drawn with blendin g.
1732 layer1->setContentsOpaque(false);
1733 layer1->setQuadRect(IntRect(5, 5, 5, 5));
1734 layer1->setQuadVisibleRect(IntRect(5, 5, 5, 2));
1735 layer1->setOpaqueContentRect(IntRect(5, 5, 2, 5));
1736 layer1->setExpectation(true, false);
1737 EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
1738 m_hostImpl->drawLayers(frame);
1739 EXPECT_TRUE(layer1->quadsAppended());
1740 m_hostImpl->didDrawAllLayers(frame);
1741
1742 // Layer with partially opaque contents culled, drawn with blending.
1743 layer1->setContentsOpaque(false);
1744 layer1->setQuadRect(IntRect(5, 5, 5, 5));
1745 layer1->setQuadVisibleRect(IntRect(7, 5, 3, 5));
1746 layer1->setOpaqueContentRect(IntRect(5, 5, 2, 5));
1747 layer1->setExpectation(true, false);
1748 EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
1749 m_hostImpl->drawLayers(frame);
1750 EXPECT_TRUE(layer1->quadsAppended());
1751 m_hostImpl->didDrawAllLayers(frame);
1752
1753 // Layer with partially opaque contents and translucent contents culled, dra wn without blending.
1754 layer1->setContentsOpaque(false);
1755 layer1->setQuadRect(IntRect(5, 5, 5, 5));
1756 layer1->setQuadVisibleRect(IntRect(5, 5, 2, 5));
1757 layer1->setOpaqueContentRect(IntRect(5, 5, 2, 5));
1758 layer1->setExpectation(false, false);
1759 EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
1760 m_hostImpl->drawLayers(frame);
1761 EXPECT_TRUE(layer1->quadsAppended());
1762 m_hostImpl->didDrawAllLayers(frame);
1763
1764 }
1765
1766 TEST_P(CCLayerTreeHostImplTest, viewportCovered)
1767 {
1768 m_hostImpl->initializeRenderer(createContext());
1769 m_hostImpl->setBackgroundColor(SK_ColorGRAY);
1770
1771 IntSize viewportSize(1000, 1000);
1772 m_hostImpl->setViewportSize(viewportSize, viewportSize);
1773
1774 m_hostImpl->setRootLayer(BlendStateCheckLayer::create(1, m_hostImpl->resourc eProvider()));
1775 BlendStateCheckLayer* root = static_cast<BlendStateCheckLayer*>(m_hostImpl-> rootLayer());
1776 root->setExpectation(false, true);
1777 root->setContentsOpaque(true);
1778
1779 // No gutter rects
1780 {
1781 IntRect layerRect(0, 0, 1000, 1000);
1782 root->setPosition(layerRect.location());
1783 root->setBounds(layerRect.size());
1784 root->setContentBounds(layerRect.size());
1785 root->setQuadRect(IntRect(IntPoint(), layerRect.size()));
1786 root->setQuadVisibleRect(IntRect(IntPoint(), layerRect.size()));
1787
1788 CCLayerTreeHostImpl::FrameData frame;
1789 EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
1790 ASSERT_EQ(1u, frame.renderPasses.size());
1791
1792 size_t numGutterQuads = 0;
1793 for (size_t i = 0; i < frame.renderPasses[0]->quadList().size(); ++i)
1794 numGutterQuads += (frame.renderPasses[0]->quadList()[i]->material() == CCDrawQuad::SolidColor) ? 1 : 0;
1795 EXPECT_EQ(0u, numGutterQuads);
1796 EXPECT_EQ(1u, frame.renderPasses[0]->quadList().size());
1797
1798 verifyQuadsExactlyCoverRect(frame.renderPasses[0]->quadList(), IntRect(- layerRect.location(), viewportSize));
1799 m_hostImpl->didDrawAllLayers(frame);
1800 }
1801
1802 // Empty visible content area (fullscreen gutter rect)
1803 {
1804 IntRect layerRect(0, 0, 0, 0);
1805 root->setPosition(layerRect.location());
1806 root->setBounds(layerRect.size());
1807 root->setContentBounds(layerRect.size());
1808 root->setQuadRect(IntRect(IntPoint(), layerRect.size()));
1809 root->setQuadVisibleRect(IntRect(IntPoint(), layerRect.size()));
1810
1811 CCLayerTreeHostImpl::FrameData frame;
1812 EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
1813 ASSERT_EQ(1u, frame.renderPasses.size());
1814 m_hostImpl->didDrawAllLayers(frame);
1815
1816 size_t numGutterQuads = 0;
1817 for (size_t i = 0; i < frame.renderPasses[0]->quadList().size(); ++i)
1818 numGutterQuads += (frame.renderPasses[0]->quadList()[i]->material() == CCDrawQuad::SolidColor) ? 1 : 0;
1819 EXPECT_EQ(1u, numGutterQuads);
1820 EXPECT_EQ(1u, frame.renderPasses[0]->quadList().size());
1821
1822 verifyQuadsExactlyCoverRect(frame.renderPasses[0]->quadList(), IntRect(- layerRect.location(), viewportSize));
1823 m_hostImpl->didDrawAllLayers(frame);
1824 }
1825
1826 // Content area in middle of clip rect (four surrounding gutter rects)
1827 {
1828 IntRect layerRect(500, 500, 200, 200);
1829 root->setPosition(layerRect.location());
1830 root->setBounds(layerRect.size());
1831 root->setContentBounds(layerRect.size());
1832 root->setQuadRect(IntRect(IntPoint(), layerRect.size()));
1833 root->setQuadVisibleRect(IntRect(IntPoint(), layerRect.size()));
1834
1835 CCLayerTreeHostImpl::FrameData frame;
1836 EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
1837 ASSERT_EQ(1u, frame.renderPasses.size());
1838
1839 size_t numGutterQuads = 0;
1840 for (size_t i = 0; i < frame.renderPasses[0]->quadList().size(); ++i)
1841 numGutterQuads += (frame.renderPasses[0]->quadList()[i]->material() == CCDrawQuad::SolidColor) ? 1 : 0;
1842 EXPECT_EQ(4u, numGutterQuads);
1843 EXPECT_EQ(5u, frame.renderPasses[0]->quadList().size());
1844
1845 verifyQuadsExactlyCoverRect(frame.renderPasses[0]->quadList(), IntRect(- layerRect.location(), viewportSize));
1846 m_hostImpl->didDrawAllLayers(frame);
1847 }
1848
1849 }
1850
1851
1852 class ReshapeTrackerContext: public FakeWebGraphicsContext3D {
1853 public:
1854 ReshapeTrackerContext() : m_reshapeCalled(false) { }
1855
1856 virtual void reshape(int width, int height)
1857 {
1858 m_reshapeCalled = true;
1859 }
1860
1861 bool reshapeCalled() const { return m_reshapeCalled; }
1862
1863 private:
1864 bool m_reshapeCalled;
1865 };
1866
1867 class FakeDrawableCCLayerImpl: public CCLayerImpl {
1868 public:
1869 static scoped_ptr<CCLayerImpl> create(int id) { return scoped_ptr<CCLayerImp l>(new FakeDrawableCCLayerImpl(id)); }
1870 protected:
1871 explicit FakeDrawableCCLayerImpl(int id) : CCLayerImpl(id) { }
1872 };
1873
1874 // Only reshape when we know we are going to draw. Otherwise, the reshape
1875 // can leave the window at the wrong size if we never draw and the proper
1876 // viewport size is never set.
1877 TEST_P(CCLayerTreeHostImplTest, reshapeNotCalledUntilDraw)
1878 {
1879 scoped_ptr<CCGraphicsContext> ccContext = FakeWebCompositorOutputSurface::cr eate(adoptPtr(new ReshapeTrackerContext)).PassAs<CCGraphicsContext>();
1880 ReshapeTrackerContext* reshapeTracker = static_cast<ReshapeTrackerContext*>( ccContext->context3D());
1881 m_hostImpl->initializeRenderer(ccContext.Pass());
1882
1883 scoped_ptr<CCLayerImpl> root = FakeDrawableCCLayerImpl::create(1);
1884 root->setAnchorPoint(FloatPoint(0, 0));
1885 root->setBounds(IntSize(10, 10));
1886 root->setDrawsContent(true);
1887 m_hostImpl->setRootLayer(root.Pass());
1888 EXPECT_FALSE(reshapeTracker->reshapeCalled());
1889
1890 CCLayerTreeHostImpl::FrameData frame;
1891 EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
1892 m_hostImpl->drawLayers(frame);
1893 EXPECT_TRUE(reshapeTracker->reshapeCalled());
1894 m_hostImpl->didDrawAllLayers(frame);
1895 }
1896
1897 class PartialSwapTrackerContext : public FakeWebGraphicsContext3D {
1898 public:
1899 virtual void postSubBufferCHROMIUM(int x, int y, int width, int height)
1900 {
1901 m_partialSwapRect = IntRect(x, y, width, height);
1902 }
1903
1904 virtual WebString getString(WGC3Denum name)
1905 {
1906 if (name == GraphicsContext3D::EXTENSIONS)
1907 return WebString("GL_CHROMIUM_post_sub_buffer GL_CHROMIUM_set_visibi lity");
1908
1909 return WebString();
1910 }
1911
1912 IntRect partialSwapRect() const { return m_partialSwapRect; }
1913
1914 private:
1915 IntRect m_partialSwapRect;
1916 };
1917
1918 // Make sure damage tracking propagates all the way to the graphics context,
1919 // where it should request to swap only the subBuffer that is damaged.
1920 TEST_P(CCLayerTreeHostImplTest, partialSwapReceivesDamageRect)
1921 {
1922 scoped_ptr<CCGraphicsContext> ccContext = FakeWebCompositorOutputSurface::cr eate(adoptPtr(new PartialSwapTrackerContext)).PassAs<CCGraphicsContext>();
1923 PartialSwapTrackerContext* partialSwapTracker = static_cast<PartialSwapTrack erContext*>(ccContext->context3D());
1924
1925 // This test creates its own CCLayerTreeHostImpl, so
1926 // that we can force partial swap enabled.
1927 CCLayerTreeSettings settings;
1928 CCSettings::setPartialSwapEnabled(true);
1929 scoped_ptr<CCLayerTreeHostImpl> layerTreeHostImpl = CCLayerTreeHostImpl::cre ate(settings, this);
1930 layerTreeHostImpl->initializeRenderer(ccContext.Pass());
1931 layerTreeHostImpl->setViewportSize(IntSize(500, 500), IntSize(500, 500));
1932
1933 scoped_ptr<CCLayerImpl> root = FakeDrawableCCLayerImpl::create(1);
1934 scoped_ptr<CCLayerImpl> child = FakeDrawableCCLayerImpl::create(2);
1935 child->setPosition(FloatPoint(12, 13));
1936 child->setAnchorPoint(FloatPoint(0, 0));
1937 child->setBounds(IntSize(14, 15));
1938 child->setContentBounds(IntSize(14, 15));
1939 child->setDrawsContent(true);
1940 root->setAnchorPoint(FloatPoint(0, 0));
1941 root->setBounds(IntSize(500, 500));
1942 root->setContentBounds(IntSize(500, 500));
1943 root->setDrawsContent(true);
1944 root->addChild(child.Pass());
1945 layerTreeHostImpl->setRootLayer(root.Pass());
1946
1947 CCLayerTreeHostImpl::FrameData frame;
1948
1949 // First frame, the entire screen should get swapped.
1950 EXPECT_TRUE(layerTreeHostImpl->prepareToDraw(frame));
1951 layerTreeHostImpl->drawLayers(frame);
1952 layerTreeHostImpl->didDrawAllLayers(frame);
1953 layerTreeHostImpl->swapBuffers();
1954 IntRect actualSwapRect = partialSwapTracker->partialSwapRect();
1955 IntRect expectedSwapRect = IntRect(IntPoint::zero(), IntSize(500, 500));
1956 EXPECT_EQ(expectedSwapRect.x(), actualSwapRect.x());
1957 EXPECT_EQ(expectedSwapRect.y(), actualSwapRect.y());
1958 EXPECT_EQ(expectedSwapRect.width(), actualSwapRect.width());
1959 EXPECT_EQ(expectedSwapRect.height(), actualSwapRect.height());
1960
1961 // Second frame, only the damaged area should get swapped. Damage should be the union
1962 // of old and new child rects.
1963 // expected damage rect: IntRect(IntPoint::zero(), IntSize(26, 28));
1964 // expected swap rect: vertically flipped, with origin at bottom left corner .
1965 layerTreeHostImpl->rootLayer()->children()[0]->setPosition(FloatPoint(0, 0)) ;
1966 EXPECT_TRUE(layerTreeHostImpl->prepareToDraw(frame));
1967 layerTreeHostImpl->drawLayers(frame);
1968 m_hostImpl->didDrawAllLayers(frame);
1969 layerTreeHostImpl->swapBuffers();
1970 actualSwapRect = partialSwapTracker->partialSwapRect();
1971 expectedSwapRect = IntRect(IntPoint(0, 500-28), IntSize(26, 28));
1972 EXPECT_EQ(expectedSwapRect.x(), actualSwapRect.x());
1973 EXPECT_EQ(expectedSwapRect.y(), actualSwapRect.y());
1974 EXPECT_EQ(expectedSwapRect.width(), actualSwapRect.width());
1975 EXPECT_EQ(expectedSwapRect.height(), actualSwapRect.height());
1976
1977 // Make sure that partial swap is constrained to the viewport dimensions
1978 // expected damage rect: IntRect(IntPoint::zero(), IntSize(500, 500));
1979 // expected swap rect: flipped damage rect, but also clamped to viewport
1980 layerTreeHostImpl->setViewportSize(IntSize(10, 10), IntSize(10, 10));
1981 layerTreeHostImpl->rootLayer()->setOpacity(0.7f); // this will damage everyt hing
1982 EXPECT_TRUE(layerTreeHostImpl->prepareToDraw(frame));
1983 layerTreeHostImpl->drawLayers(frame);
1984 m_hostImpl->didDrawAllLayers(frame);
1985 layerTreeHostImpl->swapBuffers();
1986 actualSwapRect = partialSwapTracker->partialSwapRect();
1987 expectedSwapRect = IntRect(IntPoint::zero(), IntSize(10, 10));
1988 EXPECT_EQ(expectedSwapRect.x(), actualSwapRect.x());
1989 EXPECT_EQ(expectedSwapRect.y(), actualSwapRect.y());
1990 EXPECT_EQ(expectedSwapRect.width(), actualSwapRect.width());
1991 EXPECT_EQ(expectedSwapRect.height(), actualSwapRect.height());
1992 }
1993
1994 TEST_P(CCLayerTreeHostImplTest, rootLayerDoesntCreateExtraSurface)
1995 {
1996 scoped_ptr<CCLayerImpl> root = FakeDrawableCCLayerImpl::create(1);
1997 scoped_ptr<CCLayerImpl> child = FakeDrawableCCLayerImpl::create(2);
1998 child->setAnchorPoint(FloatPoint(0, 0));
1999 child->setBounds(IntSize(10, 10));
2000 child->setContentBounds(IntSize(10, 10));
2001 child->setDrawsContent(true);
2002 root->setAnchorPoint(FloatPoint(0, 0));
2003 root->setBounds(IntSize(10, 10));
2004 root->setContentBounds(IntSize(10, 10));
2005 root->setDrawsContent(true);
2006 root->setOpacity(0.7f);
2007 root->addChild(child.Pass());
2008
2009 m_hostImpl->setRootLayer(root.Pass());
2010
2011 CCLayerTreeHostImpl::FrameData frame;
2012
2013 EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
2014 EXPECT_EQ(1u, frame.renderSurfaceLayerList->size());
2015 EXPECT_EQ(1u, frame.renderPasses.size());
2016 m_hostImpl->didDrawAllLayers(frame);
2017 }
2018
2019 } // namespace
2020
2021 class FakeLayerWithQuads : public CCLayerImpl {
2022 public:
2023 static scoped_ptr<CCLayerImpl> create(int id) { return scoped_ptr<CCLayerImp l>(new FakeLayerWithQuads(id)); }
2024
2025 virtual void appendQuads(CCQuadSink& quadSink, CCAppendQuadsData& appendQuad sData) OVERRIDE
2026 {
2027 CCSharedQuadState* sharedQuadState = quadSink.useSharedQuadState(createS haredQuadState());
2028
2029 SkColor gray = SkColorSetRGB(100, 100, 100);
2030 IntRect quadRect(IntPoint(0, 0), contentBounds());
2031 scoped_ptr<CCSolidColorDrawQuad> myQuad = CCSolidColorDrawQuad::create(s haredQuadState, quadRect, gray);
2032 quadSink.append(myQuad.PassAs<CCDrawQuad>(), appendQuadsData);
2033 }
2034
2035 private:
2036 FakeLayerWithQuads(int id)
2037 : CCLayerImpl(id)
2038 {
2039 }
2040 };
2041
2042 namespace {
2043
2044 class MockContext : public FakeWebGraphicsContext3D {
2045 public:
2046 MOCK_METHOD1(useProgram, void(WebGLId program));
2047 MOCK_METHOD5(uniform4f, void(WGC3Dint location, WGC3Dfloat x, WGC3Dfloat y, WGC3Dfloat z, WGC3Dfloat w));
2048 MOCK_METHOD4(uniformMatrix4fv, void(WGC3Dint location, WGC3Dsizei count, WGC 3Dboolean transpose, const WGC3Dfloat* value));
2049 MOCK_METHOD4(drawElements, void(WGC3Denum mode, WGC3Dsizei count, WGC3Denum type, WGC3Dintptr offset));
2050 MOCK_METHOD1(getString, WebString(WGC3Denum name));
2051 MOCK_METHOD0(getRequestableExtensionsCHROMIUM, WebString());
2052 MOCK_METHOD1(enable, void(WGC3Denum cap));
2053 MOCK_METHOD1(disable, void(WGC3Denum cap));
2054 MOCK_METHOD4(scissor, void(WGC3Dint x, WGC3Dint y, WGC3Dsizei width, WGC3Dsi zei height));
2055 };
2056
2057 class MockContextHarness {
2058 private:
2059 MockContext* m_context;
2060 public:
2061 MockContextHarness(MockContext* context)
2062 : m_context(context)
2063 {
2064 // Catch "uninteresting" calls
2065 EXPECT_CALL(*m_context, useProgram(_))
2066 .Times(0);
2067
2068 EXPECT_CALL(*m_context, drawElements(_, _, _, _))
2069 .Times(0);
2070
2071 // These are not asserted
2072 EXPECT_CALL(*m_context, uniformMatrix4fv(_, _, _, _))
2073 .WillRepeatedly(Return());
2074
2075 EXPECT_CALL(*m_context, uniform4f(_, _, _, _, _))
2076 .WillRepeatedly(Return());
2077
2078 // Any other strings are empty
2079 EXPECT_CALL(*m_context, getString(_))
2080 .WillRepeatedly(Return(WebString()));
2081
2082 // Support for partial swap, if needed
2083 EXPECT_CALL(*m_context, getString(GraphicsContext3D::EXTENSIONS))
2084 .WillRepeatedly(Return(WebString("GL_CHROMIUM_post_sub_buffer")));
2085
2086 EXPECT_CALL(*m_context, getRequestableExtensionsCHROMIUM())
2087 .WillRepeatedly(Return(WebString("GL_CHROMIUM_post_sub_buffer")));
2088
2089 // Any un-sanctioned calls to enable() are OK
2090 EXPECT_CALL(*m_context, enable(_))
2091 .WillRepeatedly(Return());
2092
2093 // Any un-sanctioned calls to disable() are OK
2094 EXPECT_CALL(*m_context, disable(_))
2095 .WillRepeatedly(Return());
2096 }
2097
2098 void mustDrawSolidQuad()
2099 {
2100 EXPECT_CALL(*m_context, drawElements(GraphicsContext3D::TRIANGLES, 6, Gr aphicsContext3D::UNSIGNED_SHORT, 0))
2101 .WillOnce(Return())
2102 .RetiresOnSaturation();
2103
2104 // 1 is hardcoded return value of fake createProgram()
2105 EXPECT_CALL(*m_context, useProgram(1))
2106 .WillOnce(Return())
2107 .RetiresOnSaturation();
2108
2109 }
2110
2111 void mustSetScissor(int x, int y, int width, int height)
2112 {
2113 EXPECT_CALL(*m_context, enable(GraphicsContext3D::SCISSOR_TEST))
2114 .WillRepeatedly(Return());
2115
2116 EXPECT_CALL(*m_context, scissor(x, y, width, height))
2117 .Times(AtLeast(1))
2118 .WillRepeatedly(Return());
2119 }
2120
2121 void mustSetNoScissor()
2122 {
2123 EXPECT_CALL(*m_context, disable(GraphicsContext3D::SCISSOR_TEST))
2124 .WillRepeatedly(Return());
2125
2126 EXPECT_CALL(*m_context, enable(GraphicsContext3D::SCISSOR_TEST))
2127 .Times(0);
2128
2129 EXPECT_CALL(*m_context, scissor(_, _, _, _))
2130 .Times(0);
2131 }
2132 };
2133
2134 TEST_P(CCLayerTreeHostImplTest, noPartialSwap)
2135 {
2136 scoped_ptr<CCGraphicsContext> context = FakeWebCompositorOutputSurface::crea te(adoptPtr(new MockContext)).PassAs<CCGraphicsContext>();
2137 MockContext* mockContext = static_cast<MockContext*>(context->context3D());
2138 MockContextHarness harness(mockContext);
2139
2140 harness.mustDrawSolidQuad();
2141 harness.mustSetScissor(0, 0, 10, 10);
2142
2143 // Run test case
2144 scoped_ptr<CCLayerTreeHostImpl> myHostImpl = createLayerTreeHost(false, cont ext.Pass(), FakeLayerWithQuads::create(1));
2145
2146 CCLayerTreeHostImpl::FrameData frame;
2147 EXPECT_TRUE(myHostImpl->prepareToDraw(frame));
2148 myHostImpl->drawLayers(frame);
2149 myHostImpl->didDrawAllLayers(frame);
2150 Mock::VerifyAndClearExpectations(&mockContext);
2151 }
2152
2153 TEST_P(CCLayerTreeHostImplTest, partialSwap)
2154 {
2155 scoped_ptr<CCGraphicsContext> context = FakeWebCompositorOutputSurface::crea te(adoptPtr(new MockContext)).PassAs<CCGraphicsContext>();
2156 MockContext* mockContext = static_cast<MockContext*>(context->context3D());
2157 MockContextHarness harness(mockContext);
2158
2159 scoped_ptr<CCLayerTreeHostImpl> myHostImpl = createLayerTreeHost(true, conte xt.Pass(), FakeLayerWithQuads::create(1));
2160
2161 // The first frame is not a partially-swapped one.
2162 harness.mustSetScissor(0, 0, 10, 10);
2163 harness.mustDrawSolidQuad();
2164 {
2165 CCLayerTreeHostImpl::FrameData frame;
2166 EXPECT_TRUE(myHostImpl->prepareToDraw(frame));
2167 myHostImpl->drawLayers(frame);
2168 myHostImpl->didDrawAllLayers(frame);
2169 }
2170 Mock::VerifyAndClearExpectations(&mockContext);
2171
2172 // Damage a portion of the frame.
2173 myHostImpl->rootLayer()->setUpdateRect(IntRect(0, 0, 2, 3));
2174
2175 // The second frame will be partially-swapped (the y coordinates are flipped ).
2176 harness.mustSetScissor(0, 7, 2, 3);
2177 harness.mustDrawSolidQuad();
2178 {
2179 CCLayerTreeHostImpl::FrameData frame;
2180 EXPECT_TRUE(myHostImpl->prepareToDraw(frame));
2181 myHostImpl->drawLayers(frame);
2182 myHostImpl->didDrawAllLayers(frame);
2183 }
2184 Mock::VerifyAndClearExpectations(&mockContext);
2185 }
2186
2187 class PartialSwapContext : public FakeWebGraphicsContext3D {
2188 public:
2189 WebString getString(WGC3Denum name)
2190 {
2191 if (name == GraphicsContext3D::EXTENSIONS)
2192 return WebString("GL_CHROMIUM_post_sub_buffer");
2193 return WebString();
2194 }
2195
2196 WebString getRequestableExtensionsCHROMIUM()
2197 {
2198 return WebString("GL_CHROMIUM_post_sub_buffer");
2199 }
2200
2201 // Unlimited texture size.
2202 virtual void getIntegerv(WGC3Denum pname, WGC3Dint* value)
2203 {
2204 if (pname == cc::GraphicsContext3D::MAX_TEXTURE_SIZE)
2205 *value = 8192;
2206 }
2207 };
2208
2209 static scoped_ptr<CCLayerTreeHostImpl> setupLayersForOpacity(bool partialSwap, C CLayerTreeHostImplClient* client)
2210 {
2211 CCSettings::setPartialSwapEnabled(partialSwap);
2212
2213 scoped_ptr<CCGraphicsContext> context = FakeWebCompositorOutputSurface::crea te(adoptPtr(new PartialSwapContext)).PassAs<CCGraphicsContext>();
2214
2215 CCLayerTreeSettings settings;
2216 scoped_ptr<CCLayerTreeHostImpl> myHostImpl = CCLayerTreeHostImpl::create(set tings, client);
2217 myHostImpl->initializeRenderer(context.Pass());
2218 myHostImpl->setViewportSize(IntSize(100, 100), IntSize(100, 100));
2219
2220 /*
2221 Layers are created as follows:
2222
2223 +--------------------+
2224 | 1 |
2225 | +-----------+ |
2226 | | 2 | |
2227 | | +-------------------+
2228 | | | 3 |
2229 | | +-------------------+
2230 | | | |
2231 | +-----------+ |
2232 | |
2233 | |
2234 +--------------------+
2235
2236 Layers 1, 2 have render surfaces
2237 */
2238 scoped_ptr<CCLayerImpl> root = CCLayerImpl::create(1);
2239 scoped_ptr<CCLayerImpl> child = CCLayerImpl::create(2);
2240 scoped_ptr<CCLayerImpl> grandChild = FakeLayerWithQuads::create(3);
2241
2242 IntRect rootRect(0, 0, 100, 100);
2243 IntRect childRect(10, 10, 50, 50);
2244 IntRect grandChildRect(5, 5, 150, 150);
2245
2246 root->createRenderSurface();
2247 root->setAnchorPoint(FloatPoint(0, 0));
2248 root->setPosition(FloatPoint(rootRect.x(), rootRect.y()));
2249 root->setBounds(IntSize(rootRect.width(), rootRect.height()));
2250 root->setContentBounds(root->bounds());
2251 root->setVisibleContentRect(rootRect);
2252 root->setDrawsContent(false);
2253 root->renderSurface()->setContentRect(IntRect(IntPoint(), IntSize(rootRect.w idth(), rootRect.height())));
2254
2255 child->setAnchorPoint(FloatPoint(0, 0));
2256 child->setPosition(FloatPoint(childRect.x(), childRect.y()));
2257 child->setOpacity(0.5f);
2258 child->setBounds(IntSize(childRect.width(), childRect.height()));
2259 child->setContentBounds(child->bounds());
2260 child->setVisibleContentRect(childRect);
2261 child->setDrawsContent(false);
2262
2263 grandChild->setAnchorPoint(FloatPoint(0, 0));
2264 grandChild->setPosition(IntPoint(grandChildRect.x(), grandChildRect.y()));
2265 grandChild->setBounds(IntSize(grandChildRect.width(), grandChildRect.height( )));
2266 grandChild->setContentBounds(grandChild->bounds());
2267 grandChild->setVisibleContentRect(grandChildRect);
2268 grandChild->setDrawsContent(true);
2269
2270 child->addChild(grandChild.Pass());
2271 root->addChild(child.Pass());
2272
2273 myHostImpl->setRootLayer(root.Pass());
2274 return myHostImpl.Pass();
2275 }
2276
2277 TEST_P(CCLayerTreeHostImplTest, contributingLayerEmptyScissorPartialSwap)
2278 {
2279 scoped_ptr<CCLayerTreeHostImpl> myHostImpl = setupLayersForOpacity(true, thi s);
2280
2281 {
2282 CCLayerTreeHostImpl::FrameData frame;
2283 EXPECT_TRUE(myHostImpl->prepareToDraw(frame));
2284
2285 // Just for consistency, the most interesting stuff already happened
2286 myHostImpl->drawLayers(frame);
2287 myHostImpl->didDrawAllLayers(frame);
2288
2289 // Verify all quads have been computed
2290 ASSERT_EQ(2U, frame.renderPasses.size());
2291 ASSERT_EQ(1U, frame.renderPasses[0]->quadList().size());
2292 ASSERT_EQ(1U, frame.renderPasses[1]->quadList().size());
2293 EXPECT_EQ(CCDrawQuad::SolidColor, frame.renderPasses[0]->quadList()[0]-> material());
2294 EXPECT_EQ(CCDrawQuad::RenderPass, frame.renderPasses[1]->quadList()[0]-> material());
2295 }
2296 }
2297
2298 TEST_P(CCLayerTreeHostImplTest, contributingLayerEmptyScissorNoPartialSwap)
2299 {
2300 scoped_ptr<CCLayerTreeHostImpl> myHostImpl = setupLayersForOpacity(false, th is);
2301
2302 {
2303 CCLayerTreeHostImpl::FrameData frame;
2304 EXPECT_TRUE(myHostImpl->prepareToDraw(frame));
2305
2306 // Just for consistency, the most interesting stuff already happened
2307 myHostImpl->drawLayers(frame);
2308 myHostImpl->didDrawAllLayers(frame);
2309
2310 // Verify all quads have been computed
2311 ASSERT_EQ(2U, frame.renderPasses.size());
2312 ASSERT_EQ(1U, frame.renderPasses[0]->quadList().size());
2313 ASSERT_EQ(1U, frame.renderPasses[1]->quadList().size());
2314 EXPECT_EQ(CCDrawQuad::SolidColor, frame.renderPasses[0]->quadList()[0]-> material());
2315 EXPECT_EQ(CCDrawQuad::RenderPass, frame.renderPasses[1]->quadList()[0]-> material());
2316 }
2317 }
2318
2319 // Make sure that context lost notifications are propagated through the tree.
2320 class ContextLostNotificationCheckLayer : public CCLayerImpl {
2321 public:
2322 static scoped_ptr<CCLayerImpl> create(int id) { return scoped_ptr<CCLayerImp l>(new ContextLostNotificationCheckLayer(id)); }
2323
2324 virtual void didLoseContext() OVERRIDE
2325 {
2326 m_didLoseContextCalled = true;
2327 }
2328
2329 bool didLoseContextCalled() const { return m_didLoseContextCalled; }
2330
2331 private:
2332 explicit ContextLostNotificationCheckLayer(int id)
2333 : CCLayerImpl(id)
2334 , m_didLoseContextCalled(false)
2335 {
2336 }
2337
2338 bool m_didLoseContextCalled;
2339 };
2340
2341 TEST_P(CCLayerTreeHostImplTest, contextLostAndRestoredNotificationSentToAllLayer s)
2342 {
2343 m_hostImpl->setRootLayer(ContextLostNotificationCheckLayer::create(1));
2344 ContextLostNotificationCheckLayer* root = static_cast<ContextLostNotificatio nCheckLayer*>(m_hostImpl->rootLayer());
2345
2346 root->addChild(ContextLostNotificationCheckLayer::create(1));
2347 ContextLostNotificationCheckLayer* layer1 = static_cast<ContextLostNotificat ionCheckLayer*>(root->children()[0]);
2348
2349 layer1->addChild(ContextLostNotificationCheckLayer::create(2));
2350 ContextLostNotificationCheckLayer* layer2 = static_cast<ContextLostNotificat ionCheckLayer*>(layer1->children()[0]);
2351
2352 EXPECT_FALSE(root->didLoseContextCalled());
2353 EXPECT_FALSE(layer1->didLoseContextCalled());
2354 EXPECT_FALSE(layer2->didLoseContextCalled());
2355
2356 m_hostImpl->initializeRenderer(createContext());
2357
2358 EXPECT_TRUE(root->didLoseContextCalled());
2359 EXPECT_TRUE(layer1->didLoseContextCalled());
2360 EXPECT_TRUE(layer2->didLoseContextCalled());
2361 }
2362
2363 TEST_P(CCLayerTreeHostImplTest, finishAllRenderingAfterContextLost)
2364 {
2365 CCLayerTreeSettings settings;
2366 m_hostImpl = CCLayerTreeHostImpl::create(settings, this);
2367
2368 // The context initialization will fail, but we should still be able to call finishAllRendering() without any ill effects.
2369 m_hostImpl->initializeRenderer(FakeWebCompositorOutputSurface::create(adoptP tr(new FakeWebGraphicsContext3DMakeCurrentFails)).PassAs<CCGraphicsContext>());
2370 m_hostImpl->finishAllRendering();
2371 }
2372
2373 class FakeWebGraphicsContext3DMakeCurrentFailsEventually : public FakeWebGraphic sContext3D {
2374 public:
2375 explicit FakeWebGraphicsContext3DMakeCurrentFailsEventually(unsigned succeed Count) : m_succeedCount(succeedCount) { }
2376 virtual bool makeContextCurrent() {
2377 if (!m_succeedCount)
2378 return false;
2379 --m_succeedCount;
2380 return true;
2381 }
2382
2383 private:
2384 unsigned m_succeedCount;
2385 };
2386
2387 TEST_P(CCLayerTreeHostImplTest, contextLostDuringInitialize)
2388 {
2389 CCLayerTreeSettings settings;
2390 m_hostImpl = CCLayerTreeHostImpl::create(settings, this);
2391
2392 // Initialize into a known successful state.
2393 EXPECT_TRUE(m_hostImpl->initializeRenderer(createContext()));
2394 EXPECT_TRUE(m_hostImpl->context());
2395 EXPECT_TRUE(m_hostImpl->renderer());
2396 EXPECT_TRUE(m_hostImpl->resourceProvider());
2397
2398 // We will make the context get lost after a numer of makeContextCurrent
2399 // calls. The exact number of calls to make it succeed is dependent on the
2400 // implementation and doesn't really matter (i.e. can be changed to make the
2401 // tests pass after some refactoring).
2402 const unsigned kMakeCurrentSuccessesNeededForSuccessfulInitialization = 3;
2403
2404 for (unsigned i = 0; i < kMakeCurrentSuccessesNeededForSuccessfulInitializat ion; ++i) {
2405 // The context will get lost during initialization, we shouldn't crash. We
2406 // should also be in a consistent state.
2407 EXPECT_FALSE(m_hostImpl->initializeRenderer(FakeWebCompositorOutputSurfa ce::create(adoptPtr(new FakeWebGraphicsContext3DMakeCurrentFailsEventually(i))). PassAs<CCGraphicsContext>()));
2408 EXPECT_EQ(0, m_hostImpl->context());
2409 EXPECT_EQ(0, m_hostImpl->renderer());
2410 EXPECT_EQ(0, m_hostImpl->resourceProvider());
2411 EXPECT_TRUE(m_hostImpl->initializeRenderer(createContext()));
2412 }
2413
2414 EXPECT_TRUE(m_hostImpl->initializeRenderer(FakeWebCompositorOutputSurface::c reate(adoptPtr(new FakeWebGraphicsContext3DMakeCurrentFailsEventually(kMakeCurre ntSuccessesNeededForSuccessfulInitialization))).PassAs<CCGraphicsContext>()));
2415 EXPECT_TRUE(m_hostImpl->context());
2416 EXPECT_TRUE(m_hostImpl->renderer());
2417 EXPECT_TRUE(m_hostImpl->resourceProvider());
2418 }
2419
2420 // Fake WebGraphicsContext3D that will cause a failure if trying to use a
2421 // resource that wasn't created by it (resources created by
2422 // FakeWebGraphicsContext3D have an id of 1).
2423 class StrictWebGraphicsContext3D : public FakeWebGraphicsContext3D {
2424 public:
2425 StrictWebGraphicsContext3D()
2426 : FakeWebGraphicsContext3D()
2427 {
2428 m_nextTextureId = 7; // Start allocating texture ids larger than any oth er resource IDs so we can tell if someone's mixing up their resource types.
2429 }
2430
2431 virtual WebGLId createBuffer() { return 2; }
2432 virtual WebGLId createFramebuffer() { return 3; }
2433 virtual WebGLId createProgram() { return 4; }
2434 virtual WebGLId createRenderbuffer() { return 5; }
2435 virtual WebGLId createShader(WGC3Denum) { return 6; }
2436
2437 virtual void deleteBuffer(WebGLId id)
2438 {
2439 if (id != 2)
2440 ADD_FAILURE() << "Trying to delete buffer id " << id;
2441 }
2442
2443 virtual void deleteFramebuffer(WebGLId id)
2444 {
2445 if (id != 3)
2446 ADD_FAILURE() << "Trying to delete framebuffer id " << id;
2447 }
2448
2449 virtual void deleteProgram(WebGLId id)
2450 {
2451 if (id != 4)
2452 ADD_FAILURE() << "Trying to delete program id " << id;
2453 }
2454
2455 virtual void deleteRenderbuffer(WebGLId id)
2456 {
2457 if (id != 5)
2458 ADD_FAILURE() << "Trying to delete renderbuffer id " << id;
2459 }
2460
2461 virtual void deleteShader(WebGLId id)
2462 {
2463 if (id != 6)
2464 ADD_FAILURE() << "Trying to delete shader id " << id;
2465 }
2466
2467 virtual WebGLId createTexture()
2468 {
2469 unsigned textureId = FakeWebGraphicsContext3D::createTexture();
2470 m_allocatedTextureIds.insert(textureId);
2471 return textureId;
2472 }
2473 virtual void deleteTexture(WebGLId id)
2474 {
2475 if (!ContainsKey(m_allocatedTextureIds, id))
2476 ADD_FAILURE() << "Trying to delete texture id " << id;
2477 m_allocatedTextureIds.erase(id);
2478 }
2479
2480 virtual void bindBuffer(WGC3Denum, WebGLId id)
2481 {
2482 if (id != 2 && id)
2483 ADD_FAILURE() << "Trying to bind buffer id " << id;
2484 }
2485
2486 virtual void bindFramebuffer(WGC3Denum, WebGLId id)
2487 {
2488 if (id != 3 && id)
2489 ADD_FAILURE() << "Trying to bind framebuffer id " << id;
2490 }
2491
2492 virtual void useProgram(WebGLId id)
2493 {
2494 if (id != 4)
2495 ADD_FAILURE() << "Trying to use program id " << id;
2496 }
2497
2498 virtual void bindRenderbuffer(WGC3Denum, WebGLId id)
2499 {
2500 if (id != 5 && id)
2501 ADD_FAILURE() << "Trying to bind renderbuffer id " << id;
2502 }
2503
2504 virtual void attachShader(WebGLId program, WebGLId shader)
2505 {
2506 if ((program != 4) || (shader != 6))
2507 ADD_FAILURE() << "Trying to attach shader id " << shader << " to pro gram id " << program;
2508 }
2509
2510 virtual void bindTexture(WGC3Denum, WebGLId id)
2511 {
2512 if (id && !ContainsKey(m_allocatedTextureIds, id))
2513 ADD_FAILURE() << "Trying to bind texture id " << id;
2514 }
2515
2516 private:
2517 base::hash_set<unsigned> m_allocatedTextureIds;
2518 };
2519
2520 // Fake video frame that represents a 4x4 YUV video frame.
2521 class FakeVideoFrame: public WebVideoFrame {
2522 public:
2523 FakeVideoFrame() : m_textureId(0) { memset(m_data, 0x80, sizeof(m_data)); }
2524 virtual ~FakeVideoFrame() { }
2525 virtual Format format() const { return m_textureId ? FormatNativeTexture : F ormatYV12; }
2526 virtual unsigned width() const { return 4; }
2527 virtual unsigned height() const { return 4; }
2528 virtual unsigned planes() const { return 3; }
2529 virtual int stride(unsigned plane) const { return 4; }
2530 virtual const void* data(unsigned plane) const { return m_data; }
2531 virtual unsigned textureId() const { return m_textureId; }
2532 virtual unsigned textureTarget() const { return m_textureId ? GraphicsContex t3D::TEXTURE_2D : 0; }
2533
2534 void setTextureId(unsigned id) { m_textureId = id; }
2535
2536 private:
2537 char m_data[16];
2538 unsigned m_textureId;
2539 };
2540
2541 // Fake video frame provider that always provides the same FakeVideoFrame.
2542 class FakeVideoFrameProvider: public WebVideoFrameProvider {
2543 public:
2544 FakeVideoFrameProvider() : m_frame(0), m_client(0) { }
2545 virtual ~FakeVideoFrameProvider()
2546 {
2547 if (m_client)
2548 m_client->stopUsingProvider();
2549 }
2550
2551 virtual void setVideoFrameProviderClient(Client* client) { m_client = client ; }
2552 virtual WebVideoFrame* getCurrentFrame() { return m_frame; }
2553 virtual void putCurrentFrame(WebVideoFrame*) { }
2554
2555 void setFrame(WebVideoFrame* frame) { m_frame = frame; }
2556
2557 private:
2558 WebVideoFrame* m_frame;
2559 Client* m_client;
2560 };
2561
2562 class StrictWebGraphicsContext3DWithIOSurface : public StrictWebGraphicsContext3 D {
2563 public:
2564 virtual WebString getString(WGC3Denum name) OVERRIDE
2565 {
2566 if (name == cc::GraphicsContext3D::EXTENSIONS)
2567 return WebString("GL_CHROMIUM_iosurface GL_ARB_texture_rectangle");
2568
2569 return WebString();
2570 }
2571 };
2572
2573 class FakeWebGraphicsContext3DWithIOSurface : public FakeWebGraphicsContext3D {
2574 public:
2575 virtual WebString getString(WGC3Denum name) OVERRIDE
2576 {
2577 if (name == cc::GraphicsContext3D::EXTENSIONS)
2578 return WebString("GL_CHROMIUM_iosurface GL_ARB_texture_rectangle");
2579
2580 return WebString();
2581 }
2582 };
2583
2584 class FakeWebScrollbarThemeGeometryNonEmpty : public FakeWebScrollbarThemeGeomet ry {
2585 virtual WebRect trackRect(WebScrollbar*) OVERRIDE { return WebRect(0, 0, 10, 10); }
2586 virtual WebRect thumbRect(WebScrollbar*) OVERRIDE { return WebRect(0, 5, 5, 2); }
2587 virtual void splitTrack(WebScrollbar*, const WebRect& track, WebRect& startT rack, WebRect& thumb, WebRect& endTrack) OVERRIDE
2588 {
2589 thumb = WebRect(0, 5, 5, 2);
2590 startTrack = WebRect(0, 5, 0, 5);
2591 endTrack = WebRect(0, 0, 0, 5);
2592 }
2593 };
2594
2595 class FakeScrollbarLayerImpl : public CCScrollbarLayerImpl {
2596 public:
2597 static scoped_ptr<FakeScrollbarLayerImpl> create(int id)
2598 {
2599 return make_scoped_ptr(new FakeScrollbarLayerImpl(id));
2600 }
2601
2602 void createResources(CCResourceProvider* provider)
2603 {
2604 ASSERT(provider);
2605 int pool = 0;
2606 IntSize size(10, 10);
2607 GC3Denum format = GraphicsContext3D::RGBA;
2608 CCResourceProvider::TextureUsageHint hint = CCResourceProvider::TextureU sageAny;
2609 setScrollbarGeometry(CCScrollbarGeometryFixedThumb::create(FakeWebScroll barThemeGeometryNonEmpty::create()));
2610
2611 setBackTrackResourceId(provider->createResource(pool, size, format, hint ));
2612 setForeTrackResourceId(provider->createResource(pool, size, format, hint ));
2613 setThumbResourceId(provider->createResource(pool, size, format, hint));
2614 }
2615
2616 protected:
2617 explicit FakeScrollbarLayerImpl(int id)
2618 : CCScrollbarLayerImpl(id)
2619 {
2620 }
2621 };
2622
2623 static inline scoped_ptr<CCRenderPass> createRenderPassWithResource(CCResourcePr ovider* provider)
2624 {
2625 CCResourceProvider::ResourceId resourceId = provider->createResource(0, IntS ize(1, 1), GraphicsContext3D::RGBA, CCResourceProvider::TextureUsageAny);
2626
2627 scoped_ptr<CCRenderPass> pass = CCRenderPass::create(CCRenderPass::Id(1, 1), IntRect(0, 0, 1, 1), WebTransformationMatrix());
2628 scoped_ptr<CCSharedQuadState> sharedState = CCSharedQuadState::create(WebTra nsformationMatrix(), IntRect(0, 0, 1, 1), IntRect(0, 0, 1, 1), 1, false);
2629 scoped_ptr<CCTextureDrawQuad> quad = CCTextureDrawQuad::create(sharedState.g et(), IntRect(0, 0, 1, 1), resourceId, false, FloatRect(0, 0, 1, 1), false);
2630
2631 static_cast<CCTestRenderPass*>(pass.get())->appendSharedQuadState(sharedStat e.Pass());
2632 static_cast<CCTestRenderPass*>(pass.get())->appendQuad(quad.PassAs<CCDrawQua d>());
2633
2634 return pass.Pass();
2635 }
2636
2637 TEST_P(CCLayerTreeHostImplTest, dontUseOldResourcesAfterLostContext)
2638 {
2639 int layerId = 1;
2640
2641 scoped_ptr<CCLayerImpl> rootLayer(CCLayerImpl::create(layerId++));
2642 rootLayer->setBounds(IntSize(10, 10));
2643 rootLayer->setAnchorPoint(FloatPoint(0, 0));
2644
2645 scoped_ptr<CCTiledLayerImpl> tileLayer = CCTiledLayerImpl::create(layerId++) ;
2646 tileLayer->setBounds(IntSize(10, 10));
2647 tileLayer->setAnchorPoint(FloatPoint(0, 0));
2648 tileLayer->setContentBounds(IntSize(10, 10));
2649 tileLayer->setDrawsContent(true);
2650 tileLayer->setSkipsDraw(false);
2651 OwnPtr<CCLayerTilingData> tilingData(CCLayerTilingData::create(IntSize(10, 1 0), CCLayerTilingData::NoBorderTexels));
2652 tilingData->setBounds(IntSize(10, 10));
2653 tileLayer->setTilingData(*tilingData);
2654 tileLayer->pushTileProperties(0, 0, 1, IntRect(0, 0, 10, 10));
2655 rootLayer->addChild(tileLayer.PassAs<CCLayerImpl>());
2656
2657 scoped_ptr<CCTextureLayerImpl> textureLayer = CCTextureLayerImpl::create(lay erId++);
2658 textureLayer->setBounds(IntSize(10, 10));
2659 textureLayer->setAnchorPoint(FloatPoint(0, 0));
2660 textureLayer->setContentBounds(IntSize(10, 10));
2661 textureLayer->setDrawsContent(true);
2662 textureLayer->setTextureId(1);
2663 rootLayer->addChild(textureLayer.PassAs<CCLayerImpl>());
2664
2665 scoped_ptr<CCTiledLayerImpl> maskLayer = CCTiledLayerImpl::create(layerId++) ;
2666 maskLayer->setBounds(IntSize(10, 10));
2667 maskLayer->setAnchorPoint(FloatPoint(0, 0));
2668 maskLayer->setContentBounds(IntSize(10, 10));
2669 maskLayer->setDrawsContent(true);
2670 maskLayer->setSkipsDraw(false);
2671 maskLayer->setTilingData(*tilingData);
2672 maskLayer->pushTileProperties(0, 0, 1, IntRect(0, 0, 10, 10));
2673
2674 scoped_ptr<CCTextureLayerImpl> textureLayerWithMask = CCTextureLayerImpl::cr eate(layerId++);
2675 textureLayerWithMask->setBounds(IntSize(10, 10));
2676 textureLayerWithMask->setAnchorPoint(FloatPoint(0, 0));
2677 textureLayerWithMask->setContentBounds(IntSize(10, 10));
2678 textureLayerWithMask->setDrawsContent(true);
2679 textureLayerWithMask->setTextureId(1);
2680 textureLayerWithMask->setMaskLayer(maskLayer.PassAs<CCLayerImpl>());
2681 rootLayer->addChild(textureLayerWithMask.PassAs<CCLayerImpl>());
2682
2683 FakeVideoFrame videoFrame;
2684 FakeVideoFrameProvider provider;
2685 provider.setFrame(&videoFrame);
2686 scoped_ptr<CCVideoLayerImpl> videoLayer = CCVideoLayerImpl::create(layerId++ , &provider);
2687 videoLayer->setBounds(IntSize(10, 10));
2688 videoLayer->setAnchorPoint(FloatPoint(0, 0));
2689 videoLayer->setContentBounds(IntSize(10, 10));
2690 videoLayer->setDrawsContent(true);
2691 videoLayer->setLayerTreeHostImpl(m_hostImpl.get());
2692 rootLayer->addChild(videoLayer.PassAs<CCLayerImpl>());
2693
2694 FakeVideoFrame hwVideoFrame;
2695 FakeVideoFrameProvider hwProvider;
2696 hwProvider.setFrame(&hwVideoFrame);
2697 scoped_ptr<CCVideoLayerImpl> hwVideoLayer = CCVideoLayerImpl::create(layerId ++, &hwProvider);
2698 hwVideoLayer->setBounds(IntSize(10, 10));
2699 hwVideoLayer->setAnchorPoint(FloatPoint(0, 0));
2700 hwVideoLayer->setContentBounds(IntSize(10, 10));
2701 hwVideoLayer->setDrawsContent(true);
2702 hwVideoLayer->setLayerTreeHostImpl(m_hostImpl.get());
2703 rootLayer->addChild(hwVideoLayer.PassAs<CCLayerImpl>());
2704
2705 scoped_ptr<CCIOSurfaceLayerImpl> ioSurfaceLayer = CCIOSurfaceLayerImpl::crea te(layerId++);
2706 ioSurfaceLayer->setBounds(IntSize(10, 10));
2707 ioSurfaceLayer->setAnchorPoint(FloatPoint(0, 0));
2708 ioSurfaceLayer->setContentBounds(IntSize(10, 10));
2709 ioSurfaceLayer->setDrawsContent(true);
2710 ioSurfaceLayer->setIOSurfaceProperties(1, IntSize(10, 10));
2711 ioSurfaceLayer->setLayerTreeHostImpl(m_hostImpl.get());
2712 rootLayer->addChild(ioSurfaceLayer.PassAs<CCLayerImpl>());
2713
2714 scoped_ptr<CCHeadsUpDisplayLayerImpl> hudLayer = CCHeadsUpDisplayLayerImpl:: create(layerId++);
2715 hudLayer->setBounds(IntSize(10, 10));
2716 hudLayer->setAnchorPoint(FloatPoint(0, 0));
2717 hudLayer->setContentBounds(IntSize(10, 10));
2718 hudLayer->setDrawsContent(true);
2719 hudLayer->setLayerTreeHostImpl(m_hostImpl.get());
2720 rootLayer->addChild(hudLayer.PassAs<CCLayerImpl>());
2721
2722 scoped_ptr<FakeScrollbarLayerImpl> scrollbarLayer(FakeScrollbarLayerImpl::cr eate(layerId++));
2723 scrollbarLayer->setBounds(IntSize(10, 10));
2724 scrollbarLayer->setContentBounds(IntSize(10, 10));
2725 scrollbarLayer->setDrawsContent(true);
2726 scrollbarLayer->setLayerTreeHostImpl(m_hostImpl.get());
2727 scrollbarLayer->createResources(m_hostImpl->resourceProvider());
2728 rootLayer->addChild(scrollbarLayer.PassAs<CCLayerImpl>());
2729
2730 scoped_ptr<CCDelegatedRendererLayerImpl> delegatedRendererLayer(CCDelegatedR endererLayerImpl::create(layerId++));
2731 delegatedRendererLayer->setBounds(IntSize(10, 10));
2732 delegatedRendererLayer->setContentBounds(IntSize(10, 10));
2733 delegatedRendererLayer->setDrawsContent(true);
2734 delegatedRendererLayer->setLayerTreeHostImpl(m_hostImpl.get());
2735 ScopedPtrVector<CCRenderPass> passList;
2736 passList.append(createRenderPassWithResource(m_hostImpl->resourceProvider()) );
2737 delegatedRendererLayer->setRenderPasses(passList);
2738 EXPECT_TRUE(passList.isEmpty());
2739 rootLayer->addChild(delegatedRendererLayer.PassAs<CCLayerImpl>());
2740
2741 // Use a context that supports IOSurfaces
2742 m_hostImpl->initializeRenderer(FakeWebCompositorOutputSurface::create(adoptP tr(new FakeWebGraphicsContext3DWithIOSurface)).PassAs<CCGraphicsContext>());
2743
2744 hwVideoFrame.setTextureId(m_hostImpl->resourceProvider()->graphicsContext3D( )->createTexture());
2745
2746 m_hostImpl->setRootLayer(rootLayer.Pass());
2747
2748 CCLayerTreeHostImpl::FrameData frame;
2749 EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
2750 m_hostImpl->drawLayers(frame);
2751 m_hostImpl->didDrawAllLayers(frame);
2752 m_hostImpl->swapBuffers();
2753
2754 unsigned numResources = m_hostImpl->resourceProvider()->numResources();
2755
2756 // Lose the context, replacing it with a StrictWebGraphicsContext3DWithIOSur face,
2757 // that will warn if any resource from the previous context gets used.
2758 m_hostImpl->initializeRenderer(FakeWebCompositorOutputSurface::create(adoptP tr(new StrictWebGraphicsContext3DWithIOSurface)).PassAs<CCGraphicsContext>());
2759
2760 // Create dummy resources so that looking up an old resource will get an
2761 // invalid texture id mapping.
2762 for (unsigned i = 0; i < numResources; ++i)
2763 m_hostImpl->resourceProvider()->createResourceFromExternalTexture(1);
2764
2765 // The WebVideoFrameProvider is expected to recreate its textures after a
2766 // lost context (or not serve a frame).
2767 hwProvider.setFrame(0);
2768
2769 EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
2770 m_hostImpl->drawLayers(frame);
2771 m_hostImpl->didDrawAllLayers(frame);
2772 m_hostImpl->swapBuffers();
2773
2774 hwVideoFrame.setTextureId(m_hostImpl->resourceProvider()->graphicsContext3D( )->createTexture());
2775 hwProvider.setFrame(&hwVideoFrame);
2776
2777 EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
2778 m_hostImpl->drawLayers(frame);
2779 m_hostImpl->didDrawAllLayers(frame);
2780 m_hostImpl->swapBuffers();
2781 }
2782
2783 // Fake WebGraphicsContext3D that tracks the number of textures in use.
2784 class TrackingWebGraphicsContext3D : public FakeWebGraphicsContext3D {
2785 public:
2786 TrackingWebGraphicsContext3D()
2787 : FakeWebGraphicsContext3D()
2788 , m_numTextures(0)
2789 { }
2790
2791 virtual WebGLId createTexture() OVERRIDE
2792 {
2793 WebGLId id = FakeWebGraphicsContext3D::createTexture();
2794
2795 m_textures.set(id, true);
2796 ++m_numTextures;
2797 return id;
2798 }
2799
2800 virtual void deleteTexture(WebGLId id) OVERRIDE
2801 {
2802 if (!m_textures.get(id))
2803 return;
2804
2805 m_textures.set(id, false);
2806 --m_numTextures;
2807 }
2808
2809 virtual WebString getString(WGC3Denum name) OVERRIDE
2810 {
2811 if (name == cc::GraphicsContext3D::EXTENSIONS)
2812 return WebString("GL_CHROMIUM_iosurface GL_ARB_texture_rectangle");
2813
2814 return WebString();
2815 }
2816
2817 unsigned numTextures() const { return m_numTextures; }
2818
2819 private:
2820 HashMap<WebGLId, bool> m_textures;
2821 unsigned m_numTextures;
2822 };
2823
2824 TEST_P(CCLayerTreeHostImplTest, layersFreeTextures)
2825 {
2826 scoped_ptr<CCLayerImpl> rootLayer(CCLayerImpl::create(1));
2827 rootLayer->setBounds(IntSize(10, 10));
2828 rootLayer->setAnchorPoint(FloatPoint(0, 0));
2829
2830 scoped_ptr<CCTiledLayerImpl> tileLayer = CCTiledLayerImpl::create(2);
2831 tileLayer->setBounds(IntSize(10, 10));
2832 tileLayer->setAnchorPoint(FloatPoint(0, 0));
2833 tileLayer->setContentBounds(IntSize(10, 10));
2834 tileLayer->setDrawsContent(true);
2835 tileLayer->setSkipsDraw(false);
2836 OwnPtr<CCLayerTilingData> tilingData(CCLayerTilingData::create(IntSize(10, 1 0), CCLayerTilingData::NoBorderTexels));
2837 tilingData->setBounds(IntSize(10, 10));
2838 tileLayer->setTilingData(*tilingData);
2839 tileLayer->pushTileProperties(0, 0, 1, IntRect(0, 0, 10, 10));
2840 rootLayer->addChild(tileLayer.PassAs<CCLayerImpl>());
2841
2842 scoped_ptr<CCTextureLayerImpl> textureLayer = CCTextureLayerImpl::create(3);
2843 textureLayer->setBounds(IntSize(10, 10));
2844 textureLayer->setAnchorPoint(FloatPoint(0, 0));
2845 textureLayer->setContentBounds(IntSize(10, 10));
2846 textureLayer->setDrawsContent(true);
2847 textureLayer->setTextureId(1);
2848 rootLayer->addChild(textureLayer.PassAs<CCLayerImpl>());
2849
2850 FakeVideoFrameProvider provider;
2851 scoped_ptr<CCVideoLayerImpl> videoLayer = CCVideoLayerImpl::create(4, &provi der);
2852 videoLayer->setBounds(IntSize(10, 10));
2853 videoLayer->setAnchorPoint(FloatPoint(0, 0));
2854 videoLayer->setContentBounds(IntSize(10, 10));
2855 videoLayer->setDrawsContent(true);
2856 videoLayer->setLayerTreeHostImpl(m_hostImpl.get());
2857 rootLayer->addChild(videoLayer.PassAs<CCLayerImpl>());
2858
2859 scoped_ptr<CCIOSurfaceLayerImpl> ioSurfaceLayer = CCIOSurfaceLayerImpl::crea te(5);
2860 ioSurfaceLayer->setBounds(IntSize(10, 10));
2861 ioSurfaceLayer->setAnchorPoint(FloatPoint(0, 0));
2862 ioSurfaceLayer->setContentBounds(IntSize(10, 10));
2863 ioSurfaceLayer->setDrawsContent(true);
2864 ioSurfaceLayer->setIOSurfaceProperties(1, IntSize(10, 10));
2865 ioSurfaceLayer->setLayerTreeHostImpl(m_hostImpl.get());
2866 rootLayer->addChild(ioSurfaceLayer.PassAs<CCLayerImpl>());
2867
2868 // Lose the context, replacing it with a TrackingWebGraphicsContext3D (which the CCLayerTreeHostImpl takes ownership of).
2869 scoped_ptr<CCGraphicsContext> ccContext(FakeWebCompositorOutputSurface::crea te(adoptPtr(new TrackingWebGraphicsContext3D)));
2870 TrackingWebGraphicsContext3D* trackingWebGraphicsContext = static_cast<Track ingWebGraphicsContext3D*>(ccContext->context3D());
2871 m_hostImpl->initializeRenderer(ccContext.Pass());
2872
2873 m_hostImpl->setRootLayer(rootLayer.Pass());
2874
2875 CCLayerTreeHostImpl::FrameData frame;
2876 EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
2877 m_hostImpl->drawLayers(frame);
2878 m_hostImpl->didDrawAllLayers(frame);
2879 m_hostImpl->swapBuffers();
2880
2881 EXPECT_GT(trackingWebGraphicsContext->numTextures(), 0u);
2882
2883 // Kill the layer tree.
2884 m_hostImpl->setRootLayer(CCLayerImpl::create(100));
2885 // There should be no textures left in use after.
2886 EXPECT_EQ(0u, trackingWebGraphicsContext->numTextures());
2887 }
2888
2889 class MockDrawQuadsToFillScreenContext : public FakeWebGraphicsContext3D {
2890 public:
2891 MOCK_METHOD1(useProgram, void(WebGLId program));
2892 MOCK_METHOD4(drawElements, void(WGC3Denum mode, WGC3Dsizei count, WGC3Denum type, WGC3Dintptr offset));
2893 };
2894
2895 TEST_P(CCLayerTreeHostImplTest, hasTransparentBackground)
2896 {
2897 scoped_ptr<CCGraphicsContext> context = FakeWebCompositorOutputSurface::crea te(adoptPtr(new MockDrawQuadsToFillScreenContext)).PassAs<CCGraphicsContext>();
2898 MockDrawQuadsToFillScreenContext* mockContext = static_cast<MockDrawQuadsToF illScreenContext*>(context->context3D());
2899
2900 // Run test case
2901 scoped_ptr<CCLayerTreeHostImpl> myHostImpl = createLayerTreeHost(false, cont ext.Pass(), CCLayerImpl::create(1));
2902 myHostImpl->setBackgroundColor(SK_ColorWHITE);
2903
2904 // Verify one quad is drawn when transparent background set is not set.
2905 myHostImpl->setHasTransparentBackground(false);
2906 EXPECT_CALL(*mockContext, useProgram(_))
2907 .Times(1);
2908 EXPECT_CALL(*mockContext, drawElements(_, _, _, _))
2909 .Times(1);
2910 CCLayerTreeHostImpl::FrameData frame;
2911 EXPECT_TRUE(myHostImpl->prepareToDraw(frame));
2912 myHostImpl->drawLayers(frame);
2913 myHostImpl->didDrawAllLayers(frame);
2914 Mock::VerifyAndClearExpectations(&mockContext);
2915
2916 // Verify no quads are drawn when transparent background is set.
2917 myHostImpl->setHasTransparentBackground(true);
2918 EXPECT_TRUE(myHostImpl->prepareToDraw(frame));
2919 myHostImpl->drawLayers(frame);
2920 myHostImpl->didDrawAllLayers(frame);
2921 Mock::VerifyAndClearExpectations(&mockContext);
2922 }
2923
2924 static void addDrawingLayerTo(CCLayerImpl* parent, int id, const IntRect& layerR ect, CCLayerImpl** result)
2925 {
2926 scoped_ptr<CCLayerImpl> layer = FakeLayerWithQuads::create(id);
2927 CCLayerImpl* layerPtr = layer.get();
2928 layerPtr->setAnchorPoint(FloatPoint(0, 0));
2929 layerPtr->setPosition(FloatPoint(layerRect.location()));
2930 layerPtr->setBounds(layerRect.size());
2931 layerPtr->setContentBounds(layerRect.size());
2932 layerPtr->setDrawsContent(true); // only children draw content
2933 layerPtr->setContentsOpaque(true);
2934 parent->addChild(layer.Pass());
2935 if (result)
2936 *result = layerPtr;
2937 }
2938
2939 static void setupLayersForTextureCaching(CCLayerTreeHostImpl* layerTreeHostImpl, CCLayerImpl*& rootPtr, CCLayerImpl*& intermediateLayerPtr, CCLayerImpl*& surfac eLayerPtr, CCLayerImpl*& childPtr, const IntSize& rootSize)
2940 {
2941 scoped_ptr<CCGraphicsContext> context = FakeWebCompositorOutputSurface::crea te(adoptPtr(new PartialSwapContext)).PassAs<CCGraphicsContext>();
2942
2943 layerTreeHostImpl->initializeRenderer(context.Pass());
2944 layerTreeHostImpl->setViewportSize(rootSize, rootSize);
2945
2946 scoped_ptr<CCLayerImpl> root = CCLayerImpl::create(1);
2947 rootPtr = root.get();
2948
2949 root->setAnchorPoint(FloatPoint(0, 0));
2950 root->setPosition(FloatPoint(0, 0));
2951 root->setBounds(rootSize);
2952 root->setContentBounds(rootSize);
2953 root->setDrawsContent(true);
2954 layerTreeHostImpl->setRootLayer(root.Pass());
2955
2956 addDrawingLayerTo(rootPtr, 2, IntRect(10, 10, rootSize.width(), rootSize.hei ght()), &intermediateLayerPtr);
2957 intermediateLayerPtr->setDrawsContent(false); // only children draw content
2958
2959 // Surface layer is the layer that changes its opacity
2960 // It will contain other layers that draw content.
2961 addDrawingLayerTo(intermediateLayerPtr, 3, IntRect(10, 10, rootSize.width(), rootSize.height()), &surfaceLayerPtr);
2962 surfaceLayerPtr->setDrawsContent(false); // only children draw content
2963 surfaceLayerPtr->setOpacity(0.5f); // This will cause it to have a surface
2964
2965 // Child of the surface layer will produce some quads
2966 addDrawingLayerTo(surfaceLayerPtr, 4, IntRect(5, 5, rootSize.width() - 25, r ootSize.height() - 25), &childPtr);
2967 }
2968
2969 class CCRendererGLWithReleaseTextures : public CCRendererGL {
2970 public:
2971 using CCRendererGL::releaseRenderPassTextures;
2972 };
2973
2974 TEST_P(CCLayerTreeHostImplTest, textureCachingWithClipping)
2975 {
2976 CCSettings::setPartialSwapEnabled(true);
2977
2978 CCLayerTreeSettings settings;
2979 settings.minimumOcclusionTrackingSize = IntSize();
2980 scoped_ptr<CCLayerTreeHostImpl> myHostImpl = CCLayerTreeHostImpl::create(set tings, this);
2981
2982 CCLayerImpl* rootPtr;
2983 CCLayerImpl* surfaceLayerPtr;
2984
2985 scoped_ptr<CCGraphicsContext> context = FakeWebCompositorOutputSurface::crea te(adoptPtr(new PartialSwapContext)).PassAs<CCGraphicsContext>();
2986
2987 IntSize rootSize(100, 100);
2988
2989 myHostImpl->initializeRenderer(context.Pass());
2990 myHostImpl->setViewportSize(IntSize(rootSize.width(), rootSize.height()), In tSize(rootSize.width(), rootSize.height()));
2991
2992 scoped_ptr<CCLayerImpl> root = CCLayerImpl::create(1);
2993 rootPtr = root.get();
2994
2995 root->setAnchorPoint(FloatPoint(0, 0));
2996 root->setPosition(FloatPoint(0, 0));
2997 root->setBounds(rootSize);
2998 root->setContentBounds(rootSize);
2999 root->setDrawsContent(true);
3000 root->setMasksToBounds(true);
3001 myHostImpl->setRootLayer(root.Pass());
3002
3003 addDrawingLayerTo(rootPtr, 3, IntRect(0, 0, rootSize.width(), rootSize.heigh t()), &surfaceLayerPtr);
3004 surfaceLayerPtr->setDrawsContent(false);
3005
3006 // Surface layer is the layer that changes its opacity
3007 // It will contain other layers that draw content.
3008 surfaceLayerPtr->setOpacity(0.5f); // This will cause it to have a surface
3009
3010 addDrawingLayerTo(surfaceLayerPtr, 4, IntRect(0, 0, 100, 3), 0);
3011 addDrawingLayerTo(surfaceLayerPtr, 5, IntRect(0, 97, 100, 3), 0);
3012
3013 // Rotation will put part of the child ouside the bounds of the root layer.
3014 // Nevertheless, the child layers should be drawn.
3015 WebTransformationMatrix transform = surfaceLayerPtr->transform();
3016 transform.translate(50, 50);
3017 transform.rotate(35);
3018 transform.translate(-50, -50);
3019 surfaceLayerPtr->setTransform(transform);
3020
3021 {
3022 CCLayerTreeHostImpl::FrameData frame;
3023 EXPECT_TRUE(myHostImpl->prepareToDraw(frame));
3024
3025 // Must receive two render passes, each with one quad
3026 ASSERT_EQ(2U, frame.renderPasses.size());
3027 EXPECT_EQ(2U, frame.renderPasses[0]->quadList().size());
3028 ASSERT_EQ(1U, frame.renderPasses[1]->quadList().size());
3029
3030 // Verify that the child layers are being clipped.
3031 IntRect quadVisibleRect = frame.renderPasses[0]->quadList()[0]->quadVisi bleRect();
3032 EXPECT_LT(quadVisibleRect.width(), 100);
3033
3034 quadVisibleRect = frame.renderPasses[0]->quadList()[1]->quadVisibleRect( );
3035 EXPECT_LT(quadVisibleRect.width(), 100);
3036
3037 // Verify that the render surface texture is *not* clipped.
3038 EXPECT_RECT_EQ(IntRect(0, 0, 100, 100), frame.renderPasses[0]->outputRec t());
3039
3040 EXPECT_EQ(CCDrawQuad::RenderPass, frame.renderPasses[1]->quadList()[0]-> material());
3041 CCRenderPassDrawQuad* quad = static_cast<CCRenderPassDrawQuad*>(frame.re nderPasses[1]->quadList()[0]);
3042 EXPECT_FALSE(quad->contentsChangedSinceLastFrame().isEmpty());
3043
3044 myHostImpl->drawLayers(frame);
3045 myHostImpl->didDrawAllLayers(frame);
3046 }
3047
3048 transform = surfaceLayerPtr->transform();
3049 transform.translate(50, 50);
3050 transform.rotate(-35);
3051 transform.translate(-50, -50);
3052 surfaceLayerPtr->setTransform(transform);
3053
3054 // The surface is now aligned again, and the clipped parts are exposed.
3055 // Since the layers were clipped, even though the render surface size
3056 // was not changed, the texture should not be saved.
3057 {
3058 CCLayerTreeHostImpl::FrameData frame;
3059 EXPECT_TRUE(myHostImpl->prepareToDraw(frame));
3060
3061 // Must receive two render passes, each with one quad
3062 ASSERT_EQ(2U, frame.renderPasses.size());
3063 EXPECT_EQ(2U, frame.renderPasses[0]->quadList().size());
3064 ASSERT_EQ(1U, frame.renderPasses[1]->quadList().size());
3065
3066 myHostImpl->drawLayers(frame);
3067 myHostImpl->didDrawAllLayers(frame);
3068 }
3069 }
3070
3071 TEST_P(CCLayerTreeHostImplTest, textureCachingWithOcclusion)
3072 {
3073 CCSettings::setPartialSwapEnabled(false);
3074
3075 CCLayerTreeSettings settings;
3076 settings.minimumOcclusionTrackingSize = IntSize();
3077 scoped_ptr<CCLayerTreeHostImpl> myHostImpl = CCLayerTreeHostImpl::create(set tings, this);
3078
3079 // Layers are structure as follows:
3080 //
3081 // R +-- S1 +- L10 (owning)
3082 // | +- L11
3083 // | +- L12
3084 // |
3085 // +-- S2 +- L20 (owning)
3086 // +- L21
3087 //
3088 // Occlusion:
3089 // L12 occludes L11 (internal)
3090 // L20 occludes L10 (external)
3091 // L21 occludes L20 (internal)
3092
3093 CCLayerImpl* rootPtr;
3094 CCLayerImpl* layerS1Ptr;
3095 CCLayerImpl* layerS2Ptr;
3096
3097 scoped_ptr<CCGraphicsContext> context = FakeWebCompositorOutputSurface::crea te(adoptPtr(new PartialSwapContext)).PassAs<CCGraphicsContext>();
3098
3099 IntSize rootSize(1000, 1000);
3100
3101 myHostImpl->initializeRenderer(context.Pass());
3102 myHostImpl->setViewportSize(IntSize(rootSize.width(), rootSize.height()), In tSize(rootSize.width(), rootSize.height()));
3103
3104 scoped_ptr<CCLayerImpl> root = CCLayerImpl::create(1);
3105 rootPtr = root.get();
3106
3107 root->setAnchorPoint(FloatPoint(0, 0));
3108 root->setPosition(FloatPoint(0, 0));
3109 root->setBounds(rootSize);
3110 root->setContentBounds(rootSize);
3111 root->setDrawsContent(true);
3112 root->setMasksToBounds(true);
3113 myHostImpl->setRootLayer(root.Pass());
3114
3115 addDrawingLayerTo(rootPtr, 2, IntRect(300, 300, 300, 300), &layerS1Ptr);
3116 layerS1Ptr->setForceRenderSurface(true);
3117
3118 addDrawingLayerTo(layerS1Ptr, 3, IntRect(10, 10, 10, 10), 0); // L11
3119 addDrawingLayerTo(layerS1Ptr, 4, IntRect(0, 0, 30, 30), 0); // L12
3120
3121 addDrawingLayerTo(rootPtr, 5, IntRect(550, 250, 300, 400), &layerS2Ptr);
3122 layerS2Ptr->setForceRenderSurface(true);
3123
3124 addDrawingLayerTo(layerS2Ptr, 6, IntRect(20, 20, 5, 5), 0); // L21
3125
3126 // Initial draw - must receive all quads
3127 {
3128 CCLayerTreeHostImpl::FrameData frame;
3129 EXPECT_TRUE(myHostImpl->prepareToDraw(frame));
3130
3131 // Must receive 3 render passes.
3132 // For Root, there are 2 quads; for S1, there are 2 quads (1 is occluded ); for S2, there is 2 quads.
3133 ASSERT_EQ(3U, frame.renderPasses.size());
3134
3135 EXPECT_EQ(2U, frame.renderPasses[0]->quadList().size());
3136 EXPECT_EQ(2U, frame.renderPasses[1]->quadList().size());
3137 EXPECT_EQ(2U, frame.renderPasses[2]->quadList().size());
3138
3139 myHostImpl->drawLayers(frame);
3140 myHostImpl->didDrawAllLayers(frame);
3141 }
3142
3143 // "Unocclude" surface S1 and repeat draw.
3144 // Must remove S2's render pass since it's cached;
3145 // Must keep S1 quads because texture contained external occlusion.
3146 WebTransformationMatrix transform = layerS2Ptr->transform();
3147 transform.translate(150, 150);
3148 layerS2Ptr->setTransform(transform);
3149 {
3150 CCLayerTreeHostImpl::FrameData frame;
3151 EXPECT_TRUE(myHostImpl->prepareToDraw(frame));
3152
3153 // Must receive 2 render passes.
3154 // For Root, there are 2 quads
3155 // For S1, the number of quads depends on what got unoccluded, so not as serted beyond being positive.
3156 // For S2, there is no render pass
3157 ASSERT_EQ(2U, frame.renderPasses.size());
3158
3159 EXPECT_GT(frame.renderPasses[0]->quadList().size(), 0U);
3160 EXPECT_EQ(2U, frame.renderPasses[1]->quadList().size());
3161
3162 myHostImpl->drawLayers(frame);
3163 myHostImpl->didDrawAllLayers(frame);
3164 }
3165
3166 // "Re-occlude" surface S1 and repeat draw.
3167 // Must remove S1's render pass since it is now available in full.
3168 // S2 has no change so must also be removed.
3169 transform = layerS2Ptr->transform();
3170 transform.translate(-15, -15);
3171 layerS2Ptr->setTransform(transform);
3172 {
3173 CCLayerTreeHostImpl::FrameData frame;
3174 EXPECT_TRUE(myHostImpl->prepareToDraw(frame));
3175
3176 // Must receive 1 render pass - for the root.
3177 ASSERT_EQ(1U, frame.renderPasses.size());
3178
3179 EXPECT_EQ(2U, frame.renderPasses[0]->quadList().size());
3180
3181 myHostImpl->drawLayers(frame);
3182 myHostImpl->didDrawAllLayers(frame);
3183 }
3184
3185 }
3186
3187 TEST_P(CCLayerTreeHostImplTest, textureCachingWithOcclusionEarlyOut)
3188 {
3189 CCSettings::setPartialSwapEnabled(false);
3190
3191 CCLayerTreeSettings settings;
3192 settings.minimumOcclusionTrackingSize = IntSize();
3193 scoped_ptr<CCLayerTreeHostImpl> myHostImpl = CCLayerTreeHostImpl::create(set tings, this);
3194
3195 // Layers are structure as follows:
3196 //
3197 // R +-- S1 +- L10 (owning, non drawing)
3198 // | +- L11 (corner, unoccluded)
3199 // | +- L12 (corner, unoccluded)
3200 // | +- L13 (corner, unoccluded)
3201 // | +- L14 (corner, entirely occluded)
3202 // |
3203 // +-- S2 +- L20 (owning, drawing)
3204 //
3205
3206 CCLayerImpl* rootPtr;
3207 CCLayerImpl* layerS1Ptr;
3208 CCLayerImpl* layerS2Ptr;
3209
3210 scoped_ptr<CCGraphicsContext> context = FakeWebCompositorOutputSurface::crea te(adoptPtr(new PartialSwapContext)).PassAs<CCGraphicsContext>();
3211
3212 IntSize rootSize(1000, 1000);
3213
3214 myHostImpl->initializeRenderer(context.Pass());
3215 myHostImpl->setViewportSize(IntSize(rootSize.width(), rootSize.height()), In tSize(rootSize.width(), rootSize.height()));
3216
3217 scoped_ptr<CCLayerImpl> root = CCLayerImpl::create(1);
3218 rootPtr = root.get();
3219
3220 root->setAnchorPoint(FloatPoint(0, 0));
3221 root->setPosition(FloatPoint(0, 0));
3222 root->setBounds(rootSize);
3223 root->setContentBounds(rootSize);
3224 root->setDrawsContent(true);
3225 root->setMasksToBounds(true);
3226 myHostImpl->setRootLayer(root.Pass());
3227
3228 addDrawingLayerTo(rootPtr, 2, IntRect(0, 0, 800, 800), &layerS1Ptr);
3229 layerS1Ptr->setForceRenderSurface(true);
3230 layerS1Ptr->setDrawsContent(false);
3231
3232 addDrawingLayerTo(layerS1Ptr, 3, IntRect(0, 0, 300, 300), 0); // L11
3233 addDrawingLayerTo(layerS1Ptr, 4, IntRect(0, 500, 300, 300), 0); // L12
3234 addDrawingLayerTo(layerS1Ptr, 5, IntRect(500, 0, 300, 300), 0); // L13
3235 addDrawingLayerTo(layerS1Ptr, 6, IntRect(500, 500, 300, 300), 0); // L14
3236 addDrawingLayerTo(layerS1Ptr, 9, IntRect(500, 500, 300, 300), 0); // L14
3237
3238 addDrawingLayerTo(rootPtr, 7, IntRect(450, 450, 450, 450), &layerS2Ptr);
3239 layerS2Ptr->setForceRenderSurface(true);
3240
3241 // Initial draw - must receive all quads
3242 {
3243 CCLayerTreeHostImpl::FrameData frame;
3244 EXPECT_TRUE(myHostImpl->prepareToDraw(frame));
3245
3246 // Must receive 3 render passes.
3247 // For Root, there are 2 quads; for S1, there are 3 quads; for S2, there is 1 quad.
3248 ASSERT_EQ(3U, frame.renderPasses.size());
3249
3250 EXPECT_EQ(1U, frame.renderPasses[0]->quadList().size());
3251
3252 // L14 is culled, so only 3 quads.
3253 EXPECT_EQ(3U, frame.renderPasses[1]->quadList().size());
3254 EXPECT_EQ(2U, frame.renderPasses[2]->quadList().size());
3255
3256 myHostImpl->drawLayers(frame);
3257 myHostImpl->didDrawAllLayers(frame);
3258 }
3259
3260 // "Unocclude" surface S1 and repeat draw.
3261 // Must remove S2's render pass since it's cached;
3262 // Must keep S1 quads because texture contained external occlusion.
3263 WebTransformationMatrix transform = layerS2Ptr->transform();
3264 transform.translate(100, 100);
3265 layerS2Ptr->setTransform(transform);
3266 {
3267 CCLayerTreeHostImpl::FrameData frame;
3268 EXPECT_TRUE(myHostImpl->prepareToDraw(frame));
3269
3270 // Must receive 2 render passes.
3271 // For Root, there are 2 quads
3272 // For S1, the number of quads depends on what got unoccluded, so not as serted beyond being positive.
3273 // For S2, there is no render pass
3274 ASSERT_EQ(2U, frame.renderPasses.size());
3275
3276 EXPECT_GT(frame.renderPasses[0]->quadList().size(), 0U);
3277 EXPECT_EQ(2U, frame.renderPasses[1]->quadList().size());
3278
3279 myHostImpl->drawLayers(frame);
3280 myHostImpl->didDrawAllLayers(frame);
3281 }
3282
3283 // "Re-occlude" surface S1 and repeat draw.
3284 // Must remove S1's render pass since it is now available in full.
3285 // S2 has no change so must also be removed.
3286 transform = layerS2Ptr->transform();
3287 transform.translate(-15, -15);
3288 layerS2Ptr->setTransform(transform);
3289 {
3290 CCLayerTreeHostImpl::FrameData frame;
3291 EXPECT_TRUE(myHostImpl->prepareToDraw(frame));
3292
3293 // Must receive 1 render pass - for the root.
3294 ASSERT_EQ(1U, frame.renderPasses.size());
3295
3296 EXPECT_EQ(2U, frame.renderPasses[0]->quadList().size());
3297
3298 myHostImpl->drawLayers(frame);
3299 myHostImpl->didDrawAllLayers(frame);
3300 }
3301 }
3302
3303 TEST_P(CCLayerTreeHostImplTest, textureCachingWithOcclusionExternalOverInternal)
3304 {
3305 CCSettings::setPartialSwapEnabled(false);
3306
3307 CCLayerTreeSettings settings;
3308 settings.minimumOcclusionTrackingSize = IntSize();
3309 scoped_ptr<CCLayerTreeHostImpl> myHostImpl = CCLayerTreeHostImpl::create(set tings, this);
3310
3311 // Layers are structured as follows:
3312 //
3313 // R +-- S1 +- L10 (owning, drawing)
3314 // | +- L11 (corner, occluded by L12)
3315 // | +- L12 (opposite corner)
3316 // |
3317 // +-- S2 +- L20 (owning, drawing)
3318 //
3319
3320 CCLayerImpl* rootPtr;
3321 CCLayerImpl* layerS1Ptr;
3322 CCLayerImpl* layerS2Ptr;
3323
3324 scoped_ptr<CCGraphicsContext> context = FakeWebCompositorOutputSurface::crea te(adoptPtr(new PartialSwapContext)).PassAs<CCGraphicsContext>();
3325
3326 IntSize rootSize(1000, 1000);
3327
3328 myHostImpl->initializeRenderer(context.Pass());
3329 myHostImpl->setViewportSize(IntSize(rootSize.width(), rootSize.height()), In tSize(rootSize.width(), rootSize.height()));
3330
3331 scoped_ptr<CCLayerImpl> root = CCLayerImpl::create(1);
3332 rootPtr = root.get();
3333
3334 root->setAnchorPoint(FloatPoint(0, 0));
3335 root->setPosition(FloatPoint(0, 0));
3336 root->setBounds(rootSize);
3337 root->setContentBounds(rootSize);
3338 root->setDrawsContent(true);
3339 root->setMasksToBounds(true);
3340 myHostImpl->setRootLayer(root.Pass());
3341
3342 addDrawingLayerTo(rootPtr, 2, IntRect(0, 0, 400, 400), &layerS1Ptr);
3343 layerS1Ptr->setForceRenderSurface(true);
3344
3345 addDrawingLayerTo(layerS1Ptr, 3, IntRect(0, 0, 300, 300), 0); // L11
3346 addDrawingLayerTo(layerS1Ptr, 4, IntRect(100, 0, 300, 300), 0); // L12
3347
3348 addDrawingLayerTo(rootPtr, 7, IntRect(200, 0, 300, 300), &layerS2Ptr);
3349 layerS2Ptr->setForceRenderSurface(true);
3350
3351 // Initial draw - must receive all quads
3352 {
3353 CCLayerTreeHostImpl::FrameData frame;
3354 EXPECT_TRUE(myHostImpl->prepareToDraw(frame));
3355
3356 // Must receive 3 render passes.
3357 // For Root, there are 2 quads; for S1, there are 3 quads; for S2, there is 1 quad.
3358 ASSERT_EQ(3U, frame.renderPasses.size());
3359
3360 EXPECT_EQ(1U, frame.renderPasses[0]->quadList().size());
3361 EXPECT_EQ(3U, frame.renderPasses[1]->quadList().size());
3362 EXPECT_EQ(2U, frame.renderPasses[2]->quadList().size());
3363
3364 myHostImpl->drawLayers(frame);
3365 myHostImpl->didDrawAllLayers(frame);
3366 }
3367
3368 // "Unocclude" surface S1 and repeat draw.
3369 // Must remove S2's render pass since it's cached;
3370 // Must keep S1 quads because texture contained external occlusion.
3371 WebTransformationMatrix transform = layerS2Ptr->transform();
3372 transform.translate(300, 0);
3373 layerS2Ptr->setTransform(transform);
3374 {
3375 CCLayerTreeHostImpl::FrameData frame;
3376 EXPECT_TRUE(myHostImpl->prepareToDraw(frame));
3377
3378 // Must receive 2 render passes.
3379 // For Root, there are 2 quads
3380 // For S1, the number of quads depends on what got unoccluded, so not as serted beyond being positive.
3381 // For S2, there is no render pass
3382 ASSERT_EQ(2U, frame.renderPasses.size());
3383
3384 EXPECT_GT(frame.renderPasses[0]->quadList().size(), 0U);
3385 EXPECT_EQ(2U, frame.renderPasses[1]->quadList().size());
3386
3387 myHostImpl->drawLayers(frame);
3388 myHostImpl->didDrawAllLayers(frame);
3389 }
3390 }
3391
3392 TEST_P(CCLayerTreeHostImplTest, textureCachingWithOcclusionExternalNotAligned)
3393 {
3394 CCSettings::setPartialSwapEnabled(false);
3395
3396 CCLayerTreeSettings settings;
3397 scoped_ptr<CCLayerTreeHostImpl> myHostImpl = CCLayerTreeHostImpl::create(set tings, this);
3398
3399 // Layers are structured as follows:
3400 //
3401 // R +-- S1 +- L10 (rotated, drawing)
3402 // +- L11 (occupies half surface)
3403
3404 CCLayerImpl* rootPtr;
3405 CCLayerImpl* layerS1Ptr;
3406
3407 scoped_ptr<CCGraphicsContext> context = FakeWebCompositorOutputSurface::crea te(adoptPtr(new PartialSwapContext)).PassAs<CCGraphicsContext>();
3408
3409 IntSize rootSize(1000, 1000);
3410
3411 myHostImpl->initializeRenderer(context.Pass());
3412 myHostImpl->setViewportSize(IntSize(rootSize.width(), rootSize.height()), In tSize(rootSize.width(), rootSize.height()));
3413
3414 scoped_ptr<CCLayerImpl> root = CCLayerImpl::create(1);
3415 rootPtr = root.get();
3416
3417 root->setAnchorPoint(FloatPoint(0, 0));
3418 root->setPosition(FloatPoint(0, 0));
3419 root->setBounds(rootSize);
3420 root->setContentBounds(rootSize);
3421 root->setDrawsContent(true);
3422 root->setMasksToBounds(true);
3423 myHostImpl->setRootLayer(root.Pass());
3424
3425 addDrawingLayerTo(rootPtr, 2, IntRect(0, 0, 400, 400), &layerS1Ptr);
3426 layerS1Ptr->setForceRenderSurface(true);
3427 WebTransformationMatrix transform = layerS1Ptr->transform();
3428 transform.translate(200, 200);
3429 transform.rotate(45);
3430 transform.translate(-200, -200);
3431 layerS1Ptr->setTransform(transform);
3432
3433 addDrawingLayerTo(layerS1Ptr, 3, IntRect(200, 0, 200, 400), 0); // L11
3434
3435 // Initial draw - must receive all quads
3436 {
3437 CCLayerTreeHostImpl::FrameData frame;
3438 EXPECT_TRUE(myHostImpl->prepareToDraw(frame));
3439
3440 // Must receive 2 render passes.
3441 ASSERT_EQ(2U, frame.renderPasses.size());
3442
3443 EXPECT_EQ(2U, frame.renderPasses[0]->quadList().size());
3444 EXPECT_EQ(1U, frame.renderPasses[1]->quadList().size());
3445
3446 myHostImpl->drawLayers(frame);
3447 myHostImpl->didDrawAllLayers(frame);
3448 }
3449
3450 // Change opacity and draw. Verify we used cached texture.
3451 layerS1Ptr->setOpacity(0.2f);
3452 {
3453 CCLayerTreeHostImpl::FrameData frame;
3454 EXPECT_TRUE(myHostImpl->prepareToDraw(frame));
3455
3456 // One render pass must be gone due to cached texture.
3457 ASSERT_EQ(1U, frame.renderPasses.size());
3458
3459 EXPECT_EQ(1U, frame.renderPasses[0]->quadList().size());
3460
3461 myHostImpl->drawLayers(frame);
3462 myHostImpl->didDrawAllLayers(frame);
3463 }
3464 }
3465
3466 TEST_P(CCLayerTreeHostImplTest, textureCachingWithOcclusionPartialSwap)
3467 {
3468 CCSettings::setPartialSwapEnabled(true);
3469
3470 CCLayerTreeSettings settings;
3471 settings.minimumOcclusionTrackingSize = IntSize();
3472 scoped_ptr<CCLayerTreeHostImpl> myHostImpl = CCLayerTreeHostImpl::create(set tings, this);
3473
3474 // Layers are structure as follows:
3475 //
3476 // R +-- S1 +- L10 (owning)
3477 // | +- L11
3478 // | +- L12
3479 // |
3480 // +-- S2 +- L20 (owning)
3481 // +- L21
3482 //
3483 // Occlusion:
3484 // L12 occludes L11 (internal)
3485 // L20 occludes L10 (external)
3486 // L21 occludes L20 (internal)
3487
3488 CCLayerImpl* rootPtr;
3489 CCLayerImpl* layerS1Ptr;
3490 CCLayerImpl* layerS2Ptr;
3491
3492 scoped_ptr<CCGraphicsContext> context = FakeWebCompositorOutputSurface::crea te(adoptPtr(new PartialSwapContext)).PassAs<CCGraphicsContext>();
3493
3494 IntSize rootSize(1000, 1000);
3495
3496 myHostImpl->initializeRenderer(context.Pass());
3497 myHostImpl->setViewportSize(IntSize(rootSize.width(), rootSize.height()), In tSize(rootSize.width(), rootSize.height()));
3498
3499 scoped_ptr<CCLayerImpl> root = CCLayerImpl::create(1);
3500 rootPtr = root.get();
3501
3502 root->setAnchorPoint(FloatPoint(0, 0));
3503 root->setPosition(FloatPoint(0, 0));
3504 root->setBounds(rootSize);
3505 root->setContentBounds(rootSize);
3506 root->setDrawsContent(true);
3507 root->setMasksToBounds(true);
3508 myHostImpl->setRootLayer(root.Pass());
3509
3510 addDrawingLayerTo(rootPtr, 2, IntRect(300, 300, 300, 300), &layerS1Ptr);
3511 layerS1Ptr->setForceRenderSurface(true);
3512
3513 addDrawingLayerTo(layerS1Ptr, 3, IntRect(10, 10, 10, 10), 0); // L11
3514 addDrawingLayerTo(layerS1Ptr, 4, IntRect(0, 0, 30, 30), 0); // L12
3515
3516 addDrawingLayerTo(rootPtr, 5, IntRect(550, 250, 300, 400), &layerS2Ptr);
3517 layerS2Ptr->setForceRenderSurface(true);
3518
3519 addDrawingLayerTo(layerS2Ptr, 6, IntRect(20, 20, 5, 5), 0); // L21
3520
3521 // Initial draw - must receive all quads
3522 {
3523 CCLayerTreeHostImpl::FrameData frame;
3524 EXPECT_TRUE(myHostImpl->prepareToDraw(frame));
3525
3526 // Must receive 3 render passes.
3527 // For Root, there are 2 quads; for S1, there are 2 quads (one is occlud ed); for S2, there is 2 quads.
3528 ASSERT_EQ(3U, frame.renderPasses.size());
3529
3530 EXPECT_EQ(2U, frame.renderPasses[0]->quadList().size());
3531 EXPECT_EQ(2U, frame.renderPasses[1]->quadList().size());
3532 EXPECT_EQ(2U, frame.renderPasses[2]->quadList().size());
3533
3534 myHostImpl->drawLayers(frame);
3535 myHostImpl->didDrawAllLayers(frame);
3536 }
3537
3538 // "Unocclude" surface S1 and repeat draw.
3539 // Must remove S2's render pass since it's cached;
3540 // Must keep S1 quads because texture contained external occlusion.
3541 WebTransformationMatrix transform = layerS2Ptr->transform();
3542 transform.translate(150, 150);
3543 layerS2Ptr->setTransform(transform);
3544 {
3545 CCLayerTreeHostImpl::FrameData frame;
3546 EXPECT_TRUE(myHostImpl->prepareToDraw(frame));
3547
3548 // Must receive 2 render passes.
3549 // For Root, there are 2 quads.
3550 // For S1, there are 2 quads.
3551 // For S2, there is no render pass
3552 ASSERT_EQ(2U, frame.renderPasses.size());
3553
3554 EXPECT_EQ(2U, frame.renderPasses[0]->quadList().size());
3555 EXPECT_EQ(2U, frame.renderPasses[1]->quadList().size());
3556
3557 myHostImpl->drawLayers(frame);
3558 myHostImpl->didDrawAllLayers(frame);
3559 }
3560
3561 // "Re-occlude" surface S1 and repeat draw.
3562 // Must remove S1's render pass since it is now available in full.
3563 // S2 has no change so must also be removed.
3564 transform = layerS2Ptr->transform();
3565 transform.translate(-15, -15);
3566 layerS2Ptr->setTransform(transform);
3567 {
3568 CCLayerTreeHostImpl::FrameData frame;
3569 EXPECT_TRUE(myHostImpl->prepareToDraw(frame));
3570
3571 // Root render pass only.
3572 ASSERT_EQ(1U, frame.renderPasses.size());
3573
3574 myHostImpl->drawLayers(frame);
3575 myHostImpl->didDrawAllLayers(frame);
3576 }
3577 }
3578
3579 TEST_P(CCLayerTreeHostImplTest, textureCachingWithScissor)
3580 {
3581 CCSettings::setPartialSwapEnabled(false);
3582
3583 CCLayerTreeSettings settings;
3584 settings.minimumOcclusionTrackingSize = IntSize();
3585 scoped_ptr<CCLayerTreeHostImpl> myHostImpl = CCLayerTreeHostImpl::create(set tings, this);
3586
3587 /*
3588 Layers are created as follows:
3589
3590 +--------------------+
3591 | 1 |
3592 | +-----------+ |
3593 | | 2 | |
3594 | | +-------------------+
3595 | | | 3 |
3596 | | +-------------------+
3597 | | | |
3598 | +-----------+ |
3599 | |
3600 | |
3601 +--------------------+
3602
3603 Layers 1, 2 have render surfaces
3604 */
3605 scoped_ptr<CCLayerImpl> root = CCLayerImpl::create(1);
3606 scoped_ptr<CCTiledLayerImpl> child = CCTiledLayerImpl::create(2);
3607 scoped_ptr<CCLayerImpl> grandChild = CCLayerImpl::create(3);
3608
3609 IntRect rootRect(0, 0, 100, 100);
3610 IntRect childRect(10, 10, 50, 50);
3611 IntRect grandChildRect(5, 5, 150, 150);
3612
3613 scoped_ptr<CCGraphicsContext> context = FakeWebCompositorOutputSurface::crea te(adoptPtr(new PartialSwapContext)).PassAs<CCGraphicsContext>();
3614 myHostImpl->initializeRenderer(context.Pass());
3615
3616 root->setAnchorPoint(FloatPoint(0, 0));
3617 root->setPosition(FloatPoint(rootRect.x(), rootRect.y()));
3618 root->setBounds(IntSize(rootRect.width(), rootRect.height()));
3619 root->setContentBounds(root->bounds());
3620 root->setDrawsContent(true);
3621 root->setMasksToBounds(true);
3622
3623 child->setAnchorPoint(FloatPoint(0, 0));
3624 child->setPosition(FloatPoint(childRect.x(), childRect.y()));
3625 child->setOpacity(0.5);
3626 child->setBounds(IntSize(childRect.width(), childRect.height()));
3627 child->setContentBounds(child->bounds());
3628 child->setDrawsContent(true);
3629 child->setSkipsDraw(false);
3630
3631 // child layer has 10x10 tiles.
3632 OwnPtr<CCLayerTilingData> tiler = CCLayerTilingData::create(IntSize(10, 10), CCLayerTilingData::HasBorderTexels);
3633 tiler->setBounds(child->contentBounds());
3634 child->setTilingData(*tiler.get());
3635
3636 grandChild->setAnchorPoint(FloatPoint(0, 0));
3637 grandChild->setPosition(IntPoint(grandChildRect.x(), grandChildRect.y()));
3638 grandChild->setBounds(IntSize(grandChildRect.width(), grandChildRect.height( )));
3639 grandChild->setContentBounds(grandChild->bounds());
3640 grandChild->setDrawsContent(true);
3641
3642 CCTiledLayerImpl* childPtr = child.get();
3643 CCRenderPass::Id childPassId(childPtr->id(), 0);
3644
3645 child->addChild(grandChild.Pass());
3646 root->addChild(child.PassAs<CCLayerImpl>());
3647 myHostImpl->setRootLayer(root.Pass());
3648 myHostImpl->setViewportSize(rootRect.size(), rootRect.size());
3649
3650 EXPECT_FALSE(myHostImpl->renderer()->haveCachedResourcesForRenderPassId(chil dPassId));
3651
3652 {
3653 CCLayerTreeHostImpl::FrameData frame;
3654 EXPECT_TRUE(myHostImpl->prepareToDraw(frame));
3655 myHostImpl->drawLayers(frame);
3656 myHostImpl->didDrawAllLayers(frame);
3657 }
3658
3659 // We should have cached textures for surface 2.
3660 EXPECT_TRUE(myHostImpl->renderer()->haveCachedResourcesForRenderPassId(child PassId));
3661
3662 {
3663 CCLayerTreeHostImpl::FrameData frame;
3664 EXPECT_TRUE(myHostImpl->prepareToDraw(frame));
3665 myHostImpl->drawLayers(frame);
3666 myHostImpl->didDrawAllLayers(frame);
3667 }
3668
3669 // We should still have cached textures for surface 2 after drawing with no damage.
3670 EXPECT_TRUE(myHostImpl->renderer()->haveCachedResourcesForRenderPassId(child PassId));
3671
3672 // Damage a single tile of surface 2.
3673 childPtr->setUpdateRect(IntRect(10, 10, 10, 10));
3674
3675 {
3676 CCLayerTreeHostImpl::FrameData frame;
3677 EXPECT_TRUE(myHostImpl->prepareToDraw(frame));
3678 myHostImpl->drawLayers(frame);
3679 myHostImpl->didDrawAllLayers(frame);
3680 }
3681
3682 // We should have a cached texture for surface 2 again even though it was da maged.
3683 EXPECT_TRUE(myHostImpl->renderer()->haveCachedResourcesForRenderPassId(child PassId));
3684 }
3685
3686 TEST_P(CCLayerTreeHostImplTest, surfaceTextureCaching)
3687 {
3688 CCSettings::setPartialSwapEnabled(true);
3689
3690 CCLayerTreeSettings settings;
3691 settings.minimumOcclusionTrackingSize = IntSize();
3692 scoped_ptr<CCLayerTreeHostImpl> myHostImpl = CCLayerTreeHostImpl::create(set tings, this);
3693
3694 CCLayerImpl* rootPtr;
3695 CCLayerImpl* intermediateLayerPtr;
3696 CCLayerImpl* surfaceLayerPtr;
3697 CCLayerImpl* childPtr;
3698
3699 setupLayersForTextureCaching(myHostImpl.get(), rootPtr, intermediateLayerPtr , surfaceLayerPtr, childPtr, IntSize(100, 100));
3700
3701 {
3702 CCLayerTreeHostImpl::FrameData frame;
3703 EXPECT_TRUE(myHostImpl->prepareToDraw(frame));
3704
3705 // Must receive two render passes, each with one quad
3706 ASSERT_EQ(2U, frame.renderPasses.size());
3707 EXPECT_EQ(1U, frame.renderPasses[0]->quadList().size());
3708 EXPECT_EQ(1U, frame.renderPasses[1]->quadList().size());
3709
3710 EXPECT_EQ(CCDrawQuad::RenderPass, frame.renderPasses[1]->quadList()[0]-> material());
3711 CCRenderPassDrawQuad* quad = static_cast<CCRenderPassDrawQuad*>(frame.re nderPasses[1]->quadList()[0]);
3712 CCRenderPass* targetPass = frame.renderPassesById.get(quad->renderPassId ());
3713 EXPECT_FALSE(targetPass->damageRect().isEmpty());
3714
3715 myHostImpl->drawLayers(frame);
3716 myHostImpl->didDrawAllLayers(frame);
3717 }
3718
3719 // Draw without any change
3720 {
3721 CCLayerTreeHostImpl::FrameData frame;
3722 EXPECT_TRUE(myHostImpl->prepareToDraw(frame));
3723
3724 // Must receive one render pass, as the other one should be culled
3725 ASSERT_EQ(1U, frame.renderPasses.size());
3726
3727 EXPECT_EQ(1U, frame.renderPasses[0]->quadList().size());
3728 EXPECT_EQ(CCDrawQuad::RenderPass, frame.renderPasses[0]->quadList()[0]-> material());
3729 CCRenderPassDrawQuad* quad = static_cast<CCRenderPassDrawQuad*>(frame.re nderPasses[0]->quadList()[0]);
3730 CCRenderPass* targetPass = frame.renderPassesById.get(quad->renderPassId ());
3731 EXPECT_TRUE(targetPass->damageRect().isEmpty());
3732
3733 myHostImpl->drawLayers(frame);
3734 myHostImpl->didDrawAllLayers(frame);
3735 }
3736
3737 // Change opacity and draw
3738 surfaceLayerPtr->setOpacity(0.6f);
3739 {
3740 CCLayerTreeHostImpl::FrameData frame;
3741 EXPECT_TRUE(myHostImpl->prepareToDraw(frame));
3742
3743 // Must receive one render pass, as the other one should be culled
3744 ASSERT_EQ(1U, frame.renderPasses.size());
3745
3746 EXPECT_EQ(1U, frame.renderPasses[0]->quadList().size());
3747 EXPECT_EQ(CCDrawQuad::RenderPass, frame.renderPasses[0]->quadList()[0]-> material());
3748 CCRenderPassDrawQuad* quad = static_cast<CCRenderPassDrawQuad*>(frame.re nderPasses[0]->quadList()[0]);
3749 CCRenderPass* targetPass = frame.renderPassesById.get(quad->renderPassId ());
3750 EXPECT_TRUE(targetPass->damageRect().isEmpty());
3751
3752 myHostImpl->drawLayers(frame);
3753 myHostImpl->didDrawAllLayers(frame);
3754 }
3755
3756 // Change less benign property and draw - should have contents changed flag
3757 surfaceLayerPtr->setStackingOrderChanged(true);
3758 {
3759 CCLayerTreeHostImpl::FrameData frame;
3760 EXPECT_TRUE(myHostImpl->prepareToDraw(frame));
3761
3762 // Must receive two render passes, each with one quad
3763 ASSERT_EQ(2U, frame.renderPasses.size());
3764
3765 EXPECT_EQ(1U, frame.renderPasses[0]->quadList().size());
3766 EXPECT_EQ(CCDrawQuad::SolidColor, frame.renderPasses[0]->quadList()[0]-> material());
3767
3768 EXPECT_EQ(CCDrawQuad::RenderPass, frame.renderPasses[1]->quadList()[0]-> material());
3769 CCRenderPassDrawQuad* quad = static_cast<CCRenderPassDrawQuad*>(frame.re nderPasses[1]->quadList()[0]);
3770 CCRenderPass* targetPass = frame.renderPassesById.get(quad->renderPassId ());
3771 EXPECT_FALSE(targetPass->damageRect().isEmpty());
3772
3773 myHostImpl->drawLayers(frame);
3774 myHostImpl->didDrawAllLayers(frame);
3775 }
3776
3777 // Change opacity again, and evict the cached surface texture.
3778 surfaceLayerPtr->setOpacity(0.5f);
3779 static_cast<CCRendererGLWithReleaseTextures*>(myHostImpl->renderer())->relea seRenderPassTextures();
3780
3781 // Change opacity and draw
3782 surfaceLayerPtr->setOpacity(0.6f);
3783 {
3784 CCLayerTreeHostImpl::FrameData frame;
3785 EXPECT_TRUE(myHostImpl->prepareToDraw(frame));
3786
3787 // Must receive two render passes
3788 ASSERT_EQ(2U, frame.renderPasses.size());
3789
3790 // Even though not enough properties changed, the entire thing must be
3791 // redrawn as we don't have cached textures
3792 EXPECT_EQ(1U, frame.renderPasses[0]->quadList().size());
3793 EXPECT_EQ(1U, frame.renderPasses[1]->quadList().size());
3794
3795 EXPECT_EQ(CCDrawQuad::RenderPass, frame.renderPasses[1]->quadList()[0]-> material());
3796 CCRenderPassDrawQuad* quad = static_cast<CCRenderPassDrawQuad*>(frame.re nderPasses[1]->quadList()[0]);
3797 CCRenderPass* targetPass = frame.renderPassesById.get(quad->renderPassId ());
3798 EXPECT_TRUE(targetPass->damageRect().isEmpty());
3799
3800 // Was our surface evicted?
3801 EXPECT_FALSE(myHostImpl->renderer()->haveCachedResourcesForRenderPassId( targetPass->id()));
3802
3803 myHostImpl->drawLayers(frame);
3804 myHostImpl->didDrawAllLayers(frame);
3805 }
3806
3807 // Draw without any change, to make sure the state is clear
3808 {
3809 CCLayerTreeHostImpl::FrameData frame;
3810 EXPECT_TRUE(myHostImpl->prepareToDraw(frame));
3811
3812 // Must receive one render pass, as the other one should be culled
3813 ASSERT_EQ(1U, frame.renderPasses.size());
3814
3815 EXPECT_EQ(1U, frame.renderPasses[0]->quadList().size());
3816 EXPECT_EQ(CCDrawQuad::RenderPass, frame.renderPasses[0]->quadList()[0]-> material());
3817 CCRenderPassDrawQuad* quad = static_cast<CCRenderPassDrawQuad*>(frame.re nderPasses[0]->quadList()[0]);
3818 CCRenderPass* targetPass = frame.renderPassesById.get(quad->renderPassId ());
3819 EXPECT_TRUE(targetPass->damageRect().isEmpty());
3820
3821 myHostImpl->drawLayers(frame);
3822 myHostImpl->didDrawAllLayers(frame);
3823 }
3824
3825 // Change opacity on the intermediate layer
3826 WebTransformationMatrix transform = intermediateLayerPtr->transform();
3827 transform.setM11(1.0001);
3828 intermediateLayerPtr->setTransform(transform);
3829 {
3830 CCLayerTreeHostImpl::FrameData frame;
3831 EXPECT_TRUE(myHostImpl->prepareToDraw(frame));
3832
3833 // Must receive one render pass, as the other one should be culled.
3834 ASSERT_EQ(1U, frame.renderPasses.size());
3835 EXPECT_EQ(1U, frame.renderPasses[0]->quadList().size());
3836
3837 EXPECT_EQ(CCDrawQuad::RenderPass, frame.renderPasses[0]->quadList()[0]-> material());
3838 CCRenderPassDrawQuad* quad = static_cast<CCRenderPassDrawQuad*>(frame.re nderPasses[0]->quadList()[0]);
3839 CCRenderPass* targetPass = frame.renderPassesById.get(quad->renderPassId ());
3840 EXPECT_TRUE(targetPass->damageRect().isEmpty());
3841
3842 myHostImpl->drawLayers(frame);
3843 myHostImpl->didDrawAllLayers(frame);
3844 }
3845 }
3846
3847 TEST_P(CCLayerTreeHostImplTest, surfaceTextureCachingNoPartialSwap)
3848 {
3849 CCSettings::setPartialSwapEnabled(false);
3850
3851 CCLayerTreeSettings settings;
3852 settings.minimumOcclusionTrackingSize = IntSize();
3853 scoped_ptr<CCLayerTreeHostImpl> myHostImpl = CCLayerTreeHostImpl::create(set tings, this);
3854
3855 CCLayerImpl* rootPtr;
3856 CCLayerImpl* intermediateLayerPtr;
3857 CCLayerImpl* surfaceLayerPtr;
3858 CCLayerImpl* childPtr;
3859
3860 setupLayersForTextureCaching(myHostImpl.get(), rootPtr, intermediateLayerPtr , surfaceLayerPtr, childPtr, IntSize(100, 100));
3861
3862 {
3863 CCLayerTreeHostImpl::FrameData frame;
3864 EXPECT_TRUE(myHostImpl->prepareToDraw(frame));
3865
3866 // Must receive two render passes, each with one quad
3867 ASSERT_EQ(2U, frame.renderPasses.size());
3868 EXPECT_EQ(1U, frame.renderPasses[0]->quadList().size());
3869 EXPECT_EQ(1U, frame.renderPasses[1]->quadList().size());
3870
3871 EXPECT_EQ(CCDrawQuad::RenderPass, frame.renderPasses[1]->quadList()[0]-> material());
3872 CCRenderPassDrawQuad* quad = static_cast<CCRenderPassDrawQuad*>(frame.re nderPasses[1]->quadList()[0]);
3873 CCRenderPass* targetPass = frame.renderPassesById.get(quad->renderPassId ());
3874 EXPECT_FALSE(targetPass->damageRect().isEmpty());
3875
3876 EXPECT_FALSE(frame.renderPasses[0]->damageRect().isEmpty());
3877 EXPECT_FALSE(frame.renderPasses[1]->damageRect().isEmpty());
3878
3879 EXPECT_FALSE(frame.renderPasses[0]->hasOcclusionFromOutsideTargetSurface ());
3880 EXPECT_FALSE(frame.renderPasses[1]->hasOcclusionFromOutsideTargetSurface ());
3881
3882 myHostImpl->drawLayers(frame);
3883 myHostImpl->didDrawAllLayers(frame);
3884 }
3885
3886 // Draw without any change
3887 {
3888 CCLayerTreeHostImpl::FrameData frame;
3889 EXPECT_TRUE(myHostImpl->prepareToDraw(frame));
3890
3891 // Even though there was no change, we set the damage to entire viewport .
3892 // One of the passes should be culled as a result, since contents didn't change
3893 // and we have cached texture.
3894 ASSERT_EQ(1U, frame.renderPasses.size());
3895 EXPECT_EQ(1U, frame.renderPasses[0]->quadList().size());
3896
3897 EXPECT_TRUE(frame.renderPasses[0]->damageRect().isEmpty());
3898
3899 myHostImpl->drawLayers(frame);
3900 myHostImpl->didDrawAllLayers(frame);
3901 }
3902
3903 // Change opacity and draw
3904 surfaceLayerPtr->setOpacity(0.6f);
3905 {
3906 CCLayerTreeHostImpl::FrameData frame;
3907 EXPECT_TRUE(myHostImpl->prepareToDraw(frame));
3908
3909 // Must receive one render pass, as the other one should be culled
3910 ASSERT_EQ(1U, frame.renderPasses.size());
3911
3912 EXPECT_EQ(1U, frame.renderPasses[0]->quadList().size());
3913 EXPECT_EQ(CCDrawQuad::RenderPass, frame.renderPasses[0]->quadList()[0]-> material());
3914 CCRenderPassDrawQuad* quad = static_cast<CCRenderPassDrawQuad*>(frame.re nderPasses[0]->quadList()[0]);
3915 CCRenderPass* targetPass = frame.renderPassesById.get(quad->renderPassId ());
3916 EXPECT_TRUE(targetPass->damageRect().isEmpty());
3917
3918 myHostImpl->drawLayers(frame);
3919 myHostImpl->didDrawAllLayers(frame);
3920 }
3921
3922 // Change less benign property and draw - should have contents changed flag
3923 surfaceLayerPtr->setStackingOrderChanged(true);
3924 {
3925 CCLayerTreeHostImpl::FrameData frame;
3926 EXPECT_TRUE(myHostImpl->prepareToDraw(frame));
3927
3928 // Must receive two render passes, each with one quad
3929 ASSERT_EQ(2U, frame.renderPasses.size());
3930
3931 EXPECT_EQ(1U, frame.renderPasses[0]->quadList().size());
3932 EXPECT_EQ(CCDrawQuad::SolidColor, frame.renderPasses[0]->quadList()[0]-> material());
3933
3934 EXPECT_EQ(CCDrawQuad::RenderPass, frame.renderPasses[1]->quadList()[0]-> material());
3935 CCRenderPassDrawQuad* quad = static_cast<CCRenderPassDrawQuad*>(frame.re nderPasses[1]->quadList()[0]);
3936 CCRenderPass* targetPass = frame.renderPassesById.get(quad->renderPassId ());
3937 EXPECT_FALSE(targetPass->damageRect().isEmpty());
3938
3939 myHostImpl->drawLayers(frame);
3940 myHostImpl->didDrawAllLayers(frame);
3941 }
3942
3943 // Change opacity again, and evict the cached surface texture.
3944 surfaceLayerPtr->setOpacity(0.5f);
3945 static_cast<CCRendererGLWithReleaseTextures*>(myHostImpl->renderer())->relea seRenderPassTextures();
3946
3947 // Change opacity and draw
3948 surfaceLayerPtr->setOpacity(0.6f);
3949 {
3950 CCLayerTreeHostImpl::FrameData frame;
3951 EXPECT_TRUE(myHostImpl->prepareToDraw(frame));
3952
3953 // Must receive two render passes
3954 ASSERT_EQ(2U, frame.renderPasses.size());
3955
3956 // Even though not enough properties changed, the entire thing must be
3957 // redrawn as we don't have cached textures
3958 EXPECT_EQ(1U, frame.renderPasses[0]->quadList().size());
3959 EXPECT_EQ(1U, frame.renderPasses[1]->quadList().size());
3960
3961 EXPECT_EQ(CCDrawQuad::RenderPass, frame.renderPasses[1]->quadList()[0]-> material());
3962 CCRenderPassDrawQuad* quad = static_cast<CCRenderPassDrawQuad*>(frame.re nderPasses[1]->quadList()[0]);
3963 CCRenderPass* targetPass = frame.renderPassesById.get(quad->renderPassId ());
3964 EXPECT_TRUE(targetPass->damageRect().isEmpty());
3965
3966 // Was our surface evicted?
3967 EXPECT_FALSE(myHostImpl->renderer()->haveCachedResourcesForRenderPassId( targetPass->id()));
3968
3969 myHostImpl->drawLayers(frame);
3970 myHostImpl->didDrawAllLayers(frame);
3971 }
3972
3973 // Draw without any change, to make sure the state is clear
3974 {
3975 CCLayerTreeHostImpl::FrameData frame;
3976 EXPECT_TRUE(myHostImpl->prepareToDraw(frame));
3977
3978 // Even though there was no change, we set the damage to entire viewport .
3979 // One of the passes should be culled as a result, since contents didn't change
3980 // and we have cached texture.
3981 ASSERT_EQ(1U, frame.renderPasses.size());
3982 EXPECT_EQ(1U, frame.renderPasses[0]->quadList().size());
3983
3984 myHostImpl->drawLayers(frame);
3985 myHostImpl->didDrawAllLayers(frame);
3986 }
3987
3988 // Change opacity on the intermediate layer
3989 WebTransformationMatrix transform = intermediateLayerPtr->transform();
3990 transform.setM11(1.0001);
3991 intermediateLayerPtr->setTransform(transform);
3992 {
3993 CCLayerTreeHostImpl::FrameData frame;
3994 EXPECT_TRUE(myHostImpl->prepareToDraw(frame));
3995
3996 // Must receive one render pass, as the other one should be culled.
3997 ASSERT_EQ(1U, frame.renderPasses.size());
3998 EXPECT_EQ(1U, frame.renderPasses[0]->quadList().size());
3999
4000 EXPECT_EQ(CCDrawQuad::RenderPass, frame.renderPasses[0]->quadList()[0]-> material());
4001 CCRenderPassDrawQuad* quad = static_cast<CCRenderPassDrawQuad*>(frame.re nderPasses[0]->quadList()[0]);
4002 CCRenderPass* targetPass = frame.renderPassesById.get(quad->renderPassId ());
4003 EXPECT_TRUE(targetPass->damageRect().isEmpty());
4004
4005 myHostImpl->drawLayers(frame);
4006 myHostImpl->didDrawAllLayers(frame);
4007 }
4008 }
4009
4010 TEST_P(CCLayerTreeHostImplTest, releaseContentsTextureShouldTriggerCommit)
4011 {
4012 m_hostImpl->releaseContentsTextures();
4013 EXPECT_TRUE(m_didRequestCommit);
4014 }
4015
4016 struct RenderPassRemovalTestData : public CCLayerTreeHostImpl::FrameData {
4017 ScopedPtrHashMap<CCRenderPass::Id, CCRenderPass> renderPassCache;
4018 scoped_ptr<CCSharedQuadState> sharedQuadState;
4019 };
4020
4021 class CCTestRenderer : public CCRendererGL, public CCRendererClient {
4022 public:
4023 static PassOwnPtr<CCTestRenderer> create(CCResourceProvider* resourceProvide r)
4024 {
4025 OwnPtr<CCTestRenderer> renderer(adoptPtr(new CCTestRenderer(resourceProv ider)));
4026 if (!renderer->initialize())
4027 return nullptr;
4028
4029 return renderer.release();
4030 }
4031
4032 void clearCachedTextures() { m_textures.clear(); }
4033 void setHaveCachedResourcesForRenderPassId(CCRenderPass::Id id) { m_textures .insert(id); }
4034
4035 virtual bool haveCachedResourcesForRenderPassId(CCRenderPass::Id id) const O VERRIDE { return m_textures.count(id); }
4036
4037 // CCRendererClient implementation.
4038 virtual const IntSize& deviceViewportSize() const OVERRIDE { return m_viewpo rtSize; }
4039 virtual const CCLayerTreeSettings& settings() const OVERRIDE { return m_sett ings; }
4040 virtual void didLoseContext() OVERRIDE { }
4041 virtual void onSwapBuffersComplete() OVERRIDE { }
4042 virtual void setFullRootLayerDamage() OVERRIDE { }
4043 virtual void releaseContentsTextures() OVERRIDE { }
4044 virtual void setMemoryAllocationLimitBytes(size_t) OVERRIDE { }
4045
4046 protected:
4047 CCTestRenderer(CCResourceProvider* resourceProvider) : CCRendererGL(this, re sourceProvider) { }
4048
4049 private:
4050 CCLayerTreeSettings m_settings;
4051 IntSize m_viewportSize;
4052 base::hash_set<CCRenderPass::Id> m_textures;
4053 };
4054
4055 static void configureRenderPassTestData(const char* testScript, RenderPassRemova lTestData& testData, CCTestRenderer* renderer)
4056 {
4057 renderer->clearCachedTextures();
4058
4059 // One shared state for all quads - we don't need the correct details
4060 testData.sharedQuadState = CCSharedQuadState::create(WebTransformationMatrix (), IntRect(), IntRect(), 1.0, true);
4061
4062 const char* currentChar = testScript;
4063
4064 // Pre-create root pass
4065 CCRenderPass::Id rootRenderPassId = CCRenderPass::Id(testScript[0], testScri pt[1]);
4066 testData.renderPassCache.add(rootRenderPassId, CCRenderPass::create(rootRend erPassId, IntRect(), WebTransformationMatrix()));
4067 while (*currentChar) {
4068 int layerId = *currentChar;
4069 currentChar++;
4070 ASSERT_TRUE(currentChar);
4071 int index = *currentChar;
4072 currentChar++;
4073
4074 CCRenderPass::Id renderPassId = CCRenderPass::Id(layerId, index);
4075
4076 bool isReplica = false;
4077 if (!testData.renderPassCache.contains(renderPassId))
4078 isReplica = true;
4079
4080 scoped_ptr<CCRenderPass> renderPass = testData.renderPassCache.take(rend erPassId);
4081
4082 // Cycle through quad data and create all quads
4083 while (*currentChar && *currentChar != '\n') {
4084 if (*currentChar == 's') {
4085 // Solid color draw quad
4086 scoped_ptr<CCSolidColorDrawQuad> quad = CCSolidColorDrawQuad::cr eate(testData.sharedQuadState.get(), IntRect(0, 0, 10, 10), SK_ColorWHITE);
4087
4088 static_cast<CCTestRenderPass*>(renderPass.get())->appendQuad(qua d.PassAs<CCDrawQuad>());
4089 currentChar++;
4090 } else if ((*currentChar >= 'A') && (*currentChar <= 'Z')) {
4091 // RenderPass draw quad
4092 int layerId = *currentChar;
4093 currentChar++;
4094 ASSERT_TRUE(currentChar);
4095 int index = *currentChar;
4096 currentChar++;
4097 CCRenderPass::Id newRenderPassId = CCRenderPass::Id(layerId, ind ex);
4098 ASSERT_NE(rootRenderPassId, newRenderPassId);
4099 bool hasTexture = false;
4100 bool contentsChanged = true;
4101
4102 if (*currentChar == '[') {
4103 currentChar++;
4104 while (*currentChar && *currentChar != ']') {
4105 switch (*currentChar) {
4106 case 'c':
4107 contentsChanged = false;
4108 break;
4109 case 't':
4110 hasTexture = true;
4111 break;
4112 }
4113 currentChar++;
4114 }
4115 if (*currentChar == ']')
4116 currentChar++;
4117 }
4118
4119 if (testData.renderPassCache.find(newRenderPassId) == testData.r enderPassCache.end()) {
4120 if (hasTexture)
4121 renderer->setHaveCachedResourcesForRenderPassId(newRende rPassId);
4122
4123 testData.renderPassCache.add(newRenderPassId, CCTestRenderPa ss::create(newRenderPassId, IntRect(), WebTransformationMatrix()));
4124 }
4125
4126 IntRect quadRect = IntRect(0, 0, 1, 1);
4127 IntRect contentsChangedRect = contentsChanged ? quadRect : IntRe ct();
4128 scoped_ptr<CCRenderPassDrawQuad> quad = CCRenderPassDrawQuad::cr eate(testData.sharedQuadState.get(), quadRect, newRenderPassId, isReplica, 1, co ntentsChangedRect, 1, 1, 0, 0);
4129 static_cast<CCTestRenderPass*>(renderPass.get())->appendQuad(qua d.PassAs<CCDrawQuad>());
4130 }
4131 }
4132 testData.renderPasses.insert(testData.renderPasses.begin(), renderPass.g et());
4133 testData.renderPassesById.add(renderPassId, renderPass.Pass());
4134 if (*currentChar)
4135 currentChar++;
4136 }
4137 }
4138
4139 void dumpRenderPassTestData(const RenderPassRemovalTestData& testData, char* buf fer)
4140 {
4141 char* pos = buffer;
4142 for (CCRenderPassList::const_reverse_iterator it = testData.renderPasses.rbe gin(); it != testData.renderPasses.rend(); ++it) {
4143 const CCRenderPass* currentPass = *it;
4144 *pos = currentPass->id().layerId;
4145 pos++;
4146 *pos = currentPass->id().index;
4147 pos++;
4148
4149 CCQuadList::const_iterator quadListIterator = currentPass->quadList().be gin();
4150 while (quadListIterator != currentPass->quadList().end()) {
4151 CCDrawQuad* currentQuad = *quadListIterator;
4152 switch (currentQuad->material()) {
4153 case CCDrawQuad::SolidColor:
4154 *pos = 's';
4155 pos++;
4156 break;
4157 case CCDrawQuad::RenderPass:
4158 *pos = CCRenderPassDrawQuad::materialCast(currentQuad)->renderPa ssId().layerId;
4159 pos++;
4160 *pos = CCRenderPassDrawQuad::materialCast(currentQuad)->renderPa ssId().index;
4161 pos++;
4162 break;
4163 default:
4164 *pos = 'x';
4165 pos++;
4166 break;
4167 }
4168
4169 quadListIterator++;
4170 }
4171 *pos = '\n';
4172 pos++;
4173 }
4174 *pos = '\0';
4175 }
4176
4177 // Each CCRenderPassList is represented by a string which describes the configur ation.
4178 // The syntax of the string is as follows:
4179 //
4180 // RsssssX[c]ssYsssZ[t]ssW[ ct]
4181 // Identifies the render pass---------------------------^ ^^^ ^ ^ ^ ^ ^
4182 // These are solid color quads-----------------------------+ | | | | |
4183 // Identifies RenderPassDrawQuad's RenderPass-----------------+ | | | |
4184 // This quad's contents didn't change---------------------------+ | | |
4185 // This quad's contents changed and it has no texture---------------+ | |
4186 // This quad has texture but its contents changed-------------------------+ |
4187 // This quad's contents didn't change and it has texture - will be removed------ +
4188 //
4189 // Expected results have exactly the same syntax, except they do not use square brackets,
4190 // since we only check the structure, not attributes.
4191 //
4192 // Test case configuration consists of initialization script and expected result s,
4193 // all in the same format.
4194 struct TestCase {
4195 const char* name;
4196 const char* initScript;
4197 const char* expectedResult;
4198 };
4199
4200 TestCase removeRenderPassesCases[] =
4201 {
4202 {
4203 "Single root pass",
4204 "R0ssss\n",
4205 "R0ssss\n"
4206 }, {
4207 "Single pass - no quads",
4208 "R0\n",
4209 "R0\n"
4210 }, {
4211 "Two passes, no removal",
4212 "R0ssssA0sss\n"
4213 "A0ssss\n",
4214 "R0ssssA0sss\n"
4215 "A0ssss\n"
4216 }, {
4217 "Two passes, remove last",
4218 "R0ssssA0[ct]sss\n"
4219 "A0ssss\n",
4220 "R0ssssA0sss\n"
4221 }, {
4222 "Have texture but contents changed - leave pass",
4223 "R0ssssA0[t]sss\n"
4224 "A0ssss\n",
4225 "R0ssssA0sss\n"
4226 "A0ssss\n"
4227 }, {
4228 "Contents didn't change but no texture - leave pass",
4229 "R0ssssA0[c]sss\n"
4230 "A0ssss\n",
4231 "R0ssssA0sss\n"
4232 "A0ssss\n"
4233 }, {
4234 "Replica: two quads reference the same pass; remove",
4235 "R0ssssA0[ct]A0[ct]sss\n"
4236 "A0ssss\n",
4237 "R0ssssA0A0sss\n"
4238 }, {
4239 "Replica: two quads reference the same pass; leave",
4240 "R0ssssA0[c]A0[c]sss\n"
4241 "A0ssss\n",
4242 "R0ssssA0A0sss\n"
4243 "A0ssss\n",
4244 }, {
4245 "Many passes, remove all",
4246 "R0ssssA0[ct]sss\n"
4247 "A0sssB0[ct]C0[ct]s\n"
4248 "B0sssD0[ct]ssE0[ct]F0[ct]\n"
4249 "E0ssssss\n"
4250 "C0G0[ct]\n"
4251 "D0sssssss\n"
4252 "F0sssssss\n"
4253 "G0sss\n",
4254
4255 "R0ssssA0sss\n"
4256 }, {
4257 "Deep recursion, remove all",
4258
4259 "R0sssssA0[ct]ssss\n"
4260 "A0ssssB0sss\n"
4261 "B0C0\n"
4262 "C0D0\n"
4263 "D0E0\n"
4264 "E0F0\n"
4265 "F0G0\n"
4266 "G0H0\n"
4267 "H0sssI0sss\n"
4268 "I0J0\n"
4269 "J0ssss\n",
4270
4271 "R0sssssA0ssss\n"
4272 }, {
4273 "Wide recursion, remove all",
4274 "R0A0[ct]B0[ct]C0[ct]D0[ct]E0[ct]F0[ct]G0[ct]H0[ct]I0[ct]J0[ct]\n"
4275 "A0s\n"
4276 "B0s\n"
4277 "C0ssss\n"
4278 "D0ssss\n"
4279 "E0s\n"
4280 "F0\n"
4281 "G0s\n"
4282 "H0s\n"
4283 "I0s\n"
4284 "J0ssss\n",
4285
4286 "R0A0B0C0D0E0F0G0H0I0J0\n"
4287 }, {
4288 "Remove passes regardless of cache state",
4289 "R0ssssA0[ct]sss\n"
4290 "A0sssB0C0s\n"
4291 "B0sssD0[c]ssE0[t]F0\n"
4292 "E0ssssss\n"
4293 "C0G0\n"
4294 "D0sssssss\n"
4295 "F0sssssss\n"
4296 "G0sss\n",
4297
4298 "R0ssssA0sss\n"
4299 }, {
4300 "Leave some passes, remove others",
4301
4302 "R0ssssA0[c]sss\n"
4303 "A0sssB0[t]C0[ct]s\n"
4304 "B0sssD0[c]ss\n"
4305 "C0G0\n"
4306 "D0sssssss\n"
4307 "G0sss\n",
4308
4309 "R0ssssA0sss\n"
4310 "A0sssB0C0s\n"
4311 "B0sssD0ss\n"
4312 "D0sssssss\n"
4313 }, {
4314 0, 0, 0
4315 }
4316 };
4317
4318 static void verifyRenderPassTestData(TestCase& testCase, RenderPassRemovalTestDa ta& testData)
4319 {
4320 char actualResult[1024];
4321 dumpRenderPassTestData(testData, actualResult);
4322 EXPECT_STREQ(testCase.expectedResult, actualResult) << "In test case: " << t estCase.name;
4323 }
4324
4325 TEST_P(CCLayerTreeHostImplTest, testRemoveRenderPasses)
4326 {
4327 scoped_ptr<CCGraphicsContext> context(createContext());
4328 ASSERT_TRUE(context->context3D());
4329 OwnPtr<CCResourceProvider> resourceProvider(CCResourceProvider::create(conte xt.get()));
4330
4331 OwnPtr<CCTestRenderer> renderer(CCTestRenderer::create(resourceProvider.get( )));
4332
4333 int testCaseIndex = 0;
4334 while (removeRenderPassesCases[testCaseIndex].name) {
4335 RenderPassRemovalTestData testData;
4336 configureRenderPassTestData(removeRenderPassesCases[testCaseIndex].initS cript, testData, renderer.get());
4337 CCLayerTreeHostImpl::removeRenderPasses(CCLayerTreeHostImpl::CullRenderP assesWithCachedTextures(*renderer), testData);
4338 verifyRenderPassTestData(removeRenderPassesCases[testCaseIndex], testDat a);
4339 testCaseIndex++;
4340 }
4341 }
4342
4343 INSTANTIATE_TEST_CASE_P(CCLayerTreeHostImplTests,
4344 CCLayerTreeHostImplTest,
4345 ::testing::Values(false, true));
4346
4347 } // namespace
OLDNEW
« no previous file with comments | « cc/CCLayerTreeHostCommonTest.cpp ('k') | cc/CCLayerTreeHostTest.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698