1/*
2 * Copyright (C) 2009 Apple 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 * 1. Redistributions of source code must retain the above copyright
8 *    notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 *    notice, this list of conditions and the following disclaimer in the
11 *    documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF 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 "GraphicsLayer.h"
31
32#include "FloatPoint.h"
33#include "RotateTransformOperation.h"
34#include "TextStream.h"
35#include <wtf/text/CString.h>
36#include <wtf/text/StringConcatenate.h>
37
38#ifndef NDEBUG
39#include <stdio.h>
40#endif
41
42namespace WebCore {
43
44void KeyframeValueList::insert(const AnimationValue* value)
45{
46    for (size_t i = 0; i < m_values.size(); ++i) {
47        const AnimationValue* curValue = m_values[i];
48        if (curValue->keyTime() == value->keyTime()) {
49            ASSERT_NOT_REACHED();
50            // insert after
51            m_values.insert(i + 1, value);
52            return;
53        }
54        if (curValue->keyTime() > value->keyTime()) {
55            // insert before
56            m_values.insert(i, value);
57            return;
58        }
59    }
60
61    m_values.append(value);
62}
63
64GraphicsLayer::GraphicsLayer(GraphicsLayerClient* client)
65    : m_client(client)
66    , m_anchorPoint(0.5f, 0.5f, 0)
67    , m_opacity(1)
68    , m_zPosition(0)
69    , m_backgroundColorSet(false)
70    , m_contentsOpaque(false)
71    , m_preserves3D(false)
72    , m_backfaceVisibility(true)
73    , m_usingTiledLayer(false)
74    , m_masksToBounds(false)
75    , m_drawsContent(false)
76    , m_acceleratesDrawing(false)
77    , m_paintingPhase(GraphicsLayerPaintAll)
78    , m_contentsOrientation(CompositingCoordinatesTopDown)
79    , m_parent(0)
80    , m_maskLayer(0)
81    , m_replicaLayer(0)
82    , m_replicatedLayer(0)
83    , m_repaintCount(0)
84{
85}
86
87GraphicsLayer::~GraphicsLayer()
88{
89    removeAllChildren();
90    removeFromParent();
91}
92
93bool GraphicsLayer::hasAncestor(GraphicsLayer* ancestor) const
94{
95    for (GraphicsLayer* curr = parent(); curr; curr = curr->parent()) {
96        if (curr == ancestor)
97            return true;
98    }
99
100    return false;
101}
102
103bool GraphicsLayer::setChildren(const Vector<GraphicsLayer*>& newChildren)
104{
105    // If the contents of the arrays are the same, nothing to do.
106    if (newChildren == m_children)
107        return false;
108
109    removeAllChildren();
110
111    size_t listSize = newChildren.size();
112    for (size_t i = 0; i < listSize; ++i)
113        addChild(newChildren[i]);
114
115    return true;
116}
117
118void GraphicsLayer::addChild(GraphicsLayer* childLayer)
119{
120    ASSERT(childLayer != this);
121
122    if (childLayer->parent())
123        childLayer->removeFromParent();
124
125    childLayer->setParent(this);
126    m_children.append(childLayer);
127}
128
129void GraphicsLayer::addChildAtIndex(GraphicsLayer* childLayer, int index)
130{
131    ASSERT(childLayer != this);
132
133    if (childLayer->parent())
134        childLayer->removeFromParent();
135
136    childLayer->setParent(this);
137    m_children.insert(index, childLayer);
138}
139
140void GraphicsLayer::addChildBelow(GraphicsLayer* childLayer, GraphicsLayer* sibling)
141{
142    ASSERT(childLayer != this);
143    childLayer->removeFromParent();
144
145    bool found = false;
146    for (unsigned i = 0; i < m_children.size(); i++) {
147        if (sibling == m_children[i]) {
148            m_children.insert(i, childLayer);
149            found = true;
150            break;
151        }
152    }
153
154    childLayer->setParent(this);
155
156    if (!found)
157        m_children.append(childLayer);
158}
159
160void GraphicsLayer::addChildAbove(GraphicsLayer* childLayer, GraphicsLayer* sibling)
161{
162    childLayer->removeFromParent();
163    ASSERT(childLayer != this);
164
165    bool found = false;
166    for (unsigned i = 0; i < m_children.size(); i++) {
167        if (sibling == m_children[i]) {
168            m_children.insert(i+1, childLayer);
169            found = true;
170            break;
171        }
172    }
173
174    childLayer->setParent(this);
175
176    if (!found)
177        m_children.append(childLayer);
178}
179
180bool GraphicsLayer::replaceChild(GraphicsLayer* oldChild, GraphicsLayer* newChild)
181{
182    ASSERT(!newChild->parent());
183    bool found = false;
184    for (unsigned i = 0; i < m_children.size(); i++) {
185        if (oldChild == m_children[i]) {
186            m_children[i] = newChild;
187            found = true;
188            break;
189        }
190    }
191    if (found) {
192        oldChild->setParent(0);
193
194        newChild->removeFromParent();
195        newChild->setParent(this);
196        return true;
197    }
198    return false;
199}
200
201void GraphicsLayer::removeAllChildren()
202{
203    while (m_children.size()) {
204        GraphicsLayer* curLayer = m_children[0];
205        ASSERT(curLayer->parent());
206        curLayer->removeFromParent();
207    }
208}
209
210void GraphicsLayer::removeFromParent()
211{
212    if (m_parent) {
213        unsigned i;
214        for (i = 0; i < m_parent->m_children.size(); i++) {
215            if (this == m_parent->m_children[i]) {
216                m_parent->m_children.remove(i);
217                break;
218            }
219        }
220
221        setParent(0);
222    }
223}
224
225void GraphicsLayer::setReplicatedByLayer(GraphicsLayer* layer)
226{
227    if (layer)
228        layer->setReplicatedLayer(this);
229
230    m_replicaLayer = layer;
231}
232
233void GraphicsLayer::setBackgroundColor(const Color& color)
234{
235    m_backgroundColor = color;
236    m_backgroundColorSet = true;
237}
238
239void GraphicsLayer::clearBackgroundColor()
240{
241    m_backgroundColor = Color();
242    m_backgroundColorSet = false;
243}
244
245void GraphicsLayer::paintGraphicsLayerContents(GraphicsContext& context, const IntRect& clip)
246{
247    if (m_client)
248        m_client->paintContents(this, context, m_paintingPhase, clip);
249}
250
251String GraphicsLayer::animationNameForTransition(AnimatedPropertyID property)
252{
253    // | is not a valid identifier character in CSS, so this can never conflict with a keyframe identifier.
254    return makeString("-|transition", static_cast<char>(property), '-');
255}
256
257void GraphicsLayer::suspendAnimations(double)
258{
259}
260
261void GraphicsLayer::resumeAnimations()
262{
263}
264
265void GraphicsLayer::updateDebugIndicators()
266{
267    if (GraphicsLayer::showDebugBorders()) {
268        if (drawsContent()) {
269            if (m_usingTiledLayer)
270                setDebugBorder(Color(0, 255, 0, 204), 2.0f);    // tiled layer: green
271            else
272                setDebugBorder(Color(255, 0, 0, 204), 2.0f);    // normal layer: red
273        } else if (masksToBounds()) {
274            setDebugBorder(Color(128, 255, 255, 178), 2.0f);    // masking layer: pale blue
275            if (GraphicsLayer::showDebugBorders())
276                setDebugBackgroundColor(Color(128, 255, 255, 52));
277        } else
278            setDebugBorder(Color(255, 255, 0, 204), 2.0f);      // container: yellow
279    }
280}
281
282void GraphicsLayer::setZPosition(float position)
283{
284    m_zPosition = position;
285}
286
287float GraphicsLayer::accumulatedOpacity() const
288{
289    if (!preserves3D())
290        return 1;
291
292    return m_opacity * (parent() ? parent()->accumulatedOpacity() : 1);
293}
294
295void GraphicsLayer::distributeOpacity(float accumulatedOpacity)
296{
297    // If this is a transform layer we need to distribute our opacity to all our children
298
299    // Incoming accumulatedOpacity is the contribution from our parent(s). We mutiply this by our own
300    // opacity to get the total contribution
301    accumulatedOpacity *= m_opacity;
302
303    setOpacityInternal(accumulatedOpacity);
304
305    if (preserves3D()) {
306        size_t numChildren = children().size();
307        for (size_t i = 0; i < numChildren; ++i)
308            children()[i]->distributeOpacity(accumulatedOpacity);
309    }
310}
311
312// An "invalid" list is one whose functions don't match, and therefore has to be animated as a Matrix
313// The hasBigRotation flag will always return false if isValid is false. Otherwise hasBigRotation is
314// true if the rotation between any two keyframes is >= 180 degrees.
315
316static inline const TransformOperations* operationsAt(const KeyframeValueList& valueList, size_t index)
317{
318    return static_cast<const TransformAnimationValue*>(valueList.at(index))->value();
319}
320
321void GraphicsLayer::fetchTransformOperationList(const KeyframeValueList& valueList, TransformOperationList& list, bool& isValid, bool& hasBigRotation)
322{
323    ASSERT(valueList.property() == AnimatedPropertyWebkitTransform);
324
325    list.clear();
326    isValid = false;
327    hasBigRotation = false;
328
329    if (valueList.size() < 2)
330        return;
331
332    // Empty transforms match anything, so find the first non-empty entry as the reference.
333    size_t firstIndex = 0;
334    for ( ; firstIndex < valueList.size(); ++firstIndex) {
335        if (operationsAt(valueList, firstIndex)->operations().size() > 0)
336            break;
337    }
338
339    if (firstIndex >= valueList.size())
340        return;
341
342    const TransformOperations* firstVal = operationsAt(valueList, firstIndex);
343
344    // See if the keyframes are valid.
345    for (size_t i = firstIndex + 1; i < valueList.size(); ++i) {
346        const TransformOperations* val = operationsAt(valueList, i);
347
348        // a null transform matches anything
349        if (val->operations().isEmpty())
350            continue;
351
352        if (firstVal->operations().size() != val->operations().size())
353            return;
354
355        for (size_t j = 0; j < firstVal->operations().size(); ++j) {
356            if (!firstVal->operations().at(j)->isSameType(*val->operations().at(j)))
357                return;
358        }
359    }
360
361    // Keyframes are valid, fill in the list.
362    isValid = true;
363
364    double lastRotAngle = 0.0;
365    double maxRotAngle = -1.0;
366
367    list.resize(firstVal->operations().size());
368    for (size_t j = 0; j < firstVal->operations().size(); ++j) {
369        TransformOperation::OperationType type = firstVal->operations().at(j)->getOperationType();
370        list[j] = type;
371
372        // if this is a rotation entry, we need to see if any angle differences are >= 180 deg
373        if (type == TransformOperation::ROTATE_X ||
374            type == TransformOperation::ROTATE_Y ||
375            type == TransformOperation::ROTATE_Z ||
376            type == TransformOperation::ROTATE_3D) {
377            lastRotAngle = static_cast<RotateTransformOperation*>(firstVal->operations().at(j).get())->angle();
378
379            if (maxRotAngle < 0)
380                maxRotAngle = fabs(lastRotAngle);
381
382            for (size_t i = firstIndex + 1; i < valueList.size(); ++i) {
383                const TransformOperations* val = operationsAt(valueList, i);
384                double rotAngle = val->operations().isEmpty() ? 0 : (static_cast<RotateTransformOperation*>(val->operations().at(j).get())->angle());
385                double diffAngle = fabs(rotAngle - lastRotAngle);
386                if (diffAngle > maxRotAngle)
387                    maxRotAngle = diffAngle;
388                lastRotAngle = rotAngle;
389            }
390        }
391    }
392
393    hasBigRotation = maxRotAngle >= 180.0;
394}
395
396
397static void writeIndent(TextStream& ts, int indent)
398{
399    for (int i = 0; i != indent; ++i)
400        ts << "  ";
401}
402
403void GraphicsLayer::dumpLayer(TextStream& ts, int indent, LayerTreeAsTextBehavior behavior) const
404{
405    writeIndent(ts, indent);
406    ts << "(" << "GraphicsLayer";
407
408    if (behavior & LayerTreeAsTextDebug) {
409        ts << " " << static_cast<void*>(const_cast<GraphicsLayer*>(this));
410        ts << " \"" << m_name << "\"";
411    }
412
413    ts << "\n";
414    dumpProperties(ts, indent, behavior);
415    writeIndent(ts, indent);
416    ts << ")\n";
417}
418
419void GraphicsLayer::dumpProperties(TextStream& ts, int indent, LayerTreeAsTextBehavior behavior) const
420{
421    if (m_position != FloatPoint()) {
422        writeIndent(ts, indent + 1);
423        ts << "(position " << m_position.x() << " " << m_position.y() << ")\n";
424    }
425
426    if (m_anchorPoint != FloatPoint3D(0.5f, 0.5f, 0)) {
427        writeIndent(ts, indent + 1);
428        ts << "(anchor " << m_anchorPoint.x() << " " << m_anchorPoint.y() << ")\n";
429    }
430
431    if (m_size != IntSize()) {
432        writeIndent(ts, indent + 1);
433        ts << "(bounds " << m_size.width() << " " << m_size.height() << ")\n";
434    }
435
436    if (m_opacity != 1) {
437        writeIndent(ts, indent + 1);
438        ts << "(opacity " << m_opacity << ")\n";
439    }
440
441    if (m_usingTiledLayer) {
442        writeIndent(ts, indent + 1);
443        ts << "(usingTiledLayer " << m_usingTiledLayer << ")\n";
444    }
445
446    if (m_preserves3D) {
447        writeIndent(ts, indent + 1);
448        ts << "(preserves3D " << m_preserves3D << ")\n";
449    }
450
451    if (m_drawsContent) {
452        writeIndent(ts, indent + 1);
453        ts << "(drawsContent " << m_drawsContent << ")\n";
454    }
455
456    if (!m_backfaceVisibility) {
457        writeIndent(ts, indent + 1);
458        ts << "(backfaceVisibility " << (m_backfaceVisibility ? "visible" : "hidden") << ")\n";
459    }
460
461    if (behavior & LayerTreeAsTextDebug) {
462        writeIndent(ts, indent + 1);
463        ts << "(";
464        if (m_client)
465            ts << "client " << static_cast<void*>(m_client);
466        else
467            ts << "no client";
468        ts << ")\n";
469    }
470
471    if (m_backgroundColorSet) {
472        writeIndent(ts, indent + 1);
473        ts << "(backgroundColor " << m_backgroundColor.nameForRenderTreeAsText() << ")\n";
474    }
475
476    if (!m_transform.isIdentity()) {
477        writeIndent(ts, indent + 1);
478        ts << "(transform ";
479        ts << "[" << m_transform.m11() << " " << m_transform.m12() << " " << m_transform.m13() << " " << m_transform.m14() << "] ";
480        ts << "[" << m_transform.m21() << " " << m_transform.m22() << " " << m_transform.m23() << " " << m_transform.m24() << "] ";
481        ts << "[" << m_transform.m31() << " " << m_transform.m32() << " " << m_transform.m33() << " " << m_transform.m34() << "] ";
482        ts << "[" << m_transform.m41() << " " << m_transform.m42() << " " << m_transform.m43() << " " << m_transform.m44() << "])\n";
483    }
484
485    // Avoid dumping the sublayer transform on the root layer, because it's used for geometry flipping, whose behavior
486    // differs between platforms.
487    if (parent() && !m_childrenTransform.isIdentity()) {
488        writeIndent(ts, indent + 1);
489        ts << "(childrenTransform ";
490        ts << "[" << m_childrenTransform.m11() << " " << m_childrenTransform.m12() << " " << m_childrenTransform.m13() << " " << m_childrenTransform.m14() << "] ";
491        ts << "[" << m_childrenTransform.m21() << " " << m_childrenTransform.m22() << " " << m_childrenTransform.m23() << " " << m_childrenTransform.m24() << "] ";
492        ts << "[" << m_childrenTransform.m31() << " " << m_childrenTransform.m32() << " " << m_childrenTransform.m33() << " " << m_childrenTransform.m34() << "] ";
493        ts << "[" << m_childrenTransform.m41() << " " << m_childrenTransform.m42() << " " << m_childrenTransform.m43() << " " << m_childrenTransform.m44() << "])\n";
494    }
495
496    if (m_replicaLayer) {
497        writeIndent(ts, indent + 1);
498        ts << "(replica layer";
499        if (behavior & LayerTreeAsTextDebug)
500            ts << " " << m_replicaLayer;
501        ts << ")\n";
502        m_replicaLayer->dumpLayer(ts, indent + 2, behavior);
503    }
504
505    if (m_replicatedLayer) {
506        writeIndent(ts, indent + 1);
507        ts << "(replicated layer";
508        if (behavior & LayerTreeAsTextDebug)
509            ts << " " << m_replicatedLayer;;
510        ts << ")\n";
511    }
512
513    if (m_children.size()) {
514        writeIndent(ts, indent + 1);
515        ts << "(children " << m_children.size() << "\n";
516
517        unsigned i;
518        for (i = 0; i < m_children.size(); i++)
519            m_children[i]->dumpLayer(ts, indent + 2, behavior);
520        writeIndent(ts, indent + 1);
521        ts << ")\n";
522    }
523}
524
525String GraphicsLayer::layerTreeAsText(LayerTreeAsTextBehavior behavior) const
526{
527    TextStream ts;
528
529    dumpLayer(ts, 0, behavior);
530    return ts.release();
531}
532
533} // namespace WebCore
534
535#ifndef NDEBUG
536void showGraphicsLayerTree(const WebCore::GraphicsLayer* layer)
537{
538    if (!layer)
539        return;
540
541    WTF::String output = layer->layerTreeAsText(LayerTreeAsTextDebug);
542    fprintf(stderr, "%s\n", output.utf8().data());
543}
544#endif
545
546#endif // USE(ACCELERATED_COMPOSITING)
547