blob: d309bcee7a9188c2098fe615d971d6e7f96ce994 [file] [log] [blame]
// Copyright 2014 The Chromium Authors
// 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/memory/scoped_refptr.h"
#include "third_party/abseil-cpp/absl/types/optional.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/animation/timing_function.h"
#include "third_party/blink/renderer/platform/heap/garbage_collected.h"
#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
#include "third_party/blink/renderer/platform/wtf/forward.h"
#include "third_party/blink/renderer/platform/wtf/hash_set.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://w3.org/TR/web-animations-1/#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:
Keyframe(const Keyframe&) = delete;
Keyframe& operator=(const Keyframe&) = delete;
virtual ~Keyframe() = default;
// TODO(smcgruer): The keyframe offset should be immutable.
void SetOffset(absl::optional<double> offset) { offset_ = offset; }
absl::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;
}
absl::optional<EffectModel::CompositeOperation> Composite() const {
return composite_;
}
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);
PropertySpecificKeyframe(const PropertySpecificKeyframe&) = delete;
PropertySpecificKeyframe& operator=(const PropertySpecificKeyframe&) =
delete;
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 bool IsRevertLayer() 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_;
};
// 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(absl::optional<double> offset,
absl::optional<EffectModel::CompositeOperation> composite,
scoped_refptr<TimingFunction> easing)
: offset_(offset), composite_(composite), easing_(std::move(easing)) {
if (!easing_)
easing_ = LinearTimingFunction::Shared();
}
absl::optional<double> offset_;
// To avoid having multiple CompositeOperation enums internally (one with
// 'auto' and one without), we use a absl::optional for composite_. A
// absl::nullopt value represents 'auto'.
absl::optional<EffectModel::CompositeOperation> composite_;
scoped_refptr<TimingFunction> easing_;
};
using PropertySpecificKeyframe = Keyframe::PropertySpecificKeyframe;
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_CORE_ANIMATION_KEYFRAME_H_