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 are
6 * met:
7 *
8 *     * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 *     * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the
13 * distribution.
14 *     * Neither the name of Google Inc. nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31#include "config.h"
32
33#if USE(ACCELERATED_COMPOSITING)
34
35#include "LayerChromium.h"
36
37#include "cc/CCLayerImpl.h"
38#include "GraphicsContext3D.h"
39#include "LayerRendererChromium.h"
40#if USE(SKIA)
41#include "NativeImageSkia.h"
42#include "PlatformContextSkia.h"
43#endif
44#include "RenderLayerBacking.h"
45#include "TextStream.h"
46#include "skia/ext/platform_canvas.h"
47
48namespace WebCore {
49
50using namespace std;
51
52#ifndef NDEBUG
53static int s_nextLayerDebugID = 1;
54#endif
55
56PassRefPtr<LayerChromium> LayerChromium::create(GraphicsLayerChromium* owner)
57{
58    return adoptRef(new LayerChromium(owner));
59}
60
61LayerChromium::LayerChromium(GraphicsLayerChromium* owner)
62    : m_owner(owner)
63    , m_contentsDirty(false)
64    , m_maskLayer(0)
65    , m_ccLayerImpl(0)
66    , m_superlayer(0)
67#ifndef NDEBUG
68    , m_debugID(s_nextLayerDebugID++)
69#endif
70    , m_anchorPoint(0.5, 0.5)
71    , m_backgroundColor(0, 0, 0, 0)
72    , m_opacity(1.0)
73    , m_zPosition(0.0)
74    , m_anchorPointZ(0)
75    , m_clearsContext(false)
76    , m_hidden(false)
77    , m_masksToBounds(false)
78    , m_opaque(true)
79    , m_geometryFlipped(false)
80    , m_needsDisplayOnBoundsChange(false)
81    , m_doubleSided(true)
82    , m_replicaLayer(0)
83{
84}
85
86LayerChromium::~LayerChromium()
87{
88    // Our superlayer should be holding a reference to us so there should be no
89    // way for us to be destroyed while we still have a superlayer.
90    ASSERT(!superlayer());
91
92    if (m_ccLayerImpl)
93        m_ccLayerImpl->resetOwner();
94
95    // Remove the superlayer reference from all sublayers.
96    removeAllSublayers();
97}
98
99void LayerChromium::cleanupResources()
100{
101    if (m_ccLayerImpl)
102        m_ccLayerImpl->cleanupResources();
103}
104
105void LayerChromium::setLayerRenderer(LayerRendererChromium* renderer)
106{
107    // If we're changing layer renderers then we need to free up any resources
108    // allocated by the old renderer.
109    if (layerRenderer() && layerRenderer() != renderer) {
110        cleanupResources();
111        setNeedsDisplay();
112    }
113    m_layerRenderer = renderer;
114}
115
116void LayerChromium::setNeedsCommit()
117{
118    // Call notifySyncRequired(), which for non-root layers plumbs through to
119    // call setRootLayerNeedsDisplay() on the WebView, which will cause LayerRendererChromium
120    // to render a frame.
121    // This function has no effect on root layers.
122    if (m_owner)
123        m_owner->notifySyncRequired();
124}
125
126void LayerChromium::addSublayer(PassRefPtr<LayerChromium> sublayer)
127{
128    insertSublayer(sublayer, numSublayers());
129}
130
131void LayerChromium::insertSublayer(PassRefPtr<LayerChromium> sublayer, size_t index)
132{
133    index = min(index, m_sublayers.size());
134    sublayer->removeFromSuperlayer();
135    sublayer->setSuperlayer(this);
136    m_sublayers.insert(index, sublayer);
137    setNeedsCommit();
138}
139
140void LayerChromium::removeFromSuperlayer()
141{
142    if (m_superlayer)
143        m_superlayer->removeSublayer(this);
144}
145
146void LayerChromium::removeSublayer(LayerChromium* sublayer)
147{
148    int foundIndex = indexOfSublayer(sublayer);
149    if (foundIndex == -1)
150        return;
151
152    sublayer->setSuperlayer(0);
153    m_sublayers.remove(foundIndex);
154    setNeedsCommit();
155}
156
157void LayerChromium::replaceSublayer(LayerChromium* reference, PassRefPtr<LayerChromium> newLayer)
158{
159    ASSERT_ARG(reference, reference);
160    ASSERT_ARG(reference, reference->superlayer() == this);
161
162    if (reference == newLayer)
163        return;
164
165    int referenceIndex = indexOfSublayer(reference);
166    if (referenceIndex == -1) {
167        ASSERT_NOT_REACHED();
168        return;
169    }
170
171    reference->removeFromSuperlayer();
172
173    if (newLayer) {
174        newLayer->removeFromSuperlayer();
175        insertSublayer(newLayer, referenceIndex);
176    }
177}
178
179int LayerChromium::indexOfSublayer(const LayerChromium* reference)
180{
181    for (size_t i = 0; i < m_sublayers.size(); i++) {
182        if (m_sublayers[i] == reference)
183            return i;
184    }
185    return -1;
186}
187
188void LayerChromium::setBounds(const IntSize& size)
189{
190    if (bounds() == size)
191        return;
192
193    bool firstResize = !bounds().width() && !bounds().height() && size.width() && size.height();
194
195    m_bounds = size;
196
197    if (firstResize)
198        setNeedsDisplay(FloatRect(0, 0, bounds().width(), bounds().height()));
199    else
200        setNeedsCommit();
201}
202
203void LayerChromium::setFrame(const FloatRect& rect)
204{
205    if (rect == m_frame)
206      return;
207
208    m_frame = rect;
209    setNeedsDisplay(FloatRect(0, 0, bounds().width(), bounds().height()));
210}
211
212const LayerChromium* LayerChromium::rootLayer() const
213{
214    const LayerChromium* layer = this;
215    for (LayerChromium* superlayer = layer->superlayer(); superlayer; layer = superlayer, superlayer = superlayer->superlayer()) { }
216    return layer;
217}
218
219void LayerChromium::removeAllSublayers()
220{
221    while (m_sublayers.size()) {
222        LayerChromium* layer = m_sublayers[0].get();
223        ASSERT(layer->superlayer());
224        layer->removeFromSuperlayer();
225    }
226}
227
228void LayerChromium::setSublayers(const Vector<RefPtr<LayerChromium> >& sublayers)
229{
230    if (sublayers == m_sublayers)
231        return;
232
233    removeAllSublayers();
234    size_t listSize = sublayers.size();
235    for (size_t i = 0; i < listSize; i++)
236        addSublayer(sublayers[i]);
237}
238
239LayerChromium* LayerChromium::superlayer() const
240{
241    return m_superlayer;
242}
243
244void LayerChromium::setName(const String& name)
245{
246    m_name = name;
247}
248
249void LayerChromium::setNeedsDisplay(const FloatRect& dirtyRect)
250{
251    // Simply mark the contents as dirty. For non-root layers, the call to
252    // setNeedsCommit will schedule a fresh compositing pass.
253    // For the root layer, setNeedsCommit has no effect.
254    m_contentsDirty = true;
255
256    m_dirtyRect.unite(dirtyRect);
257    setNeedsCommit();
258}
259
260void LayerChromium::setNeedsDisplay()
261{
262    m_dirtyRect.setLocation(FloatPoint());
263    m_dirtyRect.setSize(bounds());
264    m_contentsDirty = true;
265    setNeedsCommit();
266}
267
268void LayerChromium::resetNeedsDisplay()
269{
270    m_dirtyRect = FloatRect();
271    m_contentsDirty = false;
272}
273
274void LayerChromium::toGLMatrix(float* flattened, const TransformationMatrix& m)
275{
276    flattened[0] = m.m11();
277    flattened[1] = m.m12();
278    flattened[2] = m.m13();
279    flattened[3] = m.m14();
280    flattened[4] = m.m21();
281    flattened[5] = m.m22();
282    flattened[6] = m.m23();
283    flattened[7] = m.m24();
284    flattened[8] = m.m31();
285    flattened[9] = m.m32();
286    flattened[10] = m.m33();
287    flattened[11] = m.m34();
288    flattened[12] = m.m41();
289    flattened[13] = m.m42();
290    flattened[14] = m.m43();
291    flattened[15] = m.m44();
292}
293
294void LayerChromium::pushPropertiesTo(CCLayerImpl* layer)
295{
296    layer->setAnchorPoint(m_anchorPoint);
297    layer->setAnchorPointZ(m_anchorPointZ);
298    layer->setBounds(m_bounds);
299    layer->setDebugBorderColor(m_debugBorderColor);
300    layer->setDebugBorderWidth(m_debugBorderWidth);
301    layer->setDoubleSided(m_doubleSided);
302    layer->setLayerRenderer(m_layerRenderer.get());
303    layer->setMasksToBounds(m_masksToBounds);
304    layer->setName(m_name);
305    layer->setOpacity(m_opacity);
306    layer->setPosition(m_position);
307    layer->setPreserves3D(preserves3D());
308    layer->setSublayerTransform(m_sublayerTransform);
309    layer->setTransform(m_transform);
310
311    if (maskLayer())
312        maskLayer()->pushPropertiesTo(layer->maskLayer());
313    if (replicaLayer())
314        replicaLayer()->pushPropertiesTo(layer->replicaLayer());
315}
316
317GraphicsContext3D* LayerChromium::layerRendererContext() const
318{
319    ASSERT(layerRenderer());
320    return layerRenderer()->context();
321}
322
323void LayerChromium::drawTexturedQuad(GraphicsContext3D* context, const TransformationMatrix& projectionMatrix, const TransformationMatrix& drawMatrix,
324                                     float width, float height, float opacity,
325                                     int matrixLocation, int alphaLocation)
326{
327    static float glMatrix[16];
328
329    TransformationMatrix renderMatrix = drawMatrix;
330
331    // Apply a scaling factor to size the quad from 1x1 to its intended size.
332    renderMatrix.scale3d(width, height, 1);
333
334    // Apply the projection matrix before sending the transform over to the shader.
335    toGLMatrix(&glMatrix[0], projectionMatrix * renderMatrix);
336
337    GLC(context, context->uniformMatrix4fv(matrixLocation, false, &glMatrix[0], 1));
338
339    if (alphaLocation != -1)
340        GLC(context, context->uniform1f(alphaLocation, opacity));
341
342    GLC(context, context->drawElements(GraphicsContext3D::TRIANGLES, 6, GraphicsContext3D::UNSIGNED_SHORT, 0));
343}
344
345String LayerChromium::layerTreeAsText() const
346{
347    TextStream ts;
348    dumpLayer(ts, 0);
349    return ts.release();
350}
351
352static void writeIndent(TextStream& ts, int indent)
353{
354    for (int i = 0; i != indent; ++i)
355        ts << "  ";
356}
357
358void LayerChromium::dumpLayer(TextStream& ts, int indent) const
359{
360    writeIndent(ts, indent);
361    ts << layerTypeAsString() << "(" << m_name << ")\n";
362    dumpLayerProperties(ts, indent+2);
363    if (m_ccLayerImpl)
364        m_ccLayerImpl->dumpLayerProperties(ts, indent+2);
365    if (m_replicaLayer) {
366        writeIndent(ts, indent+2);
367        ts << "Replica:\n";
368        m_replicaLayer->dumpLayer(ts, indent+3);
369    }
370    if (m_maskLayer) {
371        writeIndent(ts, indent+2);
372        ts << "Mask:\n";
373        m_maskLayer->dumpLayer(ts, indent+3);
374    }
375    for (size_t i = 0; i < m_sublayers.size(); ++i)
376        m_sublayers[i]->dumpLayer(ts, indent+1);
377}
378
379void LayerChromium::dumpLayerProperties(TextStream& ts, int indent) const
380{
381    writeIndent(ts, indent);
382#ifndef NDEBUG
383    ts << "debugID: " << debugID() << ", ";
384#else
385#endif
386    ts << "drawsContent: " << drawsContent() << "\n";
387
388}
389
390PassRefPtr<CCLayerImpl> LayerChromium::createCCLayerImpl()
391{
392    return CCLayerImpl::create(this);
393}
394
395void LayerChromium::createCCLayerImplIfNeeded()
396{
397    if (!m_ccLayerImpl)
398        m_ccLayerImpl = createCCLayerImpl();
399}
400
401CCLayerImpl* LayerChromium::ccLayerImpl()
402{
403    return m_ccLayerImpl.get();
404}
405
406void LayerChromium::setBorderColor(const Color& color)
407{
408    m_debugBorderColor = color;
409    setNeedsCommit();
410}
411
412void LayerChromium::setBorderWidth(float width)
413{
414    m_debugBorderWidth = width;
415    setNeedsCommit();
416}
417
418LayerRendererChromium* LayerChromium::layerRenderer() const
419{
420    return m_layerRenderer.get();
421}
422
423}
424#endif // USE(ACCELERATED_COMPOSITING)
425