1/* 2 * Copyright (C) 2011 Apple Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26#include "config.h" 27 28#if USE(ACCELERATED_COMPOSITING) 29 30#include "PlatformCAAnimation.h" 31 32#include "FloatConversion.h" 33#include "TimingFunction.h" 34#include <QuartzCore/CACFAnimation.h> 35#include <QuartzCore/CACFTiming.h> 36#include <QuartzCore/CACFTimingFunction.h> 37#include <QuartzCore/CACFValueFunction.h> 38#include <QuartzCore/CACFVector.h> 39#include <wtf/text/WTFString.h> 40 41using namespace WebCore; 42 43static CFStringRef toCACFFillModeType(PlatformCAAnimation::FillModeType type) 44{ 45 switch (type) { 46 case PlatformCAAnimation::NoFillMode: 47 case PlatformCAAnimation::Forwards: return kCACFFillModeForwards; 48 case PlatformCAAnimation::Backwards: return kCACFFillModeBackwards; 49 case PlatformCAAnimation::Both: return kCACFFillModeBoth; 50 } 51 ASSERT_NOT_REACHED(); 52 return 0; 53} 54 55static PlatformCAAnimation::FillModeType fromCACFFillModeType(CFStringRef string) 56{ 57 if (string == kCACFFillModeBackwards) 58 return PlatformCAAnimation::Backwards; 59 60 if (string == kCACFFillModeBoth) 61 return PlatformCAAnimation::Both; 62 63 return PlatformCAAnimation::Forwards; 64} 65 66static CFStringRef toCACFValueFunctionType(PlatformCAAnimation::ValueFunctionType type) 67{ 68 switch (type) { 69 case PlatformCAAnimation::NoValueFunction: return 0; 70 case PlatformCAAnimation::RotateX: return kCACFValueFunctionRotateX; 71 case PlatformCAAnimation::RotateY: return kCACFValueFunctionRotateY; 72 case PlatformCAAnimation::RotateZ: return kCACFValueFunctionRotateZ; 73 case PlatformCAAnimation::ScaleX: return kCACFValueFunctionScaleX; 74 case PlatformCAAnimation::ScaleY: return kCACFValueFunctionScaleY; 75 case PlatformCAAnimation::ScaleZ: return kCACFValueFunctionScaleZ; 76 case PlatformCAAnimation::Scale: return kCACFValueFunctionScale; 77 case PlatformCAAnimation::TranslateX: return kCACFValueFunctionTranslateX; 78 case PlatformCAAnimation::TranslateY: return kCACFValueFunctionTranslateY; 79 case PlatformCAAnimation::TranslateZ: return kCACFValueFunctionTranslateZ; 80 case PlatformCAAnimation::Translate: return kCACFValueFunctionTranslate; 81 } 82 ASSERT_NOT_REACHED(); 83 return 0; 84} 85 86static PlatformCAAnimation::ValueFunctionType fromCACFValueFunctionType(CFStringRef string) 87{ 88 if (string == kCACFValueFunctionRotateX) 89 return PlatformCAAnimation::RotateX; 90 91 if (string == kCACFValueFunctionRotateY) 92 return PlatformCAAnimation::RotateY; 93 94 if (string == kCACFValueFunctionRotateZ) 95 return PlatformCAAnimation::RotateZ; 96 97 if (string == kCACFValueFunctionScaleX) 98 return PlatformCAAnimation::ScaleX; 99 100 if (string == kCACFValueFunctionScaleY) 101 return PlatformCAAnimation::ScaleY; 102 103 if (string == kCACFValueFunctionScaleZ) 104 return PlatformCAAnimation::ScaleZ; 105 106 if (string == kCACFValueFunctionScale) 107 return PlatformCAAnimation::Scale; 108 109 if (string == kCACFValueFunctionTranslateX) 110 return PlatformCAAnimation::TranslateX; 111 112 if (string == kCACFValueFunctionTranslateY) 113 return PlatformCAAnimation::TranslateY; 114 115 if (string == kCACFValueFunctionTranslateZ) 116 return PlatformCAAnimation::TranslateZ; 117 118 if (string == kCACFValueFunctionTranslate) 119 return PlatformCAAnimation::Translate; 120 121 return PlatformCAAnimation::NoValueFunction; 122} 123 124static RetainPtr<CACFTimingFunctionRef> toCACFTimingFunction(const TimingFunction* timingFunction, bool reverse) 125{ 126 ASSERT(timingFunction); 127 if (timingFunction->isCubicBezierTimingFunction()) { 128 RefPtr<CubicBezierTimingFunction> reversed; 129 const CubicBezierTimingFunction* ctf = static_cast<const CubicBezierTimingFunction*>(timingFunction); 130 131 if (reverse) { 132 reversed = ctf->createReversed(); 133 ctf = reversed.get(); 134 } 135 136 float x1 = static_cast<float>(ctf->x1()); 137 float y1 = static_cast<float>(ctf->y1()); 138 float x2 = static_cast<float>(ctf->x2()); 139 float y2 = static_cast<float>(ctf->y2()); 140 return adoptCF(CACFTimingFunctionCreate(x1, y1, x2, y2)); 141 } 142 143 return CACFTimingFunctionGetFunctionWithName(kCACFTimingFunctionLinear); 144} 145 146PassRefPtr<PlatformCAAnimation> PlatformCAAnimation::create(AnimationType type, const String& keyPath) 147{ 148 return adoptRef(new PlatformCAAnimation(type, keyPath)); 149} 150 151PassRefPtr<PlatformCAAnimation> PlatformCAAnimation::create(PlatformAnimationRef animation) 152{ 153 return adoptRef(new PlatformCAAnimation(animation)); 154} 155 156PlatformCAAnimation::PlatformCAAnimation(AnimationType type, const String& keyPath) 157 : m_type(type) 158{ 159 if (type == Basic) 160 m_animation = adoptCF(CACFAnimationCreate(kCACFBasicAnimation)); 161 else 162 m_animation = adoptCF(CACFAnimationCreate(kCACFKeyframeAnimation)); 163 164 CACFAnimationSetKeyPath(m_animation.get(), keyPath.createCFString().get()); 165} 166 167PlatformCAAnimation::PlatformCAAnimation(PlatformAnimationRef animation) 168{ 169 if (CACFAnimationGetClass(animation) == kCACFBasicAnimation) 170 m_type = Basic; 171 else if (CACFAnimationGetClass(animation) == kCACFKeyframeAnimation) 172 m_type = Keyframe; 173 else { 174 ASSERT_NOT_REACHED(); 175 return; 176 } 177 178 m_animation = animation; 179} 180 181PassRefPtr<PlatformCAAnimation> PlatformCAAnimation::copy() const 182{ 183 RefPtr<PlatformCAAnimation> animation = create(animationType(), keyPath()); 184 185 animation->setBeginTime(beginTime()); 186 animation->setDuration(duration()); 187 animation->setSpeed(speed()); 188 animation->setTimeOffset(timeOffset()); 189 animation->setRepeatCount(repeatCount()); 190 animation->setAutoreverses(autoreverses()); 191 animation->setFillMode(fillMode()); 192 animation->setRemovedOnCompletion(isRemovedOnCompletion()); 193 animation->setAdditive(isAdditive()); 194 animation->copyTimingFunctionFrom(this); 195 if (valueFunction()) 196 animation->setValueFunction(valueFunction()); 197 198 // Copy the specific Basic or Keyframe values 199 if (animationType() == Keyframe) { 200 animation->copyValuesFrom(this); 201 animation->copyKeyTimesFrom(this); 202 animation->copyTimingFunctionsFrom(this); 203 } else { 204 animation->copyFromValueFrom(this); 205 animation->copyToValueFrom(this); 206 } 207 208 return animation; 209} 210 211PlatformCAAnimation::~PlatformCAAnimation() 212{ 213} 214 215bool PlatformCAAnimation::supportsValueFunction() 216{ 217 return true; 218} 219 220PlatformAnimationRef PlatformCAAnimation::platformAnimation() const 221{ 222 return m_animation.get(); 223} 224 225String PlatformCAAnimation::keyPath() const 226{ 227 return CACFAnimationGetKeyPath(m_animation.get()); 228} 229 230CFTimeInterval PlatformCAAnimation::beginTime() const 231{ 232 return CACFAnimationGetBeginTime(m_animation.get()); 233} 234 235void PlatformCAAnimation::setBeginTime(CFTimeInterval value) 236{ 237 CACFAnimationSetBeginTime(m_animation.get(), value); 238} 239 240CFTimeInterval PlatformCAAnimation::duration() const 241{ 242 return CACFAnimationGetDuration(m_animation.get()); 243} 244 245void PlatformCAAnimation::setDuration(CFTimeInterval value) 246{ 247 CACFAnimationSetDuration(m_animation.get(), value); 248} 249 250float PlatformCAAnimation::speed() const 251{ 252 return CACFAnimationGetSpeed(m_animation.get()); 253} 254 255void PlatformCAAnimation::setSpeed(float value) 256{ 257 CACFAnimationSetSpeed(m_animation.get(), value); 258} 259 260CFTimeInterval PlatformCAAnimation::timeOffset() const 261{ 262 return CACFAnimationGetTimeOffset(m_animation.get()); 263} 264 265void PlatformCAAnimation::setTimeOffset(CFTimeInterval value) 266{ 267 CACFAnimationSetTimeOffset(m_animation.get(), value); 268} 269 270float PlatformCAAnimation::repeatCount() const 271{ 272 return CACFAnimationGetRepeatCount(m_animation.get()); 273} 274 275void PlatformCAAnimation::setRepeatCount(float value) 276{ 277 CACFAnimationSetRepeatCount(m_animation.get(), value); 278} 279 280bool PlatformCAAnimation::autoreverses() const 281{ 282 return CACFAnimationGetAutoreverses(m_animation.get()); 283} 284 285void PlatformCAAnimation::setAutoreverses(bool value) 286{ 287 CACFAnimationSetAutoreverses(m_animation.get(), value); 288} 289 290PlatformCAAnimation::FillModeType PlatformCAAnimation::fillMode() const 291{ 292 return fromCACFFillModeType(CACFAnimationGetFillMode(m_animation.get())); 293} 294 295void PlatformCAAnimation::setFillMode(FillModeType value) 296{ 297 CACFAnimationSetFillMode(m_animation.get(), toCACFFillModeType(value)); 298} 299 300void PlatformCAAnimation::setTimingFunction(const TimingFunction* value, bool reverse) 301{ 302 UNUSED_PARAM(reverse); 303 CACFAnimationSetTimingFunction(m_animation.get(), toCACFTimingFunction(value, reverse).get()); 304} 305 306void PlatformCAAnimation::copyTimingFunctionFrom(const PlatformCAAnimation* value) 307{ 308 CACFTimingFunctionRef timingFunc = CACFAnimationGetTimingFunction(value->m_animation.get()); 309 if (timingFunc) 310 CACFAnimationSetTimingFunction(m_animation.get(), timingFunc); 311} 312 313bool PlatformCAAnimation::isRemovedOnCompletion() const 314{ 315 return CACFAnimationIsRemovedOnCompletion(m_animation.get()); 316} 317 318void PlatformCAAnimation::setRemovedOnCompletion(bool value) 319{ 320 CACFAnimationSetRemovedOnCompletion(m_animation.get(), value); 321} 322 323bool PlatformCAAnimation::isAdditive() const 324{ 325 return CACFAnimationIsAdditive(m_animation.get()); 326} 327 328void PlatformCAAnimation::setAdditive(bool value) 329{ 330 CACFAnimationSetAdditive(m_animation.get(), value); 331} 332 333PlatformCAAnimation::ValueFunctionType PlatformCAAnimation::valueFunction() const 334{ 335 CACFValueFunctionRef func = CACFAnimationGetValueFunction(m_animation.get()); 336 return func ? fromCACFValueFunctionType(CACFValueFunctionGetName(func)) : NoValueFunction; 337} 338 339void PlatformCAAnimation::setValueFunction(ValueFunctionType value) 340{ 341 CFStringRef valueString = toCACFValueFunctionType(value); 342 CACFAnimationSetValueFunction(m_animation.get(), valueString ? CACFValueFunctionGetFunctionWithName(valueString) : 0); 343} 344 345void PlatformCAAnimation::setFromValue(float value) 346{ 347 if (animationType() != Basic) 348 return; 349 350 RetainPtr<CFNumberRef> v = adoptCF(CFNumberCreate(0, kCFNumberFloatType, &value)); 351 CACFAnimationSetFromValue(m_animation.get(), v.get()); 352} 353 354void PlatformCAAnimation::setFromValue(const WebCore::TransformationMatrix& value) 355{ 356 if (animationType() != Basic) 357 return; 358 359 RetainPtr<CACFVectorRef> v = adoptCF(CACFVectorCreateTransform(value)); 360 CACFAnimationSetFromValue(m_animation.get(), v.get()); 361} 362 363void PlatformCAAnimation::setFromValue(const FloatPoint3D& value) 364{ 365 if (animationType() != Basic) 366 return; 367 368 CGFloat a[3] = { value.x(), value.y(), value.z() }; 369 RetainPtr<CACFVectorRef> v = adoptCF(CACFVectorCreate(3, a)); 370 CACFAnimationSetFromValue(m_animation.get(), v.get()); 371} 372 373void PlatformCAAnimation::setFromValue(const WebCore::Color& value) 374{ 375 if (animationType() != Basic) 376 return; 377 378 CGFloat a[4] = { value.red(), value.green(), value.blue(), value.alpha() }; 379 RetainPtr<CACFVectorRef> v = adoptCF(CACFVectorCreate(4, a)); 380 CACFAnimationSetFromValue(m_animation.get(), v.get()); 381} 382 383#if ENABLE(CSS_FILTERS) 384void PlatformCAAnimation::setFromValue(const FilterOperation*, int) 385{ 386 // FIXME: Hardware filter animation not implemented on Windows 387} 388#endif 389 390void PlatformCAAnimation::copyFromValueFrom(const PlatformCAAnimation* value) 391{ 392 if (animationType() != Basic || value->animationType() != Basic) 393 return; 394 395 CACFAnimationSetFromValue(m_animation.get(), CACFAnimationGetFromValue(value->platformAnimation())); 396} 397 398void PlatformCAAnimation::setToValue(float value) 399{ 400 if (animationType() != Basic) 401 return; 402 403 RetainPtr<CFNumberRef> v = adoptCF(CFNumberCreate(0, kCFNumberFloatType, &value)); 404 CACFAnimationSetToValue(m_animation.get(), v.get()); 405} 406 407void PlatformCAAnimation::setToValue(const WebCore::TransformationMatrix& value) 408{ 409 if (animationType() != Basic) 410 return; 411 412 RetainPtr<CACFVectorRef> v = adoptCF(CACFVectorCreateTransform(value)); 413 CACFAnimationSetToValue(m_animation.get(), v.get()); 414} 415 416void PlatformCAAnimation::setToValue(const FloatPoint3D& value) 417{ 418 if (animationType() != Basic) 419 return; 420 421 CGFloat a[3] = { value.x(), value.y(), value.z() }; 422 RetainPtr<CACFVectorRef> v = adoptCF(CACFVectorCreate(3, a)); 423 CACFAnimationSetToValue(m_animation.get(), v.get()); 424} 425 426void PlatformCAAnimation::setToValue(const WebCore::Color& value) 427{ 428 if (animationType() != Basic) 429 return; 430 431 CGFloat a[4] = { value.red(), value.green(), value.blue(), value.alpha() }; 432 RetainPtr<CACFVectorRef> v = adoptCF(CACFVectorCreate(4, a)); 433 CACFAnimationSetToValue(m_animation.get(), v.get()); 434} 435 436#if ENABLE(CSS_FILTERS) 437void PlatformCAAnimation::setToValue(const FilterOperation*, int) 438{ 439 // FIXME: Hardware filter animation not implemented on Windows 440} 441#endif 442 443void PlatformCAAnimation::copyToValueFrom(const PlatformCAAnimation* value) 444{ 445 if (animationType() != Basic || value->animationType() != Basic) 446 return; 447 448 CACFAnimationSetToValue(m_animation.get(), CACFAnimationGetToValue(value->platformAnimation())); 449} 450 451 452// Keyframe-animation properties. 453void PlatformCAAnimation::setValues(const Vector<float>& value) 454{ 455 if (animationType() != Keyframe) 456 return; 457 458 RetainPtr<CFMutableArrayRef> array = adoptCF(CFArrayCreateMutable(0, value.size(), &kCFTypeArrayCallBacks)); 459 for (size_t i = 0; i < value.size(); ++i) { 460 RetainPtr<CFNumberRef> v = adoptCF(CFNumberCreate(0, kCFNumberFloatType, &value[i])); 461 CFArrayAppendValue(array.get(), v.get()); 462 } 463 464 CACFAnimationSetValues(m_animation.get(), array.get()); 465} 466 467void PlatformCAAnimation::setValues(const Vector<WebCore::TransformationMatrix>& value) 468{ 469 if (animationType() != Keyframe) 470 return; 471 472 RetainPtr<CFMutableArrayRef> array = adoptCF(CFArrayCreateMutable(0, value.size(), &kCFTypeArrayCallBacks)); 473 for (size_t i = 0; i < value.size(); ++i) { 474 RetainPtr<CACFVectorRef> v = adoptCF(CACFVectorCreateTransform(value[i])); 475 CFArrayAppendValue(array.get(), v.get()); 476 } 477 478 CACFAnimationSetValues(m_animation.get(), array.get()); 479} 480 481void PlatformCAAnimation::setValues(const Vector<FloatPoint3D>& value) 482{ 483 if (animationType() != Keyframe) 484 return; 485 486 RetainPtr<CFMutableArrayRef> array = adoptCF(CFArrayCreateMutable(0, value.size(), &kCFTypeArrayCallBacks)); 487 for (size_t i = 0; i < value.size(); ++i) { 488 CGFloat a[3] = { value[i].x(), value[i].y(), value[i].z() }; 489 RetainPtr<CACFVectorRef> v = adoptCF(CACFVectorCreate(3, a)); 490 CFArrayAppendValue(array.get(), v.get()); 491 } 492 493 CACFAnimationSetValues(m_animation.get(), array.get()); 494} 495 496void PlatformCAAnimation::setValues(const Vector<WebCore::Color>& value) 497{ 498 if (animationType() != Keyframe) 499 return; 500 501 RetainPtr<CFMutableArrayRef> array = adoptCF(CFArrayCreateMutable(0, value.size(), &kCFTypeArrayCallBacks)); 502 for (size_t i = 0; i < value.size(); ++i) { 503 CGFloat a[4] = { value[i].red(), value[i].green(), value[i].blue(), value[i].alpha() }; 504 RetainPtr<CACFVectorRef> v = adoptCF(CACFVectorCreate(4, a)); 505 CFArrayAppendValue(array.get(), v.get()); 506 } 507 508 CACFAnimationSetValues(m_animation.get(), array.get()); 509} 510 511#if ENABLE(CSS_FILTERS) 512void PlatformCAAnimation::setValues(const Vector<RefPtr<FilterOperation> >&, int) 513{ 514 // FIXME: Hardware filter animation not implemented on Windows 515} 516#endif 517 518void PlatformCAAnimation::copyValuesFrom(const PlatformCAAnimation* value) 519{ 520 if (animationType() != Keyframe || value->animationType() != Keyframe) 521 return; 522 523 CACFAnimationSetValues(m_animation.get(), CACFAnimationGetValues(value->platformAnimation())); 524} 525 526void PlatformCAAnimation::setKeyTimes(const Vector<float>& value) 527{ 528 if (animationType() != Keyframe) 529 return; 530 531 RetainPtr<CFMutableArrayRef> array = adoptCF(CFArrayCreateMutable(0, value.size(), &kCFTypeArrayCallBacks)); 532 for (size_t i = 0; i < value.size(); ++i) { 533 RetainPtr<CFNumberRef> v = adoptCF(CFNumberCreate(0, kCFNumberFloatType, &value[i])); 534 CFArrayAppendValue(array.get(), v.get()); 535 } 536 537 CACFAnimationSetKeyTimes(m_animation.get(), array.get()); 538} 539 540void PlatformCAAnimation::copyKeyTimesFrom(const PlatformCAAnimation* value) 541{ 542 if (animationType() != Keyframe) 543 return; 544 545 CACFAnimationSetKeyTimes(m_animation.get(), CACFAnimationGetKeyTimes(value->platformAnimation())); 546} 547 548void PlatformCAAnimation::setTimingFunctions(const Vector<const TimingFunction*>& value, bool reverse) 549{ 550 UNUSED_PARAM(reverse); 551 if (animationType() != Keyframe) 552 return; 553 554 RetainPtr<CFMutableArrayRef> array = adoptCF(CFArrayCreateMutable(0, value.size(), &kCFTypeArrayCallBacks)); 555 for (size_t i = 0; i < value.size(); ++i) { 556 RetainPtr<CFNumberRef> v = adoptCF(CFNumberCreate(0, kCFNumberFloatType, &value[i])); 557 CFArrayAppendValue(array.get(), toCACFTimingFunction(value[i], reverse).get()); 558 } 559 560 CACFAnimationSetTimingFunctions(m_animation.get(), array.get()); 561} 562 563void PlatformCAAnimation::copyTimingFunctionsFrom(const PlatformCAAnimation* value) 564{ 565 CACFAnimationSetTimingFunctions(m_animation.get(), CACFAnimationGetTimingFunctions(value->platformAnimation())); 566} 567 568#endif // USE(ACCELERATED_COMPOSITING) 569