1/*
2 * Copyright (C) 2010 Google Inc. All rights reserved.
3 * Copyright (C) 2009 Apple 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
33/** FIXME
34 * This file borrows code heavily from platform/graphics/win/GraphicsLayerCACF.cpp
35 * (and hence it includes both copyrights)
36 * Ideally the common code (mostly the code that keeps track of the layer hierarchy)
37 * should be kept separate and shared between platforms. It would be a well worthwhile
38 * effort once the Windows implementation (binaries and headers) of CoreAnimation is
39 * checked in to the WebKit repository. Until then only Apple can make this happen.
40 */
41
42#include "config.h"
43
44#if USE(ACCELERATED_COMPOSITING)
45
46#include "GraphicsLayerChromium.h"
47
48#include "Canvas2DLayerChromium.h"
49#include "ContentLayerChromium.h"
50#include "DrawingBuffer.h"
51#include "FloatConversion.h"
52#include "FloatRect.h"
53#include "Image.h"
54#include "ImageLayerChromium.h"
55#include "LayerChromium.h"
56#include "PlatformString.h"
57#include "SystemTime.h"
58
59#include <wtf/CurrentTime.h>
60#include <wtf/StringExtras.h>
61#include <wtf/text/CString.h>
62
63using namespace std;
64
65namespace WebCore {
66
67static void setLayerBorderColor(LayerChromium& layer, const Color& color)
68{
69    layer.setBorderColor(color);
70}
71
72static void clearBorderColor(LayerChromium& layer)
73{
74    layer.setBorderColor(static_cast<RGBA32>(0));
75}
76
77static void setLayerBackgroundColor(LayerChromium& layer, const Color& color)
78{
79    layer.setBackgroundColor(color);
80}
81
82static void clearLayerBackgroundColor(LayerChromium& layer)
83{
84    layer.setBackgroundColor(static_cast<RGBA32>(0));
85}
86
87PassOwnPtr<GraphicsLayer> GraphicsLayer::create(GraphicsLayerClient* client)
88{
89    return new GraphicsLayerChromium(client);
90}
91
92GraphicsLayerChromium::GraphicsLayerChromium(GraphicsLayerClient* client)
93    : GraphicsLayer(client)
94    , m_contentsLayerPurpose(NoContentsLayer)
95    , m_contentsLayerHasBackgroundColor(false)
96{
97    m_layer = ContentLayerChromium::create(this);
98
99    updateDebugIndicators();
100}
101
102GraphicsLayerChromium::~GraphicsLayerChromium()
103{
104    if (m_layer)
105        m_layer->setOwner(0);
106    if (m_contentsLayer)
107        m_contentsLayer->setOwner(0);
108    if (m_transformLayer)
109        m_transformLayer->setOwner(0);
110}
111
112void GraphicsLayerChromium::setName(const String& inName)
113{
114    m_nameBase = inName;
115    String name = String::format("GraphicsLayerChromium(%p) GraphicsLayer(%p) ", m_layer.get(), this) + inName;
116    GraphicsLayer::setName(name);
117    updateNames();
118}
119
120void GraphicsLayerChromium::updateNames()
121{
122    if (m_layer)
123        m_layer->setName("Layer for " + m_nameBase);
124    if (m_transformLayer)
125        m_transformLayer->setName("TransformLayer for " + m_nameBase);
126    if (m_contentsLayer)
127        m_contentsLayer->setName("ContentsLayer for " + m_nameBase);
128}
129
130bool GraphicsLayerChromium::setChildren(const Vector<GraphicsLayer*>& children)
131{
132    bool childrenChanged = GraphicsLayer::setChildren(children);
133    // FIXME: GraphicsLayer::setChildren calls addChild() for each sublayer, which
134    // will end up calling updateSublayerList() N times.
135    if (childrenChanged)
136        updateSublayerList();
137
138    return childrenChanged;
139}
140
141void GraphicsLayerChromium::addChild(GraphicsLayer* childLayer)
142{
143    GraphicsLayer::addChild(childLayer);
144    updateSublayerList();
145}
146
147void GraphicsLayerChromium::addChildAtIndex(GraphicsLayer* childLayer, int index)
148{
149    GraphicsLayer::addChildAtIndex(childLayer, index);
150    updateSublayerList();
151}
152
153void GraphicsLayerChromium::addChildBelow(GraphicsLayer* childLayer, GraphicsLayer* sibling)
154{
155    GraphicsLayer::addChildBelow(childLayer, sibling);
156    updateSublayerList();
157}
158
159void GraphicsLayerChromium::addChildAbove(GraphicsLayer* childLayer, GraphicsLayer *sibling)
160{
161    GraphicsLayer::addChildAbove(childLayer, sibling);
162    updateSublayerList();
163}
164
165bool GraphicsLayerChromium::replaceChild(GraphicsLayer* oldChild, GraphicsLayer* newChild)
166{
167    if (GraphicsLayer::replaceChild(oldChild, newChild)) {
168        updateSublayerList();
169        return true;
170    }
171    return false;
172}
173
174void GraphicsLayerChromium::removeFromParent()
175{
176    GraphicsLayer::removeFromParent();
177    layerForSuperlayer()->removeFromSuperlayer();
178}
179
180void GraphicsLayerChromium::setPosition(const FloatPoint& point)
181{
182    GraphicsLayer::setPosition(point);
183    updateLayerPosition();
184}
185
186void GraphicsLayerChromium::setAnchorPoint(const FloatPoint3D& point)
187{
188    if (point == m_anchorPoint)
189        return;
190
191    GraphicsLayer::setAnchorPoint(point);
192    updateAnchorPoint();
193}
194
195void GraphicsLayerChromium::setSize(const FloatSize& size)
196{
197    if (size == m_size)
198        return;
199
200    GraphicsLayer::setSize(size);
201    updateLayerSize();
202}
203
204void GraphicsLayerChromium::setTransform(const TransformationMatrix& transform)
205{
206    if (transform == m_transform)
207        return;
208
209    GraphicsLayer::setTransform(transform);
210    updateTransform();
211}
212
213void GraphicsLayerChromium::setChildrenTransform(const TransformationMatrix& transform)
214{
215    if (transform == m_childrenTransform)
216        return;
217
218    GraphicsLayer::setChildrenTransform(transform);
219    updateChildrenTransform();
220}
221
222void GraphicsLayerChromium::setPreserves3D(bool preserves3D)
223{
224    if (preserves3D == m_preserves3D)
225        return;
226
227    GraphicsLayer::setPreserves3D(preserves3D);
228    updateLayerPreserves3D();
229}
230
231void GraphicsLayerChromium::setMasksToBounds(bool masksToBounds)
232{
233    if (masksToBounds == m_masksToBounds)
234        return;
235
236    GraphicsLayer::setMasksToBounds(masksToBounds);
237    updateMasksToBounds();
238}
239
240void GraphicsLayerChromium::setDrawsContent(bool drawsContent)
241{
242    if (drawsContent == m_drawsContent)
243        return;
244
245    GraphicsLayer::setDrawsContent(drawsContent);
246    updateLayerDrawsContent();
247}
248
249void GraphicsLayerChromium::setBackgroundColor(const Color& color)
250{
251    if (m_backgroundColorSet && m_backgroundColor == color)
252        return;
253
254    GraphicsLayer::setBackgroundColor(color);
255
256    m_contentsLayerHasBackgroundColor = true;
257    updateLayerBackgroundColor();
258}
259
260void GraphicsLayerChromium::clearBackgroundColor()
261{
262    if (!m_backgroundColorSet)
263        return;
264
265    GraphicsLayer::clearBackgroundColor();
266    clearLayerBackgroundColor(*m_contentsLayer);
267}
268
269void GraphicsLayerChromium::setContentsOpaque(bool opaque)
270{
271    if (m_contentsOpaque == opaque)
272        return;
273
274    GraphicsLayer::setContentsOpaque(opaque);
275    updateContentsOpaque();
276}
277
278void GraphicsLayerChromium::setMaskLayer(GraphicsLayer* maskLayer)
279{
280    if (maskLayer == m_maskLayer)
281        return;
282
283    GraphicsLayer::setMaskLayer(maskLayer);
284
285    LayerChromium* maskLayerChromium = m_maskLayer ? m_maskLayer->platformLayer() : 0;
286    if (maskLayerChromium)
287        maskLayerChromium->setIsMask(true);
288    m_layer->setMaskLayer(maskLayerChromium);
289}
290
291void GraphicsLayerChromium::setBackfaceVisibility(bool visible)
292{
293    if (m_backfaceVisibility == visible)
294        return;
295
296    GraphicsLayer::setBackfaceVisibility(visible);
297    updateBackfaceVisibility();
298}
299
300void GraphicsLayerChromium::setOpacity(float opacity)
301{
302    float clampedOpacity = max(min(opacity, 1.0f), 0.0f);
303
304    if (m_opacity == clampedOpacity)
305        return;
306
307    GraphicsLayer::setOpacity(clampedOpacity);
308    primaryLayer()->setOpacity(opacity);
309}
310
311void GraphicsLayerChromium::setReplicatedByLayer(GraphicsLayer* layer)
312{
313    GraphicsLayerChromium* layerChromium = static_cast<GraphicsLayerChromium*>(layer);
314    GraphicsLayer::setReplicatedByLayer(layer);
315    LayerChromium* replicaLayer = layerChromium ? layerChromium->primaryLayer() : 0;
316    primaryLayer()->setReplicaLayer(replicaLayer);
317}
318
319
320void GraphicsLayerChromium::setContentsNeedsDisplay()
321{
322    if (m_contentsLayer)
323        m_contentsLayer->setNeedsDisplay();
324}
325
326void GraphicsLayerChromium::setNeedsDisplay()
327{
328    if (drawsContent())
329        m_layer->setNeedsDisplay();
330}
331
332void GraphicsLayerChromium::setNeedsDisplayInRect(const FloatRect& rect)
333{
334    if (drawsContent())
335        m_layer->setNeedsDisplay(rect);
336}
337
338void GraphicsLayerChromium::setContentsRect(const IntRect& rect)
339{
340    if (rect == m_contentsRect)
341        return;
342
343    GraphicsLayer::setContentsRect(rect);
344    updateContentsRect();
345}
346
347void GraphicsLayerChromium::setContentsToImage(Image* image)
348{
349    bool childrenChanged = false;
350    if (image) {
351        if (!m_contentsLayer.get() || m_contentsLayerPurpose != ContentsLayerForImage) {
352            RefPtr<ImageLayerChromium> imageLayer = ImageLayerChromium::create(this);
353            setupContentsLayer(imageLayer.get());
354            m_contentsLayer = imageLayer;
355            m_contentsLayerPurpose = ContentsLayerForImage;
356            childrenChanged = true;
357        }
358        ImageLayerChromium* imageLayer = static_cast<ImageLayerChromium*>(m_contentsLayer.get());
359        imageLayer->setContents(image);
360        updateContentsRect();
361    } else {
362        if (m_contentsLayer) {
363            childrenChanged = true;
364
365            // The old contents layer will be removed via updateSublayerList.
366            m_contentsLayer = 0;
367        }
368    }
369
370    if (childrenChanged)
371        updateSublayerList();
372}
373
374void GraphicsLayerChromium::setContentsToCanvas(PlatformLayer* platformLayer)
375{
376    bool childrenChanged = false;
377    if (platformLayer) {
378        platformLayer->setOwner(this);
379        if (m_contentsLayer.get() != platformLayer) {
380            setupContentsLayer(platformLayer);
381            m_contentsLayer = platformLayer;
382            m_contentsLayerPurpose = ContentsLayerForCanvas;
383            childrenChanged = true;
384        }
385        m_contentsLayer->setNeedsDisplay();
386        updateContentsRect();
387    } else {
388        if (m_contentsLayer) {
389            childrenChanged = true;
390
391            // The old contents layer will be removed via updateSublayerList.
392            m_contentsLayer = 0;
393        }
394    }
395
396    if (childrenChanged)
397        updateSublayerList();
398}
399
400void GraphicsLayerChromium::setContentsToMedia(PlatformLayer* layer)
401{
402    bool childrenChanged = false;
403    if (layer) {
404        if (!m_contentsLayer.get() || m_contentsLayerPurpose != ContentsLayerForVideo) {
405            setupContentsLayer(layer);
406            m_contentsLayer = layer;
407            m_contentsLayerPurpose = ContentsLayerForVideo;
408            childrenChanged = true;
409        }
410        layer->setOwner(this);
411        layer->setNeedsDisplay();
412        updateContentsRect();
413    } else {
414        if (m_contentsLayer) {
415            childrenChanged = true;
416
417            // The old contents layer will be removed via updateSublayerList.
418            m_contentsLayer = 0;
419        }
420    }
421
422    if (childrenChanged)
423        updateSublayerList();
424}
425
426PlatformLayer* GraphicsLayerChromium::hostLayerForSublayers() const
427{
428    return m_transformLayer ? m_transformLayer.get() : m_layer.get();
429}
430
431PlatformLayer* GraphicsLayerChromium::layerForSuperlayer() const
432{
433    return m_transformLayer ? m_transformLayer.get() : m_layer.get();
434}
435
436PlatformLayer* GraphicsLayerChromium::platformLayer() const
437{
438    return primaryLayer();
439}
440
441void GraphicsLayerChromium::setDebugBackgroundColor(const Color& color)
442{
443    if (color.isValid())
444        setLayerBackgroundColor(*m_layer, color);
445    else
446        clearLayerBackgroundColor(*m_layer);
447}
448
449void GraphicsLayerChromium::setDebugBorder(const Color& color, float borderWidth)
450{
451    if (color.isValid()) {
452        setLayerBorderColor(*m_layer, color);
453        m_layer->setBorderWidth(borderWidth);
454    } else {
455        clearBorderColor(*m_layer);
456        m_layer->setBorderWidth(0);
457    }
458}
459
460void GraphicsLayerChromium::updateSublayerList()
461{
462    Vector<RefPtr<LayerChromium> > newSublayers;
463
464    if (m_transformLayer) {
465        // Add the primary layer first. Even if we have negative z-order children, the primary layer always comes behind.
466        newSublayers.append(m_layer.get());
467    } else if (m_contentsLayer) {
468        // FIXME: add the contents layer in the correct order with negative z-order children.
469        // This does not cause visible rendering issues because currently contents layers are only used
470        // for replaced elements that don't have children.
471        newSublayers.append(m_contentsLayer.get());
472    }
473
474    const Vector<GraphicsLayer*>& childLayers = children();
475    size_t numChildren = childLayers.size();
476    for (size_t i = 0; i < numChildren; ++i) {
477        GraphicsLayerChromium* curChild = static_cast<GraphicsLayerChromium*>(childLayers[i]);
478
479        LayerChromium* childLayer = curChild->layerForSuperlayer();
480        newSublayers.append(childLayer);
481    }
482
483    for (size_t i = 0; i < newSublayers.size(); ++i)
484        newSublayers[i]->removeFromSuperlayer();
485
486    if (m_transformLayer) {
487        m_transformLayer->setSublayers(newSublayers);
488
489        if (m_contentsLayer) {
490            // If we have a transform layer, then the contents layer is parented in the
491            // primary layer (which is itself a child of the transform layer).
492            m_layer->removeAllSublayers();
493            m_layer->addSublayer(m_contentsLayer);
494        }
495    } else
496        m_layer->setSublayers(newSublayers);
497}
498
499void GraphicsLayerChromium::updateLayerPosition()
500{
501    // Position is offset on the layer by the layer anchor point.
502    FloatPoint layerPosition(m_position.x() + m_anchorPoint.x() * m_size.width(),
503                             m_position.y() + m_anchorPoint.y() * m_size.height());
504
505    primaryLayer()->setPosition(layerPosition);
506}
507
508void GraphicsLayerChromium::updateLayerSize()
509{
510    IntSize layerSize(m_size.width(), m_size.height());
511    if (m_transformLayer) {
512        m_transformLayer->setBounds(layerSize);
513        // The anchor of the contents layer is always at 0.5, 0.5, so the position is center-relative.
514        FloatPoint centerPoint(m_size.width() / 2, m_size.height() / 2);
515        m_layer->setPosition(centerPoint);
516    }
517
518    m_layer->setBounds(layerSize);
519
520    // Note that we don't resize m_contentsLayer. It's up the caller to do that.
521
522    // If we've changed the bounds, we need to recalculate the position
523    // of the layer, taking anchor point into account.
524    updateLayerPosition();
525}
526
527void GraphicsLayerChromium::updateAnchorPoint()
528{
529    primaryLayer()->setAnchorPoint(FloatPoint(m_anchorPoint.x(), m_anchorPoint.y()));
530    primaryLayer()->setAnchorPointZ(m_anchorPoint.z());
531
532    updateLayerPosition();
533}
534
535void GraphicsLayerChromium::updateTransform()
536{
537    primaryLayer()->setTransform(m_transform);
538}
539
540void GraphicsLayerChromium::updateChildrenTransform()
541{
542    primaryLayer()->setSublayerTransform(m_childrenTransform);
543}
544
545void GraphicsLayerChromium::updateMasksToBounds()
546{
547    m_layer->setMasksToBounds(m_masksToBounds);
548    updateDebugIndicators();
549}
550
551void GraphicsLayerChromium::updateContentsOpaque()
552{
553    m_layer->setOpaque(m_contentsOpaque);
554}
555
556void GraphicsLayerChromium::updateBackfaceVisibility()
557{
558    m_layer->setDoubleSided(m_backfaceVisibility);
559}
560
561void GraphicsLayerChromium::updateLayerPreserves3D()
562{
563    if (m_preserves3D && !m_transformLayer) {
564        // Create the transform layer.
565        m_transformLayer = LayerChromium::create(this);
566
567        // Copy the position from this layer.
568        updateLayerPosition();
569        updateLayerSize();
570        updateAnchorPoint();
571        updateTransform();
572        updateChildrenTransform();
573
574        m_layer->setPosition(FloatPoint(m_size.width() / 2.0f, m_size.height() / 2.0f));
575
576        m_layer->setAnchorPoint(FloatPoint(0.5f, 0.5f));
577        TransformationMatrix identity;
578        m_layer->setTransform(identity);
579
580        // Set the old layer to opacity of 1. Further down we will set the opacity on the transform layer.
581        m_layer->setOpacity(1);
582
583        // Move this layer to be a child of the transform layer.
584        if (m_layer->superlayer())
585            m_layer->superlayer()->replaceSublayer(m_layer.get(), m_transformLayer.get());
586        m_transformLayer->addSublayer(m_layer.get());
587
588        updateSublayerList();
589    } else if (!m_preserves3D && m_transformLayer) {
590        // Relace the transformLayer in the parent with this layer.
591        m_layer->removeFromSuperlayer();
592        m_transformLayer->superlayer()->replaceSublayer(m_transformLayer.get(), m_layer.get());
593
594        // Release the transform layer.
595        m_transformLayer = 0;
596
597        updateLayerPosition();
598        updateLayerSize();
599        updateAnchorPoint();
600        updateTransform();
601        updateChildrenTransform();
602
603        updateSublayerList();
604    }
605
606    updateOpacityOnLayer();
607    updateNames();
608}
609
610void GraphicsLayerChromium::updateLayerDrawsContent()
611{
612    if (m_drawsContent)
613        m_layer->setNeedsDisplay();
614
615    updateDebugIndicators();
616}
617
618void GraphicsLayerChromium::updateLayerBackgroundColor()
619{
620    if (!m_contentsLayer)
621        return;
622
623    // We never create the contents layer just for background color yet.
624    if (m_backgroundColorSet)
625        setLayerBackgroundColor(*m_contentsLayer, m_backgroundColor);
626    else
627        clearLayerBackgroundColor(*m_contentsLayer);
628}
629
630void GraphicsLayerChromium::updateContentsVideo()
631{
632    // FIXME: Implement
633}
634
635void GraphicsLayerChromium::updateContentsRect()
636{
637    if (!m_contentsLayer)
638        return;
639
640    m_contentsLayer->setPosition(FloatPoint(m_contentsRect.x(), m_contentsRect.y()));
641    m_contentsLayer->setBounds(IntSize(m_contentsRect.width(), m_contentsRect.height()));
642}
643
644void GraphicsLayerChromium::setupContentsLayer(LayerChromium* contentsLayer)
645{
646    if (contentsLayer == m_contentsLayer)
647        return;
648
649    if (m_contentsLayer) {
650        m_contentsLayer->removeFromSuperlayer();
651        m_contentsLayer = 0;
652    }
653
654    if (contentsLayer) {
655        m_contentsLayer = contentsLayer;
656
657        m_contentsLayer->setAnchorPoint(FloatPoint(0, 0));
658
659        // Insert the content layer first. Video elements require this, because they have
660        // shadow content that must display in front of the video.
661        m_layer->insertSublayer(m_contentsLayer.get(), 0);
662
663        updateContentsRect();
664
665        if (showDebugBorders()) {
666            setLayerBorderColor(*m_contentsLayer, Color(0, 0, 128, 180));
667            m_contentsLayer->setBorderWidth(1);
668        }
669    }
670    updateDebugIndicators();
671    updateNames();
672}
673
674// This function simply mimics the operation of GraphicsLayerCA
675void GraphicsLayerChromium::updateOpacityOnLayer()
676{
677    primaryLayer()->setOpacity(m_opacity);
678}
679
680} // namespace WebCore
681
682#endif // USE(ACCELERATED_COMPOSITING)
683