blob: c1a2afb8fd644d86a00477e4879d99cd71f3cdcc [file] [log] [blame]
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "CustomCompositorAnimations.h"
#include "core/animation/Animation.h"
#include "core/animation/DocumentTimeline.h"
#include "core/animation/KeyframeEffect.h"
#include "core/animation/KeyframeEffectModel.h"
#include "core/animation/animatable/AnimatableDouble.h"
#include "core/animation/animatable/AnimatableTransform.h"
#include "core/animation/animatable/AnimatableValue.h"
#include "platform/graphics/CompositorMutation.h"
#include "platform/instrumentation/tracing/TraceEvent.h"
#include "platform/transforms/Matrix3DTransformOperation.h"
#include "platform/transforms/MatrixTransformOperation.h"
#include "platform/transforms/TransformOperations.h"
namespace blink {
namespace {
// Create keyframe effect with zero duration, fill mode forward, and two key
// frames with same value. This corresponding animation is always running and by
// updating the key frames we are able to control the applied value.
static KeyframeEffect* createInfiniteKeyFrameEffect(
Element& element,
CSSPropertyID propertyId,
PassRefPtr<AnimatableValue> value) {
AnimatableValueKeyframeVector keyframes(2);
keyframes[0] = AnimatableValueKeyframe::create();
keyframes[0]->setOffset(0.0);
keyframes[0]->setPropertyValue(propertyId, value.get());
keyframes[1] = AnimatableValueKeyframe::create();
keyframes[1]->setOffset(1.0);
keyframes[1]->setPropertyValue(propertyId, value.get());
keyframes[1]->setComposite(EffectModel::CompositeReplace);
Timing timing;
timing.iterationDuration = 0;
timing.fillMode = Timing::FillMode::FORWARDS;
AnimatableValueKeyframeEffectModel* effectModel =
AnimatableValueKeyframeEffectModel::create(keyframes);
return KeyframeEffect::create(&element, effectModel, timing);
}
static KeyframeEffect* updateInfiniteKeyframeEffect(
const KeyframeEffect& keyframeEffect,
CSSPropertyID propertyId,
PassRefPtr<AnimatableValue> value) {
const KeyframeVector& oldFrames =
toAnimatableValueKeyframeEffectModel(keyframeEffect.model())->getFrames();
AnimatableValueKeyframeVector keyframes(2);
keyframes[0] = toAnimatableValueKeyframe(oldFrames[0]->clone().get());
keyframes[1] = toAnimatableValueKeyframe(oldFrames[1]->clone().get());
keyframes[0]->setPropertyValue(propertyId, value.get());
keyframes[1]->setPropertyValue(propertyId, value.get());
AnimatableValueKeyframeEffectModel* effectModel =
AnimatableValueKeyframeEffectModel::create(keyframes);
return KeyframeEffect::create(keyframeEffect.target(), effectModel,
keyframeEffect.specifiedTiming());
}
static Animation* createOrUpdateAnimation(
Animation* animation,
Element& element,
CSSPropertyID propertyId,
PassRefPtr<AnimatableValue> newValue) {
if (!animation) {
KeyframeEffect* keyframeEffect =
createInfiniteKeyFrameEffect(element, propertyId, std::move(newValue));
return element.document().timeline().play(keyframeEffect);
}
KeyframeEffect* keyframeEffect = updateInfiniteKeyframeEffect(
*toKeyframeEffect(animation->effect()), propertyId, std::move(newValue));
animation->setEffect(keyframeEffect);
return animation;
}
} // namespace
void CustomCompositorAnimations::applyUpdate(
Element& element,
const CompositorMutation& mutation) {
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("compositor-worker"),
"CustomCompositorAnimations::applyUpdate");
if (mutation.isOpacityMutated()) {
RefPtr<AnimatableValue> animatableValue =
AnimatableDouble::create(mutation.opacity());
m_animation = createOrUpdateAnimation(
m_animation, element, CSSPropertyOpacity, animatableValue.release());
}
if (mutation.isTransformMutated()) {
TransformOperations ops;
ops.operations().push_back(Matrix3DTransformOperation::create(
TransformationMatrix(mutation.transform())));
RefPtr<AnimatableValue> animatableValue =
AnimatableTransform::create(ops, 1);
m_animation = createOrUpdateAnimation(
m_animation, element, CSSPropertyTransform, animatableValue.release());
}
}
} // namespace blink