1/* 2 * Copyright (C) 2010 Apple Inc. All rights reserved. 3 * Copyright (C) 2013 Collabora Ltd. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY 15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR 18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27#include "config.h" 28 29#if USE(ACCELERATED_COMPOSITING) 30 31#include "PlatformClutterAnimation.h" 32 33#include "FloatConversion.h" 34#include "GraphicsLayerActor.h" 35#include "Logging.h" 36#include "NotImplemented.h" 37#include "TimingFunction.h" 38#include "UnitBezier.h" 39#include <limits.h> 40#include <wtf/CurrentTime.h> 41#include <wtf/OwnArrayPtr.h> 42#include <wtf/gobject/GOwnPtr.h> 43#include <wtf/text/CString.h> 44 45using namespace std; 46 47namespace WebCore { 48 49static void timelineStartedCallback(ClutterTimeline*, PlatformClutterAnimation* animation) 50{ 51 animation->animationDidStart(); 52} 53 54static String toClutterActorPropertyString(const PlatformClutterAnimation::ValueFunctionType valueFunctionType) 55{ 56 // ClutterActor doesn't have 'scale' and 'translate' properties. So we should support 57 // 'scale' and 'translate' ValueFunctionType by combination of existing property animations. 58 const char* clutterActorProperty[] = { "NoProperty", "rotation-angle-x", "rotation-angle-y", "rotation-angle-z", "scale-x", "scale-y", "scale-z", "scale", "translation-x", "translation-y", "translation-z", "translate", "transform" }; 59 return clutterActorProperty[valueFunctionType]; 60} 61 62static ClutterAnimationMode toClutterAnimationMode(const TimingFunction* timingFunction) 63{ 64 ASSERT(timingFunction); 65 66 if (timingFunction->isLinearTimingFunction()) 67 return CLUTTER_LINEAR; 68 if (timingFunction->isCubicBezierTimingFunction()) { 69 CubicBezierTimingFunction::TimingFunctionPreset timingFunctionPreset = static_cast<const CubicBezierTimingFunction*>(timingFunction)->timingFunctionPreset(); 70 switch (timingFunctionPreset) { 71 case CubicBezierTimingFunction::Ease: 72 return CLUTTER_EASE; 73 case CubicBezierTimingFunction::EaseIn: 74 return CLUTTER_EASE_IN; 75 case CubicBezierTimingFunction::EaseOut: 76 return CLUTTER_EASE_OUT; 77 case CubicBezierTimingFunction::EaseInOut: 78 return CLUTTER_EASE_IN_OUT; 79 default: 80 ASSERT_NOT_REACHED(); 81 } 82 } 83 84 return CLUTTER_EASE; 85} 86 87static gboolean clutterMatrixProgress(const GValue* fromValue, const GValue* toValue, gdouble progress, GValue* returnValue) 88{ 89 const CoglMatrix* fromCoglMatrix = static_cast<CoglMatrix*>(g_value_get_boxed(fromValue)); 90 const CoglMatrix* toCoglMatrix = static_cast<CoglMatrix*>(g_value_get_boxed(toValue)); 91 92 ASSERT(fromCoglMatrix && toCoglMatrix); 93 94 TransformationMatrix fromMatrix(fromCoglMatrix); 95 TransformationMatrix toMatrix(toCoglMatrix); 96 toMatrix.blend(fromMatrix, progress); 97 98 CoglMatrix resultCoglMatrix = toMatrix; 99 g_value_set_boxed(returnValue, &resultCoglMatrix); 100 101 return true; 102} 103 104PlatformClutterAnimation::AnimatedPropertyType PlatformClutterAnimation::stringToAnimatedPropertyType(const String& keyPath) const 105{ 106 if (keyPath == "transform") 107 return Transform; 108 if (keyPath == "opacity") 109 return Opacity; 110 if (keyPath == "backgroundColor") 111 return BackgroundColor; 112 return NoAnimatedPropertyType; 113} 114 115PassRefPtr<PlatformClutterAnimation> PlatformClutterAnimation::create(AnimationType type, const String& keyPath) 116{ 117 return adoptRef(new PlatformClutterAnimation(type, keyPath)); 118} 119 120PassRefPtr<PlatformClutterAnimation> PlatformClutterAnimation::create(PlatformClutterAnimation* animation) 121{ 122 return adoptRef(new PlatformClutterAnimation(animation)); 123} 124 125PlatformClutterAnimation::PlatformClutterAnimation(AnimationType type, const String& keyPath) 126 : m_type(type) 127 , m_animatedPropertyType(stringToAnimatedPropertyType(keyPath)) 128 , m_additive(false) 129 , m_fromValue(0) 130 , m_toValue(0) 131 , m_repeatCount(0) 132 , m_timingFunction(0) 133 , m_valueFunctionType(NoValueFunction) 134{ 135 m_animation = adoptGRef(G_OBJECT(clutter_transition_group_new())); 136} 137 138PlatformClutterAnimation::PlatformClutterAnimation(const PlatformClutterAnimation* animation) 139{ 140 notImplemented(); 141} 142 143PlatformClutterAnimation::~PlatformClutterAnimation() 144{ 145 m_animation.clear(); 146 m_layer.clear(); 147} 148 149bool PlatformClutterAnimation::supportsValueFunction() 150{ 151 return true; 152} 153 154bool PlatformClutterAnimation::supportsAdditiveValueFunction() 155{ 156 // FIXME: Clutter 1.12 doesn't support additive valueFunction type animations. 157 // So, we use matrix animation instead until clutter supports it. 158 return false; 159} 160 161double PlatformClutterAnimation::beginTime() const 162{ 163 notImplemented(); 164 return 0; 165} 166 167void PlatformClutterAnimation::setBeginTime(double value) 168{ 169 notImplemented(); 170} 171 172double PlatformClutterAnimation::duration() const 173{ 174 double duration = clutter_timeline_get_duration(CLUTTER_TIMELINE(m_animation.get())); 175 return duration / 1000; 176} 177 178void PlatformClutterAnimation::setDuration(double value) 179{ 180 // Clutter Animation sets the duration time in milliseconds. 181 gint duration = value * 1000; 182 clutter_timeline_set_duration(CLUTTER_TIMELINE(m_animation.get()), duration); 183} 184 185float PlatformClutterAnimation::speed() const 186{ 187 notImplemented(); 188 return 0; 189} 190 191void PlatformClutterAnimation::setSpeed(float value) 192{ 193 notImplemented(); 194} 195 196double PlatformClutterAnimation::timeOffset() const 197{ 198 notImplemented(); 199 return 0; 200} 201 202void PlatformClutterAnimation::setTimeOffset(double value) 203{ 204 notImplemented(); 205} 206 207float PlatformClutterAnimation::repeatCount() const 208{ 209 return m_repeatCount; 210} 211 212void PlatformClutterAnimation::setRepeatCount(float value) 213{ 214 if (m_repeatCount == value) 215 return; 216 217 m_repeatCount = value; 218 clutter_timeline_set_repeat_count(timeline(), static_cast<gint>(value == numeric_limits<float>::max() ? -1 : value)); 219} 220 221bool PlatformClutterAnimation::autoreverses() const 222{ 223 notImplemented(); 224 return false; 225} 226 227void PlatformClutterAnimation::setAutoreverses(bool value) 228{ 229 notImplemented(); 230} 231 232PlatformClutterAnimation::FillModeType PlatformClutterAnimation::fillMode() const 233{ 234 notImplemented(); 235 return PlatformClutterAnimation::NoFillMode; 236} 237 238void PlatformClutterAnimation::setFillMode(FillModeType value) 239{ 240 notImplemented(); 241} 242 243void PlatformClutterAnimation::setTimingFunction(const TimingFunction* timingFunction, bool reverse) 244{ 245 if (!timingFunction) 246 return; 247 248 m_timingFunction = timingFunction; 249} 250 251void PlatformClutterAnimation::copyTimingFunctionFrom(const PlatformClutterAnimation* value) 252{ 253 notImplemented(); 254} 255 256bool PlatformClutterAnimation::isRemovedOnCompletion() const 257{ 258 notImplemented(); 259 return false; 260} 261 262void PlatformClutterAnimation::setRemovedOnCompletion(bool value) 263{ 264 notImplemented(); 265} 266 267bool PlatformClutterAnimation::isAdditive() const 268{ 269 return m_additive; 270} 271 272void PlatformClutterAnimation::setAdditive(bool value) 273{ 274 if (m_additive == value) 275 return; 276 277 m_additive = value; 278} 279 280PlatformClutterAnimation::ValueFunctionType PlatformClutterAnimation::valueFunction() const 281{ 282 return m_valueFunctionType; 283} 284 285void PlatformClutterAnimation::setValueFunction(ValueFunctionType value) 286{ 287 if (m_valueFunctionType == value) 288 return; 289 290 m_valueFunctionType = value; 291} 292 293void PlatformClutterAnimation::setFromValue(float value) 294{ 295 if (animationType() != Basic || m_fromValue == value) 296 return; 297 298 m_fromValue = value; 299} 300 301void PlatformClutterAnimation::setFromValue(const WebCore::TransformationMatrix& value) 302{ 303 if (animationType() != Basic || m_fromValueMatrix == value) 304 return; 305 306 m_fromValueMatrix = value; 307} 308 309void PlatformClutterAnimation::setFromValue(const FloatPoint3D& value) 310{ 311 if (animationType() != Basic || m_fromValue3D == value) 312 return; 313 314 m_fromValue3D = value; 315} 316 317void PlatformClutterAnimation::setFromValue(const WebCore::Color& value) 318{ 319 notImplemented(); 320} 321 322void PlatformClutterAnimation::copyFromValueFrom(const PlatformClutterAnimation* value) 323{ 324 notImplemented(); 325} 326 327void PlatformClutterAnimation::setToValue(float value) 328{ 329 if (animationType() != Basic || m_toValue == value) 330 return; 331 332 m_toValue = value; 333} 334 335void PlatformClutterAnimation::setToValue(const WebCore::TransformationMatrix& value) 336{ 337 if (animationType() != Basic || m_toValueMatrix == value) 338 return; 339 340 m_toValueMatrix = value; 341} 342 343void PlatformClutterAnimation::setToValue(const FloatPoint3D& value) 344{ 345 if (animationType() != Basic || m_toValue3D == value) 346 return; 347 348 m_toValue3D = value; 349} 350 351void PlatformClutterAnimation::setToValue(const WebCore::Color& value) 352{ 353 notImplemented(); 354} 355 356void PlatformClutterAnimation::copyToValueFrom(const PlatformClutterAnimation* value) 357{ 358 notImplemented(); 359} 360 361void PlatformClutterAnimation::setValues(const Vector<float>& value) 362{ 363 ASSERT(animationType() == Keyframe); 364 365 m_values = value; 366} 367 368void PlatformClutterAnimation::setValues(const Vector<WebCore::TransformationMatrix>& value) 369{ 370 ASSERT(animationType() == Keyframe); 371 372 m_valuesMatrix = value; 373} 374 375void PlatformClutterAnimation::setValues(const Vector<FloatPoint3D>& value) 376{ 377 ASSERT(animationType() == Keyframe); 378 379 m_values3D = value; 380} 381 382void PlatformClutterAnimation::setValues(const Vector<WebCore::Color>& value) 383{ 384 notImplemented(); 385} 386 387void PlatformClutterAnimation::copyValuesFrom(const PlatformClutterAnimation* value) 388{ 389 notImplemented(); 390} 391 392void PlatformClutterAnimation::setKeyTimes(const Vector<float>& value) 393{ 394 ASSERT(animationType() == Keyframe); 395 396 m_keyTimes = value; 397} 398 399void PlatformClutterAnimation::copyKeyTimesFrom(const PlatformClutterAnimation* value) 400{ 401 notImplemented(); 402} 403 404void PlatformClutterAnimation::setTimingFunctions(const Vector<const TimingFunction*>& value, bool reverse) 405{ 406 ASSERT(animationType() == Keyframe); 407 408 m_timingFunctions = value; 409} 410 411void PlatformClutterAnimation::copyTimingFunctionsFrom(const PlatformClutterAnimation* value) 412{ 413 notImplemented(); 414} 415 416void PlatformClutterAnimation::animationDidStart() 417{ 418 ASSERT(CLUTTER_IS_ACTOR(m_layer.get())); 419 420 PlatformClutterLayerClient* client = graphicsLayerActorGetClient(GRAPHICS_LAYER_ACTOR(m_layer.get())); 421 if (!client) 422 return; 423 424 client->platformClutterLayerAnimationStarted(WTF::currentTime()); 425} 426 427ClutterTimeline* PlatformClutterAnimation::timeline() const 428{ 429 ASSERT(m_animation); 430 return CLUTTER_TIMELINE(m_animation.get()); 431} 432 433void PlatformClutterAnimation::addClutterTransitionForProperty(const String& property, const float fromValue, const float toValue) 434{ 435 ASSERT(property != "NoProperty"); 436 437 GRefPtr<ClutterTransition> transition = adoptGRef(clutter_property_transition_new(property.utf8().data())); 438 if (property == "opacity") { 439 clutter_transition_set_from(transition.get(), G_TYPE_UINT, static_cast<unsigned>(fromValue)); 440 clutter_transition_set_to(transition.get(), G_TYPE_UINT, static_cast<unsigned>(toValue)); 441 } else { 442 clutter_transition_set_from(transition.get(), G_TYPE_FLOAT, fromValue); 443 clutter_transition_set_to(transition.get(), G_TYPE_FLOAT, toValue); 444 } 445 446 clutter_timeline_set_progress_mode(timeline(), toClutterAnimationMode(m_timingFunction)); 447 448 clutter_transition_group_add_transition(CLUTTER_TRANSITION_GROUP(m_animation.get()), transition.get()); 449} 450 451void PlatformClutterAnimation::addClutterTransitionForProperty(const String& property, const WebCore::TransformationMatrix& fromValue, const WebCore::TransformationMatrix& toValue) 452{ 453 ASSERT(property != "NoProperty"); 454 455 const CoglMatrix fromCoglMatrix = fromValue; 456 const CoglMatrix toCoglMatrix = toValue; 457 458 GRefPtr<ClutterTransition> transition = adoptGRef(clutter_property_transition_new(property.utf8().data())); 459 clutter_transition_set_from(transition.get(), CLUTTER_TYPE_MATRIX, &fromCoglMatrix); 460 clutter_transition_set_to(transition.get(), CLUTTER_TYPE_MATRIX, &toCoglMatrix); 461 462 clutter_timeline_set_progress_mode(timeline(), toClutterAnimationMode(m_timingFunction)); 463 464 clutter_transition_group_add_transition(CLUTTER_TRANSITION_GROUP(m_animation.get()), transition.get()); 465 466 // FIXME: The matrix interpolation api, clutter_matrix_progress of Clutter 1.12 works unexpectedly. 467 // So we overwrite it and handle the interpolation of two matrices with TransformationMatrix. 468 // See https://bugzilla.gnome.org/show_bug.cgi?id=694197 469 clutter_interval_register_progress_func(CLUTTER_TYPE_MATRIX, clutterMatrixProgress); 470} 471 472void PlatformClutterAnimation::addClutterTransitionForProperty(const String& property, const FloatPoint3D& fromValue, const FloatPoint3D& toValue) 473{ 474 ASSERT(property != "NoProperty"); 475 476 if (property == "scale") { 477 addClutterTransitionForProperty(String("scale-x"), fromValue.x(), toValue.x()); 478 addClutterTransitionForProperty(String("scale-y"), fromValue.y(), toValue.y()); 479 return; 480 } 481 if (property == "translate") { 482 addClutterTransitionForProperty(String("translation-x"), fromValue.x(), toValue.x()); 483 addClutterTransitionForProperty(String("translation-y"), fromValue.x(), toValue.y()); 484 return; 485 } 486 487 ASSERT_NOT_REACHED(); 488} 489 490void PlatformClutterAnimation::addClutterKeyframeTransitionForProperty(const String& property, const Vector<float>& values) 491{ 492 ASSERT(property != "NoProperty"); 493 494 GType gType = (property == "opacity" ? G_TYPE_UINT : G_TYPE_FLOAT); 495 496 GRefPtr<ClutterTransition> transition = adoptGRef(clutter_keyframe_transition_new(property.utf8().data())); 497 if (gType == G_TYPE_UINT) { 498 clutter_transition_set_from(transition.get(), gType, static_cast<unsigned>(values.first())); 499 clutter_transition_set_to(transition.get(), gType, static_cast<unsigned>(values.last())); 500 } else { 501 clutter_transition_set_from(transition.get(), gType, values.first()); 502 clutter_transition_set_to(transition.get(), gType, values.last()); 503 } 504 505 // Ignore the first keyframe, since it's a '0' frame, meaningless. 506 const unsigned nKeyframes = values.size() - 1; 507 OwnArrayPtr<ClutterAnimationMode> animationModes = adoptArrayPtr(new ClutterAnimationMode[nKeyframes]); 508 OwnArrayPtr<double> keyTimes = adoptArrayPtr(new double[nKeyframes]); 509 GOwnPtr<GValue> keyValues(g_new0(GValue, nKeyframes)); 510 511 for (unsigned i = 0; i < nKeyframes; ++i) { 512 keyTimes[i] = static_cast<double>(m_keyTimes[i + 1]); 513 animationModes[i] = toClutterAnimationMode(m_timingFunctions[i]); 514 g_value_init(&keyValues.get()[i], gType); 515 if (gType == G_TYPE_UINT) 516 g_value_set_uint(&keyValues.get()[i], static_cast<unsigned>(values[i + 1])); 517 else 518 g_value_set_float(&keyValues.get()[i], values[i + 1]); 519 } 520 521 clutter_keyframe_transition_set_key_frames(CLUTTER_KEYFRAME_TRANSITION(transition.get()), nKeyframes, keyTimes.get()); 522 clutter_keyframe_transition_set_values(CLUTTER_KEYFRAME_TRANSITION(transition.get()), nKeyframes, keyValues.get()); 523 clutter_keyframe_transition_set_modes(CLUTTER_KEYFRAME_TRANSITION(transition.get()), nKeyframes, animationModes.get()); 524 525 clutter_transition_group_add_transition(CLUTTER_TRANSITION_GROUP(m_animation.get()), transition.get()); 526 527 for (unsigned i = 0; i < nKeyframes; ++i) 528 g_value_unset(&keyValues.get()[i]); 529} 530 531void PlatformClutterAnimation::addClutterKeyframeTransitionForProperty(const String& property, const Vector<WebCore::TransformationMatrix>& values) 532{ 533 ASSERT(property != "NoProperty"); 534 535 Vector<CoglMatrix> coglMatrices; 536 for (unsigned i = 0; i < values.size(); ++i) 537 coglMatrices.append(values[i]); 538 539 GRefPtr<ClutterTransition> transition = adoptGRef(clutter_keyframe_transition_new(property.utf8().data())); 540 clutter_transition_set_from(transition.get(), CLUTTER_TYPE_MATRIX, coglMatrices.first()); 541 clutter_transition_set_to(transition.get(), CLUTTER_TYPE_MATRIX, coglMatrices.last()); 542 543 // Ignore the first keyframe, since it's a '0' frame, meaningless. 544 const unsigned nKeyframes = values.size() - 1; 545 OwnArrayPtr<ClutterAnimationMode> animationModes = adoptArrayPtr(new ClutterAnimationMode[nKeyframes]); 546 OwnArrayPtr<double> keyTimes = adoptArrayPtr(new double[nKeyframes]); 547 GOwnPtr<GValue> keyValues(g_new0(GValue, nKeyframes)); 548 549 for (unsigned i = 0; i < nKeyframes; ++i) { 550 keyTimes[i] = static_cast<double>(m_keyTimes[i + 1]); 551 animationModes[i] = toClutterAnimationMode(m_timingFunctions[i]); 552 g_value_init(&keyValues.get()[i], CLUTTER_TYPE_MATRIX); 553 g_value_set_boxed(&keyValues.get()[i], &coglMatrices[i + 1]); 554 } 555 556 clutter_keyframe_transition_set_key_frames(CLUTTER_KEYFRAME_TRANSITION(transition.get()), nKeyframes, keyTimes.get()); 557 clutter_keyframe_transition_set_values(CLUTTER_KEYFRAME_TRANSITION(transition.get()), nKeyframes, keyValues.get()); 558 clutter_keyframe_transition_set_modes(CLUTTER_KEYFRAME_TRANSITION(transition.get()), nKeyframes, animationModes.get()); 559 560 clutter_transition_group_add_transition(CLUTTER_TRANSITION_GROUP(m_animation.get()), transition.get()); 561 562 clutter_interval_register_progress_func(CLUTTER_TYPE_MATRIX, clutterMatrixProgress); 563 564 for (unsigned i = 0; i < nKeyframes; ++i) 565 g_value_unset(&keyValues.get()[i]); 566} 567 568void PlatformClutterAnimation::addClutterKeyframeTransitionForProperty(const String& property, const Vector<FloatPoint3D>& values) 569{ 570 ASSERT(property != "NoProperty"); 571 572 Vector<float> valuesX, valuesY; 573 for (unsigned i = 0; i < values.size(); ++i) { 574 valuesX.append(values[i].x()); 575 valuesY.append(values[i].y()); 576 } 577 578 if (property == "scale") { 579 addClutterKeyframeTransitionForProperty(String("scale-x"), valuesX); 580 addClutterKeyframeTransitionForProperty(String("scale-y"), valuesY); 581 return; 582 } 583 if (property == "translate") { 584 addClutterKeyframeTransitionForProperty(String("translation-x"), valuesX); 585 addClutterKeyframeTransitionForProperty(String("translation-y"), valuesY); 586 return; 587 } 588 589 ASSERT_NOT_REACHED(); 590} 591 592void PlatformClutterAnimation::addOpacityTransition() 593{ 594 if (animationType() == Keyframe) { 595 for (unsigned i = 0; i < m_values.size(); ++i) 596 m_values[i] *= 255; 597 598 addClutterKeyframeTransitionForProperty(String("opacity"), m_values); 599 } else { 600 m_fromValue *= 255; 601 m_toValue *= 255; 602 603 addClutterTransitionForProperty(String("opacity"), m_fromValue, m_toValue); 604 } 605} 606 607void PlatformClutterAnimation::addTransformTransition() 608{ 609 const bool isKeyframe = (animationType() == Keyframe); 610 611 switch (m_valueFunctionType) { 612 case RotateX: 613 case RotateY: 614 case RotateZ: 615 if (isKeyframe) { 616 for (unsigned i = 0; i < m_values.size(); ++i) 617 m_values[i] = rad2deg(m_values[i]); 618 619 addClutterKeyframeTransitionForProperty(toClutterActorPropertyString(m_valueFunctionType), m_values); 620 } else { 621 m_fromValue = rad2deg(m_fromValue); 622 m_toValue = rad2deg(m_toValue); 623 624 addClutterTransitionForProperty(toClutterActorPropertyString(m_valueFunctionType), m_fromValue, m_toValue); 625 } 626 break; 627 case ScaleX: 628 case ScaleY: 629 case ScaleZ: 630 case TranslateX: 631 case TranslateY: 632 case TranslateZ: 633 if (isKeyframe) 634 addClutterKeyframeTransitionForProperty(toClutterActorPropertyString(m_valueFunctionType), m_values); 635 else 636 addClutterTransitionForProperty(toClutterActorPropertyString(m_valueFunctionType), m_fromValue, m_toValue); 637 break; 638 case Scale: 639 case Translate: 640 if (isKeyframe) 641 addClutterKeyframeTransitionForProperty(toClutterActorPropertyString(m_valueFunctionType), m_values3D); 642 else 643 addClutterTransitionForProperty(toClutterActorPropertyString(m_valueFunctionType), m_fromValue3D, m_toValue3D); 644 break; 645 case Matrix: 646 if (isKeyframe) 647 addClutterKeyframeTransitionForProperty(toClutterActorPropertyString(m_valueFunctionType), m_valuesMatrix); 648 else 649 addClutterTransitionForProperty(toClutterActorPropertyString(m_valueFunctionType), m_fromValueMatrix, m_toValueMatrix); 650 break; 651 default: 652 ASSERT_NOT_REACHED(); 653 } 654 655 // FIXME: Work-around the fact that if there is a transform already set the animation fails to start. 656 // https://bugzilla.gnome.org/show_bug.cgi?id=696804 657 clutter_actor_set_transform(m_layer.get(), 0); 658} 659 660void PlatformClutterAnimation::addAnimationForKey(GraphicsLayerActor* platformLayer, const String& key) 661{ 662 ASSERT(!g_object_get_data(G_OBJECT(platformLayer), key.utf8().data())); 663 664 m_layer = CLUTTER_ACTOR(platformLayer); 665 666 if (m_animatedPropertyType == Opacity) 667 addOpacityTransition(); 668 else if (m_animatedPropertyType == Transform) 669 addTransformTransition(); 670 else if (m_animatedPropertyType == BackgroundColor) 671 ASSERT_NOT_REACHED(); 672 else 673 ASSERT_NOT_REACHED(); 674 675 g_signal_connect(timeline(), "started", G_CALLBACK(timelineStartedCallback), this); 676 g_object_set_data(G_OBJECT(platformLayer), key.utf8().data(), this); 677 678 clutter_actor_add_transition(m_layer.get(), key.utf8().data(), CLUTTER_TRANSITION(m_animation.get())); 679} 680 681void PlatformClutterAnimation::removeAnimationForKey(GraphicsLayerActor* layer, const String& key) 682{ 683 clutter_actor_remove_transition(CLUTTER_ACTOR(layer), key.utf8().data()); 684 g_object_set_data(G_OBJECT(layer), key.utf8().data(), 0); 685} 686 687} // namespace WebCore 688 689#endif // USE(ACCELERATED_COMPOSITING) 690