[GTK][AC] Clutter required version up to 1.12
[WebKit-https.git] / Source / WebCore / platform / graphics / clutter / GraphicsLayerClutter.cpp
1 /*
2  * Copyright (C) 2010 Apple Inc. All rights reserved.
3  * Copyright (C) 2011, 2012, 2013 Collabora Ltd.
4  * Copyright (C) 2012 Intel Corporation. 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
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
16  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
19  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
23  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
26  */
27
28 #include "config.h"
29
30 #if USE(ACCELERATED_COMPOSITING)
31 #include "GraphicsLayerClutter.h"
32
33 #include "Animation.h"
34 #include "FloatConversion.h"
35 #include "FloatRect.h"
36 #include "GraphicsLayerActor.h"
37 #include "GraphicsLayerFactory.h"
38 #include "NotImplemented.h"
39 #include "RefPtrCairo.h"
40 #include "RotateTransformOperation.h"
41 #include "ScaleTransformOperation.h"
42 #include "TransformState.h"
43 #include "TranslateTransformOperation.h"
44 #include <limits.h>
45 #include <wtf/text/CString.h>
46 #include <wtf/text/WTFString.h>
47
48 using namespace std;
49
50 namespace WebCore {
51
52 // If we send a duration of 0 to ClutterTimeline, then it will fail to set the duration. 
53 // So send a very small value instead.
54 static const float cAnimationAlmostZeroDuration = 1e-3f;
55
56 static String propertyIdToString(AnimatedPropertyID property)
57 {
58     switch (property) {
59     case AnimatedPropertyWebkitTransform:
60         return "transform";
61     case AnimatedPropertyOpacity:
62         return "opacity";
63     case AnimatedPropertyBackgroundColor:
64         return "backgroundColor";
65     case AnimatedPropertyWebkitFilter:
66         ASSERT_NOT_REACHED();
67     case AnimatedPropertyInvalid:
68         ASSERT_NOT_REACHED();
69     }
70     ASSERT_NOT_REACHED();
71     return "";
72 }
73
74 static String animationIdentifier(const String& animationName, AnimatedPropertyID property, int index)
75 {
76     return animationName + '_' + String::number(property) + '_' + String::number(index);
77 }
78
79 static bool animationHasStepsTimingFunction(const KeyframeValueList& valueList, const Animation* anim)
80 {
81     if (anim->timingFunction()->isStepsTimingFunction())
82         return true;
83
84     for (unsigned i = 0; i < valueList.size(); ++i) {
85         const TimingFunction* timingFunction = valueList.at(i)->timingFunction();
86         if (timingFunction && timingFunction->isStepsTimingFunction())
87             return true;
88     }
89
90     return false;
91 }
92
93 // This is the hook for WebCore compositor to know that the webKit clutter port implements
94 // compositing with GraphicsLayerClutter.
95 PassOwnPtr<GraphicsLayer> GraphicsLayer::create(GraphicsLayerFactory* factory, GraphicsLayerClient* client)
96 {
97     if (!factory)
98         return adoptPtr(new GraphicsLayerClutter(client));
99
100     return factory->createGraphicsLayer(client);
101 }
102
103 PassOwnPtr<GraphicsLayer> GraphicsLayer::create(GraphicsLayerClient* client)
104 {
105     return adoptPtr(new GraphicsLayerClutter(client));
106 }
107
108 GraphicsLayerClutter::GraphicsLayerClutter(GraphicsLayerClient* client)
109     : GraphicsLayer(client)
110     , m_uncommittedChanges(0)
111 {
112     // ClutterRectangle will be used to show the debug border.
113     m_layer = graphicsLayerActorNewWithClient(LayerTypeWebLayer, this);
114 }
115
116 static gboolean idleDestroy(gpointer data)
117 {
118     GRefPtr<ClutterActor> actor = adoptGRef(CLUTTER_ACTOR(data));
119     ClutterActor* parent = clutter_actor_get_parent(actor.get());
120
121     // We should remove child actors manually because the container of Clutter 
122     // seems to have a bug to remove its child actors when it is removed. 
123     if (GRAPHICS_LAYER_IS_ACTOR(GRAPHICS_LAYER_ACTOR(actor.get())))
124         graphicsLayerActorRemoveAll(GRAPHICS_LAYER_ACTOR(actor.get()));
125
126     if (parent)
127         clutter_actor_remove_child(parent, actor.get());
128
129     // FIXME: we should assert that the actor's ref count is 1 here, but some
130     // of them are getting here with 2!
131     // ASSERT((G_OBJECT(actor.get()))->ref_count == 1);
132
133     return FALSE;
134 }
135
136 GraphicsLayerClutter::~GraphicsLayerClutter()
137 {
138     if (graphicsLayerActorGetLayerType(m_layer.get()) == GraphicsLayerClutter::LayerTypeRootLayer)
139         return;
140
141     willBeDestroyed();
142
143     // We destroy the actors on an idle so that the main loop can run enough to
144     // repaint the background that will replace the actor.
145     if (m_layer) {
146         graphicsLayerActorSetClient(m_layer.get(), 0);
147         g_idle_add(idleDestroy, m_layer.leakRef());
148     }
149 }
150
151 void GraphicsLayerClutter::setName(const String& name)
152 {
153     String longName = String::format("Actor(%p) GraphicsLayer(%p) ", m_layer.get(), this) + name;
154     GraphicsLayer::setName(longName);
155     noteLayerPropertyChanged(NameChanged);
156 }
157
158 ClutterActor* GraphicsLayerClutter::platformLayer() const
159 {
160     return CLUTTER_ACTOR(m_layer.get());
161 }
162
163 void GraphicsLayerClutter::setNeedsDisplay()
164 {
165     FloatRect hugeRect(FloatPoint(), m_size);
166     setNeedsDisplayInRect(hugeRect);
167 }
168
169 void GraphicsLayerClutter::setNeedsDisplayInRect(const FloatRect& r)
170 {
171     if (!drawsContent())
172         return;
173
174     FloatRect rect(r);
175     FloatRect layerBounds(FloatPoint(), m_size);
176     rect.intersect(layerBounds);
177     if (rect.isEmpty())
178         return;
179
180     const size_t maxDirtyRects = 32;
181
182     for (size_t i = 0; i < m_dirtyRects.size(); ++i) {
183         if (m_dirtyRects[i].contains(rect))
184             return;
185     }
186
187     if (m_dirtyRects.size() < maxDirtyRects)
188         m_dirtyRects.append(rect);
189     else
190         m_dirtyRects[0].unite(rect);
191
192     noteLayerPropertyChanged(DirtyRectsChanged);
193 }
194
195 void GraphicsLayerClutter::setAnchorPoint(const FloatPoint3D& point)
196 {
197     if (point == m_anchorPoint)
198         return;
199
200     GraphicsLayer::setAnchorPoint(point);
201     noteLayerPropertyChanged(GeometryChanged);
202 }
203
204 void GraphicsLayerClutter::setOpacity(float opacity)
205 {
206     float clampedOpacity = max(0.0f, min(opacity, 1.0f));
207     if (clampedOpacity == m_opacity)
208         return;
209
210     GraphicsLayer::setOpacity(clampedOpacity);
211     noteLayerPropertyChanged(OpacityChanged);
212 }
213
214 void GraphicsLayerClutter::setPosition(const FloatPoint& point)
215 {
216     if (point == m_position)
217         return;
218
219     GraphicsLayer::setPosition(point);
220     noteLayerPropertyChanged(GeometryChanged);
221 }
222
223 void GraphicsLayerClutter::setSize(const FloatSize& size)
224 {
225     if (size == m_size)
226         return;
227
228     GraphicsLayer::setSize(size);
229     noteLayerPropertyChanged(GeometryChanged);
230 }
231 void GraphicsLayerClutter::setTransform(const TransformationMatrix& t)
232 {
233     if (t == m_transform)
234         return;
235
236     GraphicsLayer::setTransform(t);
237     noteLayerPropertyChanged(TransformChanged);
238 }
239
240 void GraphicsLayerClutter::setDrawsContent(bool drawsContent)
241 {
242     if (drawsContent == m_drawsContent)
243         return;
244
245     GraphicsLayer::setDrawsContent(drawsContent);
246     noteLayerPropertyChanged(DrawsContentChanged);
247 }
248
249 void GraphicsLayerClutter::setParent(GraphicsLayer* childLayer)
250 {
251     notImplemented();
252
253     GraphicsLayer::setParent(childLayer);
254 }
255
256 bool GraphicsLayerClutter::setChildren(const Vector<GraphicsLayer*>& children)
257 {
258     bool childrenChanged = GraphicsLayer::setChildren(children);
259     if (childrenChanged)
260         noteSublayersChanged();
261
262     return childrenChanged;
263 }
264
265 void GraphicsLayerClutter::addChild(GraphicsLayer* childLayer)
266 {
267     GraphicsLayer::addChild(childLayer);
268     noteSublayersChanged();
269 }
270
271 void GraphicsLayerClutter::addChildAtIndex(GraphicsLayer* childLayer, int index)
272 {
273     GraphicsLayer::addChildAtIndex(childLayer, index);
274     noteSublayersChanged();
275 }
276
277 void GraphicsLayerClutter::addChildBelow(GraphicsLayer* childLayer, GraphicsLayer* sibling)
278 {
279     GraphicsLayer::addChildBelow(childLayer, sibling);
280     noteSublayersChanged();
281 }
282
283 void GraphicsLayerClutter::addChildAbove(GraphicsLayer* childLayer, GraphicsLayer* sibling)
284 {
285     GraphicsLayer::addChildAbove(childLayer, sibling);
286     noteSublayersChanged();
287 }
288
289 bool GraphicsLayerClutter::replaceChild(GraphicsLayer* oldChild, GraphicsLayer* newChild)
290 {
291     if (GraphicsLayer::replaceChild(oldChild, newChild)) {
292         noteSublayersChanged();
293         return true;
294     }
295     return false;
296 }
297
298 void GraphicsLayerClutter::removeFromParent()
299 {
300     if (m_parent)
301         static_cast<GraphicsLayerClutter*>(m_parent)->noteSublayersChanged();
302     GraphicsLayer::removeFromParent();
303 }
304
305 void GraphicsLayerClutter::platformClutterLayerPaintContents(GraphicsContext& context, const IntRect& clip)
306 {
307     paintGraphicsLayerContents(context, clip);
308 }
309
310 void GraphicsLayerClutter::platformClutterLayerAnimationStarted(double startTime)
311 {
312     if (m_client)
313         m_client->notifyAnimationStarted(this, startTime);
314 }
315
316 void GraphicsLayerClutter::repaintLayerDirtyRects()
317 {
318     if (!m_dirtyRects.size())
319         return;
320
321     for (size_t i = 0; i < m_dirtyRects.size(); ++i)
322         graphicsLayerActorInvalidateRectangle(m_layer.get(), m_dirtyRects[i]);
323
324     m_dirtyRects.clear();
325 }
326
327 void GraphicsLayerClutter::updateOpacityOnLayer()
328 {
329     clutter_actor_set_opacity(CLUTTER_ACTOR(primaryLayer()), static_cast<guint8>(roundf(m_opacity * 255)));
330 }
331
332 void GraphicsLayerClutter::updateAnimations()
333 {
334     if (m_animationsToProcess.size()) {
335         AnimationsToProcessMap::const_iterator end = m_animationsToProcess.end();
336         for (AnimationsToProcessMap::const_iterator it = m_animationsToProcess.begin(); it != end; ++it) {
337             const String& currAnimationName = it->key;
338             AnimationsMap::iterator animationIt = m_runningAnimations.find(currAnimationName);
339             if (animationIt == m_runningAnimations.end())
340                 continue;
341
342             const AnimationProcessingAction& processingInfo = it->value;
343             const Vector<LayerPropertyAnimation>& animations = animationIt->value;
344             for (size_t i = 0; i < animations.size(); ++i) {
345                 const LayerPropertyAnimation& currAnimation = animations[i];
346                 switch (processingInfo.action) {
347                 case Remove:
348                     removeClutterAnimationFromLayer(currAnimation.m_property, currAnimationName, currAnimation.m_index);
349                     break;
350                 case Pause:
351                     pauseClutterAnimationOnLayer(currAnimation.m_property, currAnimationName, currAnimation.m_index, processingInfo.timeOffset);
352                     break;
353                 }
354             }
355
356             if (processingInfo.action == Remove)
357                 m_runningAnimations.remove(currAnimationName);
358         }
359
360         m_animationsToProcess.clear();
361     }
362
363     size_t numAnimations;
364     if ((numAnimations = m_uncomittedAnimations.size())) {
365         for (size_t i = 0; i < numAnimations; ++i) {
366             const LayerPropertyAnimation& pendingAnimation = m_uncomittedAnimations[i];
367             setAnimationOnLayer(pendingAnimation.m_animation.get(), pendingAnimation.m_property, pendingAnimation.m_name, pendingAnimation.m_index, pendingAnimation.m_timeOffset);
368
369             AnimationsMap::iterator it = m_runningAnimations.find(pendingAnimation.m_name);
370             if (it == m_runningAnimations.end()) {
371                 Vector<LayerPropertyAnimation> animations;
372                 animations.append(pendingAnimation);
373                 m_runningAnimations.add(pendingAnimation.m_name, animations);
374             } else {
375                 Vector<LayerPropertyAnimation>& animations = it->value;
376                 animations.append(pendingAnimation);
377             }
378         }
379
380         m_uncomittedAnimations.clear();
381     }
382 }
383
384 FloatPoint GraphicsLayerClutter::computePositionRelativeToBase(float& pageScale) const
385 {
386     pageScale = 1;
387
388     FloatPoint offset;
389     for (const GraphicsLayer* currLayer = this; currLayer; currLayer = currLayer->parent()) {
390         if (currLayer->appliesPageScale()) {
391             if (currLayer->client())
392                 pageScale = currLayer->pageScaleFactor();
393             return offset;
394         }
395
396         offset += currLayer->position();
397     }
398
399     return FloatPoint();
400 }
401
402 // called from void RenderLayerCompositor::flushPendingLayerChanges
403 void GraphicsLayerClutter::flushCompositingState(const FloatRect& clipRect)
404 {
405     TransformState state(TransformState::UnapplyInverseTransformDirection, FloatQuad(clipRect));
406     recursiveCommitChanges(state);
407 }
408
409 void GraphicsLayerClutter::recursiveCommitChanges(const TransformState& state, float pageScaleFactor, const FloatPoint& positionRelativeToBase, bool affectedByPageScale)
410 {
411     // FIXME: Save the state before sending down to kids and restore it after
412     TransformState localState = state;
413
414     if (appliesPageScale()) {
415         pageScaleFactor = this->pageScaleFactor();
416         affectedByPageScale = true;
417     }
418
419     // Accumulate an offset from the ancestral pixel-aligned layer.
420     FloatPoint baseRelativePosition = positionRelativeToBase;
421     if (affectedByPageScale)
422         baseRelativePosition += m_position;
423
424     commitLayerChangesBeforeSublayers(pageScaleFactor, baseRelativePosition);
425
426     const Vector<GraphicsLayer*>& childLayers = children();
427     size_t numChildren = childLayers.size();
428
429     for (size_t i = 0; i < numChildren; ++i) {
430         GraphicsLayerClutter* curChild = static_cast<GraphicsLayerClutter*>(childLayers[i]);
431         curChild->recursiveCommitChanges(localState, pageScaleFactor, baseRelativePosition, affectedByPageScale);
432     }
433
434     commitLayerChangesAfterSublayers();
435 }
436
437 void GraphicsLayerClutter::flushCompositingStateForThisLayerOnly()
438 {
439     float pageScaleFactor;
440     FloatPoint offset = computePositionRelativeToBase(pageScaleFactor);
441     commitLayerChangesBeforeSublayers(pageScaleFactor, offset);
442     commitLayerChangesAfterSublayers();
443 }
444
445 void GraphicsLayerClutter::commitLayerChangesAfterSublayers()
446 {
447     if (!m_uncommittedChanges)
448         return;
449
450     m_uncommittedChanges = NoChange;
451 }
452 void GraphicsLayerClutter::noteSublayersChanged()
453 {
454     noteLayerPropertyChanged(ChildrenChanged);
455 }
456
457 void GraphicsLayerClutter::noteLayerPropertyChanged(LayerChangeFlags flags)
458 {
459     if (!m_uncommittedChanges && m_client)
460         m_client->notifyFlushRequired(this); // call RenderLayerBacking::notifyFlushRequired
461
462     m_uncommittedChanges |= flags;
463 }
464
465 void GraphicsLayerClutter::commitLayerChangesBeforeSublayers(float pageScaleFactor, const FloatPoint& positionRelativeToBase)
466 {
467     if (!m_uncommittedChanges)
468         return;
469
470     if (m_uncommittedChanges & NameChanged)
471         updateLayerNames();
472
473     if (m_uncommittedChanges & ChildrenChanged)
474         updateSublayerList();
475
476     if (m_uncommittedChanges & GeometryChanged)
477         updateGeometry(pageScaleFactor, positionRelativeToBase);
478
479     if (m_uncommittedChanges & TransformChanged)
480         updateTransform();
481
482     if (m_uncommittedChanges & DrawsContentChanged)
483         updateLayerDrawsContent(pageScaleFactor, positionRelativeToBase);
484
485     if (m_uncommittedChanges & DirtyRectsChanged)
486         repaintLayerDirtyRects();
487
488     if (m_uncommittedChanges & OpacityChanged)
489         updateOpacityOnLayer();
490
491     if (m_uncommittedChanges & AnimationChanged)
492         updateAnimations();
493 }
494
495 void GraphicsLayerClutter::updateGeometry(float pageScaleFactor, const FloatPoint& positionRelativeToBase)
496 {
497     FloatPoint scaledPosition;
498     FloatPoint3D scaledAnchorPoint;
499     FloatSize scaledSize;
500
501     // FIXME: Need to support scaling
502     scaledPosition = m_position;
503     scaledAnchorPoint = m_anchorPoint;
504     scaledSize = m_size;
505
506     FloatRect adjustedBounds(m_boundsOrigin , scaledSize);
507     FloatPoint adjustedPosition(scaledPosition.x() + scaledAnchorPoint.x() * scaledSize.width(), scaledPosition.y() + scaledAnchorPoint.y() * scaledSize.height());
508
509     clutter_actor_set_size(CLUTTER_ACTOR(m_layer.get()), adjustedBounds.width(), adjustedBounds.height());
510     clutter_actor_set_position(CLUTTER_ACTOR(m_layer.get()), adjustedPosition.x(), adjustedPosition.y());
511     graphicsLayerActorSetAnchorPoint(m_layer.get(), scaledAnchorPoint.x(), scaledAnchorPoint.y(), scaledAnchorPoint.z());
512 }
513
514 // Each GraphicsLayer has the corresponding layer in the platform port.
515 // So whenever the list of child layer changes, the list of GraphicsLayerActor should be updated accordingly.
516 void GraphicsLayerClutter::updateSublayerList()
517 {
518     GraphicsLayerActorList newSublayers;
519     const Vector<GraphicsLayer*>& childLayers = children();
520
521     if (childLayers.size() > 0) {
522         size_t numChildren = childLayers.size();
523         for (size_t i = 0; i < numChildren; ++i) {
524             GraphicsLayerClutter* curChild = static_cast<GraphicsLayerClutter*>(childLayers[i]);
525             GraphicsLayerActor* childLayer = curChild->layerForSuperlayer();
526             g_assert(GRAPHICS_LAYER_IS_ACTOR(childLayer));
527             newSublayers.append(childLayer);
528         }
529
530         for (size_t i = 0; i < newSublayers.size(); i++) {
531             ClutterActor* layerActor = CLUTTER_ACTOR(newSublayers[i].get());
532             ClutterActor* parentActor = clutter_actor_get_parent(layerActor);
533             if (parentActor)
534                 clutter_actor_remove_child(parentActor, layerActor);
535         }
536     }
537
538     graphicsLayerActorSetSublayers(m_layer.get(), newSublayers);
539 }
540
541 void GraphicsLayerClutter::updateLayerNames()
542 {
543     clutter_actor_set_name(CLUTTER_ACTOR(m_layer.get()), name().utf8().data());
544 }
545
546 void GraphicsLayerClutter::updateTransform()
547 {
548     CoglMatrix matrix = m_transform;
549     graphicsLayerActorSetTransform(primaryLayer(), &matrix);
550 }
551
552 void GraphicsLayerClutter::updateLayerDrawsContent(float pageScaleFactor, const FloatPoint& positionRelativeToBase)
553 {
554     if (m_drawsContent) {
555         graphicsLayerActorSetDrawsContent(m_layer.get(), TRUE);
556         setNeedsDisplay();
557     } else {
558         graphicsLayerActorSetDrawsContent(m_layer.get(), FALSE);
559         graphicsLayerActorSetSurface(m_layer.get(), 0);
560     }
561
562     updateDebugIndicators();
563 }
564
565 void GraphicsLayerClutter::setupAnimation(PlatformClutterAnimation* propertyAnim, const Animation* anim, bool additive)
566 {
567     double duration = anim->duration();
568     if (duration <= 0)
569         duration = cAnimationAlmostZeroDuration;
570
571     float repeatCount = anim->iterationCount();
572     if (repeatCount == Animation::IterationCountInfinite)
573         repeatCount = numeric_limits<float>::max();
574     else if (anim->direction() == Animation::AnimationDirectionAlternate || anim->direction() == Animation::AnimationDirectionAlternateReverse)
575         repeatCount /= 2;
576
577     PlatformClutterAnimation::FillModeType fillMode = PlatformClutterAnimation::NoFillMode;
578     switch (anim->fillMode()) {
579     case AnimationFillModeNone:
580         fillMode = PlatformClutterAnimation::Forwards; // Use "forwards" rather than "removed" because the style system will remove the animation when it is finished. This avoids a flash.
581         break;
582     case AnimationFillModeBackwards:
583         fillMode = PlatformClutterAnimation::Both; // Use "both" rather than "backwards" because the style system will remove the animation when it is finished. This avoids a flash.
584         break;
585     case AnimationFillModeForwards:
586         fillMode = PlatformClutterAnimation::Forwards;
587         break;
588     case AnimationFillModeBoth:
589         fillMode = PlatformClutterAnimation::Both;
590         break;
591     }
592
593     propertyAnim->setDuration(duration);
594     propertyAnim->setRepeatCount(repeatCount);
595     propertyAnim->setAutoreverses(anim->direction() == Animation::AnimationDirectionAlternate || anim->direction() == Animation::AnimationDirectionAlternateReverse);
596     propertyAnim->setRemovedOnCompletion(false);
597     propertyAnim->setAdditive(additive);
598     propertyAnim->setFillMode(fillMode);
599 }
600
601 const TimingFunction* GraphicsLayerClutter::timingFunctionForAnimationValue(const AnimationValue* animValue, const Animation* anim)
602 {
603     if (animValue->timingFunction())
604         return animValue->timingFunction();
605     if (anim->isTimingFunctionSet())
606         return anim->timingFunction().get();
607
608     return CubicBezierTimingFunction::defaultTimingFunction();
609 }
610
611 PassRefPtr<PlatformClutterAnimation> GraphicsLayerClutter::createBasicAnimation(const Animation* anim, const String& keyPath, bool additive)
612 {
613     RefPtr<PlatformClutterAnimation> basicAnim = PlatformClutterAnimation::create(PlatformClutterAnimation::Basic, keyPath);
614     setupAnimation(basicAnim.get(), anim, additive);
615     return basicAnim;
616 }
617
618 PassRefPtr<PlatformClutterAnimation>GraphicsLayerClutter::createKeyframeAnimation(const Animation* anim, const String& keyPath, bool additive)
619 {
620     notImplemented();
621     return 0;
622 }
623
624 bool GraphicsLayerClutter::setTransformAnimationKeyframes(const KeyframeValueList& valueList, const Animation* animation, PlatformClutterAnimation* keyframeAnim, int functionIndex, TransformOperation::OperationType transformOpType, bool isMatrixAnimation, const IntSize& boxSize)
625 {
626     notImplemented();
627     return false;
628 }
629
630 bool GraphicsLayerClutter::setTransformAnimationEndpoints(const KeyframeValueList& valueList, const Animation* animation, PlatformClutterAnimation* basicAnim, int functionIndex, TransformOperation::OperationType transformOpType, bool isMatrixAnimation, const IntSize& boxSize)
631 {
632     notImplemented();
633     return false;
634 }
635
636 bool GraphicsLayerClutter::createTransformAnimationsFromKeyframes(const KeyframeValueList& valueList, const Animation* animation, const String& animationName, double timeOffset, const IntSize& boxSize)
637 {
638     notImplemented();
639     return false;
640 }
641
642 bool GraphicsLayerClutter::createAnimationFromKeyframes(const KeyframeValueList& valueList, const Animation* animation, const String& animationName, double timeOffset)
643 {
644     ASSERT(valueList.property() != AnimatedPropertyWebkitTransform);
645
646     bool isKeyframe = valueList.size() > 2;
647     bool valuesOK;
648
649     bool additive = false;
650     int animationIndex = 0;
651
652     RefPtr<PlatformClutterAnimation> clutterAnimation;
653
654     if (isKeyframe) {
655         clutterAnimation = createKeyframeAnimation(animation, propertyIdToString(valueList.property()), additive);
656         valuesOK = setAnimationKeyframes(valueList, animation, clutterAnimation.get());
657     } else {
658         clutterAnimation = createBasicAnimation(animation, propertyIdToString(valueList.property()), additive);
659         valuesOK = setAnimationEndpoints(valueList, animation, clutterAnimation.get());
660     }
661
662     if (!valuesOK)
663         return false;
664
665     m_uncomittedAnimations.append(LayerPropertyAnimation(clutterAnimation, animationName, valueList.property(), animationIndex, timeOffset));
666
667     return true;
668 }
669
670 bool GraphicsLayerClutter::addAnimation(const KeyframeValueList& valueList, const IntSize& boxSize, const Animation* anim, const String& animationName, double timeOffset)
671 {
672     ASSERT(!animationName.isEmpty());
673
674     if (!anim || anim->isEmptyOrZeroDuration() || valueList.size() < 2)
675         return false;
676
677     // FIXME: ClutterTimeline seems to support steps timing function. So we need to improve here.
678     // See http://developer.gnome.org/clutter/stable/ClutterTimeline.html#ClutterAnimationMode
679     if (animationHasStepsTimingFunction(valueList, anim))
680         return false;
681
682     bool createdAnimations = false;
683     if (valueList.property() == AnimatedPropertyWebkitTransform)
684         createdAnimations = createTransformAnimationsFromKeyframes(valueList, anim, animationName, timeOffset, boxSize);
685     else
686         createdAnimations = createAnimationFromKeyframes(valueList, anim, animationName, timeOffset);
687
688     if (createdAnimations)
689         noteLayerPropertyChanged(AnimationChanged);
690
691     return createdAnimations;
692 }
693
694 bool GraphicsLayerClutter::removeClutterAnimationFromLayer(AnimatedPropertyID property, const String& animationName, int index)
695 {
696     notImplemented();
697     return false;
698 }
699
700 void GraphicsLayerClutter::pauseClutterAnimationOnLayer(AnimatedPropertyID property, const String& animationName, int index, double timeOffset)
701 {
702     notImplemented();
703 }
704
705 void GraphicsLayerClutter::setAnimationOnLayer(PlatformClutterAnimation* clutterAnim, AnimatedPropertyID property, const String& animationName, int index, double timeOffset)
706 {
707     GraphicsLayerActor* layer = animatedLayer(property);
708
709     if (timeOffset)
710         clutterAnim->setBeginTime(g_get_real_time() - timeOffset);
711
712     String animationID = animationIdentifier(animationName, property, index);
713
714     PlatformClutterAnimation* existingAnimation = graphicsLayerActorGetAnimationForKey(layer, animationID);
715     if (existingAnimation)
716         existingAnimation->removeAnimationForKey(layer, animationID);
717
718     clutterAnim->addAnimationForKey(layer, animationID);
719 }
720
721 bool GraphicsLayerClutter::setAnimationEndpoints(const KeyframeValueList& valueList, const Animation* animation, PlatformClutterAnimation* basicAnim)
722 {
723     bool forwards = animation->directionIsForwards();
724
725     unsigned fromIndex = !forwards;
726     unsigned toIndex = forwards;
727
728     switch (valueList.property()) {
729     case AnimatedPropertyOpacity: {
730         basicAnim->setFromValue(static_cast<const FloatAnimationValue*>(valueList.at(fromIndex))->value());
731         basicAnim->setToValue(static_cast<const FloatAnimationValue*>(valueList.at(toIndex))->value());
732         break;
733     }
734     default:
735         ASSERT_NOT_REACHED(); // we don't animate color yet
736         break;
737     }
738
739     // This codepath is used for 2-keyframe animations, so we still need to look in the start
740     // for a timing function. Even in the reversing animation case, the first keyframe provides the timing function.
741     const TimingFunction* timingFunction = timingFunctionForAnimationValue(valueList.at(0), animation);
742     if (timingFunction)
743         basicAnim->setTimingFunction(timingFunction, !forwards);
744
745     return true;
746 }
747
748 bool GraphicsLayerClutter::setAnimationKeyframes(const KeyframeValueList& valueList, const Animation* animation, PlatformClutterAnimation* keyframeAnim)
749 {
750     notImplemented();
751     return false;
752 }
753
754 GraphicsLayerActor* GraphicsLayerClutter::layerForSuperlayer() const
755 {
756     return m_layer.get();
757 }
758
759 GraphicsLayerActor* GraphicsLayerClutter::animatedLayer(AnimatedPropertyID property) const
760 {
761     return primaryLayer();
762 }
763
764 } // namespace WebCore
765
766 #endif // USE(ACCELERATED_COMPOSITING)