Home | History | Annotate | Download | only in mac
      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