1/*
2 * Copyright (C) 2010, 2011, 2012 Research In Motion Limited. All rights reserved.
3 * Copyright (C) 2010 Google Inc. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met:
8 *
9 *     * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 *     * Redistributions in binary form must reproduce the above
12 * copyright notice, this list of conditions and the following disclaimer
13 * in the documentation and/or other materials provided with the
14 * distribution.
15 *     * Neither the name of Google Inc. nor the names of its
16 * contributors may be used to endorse or promote products derived from
17 * this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31
32#include "config.h"
33
34#if USE(ACCELERATED_COMPOSITING)
35
36#include "LayerWebKitThread.h"
37
38#include "GraphicsContext.h"
39#include "LayerCompositingThread.h"
40#include "LayerMessage.h"
41#include "RenderLayerBacking.h"
42#include "TransformationMatrix.h"
43
44#include <BlackBerryPlatformGraphics.h>
45#include <wtf/CurrentTime.h>
46
47namespace WebCore {
48
49using namespace std;
50
51PassRefPtr<LayerWebKitThread> LayerWebKitThread::create(LayerType type, GraphicsLayerBlackBerry* owner)
52{
53    return adoptRef(new LayerWebKitThread(type, owner));
54}
55
56LayerWebKitThread::LayerWebKitThread(LayerType type, GraphicsLayerBlackBerry* owner)
57    : LayerData(type)
58    , m_owner(owner)
59    , m_superlayer(0)
60    , m_contents(0)
61    , m_isDrawable(false)
62    , m_isMask(false)
63    , m_animationsChanged(false)
64    , m_clearOverrideOnCommit(false)
65#if ENABLE(CSS_FILTERS)
66    , m_filtersChanged(false)
67#endif
68    , m_didStartAnimations(false)
69{
70    if (type == Layer)
71        m_tiler = LayerTiler::create(this);
72    m_layerCompositingThread = LayerCompositingThread::create(type, m_tiler.get());
73}
74
75LayerWebKitThread::~LayerWebKitThread()
76{
77    if (m_tiler)
78        m_tiler->layerWebKitThreadDestroyed();
79
80    // Our superlayer should be holding a reference to us so there should be no
81    // way for us to be destroyed while we still have a superlayer.
82    ASSERT(!superlayer());
83
84    // Remove the superlayer reference from all sublayers.
85    removeAll(m_sublayers);
86    removeAll(m_overlays);
87}
88
89void LayerWebKitThread::paintContents(BlackBerry::Platform::Graphics::Buffer* buffer, const IntRect& contentsRect, double scale)
90{
91    if (!drawsContent() && !contents())
92        return;
93
94    if (!buffer)
95        return;
96
97    IntRect untransformedContentsRect = contentsRect;
98    FloatRect clipRect = contentsRect;
99    if (scale != 1.0) {
100        TransformationMatrix matrix;
101        matrix.scale(1.0 / scale);
102        untransformedContentsRect = matrix.mapRect(contentsRect);
103        clipRect = matrix.mapRect(clipRect);
104
105        // We extract from the contentsRect but draw a slightly larger region than
106        // we were told to, in order to avoid pixels being rendered only partially.
107        const int atLeastOneDevicePixel = static_cast<int>(ceilf(1.0 / scale));
108        untransformedContentsRect.inflate(atLeastOneDevicePixel);
109    }
110
111    PlatformGraphicsContext* platformContext = lockBufferDrawable(buffer);
112    GraphicsContext graphicsContext(platformContext);
113    if (contents()) {
114        // Images needs to be centered and will be scaled to fit the bounds on the compositing thread
115        if (!contents()->size().isEmpty())
116            graphicsContext.drawImage(contents(), ColorSpaceDeviceRGB, IntPoint(0, 0));
117    } else {
118        graphicsContext.translate(-contentsRect.x(), -contentsRect.y());
119        graphicsContext.scale(FloatSize(scale, scale));
120        graphicsContext.clip(clipRect);
121        m_owner->paintGraphicsLayerContents(graphicsContext, untransformedContentsRect);
122    }
123
124    releaseBufferDrawable(buffer);
125}
126
127void LayerWebKitThread::updateTextureContentsIfNeeded()
128{
129    if (m_tiler)
130        m_tiler->updateTextureContentsIfNeeded(m_isMask ? 1.0 : contentsScale());
131}
132
133void LayerWebKitThread::commitPendingTextureUploads()
134{
135    layerCompositingThread()->commitPendingTextureUploads();
136}
137
138void LayerWebKitThread::setContents(Image* contents)
139{
140    // Check if the image has changed.
141    if (m_contents == contents) {
142        // Set needs display for animated images.
143        if (contents)
144            setNeedsDisplay();
145        return;
146    }
147    m_contents = contents;
148    setNeedsTexture(m_isDrawable && (this->contents() || drawsContent() || pluginView()));
149
150    if (m_contents)
151        setNeedsDisplay();
152    else
153        setNeedsCommit();
154
155    // If this layer contains a bitmap image it isn't rerendered at different scale (it is resolution independent)
156    m_contentsResolutionIndependent = static_cast<bool>(m_contents);
157}
158
159void LayerWebKitThread::setDrawable(bool isDrawable)
160{
161    if (m_isDrawable == isDrawable)
162        return;
163
164    m_isDrawable = isDrawable;
165
166    setNeedsTexture(m_isDrawable && (drawsContent() || contents() || pluginView() || mediaPlayer()));
167    setNeedsCommit();
168}
169
170void LayerWebKitThread::setNeedsCommit()
171{
172    // Call notifyFlushRequired(), which in this implementation plumbs through to
173    // call scheduleRootLayerCommit() on the WebView, which will cause us to commit
174    // changes done on the WebKit thread for display on the Compositing thread.
175    if (m_owner)
176        m_owner->notifyFlushRequired();
177}
178
179void LayerWebKitThread::notifyAnimationsStarted(double time)
180{
181    if (m_didStartAnimations) {
182        m_didStartAnimations = false;
183        if (m_owner)
184            m_owner->notifyAnimationStarted(time);
185    }
186
187    size_t listSize = m_sublayers.size();
188    for (size_t i = 0; i < listSize; ++i)
189        m_sublayers[i]->notifyAnimationsStarted(time);
190
191    listSize = m_overlays.size();
192    for (size_t i = 0; i < listSize; ++i)
193        m_overlays[i]->notifyAnimationsStarted(time);
194}
195
196void LayerWebKitThread::commitOnWebKitThread(double scale)
197{
198    // Updating texture contents require the latest visibility info.
199    updateTextureContents(scale);
200}
201
202bool LayerWebKitThread::startAnimations(double time)
203{
204    bool didStartAnimations = false;
205    for (size_t i = 0; i < m_runningAnimations.size(); ++i) {
206        if (!m_runningAnimations[i]->startTime()) {
207            m_runningAnimations[i]->setStartTime(time);
208            m_didStartAnimations = didStartAnimations = true;
209        }
210    }
211
212    size_t listSize = m_sublayers.size();
213    for (size_t i = 0; i < listSize; ++i)
214        didStartAnimations |= m_sublayers[i]->startAnimations(time);
215
216    listSize = m_overlays.size();
217    for (size_t i = 0; i < listSize; ++i)
218        didStartAnimations |= m_overlays[i]->startAnimations(time);
219
220    return didStartAnimations;
221}
222
223void LayerWebKitThread::updateTextureContents(double scale)
224{
225    if (m_contentsScale != scale) {
226        m_contentsScale = scale;
227
228        // Only web content can redraw at the new scale.
229        // Canvas, images, video etc can't.
230        if (drawsContent())
231            setNeedsDisplay();
232    }
233
234    updateTextureContentsIfNeeded();
235
236    if (includeVisibility()) {
237        // The RenderLayerBacking cast looks unsafe given that there are two classes
238        // derived from GraphicsLayerClient but this code is only reachable for
239        // things that produce RenderLayerBacking derivatives; i.e., plugins and media.
240        RenderLayer* renderLayer(static_cast<RenderLayerBacking*>(m_owner->client())->owningLayer());
241        bool isVisible(renderLayer->hasVisibleContent() || renderLayer->hasVisibleDescendant());
242        if (m_isVisible != isVisible) {
243            m_isVisible = isVisible;
244            setNeedsCommit();
245        }
246    }
247
248    size_t listSize = m_sublayers.size();
249    for (size_t i = 0; i < listSize; ++i)
250        m_sublayers[i]->updateTextureContents(scale);
251
252    listSize = m_overlays.size();
253    for (size_t i = 0; i < listSize; ++i)
254        m_overlays[i]->updateTextureContents(scale);
255
256    if (maskLayer())
257        maskLayer()->updateTextureContents(scale);
258
259    if (replicaLayer())
260        replicaLayer()->updateTextureContents(scale);
261}
262
263void LayerWebKitThread::commitOnCompositingThread()
264{
265    FloatPoint oldPosition = m_position;
266    m_position += m_absoluteOffset;
267    // Copy the base variables from this object into m_layerCompositingThread
268    replicate(m_layerCompositingThread.get());
269#if ENABLE(CSS_FILTERS)
270    if (m_filtersChanged) {
271        m_filtersChanged = false;
272        m_layerCompositingThread->setFilterOperationsChanged(true);
273    }
274#endif
275    if (m_animationsChanged) {
276        m_layerCompositingThread->setRunningAnimations(m_runningAnimations);
277        m_layerCompositingThread->setSuspendedAnimations(m_suspendedAnimations);
278        m_animationsChanged = false;
279    }
280    if (m_clearOverrideOnCommit) {
281        m_layerCompositingThread->clearOverride();
282        m_clearOverrideOnCommit = false;
283    }
284    m_position = oldPosition;
285    updateLayerHierarchy();
286
287    commitPendingTextureUploads();
288
289    size_t listSize = m_sublayers.size();
290    for (size_t i = 0; i < listSize; ++i)
291        m_sublayers[i]->commitOnCompositingThread();
292
293    listSize = m_overlays.size();
294    for (size_t i = 0; i < listSize; ++i)
295        m_overlays[i]->commitOnCompositingThread();
296
297    if (maskLayer()) {
298        maskLayer()->commitOnCompositingThread();
299        layerCompositingThread()->setMaskLayer(maskLayer()->layerCompositingThread());
300    } else
301        layerCompositingThread()->setMaskLayer(0);
302
303    if (replicaLayer()) {
304        replicaLayer()->commitOnCompositingThread();
305        layerCompositingThread()->setReplicaLayer(replicaLayer()->layerCompositingThread());
306    } else
307        layerCompositingThread()->setReplicaLayer(0);
308}
309
310void LayerWebKitThread::addSublayer(PassRefPtr<LayerWebKitThread> sublayer)
311{
312    insert(m_sublayers, sublayer, m_sublayers.size());
313}
314
315void LayerWebKitThread::addOverlay(PassRefPtr<LayerWebKitThread> overlay)
316{
317    insert(m_overlays, overlay, m_overlays.size());
318}
319
320void LayerWebKitThread::insert(Vector<RefPtr<LayerWebKitThread> >& list, PassRefPtr<LayerWebKitThread> sublayer, size_t index)
321{
322    sublayer->removeFromSuperlayer();
323    index = min(index, list.size());
324    sublayer->setSuperlayer(this);
325    list.insert(index, sublayer);
326
327    setNeedsCommit();
328}
329
330void LayerWebKitThread::removeFromSuperlayer()
331{
332    if (m_superlayer)
333        m_superlayer->removeSublayerOrOverlay(this);
334}
335
336void LayerWebKitThread::removeSublayerOrOverlay(LayerWebKitThread* sublayer)
337{
338    remove(m_sublayers, sublayer);
339    remove(m_overlays, sublayer);
340}
341
342void LayerWebKitThread::remove(Vector<RefPtr<LayerWebKitThread> >& vector, LayerWebKitThread* sublayer)
343{
344    size_t foundIndex = vector.find(sublayer);
345    if (foundIndex == notFound)
346        return;
347
348    sublayer->setSuperlayer(0);
349    vector.remove(foundIndex);
350
351    setNeedsCommit();
352}
353
354void LayerWebKitThread::replaceSublayer(LayerWebKitThread* reference, PassRefPtr<LayerWebKitThread> newLayer)
355{
356    ASSERT_ARG(reference, reference);
357    ASSERT_ARG(reference, reference->superlayer() == this);
358
359    if (reference == newLayer)
360        return;
361
362    size_t referenceIndex = m_sublayers.find(reference);
363    if (referenceIndex == notFound) {
364        ASSERT_NOT_REACHED();
365        return;
366    }
367
368    reference->removeFromSuperlayer();
369
370    if (newLayer) {
371        newLayer->removeFromSuperlayer();
372        insertSublayer(newLayer, referenceIndex);
373    }
374}
375
376void LayerWebKitThread::setBounds(const IntSize& size)
377{
378    if (m_bounds == size)
379        return;
380
381    bool firstResize = !m_bounds.width() && !m_bounds.height() && size.width() && size.height();
382
383    m_bounds = size;
384
385    boundsChanged();
386
387    if (firstResize)
388        setNeedsDisplay();
389    else
390        setNeedsCommit();
391}
392
393void LayerWebKitThread::setFrame(const FloatRect& rect)
394{
395    if (rect == m_frame)
396        return;
397
398    m_frame = rect;
399    setNeedsDisplay();
400}
401
402#if ENABLE(CSS_FILTERS)
403bool LayerWebKitThread::filtersCanBeComposited(const FilterOperations& filters)
404{
405    // There is work associated with compositing filters, even if there are zero filters,
406    // so if there are no filters, claim we can't composite them.
407    if (!filters.size())
408        return false;
409
410    for (unsigned i = 0; i < filters.size(); ++i) {
411        const FilterOperation* filterOperation = filters.at(i);
412        switch (filterOperation->getOperationType()) {
413        case FilterOperation::REFERENCE:
414#if ENABLE(CSS_SHADERS)
415        case FilterOperation::CUSTOM:
416#endif
417            return false;
418        default:
419            break;
420        }
421    }
422
423    return true;
424}
425#endif
426
427const LayerWebKitThread* LayerWebKitThread::rootLayer() const
428{
429    const LayerWebKitThread* layer = this;
430    LayerWebKitThread* superlayer = layer->superlayer();
431
432    while (superlayer) {
433        layer = superlayer;
434        superlayer = superlayer->superlayer();
435    }
436    return layer;
437}
438
439void LayerWebKitThread::removeAll(Vector<RefPtr<LayerWebKitThread> >& vector)
440{
441    if (!vector.size())
442        return;
443
444    while (vector.size()) {
445        RefPtr<LayerWebKitThread> layer = vector[0].get();
446        ASSERT(layer->superlayer() == this);
447        layer->removeFromSuperlayer();
448    }
449
450    setNeedsCommit();
451}
452
453void LayerWebKitThread::setSublayers(const Vector<RefPtr<LayerWebKitThread> >& sublayers)
454{
455    if (sublayers == m_sublayers)
456        return;
457
458    removeAllSublayers();
459    size_t listSize = sublayers.size();
460    for (size_t i = 0; i < listSize; ++i)
461        addSublayer(sublayers[i]);
462}
463
464void LayerWebKitThread::setNeedsDisplayInRect(const FloatRect& dirtyRect)
465{
466    if (m_tiler)
467        m_tiler->setNeedsDisplay(dirtyRect);
468    setNeedsCommit(); // FIXME: Replace this with a more targeted message for dirty rect handling with plugin content?
469}
470
471void LayerWebKitThread::setNeedsDisplay()
472{
473    if (m_tiler)
474        m_tiler->setNeedsDisplay();
475    setNeedsCommit(); // FIXME: Replace this with a more targeted message for dirty rect handling with plugin content?
476}
477
478void LayerWebKitThread::updateLayerHierarchy()
479{
480    m_layerCompositingThread->setSuperlayer(superlayer() ? superlayer()->m_layerCompositingThread.get() : 0);
481
482    Vector<RefPtr<LayerCompositingThread> > sublayers;
483    size_t listSize = m_overlays.size();
484    for (size_t i = 0; i < listSize; ++i)
485        sublayers.append(m_overlays[i]->m_layerCompositingThread.get());
486    listSize = m_sublayers.size();
487    for (size_t i = 0; i < listSize; ++i)
488        sublayers.append(m_sublayers[i]->m_layerCompositingThread.get());
489    m_layerCompositingThread->setSublayers(sublayers);
490}
491
492void LayerWebKitThread::setIsMask(bool isMask)
493{
494    m_isMask = isMask;
495    if (isMask && m_tiler)
496        m_tiler->setNeedsBacking(true);
497}
498
499void LayerWebKitThread::setRunningAnimations(const Vector<RefPtr<LayerAnimation> >& animations)
500{
501    m_runningAnimations = animations;
502    m_animationsChanged = true;
503    setNeedsCommit();
504}
505
506void LayerWebKitThread::setSuspendedAnimations(const Vector<RefPtr<LayerAnimation> >& animations)
507{
508    m_suspendedAnimations = animations;
509    m_animationsChanged = true;
510    setNeedsCommit();
511}
512
513void LayerWebKitThread::releaseLayerResources()
514{
515    deleteTextures();
516
517    size_t listSize = m_sublayers.size();
518    for (size_t i = 0; i < listSize; ++i)
519        m_sublayers[i]->releaseLayerResources();
520
521    listSize = m_overlays.size();
522    for (size_t i = 0; i < listSize; ++i)
523        m_overlays[i]->releaseLayerResources();
524
525    if (maskLayer())
526        maskLayer()->releaseLayerResources();
527
528    if (replicaLayer())
529        replicaLayer()->releaseLayerResources();
530}
531
532IntRect LayerWebKitThread::mapFromTransformed(const IntRect& contentsRect, double scale)
533{
534    IntRect untransformedContentsRect = contentsRect;
535
536    if (scale != 1.0) {
537        TransformationMatrix matrix;
538        matrix.scale(1.0 / scale);
539        untransformedContentsRect = matrix.mapRect(contentsRect);
540
541        // We extract from the contentsRect but draw a slightly larger region than
542        // we were told to, in order to avoid pixels being rendered only partially.
543        const int atLeastOneDevicePixel = static_cast<int>(ceilf(1.0 / scale));
544        untransformedContentsRect.inflate(atLeastOneDevicePixel);
545    }
546
547    return untransformedContentsRect;
548}
549
550}
551
552#endif // USE(ACCELERATED_COMPOSITING)
553