[GTK][AC] GraphicsLayerClutter doesn't need to recalculate its position after changin...
[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     // FIXME: Need to support page scaling.
498     clutter_actor_set_position(CLUTTER_ACTOR(m_layer.get()), m_position.x(), m_position.y());
499     clutter_actor_set_size(CLUTTER_ACTOR(m_layer.get()), m_size.width(), m_size.height());
500     graphicsLayerActorSetAnchorPoint(m_layer.get(), m_anchorPoint.x(), m_anchorPoint.y(), m_anchorPoint.z());
501 }
502
503 // Each GraphicsLayer has the corresponding layer in the platform port.
504 // So whenever the list of child layer changes, the list of GraphicsLayerActor should be updated accordingly.
505 void GraphicsLayerClutter::updateSublayerList()
506 {
507     GraphicsLayerActorList newSublayers;
508     const Vector<GraphicsLayer*>& childLayers = children();
509
510     if (childLayers.size() > 0) {
511         size_t numChildren = childLayers.size();
512         for (size_t i = 0; i < numChildren; ++i) {
513             GraphicsLayerClutter* curChild = static_cast<GraphicsLayerClutter*>(childLayers[i]);
514             GraphicsLayerActor* childLayer = curChild->layerForSuperlayer();
515             g_assert(GRAPHICS_LAYER_IS_ACTOR(childLayer));
516             newSublayers.append(childLayer);
517         }
518
519         for (size_t i = 0; i < newSublayers.size(); i++) {
520             ClutterActor* layerActor = CLUTTER_ACTOR(newSublayers[i].get());
521             ClutterActor* parentActor = clutter_actor_get_parent(layerActor);
522             if (parentActor)
523                 clutter_actor_remove_child(parentActor, layerActor);
524         }
525     }
526
527     graphicsLayerActorSetSublayers(m_layer.get(), newSublayers);
528 }
529
530 void GraphicsLayerClutter::updateLayerNames()
531 {
532     clutter_actor_set_name(CLUTTER_ACTOR(m_layer.get()), name().utf8().data());
533 }
534
535 void GraphicsLayerClutter::updateTransform()
536 {
537     CoglMatrix matrix = m_transform;
538     graphicsLayerActorSetTransform(primaryLayer(), &matrix);
539 }
540
541 void GraphicsLayerClutter::updateLayerDrawsContent(float pageScaleFactor, const FloatPoint& positionRelativeToBase)
542 {
543     if (m_drawsContent) {
544         graphicsLayerActorSetDrawsContent(m_layer.get(), TRUE);
545         setNeedsDisplay();
546     } else {
547         graphicsLayerActorSetDrawsContent(m_layer.get(), FALSE);
548         graphicsLayerActorSetSurface(m_layer.get(), 0);
549     }
550
551     updateDebugIndicators();
552 }
553
554 void GraphicsLayerClutter::setupAnimation(PlatformClutterAnimation* propertyAnim, const Animation* anim, bool additive)
555 {
556     double duration = anim->duration();
557     if (duration <= 0)
558         duration = cAnimationAlmostZeroDuration;
559
560     float repeatCount = anim->iterationCount();
561     if (repeatCount == Animation::IterationCountInfinite)
562         repeatCount = numeric_limits<float>::max();
563     else if (anim->direction() == Animation::AnimationDirectionAlternate || anim->direction() == Animation::AnimationDirectionAlternateReverse)
564         repeatCount /= 2;
565
566     PlatformClutterAnimation::FillModeType fillMode = PlatformClutterAnimation::NoFillMode;
567     switch (anim->fillMode()) {
568     case AnimationFillModeNone:
569         fillMode = PlatformClutterAnimation::Forwards; // Use "forwards" rather than "removed" because the style system will remove the animation when it is finished. This avoids a flash.
570         break;
571     case AnimationFillModeBackwards:
572         fillMode = PlatformClutterAnimation::Both; // Use "both" rather than "backwards" because the style system will remove the animation when it is finished. This avoids a flash.
573         break;
574     case AnimationFillModeForwards:
575         fillMode = PlatformClutterAnimation::Forwards;
576         break;
577     case AnimationFillModeBoth:
578         fillMode = PlatformClutterAnimation::Both;
579         break;
580     }
581
582     propertyAnim->setDuration(duration);
583     propertyAnim->setRepeatCount(repeatCount);
584     propertyAnim->setAutoreverses(anim->direction() == Animation::AnimationDirectionAlternate || anim->direction() == Animation::AnimationDirectionAlternateReverse);
585     propertyAnim->setRemovedOnCompletion(false);
586     propertyAnim->setAdditive(additive);
587     propertyAnim->setFillMode(fillMode);
588 }
589
590 const TimingFunction* GraphicsLayerClutter::timingFunctionForAnimationValue(const AnimationValue* animValue, const Animation* anim)
591 {
592     if (animValue->timingFunction())
593         return animValue->timingFunction();
594     if (anim->isTimingFunctionSet())
595         return anim->timingFunction().get();
596
597     return CubicBezierTimingFunction::defaultTimingFunction();
598 }
599
600 PassRefPtr<PlatformClutterAnimation> GraphicsLayerClutter::createBasicAnimation(const Animation* anim, const String& keyPath, bool additive)
601 {
602     RefPtr<PlatformClutterAnimation> basicAnim = PlatformClutterAnimation::create(PlatformClutterAnimation::Basic, keyPath);
603     setupAnimation(basicAnim.get(), anim, additive);
604     return basicAnim;
605 }
606
607 PassRefPtr<PlatformClutterAnimation>GraphicsLayerClutter::createKeyframeAnimation(const Animation* anim, const String& keyPath, bool additive)
608 {
609     notImplemented();
610     return 0;
611 }
612
613 bool GraphicsLayerClutter::setTransformAnimationKeyframes(const KeyframeValueList& valueList, const Animation* animation, PlatformClutterAnimation* keyframeAnim, int functionIndex, TransformOperation::OperationType transformOpType, bool isMatrixAnimation, const IntSize& boxSize)
614 {
615     notImplemented();
616     return false;
617 }
618
619 bool GraphicsLayerClutter::setTransformAnimationEndpoints(const KeyframeValueList& valueList, const Animation* animation, PlatformClutterAnimation* basicAnim, int functionIndex, TransformOperation::OperationType transformOpType, bool isMatrixAnimation, const IntSize& boxSize)
620 {
621     notImplemented();
622     return false;
623 }
624
625 bool GraphicsLayerClutter::createTransformAnimationsFromKeyframes(const KeyframeValueList& valueList, const Animation* animation, const String& animationName, double timeOffset, const IntSize& boxSize)
626 {
627     notImplemented();
628     return false;
629 }
630
631 bool GraphicsLayerClutter::createAnimationFromKeyframes(const KeyframeValueList& valueList, const Animation* animation, const String& animationName, double timeOffset)
632 {
633     ASSERT(valueList.property() != AnimatedPropertyWebkitTransform);
634
635     bool isKeyframe = valueList.size() > 2;
636     bool valuesOK;
637
638     bool additive = false;
639     int animationIndex = 0;
640
641     RefPtr<PlatformClutterAnimation> clutterAnimation;
642
643     if (isKeyframe) {
644         clutterAnimation = createKeyframeAnimation(animation, propertyIdToString(valueList.property()), additive);
645         valuesOK = setAnimationKeyframes(valueList, animation, clutterAnimation.get());
646     } else {
647         clutterAnimation = createBasicAnimation(animation, propertyIdToString(valueList.property()), additive);
648         valuesOK = setAnimationEndpoints(valueList, animation, clutterAnimation.get());
649     }
650
651     if (!valuesOK)
652         return false;
653
654     m_uncomittedAnimations.append(LayerPropertyAnimation(clutterAnimation, animationName, valueList.property(), animationIndex, timeOffset));
655
656     return true;
657 }
658
659 bool GraphicsLayerClutter::addAnimation(const KeyframeValueList& valueList, const IntSize& boxSize, const Animation* anim, const String& animationName, double timeOffset)
660 {
661     ASSERT(!animationName.isEmpty());
662
663     if (!anim || anim->isEmptyOrZeroDuration() || valueList.size() < 2)
664         return false;
665
666     // FIXME: ClutterTimeline seems to support steps timing function. So we need to improve here.
667     // See http://developer.gnome.org/clutter/stable/ClutterTimeline.html#ClutterAnimationMode
668     if (animationHasStepsTimingFunction(valueList, anim))
669         return false;
670
671     bool createdAnimations = false;
672     if (valueList.property() == AnimatedPropertyWebkitTransform)
673         createdAnimations = createTransformAnimationsFromKeyframes(valueList, anim, animationName, timeOffset, boxSize);
674     else
675         createdAnimations = createAnimationFromKeyframes(valueList, anim, animationName, timeOffset);
676
677     if (createdAnimations)
678         noteLayerPropertyChanged(AnimationChanged);
679
680     return createdAnimations;
681 }
682
683 bool GraphicsLayerClutter::removeClutterAnimationFromLayer(AnimatedPropertyID property, const String& animationName, int index)
684 {
685     notImplemented();
686     return false;
687 }
688
689 void GraphicsLayerClutter::pauseClutterAnimationOnLayer(AnimatedPropertyID property, const String& animationName, int index, double timeOffset)
690 {
691     notImplemented();
692 }
693
694 void GraphicsLayerClutter::setAnimationOnLayer(PlatformClutterAnimation* clutterAnim, AnimatedPropertyID property, const String& animationName, int index, double timeOffset)
695 {
696     GraphicsLayerActor* layer = animatedLayer(property);
697
698     if (timeOffset)
699         clutterAnim->setBeginTime(g_get_real_time() - timeOffset);
700
701     String animationID = animationIdentifier(animationName, property, index);
702
703     PlatformClutterAnimation* existingAnimation = graphicsLayerActorGetAnimationForKey(layer, animationID);
704     if (existingAnimation)
705         existingAnimation->removeAnimationForKey(layer, animationID);
706
707     clutterAnim->addAnimationForKey(layer, animationID);
708 }
709
710 bool GraphicsLayerClutter::setAnimationEndpoints(const KeyframeValueList& valueList, const Animation* animation, PlatformClutterAnimation* basicAnim)
711 {
712     bool forwards = animation->directionIsForwards();
713
714     unsigned fromIndex = !forwards;
715     unsigned toIndex = forwards;
716
717     switch (valueList.property()) {
718     case AnimatedPropertyOpacity: {
719         basicAnim->setFromValue(static_cast<const FloatAnimationValue*>(valueList.at(fromIndex))->value());
720         basicAnim->setToValue(static_cast<const FloatAnimationValue*>(valueList.at(toIndex))->value());
721         break;
722     }
723     default:
724         ASSERT_NOT_REACHED(); // we don't animate color yet
725         break;
726     }
727
728     // This codepath is used for 2-keyframe animations, so we still need to look in the start
729     // for a timing function. Even in the reversing animation case, the first keyframe provides the timing function.
730     const TimingFunction* timingFunction = timingFunctionForAnimationValue(valueList.at(0), animation);
731     if (timingFunction)
732         basicAnim->setTimingFunction(timingFunction, !forwards);
733
734     return true;
735 }
736
737 bool GraphicsLayerClutter::setAnimationKeyframes(const KeyframeValueList& valueList, const Animation* animation, PlatformClutterAnimation* keyframeAnim)
738 {
739     notImplemented();
740     return false;
741 }
742
743 GraphicsLayerActor* GraphicsLayerClutter::layerForSuperlayer() const
744 {
745     return m_layer.get();
746 }
747
748 GraphicsLayerActor* GraphicsLayerClutter::animatedLayer(AnimatedPropertyID property) const
749 {
750     return primaryLayer();
751 }
752
753 } // namespace WebCore
754
755 #endif // USE(ACCELERATED_COMPOSITING)