1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212
|
// 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/animatable/animatable_value.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.h"
#include "third_party/blink/renderer/platform/wtf/forward.h"
namespace blink {
using PropertyHandleSet = HashSet<PropertyHandle>;
class Element;
class ComputedStyle;
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 GarbageCollectedFinalized<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();
}
// TODO(smcgruer): The keyframe timing function should be immutable.
void SetEasing(scoped_refptr<TimingFunction> easing) {
if (easing)
easing_ = std::move(easing);
else
easing_ = LinearTimingFunction::Shared();
}
TimingFunction& Easing() const { return *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&) const;
virtual bool IsStringKeyframe() const { return false; }
virtual bool IsTransitionKeyframe() const { return false; }
virtual void Trace(Visitor*) {}
// 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 GarbageCollectedFinalized<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 PropertySpecificKeyframe* CloneWithOffset(double offset) const = 0;
// FIXME: Remove this once CompositorAnimations no longer depends on
// AnimatableValues
virtual bool PopulateAnimatableValue(
const PropertyHandle&,
Element&,
const ComputedStyle& base_style,
const ComputedStyle* parent_style) const {
return false;
}
virtual const AnimatableValue* GetAnimatableValue() const = 0;
virtual bool IsAnimatableValuePropertySpecificKeyframe() const {
return false;
}
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*){};
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_
|