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 40using namespace WebCore; 41 42// This value must be the same as in PlatformCALayerMac.mm 43static NSString * const WKNonZeroBeginTimeFlag = @"WKPlatformCAAnimationNonZeroBeginTimeFlag"; 44 45static bool hasNonZeroBeginTimeFlag(const PlatformCAAnimation* animation) 46{ 47 return [[animation->platformAnimation() valueForKey:WKNonZeroBeginTimeFlag] boolValue]; 48} 49 50static void setNonZeroBeginTimeFlag(PlatformCAAnimation* animation, bool value) 51{ 52 [animation->platformAnimation() setValue:[NSNumber numberWithBool:value] forKey:WKNonZeroBeginTimeFlag]; 53} 54 55static 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 66static 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 78static 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 97static 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 136static 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 148PassRefPtr<PlatformCAAnimation> PlatformCAAnimation::create(AnimationType type, const String& keyPath) 149{ 150 return adoptRef(new PlatformCAAnimation(type, keyPath)); 151} 152 153PassRefPtr<PlatformCAAnimation> PlatformCAAnimation::create(PlatformAnimationRef animation) 154{ 155 return adoptRef(new PlatformCAAnimation(animation)); 156} 157 158PlatformCAAnimation::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 167PlatformCAAnimation::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 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 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} 211PlatformCAAnimation::~PlatformCAAnimation() 212{ 213} 214 215bool PlatformCAAnimation::supportsValueFunction() 216{ 217 static bool sHaveValueFunction = [CAPropertyAnimation instancesRespondToSelector:@selector(setValueFunction:)]; 218 return sHaveValueFunction; 219} 220 221PlatformAnimationRef PlatformCAAnimation::platformAnimation() const 222{ 223 return m_animation.get(); 224} 225 226String PlatformCAAnimation::keyPath() const 227{ 228 return [m_animation.get() keyPath]; 229} 230 231CFTimeInterval PlatformCAAnimation::beginTime() const 232{ 233 return [m_animation.get() beginTime]; 234} 235 236void 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 248CFTimeInterval PlatformCAAnimation::duration() const 249{ 250 return [m_animation.get() duration]; 251} 252 253void PlatformCAAnimation::setDuration(CFTimeInterval value) 254{ 255 [m_animation.get() setDuration:value]; 256} 257 258float PlatformCAAnimation::speed() const 259{ 260 return [m_animation.get() speed]; 261} 262 263void PlatformCAAnimation::setSpeed(float value) 264{ 265 [m_animation.get() setSpeed:value]; 266} 267 268CFTimeInterval PlatformCAAnimation::timeOffset() const 269{ 270 return [m_animation.get() timeOffset]; 271} 272 273void PlatformCAAnimation::setTimeOffset(CFTimeInterval value) 274{ 275 [m_animation.get() setTimeOffset:value]; 276} 277 278float PlatformCAAnimation::repeatCount() const 279{ 280 return [m_animation.get() repeatCount]; 281} 282 283void PlatformCAAnimation::setRepeatCount(float value) 284{ 285 [m_animation.get() setRepeatCount:value]; 286} 287 288bool PlatformCAAnimation::autoreverses() const 289{ 290 return [m_animation.get() autoreverses]; 291} 292 293void PlatformCAAnimation::setAutoreverses(bool value) 294{ 295 [m_animation.get() setAutoreverses:value]; 296} 297 298PlatformCAAnimation::FillModeType PlatformCAAnimation::fillMode() const 299{ 300 return fromCAFillModeType([m_animation.get() fillMode]); 301} 302 303void PlatformCAAnimation::setFillMode(FillModeType value) 304{ 305 [m_animation.get() setFillMode:toCAFillModeType(value)]; 306} 307 308void PlatformCAAnimation::setTimingFunction(const TimingFunction* value) 309{ 310 [m_animation.get() setTimingFunction:toCAMediaTimingFunction(value)]; 311} 312 313void PlatformCAAnimation::copyTimingFunctionFrom(const PlatformCAAnimation* value) 314{ 315 [m_animation.get() setTimingFunction:[value->m_animation.get() timingFunction]]; 316} 317 318bool PlatformCAAnimation::isRemovedOnCompletion() const 319{ 320 return [m_animation.get() isRemovedOnCompletion]; 321} 322 323void PlatformCAAnimation::setRemovedOnCompletion(bool value) 324{ 325 [m_animation.get() setRemovedOnCompletion:value]; 326} 327 328bool PlatformCAAnimation::isAdditive() const 329{ 330 return [m_animation.get() isAdditive]; 331} 332 333void PlatformCAAnimation::setAdditive(bool value) 334{ 335 [m_animation.get() setAdditive:value]; 336} 337 338PlatformCAAnimation::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 348void 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 357void PlatformCAAnimation::setFromValue(float value) 358{ 359 if (animationType() != Basic) 360 return; 361 [static_cast<CABasicAnimation*>(m_animation.get()) setFromValue:[NSNumber numberWithDouble:value]]; 362} 363 364void 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 372void 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 385void 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 399void 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 408void PlatformCAAnimation::setToValue(float value) 409{ 410 if (animationType() != Basic) 411 return; 412 [static_cast<CABasicAnimation*>(m_animation.get()) setToValue:[NSNumber numberWithDouble:value]]; 413} 414 415void 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 423void 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 436void 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 450void 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. 461void 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 472void 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 485void 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 503void 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 522void 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 531void 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 541void 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 547void 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 557void 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