1 /* 2 * Copyright (C) 2010 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 #import "PlatformCAAnimation.h" 31 32 #import "FloatConversion.h" 33 #import "PlatformString.h" 34 #import "TimingFunction.h" 35 #import <QuartzCore/QuartzCore.h> 36 #import <wtf/UnusedParam.h> 37 38 #define HAVE_MODERN_QUARTZCORE (!defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)) 39 40 using namespace WebCore; 41 42 // This value must be the same as in PlatformCALayerMac.mm 43 static NSString * const WKNonZeroBeginTimeFlag = @"WKPlatformCAAnimationNonZeroBeginTimeFlag"; 44 45 static bool hasNonZeroBeginTimeFlag(const PlatformCAAnimation* animation) 46 { 47 return [[animation->platformAnimation() valueForKey:WKNonZeroBeginTimeFlag] boolValue]; 48 } 49 50 static void setNonZeroBeginTimeFlag(PlatformCAAnimation* animation, bool value) 51 { 52 [animation->platformAnimation() setValue:[NSNumber numberWithBool:value] forKey:WKNonZeroBeginTimeFlag]; 53 } 54 55 static NSString* toCAFillModeType(PlatformCAAnimation::FillModeType type) 56 { 57 switch (type) { 58 case PlatformCAAnimation::NoFillMode: 59 case PlatformCAAnimation::Forwards: return kCAFillModeForwards; 60 case PlatformCAAnimation::Backwards: return kCAFillModeBackwards; 61 case PlatformCAAnimation::Both: return kCAFillModeBoth; 62 } 63 return @""; 64 } 65 66 static PlatformCAAnimation::FillModeType fromCAFillModeType(NSString* string) 67 { 68 if ([string isEqualToString:kCAFillModeBackwards]) 69 return PlatformCAAnimation::Backwards; 70 71 if ([string isEqualToString:kCAFillModeBoth]) 72 return PlatformCAAnimation::Both; 73 74 return PlatformCAAnimation::Forwards; 75 } 76 77 #if HAVE_MODERN_QUARTZCORE 78 static NSString* toCAValueFunctionType(PlatformCAAnimation::ValueFunctionType type) 79 { 80 switch (type) { 81 case PlatformCAAnimation::NoValueFunction: return @""; 82 case PlatformCAAnimation::RotateX: return kCAValueFunctionRotateX; 83 case PlatformCAAnimation::RotateY: return kCAValueFunctionRotateY; 84 case PlatformCAAnimation::RotateZ: return kCAValueFunctionRotateZ; 85 case PlatformCAAnimation::ScaleX: return kCAValueFunctionScaleX; 86 case PlatformCAAnimation::ScaleY: return kCAValueFunctionScaleY; 87 case PlatformCAAnimation::ScaleZ: return kCAValueFunctionScaleZ; 88 case PlatformCAAnimation::Scale: return kCAValueFunctionScale; 89 case PlatformCAAnimation::TranslateX: return kCAValueFunctionTranslateX; 90 case PlatformCAAnimation::TranslateY: return kCAValueFunctionTranslateY; 91 case PlatformCAAnimation::TranslateZ: return kCAValueFunctionTranslateZ; 92 case PlatformCAAnimation::Translate: return kCAValueFunctionTranslate; 93 } 94 return @""; 95 } 96 97 static PlatformCAAnimation::ValueFunctionType fromCAValueFunctionType(NSString* string) 98 { 99 if ([string isEqualToString:kCAValueFunctionRotateX]) 100 return PlatformCAAnimation::RotateX; 101 102 if ([string isEqualToString:kCAValueFunctionRotateY]) 103 return PlatformCAAnimation::RotateY; 104 105 if ([string isEqualToString:kCAValueFunctionRotateZ]) 106 return PlatformCAAnimation::RotateZ; 107 108 if ([string isEqualToString:kCAValueFunctionScaleX]) 109 return PlatformCAAnimation::ScaleX; 110 111 if ([string isEqualToString:kCAValueFunctionScaleY]) 112 return PlatformCAAnimation::ScaleY; 113 114 if ([string isEqualToString:kCAValueFunctionScaleZ]) 115 return PlatformCAAnimation::ScaleZ; 116 117 if ([string isEqualToString:kCAValueFunctionScale]) 118 return PlatformCAAnimation::Scale; 119 120 if ([string isEqualToString:kCAValueFunctionTranslateX]) 121 return PlatformCAAnimation::TranslateX; 122 123 if ([string isEqualToString:kCAValueFunctionTranslateY]) 124 return PlatformCAAnimation::TranslateY; 125 126 if ([string isEqualToString:kCAValueFunctionTranslateZ]) 127 return PlatformCAAnimation::TranslateZ; 128 129 if ([string isEqualToString:kCAValueFunctionTranslate]) 130 return PlatformCAAnimation::Translate; 131 132 return PlatformCAAnimation::NoValueFunction; 133 } 134 #endif 135 136 static CAMediaTimingFunction* toCAMediaTimingFunction(const TimingFunction* timingFunction) 137 { 138 ASSERT(timingFunction); 139 if (timingFunction->isCubicBezierTimingFunction()) { 140 const CubicBezierTimingFunction* ctf = static_cast<const CubicBezierTimingFunction*>(timingFunction); 141 return [CAMediaTimingFunction functionWithControlPoints:static_cast<float>(ctf->x1()) :static_cast<float>(ctf->y1()) 142 :static_cast<float>(ctf->x2()) :static_cast<float>(ctf->y2())]; 143 } 144 145 return [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear]; 146 } 147 148 PassRefPtr<PlatformCAAnimation> PlatformCAAnimation::create(AnimationType type, const String& keyPath) 149 { 150 return adoptRef(new PlatformCAAnimation(type, keyPath)); 151 } 152 153 PassRefPtr<PlatformCAAnimation> PlatformCAAnimation::create(PlatformAnimationRef animation) 154 { 155 return adoptRef(new PlatformCAAnimation(animation)); 156 } 157 158 PlatformCAAnimation::PlatformCAAnimation(AnimationType type, const String& keyPath) 159 : m_type(type) 160 { 161 if (type == Basic) 162 m_animation.adoptNS([[CABasicAnimation animationWithKeyPath:keyPath] retain]); 163 else 164 m_animation.adoptNS([[CAKeyframeAnimation animationWithKeyPath:keyPath] retain]); 165 } 166 167 PlatformCAAnimation::PlatformCAAnimation(PlatformAnimationRef animation) 168 { 169 if ([static_cast<CAAnimation*>(animation) isKindOfClass:[CABasicAnimation class]]) 170 m_type = Basic; 171 else if ([static_cast<CAAnimation*>(animation) isKindOfClass:[CAKeyframeAnimation class]]) 172 m_type = Keyframe; 173 else { 174 ASSERT(0); 175 return; 176 } 177 178 m_animation = static_cast<CAPropertyAnimation*>(animation); 179 } 180 181 PassRefPtr<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 animation->setValueFunction(valueFunction()); 196 197 setNonZeroBeginTimeFlag(animation.get(), hasNonZeroBeginTimeFlag(this)); 198 199 // Copy the specific Basic or Keyframe values 200 if (animationType() == Keyframe) { 201 animation->copyValuesFrom(this); 202 animation->copyKeyTimesFrom(this); 203 animation->copyTimingFunctionsFrom(this); 204 } else { 205 animation->copyFromValueFrom(this); 206 animation->copyToValueFrom(this); 207 } 208 209 return animation; 210 } 211 PlatformCAAnimation::~PlatformCAAnimation() 212 { 213 } 214 215 bool PlatformCAAnimation::supportsValueFunction() 216 { 217 static bool sHaveValueFunction = [CAPropertyAnimation instancesRespondToSelector:@selector(setValueFunction:)]; 218 return sHaveValueFunction; 219 } 220 221 PlatformAnimationRef PlatformCAAnimation::platformAnimation() const 222 { 223 return m_animation.get(); 224 } 225 226 String PlatformCAAnimation::keyPath() const 227 { 228 return [m_animation.get() keyPath]; 229 } 230 231 CFTimeInterval PlatformCAAnimation::beginTime() const 232 { 233 return [m_animation.get() beginTime]; 234 } 235 236 void PlatformCAAnimation::setBeginTime(CFTimeInterval value) 237 { 238 [m_animation.get() setBeginTime:value]; 239 240 // Also set a flag to tell us if we've passed in a 0 value. 241 // The flag is needed because later beginTime will get changed 242 // to the time at which it fired and we need to know whether 243 // or not it was 0 to begin with. 244 if (value) 245 setNonZeroBeginTimeFlag(this, true); 246 } 247 248 CFTimeInterval PlatformCAAnimation::duration() const 249 { 250 return [m_animation.get() duration]; 251 } 252 253 void PlatformCAAnimation::setDuration(CFTimeInterval value) 254 { 255 [m_animation.get() setDuration:value]; 256 } 257 258 float PlatformCAAnimation::speed() const 259 { 260 return [m_animation.get() speed]; 261 } 262 263 void PlatformCAAnimation::setSpeed(float value) 264 { 265 [m_animation.get() setSpeed:value]; 266 } 267 268 CFTimeInterval PlatformCAAnimation::timeOffset() const 269 { 270 return [m_animation.get() timeOffset]; 271 } 272 273 void PlatformCAAnimation::setTimeOffset(CFTimeInterval value) 274 { 275 [m_animation.get() setTimeOffset:value]; 276 } 277 278 float PlatformCAAnimation::repeatCount() const 279 { 280 return [m_animation.get() repeatCount]; 281 } 282 283 void PlatformCAAnimation::setRepeatCount(float value) 284 { 285 [m_animation.get() setRepeatCount:value]; 286 } 287 288 bool PlatformCAAnimation::autoreverses() const 289 { 290 return [m_animation.get() autoreverses]; 291 } 292 293 void PlatformCAAnimation::setAutoreverses(bool value) 294 { 295 [m_animation.get() setAutoreverses:value]; 296 } 297 298 PlatformCAAnimation::FillModeType PlatformCAAnimation::fillMode() const 299 { 300 return fromCAFillModeType([m_animation.get() fillMode]); 301 } 302 303 void PlatformCAAnimation::setFillMode(FillModeType value) 304 { 305 [m_animation.get() setFillMode:toCAFillModeType(value)]; 306 } 307 308 void PlatformCAAnimation::setTimingFunction(const TimingFunction* value) 309 { 310 [m_animation.get() setTimingFunction:toCAMediaTimingFunction(value)]; 311 } 312 313 void PlatformCAAnimation::copyTimingFunctionFrom(const PlatformCAAnimation* value) 314 { 315 [m_animation.get() setTimingFunction:[value->m_animation.get() timingFunction]]; 316 } 317 318 bool PlatformCAAnimation::isRemovedOnCompletion() const 319 { 320 return [m_animation.get() isRemovedOnCompletion]; 321 } 322 323 void PlatformCAAnimation::setRemovedOnCompletion(bool value) 324 { 325 [m_animation.get() setRemovedOnCompletion:value]; 326 } 327 328 bool PlatformCAAnimation::isAdditive() const 329 { 330 return [m_animation.get() isAdditive]; 331 } 332 333 void PlatformCAAnimation::setAdditive(bool value) 334 { 335 [m_animation.get() setAdditive:value]; 336 } 337 338 PlatformCAAnimation::ValueFunctionType PlatformCAAnimation::valueFunction() const 339 { 340 #if HAVE_MODERN_QUARTZCORE 341 CAValueFunction* vf = [m_animation.get() valueFunction]; 342 return fromCAValueFunctionType([vf name]); 343 #else 344 return NoValueFunction; 345 #endif 346 } 347 348 void PlatformCAAnimation::setValueFunction(ValueFunctionType value) 349 { 350 #if HAVE_MODERN_QUARTZCORE 351 [m_animation.get() setValueFunction:[CAValueFunction functionWithName:toCAValueFunctionType(value)]]; 352 #else 353 UNUSED_PARAM(value); 354 #endif 355 } 356 357 void PlatformCAAnimation::setFromValue(float value) 358 { 359 if (animationType() != Basic) 360 return; 361 [static_cast<CABasicAnimation*>(m_animation.get()) setFromValue:[NSNumber numberWithDouble:value]]; 362 } 363 364 void PlatformCAAnimation::setFromValue(const WebCore::TransformationMatrix& value) 365 { 366 if (animationType() != Basic) 367 return; 368 369 [static_cast<CABasicAnimation*>(m_animation.get()) setFromValue:[NSValue valueWithCATransform3D:value]]; 370 } 371 372 void PlatformCAAnimation::setFromValue(const FloatPoint3D& value) 373 { 374 if (animationType() != Basic) 375 return; 376 377 NSArray* array = [NSArray arrayWithObjects: 378 [NSNumber numberWithDouble:value.x()], 379 [NSNumber numberWithDouble:value.y()], 380 [NSNumber numberWithDouble:value.z()], 381 nil]; 382 [static_cast<CABasicAnimation*>(m_animation.get()) setFromValue:array]; 383 } 384 385 void PlatformCAAnimation::setFromValue(const WebCore::Color& value) 386 { 387 if (animationType() != Basic) 388 return; 389 390 NSArray* array = [NSArray arrayWithObjects: 391 [NSNumber numberWithDouble:value.red()], 392 [NSNumber numberWithDouble:value.green()], 393 [NSNumber numberWithDouble:value.blue()], 394 [NSNumber numberWithDouble:value.alpha()], 395 nil]; 396 [static_cast<CABasicAnimation*>(m_animation.get()) setFromValue:array]; 397 } 398 399 void PlatformCAAnimation::copyFromValueFrom(const PlatformCAAnimation* value) 400 { 401 if (animationType() != Basic || value->animationType() != Basic) 402 return; 403 404 CABasicAnimation* otherAnimation = static_cast<CABasicAnimation*>(value->m_animation.get()); 405 [static_cast<CABasicAnimation*>(m_animation.get()) setFromValue:[otherAnimation fromValue]]; 406 } 407 408 void PlatformCAAnimation::setToValue(float value) 409 { 410 if (animationType() != Basic) 411 return; 412 [static_cast<CABasicAnimation*>(m_animation.get()) setToValue:[NSNumber numberWithDouble:value]]; 413 } 414 415 void PlatformCAAnimation::setToValue(const WebCore::TransformationMatrix& value) 416 { 417 if (animationType() != Basic) 418 return; 419 420 [static_cast<CABasicAnimation*>(m_animation.get()) setToValue:[NSValue valueWithCATransform3D:value]]; 421 } 422 423 void PlatformCAAnimation::setToValue(const FloatPoint3D& value) 424 { 425 if (animationType() != Basic) 426 return; 427 428 NSArray* array = [NSArray arrayWithObjects: 429 [NSNumber numberWithDouble:value.x()], 430 [NSNumber numberWithDouble:value.y()], 431 [NSNumber numberWithDouble:value.z()], 432 nil]; 433 [static_cast<CABasicAnimation*>(m_animation.get()) setToValue:array]; 434 } 435 436 void PlatformCAAnimation::setToValue(const WebCore::Color& value) 437 { 438 if (animationType() != Basic) 439 return; 440 441 NSArray* array = [NSArray arrayWithObjects: 442 [NSNumber numberWithDouble:value.red()], 443 [NSNumber numberWithDouble:value.green()], 444 [NSNumber numberWithDouble:value.blue()], 445 [NSNumber numberWithDouble:value.alpha()], 446 nil]; 447 [static_cast<CABasicAnimation*>(m_animation.get()) setToValue:array]; 448 } 449 450 void PlatformCAAnimation::copyToValueFrom(const PlatformCAAnimation* value) 451 { 452 if (animationType() != Basic || value->animationType() != Basic) 453 return; 454 455 CABasicAnimation* otherAnimation = static_cast<CABasicAnimation*>(value->m_animation.get()); 456 [static_cast<CABasicAnimation*>(m_animation.get()) setToValue:[otherAnimation toValue]]; 457 } 458 459 460 // Keyframe-animation properties. 461 void PlatformCAAnimation::setValues(const Vector<float>& value) 462 { 463 if (animationType() != Keyframe) 464 return; 465 466 NSMutableArray* array = [NSMutableArray array]; 467 for (size_t i = 0; i < value.size(); ++i) 468 [array addObject:[NSNumber numberWithDouble:value[i]]]; 469 [static_cast<CAKeyframeAnimation*>(m_animation.get()) setValues:array]; 470 } 471 472 void PlatformCAAnimation::setValues(const Vector<WebCore::TransformationMatrix>& value) 473 { 474 if (animationType() != Keyframe) 475 return; 476 477 NSMutableArray* array = [NSMutableArray array]; 478 479 for (size_t i = 0; i < value.size(); ++i) 480 [array addObject:[NSValue valueWithCATransform3D:value[i]]]; 481 482 [static_cast<CAKeyframeAnimation*>(m_animation.get()) setValues:array]; 483 } 484 485 void PlatformCAAnimation::setValues(const Vector<FloatPoint3D>& value) 486 { 487 if (animationType() != Keyframe) 488 return; 489 490 NSMutableArray* array = [NSMutableArray array]; 491 492 for (size_t i = 0; i < value.size(); ++i) { 493 NSArray* object = [NSArray arrayWithObjects: 494 [NSNumber numberWithDouble:value[i].x()], 495 [NSNumber numberWithDouble:value[i].y()], 496 [NSNumber numberWithDouble:value[i].z()], 497 nil]; 498 [array addObject:object]; 499 } 500 [static_cast<CAKeyframeAnimation*>(m_animation.get()) setValues:array]; 501 } 502 503 void PlatformCAAnimation::setValues(const Vector<WebCore::Color>& value) 504 { 505 if (animationType() != Keyframe) 506 return; 507 508 NSMutableArray* array = [NSMutableArray array]; 509 510 for (size_t i = 0; i < value.size(); ++i) { 511 NSArray* object = [NSArray arrayWithObjects: 512 [NSNumber numberWithDouble:value[i].red()], 513 [NSNumber numberWithDouble:value[i].green()], 514 [NSNumber numberWithDouble:value[i].blue()], 515 [NSNumber numberWithDouble:value[i].alpha()], 516 nil]; 517 [array addObject:object]; 518 } 519 [static_cast<CAKeyframeAnimation*>(m_animation.get()) setValues:array]; 520 } 521 522 void PlatformCAAnimation::copyValuesFrom(const PlatformCAAnimation* value) 523 { 524 if (animationType() != Keyframe || value->animationType() != Keyframe) 525 return; 526 527 CAKeyframeAnimation* otherAnimation = static_cast<CAKeyframeAnimation*>(value->m_animation.get()); 528 [static_cast<CAKeyframeAnimation*>(m_animation.get()) setValues:[otherAnimation values]]; 529 } 530 531 void PlatformCAAnimation::setKeyTimes(const Vector<float>& value) 532 { 533 NSMutableArray* array = [NSMutableArray array]; 534 535 for (size_t i = 0; i < value.size(); ++i) 536 [array addObject:[NSNumber numberWithFloat:value[i]]]; 537 538 [static_cast<CAKeyframeAnimation*>(m_animation.get()) setKeyTimes:array]; 539 } 540 541 void PlatformCAAnimation::copyKeyTimesFrom(const PlatformCAAnimation* value) 542 { 543 CAKeyframeAnimation* other = static_cast<CAKeyframeAnimation*>(value->m_animation.get()); 544 [static_cast<CAKeyframeAnimation*>(m_animation.get()) setKeyTimes:[other keyTimes]]; 545 } 546 547 void PlatformCAAnimation::setTimingFunctions(const Vector<const TimingFunction*>& value) 548 { 549 NSMutableArray* array = [NSMutableArray array]; 550 551 for (size_t i = 0; i < value.size(); ++i) 552 [array addObject:toCAMediaTimingFunction(value[i])]; 553 554 [static_cast<CAKeyframeAnimation*>(m_animation.get()) setTimingFunctions:array]; 555 } 556 557 void PlatformCAAnimation::copyTimingFunctionsFrom(const PlatformCAAnimation* value) 558 { 559 CAKeyframeAnimation* other = static_cast<CAKeyframeAnimation*>(value->m_animation.get()); 560 [static_cast<CAKeyframeAnimation*>(m_animation.get()) setTimingFunctions:[other timingFunctions]]; 561 } 562 563 #endif // USE(ACCELERATED_COMPOSITING) 564