5acb9258e70e9f67af8cf9218fdb843013bf85ba
[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 "GraphicsContext3DPrivate.h"
30 #include "LayerRendererChromium.h"
31 #include "MockWebGraphicsContext3D.h"
32 #include "cc/CCLayerImpl.h"
33 #include "cc/CCSingleThreadProxy.h"
34 #include <gtest/gtest.h>
35
36 using namespace WebCore;
37 using namespace WebKit;
38
39 namespace {
40
41 class CCLayerTreeHostImplTest : public testing::Test, CCLayerTreeHostImplClient {
42 public:
43     CCLayerTreeHostImplTest()
44         : m_didRequestCommit(false)
45         , m_didRequestRedraw(false)
46     {
47         CCSettings settings;
48         m_hostImpl = CCLayerTreeHostImpl::create(settings, this);
49     }
50
51     virtual void onSwapBuffersCompleteOnImplThread() { }
52     virtual void setNeedsRedrawOnImplThread() { m_didRequestRedraw = true; }
53     virtual void setNeedsCommitOnImplThread() { m_didRequestCommit = true; }
54
55     static void expectClearedScrollDeltasRecursive(CCLayerImpl* layer)
56     {
57         ASSERT_EQ(layer->scrollDelta(), IntSize());
58         for (size_t i = 0; i < layer->children().size(); ++i)
59             expectClearedScrollDeltasRecursive(layer->children()[i].get());
60     }
61
62     static void expectContains(const CCScrollAndScaleSet& scrollInfo, int id, const IntSize& scrollDelta)
63     {
64         int timesEncountered = 0;
65
66         for (size_t i = 0; i < scrollInfo.scrolls.size(); ++i) {
67             if (scrollInfo.scrolls[i].layerId != id)
68                 continue;
69             ASSERT_EQ(scrollInfo.scrolls[i].scrollDelta, scrollDelta);
70             timesEncountered++;
71         }
72
73         ASSERT_EQ(timesEncountered, 1);
74     }
75
76 protected:
77     DebugScopedSetImplThread m_alwaysImplThread;
78     OwnPtr<CCLayerTreeHostImpl> m_hostImpl;
79     bool m_didRequestCommit;
80     bool m_didRequestRedraw;
81 };
82
83 TEST_F(CCLayerTreeHostImplTest, scrollDeltaNoLayers)
84 {
85     ASSERT_FALSE(m_hostImpl->rootLayer());
86
87     OwnPtr<CCScrollAndScaleSet> scrollInfo = m_hostImpl->processScrollDeltas();
88     ASSERT_EQ(scrollInfo->scrolls.size(), 0u);
89 }
90
91 TEST_F(CCLayerTreeHostImplTest, scrollDeltaTreeButNoChanges)
92 {
93     RefPtr<CCLayerImpl> root = CCLayerImpl::create(0);
94     root->addChild(CCLayerImpl::create(1));
95     root->addChild(CCLayerImpl::create(2));
96     root->children()[1]->addChild(CCLayerImpl::create(3));
97     root->children()[1]->addChild(CCLayerImpl::create(4));
98     root->children()[1]->children()[0]->addChild(CCLayerImpl::create(5));
99     m_hostImpl->setRootLayer(root);
100
101     expectClearedScrollDeltasRecursive(root.get());
102
103     OwnPtr<CCScrollAndScaleSet> scrollInfo;
104
105     scrollInfo = m_hostImpl->processScrollDeltas();
106     ASSERT_EQ(scrollInfo->scrolls.size(), 0u);
107     expectClearedScrollDeltasRecursive(root.get());
108
109     scrollInfo = m_hostImpl->processScrollDeltas();
110     ASSERT_EQ(scrollInfo->scrolls.size(), 0u);
111     expectClearedScrollDeltasRecursive(root.get());
112 }
113
114 TEST_F(CCLayerTreeHostImplTest, scrollDeltaRepeatedScrolls)
115 {
116     IntPoint scrollPosition(20, 30);
117     IntSize scrollDelta(11, -15);
118     RefPtr<CCLayerImpl> root = CCLayerImpl::create(10);
119     root->setScrollPosition(scrollPosition);
120     root->setScrollable(true);
121     root->setMaxScrollPosition(IntSize(100, 100));
122     root->scrollBy(scrollDelta);
123     m_hostImpl->setRootLayer(root);
124
125     OwnPtr<CCScrollAndScaleSet> scrollInfo;
126
127     scrollInfo = m_hostImpl->processScrollDeltas();
128     ASSERT_EQ(root->scrollPosition(), scrollPosition + scrollDelta);
129     ASSERT_EQ(scrollInfo->scrolls.size(), 1u);
130     EXPECT_EQ(root->sentScrollDelta(), scrollDelta);
131     expectContains(*scrollInfo.get(), root->id(), scrollDelta);
132     expectClearedScrollDeltasRecursive(root.get());
133
134     IntSize scrollDelta2(-5, 27);
135     root->scrollBy(scrollDelta2);
136     scrollInfo = m_hostImpl->processScrollDeltas();
137     ASSERT_EQ(root->scrollPosition(), scrollPosition + scrollDelta + scrollDelta2);
138     ASSERT_EQ(scrollInfo->scrolls.size(), 1u);
139     expectContains(*scrollInfo.get(), root->id(), scrollDelta2);
140     expectClearedScrollDeltasRecursive(root.get());
141
142     root->scrollBy(IntSize());
143     scrollInfo = m_hostImpl->processScrollDeltas();
144     ASSERT_EQ(root->scrollPosition(), scrollPosition + scrollDelta + scrollDelta2);
145     ASSERT_EQ(scrollInfo->scrolls.size(), 0u);
146     expectClearedScrollDeltasRecursive(root.get());
147 }
148
149 TEST_F(CCLayerTreeHostImplTest, scrollRootCallsCommitAndRedraw)
150 {
151     RefPtr<CCLayerImpl> root = CCLayerImpl::create(0);
152     root->setScrollable(true);
153     root->setScrollPosition(IntPoint(0, 0));
154     root->setMaxScrollPosition(IntSize(100, 100));
155     m_hostImpl->setRootLayer(root);
156     EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(0, 0)), CCInputHandlerClient::ScrollStarted);
157     m_hostImpl->scrollBy(IntSize(0, 10));
158     m_hostImpl->scrollEnd();
159     EXPECT_TRUE(m_didRequestRedraw);
160     EXPECT_TRUE(m_didRequestCommit);
161 }
162
163 class BlendStateTrackerContext: public MockWebGraphicsContext3D {
164 public:
165     BlendStateTrackerContext() : m_blend(false) { }
166
167     virtual bool initialize(Attributes, WebView*, bool renderDirectlyToWebView) { return true; }
168
169     virtual void enable(WGC3Denum cap)
170     {
171         if (cap == GraphicsContext3D::BLEND)
172             m_blend = true;
173     }
174
175     virtual void disable(WGC3Denum cap)
176     {
177         if (cap == GraphicsContext3D::BLEND)
178             m_blend = false;
179     }
180
181     bool blend() const { return m_blend; }
182
183 private:
184     bool m_blend;
185 };
186
187 class BlendStateCheckLayer : public CCLayerImpl {
188 public:
189     static PassRefPtr<BlendStateCheckLayer> create(int id) { return adoptRef(new BlendStateCheckLayer(id)); }
190
191     virtual void draw(LayerRendererChromium* renderer)
192     {
193         m_drawn = true;
194         BlendStateTrackerContext* context = static_cast<BlendStateTrackerContext*>(GraphicsContext3DPrivate::extractWebGraphicsContext3D(renderer->context()));
195         EXPECT_EQ(m_blend, context->blend());
196         EXPECT_EQ(m_hasRenderSurface, !!renderSurface());
197     }
198
199     void setExpectation(bool blend, bool hasRenderSurface)
200     {
201         m_blend = blend;
202         m_hasRenderSurface = hasRenderSurface;
203         m_drawn = false;
204     }
205
206     bool drawn() const { return m_drawn; }
207
208 private:
209     explicit BlendStateCheckLayer(int id)
210         : CCLayerImpl(id)
211         , m_blend(false)
212         , m_hasRenderSurface(false)
213         , m_drawn(false)
214     {
215         setAnchorPoint(FloatPoint(0, 0));
216         setBounds(IntSize(10, 10));
217         setDrawsContent(true);
218     }
219
220     bool m_blend;
221     bool m_hasRenderSurface;
222     bool m_drawn;
223 };
224
225 TEST_F(CCLayerTreeHostImplTest, blendingOffWhenDrawingOpaqueLayers)
226 {
227     GraphicsContext3D::Attributes attrs;
228     RefPtr<GraphicsContext3D> context = GraphicsContext3DPrivate::createGraphicsContextFromWebContext(adoptPtr(new BlendStateTrackerContext()), attrs, 0, GraphicsContext3D::RenderDirectlyToHostWindow, GraphicsContext3DPrivate::ForUseOnThisThread);
229     m_hostImpl->initializeLayerRenderer(context);
230     m_hostImpl->setViewport(IntSize(10, 10));
231
232     RefPtr<CCLayerImpl> root = CCLayerImpl::create(0);
233     root->setAnchorPoint(FloatPoint(0, 0));
234     root->setBounds(IntSize(10, 10));
235     root->setDrawsContent(false);
236     m_hostImpl->setRootLayer(root);
237
238     RefPtr<BlendStateCheckLayer> layer1 = BlendStateCheckLayer::create(1);
239     root->addChild(layer1);
240
241     // Opaque layer, drawn without blending.
242     layer1->setOpaque(true);
243     layer1->setExpectation(false, false);
244     m_hostImpl->drawLayers();
245     EXPECT_TRUE(layer1->drawn());
246
247     // Layer with translucent content, drawn with blending.
248     layer1->setOpaque(false);
249     layer1->setExpectation(true, false);
250     m_hostImpl->drawLayers();
251     EXPECT_TRUE(layer1->drawn());
252
253     // Layer with translucent opacity, drawn with blending.
254     layer1->setOpaque(true);
255     layer1->setOpacity(0.5);
256     layer1->setExpectation(true, false);
257     m_hostImpl->drawLayers();
258     EXPECT_TRUE(layer1->drawn());
259
260     RefPtr<BlendStateCheckLayer> layer2 = BlendStateCheckLayer::create(2);
261     layer1->addChild(layer2);
262
263     // 2 opaque layers, drawn without blending.
264     layer1->setOpaque(true);
265     layer1->setOpacity(1);
266     layer1->setExpectation(false, false);
267     layer2->setOpaque(true);
268     layer2->setOpacity(1);
269     layer2->setExpectation(false, false);
270     m_hostImpl->drawLayers();
271     EXPECT_TRUE(layer1->drawn());
272     EXPECT_TRUE(layer2->drawn());
273
274     // Parent layer with translucent content, drawn with blending.
275     // Child layer with opaque content, drawn without blending.
276     layer1->setOpaque(false);
277     layer1->setExpectation(true, false);
278     layer2->setExpectation(false, false);
279     m_hostImpl->drawLayers();
280     EXPECT_TRUE(layer1->drawn());
281     EXPECT_TRUE(layer2->drawn());
282
283     // Parent layer with translucent opacity and opaque content. Since it has a
284     // drawing child, it's drawn to a render surface which carries the opacity,
285     // so it's itself drawn without blending.
286     // Child layer with opaque content, drawn without blending (parent surface
287     // carries the inherited opacity).
288     layer1->setOpaque(true);
289     layer1->setOpacity(0.5);
290     layer1->setExpectation(false, true);
291     layer2->setExpectation(false, false);
292     m_hostImpl->drawLayers();
293     EXPECT_TRUE(layer1->drawn());
294     EXPECT_TRUE(layer2->drawn());
295 }
296
297 class ReshapeTrackerContext: public MockWebGraphicsContext3D {
298 public:
299     ReshapeTrackerContext() : m_reshapeCalled(false) { }
300
301     virtual bool initialize(Attributes, WebView*, bool renderDirectlyToWebView) { return true; }
302
303     virtual void reshape(int width, int height)
304     {
305         m_reshapeCalled = true;
306     }
307
308     bool reshapeCalled() const { return m_reshapeCalled; }
309
310 private:
311     bool m_reshapeCalled;
312 };
313
314 class FakeDrawableCCLayerImpl: public CCLayerImpl {
315 public:
316     FakeDrawableCCLayerImpl() : CCLayerImpl(0) { }
317     virtual void draw(LayerRendererChromium* renderer) { }
318 };
319
320 // Only reshape when we know we are going to draw. Otherwise, the reshape
321 // can leave the window at the wrong size if we never draw and the proper
322 // viewport size is never set.
323 TEST_F(CCLayerTreeHostImplTest, reshapeNotCalledUntilDraw)
324 {
325     GraphicsContext3D::Attributes attrs;
326     ReshapeTrackerContext* reshapeTracker = new ReshapeTrackerContext();
327     RefPtr<GraphicsContext3D> context = GraphicsContext3DPrivate::createGraphicsContextFromWebContext(adoptPtr(reshapeTracker), attrs, 0, GraphicsContext3D::RenderDirectlyToHostWindow, GraphicsContext3DPrivate::ForUseOnThisThread);
328     m_hostImpl->initializeLayerRenderer(context);
329     m_hostImpl->setViewport(IntSize(10, 10));
330
331     RefPtr<CCLayerImpl> root = adoptRef(new FakeDrawableCCLayerImpl());
332     root->setAnchorPoint(FloatPoint(0, 0));
333     root->setBounds(IntSize(10, 10));
334     root->setDrawsContent(true);
335     m_hostImpl->setRootLayer(root);
336     EXPECT_FALSE(reshapeTracker->reshapeCalled());
337
338     m_hostImpl->drawLayers();
339     EXPECT_TRUE(reshapeTracker->reshapeCalled());
340 }
341
342
343 } // namespace