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