blob: fe695abdd47f0a10c69efe76e8f025a10a8325b5 [file] [log] [blame]
// Copyright 2014 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.
#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_ANIMATION_KEYFRAME_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_ANIMATION_KEYFRAME_H_
#include "base/macros.h"
#include "base/memory/scoped_refptr.h"
#include "base/optional.h"
#include "third_party/blink/renderer/core/animation/animation_effect.h"
#include "third_party/blink/renderer/core/animation/effect_model.h"
#include "third_party/blink/renderer/core/animation/property_handle.h"
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
#include "third_party/blink/renderer/platform/wtf/forward.h"
namespace blink {
using PropertyHandleSet = HashSet<PropertyHandle>;
class Element;
class ComputedStyle;
class CompositorKeyframeValue;
class V8ObjectBuilder;
// A base class representing an animation keyframe.
//
// Generically a keyframe is a set of (property, value) pairs. In the
// web-animations spec keyframes have a few additional properties:
//
// * A possibly-null keyframe offset, which represents the keyframe's position
// relative to other keyframes in the same effect.
// * A non-null timing function, which applies to the period of time between
// this keyframe and the next keyframe in the same effect and influences
// the interpolation between them.
// * An keyframe-specific composite operation, which specifies a specific
// composite operation used to combine values in this keyframe with an
// underlying value. If this is 'auto', the keyframe effect composite
// operation is used instead.
//
// For spec details, refer to: https://drafts.csswg.org/web-animations/#keyframe
//
// Implementation-wise the base Keyframe class captures the offset, composite
// operation, and timing function. It is left to subclasses to define and store
// the set of (property, value) pairs.
//
// === PropertySpecificKeyframes ===
//
// When calculating the effect value of a keyframe effect, the web-animations
// spec requires that a set of 'property-specific' keyframes are created.
// Property-specific keyframes resolve any unspecified offsets in the keyframes,
// calculate computed values for the specified properties, convert shorthand
// properties to multiple longhand properties, and resolve any conflicting
// shorthand properties.
//
// In this implementation property-specific keyframes are created only once and
// cached for subsequent calls, rather than re-computing them for every sample
// from the keyframe effect. See KeyframeEffectModelBase::EnsureKeyframeGroups.
//
// FIXME: Make Keyframe immutable
class CORE_EXPORT Keyframe : public GarbageCollected<Keyframe> {
public:
virtual ~Keyframe() = default;
// TODO(smcgruer): The keyframe offset should be immutable.
void SetOffset(base::Optional<double> offset) { offset_ = offset; }
base::Optional<double> Offset() const { return offset_; }
double CheckedOffset() const { return offset_.value(); }
// TODO(smcgruer): The keyframe composite operation should be immutable.
void SetComposite(EffectModel::CompositeOperation composite) {
composite_ = composite;
}
bool HasComposite() const { return composite_.has_value(); }
EffectModel::CompositeOperation Composite() const {
return composite_.value();
}
void SetEasing(scoped_refptr<TimingFunction> easing) {
if (easing)
easing_ = std::move(easing);
else
easing_ = LinearTimingFunction::Shared();
}
TimingFunction& Easing() const { return *easing_; }
void CopyEasing(const Keyframe& other) { SetEasing(other.easing_); }
// Returns a set of the properties represented in this keyframe.
virtual PropertyHandleSet Properties() const = 0;
// Creates a clone of this keyframe.
//
// The clone should have the same (property, value) pairs, offset value,
// composite operation, and timing function, as well as any other
// subclass-specific data.
virtual Keyframe* Clone() const = 0;
// Helper function to create a clone of this keyframe with a specific offset.
Keyframe* CloneWithOffset(double offset) const {
Keyframe* the_clone = Clone();
the_clone->SetOffset(offset);
return the_clone;
}
// Add the properties represented by this keyframe to the given V8 object.
//
// Subclasses should override this to add the (property, value) pairs they
// store, and call into the base version to add the basic Keyframe properties.
virtual void AddKeyframePropertiesToV8Object(V8ObjectBuilder&,
Element*) const;
virtual bool IsStringKeyframe() const { return false; }
virtual bool IsTransitionKeyframe() const { return false; }
virtual void Trace(Visitor*) const {}
// Represents a property-specific keyframe as defined in the spec. Refer to
// the Keyframe class-level documentation for more details.
class CORE_EXPORT PropertySpecificKeyframe
: public GarbageCollected<PropertySpecificKeyframe> {
public:
PropertySpecificKeyframe(double offset,
scoped_refptr<TimingFunction> easing,
EffectModel::CompositeOperation);
virtual ~PropertySpecificKeyframe() = default;
double Offset() const { return offset_; }
TimingFunction& Easing() const { return *easing_; }
EffectModel::CompositeOperation Composite() const { return composite_; }
double UnderlyingFraction() const {
return composite_ == EffectModel::kCompositeReplace ? 0 : 1;
}
virtual bool IsNeutral() const = 0;
virtual bool IsRevert() const = 0;
virtual PropertySpecificKeyframe* CloneWithOffset(double offset) const = 0;
// FIXME: Remove this once CompositorAnimations no longer depends on
// CompositorKeyframeValues
virtual bool PopulateCompositorKeyframeValue(
const PropertyHandle&,
Element&,
const ComputedStyle& base_style,
const ComputedStyle* parent_style) const {
return false;
}
virtual const CompositorKeyframeValue* GetCompositorKeyframeValue()
const = 0;
virtual bool IsCSSPropertySpecificKeyframe() const { return false; }
virtual bool IsSVGPropertySpecificKeyframe() const { return false; }
virtual bool IsTransitionPropertySpecificKeyframe() const { return false; }
virtual PropertySpecificKeyframe* NeutralKeyframe(
double offset,
scoped_refptr<TimingFunction> easing) const = 0;
virtual Interpolation* CreateInterpolation(
const PropertyHandle&,
const Keyframe::PropertySpecificKeyframe& end) const;
virtual void Trace(Visitor*) const {}
protected:
double offset_;
scoped_refptr<TimingFunction> easing_;
EffectModel::CompositeOperation composite_;
DISALLOW_COPY_AND_ASSIGN(PropertySpecificKeyframe);
};
// Construct and return a property-specific keyframe for this keyframe.
//
// The 'effect_composite' parameter is the composite operation of the effect
// that owns the keyframe. If the keyframe has a keyframe-specific composite
// operation it should ignore this value when creating the property specific
// keyframe.
//
// The 'offset' parameter is the offset to use in the resultant
// PropertySpecificKeyframe. For CSS Transitions and CSS Animations, this is
// the normal offset from the keyframe itself. However in web-animations this
// will be a computed offset value which may differ from the keyframe offset.
virtual PropertySpecificKeyframe* CreatePropertySpecificKeyframe(
const PropertyHandle&,
EffectModel::CompositeOperation effect_composite,
double offset) const = 0;
protected:
Keyframe()
: offset_(), composite_(), easing_(LinearTimingFunction::Shared()) {}
Keyframe(base::Optional<double> offset,
base::Optional<EffectModel::CompositeOperation> composite,
scoped_refptr<TimingFunction> easing)
: offset_(offset), composite_(composite), easing_(std::move(easing)) {
if (!easing_)
easing_ = LinearTimingFunction::Shared();
}
base::Optional<double> offset_;
// To avoid having multiple CompositeOperation enums internally (one with
// 'auto' and one without), we use a base::Optional for composite_. A
// base::nullopt value represents 'auto'.
base::Optional<EffectModel::CompositeOperation> composite_;
scoped_refptr<TimingFunction> easing_;
DISALLOW_COPY_AND_ASSIGN(Keyframe);
};
using PropertySpecificKeyframe = Keyframe::PropertySpecificKeyframe;
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_CORE_ANIMATION_KEYFRAME_H_