951859650626948d0b6d5f66e93b27a908cb1079
[WebKit-https.git] / Source / WebKit / chromium / tests / CCLayerTreeHostTest.cpp
1 /*
2  * Copyright (C) 2011 Google Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1.  Redistributions of source code must retain the above copyright
8  *     notice, this list of conditions and the following disclaimer.
9  * 2.  Redistributions in binary form must reproduce the above copyright
10  *     notice, this list of conditions and the following disclaimer in the
11  *     documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
16  * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
17  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
20  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
22  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23  */
24
25 #include "config.h"
26
27 #include "cc/CCLayerTreeHost.h"
28
29 #include "CompositorFakeGraphicsContext3D.h"
30 #include "ContentLayerChromium.h"
31 #include "FakeWebGraphicsContext3D.h"
32 #include "LayerChromium.h"
33 #include "TextureManager.h"
34 #include "WebCompositor.h"
35 #include "WebKit.h"
36 #include "cc/CCLayerImpl.h"
37 #include "cc/CCLayerTreeHostImpl.h"
38 #include "cc/CCScopedThreadProxy.h"
39 #include "cc/CCTextureUpdater.h"
40 #include "cc/CCThreadTask.h"
41 #include "platform/WebKitPlatformSupport.h"
42 #include "platform/WebThread.h"
43 #include <gtest/gtest.h>
44 #include <webkit/support/webkit_support.h>
45 #include <wtf/MainThread.h>
46 #include <wtf/PassRefPtr.h>
47 #include <wtf/Vector.h>
48
49 using namespace WebCore;
50 using namespace WebKit;
51 using namespace WTF;
52
53 namespace {
54
55 // Used by test stubs to notify the test when something interesting happens.
56 class TestHooks {
57 public:
58     virtual void beginCommitOnCCThread(CCLayerTreeHostImpl*) { }
59     virtual void commitCompleteOnCCThread(CCLayerTreeHostImpl*) { }
60     virtual void drawLayersOnCCThread(CCLayerTreeHostImpl*) { }
61     virtual void applyScrollAndScale(const IntSize&, float) { }
62     virtual void updateAnimations(double frameBeginTime) { }
63     virtual void layout() { }
64 };
65
66 // Adapts CCLayerTreeHostImpl for test. Runs real code, then invokes test hooks.
67 class MockLayerTreeHostImpl : public CCLayerTreeHostImpl {
68 public:
69     static PassOwnPtr<MockLayerTreeHostImpl> create(TestHooks* testHooks, const CCSettings& settings, CCLayerTreeHostImplClient* client)
70     {
71         return adoptPtr(new MockLayerTreeHostImpl(testHooks, settings, client));
72     }
73
74     virtual void beginCommit()
75     {
76         CCLayerTreeHostImpl::beginCommit();
77         m_testHooks->beginCommitOnCCThread(this);
78     }
79
80     virtual void commitComplete()
81     {
82         CCLayerTreeHostImpl::commitComplete();
83         m_testHooks->commitCompleteOnCCThread(this);
84     }
85
86     virtual void drawLayers()
87     {
88         CCLayerTreeHostImpl::drawLayers();
89         m_testHooks->drawLayersOnCCThread(this);
90     }
91
92 private:
93     MockLayerTreeHostImpl(TestHooks* testHooks, const CCSettings& settings, CCLayerTreeHostImplClient* client)
94         : CCLayerTreeHostImpl(settings, client)
95         , m_testHooks(testHooks)
96     {
97     }
98
99     TestHooks* m_testHooks;
100 };
101
102 // Adapts CCLayerTreeHost for test. Injects MockLayerTreeHostImpl.
103 class MockLayerTreeHost : public CCLayerTreeHost {
104 public:
105     static PassRefPtr<MockLayerTreeHost> create(TestHooks* testHooks, CCLayerTreeHostClient* client, PassRefPtr<LayerChromium> rootLayer, const CCSettings& settings)
106     {
107         RefPtr<MockLayerTreeHost> layerTreeHost = adoptRef(new MockLayerTreeHost(testHooks, client, settings));
108         bool success = layerTreeHost->initialize();
109         EXPECT_TRUE(success);
110         layerTreeHost->setRootLayer(rootLayer);
111
112         // LayerTreeHostImpl won't draw if it has 1x1 viewport.
113         layerTreeHost->setViewportSize(IntSize(1, 1));
114
115         return layerTreeHost.release();
116     }
117
118     virtual PassOwnPtr<CCLayerTreeHostImpl> createLayerTreeHostImpl(CCLayerTreeHostImplClient* client)
119     {
120         return MockLayerTreeHostImpl::create(m_testHooks, settings(), client);
121     }
122
123 private:
124     MockLayerTreeHost(TestHooks* testHooks, CCLayerTreeHostClient* client, const CCSettings& settings)
125         : CCLayerTreeHost(client, settings)
126         , m_testHooks(testHooks)
127     {
128     }
129
130     TestHooks* m_testHooks;
131 };
132
133 // Implementation of CCLayerTreeHost callback interface.
134 class MockLayerTreeHostClient : public CCLayerTreeHostClient {
135 public:
136     static PassOwnPtr<MockLayerTreeHostClient> create(TestHooks* testHooks)
137     {
138         return adoptPtr(new MockLayerTreeHostClient(testHooks));
139     }
140
141     virtual void updateAnimations(double frameBeginTime)
142     {
143         m_testHooks->updateAnimations(frameBeginTime);
144     }
145
146     virtual void layout()
147     {
148         m_testHooks->layout();
149     }
150
151     virtual void applyScrollAndScale(const IntSize& scrollDelta, float scale)
152     {
153         m_testHooks->applyScrollAndScale(scrollDelta, scale);
154     }
155
156     virtual PassRefPtr<GraphicsContext3D> createLayerTreeHostContext3D()
157     {
158         return createCompositorMockGraphicsContext3D(GraphicsContext3D::Attributes());
159     }
160
161     virtual void didCommitAndDrawFrame()
162     {
163     }
164
165     virtual void didCompleteSwapBuffers()
166     {
167     }
168
169     virtual void didRecreateGraphicsContext(bool)
170     {
171     }
172
173     virtual void scheduleComposite() { }
174
175 private:
176     explicit MockLayerTreeHostClient(TestHooks* testHooks) : m_testHooks(testHooks) { }
177
178     TestHooks* m_testHooks;
179 };
180
181 // The CCLayerTreeHostTest runs with the main loop running. It instantiates a single MockLayerTreeHost and associated
182 // MockLayerTreeHostImpl/MockLayerTreeHostClient.
183 //
184 // beginTest() is called once the main message loop is running and the layer tree host is initialized.
185 //
186 // Key stages of the drawing loop, e.g. drawing or commiting, redirect to CCLayerTreeHostTest methods of similar names.
187 // To track the commit process, override these functions.
188 //
189 // The test continues until someone calls endTest. endTest can be called on any thread, but be aware that
190 // ending the test is an asynchronous process.
191 class CCLayerTreeHostTest : public testing::Test, TestHooks {
192 public:
193     virtual void afterTest() = 0;
194     virtual void beginTest() = 0;
195
196     void endTest();
197
198     void postSetNeedsAnimateToMainThread()
199     {
200         callOnMainThread(CCLayerTreeHostTest::dispatchSetNeedsAnimate, this);
201     }
202
203     void postSetNeedsCommitToMainThread()
204     {
205         callOnMainThread(CCLayerTreeHostTest::dispatchSetNeedsCommit, this);
206     }
207
208     void postSetNeedsRedrawToMainThread()
209     {
210         callOnMainThread(CCLayerTreeHostTest::dispatchSetNeedsRedraw, this);
211     }
212
213     void postSetNeedsAnimateAndCommitToMainThread()
214     {
215         callOnMainThread(CCLayerTreeHostTest::dispatchSetNeedsAnimateAndCommit, this);
216     }
217
218
219     void postSetVisibleToMainThread(bool visible)
220     {
221         callOnMainThread(visible ? CCLayerTreeHostTest::dispatchSetVisible : CCLayerTreeHostTest::dispatchSetInvisible, this);
222     }
223
224     void timeout()
225     {
226         m_timedOut = true;
227         endTest();
228     }
229
230     void clearTimeout()
231     {
232         m_timeoutTask = 0;
233     }
234
235     CCLayerTreeHost* layerTreeHost() { return m_layerTreeHost.get(); }
236
237
238 protected:
239     CCLayerTreeHostTest()
240         : m_beginning(false)
241         , m_endWhenBeginReturns(false)
242         , m_timedOut(false) { }
243
244     void doBeginTest();
245
246     static void onBeginTest(void* self)
247     {
248         static_cast<CCLayerTreeHostTest*>(self)->doBeginTest();
249     }
250
251     static void onEndTest(void* self)
252     {
253         ASSERT(isMainThread());
254         webkit_support::QuitMessageLoop();
255         webkit_support::RunAllPendingMessages();
256     }
257
258     static void dispatchSetNeedsAnimate(void* self)
259     {
260       ASSERT(isMainThread());
261       CCLayerTreeHostTest* test = static_cast<CCLayerTreeHostTest*>(self);
262       ASSERT(test);
263       if (test->m_layerTreeHost)
264           test->m_layerTreeHost->setNeedsAnimate();
265     }
266
267     static void dispatchSetNeedsAnimateAndCommit(void* self)
268     {
269       ASSERT(isMainThread());
270       CCLayerTreeHostTest* test = static_cast<CCLayerTreeHostTest*>(self);
271       ASSERT(test);
272       if (test->m_layerTreeHost) {
273           test->m_layerTreeHost->setNeedsAnimate();
274           test->m_layerTreeHost->setNeedsCommit();
275       }
276     }
277
278     static void dispatchSetNeedsCommit(void* self)
279     {
280       ASSERT(isMainThread());
281       CCLayerTreeHostTest* test = static_cast<CCLayerTreeHostTest*>(self);
282       ASSERT_TRUE(test);
283       if (test->m_layerTreeHost)
284           test->m_layerTreeHost->setNeedsCommit();
285     }
286
287     static void dispatchSetNeedsRedraw(void* self)
288     {
289       ASSERT(isMainThread());
290       CCLayerTreeHostTest* test = static_cast<CCLayerTreeHostTest*>(self);
291       ASSERT_TRUE(test);
292       if (test->m_layerTreeHost)
293           test->m_layerTreeHost->setNeedsRedraw();
294     }
295
296     static void dispatchSetVisible(void* self)
297     {
298       ASSERT(isMainThread());
299       CCLayerTreeHostTest* test = static_cast<CCLayerTreeHostTest*>(self);
300       ASSERT(test);
301       if (test->m_layerTreeHost)
302           test->m_layerTreeHost->setVisible(true);
303     }
304
305     static void dispatchSetInvisible(void* self)
306     {
307       ASSERT(isMainThread());
308       CCLayerTreeHostTest* test = static_cast<CCLayerTreeHostTest*>(self);
309       ASSERT(test);
310       if (test->m_layerTreeHost)
311           test->m_layerTreeHost->setVisible(false);
312     }
313
314     class TimeoutTask : public webkit_support::TaskAdaptor {
315     public:
316         explicit TimeoutTask(CCLayerTreeHostTest* test)
317             : m_test(test)
318         {
319         }
320
321         void clearTest()
322         {
323             m_test = 0;
324         }
325
326         virtual ~TimeoutTask()
327         {
328             if (m_test)
329                 m_test->clearTimeout();
330         }
331
332         virtual void Run()
333         {
334             if (m_test)
335                 m_test->timeout();
336         }
337
338     private:
339         CCLayerTreeHostTest* m_test;
340     };
341
342     virtual void runTest(bool threaded)
343     {
344         m_settings.refreshRate = 100.0;
345
346         if (threaded) {
347             m_webThread = adoptPtr(webKitPlatformSupport()->createThread("CCLayerTreeHostTest"));
348             WebCompositor::initialize(m_webThread.get());
349         } else
350             WebCompositor::initialize(0);
351
352         ASSERT(CCProxy::isMainThread());
353         m_mainThreadProxy = CCScopedThreadProxy::create(CCProxy::mainThread());
354
355         webkit_support::PostDelayedTask(CCLayerTreeHostTest::onBeginTest, static_cast<void*>(this), 0);
356         m_timeoutTask = new TimeoutTask(this);
357         webkit_support::PostDelayedTask(m_timeoutTask, 5000); // webkit_support takes ownership of the task
358         webkit_support::RunMessageLoop();
359         webkit_support::RunAllPendingMessages();
360
361         if (m_layerTreeHost && m_layerTreeHost->rootLayer())
362             m_layerTreeHost->rootLayer()->setLayerTreeHost(0);
363         m_layerTreeHost.clear();
364
365         if (m_timeoutTask)
366             m_timeoutTask->clearTest();
367
368         ASSERT_FALSE(m_layerTreeHost.get());
369         m_client.clear();
370         if (m_timedOut) {
371             FAIL() << "Test timed out";
372             WebCompositor::shutdown();
373             return;
374         }
375         afterTest();
376         WebCompositor::shutdown();
377     }
378
379     CCSettings m_settings;
380     OwnPtr<MockLayerTreeHostClient> m_client;
381     RefPtr<CCLayerTreeHost> m_layerTreeHost;
382
383 private:
384     bool m_beginning;
385     bool m_endWhenBeginReturns;
386     bool m_timedOut;
387
388     OwnPtr<WebThread> m_webThread;
389     RefPtr<CCScopedThreadProxy> m_mainThreadProxy;
390     TimeoutTask* m_timeoutTask;
391 };
392
393 void CCLayerTreeHostTest::doBeginTest()
394 {
395     ASSERT(isMainThread());
396     m_client = MockLayerTreeHostClient::create(this);
397
398     RefPtr<LayerChromium> rootLayer = LayerChromium::create();
399     m_layerTreeHost = MockLayerTreeHost::create(this, m_client.get(), rootLayer, m_settings);
400     ASSERT_TRUE(m_layerTreeHost);
401     rootLayer->setLayerTreeHost(m_layerTreeHost.get());
402
403     m_beginning = true;
404     beginTest();
405     m_beginning = false;
406     if (m_endWhenBeginReturns)
407         onEndTest(static_cast<void*>(this));
408 }
409
410 void CCLayerTreeHostTest::endTest()
411 {
412     // If we are called from the CCThread, re-call endTest on the main thread.
413     if (!isMainThread())
414         m_mainThreadProxy->postTask(createCCThreadTask(this, &CCLayerTreeHostTest::endTest));
415     else {
416         // For the case where we endTest during beginTest(), set a flag to indicate that
417         // the test should end the second beginTest regains control.
418         if (m_beginning)
419             m_endWhenBeginReturns = true;
420         else
421             onEndTest(static_cast<void*>(this));
422     }
423 }
424
425 class CCLayerTreeHostTestThreadOnly : public CCLayerTreeHostTest {
426 public:
427     void runTestThreaded()
428     {
429         CCLayerTreeHostTest::runTest(true);
430     }
431 };
432
433 // Shortlived layerTreeHosts shouldn't die.
434 class CCLayerTreeHostTestShortlived1 : public CCLayerTreeHostTest {
435 public:
436     CCLayerTreeHostTestShortlived1() { }
437
438     virtual void beginTest()
439     {
440         // Kill the layerTreeHost immediately.
441         m_layerTreeHost->setRootLayer(0);
442         m_layerTreeHost.clear();
443
444         endTest();
445     }
446
447     virtual void afterTest()
448     {
449     }
450 };
451
452 #define SINGLE_AND_MULTI_THREAD_TEST_F(TEST_FIXTURE_NAME) \
453     TEST_F(TEST_FIXTURE_NAME, runSingleThread)            \
454     {                                                     \
455         runTest(false);                                   \
456     }                                                     \
457     TEST_F(TEST_FIXTURE_NAME, runMultiThread)             \
458     {                                                     \
459         runTest(true);                                    \
460     }
461
462 SINGLE_AND_MULTI_THREAD_TEST_F(CCLayerTreeHostTestShortlived1)
463
464 // Shortlived layerTreeHosts shouldn't die with a commit in flight.
465 class CCLayerTreeHostTestShortlived2 : public CCLayerTreeHostTest {
466 public:
467     CCLayerTreeHostTestShortlived2() { }
468
469     virtual void beginTest()
470     {
471         postSetNeedsCommitToMainThread();
472
473         // Kill the layerTreeHost immediately.
474         m_layerTreeHost->setRootLayer(0);
475         m_layerTreeHost.clear();
476
477         endTest();
478     }
479
480     virtual void afterTest()
481     {
482     }
483 };
484
485 SINGLE_AND_MULTI_THREAD_TEST_F(CCLayerTreeHostTestShortlived2)
486
487 // Shortlived layerTreeHosts shouldn't die with a redraw in flight.
488 class CCLayerTreeHostTestShortlived3 : public CCLayerTreeHostTest {
489 public:
490     CCLayerTreeHostTestShortlived3() { }
491
492     virtual void beginTest()
493     {
494         postSetNeedsRedrawToMainThread();
495
496         // Kill the layerTreeHost immediately.
497         m_layerTreeHost->setRootLayer(0);
498         m_layerTreeHost.clear();
499
500         endTest();
501     }
502
503     virtual void afterTest()
504     {
505     }
506 };
507
508 SINGLE_AND_MULTI_THREAD_TEST_F(CCLayerTreeHostTestShortlived3)
509
510 // Test interleaving of redraws and commits
511 class CCLayerTreeHostTestCommitingWithContinuousRedraw : public CCLayerTreeHostTestThreadOnly {
512 public:
513     CCLayerTreeHostTestCommitingWithContinuousRedraw()
514         : m_numCompleteCommits(0)
515         , m_numDraws(0)
516     {
517     }
518
519     virtual void beginTest()
520     {
521         postSetNeedsCommitToMainThread();
522     }
523
524     virtual void commitCompleteOnCCThread(CCLayerTreeHostImpl*)
525     {
526         m_numCompleteCommits++;
527         if (m_numCompleteCommits == 2)
528             endTest();
529     }
530
531     virtual void drawLayersOnCCThread(CCLayerTreeHostImpl*)
532     {
533         if (m_numDraws == 1)
534           postSetNeedsCommitToMainThread();
535         m_numDraws++;
536         postSetNeedsRedrawToMainThread();
537     }
538
539     virtual void afterTest()
540     {
541     }
542
543 private:
544     int m_numCompleteCommits;
545     int m_numDraws;
546 };
547
548 TEST_F(CCLayerTreeHostTestCommitingWithContinuousRedraw, runMultiThread)
549 {
550     runTestThreaded();
551 }
552
553 // Two setNeedsCommits in a row should lead to at least 1 commit and at least 1
554 // draw with frame 0.
555 class CCLayerTreeHostTestSetNeedsCommit1 : public CCLayerTreeHostTestThreadOnly {
556 public:
557     CCLayerTreeHostTestSetNeedsCommit1()
558         : m_numCommits(0)
559         , m_numDraws(0)
560     {
561     }
562
563     virtual void beginTest()
564     {
565         postSetNeedsCommitToMainThread();
566         postSetNeedsCommitToMainThread();
567     }
568
569     virtual void drawLayersOnCCThread(CCLayerTreeHostImpl* impl)
570     {
571         m_numDraws++;
572         if (!impl->sourceFrameNumber())
573             endTest();
574     }
575
576     virtual void commitCompleteOnCCThread(CCLayerTreeHostImpl*)
577     {
578         m_numCommits++;
579     }
580
581     virtual void afterTest()
582     {
583         EXPECT_GE(1, m_numCommits);
584         EXPECT_GE(1, m_numDraws);
585     }
586
587 private:
588     int m_numCommits;
589     int m_numDraws;
590 };
591
592 TEST_F(CCLayerTreeHostTestSetNeedsCommit1, DISABLED_runMultiThread)
593 {
594     runTestThreaded();
595 }
596
597 // A setNeedsCommit should lead to 1 commit. Issuing a second commit after that
598 // first committed frame draws should lead to another commit.
599 class CCLayerTreeHostTestSetNeedsCommit2 : public CCLayerTreeHostTestThreadOnly {
600 public:
601     CCLayerTreeHostTestSetNeedsCommit2()
602         : m_numCommits(0)
603         , m_numDraws(0)
604     {
605     }
606
607     virtual void beginTest()
608     {
609         postSetNeedsCommitToMainThread();
610     }
611
612     virtual void drawLayersOnCCThread(CCLayerTreeHostImpl* impl)
613     {
614         if (!impl->sourceFrameNumber())
615             postSetNeedsCommitToMainThread();
616         else if (impl->sourceFrameNumber() == 1)
617             endTest();
618     }
619
620     virtual void commitCompleteOnCCThread(CCLayerTreeHostImpl*)
621     {
622         m_numCommits++;
623     }
624
625     virtual void afterTest()
626     {
627         EXPECT_EQ(2, m_numCommits);
628         EXPECT_GE(2, m_numDraws);
629     }
630
631 private:
632     int m_numCommits;
633     int m_numDraws;
634 };
635
636 TEST_F(CCLayerTreeHostTestSetNeedsCommit2, runMultiThread)
637 {
638     runTestThreaded();
639 }
640
641 // 1 setNeedsRedraw after the first commit has completed should lead to 1
642 // additional draw.
643 class CCLayerTreeHostTestSetNeedsRedraw : public CCLayerTreeHostTestThreadOnly {
644 public:
645     CCLayerTreeHostTestSetNeedsRedraw()
646         : m_numCommits(0)
647         , m_numDraws(0)
648     {
649     }
650
651     virtual void beginTest()
652     {
653         postSetNeedsCommitToMainThread();
654     }
655
656     virtual void drawLayersOnCCThread(CCLayerTreeHostImpl* impl)
657     {
658         EXPECT_EQ(0, impl->sourceFrameNumber());
659         if (!m_numDraws)
660             postSetNeedsRedrawToMainThread(); // Redraw again to verify that the second redraw doesn't commit.
661         else
662             endTest();
663         m_numDraws++;
664     }
665
666     virtual void commitCompleteOnCCThread(CCLayerTreeHostImpl*)
667     {
668         EXPECT_EQ(0, m_numDraws);
669         m_numCommits++;
670     }
671
672     virtual void afterTest()
673     {
674         EXPECT_GE(2, m_numDraws);
675         EXPECT_EQ(1, m_numCommits);
676     }
677
678 private:
679     int m_numCommits;
680     int m_numDraws;
681 };
682
683 TEST_F(CCLayerTreeHostTestSetNeedsRedraw, runMultiThread)
684 {
685     runTestThreaded();
686 }
687
688 // Trigger a frame with setNeedsCommit. Then, inside the resulting animate
689 // callback, requet another frame using setNeedsAnimate. End the test when
690 // animate gets called yet-again, indicating that the proxy is correctly
691 // handling the case where setNeedsAnimate() is called inside the begin frame
692 // flow.
693 class CCLayerTreeHostTestSetNeedsAnimateInsideAnimationCallback : public CCLayerTreeHostTestThreadOnly {
694 public:
695     CCLayerTreeHostTestSetNeedsAnimateInsideAnimationCallback()
696         : m_numAnimates(0)
697     {
698     }
699
700     virtual void beginTest()
701     {
702         postSetNeedsAnimateToMainThread();
703     }
704
705     virtual void updateAnimations(double)
706     {
707         if (!m_numAnimates) {
708             m_layerTreeHost->setNeedsAnimate();
709             m_numAnimates++;
710             return;
711         }
712         endTest();
713     }
714
715     virtual void afterTest()
716     {
717     }
718
719 private:
720     int m_numAnimates;
721 };
722
723 TEST_F(CCLayerTreeHostTestSetNeedsAnimateInsideAnimationCallback, runMultiThread)
724 {
725     runTestThreaded();
726 }
727
728 class CCLayerTreeHostTestScrollSimple : public CCLayerTreeHostTestThreadOnly {
729 public:
730     CCLayerTreeHostTestScrollSimple()
731         : m_initialScroll(IntPoint(10, 20))
732         , m_secondScroll(IntPoint(40, 5))
733         , m_scrollAmount(2, -1)
734         , m_scrolls(0)
735     {
736     }
737
738     virtual void beginTest()
739     {
740         m_layerTreeHost->rootLayer()->setScrollable(true);
741         m_layerTreeHost->rootLayer()->setScrollPosition(m_initialScroll);
742         postSetNeedsCommitToMainThread();
743     }
744
745     virtual void layout()
746     {
747         LayerChromium* root = m_layerTreeHost->rootLayer();
748         if (!m_layerTreeHost->frameNumber())
749             EXPECT_EQ(root->scrollPosition(), m_initialScroll);
750         else {
751             EXPECT_EQ(root->scrollPosition(), m_initialScroll + m_scrollAmount);
752
753             // Pretend like Javascript updated the scroll position itself.
754             root->setScrollPosition(m_secondScroll);
755         }
756     }
757
758     virtual void drawLayersOnCCThread(CCLayerTreeHostImpl* impl)
759     {
760         CCLayerImpl* root = impl->rootLayer();
761         EXPECT_EQ(root->scrollDelta(), IntSize());
762
763         root->setScrollable(true);
764         root->setMaxScrollPosition(IntSize(100, 100));
765         root->scrollBy(m_scrollAmount);
766
767         if (impl->frameNumber() == 1) {
768             EXPECT_EQ(root->scrollPosition(), m_initialScroll);
769             EXPECT_EQ(root->scrollDelta(), m_scrollAmount);
770             postSetNeedsCommitToMainThread();
771         } else if (impl->frameNumber() == 2) {
772             EXPECT_EQ(root->scrollPosition(), m_secondScroll);
773             EXPECT_EQ(root->scrollDelta(), m_scrollAmount);
774             endTest();
775         }
776     }
777
778     virtual void applyScrollAndScale(const IntSize& scrollDelta, float scale)
779     {
780         IntPoint position = m_layerTreeHost->rootLayer()->scrollPosition();
781         m_layerTreeHost->rootLayer()->setScrollPosition(position + scrollDelta);
782         m_scrolls++;
783     }
784
785     virtual void afterTest()
786     {
787         EXPECT_EQ(1, m_scrolls);
788     }
789 private:
790     IntPoint m_initialScroll;
791     IntPoint m_secondScroll;
792     IntSize m_scrollAmount;
793     int m_scrolls;
794 };
795
796 TEST_F(CCLayerTreeHostTestScrollSimple, DISABLED_runMultiThread)
797 {
798     runTestThreaded();
799 }
800
801 class CCLayerTreeHostTestScrollMultipleRedraw : public CCLayerTreeHostTestThreadOnly {
802 public:
803     CCLayerTreeHostTestScrollMultipleRedraw()
804         : m_initialScroll(IntPoint(40, 10))
805         , m_scrollAmount(-3, 17)
806         , m_scrolls(0)
807     {
808     }
809
810     virtual void beginTest()
811     {
812         m_layerTreeHost->rootLayer()->setScrollable(true);
813         m_layerTreeHost->rootLayer()->setScrollPosition(m_initialScroll);
814         postSetNeedsCommitToMainThread();
815     }
816
817     virtual void beginCommitOnCCThread(CCLayerTreeHostImpl* impl)
818     {
819         LayerChromium* root = m_layerTreeHost->rootLayer();
820         if (!m_layerTreeHost->frameNumber())
821             EXPECT_EQ(root->scrollPosition(), m_initialScroll);
822         else if (m_layerTreeHost->frameNumber() == 1)
823             EXPECT_EQ(root->scrollPosition(), m_initialScroll + m_scrollAmount + m_scrollAmount);
824         else if (m_layerTreeHost->frameNumber() == 2)
825             EXPECT_EQ(root->scrollPosition(), m_initialScroll + m_scrollAmount + m_scrollAmount);
826     }
827
828     virtual void drawLayersOnCCThread(CCLayerTreeHostImpl* impl)
829     {
830         CCLayerImpl* root = impl->rootLayer();
831         root->setScrollable(true);
832         root->setMaxScrollPosition(IntSize(100, 100));
833
834         if (impl->frameNumber() == 1) {
835             EXPECT_EQ(root->scrollDelta(), IntSize());
836             root->scrollBy(m_scrollAmount);
837             EXPECT_EQ(root->scrollDelta(), m_scrollAmount);
838
839             EXPECT_EQ(root->scrollPosition(), m_initialScroll);
840             postSetNeedsRedrawToMainThread();
841         } else if (impl->frameNumber() == 2) {
842             EXPECT_EQ(root->scrollDelta(), m_scrollAmount);
843             root->scrollBy(m_scrollAmount);
844             EXPECT_EQ(root->scrollDelta(), m_scrollAmount + m_scrollAmount);
845
846             EXPECT_EQ(root->scrollPosition(), m_initialScroll);
847             postSetNeedsCommitToMainThread();
848         } else if (impl->frameNumber() == 3) {
849             EXPECT_EQ(root->scrollDelta(), IntSize());
850             EXPECT_EQ(root->scrollPosition(), m_initialScroll + m_scrollAmount + m_scrollAmount);
851             endTest();
852         }
853     }
854
855     virtual void applyScrollAndScale(const IntSize& scrollDelta, float scale)
856     {
857         IntPoint position = m_layerTreeHost->rootLayer()->scrollPosition();
858         m_layerTreeHost->rootLayer()->setScrollPosition(position + scrollDelta);
859         m_scrolls++;
860     }
861
862     virtual void afterTest()
863     {
864         EXPECT_EQ(1, m_scrolls);
865     }
866 private:
867     IntPoint m_initialScroll;
868     IntSize m_scrollAmount;
869     int m_scrolls;
870 };
871
872 TEST_F(CCLayerTreeHostTestScrollMultipleRedraw, DISABLED_runMultiThread)
873 {
874     runTestThreaded();
875 }
876
877 class CCLayerTreeHostTestSetVisible : public CCLayerTreeHostTest {
878 public:
879
880     CCLayerTreeHostTestSetVisible()
881         : m_numCommits(0)
882         , m_numDraws(0)
883     {
884     }
885
886     virtual void beginTest()
887     {
888         postSetVisibleToMainThread(false);
889         postSetNeedsRedrawToMainThread(); // This is suppressed while we're invisible.
890         postSetVisibleToMainThread(true); // Triggers the redraw.
891     }
892
893     virtual void drawLayersOnCCThread(CCLayerTreeHostImpl* impl)
894     {
895         EXPECT_TRUE(impl->visible());
896         ++m_numDraws;
897         endTest();
898     }
899
900     virtual void afterTest()
901     {
902         EXPECT_EQ(1, m_numDraws);
903     }
904
905 private:
906     int m_numCommits;
907     int m_numDraws;
908 };
909
910 TEST_F(CCLayerTreeHostTestSetVisible, runMultiThread)
911 {
912     runTest(true);
913 }
914
915 class TestOpacityChangeLayerDelegate : public ContentLayerDelegate {
916 public:
917     TestOpacityChangeLayerDelegate(CCLayerTreeHostTest* test)
918         : m_test(test)
919     {
920     }
921
922     virtual void paintContents(GraphicsContext&, const IntRect&)
923     {
924         // Set layer opacity to 0.
925         m_test->layerTreeHost()->rootLayer()->setOpacity(0);
926     }
927
928     virtual bool preserves3D() { return false; }
929
930 private:
931     CCLayerTreeHostTest* m_test;
932 };
933
934 class ContentLayerChromiumWithUpdateTracking : public ContentLayerChromium {
935 public:
936     static PassRefPtr<ContentLayerChromiumWithUpdateTracking> create(ContentLayerDelegate *delegate) { return adoptRef(new ContentLayerChromiumWithUpdateTracking(delegate)); }
937
938     int paintContentsCount() { return m_paintContentsCount; }
939     int idlePaintContentsCount() { return m_idlePaintContentsCount; }
940     void resetPaintContentsCount() { m_paintContentsCount = 0; m_idlePaintContentsCount = 0;}
941
942     int updateCount() { return m_updateCount; }
943     void resetUpdateCount() { m_updateCount = 0; }
944
945     virtual void paintContentsIfDirty()
946     {
947         ContentLayerChromium::paintContentsIfDirty();
948         m_paintContentsCount++;
949     }
950
951     virtual void idlePaintContentsIfDirty()
952     {
953         ContentLayerChromium::idlePaintContentsIfDirty();
954         m_idlePaintContentsCount++;
955     }
956
957     virtual void updateCompositorResources(GraphicsContext3D* context, CCTextureUpdater& updater)
958     {
959         ContentLayerChromium::updateCompositorResources(context, updater);
960         m_updateCount++;
961     }
962
963 private:
964     explicit ContentLayerChromiumWithUpdateTracking(ContentLayerDelegate* delegate)
965         : ContentLayerChromium(delegate)
966         , m_paintContentsCount(0)
967         , m_idlePaintContentsCount(0)
968         , m_updateCount(0)
969     {
970         setBounds(IntSize(10, 10));
971         setIsDrawable(true);
972     }
973
974     int m_paintContentsCount;
975     int m_idlePaintContentsCount;
976     int m_updateCount;
977 };
978
979 // Layer opacity change during paint should not prevent compositor resources from being updated during commit.
980 class CCLayerTreeHostTestOpacityChange : public CCLayerTreeHostTest {
981 public:
982     CCLayerTreeHostTestOpacityChange()
983         : m_testOpacityChangeDelegate(this)
984         , m_updateCheckLayer(ContentLayerChromiumWithUpdateTracking::create(&m_testOpacityChangeDelegate))
985     {
986     }
987
988     virtual void beginTest()
989     {
990         m_layerTreeHost->setRootLayer(m_updateCheckLayer);
991         m_layerTreeHost->setViewportSize(IntSize(10, 10));
992
993         postSetNeedsCommitToMainThread();
994     }
995
996     virtual void commitCompleteOnCCThread(CCLayerTreeHostImpl*)
997     {
998         endTest();
999     }
1000
1001     virtual void afterTest()
1002     {
1003         // paintContentsIfDirty() should have been called once.
1004         EXPECT_EQ(1, m_updateCheckLayer->paintContentsCount());
1005
1006         // idlePaintContentsIfDirty() should have been called once
1007         EXPECT_EQ(1, m_updateCheckLayer->idlePaintContentsCount());
1008
1009         // updateCompositorResources() should have been called the same
1010         // amout of times as paintContentsIfDirty().
1011         EXPECT_EQ(m_updateCheckLayer->paintContentsCount(),
1012                   m_updateCheckLayer->updateCount());
1013
1014         // clear m_updateCheckLayer so CCLayerTreeHost dies.
1015         m_updateCheckLayer.clear();
1016     }
1017
1018 private:
1019     TestOpacityChangeLayerDelegate m_testOpacityChangeDelegate;
1020     RefPtr<ContentLayerChromiumWithUpdateTracking> m_updateCheckLayer;
1021 };
1022
1023 TEST_F(CCLayerTreeHostTestOpacityChange, runMultiThread)
1024 {
1025     runTest(true);
1026 }
1027
1028 class CCLayerTreeHostTestSetViewportSize : public CCLayerTreeHostTest {
1029 public:
1030
1031     CCLayerTreeHostTestSetViewportSize()
1032         : m_numCommits(0)
1033         , m_numDraws(0)
1034     {
1035     }
1036
1037     virtual void beginTest()
1038     {
1039         IntSize viewportSize(10, 10);
1040         layerTreeHost()->setViewportSize(viewportSize);
1041         EXPECT_EQ(viewportSize, layerTreeHost()->viewportSize());
1042         EXPECT_EQ(TextureManager::highLimitBytes(viewportSize), layerTreeHost()->contentsTextureManager()->maxMemoryLimitBytes());
1043         EXPECT_EQ(TextureManager::reclaimLimitBytes(viewportSize), layerTreeHost()->contentsTextureManager()->preferredMemoryLimitBytes());
1044
1045         // setViewportSize() should not call TextureManager::setMaxMemoryLimitBytes() or TextureManager::setPreferredMemoryLimitBytes()
1046         // if the viewport size is not changed.
1047         IntSize fakeSize(5, 5);
1048         layerTreeHost()->contentsTextureManager()->setMaxMemoryLimitBytes(TextureManager::highLimitBytes(fakeSize));
1049         layerTreeHost()->contentsTextureManager()->setPreferredMemoryLimitBytes(TextureManager::reclaimLimitBytes(fakeSize));
1050         layerTreeHost()->setViewportSize(viewportSize);
1051         EXPECT_EQ(TextureManager::highLimitBytes(fakeSize), layerTreeHost()->contentsTextureManager()->maxMemoryLimitBytes());
1052         EXPECT_EQ(TextureManager::reclaimLimitBytes(fakeSize), layerTreeHost()->contentsTextureManager()->preferredMemoryLimitBytes());
1053
1054         endTest();
1055     }
1056
1057     virtual void afterTest()
1058     {
1059     }
1060
1061 private:
1062     int m_numCommits;
1063     int m_numDraws;
1064 };
1065
1066 TEST_F(CCLayerTreeHostTestSetViewportSize, runSingleThread)
1067 {
1068     runTest(false);
1069 }
1070
1071 } // namespace