1/*
2 * Copyright (C) 2010, 2011, 2012, 2013 Research In Motion Limited. All rights reserved.
3 * Copyright (C) 2010 Google Inc. All rights reserved.
4 * Copyright (C) 2007, 2008, 2009 Apple Inc. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
8 * met:
9 *
10 *     * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 *     * Redistributions in binary form must reproduce the above
13 * copyright notice, this list of conditions and the following disclaimer
14 * in the documentation and/or other materials provided with the
15 * distribution.
16 *     * Neither the name of Google Inc. nor the names of its
17 * contributors may be used to endorse or promote products derived from
18 * this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32
33#include "config.h"
34
35#if USE(ACCELERATED_COMPOSITING)
36
37#include "LayerCompositingThread.h"
38
39#include "LayerCompositingThreadClient.h"
40#include "LayerMessage.h"
41#include "LayerRenderer.h"
42#include "LayerRendererClient.h"
43#include "LayerUtilities.h"
44#include "LayerWebKitThread.h"
45#if ENABLE(VIDEO)
46#include "MediaPlayer.h"
47#include "MediaPlayerPrivateBlackBerry.h"
48#endif
49#include "PluginView.h"
50#include "StdLibExtras.h"
51#include "TextureCacheCompositingThread.h"
52
53#include <BlackBerryPlatformGLES2ContextState.h>
54#include <BlackBerryPlatformGraphics.h>
55#include <BlackBerryPlatformLog.h>
56#include <wtf/Assertions.h>
57
58using BlackBerry::Platform::Graphics::GLES2Program;
59
60namespace WebCore {
61
62void LayerOverride::removeAnimation(const String& name)
63{
64    for (size_t i = 0; i < m_animations.size(); ++i) {
65        if (m_animations[i]->name() == name) {
66            m_animations.remove(i);
67            return;
68        }
69    }
70}
71
72PassRefPtr<LayerCompositingThread> LayerCompositingThread::create(LayerType type, LayerCompositingThreadClient* client)
73{
74    return adoptRef(new LayerCompositingThread(type, client));
75}
76
77LayerCompositingThread::LayerCompositingThread(LayerType type, LayerCompositingThreadClient* client)
78    : LayerData(type)
79    , m_layerRenderer(0)
80    , m_superlayer(0)
81    , m_centerW(0)
82    , m_pluginBuffer(0)
83    , m_drawOpacity(0)
84    , m_visible(false)
85    , m_commitScheduled(false)
86    , m_client(client)
87#if ENABLE(CSS_FILTERS)
88    , m_filterOperationsChanged(false)
89#endif
90{
91}
92
93LayerCompositingThread::~LayerCompositingThread()
94{
95    ASSERT(isCompositingThread());
96
97    ASSERT(!superlayer());
98
99    // Remove the superlayer reference from all sublayers.
100    while (m_sublayers.size())
101        m_sublayers[0]->removeFromSuperlayer();
102
103    // Delete all allocated textures
104    deleteTextures();
105
106    // We just deleted all our textures, no need for the
107    // layer renderer to track us anymore
108    if (m_layerRenderer)
109        m_layerRenderer->removeLayer(this);
110
111    if (m_client)
112        m_client->layerCompositingThreadDestroyed(this);
113}
114
115void LayerCompositingThread::setLayerRenderer(LayerRenderer* renderer)
116{
117    // It's not expected that layers will ever switch renderers.
118    ASSERT(!renderer || !m_layerRenderer || renderer == m_layerRenderer);
119
120    m_layerRenderer = renderer;
121    if (m_layerRenderer)
122        m_layerRenderer->addLayer(this);
123}
124
125void LayerCompositingThread::deleteTextures()
126{
127    releaseTextureResources();
128
129    if (m_client)
130        m_client->deleteTextures(this);
131}
132
133void LayerCompositingThread::setDrawTransform(double scale, const TransformationMatrix& matrix, const TransformationMatrix& projectionMatrix)
134{
135    m_drawTransform = projectionMatrix * matrix;
136
137    FloatRect boundsRect(-origin(), bounds());
138
139    if (sizeIsScaleInvariant())
140        boundsRect.scale(1 / scale);
141
142    m_centerW = 0;
143    m_transformedBounds.clear();
144    m_ws.clear();
145    m_textureCoordinates.clear();
146    if (matrix.hasPerspective() && !m_layerRendererSurface) {
147        // Perform processing according to http://www.w3.org/TR/css3-transforms 6.2
148        // If w < 0 for all four corners of the transformed box, the box is not rendered.
149        // If w < 0 for one to three corners of the transformed box, the box
150        // must be replaced by a polygon that has any parts with w < 0 cut out.
151        // If w = 0, (x′, y′, z′) = (x ⋅ n, y ⋅ n, z ⋅ n)
152        // We implement this by intersecting with the image plane, i.e. the last row of the column-major matrix.
153        // To avoid problems with w close to 0, we use w = epsilon as the near plane by subtracting epsilon from matrix.m44().
154        const float epsilon = 1e-3;
155        Vector<FloatPoint3D, 4> quad = toVector<FloatPoint3D, 4>(boundsRect);
156        Vector<FloatPoint3D, 4> polygon = intersect(quad, LayerClipPlane(FloatPoint3D(matrix.m14(), matrix.m24(), matrix.m34()), matrix.m44() - epsilon));
157
158        // Compute the clipped texture coordinates.
159        if (polygon != quad) {
160            for (size_t i = 0; i < polygon.size(); ++i) {
161                FloatPoint3D& p = polygon[i];
162                m_textureCoordinates.append(FloatPoint(p.x() / boundsRect.width() + 0.5f, p.y() / boundsRect.height() + 0.5f));
163            }
164        }
165
166        // If w > 0, (x′, y′, z′) = (x/w, y/w, z/w)
167        for (size_t i = 0; i < polygon.size(); ++i) {
168            float w;
169            FloatPoint3D p = multVecMatrix(matrix, polygon[i], w);
170            if (w != 1) {
171                p.setX(p.x() / w);
172                p.setY(p.y() / w);
173                p.setZ(p.z() / w);
174            }
175
176            FloatPoint3D q = projectionMatrix.mapPoint(p);
177            m_transformedBounds.append(FloatPoint(q.x(), q.y()));
178            m_ws.append(w);
179        }
180
181        m_centerW = matrix.m44();
182    } else
183        m_transformedBounds = toVector<FloatPoint, 4>(m_drawTransform.mapQuad(boundsRect));
184
185    m_boundingBox = WebCore::boundingBox(m_transformedBounds);
186}
187
188const Vector<FloatPoint>& LayerCompositingThread::textureCoordinates(TextureCoordinateOrientation orientation) const
189{
190    if (m_textureCoordinates.size()) {
191        if (orientation == UpsideDown) {
192            static Vector<FloatPoint> upsideDownCoordinates;
193            upsideDownCoordinates = m_textureCoordinates;
194            for (size_t i = 0; i < upsideDownCoordinates.size(); ++i)
195                upsideDownCoordinates[i].setY(1 - upsideDownCoordinates[i].y());
196            return upsideDownCoordinates;
197        }
198
199        return m_textureCoordinates;
200    }
201
202    if (orientation == UpsideDown) {
203        static FloatPoint data[4] = { FloatPoint(0, 1),  FloatPoint(1, 1),  FloatPoint(1, 0),  FloatPoint(0, 0) };
204        static Vector<FloatPoint>* upsideDownCoordinates = 0;
205        if (!upsideDownCoordinates) {
206            upsideDownCoordinates = new Vector<FloatPoint>();
207            upsideDownCoordinates->append(data, 4);
208        }
209        return *upsideDownCoordinates;
210    }
211
212    static FloatPoint data[4] = { FloatPoint(0, 0),  FloatPoint(1, 0),  FloatPoint(1, 1),  FloatPoint(0, 1) };
213    static Vector<FloatPoint>* coordinates = 0;
214    if (!coordinates) {
215        coordinates = new Vector<FloatPoint>();
216        coordinates->append(data, 4);
217    }
218    return *coordinates;
219}
220
221FloatQuad LayerCompositingThread::transformedHolePunchRect() const
222{
223    FloatRect holePunchRect(m_holePunchRect);
224    holePunchRect.moveBy(-origin());
225    return m_drawTransform.mapQuad(holePunchRect);
226}
227
228void LayerCompositingThread::drawTextures(const GLES2Program& program, double scale, const FloatRect& visibleRect, const FloatRect& clipRect)
229{
230    if (m_pluginView) {
231        if (m_isVisible) {
232            // The layer contains Flash, video, or other plugin contents.
233            m_pluginBuffer = m_pluginView->lockFrontBufferForRead();
234
235            if (!m_pluginBuffer)
236                return;
237
238            if (!BlackBerry::Platform::Graphics::lockAndBindBufferGLTexture(m_pluginBuffer, GL_TEXTURE_2D)) {
239                m_pluginView->unlockFrontBuffer();
240                return;
241            }
242
243            m_layerRenderer->addLayerToReleaseTextureResourcesList(this);
244
245            glEnable(GL_BLEND);
246            glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
247            glUniform1f(program.opacityLocation(), drawOpacity());
248            glVertexAttribPointer(program.positionLocation(), 2, GL_FLOAT, GL_FALSE, 0, m_transformedBounds.data());
249            glVertexAttribPointer(program.texCoordLocation(), 2, GL_FLOAT, GL_FALSE, 0, textureCoordinates().data());
250            glDrawArrays(GL_TRIANGLE_FAN, 0, m_transformedBounds.size());
251        }
252        return;
253    }
254#if ENABLE(VIDEO)
255    if (m_mediaPlayer) {
256        if (m_isVisible) {
257            IntRect paintRect;
258            if (m_layerRenderer->client()->shouldChildWindowsUseDocumentCoordinates()) {
259                // We need to specify the media player location in contents coordinates. The 'visibleRect'
260                // specifies the content region covered by our viewport. So we transform from our
261                // normalized device coordinates [-1, 1] to the 'visibleRect'.
262                float vrw2 = visibleRect.width() / 2.0;
263                float vrh2 = visibleRect.height() / 2.0;
264                FloatPoint p(m_transformedBounds[0].x() * vrw2 + vrw2 + visibleRect.x(),
265                    -m_transformedBounds[0].y() * vrh2 + vrh2 + visibleRect.y());
266                paintRect = IntRect(roundedIntPoint(p), m_bounds);
267            } else
268                paintRect = m_layerRenderer->toWindowCoordinates(m_boundingBox);
269
270            m_mediaPlayer->paint(0, paintRect);
271            MediaPlayerPrivate* mpp = static_cast<MediaPlayerPrivate*>(m_mediaPlayer->platformMedia().media.qnxMediaPlayer);
272            mpp->drawBufferingAnimation(m_drawTransform, program);
273        }
274        return;
275    }
276#endif
277
278    if (m_client)
279        m_client->drawTextures(this, program, scale, clipRect);
280}
281
282void LayerCompositingThread::drawSurface(const GLES2Program& program, const TransformationMatrix& drawTransform, LayerCompositingThread* mask)
283{
284    using namespace BlackBerry::Platform::Graphics;
285
286    if (m_layerRenderer->layerAlreadyOnSurface(this)) {
287        LayerTexture* surfaceTexture = layerRendererSurface()->texture();
288        if (!surfaceTexture) {
289            ASSERT_NOT_REACHED();
290            return;
291        }
292        textureCacheCompositingThread()->textureAccessed(layerRendererSurface()->texture());
293        GLuint surfaceTexID = surfaceTexture->platformTexture();
294
295        if (!surfaceTexID) {
296            ASSERT_NOT_REACHED();
297            return;
298        }
299
300        if (mask) {
301            if (LayerTexture* maskTexture = mask->contentsTexture()) {
302                GLuint maskTexID = maskTexture->platformTexture();
303
304                glActiveTexture(GL_TEXTURE1);
305                glBindTexture(GL_TEXTURE_2D, maskTexID);
306                glActiveTexture(GL_TEXTURE0);
307            }
308        }
309
310        glEnable(GL_BLEND);
311        glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
312        glBindTexture(GL_TEXTURE_2D, surfaceTexID);
313
314        FloatQuad surfaceQuad = drawTransform.mapQuad(FloatRect(-origin(), bounds()));
315        glUniform1f(program.opacityLocation(), layerRendererSurface()->drawOpacity());
316        glVertexAttribPointer(program.positionLocation(), 2, GL_FLOAT, GL_FALSE, 0, &surfaceQuad);
317
318        static float texcoords[4 * 2] = { 0, 0,  1, 0,  1, 1,  0, 1 };
319        glVertexAttribPointer(program.texCoordLocation(), 2, GL_FLOAT, GL_FALSE, 0, texcoords);
320        glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
321    }
322}
323
324void LayerCompositingThread::releaseTextureResources()
325{
326    if (m_pluginView && m_pluginBuffer) {
327        BlackBerry::Platform::Graphics::releaseBufferGLTexture(m_pluginBuffer);
328        m_pluginBuffer = 0;
329        m_pluginView->unlockFrontBuffer();
330    }
331}
332
333void LayerCompositingThread::setPluginView(PluginView* pluginView)
334{
335    if (!isCompositingThread()) {
336        dispatchSyncCompositingMessage(BlackBerry::Platform::createMethodCallMessage(
337            &LayerCompositingThread::setPluginView,
338            this,
339            pluginView));
340        return;
341    }
342
343    m_pluginView = pluginView;
344}
345
346#if ENABLE(VIDEO)
347void LayerCompositingThread::setMediaPlayer(MediaPlayer* mediaPlayer)
348{
349    if (!isCompositingThread()) {
350        dispatchSyncCompositingMessage(BlackBerry::Platform::createMethodCallMessage(
351            &LayerCompositingThread::setMediaPlayer,
352            this,
353            mediaPlayer));
354        return;
355    }
356
357    m_mediaPlayer = mediaPlayer;
358}
359#endif
360
361void LayerCompositingThread::removeSublayer(LayerCompositingThread* sublayer)
362{
363    ASSERT(isCompositingThread());
364
365    int foundIndex = indexOfSublayer(sublayer);
366    if (foundIndex == -1)
367        return;
368
369    sublayer->setSuperlayer(0);
370    m_sublayers.remove(foundIndex);
371}
372
373int LayerCompositingThread::indexOfSublayer(const LayerCompositingThread* reference)
374{
375    for (size_t i = 0; i < m_sublayers.size(); i++) {
376        if (m_sublayers[i] == reference)
377            return i;
378    }
379    return -1;
380}
381
382const LayerCompositingThread* LayerCompositingThread::rootLayer() const
383{
384    const LayerCompositingThread* layer = this;
385    for (LayerCompositingThread* superlayer = layer->superlayer(); superlayer; layer = superlayer, superlayer = superlayer->superlayer()) { }
386    return layer;
387}
388
389void LayerCompositingThread::addSublayer(LayerCompositingThread* layer)
390{
391    layer->removeFromSuperlayer();
392    layer->setSuperlayer(this);
393    m_sublayers.append(layer);
394}
395
396void LayerCompositingThread::removeFromSuperlayer()
397{
398    if (m_superlayer)
399        m_superlayer->removeSublayer(this);
400}
401
402void LayerCompositingThread::setSublayers(const Vector<RefPtr<LayerCompositingThread> >& sublayers)
403{
404    if (sublayers == m_sublayers)
405        return;
406
407    while (m_sublayers.size()) {
408        RefPtr<LayerCompositingThread> layer = m_sublayers[0].get();
409        ASSERT(layer->superlayer());
410        layer->removeFromSuperlayer();
411    }
412
413    m_sublayers.clear();
414
415    size_t listSize = sublayers.size();
416    for (size_t i = 0; i < listSize; i++) {
417        RefPtr<LayerCompositingThread> sublayer = sublayers[i];
418        sublayer->removeFromSuperlayer();
419        sublayer->setSuperlayer(this);
420        m_sublayers.insert(i, sublayer);
421    }
422}
423
424void LayerCompositingThread::updateTextureContentsIfNeeded()
425{
426    if (m_client)
427        m_client->uploadTexturesIfNeeded(this);
428}
429
430LayerTexture* LayerCompositingThread::contentsTexture()
431{
432    if (m_client)
433        return m_client->contentsTexture(this);
434
435    return 0;
436}
437
438void LayerCompositingThread::setVisible(bool visible)
439{
440    if (visible == m_visible)
441        return;
442
443    m_visible = visible;
444
445    if (m_client)
446        m_client->layerVisibilityChanged(this, visible);
447}
448
449void LayerCompositingThread::setNeedsCommit()
450{
451    if (m_layerRenderer)
452        m_layerRenderer->setNeedsCommit();
453}
454
455void LayerCompositingThread::scheduleCommit()
456{
457    if (!m_client)
458        return;
459
460    if (!isWebKitThread()) {
461        if (m_commitScheduled)
462            return;
463
464        m_commitScheduled = true;
465
466        dispatchWebKitMessage(BlackBerry::Platform::createMethodCallMessage(&LayerCompositingThread::scheduleCommit, this));
467        return;
468    }
469
470    m_commitScheduled = false;
471
472    m_client->scheduleCommit();
473}
474
475void LayerCompositingThread::commitPendingTextureUploads()
476{
477    if (m_client)
478        m_client->commitPendingTextureUploads(this);
479}
480
481bool LayerCompositingThread::updateAnimations(double currentTime)
482{
483    // The commit mechanism always overwrites our state with state from the
484    // WebKit thread. This means we have to restore the last animated value for
485    // suspended animations.
486    for (size_t i = 0; i < m_suspendedAnimations.size(); ++i) {
487        LayerAnimation* animation = m_suspendedAnimations[i].get();
488        // From looking at the WebCore code, it appears that when the animation
489        // is paused, the timeOffset is modified so it will be an appropriate
490        // elapsedTime.
491        double elapsedTime = animation->timeOffset();
492        animation->apply(this, elapsedTime);
493    }
494
495    bool allAnimationsFinished = true;
496    for (size_t i = 0; i < m_runningAnimations.size(); ++i) {
497        LayerAnimation* animation = m_runningAnimations[i].get();
498        double elapsedTime = (m_suspendTime ? m_suspendTime : currentTime) - animation->startTime() + animation->timeOffset();
499        animation->apply(this, elapsedTime);
500        if (!animation->finished())
501            allAnimationsFinished = false;
502    }
503
504    // If there are any overrides, apply them
505    if (m_override) {
506        if (m_override->isPositionSet())
507            m_position = m_override->position();
508        if (m_override->isAnchorPointSet())
509            m_anchorPoint = m_override->anchorPoint();
510        if (m_override->isBoundsSet())
511            m_bounds = m_override->bounds();
512        if (m_override->isTransformSet())
513            m_transform = m_override->transform();
514        if (m_override->isOpacitySet())
515            m_opacity = m_override->opacity();
516
517        for (size_t i = 0; i < m_override->animations().size(); ++i) {
518            LayerAnimation* animation = m_override->animations()[i].get();
519            double elapsedTime = (m_suspendTime ? m_suspendTime : currentTime) - animation->startTime() + animation->timeOffset();
520            animation->apply(this, elapsedTime);
521            if (!animation->finished())
522                allAnimationsFinished = false;
523        }
524    }
525
526    return !allAnimationsFinished;
527}
528
529bool LayerCompositingThread::hasVisibleHolePunchRect() const
530{
531    if (m_pluginView && !m_isVisible)
532        return false;
533
534#if ENABLE(VIDEO)
535    if (m_mediaPlayer && !m_isVisible)
536        return false;
537#endif
538
539    return hasHolePunchRect();
540}
541
542void LayerCompositingThread::createLayerRendererSurface()
543{
544    ASSERT(!m_layerRendererSurface);
545    m_layerRendererSurface = adoptPtr(new LayerRendererSurface(m_layerRenderer, this));
546}
547
548void LayerCompositingThread::removeAnimation(const String& name)
549{
550    for (size_t i = 0; i < m_runningAnimations.size(); ++i) {
551        if (m_runningAnimations[i]->name() == name) {
552            m_runningAnimations.remove(i);
553            return;
554        }
555    }
556}
557
558LayerOverride* LayerCompositingThread::override()
559{
560    if (!m_override)
561        m_override = LayerOverride::create();
562    return m_override.get();
563}
564
565void LayerCompositingThread::clearOverride()
566{
567    m_override.clear();
568}
569
570}
571
572#endif // USE(ACCELERATED_COMPOSITING)
573