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.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
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.
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.
30 #if USE(ACCELERATED_COMPOSITING)
31 #include "GraphicsLayerClutter.h"
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"
45 #include <wtf/text/CString.h>
46 #include <wtf/text/WTFString.h>
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;
56 static String propertyIdToString(AnimatedPropertyID property)
59 case AnimatedPropertyWebkitTransform:
61 case AnimatedPropertyOpacity:
63 case AnimatedPropertyBackgroundColor:
64 return "backgroundColor";
65 case AnimatedPropertyWebkitFilter:
67 case AnimatedPropertyInvalid:
74 static String animationIdentifier(const String& animationName, AnimatedPropertyID property, int index)
76 return animationName + '_' + String::number(property) + '_' + String::number(index);
79 static bool animationHasStepsTimingFunction(const KeyframeValueList& valueList, const Animation* anim)
81 if (anim->timingFunction()->isStepsTimingFunction())
84 for (unsigned i = 0; i < valueList.size(); ++i) {
85 const TimingFunction* timingFunction = valueList.at(i)->timingFunction();
86 if (timingFunction && timingFunction->isStepsTimingFunction())
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)
98 return adoptPtr(new GraphicsLayerClutter(client));
100 return factory->createGraphicsLayer(client);
103 PassOwnPtr<GraphicsLayer> GraphicsLayer::create(GraphicsLayerClient* client)
105 return adoptPtr(new GraphicsLayerClutter(client));
108 GraphicsLayerClutter::GraphicsLayerClutter(GraphicsLayerClient* client)
109 : GraphicsLayer(client)
110 , m_uncommittedChanges(0)
112 // ClutterRectangle will be used to show the debug border.
113 m_layer = graphicsLayerActorNewWithClient(LayerTypeWebLayer, this);
116 static gboolean idleDestroy(gpointer data)
118 GRefPtr<ClutterActor> actor = adoptGRef(CLUTTER_ACTOR(data));
119 ClutterActor* parent = clutter_actor_get_parent(actor.get());
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()));
127 clutter_actor_remove_child(parent, actor.get());
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);
136 GraphicsLayerClutter::~GraphicsLayerClutter()
138 if (graphicsLayerActorGetLayerType(m_layer.get()) == GraphicsLayerClutter::LayerTypeRootLayer)
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.
146 graphicsLayerActorSetClient(m_layer.get(), 0);
147 g_idle_add(idleDestroy, m_layer.leakRef());
151 void GraphicsLayerClutter::setName(const String& name)
153 String longName = String::format("Actor(%p) GraphicsLayer(%p) ", m_layer.get(), this) + name;
154 GraphicsLayer::setName(longName);
155 noteLayerPropertyChanged(NameChanged);
158 ClutterActor* GraphicsLayerClutter::platformLayer() const
160 return CLUTTER_ACTOR(m_layer.get());
163 void GraphicsLayerClutter::setNeedsDisplay()
165 FloatRect hugeRect(FloatPoint(), m_size);
166 setNeedsDisplayInRect(hugeRect);
169 void GraphicsLayerClutter::setNeedsDisplayInRect(const FloatRect& r)
175 FloatRect layerBounds(FloatPoint(), m_size);
176 rect.intersect(layerBounds);
180 const size_t maxDirtyRects = 32;
182 for (size_t i = 0; i < m_dirtyRects.size(); ++i) {
183 if (m_dirtyRects[i].contains(rect))
187 if (m_dirtyRects.size() < maxDirtyRects)
188 m_dirtyRects.append(rect);
190 m_dirtyRects[0].unite(rect);
192 noteLayerPropertyChanged(DirtyRectsChanged);
195 void GraphicsLayerClutter::setAnchorPoint(const FloatPoint3D& point)
197 if (point == m_anchorPoint)
200 GraphicsLayer::setAnchorPoint(point);
201 noteLayerPropertyChanged(GeometryChanged);
204 void GraphicsLayerClutter::setOpacity(float opacity)
206 float clampedOpacity = max(0.0f, min(opacity, 1.0f));
207 if (clampedOpacity == m_opacity)
210 GraphicsLayer::setOpacity(clampedOpacity);
211 noteLayerPropertyChanged(OpacityChanged);
214 void GraphicsLayerClutter::setPosition(const FloatPoint& point)
216 if (point == m_position)
219 GraphicsLayer::setPosition(point);
220 noteLayerPropertyChanged(GeometryChanged);
223 void GraphicsLayerClutter::setSize(const FloatSize& size)
228 GraphicsLayer::setSize(size);
229 noteLayerPropertyChanged(GeometryChanged);
231 void GraphicsLayerClutter::setTransform(const TransformationMatrix& t)
233 if (t == m_transform)
236 GraphicsLayer::setTransform(t);
237 noteLayerPropertyChanged(TransformChanged);
240 void GraphicsLayerClutter::setDrawsContent(bool drawsContent)
242 if (drawsContent == m_drawsContent)
245 GraphicsLayer::setDrawsContent(drawsContent);
246 noteLayerPropertyChanged(DrawsContentChanged);
249 void GraphicsLayerClutter::setParent(GraphicsLayer* childLayer)
253 GraphicsLayer::setParent(childLayer);
256 bool GraphicsLayerClutter::setChildren(const Vector<GraphicsLayer*>& children)
258 bool childrenChanged = GraphicsLayer::setChildren(children);
260 noteSublayersChanged();
262 return childrenChanged;
265 void GraphicsLayerClutter::addChild(GraphicsLayer* childLayer)
267 GraphicsLayer::addChild(childLayer);
268 noteSublayersChanged();
271 void GraphicsLayerClutter::addChildAtIndex(GraphicsLayer* childLayer, int index)
273 GraphicsLayer::addChildAtIndex(childLayer, index);
274 noteSublayersChanged();
277 void GraphicsLayerClutter::addChildBelow(GraphicsLayer* childLayer, GraphicsLayer* sibling)
279 GraphicsLayer::addChildBelow(childLayer, sibling);
280 noteSublayersChanged();
283 void GraphicsLayerClutter::addChildAbove(GraphicsLayer* childLayer, GraphicsLayer* sibling)
285 GraphicsLayer::addChildAbove(childLayer, sibling);
286 noteSublayersChanged();
289 bool GraphicsLayerClutter::replaceChild(GraphicsLayer* oldChild, GraphicsLayer* newChild)
291 if (GraphicsLayer::replaceChild(oldChild, newChild)) {
292 noteSublayersChanged();
298 void GraphicsLayerClutter::removeFromParent()
301 static_cast<GraphicsLayerClutter*>(m_parent)->noteSublayersChanged();
302 GraphicsLayer::removeFromParent();
305 void GraphicsLayerClutter::platformClutterLayerPaintContents(GraphicsContext& context, const IntRect& clip)
307 paintGraphicsLayerContents(context, clip);
310 void GraphicsLayerClutter::platformClutterLayerAnimationStarted(double startTime)
313 m_client->notifyAnimationStarted(this, startTime);
316 void GraphicsLayerClutter::repaintLayerDirtyRects()
318 if (!m_dirtyRects.size())
321 for (size_t i = 0; i < m_dirtyRects.size(); ++i)
322 graphicsLayerActorInvalidateRectangle(m_layer.get(), m_dirtyRects[i]);
324 m_dirtyRects.clear();
327 void GraphicsLayerClutter::updateOpacityOnLayer()
329 clutter_actor_set_opacity(CLUTTER_ACTOR(primaryLayer()), static_cast<guint8>(roundf(m_opacity * 255)));
332 void GraphicsLayerClutter::updateAnimations()
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())
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) {
348 removeClutterAnimationFromLayer(currAnimation.m_property, currAnimationName, currAnimation.m_index);
351 pauseClutterAnimationOnLayer(currAnimation.m_property, currAnimationName, currAnimation.m_index, processingInfo.timeOffset);
356 if (processingInfo.action == Remove)
357 m_runningAnimations.remove(currAnimationName);
360 m_animationsToProcess.clear();
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);
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);
375 Vector<LayerPropertyAnimation>& animations = it->value;
376 animations.append(pendingAnimation);
380 m_uncomittedAnimations.clear();
384 FloatPoint GraphicsLayerClutter::computePositionRelativeToBase(float& pageScale) const
389 for (const GraphicsLayer* currLayer = this; currLayer; currLayer = currLayer->parent()) {
390 if (currLayer->appliesPageScale()) {
391 if (currLayer->client())
392 pageScale = currLayer->pageScaleFactor();
396 offset += currLayer->position();
402 // called from void RenderLayerCompositor::flushPendingLayerChanges
403 void GraphicsLayerClutter::flushCompositingState(const FloatRect& clipRect)
405 TransformState state(TransformState::UnapplyInverseTransformDirection, FloatQuad(clipRect));
406 recursiveCommitChanges(state);
409 void GraphicsLayerClutter::recursiveCommitChanges(const TransformState& state, float pageScaleFactor, const FloatPoint& positionRelativeToBase, bool affectedByPageScale)
411 // FIXME: Save the state before sending down to kids and restore it after
412 TransformState localState = state;
414 if (appliesPageScale()) {
415 pageScaleFactor = this->pageScaleFactor();
416 affectedByPageScale = true;
419 // Accumulate an offset from the ancestral pixel-aligned layer.
420 FloatPoint baseRelativePosition = positionRelativeToBase;
421 if (affectedByPageScale)
422 baseRelativePosition += m_position;
424 commitLayerChangesBeforeSublayers(pageScaleFactor, baseRelativePosition);
426 const Vector<GraphicsLayer*>& childLayers = children();
427 size_t numChildren = childLayers.size();
429 for (size_t i = 0; i < numChildren; ++i) {
430 GraphicsLayerClutter* curChild = static_cast<GraphicsLayerClutter*>(childLayers[i]);
431 curChild->recursiveCommitChanges(localState, pageScaleFactor, baseRelativePosition, affectedByPageScale);
434 commitLayerChangesAfterSublayers();
437 void GraphicsLayerClutter::flushCompositingStateForThisLayerOnly()
439 float pageScaleFactor;
440 FloatPoint offset = computePositionRelativeToBase(pageScaleFactor);
441 commitLayerChangesBeforeSublayers(pageScaleFactor, offset);
442 commitLayerChangesAfterSublayers();
445 void GraphicsLayerClutter::commitLayerChangesAfterSublayers()
447 if (!m_uncommittedChanges)
450 m_uncommittedChanges = NoChange;
452 void GraphicsLayerClutter::noteSublayersChanged()
454 noteLayerPropertyChanged(ChildrenChanged);
457 void GraphicsLayerClutter::noteLayerPropertyChanged(LayerChangeFlags flags)
459 if (!m_uncommittedChanges && m_client)
460 m_client->notifyFlushRequired(this); // call RenderLayerBacking::notifyFlushRequired
462 m_uncommittedChanges |= flags;
465 void GraphicsLayerClutter::commitLayerChangesBeforeSublayers(float pageScaleFactor, const FloatPoint& positionRelativeToBase)
467 if (!m_uncommittedChanges)
470 if (m_uncommittedChanges & NameChanged)
473 if (m_uncommittedChanges & ChildrenChanged)
474 updateSublayerList();
476 if (m_uncommittedChanges & GeometryChanged)
477 updateGeometry(pageScaleFactor, positionRelativeToBase);
479 if (m_uncommittedChanges & TransformChanged)
482 if (m_uncommittedChanges & DrawsContentChanged)
483 updateLayerDrawsContent(pageScaleFactor, positionRelativeToBase);
485 if (m_uncommittedChanges & DirtyRectsChanged)
486 repaintLayerDirtyRects();
488 if (m_uncommittedChanges & OpacityChanged)
489 updateOpacityOnLayer();
491 if (m_uncommittedChanges & AnimationChanged)
495 void GraphicsLayerClutter::updateGeometry(float pageScaleFactor, const FloatPoint& positionRelativeToBase)
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());
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()
507 GraphicsLayerActorList newSublayers;
508 const Vector<GraphicsLayer*>& childLayers = children();
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);
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);
523 clutter_actor_remove_child(parentActor, layerActor);
527 graphicsLayerActorSetSublayers(m_layer.get(), newSublayers);
530 void GraphicsLayerClutter::updateLayerNames()
532 clutter_actor_set_name(CLUTTER_ACTOR(m_layer.get()), name().utf8().data());
535 void GraphicsLayerClutter::updateTransform()
537 CoglMatrix matrix = m_transform;
538 graphicsLayerActorSetTransform(primaryLayer(), &matrix);
541 void GraphicsLayerClutter::updateLayerDrawsContent(float pageScaleFactor, const FloatPoint& positionRelativeToBase)
543 if (m_drawsContent) {
544 graphicsLayerActorSetDrawsContent(m_layer.get(), TRUE);
547 graphicsLayerActorSetDrawsContent(m_layer.get(), FALSE);
548 graphicsLayerActorSetSurface(m_layer.get(), 0);
551 updateDebugIndicators();
554 void GraphicsLayerClutter::setupAnimation(PlatformClutterAnimation* propertyAnim, const Animation* anim, bool additive)
556 double duration = anim->duration();
558 duration = cAnimationAlmostZeroDuration;
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)
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.
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.
574 case AnimationFillModeForwards:
575 fillMode = PlatformClutterAnimation::Forwards;
577 case AnimationFillModeBoth:
578 fillMode = PlatformClutterAnimation::Both;
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);
590 const TimingFunction* GraphicsLayerClutter::timingFunctionForAnimationValue(const AnimationValue* animValue, const Animation* anim)
592 if (animValue->timingFunction())
593 return animValue->timingFunction();
594 if (anim->isTimingFunctionSet())
595 return anim->timingFunction().get();
597 return CubicBezierTimingFunction::defaultTimingFunction();
600 PassRefPtr<PlatformClutterAnimation> GraphicsLayerClutter::createBasicAnimation(const Animation* anim, const String& keyPath, bool additive)
602 RefPtr<PlatformClutterAnimation> basicAnim = PlatformClutterAnimation::create(PlatformClutterAnimation::Basic, keyPath);
603 setupAnimation(basicAnim.get(), anim, additive);
607 PassRefPtr<PlatformClutterAnimation>GraphicsLayerClutter::createKeyframeAnimation(const Animation* anim, const String& keyPath, bool additive)
613 bool GraphicsLayerClutter::setTransformAnimationKeyframes(const KeyframeValueList& valueList, const Animation* animation, PlatformClutterAnimation* keyframeAnim, int functionIndex, TransformOperation::OperationType transformOpType, bool isMatrixAnimation, const IntSize& boxSize)
619 bool GraphicsLayerClutter::setTransformAnimationEndpoints(const KeyframeValueList& valueList, const Animation* animation, PlatformClutterAnimation* basicAnim, int functionIndex, TransformOperation::OperationType transformOpType, bool isMatrixAnimation, const IntSize& boxSize)
625 bool GraphicsLayerClutter::createTransformAnimationsFromKeyframes(const KeyframeValueList& valueList, const Animation* animation, const String& animationName, double timeOffset, const IntSize& boxSize)
631 bool GraphicsLayerClutter::createAnimationFromKeyframes(const KeyframeValueList& valueList, const Animation* animation, const String& animationName, double timeOffset)
633 ASSERT(valueList.property() != AnimatedPropertyWebkitTransform);
635 bool isKeyframe = valueList.size() > 2;
638 bool additive = false;
639 int animationIndex = 0;
641 RefPtr<PlatformClutterAnimation> clutterAnimation;
644 clutterAnimation = createKeyframeAnimation(animation, propertyIdToString(valueList.property()), additive);
645 valuesOK = setAnimationKeyframes(valueList, animation, clutterAnimation.get());
647 clutterAnimation = createBasicAnimation(animation, propertyIdToString(valueList.property()), additive);
648 valuesOK = setAnimationEndpoints(valueList, animation, clutterAnimation.get());
654 m_uncomittedAnimations.append(LayerPropertyAnimation(clutterAnimation, animationName, valueList.property(), animationIndex, timeOffset));
659 bool GraphicsLayerClutter::addAnimation(const KeyframeValueList& valueList, const IntSize& boxSize, const Animation* anim, const String& animationName, double timeOffset)
661 ASSERT(!animationName.isEmpty());
663 if (!anim || anim->isEmptyOrZeroDuration() || valueList.size() < 2)
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))
671 bool createdAnimations = false;
672 if (valueList.property() == AnimatedPropertyWebkitTransform)
673 createdAnimations = createTransformAnimationsFromKeyframes(valueList, anim, animationName, timeOffset, boxSize);
675 createdAnimations = createAnimationFromKeyframes(valueList, anim, animationName, timeOffset);
677 if (createdAnimations)
678 noteLayerPropertyChanged(AnimationChanged);
680 return createdAnimations;
683 bool GraphicsLayerClutter::removeClutterAnimationFromLayer(AnimatedPropertyID property, const String& animationName, int index)
689 void GraphicsLayerClutter::pauseClutterAnimationOnLayer(AnimatedPropertyID property, const String& animationName, int index, double timeOffset)
694 void GraphicsLayerClutter::setAnimationOnLayer(PlatformClutterAnimation* clutterAnim, AnimatedPropertyID property, const String& animationName, int index, double timeOffset)
696 GraphicsLayerActor* layer = animatedLayer(property);
699 clutterAnim->setBeginTime(g_get_real_time() - timeOffset);
701 String animationID = animationIdentifier(animationName, property, index);
703 PlatformClutterAnimation* existingAnimation = graphicsLayerActorGetAnimationForKey(layer, animationID);
704 if (existingAnimation)
705 existingAnimation->removeAnimationForKey(layer, animationID);
707 clutterAnim->addAnimationForKey(layer, animationID);
710 bool GraphicsLayerClutter::setAnimationEndpoints(const KeyframeValueList& valueList, const Animation* animation, PlatformClutterAnimation* basicAnim)
712 bool forwards = animation->directionIsForwards();
714 unsigned fromIndex = !forwards;
715 unsigned toIndex = forwards;
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());
724 ASSERT_NOT_REACHED(); // we don't animate color yet
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);
732 basicAnim->setTimingFunction(timingFunction, !forwards);
737 bool GraphicsLayerClutter::setAnimationKeyframes(const KeyframeValueList& valueList, const Animation* animation, PlatformClutterAnimation* keyframeAnim)
743 GraphicsLayerActor* GraphicsLayerClutter::layerForSuperlayer() const
745 return m_layer.get();
748 GraphicsLayerActor* GraphicsLayerClutter::animatedLayer(AnimatedPropertyID property) const
750 return primaryLayer();
753 } // namespace WebCore
755 #endif // USE(ACCELERATED_COMPOSITING)