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 "PlatformString.h" 34#include "TimingFunction.h" 35#include <QuartzCore/CACFAnimation.h> 36#include <QuartzCore/CACFTiming.h> 37#include <QuartzCore/CACFTimingFunction.h> 38#include <QuartzCore/CACFValueFunction.h> 39#include <QuartzCore/CACFVector.h> 40#include <wtf/UnusedParam.h> 41 42using namespace WebCore; 43 44static CFStringRef toCACFFillModeType(PlatformCAAnimation::FillModeType type) 45{ 46 switch (type) { 47 case PlatformCAAnimation::NoFillMode: 48 case PlatformCAAnimation::Forwards: return kCACFFillModeForwards; 49 case PlatformCAAnimation::Backwards: return kCACFFillModeBackwards; 50 case PlatformCAAnimation::Both: return kCACFFillModeBoth; 51 } 52 ASSERT_NOT_REACHED(); 53 return 0; 54} 55 56static PlatformCAAnimation::FillModeType fromCACFFillModeType(CFStringRef string) 57{ 58 if (string == kCACFFillModeBackwards) 59 return PlatformCAAnimation::Backwards; 60 61 if (string == kCACFFillModeBoth) 62 return PlatformCAAnimation::Both; 63 64 return PlatformCAAnimation::Forwards; 65} 66 67static CFStringRef toCACFValueFunctionType(PlatformCAAnimation::ValueFunctionType type) 68{ 69 switch (type) { 70 case PlatformCAAnimation::NoValueFunction: return 0; 71 case PlatformCAAnimation::RotateX: return kCACFValueFunctionRotateX; 72 case PlatformCAAnimation::RotateY: return kCACFValueFunctionRotateY; 73 case PlatformCAAnimation::RotateZ: return kCACFValueFunctionRotateZ; 74 case PlatformCAAnimation::ScaleX: return kCACFValueFunctionScaleX; 75 case PlatformCAAnimation::ScaleY: return kCACFValueFunctionScaleY; 76 case PlatformCAAnimation::ScaleZ: return kCACFValueFunctionScaleZ; 77 case PlatformCAAnimation::Scale: return kCACFValueFunctionScale; 78 case PlatformCAAnimation::TranslateX: return kCACFValueFunctionTranslateX; 79 case PlatformCAAnimation::TranslateY: return kCACFValueFunctionTranslateY; 80 case PlatformCAAnimation::TranslateZ: return kCACFValueFunctionTranslateZ; 81 case PlatformCAAnimation::Translate: return kCACFValueFunctionTranslate; 82 } 83 ASSERT_NOT_REACHED(); 84 return 0; 85} 86 87static PlatformCAAnimation::ValueFunctionType fromCACFValueFunctionType(CFStringRef string) 88{ 89 if (string == kCACFValueFunctionRotateX) 90 return PlatformCAAnimation::RotateX; 91 92 if (string == kCACFValueFunctionRotateY) 93 return PlatformCAAnimation::RotateY; 94 95 if (string == kCACFValueFunctionRotateZ) 96 return PlatformCAAnimation::RotateZ; 97 98 if (string == kCACFValueFunctionScaleX) 99 return PlatformCAAnimation::ScaleX; 100 101 if (string == kCACFValueFunctionScaleY) 102 return PlatformCAAnimation::ScaleY; 103 104 if (string == kCACFValueFunctionScaleZ) 105 return PlatformCAAnimation::ScaleZ; 106 107 if (string == kCACFValueFunctionScale) 108 return PlatformCAAnimation::Scale; 109 110 if (string == kCACFValueFunctionTranslateX) 111 return PlatformCAAnimation::TranslateX; 112 113 if (string == kCACFValueFunctionTranslateY) 114 return PlatformCAAnimation::TranslateY; 115 116 if (string == kCACFValueFunctionTranslateZ) 117 return PlatformCAAnimation::TranslateZ; 118 119 if (string == kCACFValueFunctionTranslate) 120 return PlatformCAAnimation::Translate; 121 122 return PlatformCAAnimation::NoValueFunction; 123} 124 125static RetainPtr<CACFTimingFunctionRef> toCACFTimingFunction(const TimingFunction* timingFunction) 126{ 127 ASSERT(timingFunction); 128 if (timingFunction->isCubicBezierTimingFunction()) { 129 const CubicBezierTimingFunction* ctf = static_cast<const CubicBezierTimingFunction*>(timingFunction); 130 return RetainPtr<CACFTimingFunctionRef>(AdoptCF, CACFTimingFunctionCreate(static_cast<float>(ctf->x1()), static_cast<float>(ctf->y1()), static_cast<float>(ctf->x2()), static_cast<float>(ctf->y2()))); 131 } 132 133 return CACFTimingFunctionGetFunctionWithName(kCACFTimingFunctionLinear); 134} 135 136PassRefPtr<PlatformCAAnimation> PlatformCAAnimation::create(AnimationType type, const String& keyPath) 137{ 138 return adoptRef(new PlatformCAAnimation(type, keyPath)); 139} 140 141PassRefPtr<PlatformCAAnimation> PlatformCAAnimation::create(PlatformAnimationRef animation) 142{ 143 return adoptRef(new PlatformCAAnimation(animation)); 144} 145 146PlatformCAAnimation::PlatformCAAnimation(AnimationType type, const String& keyPath) 147 : m_type(type) 148{ 149 if (type == Basic) 150 m_animation.adoptCF(CACFAnimationCreate(kCACFBasicAnimation)); 151 else 152 m_animation.adoptCF(CACFAnimationCreate(kCACFKeyframeAnimation)); 153 154 RetainPtr<CFStringRef> s(AdoptCF, keyPath.createCFString()); 155 CACFAnimationSetKeyPath(m_animation.get(), s.get()); 156} 157 158PlatformCAAnimation::PlatformCAAnimation(PlatformAnimationRef animation) 159{ 160 if (CACFAnimationGetClass(animation) == kCACFBasicAnimation) 161 m_type = Basic; 162 else if (CACFAnimationGetClass(animation) == kCACFKeyframeAnimation) 163 m_type = Keyframe; 164 else { 165 ASSERT_NOT_REACHED(); 166 return; 167 } 168 169 m_animation = animation; 170} 171 172PassRefPtr<PlatformCAAnimation> PlatformCAAnimation::copy() const 173{ 174 RefPtr<PlatformCAAnimation> animation = create(animationType(), keyPath()); 175 176 animation->setBeginTime(beginTime()); 177 animation->setDuration(duration()); 178 animation->setSpeed(speed()); 179 animation->setTimeOffset(timeOffset()); 180 animation->setRepeatCount(repeatCount()); 181 animation->setAutoreverses(autoreverses()); 182 animation->setFillMode(fillMode()); 183 animation->setRemovedOnCompletion(isRemovedOnCompletion()); 184 animation->setAdditive(isAdditive()); 185 animation->copyTimingFunctionFrom(this); 186 animation->setValueFunction(valueFunction()); 187 188 // Copy the specific Basic or Keyframe values 189 if (animationType() == Keyframe) { 190 animation->copyValuesFrom(this); 191 animation->copyKeyTimesFrom(this); 192 animation->copyTimingFunctionsFrom(this); 193 } else { 194 animation->copyFromValueFrom(this); 195 animation->copyToValueFrom(this); 196 } 197 198 return animation; 199} 200 201PlatformCAAnimation::~PlatformCAAnimation() 202{ 203} 204 205bool PlatformCAAnimation::supportsValueFunction() 206{ 207 return true; 208} 209 210PlatformAnimationRef PlatformCAAnimation::platformAnimation() const 211{ 212 return m_animation.get(); 213} 214 215String PlatformCAAnimation::keyPath() const 216{ 217 return CACFAnimationGetKeyPath(m_animation.get()); 218} 219 220CFTimeInterval PlatformCAAnimation::beginTime() const 221{ 222 return CACFAnimationGetBeginTime(m_animation.get()); 223} 224 225void PlatformCAAnimation::setBeginTime(CFTimeInterval value) 226{ 227 CACFAnimationSetBeginTime(m_animation.get(), value); 228} 229 230CFTimeInterval PlatformCAAnimation::duration() const 231{ 232 return CACFAnimationGetDuration(m_animation.get()); 233} 234 235void PlatformCAAnimation::setDuration(CFTimeInterval value) 236{ 237 CACFAnimationSetDuration(m_animation.get(), value); 238} 239 240float PlatformCAAnimation::speed() const 241{ 242 return CACFAnimationGetSpeed(m_animation.get()); 243} 244 245void PlatformCAAnimation::setSpeed(float value) 246{ 247 CACFAnimationSetSpeed(m_animation.get(), value); 248} 249 250CFTimeInterval PlatformCAAnimation::timeOffset() const 251{ 252 return CACFAnimationGetTimeOffset(m_animation.get()); 253} 254 255void PlatformCAAnimation::setTimeOffset(CFTimeInterval value) 256{ 257 CACFAnimationSetTimeOffset(m_animation.get(), value); 258} 259 260float PlatformCAAnimation::repeatCount() const 261{ 262 return CACFAnimationGetRepeatCount(m_animation.get()); 263} 264 265void PlatformCAAnimation::setRepeatCount(float value) 266{ 267 CACFAnimationSetRepeatCount(m_animation.get(), value); 268} 269 270bool PlatformCAAnimation::autoreverses() const 271{ 272 return CACFAnimationGetAutoreverses(m_animation.get()); 273} 274 275void PlatformCAAnimation::setAutoreverses(bool value) 276{ 277 CACFAnimationSetAutoreverses(m_animation.get(), value); 278} 279 280PlatformCAAnimation::FillModeType PlatformCAAnimation::fillMode() const 281{ 282 return fromCACFFillModeType(CACFAnimationGetFillMode(m_animation.get())); 283} 284 285void PlatformCAAnimation::setFillMode(FillModeType value) 286{ 287 CACFAnimationSetFillMode(m_animation.get(), toCACFFillModeType(value)); 288} 289 290void PlatformCAAnimation::setTimingFunction(const TimingFunction* value) 291{ 292 CACFAnimationSetTimingFunction(m_animation.get(), toCACFTimingFunction(value).get()); 293} 294 295void PlatformCAAnimation::copyTimingFunctionFrom(const PlatformCAAnimation* value) 296{ 297 CACFAnimationSetTimingFunction(m_animation.get(), CACFAnimationGetTimingFunction(value->m_animation.get())); 298} 299 300bool PlatformCAAnimation::isRemovedOnCompletion() const 301{ 302 return CACFAnimationIsRemovedOnCompletion(m_animation.get()); 303} 304 305void PlatformCAAnimation::setRemovedOnCompletion(bool value) 306{ 307 CACFAnimationSetRemovedOnCompletion(m_animation.get(), value); 308} 309 310bool PlatformCAAnimation::isAdditive() const 311{ 312 return CACFAnimationIsAdditive(m_animation.get()); 313} 314 315void PlatformCAAnimation::setAdditive(bool value) 316{ 317 CACFAnimationSetAdditive(m_animation.get(), value); 318} 319 320PlatformCAAnimation::ValueFunctionType PlatformCAAnimation::valueFunction() const 321{ 322 return fromCACFValueFunctionType(CACFValueFunctionGetName(CACFAnimationGetValueFunction(m_animation.get()))); 323} 324 325void PlatformCAAnimation::setValueFunction(ValueFunctionType value) 326{ 327 CACFAnimationSetValueFunction(m_animation.get(), CACFValueFunctionGetFunctionWithName(toCACFValueFunctionType(value))); 328} 329 330void PlatformCAAnimation::setFromValue(float value) 331{ 332 if (animationType() != Basic) 333 return; 334 335 RetainPtr<CFNumberRef> v(AdoptCF, CFNumberCreate(0, kCFNumberFloatType, &value)); 336 CACFAnimationSetFromValue(m_animation.get(), v.get()); 337} 338 339void PlatformCAAnimation::setFromValue(const WebCore::TransformationMatrix& value) 340{ 341 if (animationType() != Basic) 342 return; 343 344 RetainPtr<CACFVectorRef> v(AdoptCF, CACFVectorCreateTransform(value)); 345 CACFAnimationSetFromValue(m_animation.get(), v.get()); 346} 347 348void PlatformCAAnimation::setFromValue(const FloatPoint3D& value) 349{ 350 if (animationType() != Basic) 351 return; 352 353 float a[3] = { value.x(), value.y(), value.z() }; 354 RetainPtr<CACFVectorRef> v(AdoptCF, CACFVectorCreate(3, a)); 355 CACFAnimationSetFromValue(m_animation.get(), v.get()); 356} 357 358void PlatformCAAnimation::setFromValue(const WebCore::Color& value) 359{ 360 if (animationType() != Basic) 361 return; 362 363 float a[4] = { value.red(), value.green(), value.blue(), value.alpha() }; 364 RetainPtr<CACFVectorRef> v(AdoptCF, CACFVectorCreate(4, a)); 365 CACFAnimationSetFromValue(m_animation.get(), v.get()); 366} 367 368void PlatformCAAnimation::copyFromValueFrom(const PlatformCAAnimation* value) 369{ 370 if (animationType() != Basic || value->animationType() != Basic) 371 return; 372 373 CACFAnimationSetFromValue(m_animation.get(), CACFAnimationGetFromValue(value->platformAnimation())); 374} 375 376void PlatformCAAnimation::setToValue(float value) 377{ 378 if (animationType() != Basic) 379 return; 380 381 RetainPtr<CFNumberRef> v(AdoptCF, CFNumberCreate(0, kCFNumberFloatType, &value)); 382 CACFAnimationSetToValue(m_animation.get(), v.get()); 383} 384 385void PlatformCAAnimation::setToValue(const WebCore::TransformationMatrix& value) 386{ 387 if (animationType() != Basic) 388 return; 389 390 RetainPtr<CACFVectorRef> v(AdoptCF, CACFVectorCreateTransform(value)); 391 CACFAnimationSetToValue(m_animation.get(), v.get()); 392} 393 394void PlatformCAAnimation::setToValue(const FloatPoint3D& value) 395{ 396 if (animationType() != Basic) 397 return; 398 399 float a[3] = { value.x(), value.y(), value.z() }; 400 RetainPtr<CACFVectorRef> v(AdoptCF, CACFVectorCreate(3, a)); 401 CACFAnimationSetToValue(m_animation.get(), v.get()); 402} 403 404void PlatformCAAnimation::setToValue(const WebCore::Color& value) 405{ 406 if (animationType() != Basic) 407 return; 408 409 float a[4] = { value.red(), value.green(), value.blue(), value.alpha() }; 410 RetainPtr<CACFVectorRef> v(AdoptCF, CACFVectorCreate(4, a)); 411 CACFAnimationSetToValue(m_animation.get(), v.get()); 412} 413 414void PlatformCAAnimation::copyToValueFrom(const PlatformCAAnimation* value) 415{ 416 if (animationType() != Basic || value->animationType() != Basic) 417 return; 418 419 CACFAnimationSetToValue(m_animation.get(), CACFAnimationGetToValue(value->platformAnimation())); 420} 421 422 423// Keyframe-animation properties. 424void PlatformCAAnimation::setValues(const Vector<float>& value) 425{ 426 if (animationType() != Keyframe) 427 return; 428 429 RetainPtr<CFMutableArrayRef> array(AdoptCF, CFArrayCreateMutable(0, value.size(), &kCFTypeArrayCallBacks)); 430 for (size_t i = 0; i < value.size(); ++i) { 431 RetainPtr<CFNumberRef> v(AdoptCF, CFNumberCreate(0, kCFNumberFloatType, &value[i])); 432 CFArrayAppendValue(array.get(), v.get()); 433 } 434 435 CACFAnimationSetValues(m_animation.get(), array.get()); 436} 437 438void PlatformCAAnimation::setValues(const Vector<WebCore::TransformationMatrix>& value) 439{ 440 if (animationType() != Keyframe) 441 return; 442 443 RetainPtr<CFMutableArrayRef> array(AdoptCF, CFArrayCreateMutable(0, value.size(), &kCFTypeArrayCallBacks)); 444 for (size_t i = 0; i < value.size(); ++i) { 445 RetainPtr<CACFVectorRef> v(AdoptCF, CACFVectorCreateTransform(value[i])); 446 CFArrayAppendValue(array.get(), v.get()); 447 } 448 449 CACFAnimationSetValues(m_animation.get(), array.get()); 450} 451 452void PlatformCAAnimation::setValues(const Vector<FloatPoint3D>& value) 453{ 454 if (animationType() != Keyframe) 455 return; 456 457 RetainPtr<CFMutableArrayRef> array(AdoptCF, CFArrayCreateMutable(0, value.size(), &kCFTypeArrayCallBacks)); 458 for (size_t i = 0; i < value.size(); ++i) { 459 float a[3] = { value[i].x(), value[i].y(), value[i].z() }; 460 RetainPtr<CACFVectorRef> v(AdoptCF, CACFVectorCreate(3, a)); 461 CFArrayAppendValue(array.get(), v.get()); 462 } 463 464 CACFAnimationSetValues(m_animation.get(), array.get()); 465} 466 467void PlatformCAAnimation::setValues(const Vector<WebCore::Color>& 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 float a[4] = { value[i].red(), value[i].green(), value[i].blue(), value[i].alpha() }; 475 RetainPtr<CACFVectorRef> v(AdoptCF, CACFVectorCreate(4, a)); 476 CFArrayAppendValue(array.get(), v.get()); 477 } 478 479 CACFAnimationSetValues(m_animation.get(), array.get()); 480} 481 482void PlatformCAAnimation::copyValuesFrom(const PlatformCAAnimation* value) 483{ 484 if (animationType() != Keyframe || value->animationType() != Keyframe) 485 return; 486 487 CACFAnimationSetValues(m_animation.get(), CACFAnimationGetValues(value->platformAnimation())); 488} 489 490void PlatformCAAnimation::setKeyTimes(const Vector<float>& value) 491{ 492 if (animationType() != Keyframe) 493 return; 494 495 RetainPtr<CFMutableArrayRef> array(AdoptCF, CFArrayCreateMutable(0, value.size(), &kCFTypeArrayCallBacks)); 496 for (size_t i = 0; i < value.size(); ++i) { 497 RetainPtr<CFNumberRef> v(AdoptCF, CFNumberCreate(0, kCFNumberFloatType, &value[i])); 498 CFArrayAppendValue(array.get(), v.get()); 499 } 500 501 CACFAnimationSetKeyTimes(m_animation.get(), array.get()); 502} 503 504void PlatformCAAnimation::copyKeyTimesFrom(const PlatformCAAnimation* value) 505{ 506 if (animationType() != Keyframe) 507 return; 508 509 CACFAnimationSetKeyTimes(m_animation.get(), CACFAnimationGetKeyTimes(value->platformAnimation())); 510} 511 512void PlatformCAAnimation::setTimingFunctions(const Vector<const TimingFunction*>& value) 513{ 514 if (animationType() != Keyframe) 515 return; 516 517 RetainPtr<CFMutableArrayRef> array(AdoptCF, CFArrayCreateMutable(0, value.size(), &kCFTypeArrayCallBacks)); 518 for (size_t i = 0; i < value.size(); ++i) { 519 RetainPtr<CFNumberRef> v(AdoptCF, CFNumberCreate(0, kCFNumberFloatType, &value[i])); 520 CFArrayAppendValue(array.get(), toCACFTimingFunction(value[i]).get()); 521 } 522 523 CACFAnimationSetTimingFunctions(m_animation.get(), array.get()); 524} 525 526void PlatformCAAnimation::copyTimingFunctionsFrom(const PlatformCAAnimation* value) 527{ 528 CACFAnimationSetTimingFunctions(m_animation.get(), CACFAnimationGetTimingFunctions(value->platformAnimation())); 529} 530 531#endif // USE(ACCELERATED_COMPOSITING) 532