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 42 using namespace WebCore; 43 44 static 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 56 static 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 67 static 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 87 static 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 125 static 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 136 PassRefPtr<PlatformCAAnimation> PlatformCAAnimation::create(AnimationType type, const String& keyPath) 137 { 138 return adoptRef(new PlatformCAAnimation(type, keyPath)); 139 } 140 141 PassRefPtr<PlatformCAAnimation> PlatformCAAnimation::create(PlatformAnimationRef animation) 142 { 143 return adoptRef(new PlatformCAAnimation(animation)); 144 } 145 146 PlatformCAAnimation::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 158 PlatformCAAnimation::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 172 PassRefPtr<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 201 PlatformCAAnimation::~PlatformCAAnimation() 202 { 203 } 204 205 bool PlatformCAAnimation::supportsValueFunction() 206 { 207 return true; 208 } 209 210 PlatformAnimationRef PlatformCAAnimation::platformAnimation() const 211 { 212 return m_animation.get(); 213 } 214 215 String PlatformCAAnimation::keyPath() const 216 { 217 return CACFAnimationGetKeyPath(m_animation.get()); 218 } 219 220 CFTimeInterval PlatformCAAnimation::beginTime() const 221 { 222 return CACFAnimationGetBeginTime(m_animation.get()); 223 } 224 225 void PlatformCAAnimation::setBeginTime(CFTimeInterval value) 226 { 227 CACFAnimationSetBeginTime(m_animation.get(), value); 228 } 229 230 CFTimeInterval PlatformCAAnimation::duration() const 231 { 232 return CACFAnimationGetDuration(m_animation.get()); 233 } 234 235 void PlatformCAAnimation::setDuration(CFTimeInterval value) 236 { 237 CACFAnimationSetDuration(m_animation.get(), value); 238 } 239 240 float PlatformCAAnimation::speed() const 241 { 242 return CACFAnimationGetSpeed(m_animation.get()); 243 } 244 245 void PlatformCAAnimation::setSpeed(float value) 246 { 247 CACFAnimationSetSpeed(m_animation.get(), value); 248 } 249 250 CFTimeInterval PlatformCAAnimation::timeOffset() const 251 { 252 return CACFAnimationGetTimeOffset(m_animation.get()); 253 } 254 255 void PlatformCAAnimation::setTimeOffset(CFTimeInterval value) 256 { 257 CACFAnimationSetTimeOffset(m_animation.get(), value); 258 } 259 260 float PlatformCAAnimation::repeatCount() const 261 { 262 return CACFAnimationGetRepeatCount(m_animation.get()); 263 } 264 265 void PlatformCAAnimation::setRepeatCount(float value) 266 { 267 CACFAnimationSetRepeatCount(m_animation.get(), value); 268 } 269 270 bool PlatformCAAnimation::autoreverses() const 271 { 272 return CACFAnimationGetAutoreverses(m_animation.get()); 273 } 274 275 void PlatformCAAnimation::setAutoreverses(bool value) 276 { 277 CACFAnimationSetAutoreverses(m_animation.get(), value); 278 } 279 280 PlatformCAAnimation::FillModeType PlatformCAAnimation::fillMode() const 281 { 282 return fromCACFFillModeType(CACFAnimationGetFillMode(m_animation.get())); 283 } 284 285 void PlatformCAAnimation::setFillMode(FillModeType value) 286 { 287 CACFAnimationSetFillMode(m_animation.get(), toCACFFillModeType(value)); 288 } 289 290 void PlatformCAAnimation::setTimingFunction(const TimingFunction* value) 291 { 292 CACFAnimationSetTimingFunction(m_animation.get(), toCACFTimingFunction(value).get()); 293 } 294 295 void PlatformCAAnimation::copyTimingFunctionFrom(const PlatformCAAnimation* value) 296 { 297 CACFAnimationSetTimingFunction(m_animation.get(), CACFAnimationGetTimingFunction(value->m_animation.get())); 298 } 299 300 bool PlatformCAAnimation::isRemovedOnCompletion() const 301 { 302 return CACFAnimationIsRemovedOnCompletion(m_animation.get()); 303 } 304 305 void PlatformCAAnimation::setRemovedOnCompletion(bool value) 306 { 307 CACFAnimationSetRemovedOnCompletion(m_animation.get(), value); 308 } 309 310 bool PlatformCAAnimation::isAdditive() const 311 { 312 return CACFAnimationIsAdditive(m_animation.get()); 313 } 314 315 void PlatformCAAnimation::setAdditive(bool value) 316 { 317 CACFAnimationSetAdditive(m_animation.get(), value); 318 } 319 320 PlatformCAAnimation::ValueFunctionType PlatformCAAnimation::valueFunction() const 321 { 322 return fromCACFValueFunctionType(CACFValueFunctionGetName(CACFAnimationGetValueFunction(m_animation.get()))); 323 } 324 325 void PlatformCAAnimation::setValueFunction(ValueFunctionType value) 326 { 327 CACFAnimationSetValueFunction(m_animation.get(), CACFValueFunctionGetFunctionWithName(toCACFValueFunctionType(value))); 328 } 329 330 void 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 339 void 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 348 void 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 358 void 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 368 void 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 376 void 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 385 void 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 394 void 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 404 void 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 414 void 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. 424 void 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 438 void 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 452 void 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 467 void 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 482 void 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 490 void 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 504 void PlatformCAAnimation::copyKeyTimesFrom(const PlatformCAAnimation* value) 505 { 506 if (animationType() != Keyframe) 507 return; 508 509 CACFAnimationSetKeyTimes(m_animation.get(), CACFAnimationGetKeyTimes(value->platformAnimation())); 510 } 511 512 void 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 526 void PlatformCAAnimation::copyTimingFunctionsFrom(const PlatformCAAnimation* value) 527 { 528 CACFAnimationSetTimingFunctions(m_animation.get(), CACFAnimationGetTimingFunctions(value->platformAnimation())); 529 } 530 531 #endif // USE(ACCELERATED_COMPOSITING) 532