[chromium] Cleanup scissor rect computation/use with damage
[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 protected:
458     explicit DidDrawCheckLayer(int id)
459         : CCTiledLayerImpl(id)
460         , m_didDrawCalled(false)
461         , m_willDrawCalled(false)
462     {
463         setAnchorPoint(FloatPoint(0, 0));
464         setBounds(IntSize(10, 10));
465         setDrawsContent(true);
466     }
467
468 private:
469     bool m_didDrawCalled;
470     bool m_willDrawCalled;
471 };
472
473 TEST_F(CCLayerTreeHostImplTest, didDrawNotCalledOnHiddenLayer)
474 {
475     // The root layer is always drawn, so run this test on a child layer that
476     // will be masked out by the root layer's bounds.
477     m_hostImpl->setRootLayer(DidDrawCheckLayer::create(0));
478     DidDrawCheckLayer* root = static_cast<DidDrawCheckLayer*>(m_hostImpl->rootLayer());
479     root->setMasksToBounds(true);
480
481     root->addChild(DidDrawCheckLayer::create(1));
482     DidDrawCheckLayer* layer = static_cast<DidDrawCheckLayer*>(root->children()[0].get());
483     // Ensure visibleLayerRect for layer is empty
484     layer->setPosition(FloatPoint(100, 100));
485     layer->setBounds(IntSize(10, 10));
486     layer->setContentBounds(IntSize(10, 10));
487
488     CCLayerTreeHostImpl::FrameData frame;
489
490     EXPECT_FALSE(layer->willDrawCalled());
491     EXPECT_FALSE(layer->didDrawCalled());
492
493     EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
494     m_hostImpl->drawLayers(frame);
495     m_hostImpl->didDrawAllLayers(frame);
496
497     EXPECT_FALSE(layer->willDrawCalled());
498     EXPECT_FALSE(layer->didDrawCalled());
499
500     EXPECT_TRUE(layer->visibleLayerRect().isEmpty());
501
502     // Ensure visibleLayerRect for layer layer is not empty
503     layer->setPosition(FloatPoint(0, 0));
504
505     EXPECT_FALSE(layer->willDrawCalled());
506     EXPECT_FALSE(layer->didDrawCalled());
507
508     EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
509     m_hostImpl->drawLayers(frame);
510     m_hostImpl->didDrawAllLayers(frame);
511
512     EXPECT_TRUE(layer->willDrawCalled());
513     EXPECT_TRUE(layer->didDrawCalled());
514
515     EXPECT_FALSE(layer->visibleLayerRect().isEmpty());
516 }
517
518 TEST_F(CCLayerTreeHostImplTest, didDrawCalledOnAllLayers)
519 {
520     m_hostImpl->setRootLayer(DidDrawCheckLayer::create(0));
521     DidDrawCheckLayer* root = static_cast<DidDrawCheckLayer*>(m_hostImpl->rootLayer());
522
523     root->addChild(DidDrawCheckLayer::create(1));
524     DidDrawCheckLayer* layer1 = static_cast<DidDrawCheckLayer*>(root->children()[0].get());
525
526     layer1->addChild(DidDrawCheckLayer::create(2));
527     DidDrawCheckLayer* layer2 = static_cast<DidDrawCheckLayer*>(layer1->children()[0].get());
528
529     layer1->setOpacity(0.3f);
530     layer1->setPreserves3D(false);
531
532     EXPECT_FALSE(root->didDrawCalled());
533     EXPECT_FALSE(layer1->didDrawCalled());
534     EXPECT_FALSE(layer2->didDrawCalled());
535
536     CCLayerTreeHostImpl::FrameData frame;
537     EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
538     m_hostImpl->drawLayers(frame);
539     m_hostImpl->didDrawAllLayers(frame);
540
541     EXPECT_TRUE(root->didDrawCalled());
542     EXPECT_TRUE(layer1->didDrawCalled());
543     EXPECT_TRUE(layer2->didDrawCalled());
544
545     EXPECT_NE(root->renderSurface(), layer1->renderSurface());
546     EXPECT_TRUE(!!layer1->renderSurface());
547 }
548
549 class MissingTextureAnimatingLayer : public DidDrawCheckLayer {
550 public:
551     static PassOwnPtr<MissingTextureAnimatingLayer> create(int id, bool tileMissing, bool skipsDraw, bool animating) { return adoptPtr(new MissingTextureAnimatingLayer(id, tileMissing, skipsDraw, animating)); }
552
553 private:
554     explicit MissingTextureAnimatingLayer(int id, bool tileMissing, bool skipsDraw, bool animating)
555         : DidDrawCheckLayer(id)
556     {
557         OwnPtr<CCLayerTilingData> tilingData = CCLayerTilingData::create(IntSize(10, 10), CCLayerTilingData::NoBorderTexels);
558         tilingData->setBounds(bounds());
559         setTilingData(*tilingData.get());
560         setSkipsDraw(skipsDraw);
561         if (!tileMissing)
562             pushTileProperties(0, 0, 1, IntRect());
563         if (animating)
564             addAnimatedTransformToLayer(*this, 10, 3, 0);
565     }
566 };
567
568 TEST_F(CCLayerTreeHostImplTest, prepareToDrawFailsWhenAnimationUsesCheckerboard)
569 {
570     // When the texture is not missing, we draw as usual.
571     m_hostImpl->setRootLayer(DidDrawCheckLayer::create(0));
572     DidDrawCheckLayer* root = static_cast<DidDrawCheckLayer*>(m_hostImpl->rootLayer());
573     root->addChild(MissingTextureAnimatingLayer::create(1, false, false, true));
574
575     CCLayerTreeHostImpl::FrameData frame;
576
577     EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
578     m_hostImpl->drawLayers(frame);
579     m_hostImpl->didDrawAllLayers(frame);
580
581     // When a texture is missing and we're not animating, we draw as usual with checkerboarding.
582     m_hostImpl->setRootLayer(DidDrawCheckLayer::create(0));
583     root = static_cast<DidDrawCheckLayer*>(m_hostImpl->rootLayer());
584     root->addChild(MissingTextureAnimatingLayer::create(1, true, false, false));
585
586     EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
587     m_hostImpl->drawLayers(frame);
588     m_hostImpl->didDrawAllLayers(frame);
589
590     // When a texture is missing and we're animating, we don't want to draw anything.
591     m_hostImpl->setRootLayer(DidDrawCheckLayer::create(0));
592     root = static_cast<DidDrawCheckLayer*>(m_hostImpl->rootLayer());
593     root->addChild(MissingTextureAnimatingLayer::create(1, true, false, true));
594
595     m_didRequestCommit = false;
596     EXPECT_FALSE(m_hostImpl->prepareToDraw(frame));
597     EXPECT_TRUE(m_didRequestCommit);
598     m_hostImpl->drawLayers(frame);
599     m_hostImpl->didDrawAllLayers(frame);
600
601     // When the layer skips draw and we're animating, we still draw the frame.
602     m_hostImpl->setRootLayer(DidDrawCheckLayer::create(0));
603     root = static_cast<DidDrawCheckLayer*>(m_hostImpl->rootLayer());
604     root->addChild(MissingTextureAnimatingLayer::create(1, false, true, true));
605
606     EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
607     m_hostImpl->drawLayers(frame);
608     m_hostImpl->didDrawAllLayers(frame);
609 }
610
611 class BlendStateTrackerContext: public FakeWebGraphicsContext3D {
612 public:
613     BlendStateTrackerContext() : m_blend(false) { }
614
615     virtual void enable(WGC3Denum cap)
616     {
617         if (cap == GraphicsContext3D::BLEND)
618             m_blend = true;
619     }
620
621     virtual void disable(WGC3Denum cap)
622     {
623         if (cap == GraphicsContext3D::BLEND)
624             m_blend = false;
625     }
626
627     bool blend() const { return m_blend; }
628
629 private:
630     bool m_blend;
631 };
632
633 class BlendStateCheckLayer : public CCLayerImpl {
634 public:
635     static PassOwnPtr<BlendStateCheckLayer> create(int id) { return adoptPtr(new BlendStateCheckLayer(id)); }
636
637     virtual void appendQuads(CCQuadCuller& quadList, const CCSharedQuadState* sharedQuadState, bool&) OVERRIDE
638     {
639         m_quadsAppended = true;
640
641         IntRect opaqueRect;
642         if (opaque() || m_opaqueContents)
643             opaqueRect = m_quadRect;
644         else
645             opaqueRect = m_opaqueContentRect;
646         OwnPtr<CCDrawQuad> testBlendingDrawQuad = CCTileDrawQuad::create(sharedQuadState, m_quadRect, opaqueRect, 0, IntPoint(), IntSize(1, 1), 0, false, false, false, false, false);
647         testBlendingDrawQuad->setQuadVisibleRect(m_quadVisibleRect);
648         EXPECT_EQ(m_blend, testBlendingDrawQuad->needsBlending());
649         EXPECT_EQ(m_hasRenderSurface, !!renderSurface());
650         quadList.append(testBlendingDrawQuad.release());
651     }
652
653     void setExpectation(bool blend, bool hasRenderSurface)
654     {
655         m_blend = blend;
656         m_hasRenderSurface = hasRenderSurface;
657         m_quadsAppended = false;
658     }
659
660     bool quadsAppended() const { return m_quadsAppended; }
661
662     void setQuadRect(const IntRect& rect) { m_quadRect = rect; }
663     void setQuadVisibleRect(const IntRect& rect) { m_quadVisibleRect = rect; }
664     void setOpaqueContents(bool opaque) { m_opaqueContents = opaque; }
665     void setOpaqueContentRect(const IntRect& rect) { m_opaqueContentRect = rect; }
666
667 private:
668     explicit BlendStateCheckLayer(int id)
669         : CCLayerImpl(id)
670         , m_blend(false)
671         , m_hasRenderSurface(false)
672         , m_quadsAppended(false)
673         , m_opaqueContents(false)
674         , m_quadRect(5, 5, 5, 5)
675         , m_quadVisibleRect(5, 5, 5, 5)
676     {
677         setAnchorPoint(FloatPoint(0, 0));
678         setBounds(IntSize(10, 10));
679         setDrawsContent(true);
680     }
681
682     bool m_blend;
683     bool m_hasRenderSurface;
684     bool m_quadsAppended;
685     bool m_opaqueContents;
686     IntRect m_quadRect;
687     IntRect m_opaqueContentRect;
688     IntRect m_quadVisibleRect;
689 };
690
691 // https://bugs.webkit.org/show_bug.cgi?id=75783
692 TEST_F(CCLayerTreeHostImplTest, blendingOffWhenDrawingOpaqueLayers)
693 {
694
695     {
696         OwnPtr<CCLayerImpl> root = CCLayerImpl::create(0);
697         root->setAnchorPoint(FloatPoint(0, 0));
698         root->setBounds(IntSize(10, 10));
699         root->setDrawsContent(false);
700         m_hostImpl->setRootLayer(root.release());
701     }
702     CCLayerImpl* root = m_hostImpl->rootLayer();
703
704     root->addChild(BlendStateCheckLayer::create(1));
705     BlendStateCheckLayer* layer1 = static_cast<BlendStateCheckLayer*>(root->children()[0].get());
706
707     CCLayerTreeHostImpl::FrameData frame;
708
709     // Opaque layer, drawn without blending.
710     layer1->setOpaque(true);
711     layer1->setOpaqueContents(true);
712     layer1->setExpectation(false, false);
713     EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
714     m_hostImpl->drawLayers(frame);
715     EXPECT_TRUE(layer1->quadsAppended());
716     m_hostImpl->didDrawAllLayers(frame);
717
718     // Layer with translucent content, but opaque content, so drawn without blending.
719     layer1->setOpaque(false);
720     layer1->setOpaqueContents(true);
721     layer1->setExpectation(false, false);
722     EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
723     m_hostImpl->drawLayers(frame);
724     EXPECT_TRUE(layer1->quadsAppended());
725     m_hostImpl->didDrawAllLayers(frame);
726
727     // Layer with translucent content and painting, so drawn with blending.
728     layer1->setOpaque(false);
729     layer1->setOpaqueContents(false);
730     layer1->setExpectation(true, false);
731     EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
732     m_hostImpl->drawLayers(frame);
733     EXPECT_TRUE(layer1->quadsAppended());
734     m_hostImpl->didDrawAllLayers(frame);
735
736     // Layer with translucent opacity, drawn with blending.
737     layer1->setOpaque(true);
738     layer1->setOpaqueContents(true);
739     layer1->setOpacity(0.5);
740     layer1->setExpectation(true, false);
741     EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
742     m_hostImpl->drawLayers(frame);
743     EXPECT_TRUE(layer1->quadsAppended());
744     m_hostImpl->didDrawAllLayers(frame);
745
746     // Layer with translucent opacity and painting, drawn with blending.
747     layer1->setOpaque(true);
748     layer1->setOpaqueContents(false);
749     layer1->setOpacity(0.5);
750     layer1->setExpectation(true, false);
751     EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
752     m_hostImpl->drawLayers(frame);
753     EXPECT_TRUE(layer1->quadsAppended());
754     m_hostImpl->didDrawAllLayers(frame);
755
756     layer1->addChild(BlendStateCheckLayer::create(2));
757     BlendStateCheckLayer* layer2 = static_cast<BlendStateCheckLayer*>(layer1->children()[0].get());
758
759     // 2 opaque layers, drawn without blending.
760     layer1->setOpaque(true);
761     layer1->setOpaqueContents(true);
762     layer1->setOpacity(1);
763     layer1->setExpectation(false, false);
764     layer2->setOpaque(true);
765     layer2->setOpaqueContents(true);
766     layer2->setOpacity(1);
767     layer2->setExpectation(false, false);
768     EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
769     m_hostImpl->drawLayers(frame);
770     EXPECT_TRUE(layer1->quadsAppended());
771     EXPECT_TRUE(layer2->quadsAppended());
772     m_hostImpl->didDrawAllLayers(frame);
773
774     // Parent layer with translucent content, drawn with blending.
775     // Child layer with opaque content, drawn without blending.
776     layer1->setOpaque(false);
777     layer1->setOpaqueContents(false);
778     layer1->setExpectation(true, false);
779     layer2->setExpectation(false, false);
780     EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
781     m_hostImpl->drawLayers(frame);
782     EXPECT_TRUE(layer1->quadsAppended());
783     EXPECT_TRUE(layer2->quadsAppended());
784     m_hostImpl->didDrawAllLayers(frame);
785
786     // Parent layer with translucent content but opaque painting, drawn without blending.
787     // Child layer with opaque content, drawn without blending.
788     layer1->setOpaque(false);
789     layer1->setOpaqueContents(true);
790     layer1->setExpectation(false, false);
791     layer2->setExpectation(false, false);
792     EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
793     m_hostImpl->drawLayers(frame);
794     EXPECT_TRUE(layer1->quadsAppended());
795     EXPECT_TRUE(layer2->quadsAppended());
796     m_hostImpl->didDrawAllLayers(frame);
797
798     // Parent layer with translucent opacity and opaque content. Since it has a
799     // drawing child, it's drawn to a render surface which carries the opacity,
800     // so it's itself drawn without blending.
801     // Child layer with opaque content, drawn without blending (parent surface
802     // carries the inherited opacity).
803     layer1->setOpaque(true);
804     layer1->setOpaqueContents(true);
805     layer1->setOpacity(0.5);
806     layer1->setExpectation(false, true);
807     layer2->setExpectation(false, false);
808     EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
809     m_hostImpl->drawLayers(frame);
810     EXPECT_TRUE(layer1->quadsAppended());
811     EXPECT_TRUE(layer2->quadsAppended());
812     m_hostImpl->didDrawAllLayers(frame);
813
814     // Draw again, but with child non-opaque, to make sure
815     // layer1 not culled.
816     layer1->setOpaque(true);
817     layer1->setOpaqueContents(true);
818     layer1->setOpacity(1);
819     layer1->setExpectation(false, false);
820     layer2->setOpaque(true);
821     layer2->setOpaqueContents(true);
822     layer2->setOpacity(0.5);
823     layer2->setExpectation(true, false);
824     EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
825     m_hostImpl->drawLayers(frame);
826     EXPECT_TRUE(layer1->quadsAppended());
827     EXPECT_TRUE(layer2->quadsAppended());
828     m_hostImpl->didDrawAllLayers(frame);
829
830     // A second way of making the child non-opaque.
831     layer1->setOpaque(true);
832     layer1->setOpacity(1);
833     layer1->setExpectation(false, false);
834     layer2->setOpaque(false);
835     layer2->setOpaqueContents(false);
836     layer2->setOpacity(1);
837     layer2->setExpectation(true, false);
838     EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
839     m_hostImpl->drawLayers(frame);
840     EXPECT_TRUE(layer1->quadsAppended());
841     EXPECT_TRUE(layer2->quadsAppended());
842     m_hostImpl->didDrawAllLayers(frame);
843
844     // And when the layer says its not opaque but is painted opaque, it is not blended.
845     layer1->setOpaque(true);
846     layer1->setOpacity(1);
847     layer1->setExpectation(false, false);
848     layer2->setOpaque(false);
849     layer2->setOpaqueContents(true);
850     layer2->setOpacity(1);
851     layer2->setExpectation(false, false);
852     EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
853     m_hostImpl->drawLayers(frame);
854     EXPECT_TRUE(layer1->quadsAppended());
855     EXPECT_TRUE(layer2->quadsAppended());
856     m_hostImpl->didDrawAllLayers(frame);
857
858     // Layer with partially opaque contents, drawn with blending.
859     layer1->setOpaque(false);
860     layer1->setQuadRect(IntRect(5, 5, 5, 5));
861     layer1->setQuadVisibleRect(IntRect(5, 5, 5, 5));
862     layer1->setOpaqueContents(false);
863     layer1->setOpaqueContentRect(IntRect(5, 5, 2, 5));
864     layer1->setExpectation(true, false);
865     EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
866     m_hostImpl->drawLayers(frame);
867     EXPECT_TRUE(layer1->quadsAppended());
868     m_hostImpl->didDrawAllLayers(frame);
869
870     // Layer with partially opaque contents partially culled, drawn with blending.
871     layer1->setOpaque(false);
872     layer1->setQuadRect(IntRect(5, 5, 5, 5));
873     layer1->setQuadVisibleRect(IntRect(5, 5, 5, 2));
874     layer1->setOpaqueContents(false);
875     layer1->setOpaqueContentRect(IntRect(5, 5, 2, 5));
876     layer1->setExpectation(true, false);
877     EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
878     m_hostImpl->drawLayers(frame);
879     EXPECT_TRUE(layer1->quadsAppended());
880     m_hostImpl->didDrawAllLayers(frame);
881
882     // Layer with partially opaque contents culled, drawn with blending.
883     layer1->setOpaque(false);
884     layer1->setQuadRect(IntRect(5, 5, 5, 5));
885     layer1->setQuadVisibleRect(IntRect(7, 5, 3, 5));
886     layer1->setOpaqueContents(false);
887     layer1->setOpaqueContentRect(IntRect(5, 5, 2, 5));
888     layer1->setExpectation(true, false);
889     EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
890     m_hostImpl->drawLayers(frame);
891     EXPECT_TRUE(layer1->quadsAppended());
892     m_hostImpl->didDrawAllLayers(frame);
893
894     // Layer with partially opaque contents and translucent contents culled, drawn without blending.
895     layer1->setOpaque(false);
896     layer1->setQuadRect(IntRect(5, 5, 5, 5));
897     layer1->setQuadVisibleRect(IntRect(5, 5, 2, 5));
898     layer1->setOpaqueContents(false);
899     layer1->setOpaqueContentRect(IntRect(5, 5, 2, 5));
900     layer1->setExpectation(false, false);
901     EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
902     m_hostImpl->drawLayers(frame);
903     EXPECT_TRUE(layer1->quadsAppended());
904     m_hostImpl->didDrawAllLayers(frame);
905
906 }
907
908 TEST_F(CCLayerTreeHostImplTest, viewportCovered)
909 {
910     m_hostImpl->initializeLayerRenderer(createContext(), UnthrottledUploader);
911     m_hostImpl->setBackgroundColor(Color::gray);
912
913     IntSize viewportSize(1000, 1000);
914     m_hostImpl->setViewportSize(viewportSize);
915
916     m_hostImpl->setRootLayer(BlendStateCheckLayer::create(0));
917     BlendStateCheckLayer* root = static_cast<BlendStateCheckLayer*>(m_hostImpl->rootLayer());
918     root->setExpectation(false, true);
919     root->setOpaque(true);
920
921     // No gutter rects
922     {
923         IntRect layerRect(0, 0, 1000, 1000);
924         root->setPosition(layerRect.location());
925         root->setBounds(layerRect.size());
926         root->setContentBounds(layerRect.size());
927         root->setQuadRect(IntRect(IntPoint(), layerRect.size()));
928         root->setQuadVisibleRect(IntRect(IntPoint(), layerRect.size()));
929
930         CCLayerTreeHostImpl::FrameData frame;
931         EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
932         ASSERT_EQ(1u, frame.renderPasses.size());
933
934         size_t numGutterQuads = 0;
935         for (size_t i = 0; i < frame.renderPasses[0]->quadList().size(); ++i)
936             numGutterQuads += (frame.renderPasses[0]->quadList()[i]->material() == CCDrawQuad::SolidColor) ? 1 : 0;
937         EXPECT_EQ(0u, numGutterQuads);
938         EXPECT_EQ(1u, frame.renderPasses[0]->quadList().size());
939
940         verifyQuadsExactlyCoverRect(frame.renderPasses[0]->quadList(), IntRect(-layerRect.location(), viewportSize));
941         m_hostImpl->didDrawAllLayers(frame);
942     }
943
944     // Empty visible content area (fullscreen gutter rect)
945     {
946         IntRect layerRect(0, 0, 0, 0);
947         root->setPosition(layerRect.location());
948         root->setBounds(layerRect.size());
949         root->setContentBounds(layerRect.size());
950         root->setQuadRect(IntRect(IntPoint(), layerRect.size()));
951         root->setQuadVisibleRect(IntRect(IntPoint(), layerRect.size()));
952
953         CCLayerTreeHostImpl::FrameData frame;
954         EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
955         ASSERT_EQ(1u, frame.renderPasses.size());
956         m_hostImpl->didDrawAllLayers(frame);
957
958         size_t numGutterQuads = 0;
959         for (size_t i = 0; i < frame.renderPasses[0]->quadList().size(); ++i)
960             numGutterQuads += (frame.renderPasses[0]->quadList()[i]->material() == CCDrawQuad::SolidColor) ? 1 : 0;
961         EXPECT_EQ(1u, numGutterQuads);
962         EXPECT_EQ(1u, frame.renderPasses[0]->quadList().size());
963
964         verifyQuadsExactlyCoverRect(frame.renderPasses[0]->quadList(), IntRect(-layerRect.location(), viewportSize));
965         m_hostImpl->didDrawAllLayers(frame);
966     }
967
968     // Content area in middle of clip rect (four surrounding gutter rects)
969     {
970         IntRect layerRect(500, 500, 200, 200);
971         root->setPosition(layerRect.location());
972         root->setBounds(layerRect.size());
973         root->setContentBounds(layerRect.size());
974         root->setQuadRect(IntRect(IntPoint(), layerRect.size()));
975         root->setQuadVisibleRect(IntRect(IntPoint(), layerRect.size()));
976
977         CCLayerTreeHostImpl::FrameData frame;
978         EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
979         ASSERT_EQ(1u, frame.renderPasses.size());
980
981         size_t numGutterQuads = 0;
982         for (size_t i = 0; i < frame.renderPasses[0]->quadList().size(); ++i)
983             numGutterQuads += (frame.renderPasses[0]->quadList()[i]->material() == CCDrawQuad::SolidColor) ? 1 : 0;
984         EXPECT_EQ(4u, numGutterQuads);
985         EXPECT_EQ(5u, frame.renderPasses[0]->quadList().size());
986
987         verifyQuadsExactlyCoverRect(frame.renderPasses[0]->quadList(), IntRect(-layerRect.location(), viewportSize));
988         m_hostImpl->didDrawAllLayers(frame);
989     }
990
991 }
992
993
994 class ReshapeTrackerContext: public FakeWebGraphicsContext3D {
995 public:
996     ReshapeTrackerContext() : m_reshapeCalled(false) { }
997
998     virtual void reshape(int width, int height)
999     {
1000         m_reshapeCalled = true;
1001     }
1002
1003     bool reshapeCalled() const { return m_reshapeCalled; }
1004
1005 private:
1006     bool m_reshapeCalled;
1007 };
1008
1009 class FakeDrawableCCLayerImpl: public CCLayerImpl {
1010 public:
1011     explicit FakeDrawableCCLayerImpl(int id) : CCLayerImpl(id) { }
1012 };
1013
1014 // Only reshape when we know we are going to draw. Otherwise, the reshape
1015 // can leave the window at the wrong size if we never draw and the proper
1016 // viewport size is never set.
1017 TEST_F(CCLayerTreeHostImplTest, reshapeNotCalledUntilDraw)
1018 {
1019     ReshapeTrackerContext* reshapeTracker = new ReshapeTrackerContext();
1020     RefPtr<GraphicsContext3D> context = GraphicsContext3DPrivate::createGraphicsContextFromWebContext(adoptPtr(reshapeTracker), GraphicsContext3D::RenderDirectlyToHostWindow);
1021     RefPtr<CCGraphicsContext> ccContext = CCGraphicsContext::create3D(context);
1022     m_hostImpl->initializeLayerRenderer(ccContext, UnthrottledUploader);
1023
1024     CCLayerImpl* root = new FakeDrawableCCLayerImpl(1);
1025     root->setAnchorPoint(FloatPoint(0, 0));
1026     root->setBounds(IntSize(10, 10));
1027     root->setDrawsContent(true);
1028     m_hostImpl->setRootLayer(adoptPtr(root));
1029     EXPECT_FALSE(reshapeTracker->reshapeCalled());
1030
1031     CCLayerTreeHostImpl::FrameData frame;
1032     EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
1033     m_hostImpl->drawLayers(frame);
1034     EXPECT_TRUE(reshapeTracker->reshapeCalled());
1035     m_hostImpl->didDrawAllLayers(frame);
1036 }
1037
1038 class PartialSwapTrackerContext : public FakeWebGraphicsContext3D {
1039 public:
1040     virtual void postSubBufferCHROMIUM(int x, int y, int width, int height)
1041     {
1042         m_partialSwapRect = IntRect(x, y, width, height);
1043     }
1044
1045     virtual WebString getString(WGC3Denum name)
1046     {
1047         if (name == GraphicsContext3D::EXTENSIONS)
1048             return WebString("GL_CHROMIUM_post_sub_buffer GL_CHROMIUM_set_visibility");
1049
1050         return WebString();
1051     }
1052
1053     IntRect partialSwapRect() const { return m_partialSwapRect; }
1054
1055 private:
1056     IntRect m_partialSwapRect;
1057 };
1058
1059 // Make sure damage tracking propagates all the way to the graphics context,
1060 // where it should request to swap only the subBuffer that is damaged.
1061 TEST_F(CCLayerTreeHostImplTest, partialSwapReceivesDamageRect)
1062 {
1063     PartialSwapTrackerContext* partialSwapTracker = new PartialSwapTrackerContext();
1064     RefPtr<GraphicsContext3D> context = GraphicsContext3DPrivate::createGraphicsContextFromWebContext(adoptPtr(partialSwapTracker), GraphicsContext3D::RenderDirectlyToHostWindow);
1065     RefPtr<CCGraphicsContext> ccContext = CCGraphicsContext::create3D(context);
1066
1067     // This test creates its own CCLayerTreeHostImpl, so
1068     // that we can force partial swap enabled.
1069     CCSettings settings;
1070     settings.partialSwapEnabled = true;
1071     OwnPtr<CCLayerTreeHostImpl> layerTreeHostImpl = CCLayerTreeHostImpl::create(settings, this);
1072     layerTreeHostImpl->initializeLayerRenderer(ccContext, UnthrottledUploader);
1073     layerTreeHostImpl->setViewportSize(IntSize(500, 500));
1074
1075     CCLayerImpl* root = new FakeDrawableCCLayerImpl(1);
1076     CCLayerImpl* child = new FakeDrawableCCLayerImpl(2);
1077     child->setPosition(FloatPoint(12, 13));
1078     child->setAnchorPoint(FloatPoint(0, 0));
1079     child->setBounds(IntSize(14, 15));
1080     child->setDrawsContent(true);
1081     root->setAnchorPoint(FloatPoint(0, 0));
1082     root->setBounds(IntSize(500, 500));
1083     root->setDrawsContent(true);
1084     root->addChild(adoptPtr(child));
1085     layerTreeHostImpl->setRootLayer(adoptPtr(root));
1086
1087     CCLayerTreeHostImpl::FrameData frame;
1088
1089     // First frame, the entire screen should get swapped.
1090     EXPECT_TRUE(layerTreeHostImpl->prepareToDraw(frame));
1091     layerTreeHostImpl->drawLayers(frame);
1092     layerTreeHostImpl->didDrawAllLayers(frame);
1093     layerTreeHostImpl->swapBuffers();
1094     IntRect actualSwapRect = partialSwapTracker->partialSwapRect();
1095     IntRect expectedSwapRect = IntRect(IntPoint::zero(), IntSize(500, 500));
1096     EXPECT_EQ(expectedSwapRect.x(), actualSwapRect.x());
1097     EXPECT_EQ(expectedSwapRect.y(), actualSwapRect.y());
1098     EXPECT_EQ(expectedSwapRect.width(), actualSwapRect.width());
1099     EXPECT_EQ(expectedSwapRect.height(), actualSwapRect.height());
1100
1101     // Second frame, only the damaged area should get swapped. Damage should be the union
1102     // of old and new child rects.
1103     // expected damage rect: IntRect(IntPoint::zero(), IntSize(26, 28));
1104     // expected swap rect: vertically flipped, with origin at bottom left corner.
1105     child->setPosition(FloatPoint(0, 0));
1106     EXPECT_TRUE(layerTreeHostImpl->prepareToDraw(frame));
1107     layerTreeHostImpl->drawLayers(frame);
1108     m_hostImpl->didDrawAllLayers(frame);
1109     layerTreeHostImpl->swapBuffers();
1110     actualSwapRect = partialSwapTracker->partialSwapRect();
1111     expectedSwapRect = IntRect(IntPoint(0, 500-28), IntSize(26, 28));
1112     EXPECT_EQ(expectedSwapRect.x(), actualSwapRect.x());
1113     EXPECT_EQ(expectedSwapRect.y(), actualSwapRect.y());
1114     EXPECT_EQ(expectedSwapRect.width(), actualSwapRect.width());
1115     EXPECT_EQ(expectedSwapRect.height(), actualSwapRect.height());
1116
1117     // Make sure that partial swap is constrained to the viewport dimensions
1118     // expected damage rect: IntRect(IntPoint::zero(), IntSize(500, 500));
1119     // expected swap rect: flipped damage rect, but also clamped to viewport
1120     layerTreeHostImpl->setViewportSize(IntSize(10, 10));
1121     root->setOpacity(0.7f); // this will damage everything
1122     EXPECT_TRUE(layerTreeHostImpl->prepareToDraw(frame));
1123     layerTreeHostImpl->drawLayers(frame);
1124     m_hostImpl->didDrawAllLayers(frame);
1125     layerTreeHostImpl->swapBuffers();
1126     actualSwapRect = partialSwapTracker->partialSwapRect();
1127     expectedSwapRect = IntRect(IntPoint::zero(), IntSize(10, 10));
1128     EXPECT_EQ(expectedSwapRect.x(), actualSwapRect.x());
1129     EXPECT_EQ(expectedSwapRect.y(), actualSwapRect.y());
1130     EXPECT_EQ(expectedSwapRect.width(), actualSwapRect.width());
1131     EXPECT_EQ(expectedSwapRect.height(), actualSwapRect.height());
1132 }
1133
1134 class FakeLayerWithQuads : public CCLayerImpl {
1135 public:
1136     static PassOwnPtr<FakeLayerWithQuads> create(int id) { return adoptPtr(new FakeLayerWithQuads(id)); }
1137
1138     virtual void appendQuads(CCQuadCuller& quadList, const CCSharedQuadState* sharedQuadState, bool&) OVERRIDE
1139     {
1140         const Color gray(100, 100, 100);
1141         IntRect quadRect(0, 0, 5, 5);
1142         OwnPtr<CCDrawQuad> myQuad = CCSolidColorDrawQuad::create(sharedQuadState, quadRect, gray);
1143         quadList.append(myQuad.release());
1144     }
1145
1146 private:
1147     FakeLayerWithQuads(int id)
1148         : CCLayerImpl(id)
1149     {
1150     }
1151 };
1152
1153 class MockContext : public FakeWebGraphicsContext3D {
1154 public:
1155     MOCK_METHOD1(useProgram, void(WebGLId program));
1156     MOCK_METHOD5(uniform4f, void(WGC3Dint location, WGC3Dfloat x, WGC3Dfloat y, WGC3Dfloat z, WGC3Dfloat w));
1157     MOCK_METHOD4(uniformMatrix4fv, void(WGC3Dint location, WGC3Dsizei count, WGC3Dboolean transpose, const WGC3Dfloat* value));
1158     MOCK_METHOD4(drawElements, void(WGC3Denum mode, WGC3Dsizei count, WGC3Denum type, WGC3Dintptr offset));
1159     MOCK_METHOD1(getString, WebString(WGC3Denum name));
1160     MOCK_METHOD0(getRequestableExtensionsCHROMIUM, WebString());
1161     MOCK_METHOD1(enable, void(WGC3Denum cap));
1162     MOCK_METHOD4(scissor, void(WGC3Dint x, WGC3Dint y, WGC3Dsizei width, WGC3Dsizei height));
1163 };
1164
1165 class MockContextHarness {
1166 private:
1167     MockContext* m_context;
1168 public:
1169     MockContextHarness(MockContext* context)
1170         : m_context(context)
1171     {
1172         // Catch "uninteresting" calls
1173         EXPECT_CALL(*m_context, useProgram(_))
1174             .Times(0);
1175
1176         EXPECT_CALL(*m_context, drawElements(_, _, _, _))
1177             .Times(0);
1178
1179         // These are not asserted
1180         EXPECT_CALL(*m_context, uniformMatrix4fv(_, _, _, _))
1181             .WillRepeatedly(Return());
1182
1183         EXPECT_CALL(*m_context, uniform4f(_, _, _, _, _))
1184             .WillRepeatedly(Return());
1185
1186         // Any other strings are empty
1187         EXPECT_CALL(*m_context, getString(_))
1188             .WillRepeatedly(Return(WebString()));
1189
1190         // Support for partial swap, if needed
1191         EXPECT_CALL(*m_context, getString(GraphicsContext3D::EXTENSIONS))
1192             .WillRepeatedly(Return(WebString("GL_CHROMIUM_post_sub_buffer")));
1193
1194         EXPECT_CALL(*m_context, getRequestableExtensionsCHROMIUM())
1195             .WillRepeatedly(Return(WebString("GL_CHROMIUM_post_sub_buffer")));
1196
1197         // Any un-sanctioned calls to enable() are OK
1198         EXPECT_CALL(*m_context, enable(_))
1199             .WillRepeatedly(Return());
1200     }
1201
1202     void mustDrawSolidQuad()
1203     {
1204         EXPECT_CALL(*m_context, drawElements(GraphicsContext3D::TRIANGLES, 6, GraphicsContext3D::UNSIGNED_SHORT, 0))
1205             .WillOnce(Return())
1206             .RetiresOnSaturation();
1207
1208         // 1 is hardcoded return value of fake createProgram()
1209         EXPECT_CALL(*m_context, useProgram(1))
1210             .WillOnce(Return())
1211             .RetiresOnSaturation();
1212
1213     }
1214
1215     void mustSetScissor(int x, int y, int width, int height)
1216     {
1217         EXPECT_CALL(*m_context, enable(GraphicsContext3D::SCISSOR_TEST))
1218             .WillRepeatedly(Return());
1219
1220         EXPECT_CALL(*m_context, scissor(x, y, width, height))
1221             .Times(AtLeast(1))
1222             .WillRepeatedly(Return());
1223     }
1224
1225 };
1226
1227 TEST_F(CCLayerTreeHostImplTest, noPartialSwap)
1228 {
1229     MockContext* mockContext = new MockContext();
1230     RefPtr<CCGraphicsContext> context = CCGraphicsContext::create3D(GraphicsContext3DPrivate::createGraphicsContextFromWebContext(adoptPtr(mockContext), GraphicsContext3D::RenderDirectlyToHostWindow));
1231     MockContextHarness harness(mockContext);
1232
1233     harness.mustDrawSolidQuad();
1234     harness.mustSetScissor(0, 0, 10, 10);
1235
1236     // Run test case
1237     OwnPtr<CCLayerTreeHostImpl> myHostImpl = createLayerTreeHost(false, context, FakeLayerWithQuads::create(1));
1238
1239     CCLayerTreeHostImpl::FrameData frame;
1240     EXPECT_TRUE(myHostImpl->prepareToDraw(frame));
1241     myHostImpl->drawLayers(frame);
1242     myHostImpl->didDrawAllLayers(frame);
1243     Mock::VerifyAndClearExpectations(&mockContext);
1244 }
1245
1246 TEST_F(CCLayerTreeHostImplTest, partialSwap)
1247 {
1248     MockContext* mockContext = new MockContext();
1249     RefPtr<CCGraphicsContext> context = CCGraphicsContext::create3D(GraphicsContext3DPrivate::createGraphicsContextFromWebContext(adoptPtr(mockContext), GraphicsContext3D::RenderDirectlyToHostWindow));
1250     MockContextHarness harness(mockContext);
1251
1252     harness.mustDrawSolidQuad();
1253     harness.mustSetScissor(0, 0, 10, 10);
1254
1255     OwnPtr<CCLayerTreeHostImpl> myHostImpl = createLayerTreeHost(true, context, FakeLayerWithQuads::create(1));
1256
1257     CCLayerTreeHostImpl::FrameData frame;
1258     EXPECT_TRUE(myHostImpl->prepareToDraw(frame));
1259     myHostImpl->drawLayers(frame);
1260     myHostImpl->didDrawAllLayers(frame);
1261     Mock::VerifyAndClearExpectations(&mockContext);
1262 }
1263
1264 TEST_F(CCLayerTreeHostImplTest, partialSwapNoUpdate)
1265 {
1266     MockContext* mockContext = new MockContext();
1267     RefPtr<CCGraphicsContext> context = CCGraphicsContext::create3D(GraphicsContext3DPrivate::createGraphicsContextFromWebContext(adoptPtr(mockContext), GraphicsContext3D::RenderDirectlyToHostWindow));
1268     MockContextHarness harness(mockContext);
1269
1270     harness.mustDrawSolidQuad();
1271     harness.mustSetScissor(0, 8, 2, 2);
1272     harness.mustDrawSolidQuad();
1273     harness.mustSetScissor(0, 0, 10, 10);
1274
1275     OwnPtr<CCLayerTreeHostImpl> myHostImpl = createLayerTreeHost(true, context, FakeLayerWithQuads::create(1));
1276     
1277     // Draw once to make sure layer is not new
1278     CCLayerTreeHostImpl::FrameData frame;
1279     EXPECT_TRUE(myHostImpl->prepareToDraw(frame));
1280     myHostImpl->drawLayers(frame);
1281     myHostImpl->didDrawAllLayers(frame);
1282
1283     // Generate update in layer
1284     CCLayerImpl* root = myHostImpl->rootLayer();
1285     root->setUpdateRect(FloatRect(0, 0, 2, 2));
1286
1287     // This draw should generate no new udpates
1288     EXPECT_TRUE(myHostImpl->prepareToDraw(frame));
1289     myHostImpl->drawLayers(frame);
1290     myHostImpl->didDrawAllLayers(frame);
1291
1292     Mock::VerifyAndClearExpectations(&mockContext);
1293 }
1294
1295 class PartialSwapContext: public FakeWebGraphicsContext3D {
1296 public:
1297     WebString getString(WGC3Denum name)
1298     {
1299         if (name == GraphicsContext3D::EXTENSIONS)
1300             return WebString("GL_CHROMIUM_post_sub_buffer");
1301         return WebString();
1302     }
1303     
1304     WebString getRequestableExtensionsCHROMIUM()
1305     {
1306         return WebString("GL_CHROMIUM_post_sub_buffer");
1307     }
1308 };
1309
1310 static PassOwnPtr<CCLayerTreeHostImpl> setupLayersForOpacity(bool partialSwap, CCLayerTreeHostImplClient* client)
1311 {
1312     CCSettings settings;
1313     settings.partialSwapEnabled = partialSwap;
1314
1315     RefPtr<CCGraphicsContext> context = CCGraphicsContext::create3D(GraphicsContext3DPrivate::createGraphicsContextFromWebContext(adoptPtr(new PartialSwapContext()), GraphicsContext3D::RenderDirectlyToHostWindow));
1316     OwnPtr<CCLayerTreeHostImpl> myHostImpl = CCLayerTreeHostImpl::create(settings, client);
1317     myHostImpl->initializeLayerRenderer(context.release(), UnthrottledUploader);
1318     myHostImpl->setViewportSize(IntSize(100, 100));
1319
1320     /*
1321       Layers are created as follows:
1322
1323          +--------------------+
1324          |                  1 |
1325          |  +-----------+     |
1326          |  |         2 |     |
1327          |  | +-------------------+
1328          |  | |   3               |
1329          |  | +-------------------+
1330          |  |           |     |
1331          |  +-----------+     |
1332          |                    |
1333          |                    |
1334          +--------------------+
1335
1336          Layers 1, 2 have render surfaces
1337      */
1338     OwnPtr<CCLayerImpl> root = CCLayerImpl::create(1);
1339     OwnPtr<CCLayerImpl> child = CCLayerImpl::create(2);
1340     OwnPtr<CCLayerImpl> grandChild = FakeLayerWithQuads::create(3);
1341
1342     IntRect rootRect(0, 0, 100, 100);
1343     IntRect childRect(10, 10, 50, 50);
1344     IntRect grandChildRect(5, 5, 150, 150);
1345
1346     root->createRenderSurface();
1347     root->setAnchorPoint(FloatPoint(0, 0));
1348     root->setPosition(FloatPoint(rootRect.x(), rootRect.y()));
1349     root->setBounds(IntSize(rootRect.width(), rootRect.height()));
1350     root->setVisibleLayerRect(rootRect);
1351     root->setDrawsContent(false);
1352     root->renderSurface()->setContentRect(IntRect(IntPoint(), IntSize(rootRect.width(), rootRect.height())));
1353
1354     child->setAnchorPoint(FloatPoint(0, 0));
1355     child->setPosition(FloatPoint(childRect.x(), childRect.y()));
1356     child->setOpacity(0.5f);
1357     child->setBounds(IntSize(childRect.width(), childRect.height()));
1358     child->setVisibleLayerRect(childRect);
1359     child->setDrawsContent(false);
1360
1361     grandChild->setAnchorPoint(FloatPoint(0, 0));
1362     grandChild->setPosition(IntPoint(grandChildRect.x(), grandChildRect.y()));
1363     grandChild->setBounds(IntSize(grandChildRect.width(), grandChildRect.height()));
1364     grandChild->setVisibleLayerRect(grandChildRect);
1365     grandChild->setDrawsContent(true);
1366
1367     child->addChild(grandChild.release());
1368     root->addChild(child.release());
1369
1370     myHostImpl->setRootLayer(root.release());
1371     return myHostImpl.release();
1372 }
1373
1374 TEST_F(CCLayerTreeHostImplTest, contributingLayerEmptyScissorPartialSwap)
1375 {
1376     OwnPtr<CCLayerTreeHostImpl> myHostImpl = setupLayersForOpacity(true, this);
1377
1378     {
1379         CCLayerTreeHostImpl::FrameData frame;
1380         EXPECT_TRUE(myHostImpl->prepareToDraw(frame));
1381
1382         // Just for consistency, the most interesting stuff already happened
1383         myHostImpl->drawLayers(frame);
1384         myHostImpl->didDrawAllLayers(frame);
1385
1386         // Verify all quads have been computed
1387         ASSERT_EQ(2U, frame.renderPasses.size());
1388         ASSERT_EQ(1U, frame.renderPasses[0]->quadList().size());
1389         ASSERT_EQ(1U, frame.renderPasses[1]->quadList().size());
1390         EXPECT_EQ(CCDrawQuad::SolidColor, frame.renderPasses[0]->quadList()[0]->material());
1391         EXPECT_EQ(CCDrawQuad::RenderSurface, frame.renderPasses[1]->quadList()[0]->material());
1392     }
1393 }
1394
1395 TEST_F(CCLayerTreeHostImplTest, contributingLayerEmptyScissorNoPartialSwap)
1396 {
1397     OwnPtr<CCLayerTreeHostImpl> myHostImpl = setupLayersForOpacity(false, this);
1398
1399     {
1400         CCLayerTreeHostImpl::FrameData frame;
1401         EXPECT_TRUE(myHostImpl->prepareToDraw(frame));
1402
1403         // Just for consistency, the most interesting stuff already happened
1404         myHostImpl->drawLayers(frame);
1405         myHostImpl->didDrawAllLayers(frame);
1406
1407         // Verify all quads have been computed
1408         ASSERT_EQ(2U, frame.renderPasses.size());
1409         ASSERT_EQ(1U, frame.renderPasses[0]->quadList().size());
1410         ASSERT_EQ(1U, frame.renderPasses[1]->quadList().size());
1411         EXPECT_EQ(CCDrawQuad::SolidColor, frame.renderPasses[0]->quadList()[0]->material());
1412         EXPECT_EQ(CCDrawQuad::RenderSurface, frame.renderPasses[1]->quadList()[0]->material());
1413     }
1414 }
1415
1416 // Make sure that context lost notifications are propagated through the tree.
1417 class ContextLostNotificationCheckLayer : public CCLayerImpl {
1418 public:
1419     static PassOwnPtr<ContextLostNotificationCheckLayer> create(int id) { return adoptPtr(new ContextLostNotificationCheckLayer(id)); }
1420
1421     virtual void didLoseContext() OVERRIDE
1422     {
1423         m_didLoseContextCalled = true;
1424     }
1425
1426     bool didLoseContextCalled() const { return m_didLoseContextCalled; }
1427
1428 private:
1429     explicit ContextLostNotificationCheckLayer(int id)
1430         : CCLayerImpl(id)
1431         , m_didLoseContextCalled(false)
1432     {
1433     }
1434
1435     bool m_didLoseContextCalled;
1436 };
1437
1438 TEST_F(CCLayerTreeHostImplTest, contextLostAndRestoredNotificationSentToAllLayers)
1439 {
1440     m_hostImpl->setRootLayer(ContextLostNotificationCheckLayer::create(0));
1441     ContextLostNotificationCheckLayer* root = static_cast<ContextLostNotificationCheckLayer*>(m_hostImpl->rootLayer());
1442
1443     root->addChild(ContextLostNotificationCheckLayer::create(1));
1444     ContextLostNotificationCheckLayer* layer1 = static_cast<ContextLostNotificationCheckLayer*>(root->children()[0].get());
1445
1446     layer1->addChild(ContextLostNotificationCheckLayer::create(2));
1447     ContextLostNotificationCheckLayer* layer2 = static_cast<ContextLostNotificationCheckLayer*>(layer1->children()[0].get());
1448
1449     EXPECT_FALSE(root->didLoseContextCalled());
1450     EXPECT_FALSE(layer1->didLoseContextCalled());
1451     EXPECT_FALSE(layer2->didLoseContextCalled());
1452
1453     m_hostImpl->initializeLayerRenderer(createContext(), UnthrottledUploader);
1454
1455     EXPECT_TRUE(root->didLoseContextCalled());
1456     EXPECT_TRUE(layer1->didLoseContextCalled());
1457     EXPECT_TRUE(layer2->didLoseContextCalled());
1458 }
1459
1460 class FakeWebGraphicsContext3DMakeCurrentFails : public FakeWebGraphicsContext3D {
1461 public:
1462     virtual bool makeContextCurrent() { return false; }
1463 };
1464
1465 TEST_F(CCLayerTreeHostImplTest, finishAllRenderingAfterContextLost)
1466 {
1467     // The context initialization will fail, but we should still be able to call finishAllRendering() without any ill effects.
1468     m_hostImpl->initializeLayerRenderer(CCGraphicsContext::create3D(GraphicsContext3DPrivate::createGraphicsContextFromWebContext(adoptPtr(new FakeWebGraphicsContext3DMakeCurrentFails), GraphicsContext3D::RenderDirectlyToHostWindow)), UnthrottledUploader);
1469     m_hostImpl->finishAllRendering();
1470 }
1471
1472 class ScrollbarLayerFakePaint : public CCScrollbarLayerImpl {
1473 public:
1474     static PassOwnPtr<ScrollbarLayerFakePaint> create(int id) { return adoptPtr(new ScrollbarLayerFakePaint(id)); }
1475
1476     virtual void paint(GraphicsContext*) { }
1477
1478 private:
1479     ScrollbarLayerFakePaint(int id) : CCScrollbarLayerImpl(id) { }
1480 };
1481
1482 TEST_F(CCLayerTreeHostImplTest, scrollbarLayerLostContext)
1483 {
1484     m_hostImpl->setRootLayer(ScrollbarLayerFakePaint::create(0));
1485     ScrollbarLayerFakePaint* scrollbar = static_cast<ScrollbarLayerFakePaint*>(m_hostImpl->rootLayer());
1486     scrollbar->setBounds(IntSize(1, 1));
1487     scrollbar->setContentBounds(IntSize(1, 1));
1488     scrollbar->setDrawsContent(true);
1489
1490     for (int i = 0; i < 2; ++i) {
1491         CCLayerTreeHostImpl::FrameData frame;
1492         EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
1493         ASSERT(frame.renderPasses.size() == 1);
1494         CCRenderPass* renderPass = frame.renderPasses[0].get();
1495         // Scrollbar layer should always generate quads, even after lost context
1496         EXPECT_GT(renderPass->quadList().size(), 0u);
1497         m_hostImpl->didDrawAllLayers(frame);
1498         m_hostImpl->initializeLayerRenderer(createContext(), UnthrottledUploader);
1499     }
1500 }
1501
1502 // Fake WebGraphicsContext3D that will cause a failure if trying to use a
1503 // resource that wasn't created by it (resources created by
1504 // FakeWebGraphicsContext3D have an id of 1).
1505 class StrictWebGraphicsContext3D : public FakeWebGraphicsContext3D {
1506 public:
1507     virtual WebGLId createBuffer() { return 2; }
1508     virtual WebGLId createFramebuffer() { return 3; }
1509     virtual WebGLId createProgram() { return 4; }
1510     virtual WebGLId createRenderbuffer() { return 5; }
1511     virtual WebGLId createShader(WGC3Denum) { return 6; }
1512     virtual WebGLId createTexture() { return 7; }
1513
1514     virtual void deleteBuffer(WebGLId id)
1515     {
1516         if (id != 2)
1517             ADD_FAILURE() << "Trying to delete buffer id " << id;
1518     }
1519
1520     virtual void deleteFramebuffer(WebGLId id)
1521     {
1522         if (id != 3)
1523             ADD_FAILURE() << "Trying to delete framebuffer id " << id;
1524     }
1525
1526     virtual void deleteProgram(WebGLId id)
1527     {
1528         if (id != 4)
1529             ADD_FAILURE() << "Trying to delete program id " << id;
1530     }
1531
1532     virtual void deleteRenderbuffer(WebGLId id)
1533     {
1534         if (id != 5)
1535             ADD_FAILURE() << "Trying to delete renderbuffer id " << id;
1536     }
1537
1538     virtual void deleteShader(WebGLId id)
1539     {
1540         if (id != 6)
1541             ADD_FAILURE() << "Trying to delete shader id " << id;
1542     }
1543
1544     virtual void deleteTexture(WebGLId id)
1545     {
1546         if (id != 7)
1547             ADD_FAILURE() << "Trying to delete texture id " << id;
1548     }
1549
1550     virtual void bindBuffer(WGC3Denum, WebGLId id)
1551     {
1552         if (id != 2 && id)
1553             ADD_FAILURE() << "Trying to bind buffer id " << id;
1554     }
1555
1556     virtual void bindFramebuffer(WGC3Denum, WebGLId id)
1557     {
1558         if (id != 3 && id)
1559             ADD_FAILURE() << "Trying to bind framebuffer id " << id;
1560     }
1561
1562     virtual void useProgram(WebGLId id)
1563     {
1564         if (id != 4)
1565             ADD_FAILURE() << "Trying to use program id " << id;
1566     }
1567
1568     virtual void bindRenderbuffer(WGC3Denum, WebGLId id)
1569     {
1570         if (id != 5 && id)
1571             ADD_FAILURE() << "Trying to bind renderbuffer id " << id;
1572     }
1573
1574     virtual void attachShader(WebGLId program, WebGLId shader)
1575     {
1576         if ((program != 4) || (shader != 6))
1577             ADD_FAILURE() << "Trying to attach shader id " << shader << " to program id " << program;
1578     }
1579
1580     virtual void bindTexture(WGC3Denum, WebGLId id)
1581     {
1582         if (id != 7 && id)
1583             ADD_FAILURE() << "Trying to bind texture id " << id;
1584     }
1585
1586     static PassRefPtr<GraphicsContext3D> createGraphicsContext()
1587     {
1588         return GraphicsContext3DPrivate::createGraphicsContextFromWebContext(adoptPtr(new StrictWebGraphicsContext3D()), GraphicsContext3D::RenderDirectlyToHostWindow);
1589     }
1590 };
1591
1592 // Fake video frame that represents a 4x4 YUV video frame.
1593 class FakeVideoFrame: public WebVideoFrame {
1594 public:
1595     FakeVideoFrame() { memset(m_data, 0x80, sizeof(m_data)); }
1596     virtual ~FakeVideoFrame() { }
1597     virtual Format format() const { return FormatYV12; }
1598     virtual unsigned width() const { return 4; }
1599     virtual unsigned height() const { return 4; }
1600     virtual unsigned planes() const { return 3; }
1601     virtual int stride(unsigned plane) const { return 4; }
1602     virtual const void* data(unsigned plane) const { return m_data; }
1603     virtual unsigned textureId() const { return 0; }
1604     virtual unsigned textureTarget() const { return 0; }
1605
1606 private:
1607     char m_data[16];
1608 };
1609
1610 // Fake video frame provider that always provides the same FakeVideoFrame.
1611 class FakeVideoFrameProvider: public WebVideoFrameProvider {
1612 public:
1613     FakeVideoFrameProvider() : m_client(0) { }
1614     virtual ~FakeVideoFrameProvider()
1615     {
1616         if (m_client)
1617             m_client->stopUsingProvider();
1618     }
1619
1620     virtual void setVideoFrameProviderClient(Client* client) { m_client = client; }
1621     virtual WebVideoFrame* getCurrentFrame() { return &m_frame; }
1622     virtual void putCurrentFrame(WebVideoFrame*) { }
1623
1624 private:
1625     FakeVideoFrame m_frame;
1626     Client* m_client;
1627 };
1628
1629 TEST_F(CCLayerTreeHostImplTest, dontUseOldResourcesAfterLostContext)
1630 {
1631     OwnPtr<CCLayerImpl> rootLayer(CCLayerImpl::create(0));
1632     rootLayer->setBounds(IntSize(10, 10));
1633     rootLayer->setAnchorPoint(FloatPoint(0, 0));
1634
1635     OwnPtr<CCTiledLayerImpl> tileLayer = CCTiledLayerImpl::create(1);
1636     tileLayer->setBounds(IntSize(10, 10));
1637     tileLayer->setAnchorPoint(FloatPoint(0, 0));
1638     tileLayer->setContentBounds(IntSize(10, 10));
1639     tileLayer->setDrawsContent(true);
1640     tileLayer->setSkipsDraw(false);
1641     OwnPtr<CCLayerTilingData> tilingData(CCLayerTilingData::create(IntSize(10, 10), CCLayerTilingData::NoBorderTexels));
1642     tilingData->setBounds(IntSize(10, 10));
1643     tileLayer->setTilingData(*tilingData);
1644     tileLayer->pushTileProperties(0, 0, 1, IntRect(0, 0, 10, 10));
1645     rootLayer->addChild(tileLayer.release());
1646
1647     OwnPtr<CCTextureLayerImpl> textureLayer = CCTextureLayerImpl::create(2);
1648     textureLayer->setBounds(IntSize(10, 10));
1649     textureLayer->setAnchorPoint(FloatPoint(0, 0));
1650     textureLayer->setContentBounds(IntSize(10, 10));
1651     textureLayer->setDrawsContent(true);
1652     textureLayer->setTextureId(1);
1653     rootLayer->addChild(textureLayer.release());
1654
1655     FakeVideoFrameProvider provider;
1656     OwnPtr<CCVideoLayerImpl> videoLayer = CCVideoLayerImpl::create(3, &provider);
1657     videoLayer->setBounds(IntSize(10, 10));
1658     videoLayer->setAnchorPoint(FloatPoint(0, 0));
1659     videoLayer->setContentBounds(IntSize(10, 10));
1660     videoLayer->setDrawsContent(true);
1661     rootLayer->addChild(videoLayer.release());
1662
1663     m_hostImpl->setRootLayer(rootLayer.release());
1664
1665     CCLayerTreeHostImpl::FrameData frame;
1666     EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
1667     m_hostImpl->drawLayers(frame);
1668     m_hostImpl->didDrawAllLayers(frame);
1669     m_hostImpl->swapBuffers();
1670
1671     // Lose the context, replacing it with a StrictWebGraphicsContext3D, that
1672     // will warn if any resource from the previous context gets used.
1673     m_hostImpl->initializeLayerRenderer(CCGraphicsContext::create3D(StrictWebGraphicsContext3D::createGraphicsContext()), UnthrottledUploader);
1674     EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
1675     m_hostImpl->drawLayers(frame);
1676     m_hostImpl->didDrawAllLayers(frame);
1677     m_hostImpl->swapBuffers();
1678 }
1679
1680 } // namespace