1657c3341891303cec33e609dcbd79e41b2cc79a
[WebKit-https.git] / Source / WebKit / chromium / tests / CCLayerTreeHostImplTest.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/CCLayerTreeHostImpl.h"
28
29 #include "CCAnimationTestCommon.h"
30 #include "CCLayerTestCommon.h"
31 #include "FakeWebGraphicsContext3D.h"
32 #include "GraphicsContext3DPrivate.h"
33 #include "LayerRendererChromium.h"
34 #include "cc/CCLayerImpl.h"
35 #include "cc/CCLayerTilingData.h"
36 #include "cc/CCQuadCuller.h"
37 #include "cc/CCScrollbarLayerImpl.h"
38 #include "cc/CCSingleThreadProxy.h"
39 #include "cc/CCSolidColorDrawQuad.h"
40 #include "cc/CCTextureLayerImpl.h"
41 #include "cc/CCTileDrawQuad.h"
42 #include "cc/CCTiledLayerImpl.h"
43 #include "cc/CCVideoLayerImpl.h"
44 #include <gmock/gmock.h>
45 #include <gtest/gtest.h>
46 #include <public/WebVideoFrame.h>
47 #include <public/WebVideoFrameProvider.h>
48
49 using namespace CCLayerTestCommon;
50 using namespace WebCore;
51 using namespace WebKit;
52 using namespace WebKitTests;
53
54 using ::testing::Mock;
55 using ::testing::Return;
56 using ::testing::AnyNumber;
57 using ::testing::AtLeast;
58 using ::testing::_;
59
60 namespace {
61
62 class CCLayerTreeHostImplTest : public testing::Test, public CCLayerTreeHostImplClient {
63 public:
64     CCLayerTreeHostImplTest()
65         : m_didRequestCommit(false)
66         , m_didRequestRedraw(false)
67     {
68         CCSettings settings;
69         m_hostImpl = CCLayerTreeHostImpl::create(settings, this);
70         m_hostImpl->initializeLayerRenderer(createContext(), UnthrottledUploader);
71         m_hostImpl->setViewportSize(IntSize(10, 10));
72     }
73
74     virtual void didLoseContextOnImplThread() OVERRIDE { }
75     virtual void onSwapBuffersCompleteOnImplThread() OVERRIDE { }
76     virtual void setNeedsRedrawOnImplThread() OVERRIDE { m_didRequestRedraw = true; }
77     virtual void setNeedsCommitOnImplThread() OVERRIDE { m_didRequestCommit = true; }
78     virtual void postAnimationEventsToMainThreadOnImplThread(PassOwnPtr<CCAnimationEventsVector>, double wallClockTime) OVERRIDE { }
79     virtual void postSetContentsMemoryAllocationLimitBytesToMainThreadOnImplThread(size_t) OVERRIDE { }
80
81     PassOwnPtr<CCLayerTreeHostImpl> createLayerTreeHost(bool partialSwap, PassRefPtr<CCGraphicsContext> graphicsContext, PassOwnPtr<CCLayerImpl> rootPtr)
82     {
83         CCSettings settings;
84
85         settings.partialSwapEnabled = partialSwap;
86
87         OwnPtr<CCLayerTreeHostImpl> myHostImpl = CCLayerTreeHostImpl::create(settings, this);
88
89         myHostImpl->initializeLayerRenderer(graphicsContext, UnthrottledUploader);
90         myHostImpl->setViewportSize(IntSize(10, 10));
91
92         OwnPtr<CCLayerImpl> root = rootPtr;
93
94         root->setAnchorPoint(FloatPoint(0, 0));
95         root->setPosition(FloatPoint(0, 0));
96         root->setBounds(IntSize(10, 10));
97         root->setVisibleLayerRect(IntRect(0, 0, 10, 10));
98         root->setDrawsContent(true);
99         myHostImpl->setRootLayer(root.release());
100         return myHostImpl.release();
101     }
102
103     static void expectClearedScrollDeltasRecursive(CCLayerImpl* layer)
104     {
105         ASSERT_EQ(layer->scrollDelta(), IntSize());
106         for (size_t i = 0; i < layer->children().size(); ++i)
107             expectClearedScrollDeltasRecursive(layer->children()[i].get());
108     }
109
110     static void expectContains(const CCScrollAndScaleSet& scrollInfo, int id, const IntSize& scrollDelta)
111     {
112         int timesEncountered = 0;
113
114         for (size_t i = 0; i < scrollInfo.scrolls.size(); ++i) {
115             if (scrollInfo.scrolls[i].layerId != id)
116                 continue;
117             EXPECT_EQ(scrollDelta.width(), scrollInfo.scrolls[i].scrollDelta.width());
118             EXPECT_EQ(scrollDelta.height(), scrollInfo.scrolls[i].scrollDelta.height());
119             timesEncountered++;
120         }
121
122         ASSERT_EQ(timesEncountered, 1);
123     }
124
125     void setupScrollAndContentsLayers(const IntSize& contentSize)
126     {
127         OwnPtr<CCLayerImpl> root = CCLayerImpl::create(0);
128         root->setScrollable(true);
129         root->setScrollPosition(IntPoint(0, 0));
130         root->setMaxScrollPosition(contentSize);
131         OwnPtr<CCLayerImpl> contents = CCLayerImpl::create(1);
132         contents->setDrawsContent(true);
133         contents->setBounds(contentSize);
134         contents->setContentBounds(contentSize);
135         root->addChild(contents.release());
136         m_hostImpl->setRootLayer(root.release());
137     }
138
139 protected:
140     PassRefPtr<CCGraphicsContext> createContext()
141     {
142         return CCGraphicsContext::create3D(GraphicsContext3DPrivate::createGraphicsContextFromWebContext(adoptPtr(new FakeWebGraphicsContext3D()), GraphicsContext3D::RenderDirectlyToHostWindow));
143     }
144
145     DebugScopedSetImplThread m_alwaysImplThread;
146     DebugScopedSetMainThreadBlocked m_alwaysMainThreadBlocked;
147
148     OwnPtr<CCLayerTreeHostImpl> m_hostImpl;
149     bool m_didRequestCommit;
150     bool m_didRequestRedraw;
151 };
152
153 TEST_F(CCLayerTreeHostImplTest, scrollDeltaNoLayers)
154 {
155     ASSERT_FALSE(m_hostImpl->rootLayer());
156
157     OwnPtr<CCScrollAndScaleSet> scrollInfo = m_hostImpl->processScrollDeltas();
158     ASSERT_EQ(scrollInfo->scrolls.size(), 0u);
159 }
160
161 TEST_F(CCLayerTreeHostImplTest, scrollDeltaTreeButNoChanges)
162 {
163     {
164         OwnPtr<CCLayerImpl> root = CCLayerImpl::create(0);
165         root->addChild(CCLayerImpl::create(1));
166         root->addChild(CCLayerImpl::create(2));
167         root->children()[1]->addChild(CCLayerImpl::create(3));
168         root->children()[1]->addChild(CCLayerImpl::create(4));
169         root->children()[1]->children()[0]->addChild(CCLayerImpl::create(5));
170         m_hostImpl->setRootLayer(root.release());
171     }
172     CCLayerImpl* root = m_hostImpl->rootLayer();
173
174     expectClearedScrollDeltasRecursive(root);
175
176     OwnPtr<CCScrollAndScaleSet> scrollInfo;
177
178     scrollInfo = m_hostImpl->processScrollDeltas();
179     ASSERT_EQ(scrollInfo->scrolls.size(), 0u);
180     expectClearedScrollDeltasRecursive(root);
181
182     scrollInfo = m_hostImpl->processScrollDeltas();
183     ASSERT_EQ(scrollInfo->scrolls.size(), 0u);
184     expectClearedScrollDeltasRecursive(root);
185 }
186
187 TEST_F(CCLayerTreeHostImplTest, scrollDeltaRepeatedScrolls)
188 {
189     IntPoint scrollPosition(20, 30);
190     IntSize scrollDelta(11, -15);
191     {
192         OwnPtr<CCLayerImpl> root = CCLayerImpl::create(10);
193         root->setScrollPosition(scrollPosition);
194         root->setScrollable(true);
195         root->setMaxScrollPosition(IntSize(100, 100));
196         root->scrollBy(scrollDelta);
197         m_hostImpl->setRootLayer(root.release());
198     }
199     CCLayerImpl* root = m_hostImpl->rootLayer();
200
201     OwnPtr<CCScrollAndScaleSet> scrollInfo;
202
203     scrollInfo = m_hostImpl->processScrollDeltas();
204     ASSERT_EQ(scrollInfo->scrolls.size(), 1u);
205     EXPECT_EQ(root->sentScrollDelta(), scrollDelta);
206     expectContains(*scrollInfo, root->id(), scrollDelta);
207
208     IntSize scrollDelta2(-5, 27);
209     root->scrollBy(scrollDelta2);
210     scrollInfo = m_hostImpl->processScrollDeltas();
211     ASSERT_EQ(scrollInfo->scrolls.size(), 1u);
212     EXPECT_EQ(root->sentScrollDelta(), scrollDelta + scrollDelta2);
213     expectContains(*scrollInfo, root->id(), scrollDelta + scrollDelta2);
214
215     root->scrollBy(IntSize());
216     scrollInfo = m_hostImpl->processScrollDeltas();
217     EXPECT_EQ(root->sentScrollDelta(), scrollDelta + scrollDelta2);
218 }
219
220 TEST_F(CCLayerTreeHostImplTest, scrollRootCallsCommitAndRedraw)
221 {
222     {
223         OwnPtr<CCLayerImpl> root = CCLayerImpl::create(0);
224         root->setScrollable(true);
225         root->setScrollPosition(IntPoint(0, 0));
226         root->setMaxScrollPosition(IntSize(100, 100));
227         m_hostImpl->setRootLayer(root.release());
228     }
229
230     EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(0, 0), CCInputHandlerClient::Wheel), CCInputHandlerClient::ScrollStarted);
231     m_hostImpl->scrollBy(IntSize(0, 10));
232     m_hostImpl->scrollEnd();
233     EXPECT_TRUE(m_didRequestRedraw);
234     EXPECT_TRUE(m_didRequestCommit);
235 }
236
237 TEST_F(CCLayerTreeHostImplTest, wheelEventHandlers)
238 {
239     {
240         OwnPtr<CCLayerImpl> root = CCLayerImpl::create(0);
241         root->setScrollable(true);
242         root->setScrollPosition(IntPoint(0, 0));
243         root->setMaxScrollPosition(IntSize(100, 100));
244         m_hostImpl->setRootLayer(root.release());
245     }
246     CCLayerImpl* root = m_hostImpl->rootLayer();
247
248     root->setHaveWheelEventHandlers(true);
249     // With registered event handlers, wheel scrolls have to go to the main thread.
250     EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(0, 0), CCInputHandlerClient::Wheel), CCInputHandlerClient::ScrollFailed);
251
252     // But gesture scrolls can still be handled.
253     EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(0, 0), CCInputHandlerClient::Gesture), CCInputHandlerClient::ScrollStarted);
254 }
255
256 TEST_F(CCLayerTreeHostImplTest, shouldScrollOnMainThread)
257 {
258     OwnPtr<CCLayerImpl> root = CCLayerImpl::create(0);
259     root->setScrollable(true);
260     root->setScrollPosition(IntPoint(0, 0));
261     root->setMaxScrollPosition(IntSize(100, 100));
262     root->setShouldScrollOnMainThread(true);
263     m_hostImpl->setRootLayer(root.release());
264     EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(0, 0), CCInputHandlerClient::Wheel), CCInputHandlerClient::ScrollFailed);
265     EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(0, 0), CCInputHandlerClient::Gesture), CCInputHandlerClient::ScrollFailed);
266 }
267
268 TEST_F(CCLayerTreeHostImplTest, nonFastScrollableRegionBasic)
269 {
270     OwnPtr<CCLayerImpl> root = CCLayerImpl::create(0);
271     root->setScrollable(true);
272     root->setScrollPosition(IntPoint(0, 0));
273     root->setMaxScrollPosition(IntSize(100, 100));
274     root->setNonFastScrollableRegion(IntRect(0, 0, 50, 50));
275     m_hostImpl->setRootLayer(root.release());
276     // All scroll types inside the non-fast scrollable region should fail.
277     EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(25, 25), CCInputHandlerClient::Wheel), CCInputHandlerClient::ScrollFailed);
278     EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(25, 25), CCInputHandlerClient::Gesture), CCInputHandlerClient::ScrollFailed);
279
280     // All scroll types outside this region should succeed.
281     EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(75, 75), CCInputHandlerClient::Wheel), CCInputHandlerClient::ScrollStarted);
282     m_hostImpl->scrollBy(IntSize(0, 10));
283     m_hostImpl->scrollEnd();
284     EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(75, 75), CCInputHandlerClient::Gesture), CCInputHandlerClient::ScrollStarted);
285     m_hostImpl->scrollBy(IntSize(0, 10));
286     m_hostImpl->scrollEnd();
287 }
288
289 TEST_F(CCLayerTreeHostImplTest, nonFastScrollableRegionWithOffset)
290 {
291     OwnPtr<CCLayerImpl> root = CCLayerImpl::create(0);
292     root->setScrollable(true);
293     root->setScrollPosition(IntPoint(0, 0));
294     root->setMaxScrollPosition(IntSize(100, 100));
295     root->setNonFastScrollableRegion(IntRect(0, 0, 50, 50));
296     root->setPosition(FloatPoint(-25, 0));
297     m_hostImpl->setRootLayer(root.release());
298     CCLayerTreeHostImpl::FrameData frame;
299     EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
300     m_hostImpl->drawLayers(frame); // Update draw transforms so we can correctly map points into layer space.
301
302     // This point would fall into the non-fast scrollable region except that we've moved the layer down by 25 pixels.
303     EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(40, 10), CCInputHandlerClient::Wheel), CCInputHandlerClient::ScrollStarted);
304     m_hostImpl->scrollBy(IntSize(0, 1));
305     m_hostImpl->scrollEnd();
306
307     // This point is still inside the non-fast region.
308     EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(10, 10), CCInputHandlerClient::Wheel), CCInputHandlerClient::ScrollFailed);
309 }
310
311 TEST_F(CCLayerTreeHostImplTest, pinchGesture)
312 {
313     setupScrollAndContentsLayers(IntSize(100, 100));
314     m_hostImpl->setViewportSize(IntSize(50, 50));
315
316     CCLayerImpl* scrollLayer = m_hostImpl->scrollLayer();
317     ASSERT(scrollLayer);
318
319     const float minPageScale = 0.5, maxPageScale = 4;
320
321     // Basic pinch zoom in gesture
322     {
323         m_hostImpl->setPageScaleFactorAndLimits(1, minPageScale, maxPageScale);
324         scrollLayer->setPageScaleDelta(1);
325         scrollLayer->setScrollDelta(IntSize());
326
327         float pageScaleDelta = 2;
328         m_hostImpl->pinchGestureBegin();
329         m_hostImpl->pinchGestureUpdate(pageScaleDelta, IntPoint(50, 50));
330         m_hostImpl->pinchGestureEnd();
331         EXPECT_TRUE(m_didRequestRedraw);
332         EXPECT_TRUE(m_didRequestCommit);
333
334         OwnPtr<CCScrollAndScaleSet> scrollInfo = m_hostImpl->processScrollDeltas();
335         EXPECT_EQ(scrollInfo->pageScaleDelta, pageScaleDelta);
336     }
337
338     // Zoom-in clamping
339     {
340         m_hostImpl->setPageScaleFactorAndLimits(1, minPageScale, maxPageScale);
341         scrollLayer->setPageScaleDelta(1);
342         scrollLayer->setScrollDelta(IntSize());
343         float pageScaleDelta = 10;
344
345         m_hostImpl->pinchGestureBegin();
346         m_hostImpl->pinchGestureUpdate(pageScaleDelta, IntPoint(50, 50));
347         m_hostImpl->pinchGestureEnd();
348
349         OwnPtr<CCScrollAndScaleSet> scrollInfo = m_hostImpl->processScrollDeltas();
350         EXPECT_EQ(scrollInfo->pageScaleDelta, maxPageScale);
351     }
352
353     // Zoom-out clamping
354     {
355         m_hostImpl->setPageScaleFactorAndLimits(1, minPageScale, maxPageScale);
356         scrollLayer->setPageScaleDelta(1);
357         scrollLayer->setScrollDelta(IntSize());
358         scrollLayer->setScrollPosition(IntPoint(50, 50));
359
360         float pageScaleDelta = 0.1f;
361         m_hostImpl->pinchGestureBegin();
362         m_hostImpl->pinchGestureUpdate(pageScaleDelta, IntPoint(0, 0));
363         m_hostImpl->pinchGestureEnd();
364
365         OwnPtr<CCScrollAndScaleSet> scrollInfo = m_hostImpl->processScrollDeltas();
366         EXPECT_EQ(scrollInfo->pageScaleDelta, minPageScale);
367
368         // Pushed to (0,0) via clamping against contents layer size.
369         expectContains(*scrollInfo, scrollLayer->id(), IntSize(-50, -50));
370     }
371
372     // Two-finger panning
373     {
374         m_hostImpl->setPageScaleFactorAndLimits(1, minPageScale, maxPageScale);
375         scrollLayer->setPageScaleDelta(1);
376         scrollLayer->setScrollDelta(IntSize());
377         scrollLayer->setScrollPosition(IntPoint(20, 20));
378
379         float pageScaleDelta = 1;
380         m_hostImpl->pinchGestureBegin();
381         m_hostImpl->pinchGestureUpdate(pageScaleDelta, IntPoint(10, 10));
382         m_hostImpl->pinchGestureUpdate(pageScaleDelta, IntPoint(20, 20));
383         m_hostImpl->pinchGestureEnd();
384
385         OwnPtr<CCScrollAndScaleSet> scrollInfo = m_hostImpl->processScrollDeltas();
386         EXPECT_EQ(scrollInfo->pageScaleDelta, pageScaleDelta);
387         expectContains(*scrollInfo, scrollLayer->id(), IntSize(-10, -10));
388     }
389 }
390
391 TEST_F(CCLayerTreeHostImplTest, pageScaleAnimation)
392 {
393     setupScrollAndContentsLayers(IntSize(100, 100));
394     m_hostImpl->setViewportSize(IntSize(50, 50));
395
396     CCLayerImpl* scrollLayer = m_hostImpl->scrollLayer();
397     ASSERT(scrollLayer);
398
399     const float minPageScale = 0.5, maxPageScale = 4;
400     const double startTime = 1;
401     const double duration = 0.1;
402     const double halfwayThroughAnimation = startTime + duration / 2;
403     const double endTime = startTime + duration;
404
405     // Non-anchor zoom-in
406     {
407         m_hostImpl->setPageScaleFactorAndLimits(1, minPageScale, maxPageScale);
408         scrollLayer->setPageScaleDelta(1);
409         scrollLayer->setScrollPosition(IntPoint(50, 50));
410
411         m_hostImpl->startPageScaleAnimation(IntSize(0, 0), false, 2, startTime, duration);
412         m_hostImpl->animate(halfwayThroughAnimation, halfwayThroughAnimation);
413         EXPECT_TRUE(m_didRequestRedraw);
414         m_hostImpl->animate(endTime, endTime);
415         EXPECT_TRUE(m_didRequestCommit);
416
417         OwnPtr<CCScrollAndScaleSet> scrollInfo = m_hostImpl->processScrollDeltas();
418         EXPECT_EQ(scrollInfo->pageScaleDelta, 2);
419         expectContains(*scrollInfo, scrollLayer->id(), IntSize(-50, -50));
420     }
421
422     // Anchor zoom-out
423     {
424         m_hostImpl->setPageScaleFactorAndLimits(1, minPageScale, maxPageScale);
425         scrollLayer->setPageScaleDelta(1);
426         scrollLayer->setScrollPosition(IntPoint(50, 50));
427
428         m_hostImpl->startPageScaleAnimation(IntSize(25, 25), true, minPageScale, startTime, duration);
429         m_hostImpl->animate(endTime, endTime);
430         EXPECT_TRUE(m_didRequestRedraw);
431         EXPECT_TRUE(m_didRequestCommit);
432
433         OwnPtr<CCScrollAndScaleSet> scrollInfo = m_hostImpl->processScrollDeltas();
434         EXPECT_EQ(scrollInfo->pageScaleDelta, minPageScale);
435         // Pushed to (0,0) via clamping against contents layer size.
436         expectContains(*scrollInfo, scrollLayer->id(), IntSize(-50, -50));
437     }
438 }
439
440 class DidDrawCheckLayer : public CCTiledLayerImpl {
441 public:
442     static PassOwnPtr<DidDrawCheckLayer> create(int id) { return adoptPtr(new DidDrawCheckLayer(id)); }
443
444     virtual void didDraw()
445     {
446         m_didDrawCalled = true;
447     }
448
449     virtual void willDraw(CCRenderer*, CCGraphicsContext*)
450     {
451         m_willDrawCalled = true;
452     }
453
454     bool didDrawCalled() const { return m_didDrawCalled; }
455     bool willDrawCalled() const { return m_willDrawCalled; }
456
457     void clearDidDrawCheck()
458     {
459         m_didDrawCalled = false;
460         m_willDrawCalled = false;
461     }
462
463 protected:
464     explicit DidDrawCheckLayer(int id)
465         : CCTiledLayerImpl(id)
466         , m_didDrawCalled(false)
467         , m_willDrawCalled(false)
468     {
469         setAnchorPoint(FloatPoint(0, 0));
470         setBounds(IntSize(10, 10));
471         setDrawsContent(true);
472     }
473
474 private:
475     bool m_didDrawCalled;
476     bool m_willDrawCalled;
477 };
478
479 TEST_F(CCLayerTreeHostImplTest, didDrawNotCalledOnHiddenLayer)
480 {
481     // The root layer is always drawn, so run this test on a child layer that
482     // will be masked out by the root layer's bounds.
483     m_hostImpl->setRootLayer(DidDrawCheckLayer::create(0));
484     DidDrawCheckLayer* root = static_cast<DidDrawCheckLayer*>(m_hostImpl->rootLayer());
485     root->setMasksToBounds(true);
486
487     root->addChild(DidDrawCheckLayer::create(1));
488     DidDrawCheckLayer* layer = static_cast<DidDrawCheckLayer*>(root->children()[0].get());
489     // Ensure visibleLayerRect for layer is empty
490     layer->setPosition(FloatPoint(100, 100));
491     layer->setBounds(IntSize(10, 10));
492     layer->setContentBounds(IntSize(10, 10));
493
494     CCLayerTreeHostImpl::FrameData frame;
495
496     EXPECT_FALSE(layer->willDrawCalled());
497     EXPECT_FALSE(layer->didDrawCalled());
498
499     EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
500     m_hostImpl->drawLayers(frame);
501     m_hostImpl->didDrawAllLayers(frame);
502
503     EXPECT_FALSE(layer->willDrawCalled());
504     EXPECT_FALSE(layer->didDrawCalled());
505
506     EXPECT_TRUE(layer->visibleLayerRect().isEmpty());
507
508     // Ensure visibleLayerRect for layer layer is not empty
509     layer->setPosition(FloatPoint(0, 0));
510
511     EXPECT_FALSE(layer->willDrawCalled());
512     EXPECT_FALSE(layer->didDrawCalled());
513
514     EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
515     m_hostImpl->drawLayers(frame);
516     m_hostImpl->didDrawAllLayers(frame);
517
518     EXPECT_TRUE(layer->willDrawCalled());
519     EXPECT_TRUE(layer->didDrawCalled());
520
521     EXPECT_FALSE(layer->visibleLayerRect().isEmpty());
522 }
523
524 TEST_F(CCLayerTreeHostImplTest, didDrawCalledOnAllLayers)
525 {
526     m_hostImpl->setRootLayer(DidDrawCheckLayer::create(0));
527     DidDrawCheckLayer* root = static_cast<DidDrawCheckLayer*>(m_hostImpl->rootLayer());
528
529     root->addChild(DidDrawCheckLayer::create(1));
530     DidDrawCheckLayer* layer1 = static_cast<DidDrawCheckLayer*>(root->children()[0].get());
531
532     layer1->addChild(DidDrawCheckLayer::create(2));
533     DidDrawCheckLayer* layer2 = static_cast<DidDrawCheckLayer*>(layer1->children()[0].get());
534
535     layer1->setOpacity(0.3f);
536     layer1->setPreserves3D(false);
537
538     EXPECT_FALSE(root->didDrawCalled());
539     EXPECT_FALSE(layer1->didDrawCalled());
540     EXPECT_FALSE(layer2->didDrawCalled());
541
542     CCLayerTreeHostImpl::FrameData frame;
543     EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
544     m_hostImpl->drawLayers(frame);
545     m_hostImpl->didDrawAllLayers(frame);
546
547     EXPECT_TRUE(root->didDrawCalled());
548     EXPECT_TRUE(layer1->didDrawCalled());
549     EXPECT_TRUE(layer2->didDrawCalled());
550
551     EXPECT_NE(root->renderSurface(), layer1->renderSurface());
552     EXPECT_TRUE(!!layer1->renderSurface());
553 }
554
555 class MissingTextureAnimatingLayer : public DidDrawCheckLayer {
556 public:
557     static PassOwnPtr<MissingTextureAnimatingLayer> create(int id, bool tileMissing, bool skipsDraw, bool animating) { return adoptPtr(new MissingTextureAnimatingLayer(id, tileMissing, skipsDraw, animating)); }
558
559 private:
560     explicit MissingTextureAnimatingLayer(int id, bool tileMissing, bool skipsDraw, bool animating)
561         : DidDrawCheckLayer(id)
562     {
563         OwnPtr<CCLayerTilingData> tilingData = CCLayerTilingData::create(IntSize(10, 10), CCLayerTilingData::NoBorderTexels);
564         tilingData->setBounds(bounds());
565         setTilingData(*tilingData.get());
566         setSkipsDraw(skipsDraw);
567         if (!tileMissing)
568             pushTileProperties(0, 0, 1, IntRect());
569         if (animating)
570             addAnimatedTransformToLayer(*this, 10, 3, 0);
571     }
572 };
573
574 TEST_F(CCLayerTreeHostImplTest, prepareToDrawFailsWhenAnimationUsesCheckerboard)
575 {
576     // When the texture is not missing, we draw as usual.
577     m_hostImpl->setRootLayer(DidDrawCheckLayer::create(0));
578     DidDrawCheckLayer* root = static_cast<DidDrawCheckLayer*>(m_hostImpl->rootLayer());
579     root->addChild(MissingTextureAnimatingLayer::create(1, false, false, true));
580
581     CCLayerTreeHostImpl::FrameData frame;
582
583     EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
584     m_hostImpl->drawLayers(frame);
585     m_hostImpl->didDrawAllLayers(frame);
586
587     // When a texture is missing and we're not animating, we draw as usual with checkerboarding.
588     m_hostImpl->setRootLayer(DidDrawCheckLayer::create(0));
589     root = static_cast<DidDrawCheckLayer*>(m_hostImpl->rootLayer());
590     root->addChild(MissingTextureAnimatingLayer::create(1, true, false, false));
591
592     EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
593     m_hostImpl->drawLayers(frame);
594     m_hostImpl->didDrawAllLayers(frame);
595
596     // When a texture is missing and we're animating, we don't want to draw anything.
597     m_hostImpl->setRootLayer(DidDrawCheckLayer::create(0));
598     root = static_cast<DidDrawCheckLayer*>(m_hostImpl->rootLayer());
599     root->addChild(MissingTextureAnimatingLayer::create(1, true, false, true));
600
601     EXPECT_FALSE(m_hostImpl->prepareToDraw(frame));
602     m_hostImpl->drawLayers(frame);
603     m_hostImpl->didDrawAllLayers(frame);
604
605     // When the layer skips draw and we're animating, we still draw the frame.
606     m_hostImpl->setRootLayer(DidDrawCheckLayer::create(0));
607     root = static_cast<DidDrawCheckLayer*>(m_hostImpl->rootLayer());
608     root->addChild(MissingTextureAnimatingLayer::create(1, false, true, true));
609
610     EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
611     m_hostImpl->drawLayers(frame);
612     m_hostImpl->didDrawAllLayers(frame);
613 }
614
615 class BlendStateTrackerContext: public FakeWebGraphicsContext3D {
616 public:
617     BlendStateTrackerContext() : m_blend(false) { }
618
619     virtual void enable(WGC3Denum cap)
620     {
621         if (cap == GraphicsContext3D::BLEND)
622             m_blend = true;
623     }
624
625     virtual void disable(WGC3Denum cap)
626     {
627         if (cap == GraphicsContext3D::BLEND)
628             m_blend = false;
629     }
630
631     bool blend() const { return m_blend; }
632
633 private:
634     bool m_blend;
635 };
636
637 class BlendStateCheckLayer : public CCLayerImpl {
638 public:
639     static PassOwnPtr<BlendStateCheckLayer> create(int id) { return adoptPtr(new BlendStateCheckLayer(id)); }
640
641     virtual void appendQuads(CCQuadCuller& quadList, const CCSharedQuadState* sharedQuadState, bool&) OVERRIDE
642     {
643         m_quadsAppended = true;
644
645         IntRect opaqueRect;
646         if (opaque() || m_opaqueContents)
647             opaqueRect = m_quadRect;
648         else
649             opaqueRect = m_opaqueContentRect;
650         OwnPtr<CCDrawQuad> testBlendingDrawQuad = CCTileDrawQuad::create(sharedQuadState, m_quadRect, opaqueRect, 0, IntPoint(), IntSize(1, 1), 0, false, false, false, false, false);
651         testBlendingDrawQuad->setQuadVisibleRect(m_quadVisibleRect);
652         EXPECT_EQ(m_blend, testBlendingDrawQuad->needsBlending());
653         EXPECT_EQ(m_hasRenderSurface, !!renderSurface());
654         quadList.append(testBlendingDrawQuad.release());
655     }
656
657     void setExpectation(bool blend, bool hasRenderSurface)
658     {
659         m_blend = blend;
660         m_hasRenderSurface = hasRenderSurface;
661         m_quadsAppended = false;
662     }
663
664     bool quadsAppended() const { return m_quadsAppended; }
665
666     void setQuadRect(const IntRect& rect) { m_quadRect = rect; }
667     void setQuadVisibleRect(const IntRect& rect) { m_quadVisibleRect = rect; }
668     void setOpaqueContents(bool opaque) { m_opaqueContents = opaque; }
669     void setOpaqueContentRect(const IntRect& rect) { m_opaqueContentRect = rect; }
670
671 private:
672     explicit BlendStateCheckLayer(int id)
673         : CCLayerImpl(id)
674         , m_blend(false)
675         , m_hasRenderSurface(false)
676         , m_quadsAppended(false)
677         , m_opaqueContents(false)
678         , m_quadRect(5, 5, 5, 5)
679         , m_quadVisibleRect(5, 5, 5, 5)
680     {
681         setAnchorPoint(FloatPoint(0, 0));
682         setBounds(IntSize(10, 10));
683         setDrawsContent(true);
684     }
685
686     bool m_blend;
687     bool m_hasRenderSurface;
688     bool m_quadsAppended;
689     bool m_opaqueContents;
690     IntRect m_quadRect;
691     IntRect m_opaqueContentRect;
692     IntRect m_quadVisibleRect;
693 };
694
695 // https://bugs.webkit.org/show_bug.cgi?id=75783
696 TEST_F(CCLayerTreeHostImplTest, blendingOffWhenDrawingOpaqueLayers)
697 {
698
699     {
700         OwnPtr<CCLayerImpl> root = CCLayerImpl::create(0);
701         root->setAnchorPoint(FloatPoint(0, 0));
702         root->setBounds(IntSize(10, 10));
703         root->setDrawsContent(false);
704         m_hostImpl->setRootLayer(root.release());
705     }
706     CCLayerImpl* root = m_hostImpl->rootLayer();
707
708     root->addChild(BlendStateCheckLayer::create(1));
709     BlendStateCheckLayer* layer1 = static_cast<BlendStateCheckLayer*>(root->children()[0].get());
710
711     CCLayerTreeHostImpl::FrameData frame;
712
713     // Opaque layer, drawn without blending.
714     layer1->setOpaque(true);
715     layer1->setOpaqueContents(true);
716     layer1->setExpectation(false, false);
717     EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
718     m_hostImpl->drawLayers(frame);
719     EXPECT_TRUE(layer1->quadsAppended());
720     m_hostImpl->didDrawAllLayers(frame);
721
722     // Layer with translucent content, but opaque content, so drawn without blending.
723     layer1->setOpaque(false);
724     layer1->setOpaqueContents(true);
725     layer1->setExpectation(false, false);
726     EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
727     m_hostImpl->drawLayers(frame);
728     EXPECT_TRUE(layer1->quadsAppended());
729     m_hostImpl->didDrawAllLayers(frame);
730
731     // Layer with translucent content and painting, so drawn with blending.
732     layer1->setOpaque(false);
733     layer1->setOpaqueContents(false);
734     layer1->setExpectation(true, false);
735     EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
736     m_hostImpl->drawLayers(frame);
737     EXPECT_TRUE(layer1->quadsAppended());
738     m_hostImpl->didDrawAllLayers(frame);
739
740     // Layer with translucent opacity, drawn with blending.
741     layer1->setOpaque(true);
742     layer1->setOpaqueContents(true);
743     layer1->setOpacity(0.5);
744     layer1->setExpectation(true, false);
745     EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
746     m_hostImpl->drawLayers(frame);
747     EXPECT_TRUE(layer1->quadsAppended());
748     m_hostImpl->didDrawAllLayers(frame);
749
750     // Layer with translucent opacity and painting, drawn with blending.
751     layer1->setOpaque(true);
752     layer1->setOpaqueContents(false);
753     layer1->setOpacity(0.5);
754     layer1->setExpectation(true, false);
755     EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
756     m_hostImpl->drawLayers(frame);
757     EXPECT_TRUE(layer1->quadsAppended());
758     m_hostImpl->didDrawAllLayers(frame);
759
760     layer1->addChild(BlendStateCheckLayer::create(2));
761     BlendStateCheckLayer* layer2 = static_cast<BlendStateCheckLayer*>(layer1->children()[0].get());
762
763     // 2 opaque layers, drawn without blending.
764     layer1->setOpaque(true);
765     layer1->setOpaqueContents(true);
766     layer1->setOpacity(1);
767     layer1->setExpectation(false, false);
768     layer2->setOpaque(true);
769     layer2->setOpaqueContents(true);
770     layer2->setOpacity(1);
771     layer2->setExpectation(false, false);
772     EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
773     m_hostImpl->drawLayers(frame);
774     EXPECT_TRUE(layer1->quadsAppended());
775     EXPECT_TRUE(layer2->quadsAppended());
776     m_hostImpl->didDrawAllLayers(frame);
777
778     // Parent layer with translucent content, drawn with blending.
779     // Child layer with opaque content, drawn without blending.
780     layer1->setOpaque(false);
781     layer1->setOpaqueContents(false);
782     layer1->setExpectation(true, false);
783     layer2->setExpectation(false, false);
784     EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
785     m_hostImpl->drawLayers(frame);
786     EXPECT_TRUE(layer1->quadsAppended());
787     EXPECT_TRUE(layer2->quadsAppended());
788     m_hostImpl->didDrawAllLayers(frame);
789
790     // Parent layer with translucent content but opaque painting, drawn without blending.
791     // Child layer with opaque content, drawn without blending.
792     layer1->setOpaque(false);
793     layer1->setOpaqueContents(true);
794     layer1->setExpectation(false, false);
795     layer2->setExpectation(false, false);
796     EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
797     m_hostImpl->drawLayers(frame);
798     EXPECT_TRUE(layer1->quadsAppended());
799     EXPECT_TRUE(layer2->quadsAppended());
800     m_hostImpl->didDrawAllLayers(frame);
801
802     // Parent layer with translucent opacity and opaque content. Since it has a
803     // drawing child, it's drawn to a render surface which carries the opacity,
804     // so it's itself drawn without blending.
805     // Child layer with opaque content, drawn without blending (parent surface
806     // carries the inherited opacity).
807     layer1->setOpaque(true);
808     layer1->setOpaqueContents(true);
809     layer1->setOpacity(0.5);
810     layer1->setExpectation(false, true);
811     layer2->setExpectation(false, false);
812     EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
813     m_hostImpl->drawLayers(frame);
814     EXPECT_TRUE(layer1->quadsAppended());
815     EXPECT_TRUE(layer2->quadsAppended());
816     m_hostImpl->didDrawAllLayers(frame);
817
818     // Draw again, but with child non-opaque, to make sure
819     // layer1 not culled.
820     layer1->setOpaque(true);
821     layer1->setOpaqueContents(true);
822     layer1->setOpacity(1);
823     layer1->setExpectation(false, false);
824     layer2->setOpaque(true);
825     layer2->setOpaqueContents(true);
826     layer2->setOpacity(0.5);
827     layer2->setExpectation(true, false);
828     EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
829     m_hostImpl->drawLayers(frame);
830     EXPECT_TRUE(layer1->quadsAppended());
831     EXPECT_TRUE(layer2->quadsAppended());
832     m_hostImpl->didDrawAllLayers(frame);
833
834     // A second way of making the child non-opaque.
835     layer1->setOpaque(true);
836     layer1->setOpacity(1);
837     layer1->setExpectation(false, false);
838     layer2->setOpaque(false);
839     layer2->setOpaqueContents(false);
840     layer2->setOpacity(1);
841     layer2->setExpectation(true, false);
842     EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
843     m_hostImpl->drawLayers(frame);
844     EXPECT_TRUE(layer1->quadsAppended());
845     EXPECT_TRUE(layer2->quadsAppended());
846     m_hostImpl->didDrawAllLayers(frame);
847
848     // And when the layer says its not opaque but is painted opaque, it is not blended.
849     layer1->setOpaque(true);
850     layer1->setOpacity(1);
851     layer1->setExpectation(false, false);
852     layer2->setOpaque(false);
853     layer2->setOpaqueContents(true);
854     layer2->setOpacity(1);
855     layer2->setExpectation(false, false);
856     EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
857     m_hostImpl->drawLayers(frame);
858     EXPECT_TRUE(layer1->quadsAppended());
859     EXPECT_TRUE(layer2->quadsAppended());
860     m_hostImpl->didDrawAllLayers(frame);
861
862     // Layer with partially opaque contents, drawn with blending.
863     layer1->setOpaque(false);
864     layer1->setQuadRect(IntRect(5, 5, 5, 5));
865     layer1->setQuadVisibleRect(IntRect(5, 5, 5, 5));
866     layer1->setOpaqueContents(false);
867     layer1->setOpaqueContentRect(IntRect(5, 5, 2, 5));
868     layer1->setExpectation(true, false);
869     EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
870     m_hostImpl->drawLayers(frame);
871     EXPECT_TRUE(layer1->quadsAppended());
872     m_hostImpl->didDrawAllLayers(frame);
873
874     // Layer with partially opaque contents partially culled, drawn with blending.
875     layer1->setOpaque(false);
876     layer1->setQuadRect(IntRect(5, 5, 5, 5));
877     layer1->setQuadVisibleRect(IntRect(5, 5, 5, 2));
878     layer1->setOpaqueContents(false);
879     layer1->setOpaqueContentRect(IntRect(5, 5, 2, 5));
880     layer1->setExpectation(true, false);
881     EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
882     m_hostImpl->drawLayers(frame);
883     EXPECT_TRUE(layer1->quadsAppended());
884     m_hostImpl->didDrawAllLayers(frame);
885
886     // Layer with partially opaque contents culled, drawn with blending.
887     layer1->setOpaque(false);
888     layer1->setQuadRect(IntRect(5, 5, 5, 5));
889     layer1->setQuadVisibleRect(IntRect(7, 5, 3, 5));
890     layer1->setOpaqueContents(false);
891     layer1->setOpaqueContentRect(IntRect(5, 5, 2, 5));
892     layer1->setExpectation(true, false);
893     EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
894     m_hostImpl->drawLayers(frame);
895     EXPECT_TRUE(layer1->quadsAppended());
896     m_hostImpl->didDrawAllLayers(frame);
897
898     // Layer with partially opaque contents and translucent contents culled, drawn without blending.
899     layer1->setOpaque(false);
900     layer1->setQuadRect(IntRect(5, 5, 5, 5));
901     layer1->setQuadVisibleRect(IntRect(5, 5, 2, 5));
902     layer1->setOpaqueContents(false);
903     layer1->setOpaqueContentRect(IntRect(5, 5, 2, 5));
904     layer1->setExpectation(false, false);
905     EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
906     m_hostImpl->drawLayers(frame);
907     EXPECT_TRUE(layer1->quadsAppended());
908     m_hostImpl->didDrawAllLayers(frame);
909
910 }
911
912 TEST_F(CCLayerTreeHostImplTest, viewportCovered)
913 {
914     m_hostImpl->initializeLayerRenderer(createContext(), UnthrottledUploader);
915     m_hostImpl->setBackgroundColor(Color::gray);
916
917     IntSize viewportSize(1000, 1000);
918     m_hostImpl->setViewportSize(viewportSize);
919
920     m_hostImpl->setRootLayer(BlendStateCheckLayer::create(0));
921     BlendStateCheckLayer* root = static_cast<BlendStateCheckLayer*>(m_hostImpl->rootLayer());
922     root->setExpectation(false, true);
923     root->setOpaque(true);
924
925     // No gutter rects
926     {
927         IntRect layerRect(0, 0, 1000, 1000);
928         root->setPosition(layerRect.location());
929         root->setBounds(layerRect.size());
930         root->setContentBounds(layerRect.size());
931         root->setQuadRect(IntRect(IntPoint(), layerRect.size()));
932         root->setQuadVisibleRect(IntRect(IntPoint(), layerRect.size()));
933
934         CCLayerTreeHostImpl::FrameData frame;
935         EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
936         ASSERT_EQ(1u, frame.renderPasses.size());
937
938         size_t numGutterQuads = 0;
939         for (size_t i = 0; i < frame.renderPasses[0]->quadList().size(); ++i)
940             numGutterQuads += (frame.renderPasses[0]->quadList()[i]->material() == CCDrawQuad::SolidColor) ? 1 : 0;
941         EXPECT_EQ(0u, numGutterQuads);
942         EXPECT_EQ(1u, frame.renderPasses[0]->quadList().size());
943
944         verifyQuadsExactlyCoverRect(frame.renderPasses[0]->quadList(), IntRect(-layerRect.location(), viewportSize));
945         m_hostImpl->didDrawAllLayers(frame);
946     }
947
948     // Empty visible content area (fullscreen gutter rect)
949     {
950         IntRect layerRect(0, 0, 0, 0);
951         root->setPosition(layerRect.location());
952         root->setBounds(layerRect.size());
953         root->setContentBounds(layerRect.size());
954         root->setQuadRect(IntRect(IntPoint(), layerRect.size()));
955         root->setQuadVisibleRect(IntRect(IntPoint(), layerRect.size()));
956
957         CCLayerTreeHostImpl::FrameData frame;
958         EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
959         ASSERT_EQ(1u, frame.renderPasses.size());
960         m_hostImpl->didDrawAllLayers(frame);
961
962         size_t numGutterQuads = 0;
963         for (size_t i = 0; i < frame.renderPasses[0]->quadList().size(); ++i)
964             numGutterQuads += (frame.renderPasses[0]->quadList()[i]->material() == CCDrawQuad::SolidColor) ? 1 : 0;
965         EXPECT_EQ(1u, numGutterQuads);
966         EXPECT_EQ(1u, frame.renderPasses[0]->quadList().size());
967
968         verifyQuadsExactlyCoverRect(frame.renderPasses[0]->quadList(), IntRect(-layerRect.location(), viewportSize));
969         m_hostImpl->didDrawAllLayers(frame);
970     }
971
972     // Content area in middle of clip rect (four surrounding gutter rects)
973     {
974         IntRect layerRect(500, 500, 200, 200);
975         root->setPosition(layerRect.location());
976         root->setBounds(layerRect.size());
977         root->setContentBounds(layerRect.size());
978         root->setQuadRect(IntRect(IntPoint(), layerRect.size()));
979         root->setQuadVisibleRect(IntRect(IntPoint(), layerRect.size()));
980
981         CCLayerTreeHostImpl::FrameData frame;
982         EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
983         ASSERT_EQ(1u, frame.renderPasses.size());
984
985         size_t numGutterQuads = 0;
986         for (size_t i = 0; i < frame.renderPasses[0]->quadList().size(); ++i)
987             numGutterQuads += (frame.renderPasses[0]->quadList()[i]->material() == CCDrawQuad::SolidColor) ? 1 : 0;
988         EXPECT_EQ(4u, numGutterQuads);
989         EXPECT_EQ(5u, frame.renderPasses[0]->quadList().size());
990
991         verifyQuadsExactlyCoverRect(frame.renderPasses[0]->quadList(), IntRect(-layerRect.location(), viewportSize));
992         m_hostImpl->didDrawAllLayers(frame);
993     }
994
995 }
996
997
998 class ReshapeTrackerContext: public FakeWebGraphicsContext3D {
999 public:
1000     ReshapeTrackerContext() : m_reshapeCalled(false) { }
1001
1002     virtual void reshape(int width, int height)
1003     {
1004         m_reshapeCalled = true;
1005     }
1006
1007     bool reshapeCalled() const { return m_reshapeCalled; }
1008
1009 private:
1010     bool m_reshapeCalled;
1011 };
1012
1013 class FakeDrawableCCLayerImpl: public CCLayerImpl {
1014 public:
1015     explicit FakeDrawableCCLayerImpl(int id) : CCLayerImpl(id) { }
1016 };
1017
1018 // Only reshape when we know we are going to draw. Otherwise, the reshape
1019 // can leave the window at the wrong size if we never draw and the proper
1020 // viewport size is never set.
1021 TEST_F(CCLayerTreeHostImplTest, reshapeNotCalledUntilDraw)
1022 {
1023     ReshapeTrackerContext* reshapeTracker = new ReshapeTrackerContext();
1024     RefPtr<GraphicsContext3D> context = GraphicsContext3DPrivate::createGraphicsContextFromWebContext(adoptPtr(reshapeTracker), GraphicsContext3D::RenderDirectlyToHostWindow);
1025     RefPtr<CCGraphicsContext> ccContext = CCGraphicsContext::create3D(context);
1026     m_hostImpl->initializeLayerRenderer(ccContext, UnthrottledUploader);
1027
1028     CCLayerImpl* root = new FakeDrawableCCLayerImpl(1);
1029     root->setAnchorPoint(FloatPoint(0, 0));
1030     root->setBounds(IntSize(10, 10));
1031     root->setDrawsContent(true);
1032     m_hostImpl->setRootLayer(adoptPtr(root));
1033     EXPECT_FALSE(reshapeTracker->reshapeCalled());
1034
1035     CCLayerTreeHostImpl::FrameData frame;
1036     EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
1037     m_hostImpl->drawLayers(frame);
1038     EXPECT_TRUE(reshapeTracker->reshapeCalled());
1039     m_hostImpl->didDrawAllLayers(frame);
1040 }
1041
1042 class PartialSwapTrackerContext : public FakeWebGraphicsContext3D {
1043 public:
1044     virtual void postSubBufferCHROMIUM(int x, int y, int width, int height)
1045     {
1046         m_partialSwapRect = IntRect(x, y, width, height);
1047     }
1048
1049     virtual WebString getString(WGC3Denum name)
1050     {
1051         if (name == GraphicsContext3D::EXTENSIONS)
1052             return WebString("GL_CHROMIUM_post_sub_buffer GL_CHROMIUM_set_visibility");
1053
1054         return WebString();
1055     }
1056
1057     IntRect partialSwapRect() const { return m_partialSwapRect; }
1058
1059 private:
1060     IntRect m_partialSwapRect;
1061 };
1062
1063 // Make sure damage tracking propagates all the way to the graphics context,
1064 // where it should request to swap only the subBuffer that is damaged.
1065 TEST_F(CCLayerTreeHostImplTest, partialSwapReceivesDamageRect)
1066 {
1067     PartialSwapTrackerContext* partialSwapTracker = new PartialSwapTrackerContext();
1068     RefPtr<GraphicsContext3D> context = GraphicsContext3DPrivate::createGraphicsContextFromWebContext(adoptPtr(partialSwapTracker), GraphicsContext3D::RenderDirectlyToHostWindow);
1069     RefPtr<CCGraphicsContext> ccContext = CCGraphicsContext::create3D(context);
1070
1071     // This test creates its own CCLayerTreeHostImpl, so
1072     // that we can force partial swap enabled.
1073     CCSettings settings;
1074     settings.partialSwapEnabled = true;
1075     OwnPtr<CCLayerTreeHostImpl> layerTreeHostImpl = CCLayerTreeHostImpl::create(settings, this);
1076     layerTreeHostImpl->initializeLayerRenderer(ccContext, UnthrottledUploader);
1077     layerTreeHostImpl->setViewportSize(IntSize(500, 500));
1078
1079     CCLayerImpl* root = new FakeDrawableCCLayerImpl(1);
1080     CCLayerImpl* child = new FakeDrawableCCLayerImpl(2);
1081     child->setPosition(FloatPoint(12, 13));
1082     child->setAnchorPoint(FloatPoint(0, 0));
1083     child->setBounds(IntSize(14, 15));
1084     child->setDrawsContent(true);
1085     root->setAnchorPoint(FloatPoint(0, 0));
1086     root->setBounds(IntSize(500, 500));
1087     root->setDrawsContent(true);
1088     root->addChild(adoptPtr(child));
1089     layerTreeHostImpl->setRootLayer(adoptPtr(root));
1090
1091     CCLayerTreeHostImpl::FrameData frame;
1092
1093     // First frame, the entire screen should get swapped.
1094     EXPECT_TRUE(layerTreeHostImpl->prepareToDraw(frame));
1095     layerTreeHostImpl->drawLayers(frame);
1096     layerTreeHostImpl->didDrawAllLayers(frame);
1097     layerTreeHostImpl->swapBuffers();
1098     IntRect actualSwapRect = partialSwapTracker->partialSwapRect();
1099     IntRect expectedSwapRect = IntRect(IntPoint::zero(), IntSize(500, 500));
1100     EXPECT_EQ(expectedSwapRect.x(), actualSwapRect.x());
1101     EXPECT_EQ(expectedSwapRect.y(), actualSwapRect.y());
1102     EXPECT_EQ(expectedSwapRect.width(), actualSwapRect.width());
1103     EXPECT_EQ(expectedSwapRect.height(), actualSwapRect.height());
1104
1105     // Second frame, only the damaged area should get swapped. Damage should be the union
1106     // of old and new child rects.
1107     // expected damage rect: IntRect(IntPoint::zero(), IntSize(26, 28));
1108     // expected swap rect: vertically flipped, with origin at bottom left corner.
1109     child->setPosition(FloatPoint(0, 0));
1110     EXPECT_TRUE(layerTreeHostImpl->prepareToDraw(frame));
1111     layerTreeHostImpl->drawLayers(frame);
1112     m_hostImpl->didDrawAllLayers(frame);
1113     layerTreeHostImpl->swapBuffers();
1114     actualSwapRect = partialSwapTracker->partialSwapRect();
1115     expectedSwapRect = IntRect(IntPoint(0, 500-28), IntSize(26, 28));
1116     EXPECT_EQ(expectedSwapRect.x(), actualSwapRect.x());
1117     EXPECT_EQ(expectedSwapRect.y(), actualSwapRect.y());
1118     EXPECT_EQ(expectedSwapRect.width(), actualSwapRect.width());
1119     EXPECT_EQ(expectedSwapRect.height(), actualSwapRect.height());
1120
1121     // Make sure that partial swap is constrained to the viewport dimensions
1122     // expected damage rect: IntRect(IntPoint::zero(), IntSize(500, 500));
1123     // expected swap rect: flipped damage rect, but also clamped to viewport
1124     layerTreeHostImpl->setViewportSize(IntSize(10, 10));
1125     root->setOpacity(0.7f); // this will damage everything
1126     EXPECT_TRUE(layerTreeHostImpl->prepareToDraw(frame));
1127     layerTreeHostImpl->drawLayers(frame);
1128     m_hostImpl->didDrawAllLayers(frame);
1129     layerTreeHostImpl->swapBuffers();
1130     actualSwapRect = partialSwapTracker->partialSwapRect();
1131     expectedSwapRect = IntRect(IntPoint::zero(), IntSize(10, 10));
1132     EXPECT_EQ(expectedSwapRect.x(), actualSwapRect.x());
1133     EXPECT_EQ(expectedSwapRect.y(), actualSwapRect.y());
1134     EXPECT_EQ(expectedSwapRect.width(), actualSwapRect.width());
1135     EXPECT_EQ(expectedSwapRect.height(), actualSwapRect.height());
1136 }
1137
1138 class FakeLayerWithQuads : public CCLayerImpl {
1139 public:
1140     static PassOwnPtr<FakeLayerWithQuads> create(int id) { return adoptPtr(new FakeLayerWithQuads(id)); }
1141
1142     virtual void appendQuads(CCQuadCuller& quadList, const CCSharedQuadState* sharedQuadState, bool&) OVERRIDE
1143     {
1144         const Color gray(100, 100, 100);
1145         IntRect quadRect(0, 0, 5, 5);
1146         OwnPtr<CCDrawQuad> myQuad = CCSolidColorDrawQuad::create(sharedQuadState, quadRect, gray);
1147         quadList.append(myQuad.release());
1148     }
1149
1150 private:
1151     FakeLayerWithQuads(int id)
1152         : CCLayerImpl(id)
1153     {
1154     }
1155 };
1156
1157 class MockContext : public FakeWebGraphicsContext3D {
1158 public:
1159     MOCK_METHOD1(useProgram, void(WebGLId program));
1160     MOCK_METHOD5(uniform4f, void(WGC3Dint location, WGC3Dfloat x, WGC3Dfloat y, WGC3Dfloat z, WGC3Dfloat w));
1161     MOCK_METHOD4(uniformMatrix4fv, void(WGC3Dint location, WGC3Dsizei count, WGC3Dboolean transpose, const WGC3Dfloat* value));
1162     MOCK_METHOD4(drawElements, void(WGC3Denum mode, WGC3Dsizei count, WGC3Denum type, WGC3Dintptr offset));
1163     MOCK_METHOD1(getString, WebString(WGC3Denum name));
1164     MOCK_METHOD0(getRequestableExtensionsCHROMIUM, WebString());
1165     MOCK_METHOD1(enable, void(WGC3Denum cap));
1166     MOCK_METHOD4(scissor, void(WGC3Dint x, WGC3Dint y, WGC3Dsizei width, WGC3Dsizei height));
1167 };
1168
1169 class MockContextHarness {
1170 private:
1171     MockContext* m_context;
1172 public:
1173     MockContextHarness(MockContext* context)
1174         : m_context(context)
1175     {
1176         // Catch "uninteresting" calls
1177         EXPECT_CALL(*m_context, useProgram(_))
1178             .Times(0);
1179
1180         EXPECT_CALL(*m_context, drawElements(_, _, _, _))
1181             .Times(0);
1182
1183         // These are not asserted
1184         EXPECT_CALL(*m_context, uniformMatrix4fv(_, _, _, _))
1185             .WillRepeatedly(Return());
1186
1187         EXPECT_CALL(*m_context, uniform4f(_, _, _, _, _))
1188             .WillRepeatedly(Return());
1189
1190         // Any other strings are empty
1191         EXPECT_CALL(*m_context, getString(_))
1192             .WillRepeatedly(Return(WebString()));
1193
1194         // Support for partial swap, if needed
1195         EXPECT_CALL(*m_context, getString(GraphicsContext3D::EXTENSIONS))
1196             .WillRepeatedly(Return(WebString("GL_CHROMIUM_post_sub_buffer")));
1197
1198         EXPECT_CALL(*m_context, getRequestableExtensionsCHROMIUM())
1199             .WillRepeatedly(Return(WebString("GL_CHROMIUM_post_sub_buffer")));
1200
1201         // Any un-sanctioned calls to enable() are OK
1202         EXPECT_CALL(*m_context, enable(_))
1203             .WillRepeatedly(Return());
1204     }
1205
1206     void mustDrawSolidQuad()
1207     {
1208         EXPECT_CALL(*m_context, drawElements(GraphicsContext3D::TRIANGLES, 6, GraphicsContext3D::UNSIGNED_SHORT, 0))
1209             .WillOnce(Return())
1210             .RetiresOnSaturation();
1211
1212         // 1 is hardcoded return value of fake createProgram()
1213         EXPECT_CALL(*m_context, useProgram(1))
1214             .WillOnce(Return())
1215             .RetiresOnSaturation();
1216
1217     }
1218
1219     void mustSetScissor(int x, int y, int width, int height)
1220     {
1221         EXPECT_CALL(*m_context, enable(GraphicsContext3D::SCISSOR_TEST))
1222             .WillRepeatedly(Return());
1223
1224         EXPECT_CALL(*m_context, scissor(x, y, width, height))
1225             .Times(AtLeast(1))
1226             .WillRepeatedly(Return());
1227     }
1228
1229 };
1230
1231 TEST_F(CCLayerTreeHostImplTest, noPartialSwap)
1232 {
1233     MockContext* mockContext = new MockContext();
1234     RefPtr<CCGraphicsContext> context = CCGraphicsContext::create3D(GraphicsContext3DPrivate::createGraphicsContextFromWebContext(adoptPtr(mockContext), GraphicsContext3D::RenderDirectlyToHostWindow));
1235     MockContextHarness harness(mockContext);
1236
1237     harness.mustDrawSolidQuad();
1238     harness.mustSetScissor(0, 0, 10, 10);
1239
1240     // Run test case
1241     OwnPtr<CCLayerTreeHostImpl> myHostImpl = createLayerTreeHost(false, context, FakeLayerWithQuads::create(1));
1242
1243     CCLayerTreeHostImpl::FrameData frame;
1244     EXPECT_TRUE(myHostImpl->prepareToDraw(frame));
1245     myHostImpl->drawLayers(frame);
1246     myHostImpl->didDrawAllLayers(frame);
1247     Mock::VerifyAndClearExpectations(&mockContext);
1248 }
1249
1250 TEST_F(CCLayerTreeHostImplTest, partialSwap)
1251 {
1252     MockContext* mockContext = new MockContext();
1253     RefPtr<CCGraphicsContext> context = CCGraphicsContext::create3D(GraphicsContext3DPrivate::createGraphicsContextFromWebContext(adoptPtr(mockContext), GraphicsContext3D::RenderDirectlyToHostWindow));
1254     MockContextHarness harness(mockContext);
1255
1256     harness.mustDrawSolidQuad();
1257     harness.mustSetScissor(0, 0, 10, 10);
1258
1259     OwnPtr<CCLayerTreeHostImpl> myHostImpl = createLayerTreeHost(true, context, FakeLayerWithQuads::create(1));
1260
1261     CCLayerTreeHostImpl::FrameData frame;
1262     EXPECT_TRUE(myHostImpl->prepareToDraw(frame));
1263     myHostImpl->drawLayers(frame);
1264     myHostImpl->didDrawAllLayers(frame);
1265     Mock::VerifyAndClearExpectations(&mockContext);
1266 }
1267
1268 TEST_F(CCLayerTreeHostImplTest, partialSwapNoUpdate)
1269 {
1270     MockContext* mockContext = new MockContext();
1271     RefPtr<CCGraphicsContext> context = CCGraphicsContext::create3D(GraphicsContext3DPrivate::createGraphicsContextFromWebContext(adoptPtr(mockContext), GraphicsContext3D::RenderDirectlyToHostWindow));
1272     MockContextHarness harness(mockContext);
1273
1274     harness.mustDrawSolidQuad();
1275     harness.mustSetScissor(0, 8, 2, 2);
1276     harness.mustDrawSolidQuad();
1277     harness.mustSetScissor(0, 0, 10, 10);
1278
1279     OwnPtr<CCLayerTreeHostImpl> myHostImpl = createLayerTreeHost(true, context, FakeLayerWithQuads::create(1));
1280     
1281     // Draw once to make sure layer is not new
1282     CCLayerTreeHostImpl::FrameData frame;
1283     EXPECT_TRUE(myHostImpl->prepareToDraw(frame));
1284     myHostImpl->drawLayers(frame);
1285     myHostImpl->didDrawAllLayers(frame);
1286
1287     // Generate update in layer
1288     CCLayerImpl* root = myHostImpl->rootLayer();
1289     root->setUpdateRect(FloatRect(0, 0, 2, 2));
1290
1291     // This draw should generate no new udpates
1292     EXPECT_TRUE(myHostImpl->prepareToDraw(frame));
1293     myHostImpl->drawLayers(frame);
1294     myHostImpl->didDrawAllLayers(frame);
1295
1296     Mock::VerifyAndClearExpectations(&mockContext);
1297 }
1298
1299 class PartialSwapContext: public FakeWebGraphicsContext3D {
1300 public:
1301     WebString getString(WGC3Denum name)
1302     {
1303         if (name == GraphicsContext3D::EXTENSIONS)
1304             return WebString("GL_CHROMIUM_post_sub_buffer");
1305         return WebString();
1306     }
1307     
1308     WebString getRequestableExtensionsCHROMIUM()
1309     {
1310         return WebString("GL_CHROMIUM_post_sub_buffer");
1311     }
1312 };
1313
1314 static PassOwnPtr<CCLayerTreeHostImpl> setupLayersForOpacity(bool partialSwap, CCLayerTreeHostImplClient* client)
1315 {
1316     CCSettings settings;
1317     settings.partialSwapEnabled = partialSwap;
1318
1319     RefPtr<CCGraphicsContext> context = CCGraphicsContext::create3D(GraphicsContext3DPrivate::createGraphicsContextFromWebContext(adoptPtr(new PartialSwapContext()), GraphicsContext3D::RenderDirectlyToHostWindow));
1320     OwnPtr<CCLayerTreeHostImpl> myHostImpl = CCLayerTreeHostImpl::create(settings, client);
1321     myHostImpl->initializeLayerRenderer(context.release(), UnthrottledUploader);
1322     myHostImpl->setViewportSize(IntSize(100, 100));
1323
1324     /*
1325       Layers are created as follows:
1326
1327          +--------------------+
1328          |                  1 |
1329          |  +-----------+     |
1330          |  |         2 |     |
1331          |  | +-------------------+
1332          |  | |   3               |
1333          |  | +-------------------+
1334          |  |           |     |
1335          |  +-----------+     |
1336          |                    |
1337          |                    |
1338          +--------------------+
1339
1340          Layers 1, 2 have render surfaces
1341      */
1342     OwnPtr<CCLayerImpl> root = CCLayerImpl::create(1);
1343     OwnPtr<CCLayerImpl> child = CCLayerImpl::create(2);
1344     OwnPtr<CCLayerImpl> grandChild = FakeLayerWithQuads::create(3);
1345
1346     IntRect rootRect(0, 0, 100, 100);
1347     IntRect childRect(10, 10, 50, 50);
1348     IntRect grandChildRect(5, 5, 150, 150);
1349
1350     root->createRenderSurface();
1351     root->setAnchorPoint(FloatPoint(0, 0));
1352     root->setPosition(FloatPoint(rootRect.x(), rootRect.y()));
1353     root->setBounds(IntSize(rootRect.width(), rootRect.height()));
1354     root->setVisibleLayerRect(rootRect);
1355     root->setDrawsContent(false);
1356     root->renderSurface()->setContentRect(IntRect(IntPoint(), IntSize(rootRect.width(), rootRect.height())));
1357
1358     child->setAnchorPoint(FloatPoint(0, 0));
1359     child->setPosition(FloatPoint(childRect.x(), childRect.y()));
1360     child->setOpacity(0.5f);
1361     child->setBounds(IntSize(childRect.width(), childRect.height()));
1362     child->setVisibleLayerRect(childRect);
1363     child->setDrawsContent(false);
1364
1365     grandChild->setAnchorPoint(FloatPoint(0, 0));
1366     grandChild->setPosition(IntPoint(grandChildRect.x(), grandChildRect.y()));
1367     grandChild->setBounds(IntSize(grandChildRect.width(), grandChildRect.height()));
1368     grandChild->setVisibleLayerRect(grandChildRect);
1369     grandChild->setDrawsContent(true);
1370
1371     child->addChild(grandChild.release());
1372     root->addChild(child.release());
1373
1374     myHostImpl->setRootLayer(root.release());
1375     return myHostImpl.release();
1376 }
1377
1378 TEST_F(CCLayerTreeHostImplTest, contributingLayerEmptyScissorPartialSwap)
1379 {
1380     OwnPtr<CCLayerTreeHostImpl> myHostImpl = setupLayersForOpacity(true, this);
1381
1382     {
1383         CCLayerTreeHostImpl::FrameData frame;
1384         EXPECT_TRUE(myHostImpl->prepareToDraw(frame));
1385
1386         // Just for consistency, the most interesting stuff already happened
1387         myHostImpl->drawLayers(frame);
1388         myHostImpl->didDrawAllLayers(frame);
1389
1390         // Verify all quads have been computed
1391         ASSERT_EQ(2U, frame.renderPasses.size());
1392         ASSERT_EQ(1U, frame.renderPasses[0]->quadList().size());
1393         ASSERT_EQ(1U, frame.renderPasses[1]->quadList().size());
1394         EXPECT_EQ(CCDrawQuad::SolidColor, frame.renderPasses[0]->quadList()[0]->material());
1395         EXPECT_EQ(CCDrawQuad::RenderPass, frame.renderPasses[1]->quadList()[0]->material());
1396     }
1397 }
1398
1399 TEST_F(CCLayerTreeHostImplTest, contributingLayerEmptyScissorNoPartialSwap)
1400 {
1401     OwnPtr<CCLayerTreeHostImpl> myHostImpl = setupLayersForOpacity(false, this);
1402
1403     {
1404         CCLayerTreeHostImpl::FrameData frame;
1405         EXPECT_TRUE(myHostImpl->prepareToDraw(frame));
1406
1407         // Just for consistency, the most interesting stuff already happened
1408         myHostImpl->drawLayers(frame);
1409         myHostImpl->didDrawAllLayers(frame);
1410
1411         // Verify all quads have been computed
1412         ASSERT_EQ(2U, frame.renderPasses.size());
1413         ASSERT_EQ(1U, frame.renderPasses[0]->quadList().size());
1414         ASSERT_EQ(1U, frame.renderPasses[1]->quadList().size());
1415         EXPECT_EQ(CCDrawQuad::SolidColor, frame.renderPasses[0]->quadList()[0]->material());
1416         EXPECT_EQ(CCDrawQuad::RenderPass, frame.renderPasses[1]->quadList()[0]->material());
1417     }
1418 }
1419
1420 TEST_F(CCLayerTreeHostImplTest, didDrawNotCalledOnScissoredLayer)
1421 {
1422     CCSettings settings;
1423     settings.partialSwapEnabled = true;
1424
1425     RefPtr<CCGraphicsContext> context = CCGraphicsContext::create3D(GraphicsContext3DPrivate::createGraphicsContextFromWebContext(adoptPtr(new PartialSwapContext()), GraphicsContext3D::RenderDirectlyToHostWindow));
1426     OwnPtr<CCLayerTreeHostImpl> myHostImpl = CCLayerTreeHostImpl::create(settings, this);
1427     myHostImpl->initializeLayerRenderer(context.release(), UnthrottledUploader);
1428     myHostImpl->setViewportSize(IntSize(10, 10));
1429
1430     myHostImpl->setRootLayer(DidDrawCheckLayer::create(1));
1431     DidDrawCheckLayer* root = static_cast<DidDrawCheckLayer*>(myHostImpl->rootLayer());
1432     root->setMasksToBounds(true);
1433
1434     root->addChild(DidDrawCheckLayer::create(2));
1435     DidDrawCheckLayer* layer = static_cast<DidDrawCheckLayer*>(root->children()[0].get());
1436
1437     CCLayerTreeHostImpl::FrameData frame;
1438
1439     EXPECT_FALSE(root->willDrawCalled());
1440     EXPECT_FALSE(root->didDrawCalled());
1441     EXPECT_FALSE(layer->willDrawCalled());
1442     EXPECT_FALSE(layer->didDrawCalled());
1443
1444     // We should draw everything the first frame.
1445     EXPECT_TRUE(myHostImpl->prepareToDraw(frame));
1446     myHostImpl->drawLayers(frame);
1447     myHostImpl->didDrawAllLayers(frame);
1448
1449     EXPECT_TRUE(root->willDrawCalled());
1450     EXPECT_TRUE(root->didDrawCalled());
1451     EXPECT_TRUE(layer->willDrawCalled());
1452     EXPECT_TRUE(layer->didDrawCalled());
1453
1454     root->clearDidDrawCheck();
1455     layer->clearDidDrawCheck();
1456
1457     EXPECT_FALSE(root->willDrawCalled());
1458     EXPECT_FALSE(root->didDrawCalled());
1459     EXPECT_FALSE(layer->willDrawCalled());
1460     EXPECT_FALSE(layer->didDrawCalled());
1461
1462     // Drawing again, we should scissor out everything since there is no damage.
1463     EXPECT_TRUE(myHostImpl->prepareToDraw(frame));
1464     myHostImpl->drawLayers(frame);
1465     myHostImpl->didDrawAllLayers(frame);
1466
1467     EXPECT_FALSE(root->willDrawCalled());
1468     EXPECT_FALSE(root->didDrawCalled());
1469     EXPECT_FALSE(layer->willDrawCalled());
1470     EXPECT_FALSE(layer->didDrawCalled());
1471 }
1472
1473 // Make sure that context lost notifications are propagated through the tree.
1474 class ContextLostNotificationCheckLayer : public CCLayerImpl {
1475 public:
1476     static PassOwnPtr<ContextLostNotificationCheckLayer> create(int id) { return adoptPtr(new ContextLostNotificationCheckLayer(id)); }
1477
1478     virtual void didLoseContext() OVERRIDE
1479     {
1480         m_didLoseContextCalled = true;
1481     }
1482
1483     bool didLoseContextCalled() const { return m_didLoseContextCalled; }
1484
1485 private:
1486     explicit ContextLostNotificationCheckLayer(int id)
1487         : CCLayerImpl(id)
1488         , m_didLoseContextCalled(false)
1489     {
1490     }
1491
1492     bool m_didLoseContextCalled;
1493 };
1494
1495 TEST_F(CCLayerTreeHostImplTest, contextLostAndRestoredNotificationSentToAllLayers)
1496 {
1497     m_hostImpl->setRootLayer(ContextLostNotificationCheckLayer::create(0));
1498     ContextLostNotificationCheckLayer* root = static_cast<ContextLostNotificationCheckLayer*>(m_hostImpl->rootLayer());
1499
1500     root->addChild(ContextLostNotificationCheckLayer::create(1));
1501     ContextLostNotificationCheckLayer* layer1 = static_cast<ContextLostNotificationCheckLayer*>(root->children()[0].get());
1502
1503     layer1->addChild(ContextLostNotificationCheckLayer::create(2));
1504     ContextLostNotificationCheckLayer* layer2 = static_cast<ContextLostNotificationCheckLayer*>(layer1->children()[0].get());
1505
1506     EXPECT_FALSE(root->didLoseContextCalled());
1507     EXPECT_FALSE(layer1->didLoseContextCalled());
1508     EXPECT_FALSE(layer2->didLoseContextCalled());
1509
1510     m_hostImpl->initializeLayerRenderer(createContext(), UnthrottledUploader);
1511
1512     EXPECT_TRUE(root->didLoseContextCalled());
1513     EXPECT_TRUE(layer1->didLoseContextCalled());
1514     EXPECT_TRUE(layer2->didLoseContextCalled());
1515 }
1516
1517 class FakeWebGraphicsContext3DMakeCurrentFails : public FakeWebGraphicsContext3D {
1518 public:
1519     virtual bool makeContextCurrent() { return false; }
1520 };
1521
1522 TEST_F(CCLayerTreeHostImplTest, finishAllRenderingAfterContextLost)
1523 {
1524     // The context initialization will fail, but we should still be able to call finishAllRendering() without any ill effects.
1525     m_hostImpl->initializeLayerRenderer(CCGraphicsContext::create3D(GraphicsContext3DPrivate::createGraphicsContextFromWebContext(adoptPtr(new FakeWebGraphicsContext3DMakeCurrentFails), GraphicsContext3D::RenderDirectlyToHostWindow)), UnthrottledUploader);
1526     m_hostImpl->finishAllRendering();
1527 }
1528
1529 class ScrollbarLayerFakePaint : public CCScrollbarLayerImpl {
1530 public:
1531     static PassOwnPtr<ScrollbarLayerFakePaint> create(int id) { return adoptPtr(new ScrollbarLayerFakePaint(id)); }
1532
1533     virtual void paint(GraphicsContext*) { }
1534
1535 private:
1536     ScrollbarLayerFakePaint(int id) : CCScrollbarLayerImpl(id) { }
1537 };
1538
1539 TEST_F(CCLayerTreeHostImplTest, scrollbarLayerLostContext)
1540 {
1541     m_hostImpl->setRootLayer(ScrollbarLayerFakePaint::create(0));
1542     ScrollbarLayerFakePaint* scrollbar = static_cast<ScrollbarLayerFakePaint*>(m_hostImpl->rootLayer());
1543     scrollbar->setBounds(IntSize(1, 1));
1544     scrollbar->setContentBounds(IntSize(1, 1));
1545     scrollbar->setDrawsContent(true);
1546
1547     for (int i = 0; i < 2; ++i) {
1548         CCLayerTreeHostImpl::FrameData frame;
1549         EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
1550         ASSERT(frame.renderPasses.size() == 1);
1551         CCRenderPass* renderPass = frame.renderPasses[0].get();
1552         // Scrollbar layer should always generate quads, even after lost context
1553         EXPECT_GT(renderPass->quadList().size(), 0u);
1554         m_hostImpl->didDrawAllLayers(frame);
1555         m_hostImpl->initializeLayerRenderer(createContext(), UnthrottledUploader);
1556     }
1557 }
1558
1559 // Fake WebGraphicsContext3D that will cause a failure if trying to use a
1560 // resource that wasn't created by it (resources created by
1561 // FakeWebGraphicsContext3D have an id of 1).
1562 class StrictWebGraphicsContext3D : public FakeWebGraphicsContext3D {
1563 public:
1564     virtual WebGLId createBuffer() { return 2; }
1565     virtual WebGLId createFramebuffer() { return 3; }
1566     virtual WebGLId createProgram() { return 4; }
1567     virtual WebGLId createRenderbuffer() { return 5; }
1568     virtual WebGLId createShader(WGC3Denum) { return 6; }
1569     virtual WebGLId createTexture() { return 7; }
1570
1571     virtual void deleteBuffer(WebGLId id)
1572     {
1573         if (id != 2)
1574             ADD_FAILURE() << "Trying to delete buffer id " << id;
1575     }
1576
1577     virtual void deleteFramebuffer(WebGLId id)
1578     {
1579         if (id != 3)
1580             ADD_FAILURE() << "Trying to delete framebuffer id " << id;
1581     }
1582
1583     virtual void deleteProgram(WebGLId id)
1584     {
1585         if (id != 4)
1586             ADD_FAILURE() << "Trying to delete program id " << id;
1587     }
1588
1589     virtual void deleteRenderbuffer(WebGLId id)
1590     {
1591         if (id != 5)
1592             ADD_FAILURE() << "Trying to delete renderbuffer id " << id;
1593     }
1594
1595     virtual void deleteShader(WebGLId id)
1596     {
1597         if (id != 6)
1598             ADD_FAILURE() << "Trying to delete shader id " << id;
1599     }
1600
1601     virtual void deleteTexture(WebGLId id)
1602     {
1603         if (id != 7)
1604             ADD_FAILURE() << "Trying to delete texture id " << id;
1605     }
1606
1607     virtual void bindBuffer(WGC3Denum, WebGLId id)
1608     {
1609         if (id != 2 && id)
1610             ADD_FAILURE() << "Trying to bind buffer id " << id;
1611     }
1612
1613     virtual void bindFramebuffer(WGC3Denum, WebGLId id)
1614     {
1615         if (id != 3 && id)
1616             ADD_FAILURE() << "Trying to bind framebuffer id " << id;
1617     }
1618
1619     virtual void useProgram(WebGLId id)
1620     {
1621         if (id != 4)
1622             ADD_FAILURE() << "Trying to use program id " << id;
1623     }
1624
1625     virtual void bindRenderbuffer(WGC3Denum, WebGLId id)
1626     {
1627         if (id != 5 && id)
1628             ADD_FAILURE() << "Trying to bind renderbuffer id " << id;
1629     }
1630
1631     virtual void attachShader(WebGLId program, WebGLId shader)
1632     {
1633         if ((program != 4) || (shader != 6))
1634             ADD_FAILURE() << "Trying to attach shader id " << shader << " to program id " << program;
1635     }
1636
1637     virtual void bindTexture(WGC3Denum, WebGLId id)
1638     {
1639         if (id != 7 && id)
1640             ADD_FAILURE() << "Trying to bind texture id " << id;
1641     }
1642
1643     static PassRefPtr<GraphicsContext3D> createGraphicsContext()
1644     {
1645         return GraphicsContext3DPrivate::createGraphicsContextFromWebContext(adoptPtr(new StrictWebGraphicsContext3D()), GraphicsContext3D::RenderDirectlyToHostWindow);
1646     }
1647 };
1648
1649 // Fake video frame that represents a 4x4 YUV video frame.
1650 class FakeVideoFrame: public WebVideoFrame {
1651 public:
1652     FakeVideoFrame() { memset(m_data, 0x80, sizeof(m_data)); }
1653     virtual ~FakeVideoFrame() { }
1654     virtual Format format() const { return FormatYV12; }
1655     virtual unsigned width() const { return 4; }
1656     virtual unsigned height() const { return 4; }
1657     virtual unsigned planes() const { return 3; }
1658     virtual int stride(unsigned plane) const { return 4; }
1659     virtual const void* data(unsigned plane) const { return m_data; }
1660     virtual unsigned textureId() const { return 0; }
1661     virtual unsigned textureTarget() const { return 0; }
1662
1663 private:
1664     char m_data[16];
1665 };
1666
1667 // Fake video frame provider that always provides the same FakeVideoFrame.
1668 class FakeVideoFrameProvider: public WebVideoFrameProvider {
1669 public:
1670     FakeVideoFrameProvider() : m_client(0) { }
1671     virtual ~FakeVideoFrameProvider()
1672     {
1673         if (m_client)
1674             m_client->stopUsingProvider();
1675     }
1676
1677     virtual void setVideoFrameProviderClient(Client* client) { m_client = client; }
1678     virtual WebVideoFrame* getCurrentFrame() { return &m_frame; }
1679     virtual void putCurrentFrame(WebVideoFrame*) { }
1680
1681 private:
1682     FakeVideoFrame m_frame;
1683     Client* m_client;
1684 };
1685
1686 TEST_F(CCLayerTreeHostImplTest, dontUseOldResourcesAfterLostContext)
1687 {
1688     OwnPtr<CCLayerImpl> rootLayer(CCLayerImpl::create(0));
1689     rootLayer->setBounds(IntSize(10, 10));
1690     rootLayer->setAnchorPoint(FloatPoint(0, 0));
1691
1692     OwnPtr<CCTiledLayerImpl> tileLayer = CCTiledLayerImpl::create(1);
1693     tileLayer->setBounds(IntSize(10, 10));
1694     tileLayer->setAnchorPoint(FloatPoint(0, 0));
1695     tileLayer->setContentBounds(IntSize(10, 10));
1696     tileLayer->setDrawsContent(true);
1697     tileLayer->setSkipsDraw(false);
1698     OwnPtr<CCLayerTilingData> tilingData(CCLayerTilingData::create(IntSize(10, 10), CCLayerTilingData::NoBorderTexels));
1699     tilingData->setBounds(IntSize(10, 10));
1700     tileLayer->setTilingData(*tilingData);
1701     tileLayer->pushTileProperties(0, 0, 1, IntRect(0, 0, 10, 10));
1702     rootLayer->addChild(tileLayer.release());
1703
1704     OwnPtr<CCTextureLayerImpl> textureLayer = CCTextureLayerImpl::create(2);
1705     textureLayer->setBounds(IntSize(10, 10));
1706     textureLayer->setAnchorPoint(FloatPoint(0, 0));
1707     textureLayer->setContentBounds(IntSize(10, 10));
1708     textureLayer->setDrawsContent(true);
1709     textureLayer->setTextureId(1);
1710     rootLayer->addChild(textureLayer.release());
1711
1712     FakeVideoFrameProvider provider;
1713     OwnPtr<CCVideoLayerImpl> videoLayer = CCVideoLayerImpl::create(3, &provider);
1714     videoLayer->setBounds(IntSize(10, 10));
1715     videoLayer->setAnchorPoint(FloatPoint(0, 0));
1716     videoLayer->setContentBounds(IntSize(10, 10));
1717     videoLayer->setDrawsContent(true);
1718     rootLayer->addChild(videoLayer.release());
1719
1720     m_hostImpl->setRootLayer(rootLayer.release());
1721
1722     CCLayerTreeHostImpl::FrameData frame;
1723     EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
1724     m_hostImpl->drawLayers(frame);
1725     m_hostImpl->didDrawAllLayers(frame);
1726     m_hostImpl->swapBuffers();
1727
1728     // Lose the context, replacing it with a StrictWebGraphicsContext3D, that
1729     // will warn if any resource from the previous context gets used.
1730     m_hostImpl->initializeLayerRenderer(CCGraphicsContext::create3D(StrictWebGraphicsContext3D::createGraphicsContext()), UnthrottledUploader);
1731     EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
1732     m_hostImpl->drawLayers(frame);
1733     m_hostImpl->didDrawAllLayers(frame);
1734     m_hostImpl->swapBuffers();
1735 }
1736
1737 } // namespace