1/*
2 * Copyright (C) 2010 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 *
8 * 1.  Redistributions of source code must retain the above copyright
9 *     notice, this list of conditions and the following disclaimer.
10 * 2.  Redistributions in binary form must reproduce the above copyright
11 *     notice, this list of conditions and the following disclaimer in the
12 *     documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
18 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
20 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
21 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27
28#if USE(ACCELERATED_COMPOSITING)
29
30#include "RenderSurfaceChromium.h"
31
32#include "cc/CCLayerImpl.h"
33#include "GraphicsContext3D.h"
34#include "LayerChromium.h"
35#include "LayerRendererChromium.h"
36#include "LayerTexture.h"
37#include "TextStream.h"
38#include <wtf/text/CString.h>
39
40namespace WebCore {
41
42RenderSurfaceChromium::RenderSurfaceChromium(CCLayerImpl* owningLayer)
43    : m_owningLayer(owningLayer)
44    , m_maskLayer(0)
45    , m_skipsDraw(false)
46{
47}
48
49RenderSurfaceChromium::~RenderSurfaceChromium()
50{
51    cleanupResources();
52}
53
54void RenderSurfaceChromium::cleanupResources()
55{
56    if (!m_contentsTexture)
57        return;
58
59    ASSERT(layerRenderer());
60
61    m_contentsTexture.clear();
62}
63
64LayerRendererChromium* RenderSurfaceChromium::layerRenderer()
65{
66    ASSERT(m_owningLayer);
67    return m_owningLayer->layerRenderer();
68}
69
70FloatRect RenderSurfaceChromium::drawableContentRect() const
71{
72    FloatRect localContentRect(-0.5 * m_contentRect.width(), -0.5 * m_contentRect.height(),
73                               m_contentRect.width(), m_contentRect.height());
74    FloatRect drawableContentRect = m_drawTransform.mapRect(localContentRect);
75    if (m_owningLayer->replicaLayer())
76        drawableContentRect.unite(m_replicaDrawTransform.mapRect(localContentRect));
77
78    return drawableContentRect;
79}
80
81bool RenderSurfaceChromium::prepareContentsTexture()
82{
83    IntSize requiredSize(m_contentRect.size());
84    TextureManager* textureManager = layerRenderer()->textureManager();
85
86    if (!m_contentsTexture)
87        m_contentsTexture = LayerTexture::create(layerRenderer()->context(), textureManager);
88
89    if (m_contentsTexture->isReserved())
90        return true;
91
92    if (!m_contentsTexture->reserve(requiredSize, GraphicsContext3D::RGBA)) {
93        m_skipsDraw = true;
94        return false;
95    }
96
97    m_skipsDraw = false;
98    return true;
99}
100
101void RenderSurfaceChromium::drawSurface(CCLayerImpl* maskLayer, const TransformationMatrix& drawTransform)
102{
103    GraphicsContext3D* context3D = layerRenderer()->context();
104
105    int shaderMatrixLocation = -1;
106    int shaderAlphaLocation = -1;
107    const RenderSurfaceChromium::Program* program = layerRenderer()->renderSurfaceProgram();
108    const RenderSurfaceChromium::MaskProgram* maskProgram = layerRenderer()->renderSurfaceMaskProgram();
109    ASSERT(program && program->initialized());
110    bool useMask = false;
111    if (maskLayer && maskLayer->drawsContent()) {
112        if (!maskLayer->bounds().isEmpty()) {
113            context3D->makeContextCurrent();
114            layerRenderer()->useShader(maskProgram->program());
115            GLC(context3D, context3D->activeTexture(GraphicsContext3D::TEXTURE0));
116            GLC(context3D, context3D->uniform1i(maskProgram->fragmentShader().samplerLocation(), 0));
117            m_contentsTexture->bindTexture();
118            GLC(context3D, context3D->activeTexture(GraphicsContext3D::TEXTURE1));
119            GLC(context3D, context3D->uniform1i(maskProgram->fragmentShader().maskSamplerLocation(), 1));
120            maskLayer->bindContentsTexture();
121            GLC(context3D, context3D->activeTexture(GraphicsContext3D::TEXTURE0));
122            shaderMatrixLocation = maskProgram->vertexShader().matrixLocation();
123            shaderAlphaLocation = maskProgram->fragmentShader().alphaLocation();
124            useMask = true;
125        }
126    }
127
128    if (!useMask) {
129        layerRenderer()->useShader(program->program());
130        m_contentsTexture->bindTexture();
131        GLC(context3D, context3D->uniform1i(program->fragmentShader().samplerLocation(), 0));
132        shaderMatrixLocation = program->vertexShader().matrixLocation();
133        shaderAlphaLocation = program->fragmentShader().alphaLocation();
134    }
135
136    LayerChromium::drawTexturedQuad(layerRenderer()->context(), layerRenderer()->projectionMatrix(), drawTransform,
137                                        m_contentRect.width(), m_contentRect.height(), m_drawOpacity,
138                                        shaderMatrixLocation, shaderAlphaLocation);
139}
140
141void RenderSurfaceChromium::draw(const IntRect&)
142{
143    if (m_skipsDraw || !m_contentsTexture)
144        return;
145    // FIXME: By using the same RenderSurface for both the content and its reflection,
146    // it's currently not possible to apply a separate mask to the reflection layer
147    // or correctly handle opacity in reflections (opacity must be applied after drawing
148    // both the layer and its reflection). The solution is to introduce yet another RenderSurface
149    // to draw the layer and its reflection in. For now we only apply a separate reflection
150    // mask if the contents don't have a mask of their own.
151    CCLayerImpl* replicaMaskLayer = m_maskLayer;
152    if (!m_maskLayer && m_owningLayer->replicaLayer())
153        replicaMaskLayer = m_owningLayer->replicaLayer()->maskLayer();
154
155    layerRenderer()->setScissorToRect(m_scissorRect);
156
157    // Reflection draws before the layer.
158    if (m_owningLayer->replicaLayer())
159        drawSurface(replicaMaskLayer, m_replicaDrawTransform);
160
161    drawSurface(m_maskLayer, m_drawTransform);
162}
163
164String RenderSurfaceChromium::name() const
165{
166#ifndef NDEBUG
167    return String::format("RenderSurface(id=%i,owner=%s)", m_owningLayer->debugID(), m_owningLayer->name().utf8().data());
168#else
169    return String::format("RenderSurface(owner=%s)", m_owningLayer->name().utf8().data());
170#endif
171}
172
173static void writeIndent(TextStream& ts, int indent)
174{
175    for (int i = 0; i != indent; ++i)
176        ts << "  ";
177}
178
179void RenderSurfaceChromium::dumpSurface(TextStream& ts, int indent) const
180{
181    writeIndent(ts, indent);
182    ts << name() << "\n";
183
184    writeIndent(ts, indent+1);
185    ts << "contentRect: (" << m_contentRect.x() << ", " << m_contentRect.y() << ", " << m_contentRect.width() << ", " << m_contentRect.height() << "\n";
186}
187
188}
189#endif // USE(ACCELERATED_COMPOSITING)
190