1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef THIRD_PARTY_BLINK_RENDERER_CORE_ANIMATION_KEYFRAME_H_
6 #define THIRD_PARTY_BLINK_RENDERER_CORE_ANIMATION_KEYFRAME_H_
7 
8 #include "base/macros.h"
9 #include "base/memory/scoped_refptr.h"
10 #include "base/optional.h"
11 #include "third_party/blink/renderer/core/animation/animation_effect.h"
12 #include "third_party/blink/renderer/core/animation/effect_model.h"
13 #include "third_party/blink/renderer/core/animation/property_handle.h"
14 #include "third_party/blink/renderer/core/core_export.h"
15 #include "third_party/blink/renderer/platform/heap/handle.h"
16 #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
17 #include "third_party/blink/renderer/platform/wtf/forward.h"
18 
19 namespace blink {
20 
21 using PropertyHandleSet = HashSet<PropertyHandle>;
22 
23 class Element;
24 class ComputedStyle;
25 class CompositorKeyframeValue;
26 class V8ObjectBuilder;
27 
28 // A base class representing an animation keyframe.
29 //
30 // Generically a keyframe is a set of (property, value) pairs. In the
31 // web-animations spec keyframes have a few additional properties:
32 //
33 //   * A possibly-null keyframe offset, which represents the keyframe's position
34 //     relative to other keyframes in the same effect.
35 //   * A non-null timing function, which applies to the period of time between
36 //     this keyframe and the next keyframe in the same effect and influences
37 //     the interpolation between them.
38 //   * An keyframe-specific composite operation, which specifies a specific
39 //     composite operation used to combine values in this keyframe with an
40 //     underlying value. If this is 'auto', the keyframe effect composite
41 //     operation is used instead.
42 //
43 // For spec details, refer to: https://drafts.csswg.org/web-animations/#keyframe
44 //
45 // Implementation-wise the base Keyframe class captures the offset, composite
46 // operation, and timing function. It is left to subclasses to define and store
47 // the set of (property, value) pairs.
48 //
49 // === PropertySpecificKeyframes ===
50 //
51 // When calculating the effect value of a keyframe effect, the web-animations
52 // spec requires that a set of 'property-specific' keyframes are created.
53 // Property-specific keyframes resolve any unspecified offsets in the keyframes,
54 // calculate computed values for the specified properties, convert shorthand
55 // properties to multiple longhand properties, and resolve any conflicting
56 // shorthand properties.
57 //
58 // In this implementation property-specific keyframes are created only once and
59 // cached for subsequent calls, rather than re-computing them for every sample
60 // from the keyframe effect. See KeyframeEffectModelBase::EnsureKeyframeGroups.
61 //
62 // FIXME: Make Keyframe immutable
63 class CORE_EXPORT Keyframe : public GarbageCollected<Keyframe> {
64  public:
65   virtual ~Keyframe() = default;
66 
67   // TODO(smcgruer): The keyframe offset should be immutable.
SetOffset(base::Optional<double> offset)68   void SetOffset(base::Optional<double> offset) { offset_ = offset; }
Offset()69   base::Optional<double> Offset() const { return offset_; }
CheckedOffset()70   double CheckedOffset() const { return offset_.value(); }
71 
72   // TODO(smcgruer): The keyframe composite operation should be immutable.
SetComposite(EffectModel::CompositeOperation composite)73   void SetComposite(EffectModel::CompositeOperation composite) {
74     composite_ = composite;
75   }
HasComposite()76   bool HasComposite() const { return composite_.has_value(); }
Composite()77   EffectModel::CompositeOperation Composite() const {
78     return composite_.value();
79   }
80 
SetEasing(scoped_refptr<TimingFunction> easing)81   void SetEasing(scoped_refptr<TimingFunction> easing) {
82     if (easing)
83       easing_ = std::move(easing);
84     else
85       easing_ = LinearTimingFunction::Shared();
86   }
Easing()87   TimingFunction& Easing() const { return *easing_; }
CopyEasing(const Keyframe & other)88   void CopyEasing(const Keyframe& other) { SetEasing(other.easing_); }
89 
90   // Returns a set of the properties represented in this keyframe.
91   virtual PropertyHandleSet Properties() const = 0;
92 
93   // Creates a clone of this keyframe.
94   //
95   // The clone should have the same (property, value) pairs, offset value,
96   // composite operation, and timing function, as well as any other
97   // subclass-specific data.
98   virtual Keyframe* Clone() const = 0;
99 
100   // Helper function to create a clone of this keyframe with a specific offset.
CloneWithOffset(double offset)101   Keyframe* CloneWithOffset(double offset) const {
102     Keyframe* the_clone = Clone();
103     the_clone->SetOffset(offset);
104     return the_clone;
105   }
106 
107   // Add the properties represented by this keyframe to the given V8 object.
108   //
109   // Subclasses should override this to add the (property, value) pairs they
110   // store, and call into the base version to add the basic Keyframe properties.
111   virtual void AddKeyframePropertiesToV8Object(V8ObjectBuilder&,
112                                                Element*) const;
113 
IsStringKeyframe()114   virtual bool IsStringKeyframe() const { return false; }
IsTransitionKeyframe()115   virtual bool IsTransitionKeyframe() const { return false; }
116 
Trace(Visitor *)117   virtual void Trace(Visitor*) const {}
118 
119   // Represents a property-specific keyframe as defined in the spec. Refer to
120   // the Keyframe class-level documentation for more details.
121   class CORE_EXPORT PropertySpecificKeyframe
122       : public GarbageCollected<PropertySpecificKeyframe> {
123    public:
124     PropertySpecificKeyframe(double offset,
125                              scoped_refptr<TimingFunction> easing,
126                              EffectModel::CompositeOperation);
127     virtual ~PropertySpecificKeyframe() = default;
Offset()128     double Offset() const { return offset_; }
Easing()129     TimingFunction& Easing() const { return *easing_; }
Composite()130     EffectModel::CompositeOperation Composite() const { return composite_; }
UnderlyingFraction()131     double UnderlyingFraction() const {
132       return composite_ == EffectModel::kCompositeReplace ? 0 : 1;
133     }
134     virtual bool IsNeutral() const = 0;
135     virtual bool IsRevert() const = 0;
136     virtual PropertySpecificKeyframe* CloneWithOffset(double offset) const = 0;
137 
138     // FIXME: Remove this once CompositorAnimations no longer depends on
139     // CompositorKeyframeValues
PopulateCompositorKeyframeValue(const PropertyHandle &,Element &,const ComputedStyle & base_style,const ComputedStyle * parent_style)140     virtual bool PopulateCompositorKeyframeValue(
141         const PropertyHandle&,
142         Element&,
143         const ComputedStyle& base_style,
144         const ComputedStyle* parent_style) const {
145       return false;
146     }
147 
148     virtual const CompositorKeyframeValue* GetCompositorKeyframeValue()
149         const = 0;
150 
IsCSSPropertySpecificKeyframe()151     virtual bool IsCSSPropertySpecificKeyframe() const { return false; }
IsSVGPropertySpecificKeyframe()152     virtual bool IsSVGPropertySpecificKeyframe() const { return false; }
IsTransitionPropertySpecificKeyframe()153     virtual bool IsTransitionPropertySpecificKeyframe() const { return false; }
154 
155     virtual PropertySpecificKeyframe* NeutralKeyframe(
156         double offset,
157         scoped_refptr<TimingFunction> easing) const = 0;
158     virtual Interpolation* CreateInterpolation(
159         const PropertyHandle&,
160         const Keyframe::PropertySpecificKeyframe& end) const;
161 
Trace(Visitor *)162     virtual void Trace(Visitor*) const {}
163 
164    protected:
165     double offset_;
166     scoped_refptr<TimingFunction> easing_;
167     EffectModel::CompositeOperation composite_;
168 
169     DISALLOW_COPY_AND_ASSIGN(PropertySpecificKeyframe);
170   };
171 
172   // Construct and return a property-specific keyframe for this keyframe.
173   //
174   // The 'effect_composite' parameter is the composite operation of the effect
175   // that owns the keyframe. If the keyframe has a keyframe-specific composite
176   // operation it should ignore this value when creating the property specific
177   // keyframe.
178   //
179   // The 'offset' parameter is the offset to use in the resultant
180   // PropertySpecificKeyframe. For CSS Transitions and CSS Animations, this is
181   // the normal offset from the keyframe itself. However in web-animations this
182   // will be a computed offset value which may differ from the keyframe offset.
183   virtual PropertySpecificKeyframe* CreatePropertySpecificKeyframe(
184       const PropertyHandle&,
185       EffectModel::CompositeOperation effect_composite,
186       double offset) const = 0;
187 
188  protected:
Keyframe()189   Keyframe()
190       : offset_(), composite_(), easing_(LinearTimingFunction::Shared()) {}
Keyframe(base::Optional<double> offset,base::Optional<EffectModel::CompositeOperation> composite,scoped_refptr<TimingFunction> easing)191   Keyframe(base::Optional<double> offset,
192            base::Optional<EffectModel::CompositeOperation> composite,
193            scoped_refptr<TimingFunction> easing)
194       : offset_(offset), composite_(composite), easing_(std::move(easing)) {
195     if (!easing_)
196       easing_ = LinearTimingFunction::Shared();
197   }
198 
199   base::Optional<double> offset_;
200   // To avoid having multiple CompositeOperation enums internally (one with
201   // 'auto' and one without), we use a base::Optional for composite_. A
202   // base::nullopt value represents 'auto'.
203   base::Optional<EffectModel::CompositeOperation> composite_;
204   scoped_refptr<TimingFunction> easing_;
205   DISALLOW_COPY_AND_ASSIGN(Keyframe);
206 };
207 
208 using PropertySpecificKeyframe = Keyframe::PropertySpecificKeyframe;
209 
210 }  // namespace blink
211 
212 #endif  // THIRD_PARTY_BLINK_RENDERER_CORE_ANIMATION_KEYFRAME_H_
213