blob: 1def0940b1d2df47daa6656d1b26ebfdb87f488e [file] [log] [blame]
/*
* Copyright (C) 2014 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "config.h"
#import "PlatformCAAnimationRemote.h"
#import "ArgumentCoders.h"
#import "RemoteLayerTreeHost.h"
#import "WKAnimationDelegate.h"
#import "WebCoreArgumentCoders.h"
#import <QuartzCore/QuartzCore.h>
#import <WebCore/GraphicsLayer.h>
#import <WebCore/PlatformCAAnimationCocoa.h>
#import <WebCore/PlatformCAFilters.h>
#import <WebCore/TimingFunction.h>
#import <pal/spi/cocoa/QuartzCoreSPI.h>
#import <wtf/BlockObjCExceptions.h>
#import <wtf/RetainPtr.h>
#import <wtf/text/TextStream.h>
static MonotonicTime mediaTimeToCurrentTime(CFTimeInterval t)
{
return WTF::MonotonicTime::now() + Seconds(t - CACurrentMediaTime());
}
static NSString * const WKExplicitBeginTimeFlag = @"WKPlatformCAAnimationExplicitBeginTimeFlag";
@interface WKAnimationDelegate () <CAAnimationDelegate>
@end
@implementation WKAnimationDelegate
- (instancetype)initWithLayerID:(WebCore::GraphicsLayer::PlatformLayerID)layerID layerTreeHost:(WebKit::RemoteLayerTreeHost*)layerTreeHost
{
if ((self = [super init])) {
_layerID = layerID;
_layerTreeHost = layerTreeHost;
}
return self;
}
- (void)invalidate
{
_layerTreeHost = nullptr;
}
- (void)animationDidStart:(CAAnimation *)animation
{
if (!_layerTreeHost)
return;
bool hasExplicitBeginTime = [[animation valueForKey:WKExplicitBeginTimeFlag] boolValue];
MonotonicTime startTime;
if (hasExplicitBeginTime) {
// We don't know what time CA used to commit the animation, so just use the current time
// (even though this will be slightly off).
startTime = mediaTimeToCurrentTime(CACurrentMediaTime());
} else
startTime = mediaTimeToCurrentTime([animation beginTime]);
_layerTreeHost->animationDidStart(_layerID, animation, startTime);
}
- (void)animationDidStop:(CAAnimation *)animation finished:(BOOL)finished
{
if (!_layerTreeHost)
return;
_layerTreeHost->animationDidEnd(_layerID, animation);
}
@end
namespace WebKit {
using namespace WebCore;
void PlatformCAAnimationRemote::KeyframeValue::encode(IPC::Encoder& encoder) const
{
encoder.encodeEnum(keyType);
switch (keyType) {
case NumberKeyType:
encoder << number;
break;
case ColorKeyType:
encoder << color;
break;
case PointKeyType:
encoder << point;
break;
case TransformKeyType:
encoder << transform;
break;
case FilterKeyType:
encoder << *filter.get();
break;
}
}
Optional<PlatformCAAnimationRemote::KeyframeValue> PlatformCAAnimationRemote::KeyframeValue::decode(IPC::Decoder& decoder)
{
PlatformCAAnimationRemote::KeyframeValue value;
if (!decoder.decodeEnum(value.keyType))
return WTF::nullopt;
switch (value.keyType) {
case NumberKeyType:
if (!decoder.decode(value.number))
return WTF::nullopt;
break;
case ColorKeyType:
if (!decoder.decode(value.color))
return WTF::nullopt;
break;
case PointKeyType:
if (!decoder.decode(value.point))
return WTF::nullopt;
break;
case TransformKeyType:
if (!decoder.decode(value.transform))
return WTF::nullopt;
break;
case FilterKeyType:
if (!decodeFilterOperation(decoder, value.filter))
return WTF::nullopt;
break;
}
return WTFMove(value);
}
void PlatformCAAnimationRemote::Properties::encode(IPC::Encoder& encoder) const
{
encoder << keyPath;
encoder.encodeEnum(animationType);
encoder << beginTime;
encoder << duration;
encoder << timeOffset;
encoder << repeatCount;
encoder << speed;
encoder.encodeEnum(fillMode);
encoder.encodeEnum(valueFunction);
encoder << autoReverses;
encoder << removedOnCompletion;
encoder << additive;
encoder << reverseTimingFunctions;
encoder << hasExplicitBeginTime;
encoder << keyValues;
encoder << keyTimes;
encoder << static_cast<uint64_t>(timingFunctions.size());
for (const auto& timingFunction : timingFunctions) {
switch (timingFunction->type()) {
case TimingFunction::LinearFunction:
encoder << *static_cast<LinearTimingFunction*>(timingFunction.get());
break;
case TimingFunction::CubicBezierFunction:
encoder << *static_cast<CubicBezierTimingFunction*>(timingFunction.get());
break;
case TimingFunction::StepsFunction:
encoder << *static_cast<StepsTimingFunction*>(timingFunction.get());
break;
case TimingFunction::SpringFunction:
encoder << *static_cast<SpringTimingFunction*>(timingFunction.get());
break;
}
}
}
Optional<PlatformCAAnimationRemote::Properties> PlatformCAAnimationRemote::Properties::decode(IPC::Decoder& decoder)
{
PlatformCAAnimationRemote::Properties properties;
if (!decoder.decode(properties.keyPath))
return WTF::nullopt;
if (!decoder.decodeEnum(properties.animationType))
return WTF::nullopt;
if (!decoder.decode(properties.beginTime))
return WTF::nullopt;
if (!decoder.decode(properties.duration))
return WTF::nullopt;
if (!decoder.decode(properties.timeOffset))
return WTF::nullopt;
if (!decoder.decode(properties.repeatCount))
return WTF::nullopt;
if (!decoder.decode(properties.speed))
return WTF::nullopt;
if (!decoder.decodeEnum(properties.fillMode))
return WTF::nullopt;
if (!decoder.decodeEnum(properties.valueFunction))
return WTF::nullopt;
if (!decoder.decode(properties.autoReverses))
return WTF::nullopt;
if (!decoder.decode(properties.removedOnCompletion))
return WTF::nullopt;
if (!decoder.decode(properties.additive))
return WTF::nullopt;
if (!decoder.decode(properties.reverseTimingFunctions))
return WTF::nullopt;
if (!decoder.decode(properties.hasExplicitBeginTime))
return WTF::nullopt;
if (!decoder.decode(properties.keyValues))
return WTF::nullopt;
if (!decoder.decode(properties.keyTimes))
return WTF::nullopt;
uint64_t numTimingFunctions;
if (!decoder.decode(numTimingFunctions))
return WTF::nullopt;
if (numTimingFunctions) {
properties.timingFunctions.reserveInitialCapacity(numTimingFunctions);
for (size_t i = 0; i < numTimingFunctions; ++i) {
TimingFunction::TimingFunctionType type;
if (!decoder.decodeEnum(type))
return WTF::nullopt;
RefPtr<TimingFunction> timingFunction;
switch (type) {
case TimingFunction::LinearFunction:
timingFunction = LinearTimingFunction::create();
if (!decoder.decode(*static_cast<LinearTimingFunction*>(timingFunction.get())))
return WTF::nullopt;
break;
case TimingFunction::CubicBezierFunction:
timingFunction = CubicBezierTimingFunction::create();
if (!decoder.decode(*static_cast<CubicBezierTimingFunction*>(timingFunction.get())))
return WTF::nullopt;
break;
case TimingFunction::StepsFunction:
timingFunction = StepsTimingFunction::create();
if (!decoder.decode(*static_cast<StepsTimingFunction*>(timingFunction.get())))
return WTF::nullopt;
break;
case TimingFunction::SpringFunction:
timingFunction = SpringTimingFunction::create();
if (!decoder.decode(*static_cast<SpringTimingFunction*>(timingFunction.get())))
return WTF::nullopt;
break;
}
properties.timingFunctions.uncheckedAppend(WTFMove(timingFunction));
}
}
return WTFMove(properties);
}
Ref<PlatformCAAnimation> PlatformCAAnimationRemote::create(PlatformCAAnimation::AnimationType type, const String& keyPath)
{
return adoptRef(*new PlatformCAAnimationRemote(type, keyPath));
}
Ref<PlatformCAAnimation> PlatformCAAnimationRemote::copy() const
{
auto animation = create(animationType(), keyPath());
animation->setBeginTime(beginTime());
animation->setDuration(duration());
animation->setSpeed(speed());
animation->setTimeOffset(timeOffset());
animation->setRepeatCount(repeatCount());
animation->setAutoreverses(autoreverses());
animation->setFillMode(fillMode());
animation->setRemovedOnCompletion(isRemovedOnCompletion());
animation->setAdditive(isAdditive());
animation->copyTimingFunctionFrom(*this);
animation->setValueFunction(valueFunction());
downcast<PlatformCAAnimationRemote>(animation.get()).setHasExplicitBeginTime(hasExplicitBeginTime());
// Copy the specific Basic or Keyframe values.
if (animationType() == Keyframe) {
animation->copyValuesFrom(*this);
animation->copyKeyTimesFrom(*this);
animation->copyTimingFunctionsFrom(*this);
} else {
animation->copyFromValueFrom(*this);
animation->copyToValueFrom(*this);
}
return animation;
}
PlatformCAAnimationRemote::PlatformCAAnimationRemote(AnimationType type, const String& keyPath)
: PlatformCAAnimation(type)
{
m_properties.keyPath = keyPath;
m_properties.animationType = type;
}
String PlatformCAAnimationRemote::keyPath() const
{
return m_properties.keyPath;
}
CFTimeInterval PlatformCAAnimationRemote::beginTime() const
{
return m_properties.beginTime;
}
void PlatformCAAnimationRemote::setBeginTime(CFTimeInterval value)
{
m_properties.beginTime = value;
// Also set a flag to tell us if we've passed in a 0 value.
// The flag is needed because later beginTime will get changed
// to the time at which it fired and we need to know whether
// or not it was 0 to begin with.
if (value)
m_properties.hasExplicitBeginTime = value;
}
CFTimeInterval PlatformCAAnimationRemote::duration() const
{
return m_properties.duration;
}
void PlatformCAAnimationRemote::setDuration(CFTimeInterval value)
{
m_properties.duration = value;
}
float PlatformCAAnimationRemote::speed() const
{
return m_properties.speed;
}
void PlatformCAAnimationRemote::setSpeed(float value)
{
m_properties.speed = value;
}
CFTimeInterval PlatformCAAnimationRemote::timeOffset() const
{
return m_properties.timeOffset;
}
void PlatformCAAnimationRemote::setTimeOffset(CFTimeInterval value)
{
m_properties.timeOffset = value;
}
float PlatformCAAnimationRemote::repeatCount() const
{
return m_properties.repeatCount;
}
void PlatformCAAnimationRemote::setRepeatCount(float value)
{
m_properties.repeatCount = value;
}
bool PlatformCAAnimationRemote::autoreverses() const
{
return m_properties.autoReverses;
}
void PlatformCAAnimationRemote::setAutoreverses(bool value)
{
m_properties.autoReverses = value;
}
PlatformCAAnimation::FillModeType PlatformCAAnimationRemote::fillMode() const
{
return m_properties.fillMode;
}
void PlatformCAAnimationRemote::setFillMode(FillModeType value)
{
m_properties.fillMode = value;
}
void PlatformCAAnimationRemote::setTimingFunction(const TimingFunction* value, bool reverse)
{
Vector<RefPtr<TimingFunction>> timingFunctions;
timingFunctions.append(value->clone());
m_properties.timingFunctions = WTFMove(timingFunctions);
m_properties.reverseTimingFunctions = reverse;
}
void PlatformCAAnimationRemote::copyTimingFunctionFrom(const PlatformCAAnimation& value)
{
copyTimingFunctionsFrom(value);
}
bool PlatformCAAnimationRemote::isRemovedOnCompletion() const
{
return m_properties.removedOnCompletion;
}
void PlatformCAAnimationRemote::setRemovedOnCompletion(bool value)
{
m_properties.removedOnCompletion = value;
}
bool PlatformCAAnimationRemote::isAdditive() const
{
return m_properties.additive;
}
void PlatformCAAnimationRemote::setAdditive(bool value)
{
m_properties.additive = value;
}
PlatformCAAnimation::ValueFunctionType PlatformCAAnimationRemote::valueFunction() const
{
return m_properties.valueFunction;
}
void PlatformCAAnimationRemote::setValueFunction(ValueFunctionType value)
{
m_properties.valueFunction = value;
}
void PlatformCAAnimationRemote::setFromValue(float value)
{
if (animationType() != Basic)
return;
m_properties.keyValues.resize(2);
m_properties.keyValues[0] = KeyframeValue(value);
}
void PlatformCAAnimationRemote::setFromValue(const TransformationMatrix& value)
{
if (animationType() != Basic)
return;
m_properties.keyValues.resize(2);
m_properties.keyValues[0] = KeyframeValue(value);
}
void PlatformCAAnimationRemote::setFromValue(const FloatPoint3D& value)
{
if (animationType() != Basic)
return;
m_properties.keyValues.resize(2);
m_properties.keyValues[0] = KeyframeValue(value);
}
void PlatformCAAnimationRemote::setFromValue(const Color& value)
{
if (animationType() != Basic)
return;
m_properties.keyValues.resize(2);
m_properties.keyValues[0] = KeyframeValue(value);
}
void PlatformCAAnimationRemote::setFromValue(const FilterOperation* operation, int internalFilterPropertyIndex)
{
if (animationType() != Basic)
return;
m_properties.keyValues.resize(2);
m_properties.keyValues[0] = KeyframeValue(operation->clone());
}
void PlatformCAAnimationRemote::copyFromValueFrom(const PlatformCAAnimation& value)
{
const PlatformCAAnimationRemote& other = downcast<PlatformCAAnimationRemote>(value);
if (other.m_properties.keyValues.isEmpty())
return;
m_properties.keyValues.resize(2);
m_properties.keyValues[0] = other.m_properties.keyValues[0];
}
void PlatformCAAnimationRemote::setToValue(float value)
{
if (animationType() != Basic)
return;
m_properties.keyValues.resize(2);
m_properties.keyValues[1] = KeyframeValue(value);
}
void PlatformCAAnimationRemote::setToValue(const TransformationMatrix& value)
{
if (animationType() != Basic)
return;
m_properties.keyValues.resize(2);
m_properties.keyValues[1] = KeyframeValue(value);
}
void PlatformCAAnimationRemote::setToValue(const FloatPoint3D& value)
{
if (animationType() != Basic)
return;
m_properties.keyValues.resize(2);
m_properties.keyValues[1] = KeyframeValue(value);
}
void PlatformCAAnimationRemote::setToValue(const Color& value)
{
if (animationType() != Basic)
return;
m_properties.keyValues.resize(2);
m_properties.keyValues[1] = KeyframeValue(value);
}
void PlatformCAAnimationRemote::setToValue(const FilterOperation* operation, int internalFilterPropertyIndex)
{
if (animationType() != Basic)
return;
UNUSED_PARAM(internalFilterPropertyIndex);
ASSERT(operation);
m_properties.keyValues.resize(2);
m_properties.keyValues[1] = KeyframeValue(operation->clone());
}
void PlatformCAAnimationRemote::copyToValueFrom(const PlatformCAAnimation& value)
{
const PlatformCAAnimationRemote& other = downcast<PlatformCAAnimationRemote>(value);
if (other.m_properties.keyValues.size() < 2)
return;
m_properties.keyValues.resize(2);
m_properties.keyValues[1] = other.m_properties.keyValues[1];
}
// Keyframe-animation properties.
void PlatformCAAnimationRemote::setValues(const Vector<float>& values)
{
if (animationType() != Keyframe)
return;
Vector<KeyframeValue> keyframes;
keyframes.reserveInitialCapacity(values.size());
for (size_t i = 0; i < values.size(); ++i)
keyframes.uncheckedAppend(KeyframeValue(values[i]));
m_properties.keyValues = WTFMove(keyframes);
}
void PlatformCAAnimationRemote::setValues(const Vector<TransformationMatrix>& values)
{
if (animationType() != Keyframe)
return;
Vector<KeyframeValue> keyframes;
keyframes.reserveInitialCapacity(values.size());
for (size_t i = 0; i < values.size(); ++i)
keyframes.uncheckedAppend(KeyframeValue(values[i]));
m_properties.keyValues = WTFMove(keyframes);
}
void PlatformCAAnimationRemote::setValues(const Vector<FloatPoint3D>& values)
{
if (animationType() != Keyframe)
return;
Vector<KeyframeValue> keyframes;
keyframes.reserveInitialCapacity(values.size());
for (size_t i = 0; i < values.size(); ++i)
keyframes.uncheckedAppend(KeyframeValue(values[i]));
m_properties.keyValues = WTFMove(keyframes);
}
void PlatformCAAnimationRemote::setValues(const Vector<Color>& values)
{
if (animationType() != Keyframe)
return;
Vector<KeyframeValue> keyframes;
keyframes.reserveInitialCapacity(values.size());
for (size_t i = 0; i < values.size(); ++i)
keyframes.uncheckedAppend(KeyframeValue(values[i]));
m_properties.keyValues = WTFMove(keyframes);
}
void PlatformCAAnimationRemote::setValues(const Vector<RefPtr<FilterOperation>>& values, int internalFilterPropertyIndex)
{
UNUSED_PARAM(internalFilterPropertyIndex);
if (animationType() != Keyframe)
return;
Vector<KeyframeValue> keyframes;
keyframes.reserveInitialCapacity(values.size());
for (auto& value : values)
keyframes.uncheckedAppend(KeyframeValue { value.copyRef() });
m_properties.keyValues = WTFMove(keyframes);
}
void PlatformCAAnimationRemote::copyValuesFrom(const PlatformCAAnimation& value)
{
m_properties.keyValues = downcast<PlatformCAAnimationRemote>(value).m_properties.keyValues;
}
void PlatformCAAnimationRemote::setKeyTimes(const Vector<float>& keyTimes)
{
m_properties.keyTimes = keyTimes;
}
void PlatformCAAnimationRemote::copyKeyTimesFrom(const PlatformCAAnimation& value)
{
m_properties.keyTimes = downcast<PlatformCAAnimationRemote>(value).m_properties.keyTimes;
}
void PlatformCAAnimationRemote::setTimingFunctions(const Vector<const TimingFunction*>& values, bool reverse)
{
Vector<RefPtr<WebCore::TimingFunction>> timingFunctions;
timingFunctions.reserveInitialCapacity(values.size());
for (size_t i = 0; i < values.size(); ++i)
timingFunctions.uncheckedAppend(values[i]->clone());
m_properties.timingFunctions = WTFMove(timingFunctions);
m_properties.reverseTimingFunctions = reverse;
}
void PlatformCAAnimationRemote::copyTimingFunctionsFrom(const PlatformCAAnimation& value)
{
const PlatformCAAnimationRemote& other = downcast<PlatformCAAnimationRemote>(value);
m_properties.timingFunctions = other.m_properties.timingFunctions;
m_properties.reverseTimingFunctions = other.m_properties.reverseTimingFunctions;
}
static NSObject* animationValueFromKeyframeValue(const PlatformCAAnimationRemote::KeyframeValue& keyframeValue)
{
switch (keyframeValue.keyframeType()) {
case PlatformCAAnimationRemote::KeyframeValue::NumberKeyType:
return @(keyframeValue.numberValue());
case PlatformCAAnimationRemote::KeyframeValue::ColorKeyType: {
Color color = keyframeValue.colorValue();
return @[ @(color.red()), @(color.green()), @(color.blue()), @(color.alpha()) ];
}
case PlatformCAAnimationRemote::KeyframeValue::PointKeyType: {
FloatPoint3D point = keyframeValue.pointValue();
return @[ @(point.x()), @(point.y()), @(point.z()) ];
}
case PlatformCAAnimationRemote::KeyframeValue::TransformKeyType:
return [NSValue valueWithCATransform3D:keyframeValue.transformValue()];
case PlatformCAAnimationRemote::KeyframeValue::FilterKeyType:
return PlatformCAFilters::filterValueForOperation(keyframeValue.filterValue(), 0 /* unused */).autorelease();
}
}
static void addAnimationToLayer(CALayer *layer, RemoteLayerTreeHost* layerTreeHost, const String& key, const PlatformCAAnimationRemote::Properties& properties)
{
RetainPtr<CAPropertyAnimation> caAnimation;
switch (properties.animationType) {
case PlatformCAAnimation::Basic: {
RetainPtr<CABasicAnimation> basicAnimation;
basicAnimation = [CABasicAnimation animationWithKeyPath:properties.keyPath];
if (properties.keyValues.size() > 1) {
[basicAnimation setFromValue:animationValueFromKeyframeValue(properties.keyValues[0])];
[basicAnimation setToValue:animationValueFromKeyframeValue(properties.keyValues[1])];
}
if (properties.timingFunctions.size())
[basicAnimation setTimingFunction:toCAMediaTimingFunction(properties.timingFunctions[0].get(), properties.reverseTimingFunctions)];
caAnimation = basicAnimation;
break;
}
case PlatformCAAnimation::Keyframe: {
RetainPtr<CAKeyframeAnimation> keyframeAnimation;
keyframeAnimation = [CAKeyframeAnimation animationWithKeyPath:properties.keyPath];
if (properties.keyValues.size()) {
RetainPtr<NSMutableArray> keyframes = adoptNS([[NSMutableArray alloc] initWithCapacity:properties.keyValues.size()]);
for (const auto& value : properties.keyValues)
[keyframes addObject:animationValueFromKeyframeValue(value)];
[keyframeAnimation setValues:keyframes.get()];
}
if (properties.keyTimes.size()) {
RetainPtr<NSMutableArray> keyTimes = adoptNS([[NSMutableArray alloc] initWithCapacity:properties.keyTimes.size()]);
for (auto keyTime : properties.keyTimes)
[keyTimes addObject:@(keyTime)];
[keyframeAnimation setKeyTimes:keyTimes.get()];
}
if (properties.timingFunctions.size()) {
RetainPtr<NSMutableArray> timingFunctions = adoptNS([[NSMutableArray alloc] initWithCapacity:properties.timingFunctions.size()]);
for (const auto& timingFunction : properties.timingFunctions)
[timingFunctions addObject:toCAMediaTimingFunction(timingFunction.get(), properties.reverseTimingFunctions)];
[keyframeAnimation setTimingFunctions:timingFunctions.get()];
}
caAnimation = keyframeAnimation;
break;
}
case PlatformCAAnimation::Spring: {
RetainPtr<CASpringAnimation> springAnimation;
springAnimation = [CASpringAnimation animationWithKeyPath:properties.keyPath];
if (properties.keyValues.size() > 1) {
[springAnimation setFromValue:animationValueFromKeyframeValue(properties.keyValues[0])];
[springAnimation setToValue:animationValueFromKeyframeValue(properties.keyValues[1])];
}
if (properties.timingFunctions.size()) {
auto& timingFunction = properties.timingFunctions[0];
if (timingFunction->isSpringTimingFunction()) {
auto& function = *static_cast<const SpringTimingFunction*>(timingFunction.get());
[springAnimation setMass:function.mass()];
[springAnimation setStiffness:function.stiffness()];
[springAnimation setDamping:function.damping()];
[springAnimation setInitialVelocity:function.initialVelocity()];
}
}
caAnimation = springAnimation;
break;
}
}
[caAnimation setBeginTime:properties.beginTime];
[caAnimation setDuration:properties.duration];
[caAnimation setTimeOffset:properties.timeOffset];
[caAnimation setRepeatCount:properties.repeatCount];
[caAnimation setSpeed:properties.speed];
[caAnimation setAutoreverses:properties.autoReverses];
[caAnimation setRemovedOnCompletion:properties.removedOnCompletion];
[caAnimation setAdditive:properties.additive];
if (properties.fillMode != PlatformCAAnimation::NoFillMode)
[caAnimation setFillMode:toCAFillModeType(properties.fillMode)];
if (properties.valueFunction != PlatformCAAnimation::NoValueFunction)
[caAnimation setValueFunction:[CAValueFunction functionWithName:toCAValueFunctionType(properties.valueFunction)]];
if (properties.hasExplicitBeginTime)
[caAnimation setValue:@YES forKey:WKExplicitBeginTimeFlag];
if (layerTreeHost) {
GraphicsLayer::PlatformLayerID layerID = RemoteLayerTreeNode::layerID(layer);
RetainPtr<WKAnimationDelegate>& delegate = layerTreeHost->animationDelegates().add(layerID, nullptr).iterator->value;
if (!delegate)
delegate = adoptNS([[WKAnimationDelegate alloc] initWithLayerID:layerID layerTreeHost:layerTreeHost]);
[caAnimation setDelegate:delegate.get()];
}
[layer addAnimation:caAnimation.get() forKey:key];
}
void PlatformCAAnimationRemote::updateLayerAnimations(CALayer *layer, RemoteLayerTreeHost* layerTreeHost, const AnimationsList& animationsToAdd, const HashSet<String>& animationsToRemove)
{
BEGIN_BLOCK_OBJC_EXCEPTIONS;
for (const auto& value : animationsToRemove)
[layer removeAnimationForKey:value];
for (const auto& keyAnimationPair : animationsToAdd)
addAnimationToLayer(layer, layerTreeHost, keyAnimationPair.first, keyAnimationPair.second);
END_BLOCK_OBJC_EXCEPTIONS;
}
TextStream& operator<<(TextStream&ts, const PlatformCAAnimationRemote::KeyframeValue& value)
{
switch (value.keyframeType()) {
case PlatformCAAnimationRemote::KeyframeValue::NumberKeyType:
ts << "number=" << value.numberValue();
break;
case PlatformCAAnimationRemote::KeyframeValue::ColorKeyType:
ts << "color=";
ts << value.colorValue();
break;
case PlatformCAAnimationRemote::KeyframeValue::PointKeyType:
ts << "point=";
ts << value.pointValue();
break;
case PlatformCAAnimationRemote::KeyframeValue::TransformKeyType:
ts << "transform=";
ts << value.transformValue();
break;
case PlatformCAAnimationRemote::KeyframeValue::FilterKeyType:
ts << "filter=";
if (value.filterValue())
ts << *value.filterValue();
else
ts << "null";
break;
}
return ts;
}
TextStream& operator<<(TextStream& ts, const PlatformCAAnimationRemote::Properties& animation)
{
ts << "type=";
ts << animation.animationType;
ts << " keyPath=";
ts << animation.keyPath;
if (animation.beginTime)
ts.dumpProperty("beginTime", animation.beginTime);
if (animation.duration)
ts.dumpProperty("duration", animation.duration);
if (animation.timeOffset)
ts.dumpProperty("timeOffset", animation.timeOffset);
ts.dumpProperty("repeatCount", animation.repeatCount);
if (animation.speed != 1)
ts.dumpProperty("speed", animation.speed);
ts.dumpProperty("fillMode", animation.fillMode);
ts.dumpProperty("valueFunction", animation.valueFunction);
if (animation.autoReverses)
ts.dumpProperty("autoReverses", animation.autoReverses);
if (!animation.removedOnCompletion)
ts.dumpProperty("removedOnCompletion", animation.removedOnCompletion);
if (animation.additive)
ts.dumpProperty("additive", animation.additive);
if (animation.reverseTimingFunctions)
ts.dumpProperty("reverseTimingFunctions", animation.reverseTimingFunctions);
if (animation.hasExplicitBeginTime)
ts.dumpProperty("hasExplicitBeginTime", animation.hasExplicitBeginTime);
ts << "\n";
ts.increaseIndent();
ts.writeIndent();
ts << "(" << "keyframes";
ts.increaseIndent();
size_t maxFrames = std::max(animation.keyValues.size(), animation.keyTimes.size());
maxFrames = std::max(maxFrames, animation.timingFunctions.size());
for (size_t i = 0; i < maxFrames; ++i) {
ts << "\n";
ts.writeIndent();
ts << "(keyframe " << unsigned(i);
if (i < animation.keyTimes.size())
ts.dumpProperty("time", animation.keyTimes[i]);
if (i < animation.timingFunctions.size() && animation.timingFunctions[i])
ts.dumpProperty<const TimingFunction&>("timing function", *animation.timingFunctions[i]);
if (i < animation.keyValues.size())
ts.dumpProperty("value", animation.keyValues[i]);
ts << ")";
}
ts.decreaseIndent();
ts.decreaseIndent();
return ts;
}
} // namespace WebKit