File: keyframe.h

package info (click to toggle)
chromium 138.0.7204.183-1
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 6,071,908 kB
  • sloc: cpp: 34,937,088; ansic: 7,176,967; javascript: 4,110,704; python: 1,419,953; asm: 946,768; xml: 739,971; pascal: 187,324; sh: 89,623; perl: 88,663; objc: 79,944; sql: 50,304; cs: 41,786; fortran: 24,137; makefile: 21,806; php: 13,980; tcl: 13,166; yacc: 8,925; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (329 lines) | stat: -rw-r--r-- 13,603 bytes parent folder | download | duplicates (3)
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
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
// 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 <optional>

#include "base/memory/scoped_refptr.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/animation/timeline_offset.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/bindings/script_state.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 TimelineRange;
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:
  struct EndIterator {};

  class VirtualPropertyIterator {
   public:
    virtual ~VirtualPropertyIterator() = default;
    virtual void Advance(const Keyframe* keyframe) = 0;
    virtual PropertyHandle Deref(const Keyframe* keyframe) const = 0;
    virtual bool AtEnd(const Keyframe* keyframe) const = 0;
  };

  class CORE_EXPORT PropertyIteratorWrapper {
    STACK_ALLOCATED();

   public:
    explicit PropertyIteratorWrapper(
        const Keyframe* keyframe,
        std::unique_ptr<VirtualPropertyIterator> impl)
        : keyframe_(keyframe), impl_(std::move(impl)) {}

    bool operator==(EndIterator other) const { return impl_->AtEnd(keyframe_); }

    PropertyIteratorWrapper& operator++() {
      impl_->Advance(keyframe_);
      return *this;
    }

    PropertyHandle operator*() const { return impl_->Deref(keyframe_); }

   private:
    const Keyframe* keyframe_;
    std::unique_ptr<VirtualPropertyIterator> impl_;
  };

  class CORE_EXPORT IterableProperties
      : public GarbageCollected<IterableProperties> {
   public:
    IterableProperties() = default;
    virtual ~IterableProperties() = default;
    virtual PropertyIteratorWrapper begin() const = 0;
    EndIterator end() const { return EndIterator(); }
    virtual size_t size() const = 0;
    bool empty() const { return begin() == end(); }
    virtual void Trace(Visitor*) const {}
    virtual bool IsTransitionProperties() const { return false; }
  };

  Keyframe(const Keyframe&) = delete;
  Keyframe& operator=(const Keyframe&) = delete;
  virtual ~Keyframe() = default;

  static const double kNullComputedOffset;

  // TODO(smcgruer): The keyframe offset should be immutable.
  void SetOffset(std::optional<double> offset) { offset_ = offset; }
  std::optional<double> Offset() const { return offset_; }

  // Offsets are computed for programmatic keyframes that do not have a
  // specified offset (either as a percentage or timeline offset). These are
  // explicitly stored in the keyframe rather than computed on demand since
  // keyframes can be reordered to accommodate changes to the resolved timeline
  // offsets and computed offsets need to be sorted into the correct position.
  void SetComputedOffset(std::optional<double> offset) {
    computed_offset_ = offset;
  }
  std::optional<double> ComputedOffset() const { return computed_offset_; }

  // In order to have a valid computed offset, it must be evaluated and finite.
  // NaN Is used as the null value for computed offset. Note as NaN != NaN we
  // cannot check that the value matches kNullComputedOffset.
  bool HasComputedOffset() const {
    return computed_offset_ && !std::isnan(computed_offset_.value());
  }

  double CheckedOffset() const { return offset_.value_or(-1); }

  void SetTimelineOffset(std::optional<TimelineOffset> timeline_offset) {
    timeline_offset_ = timeline_offset;
  }
  const std::optional<TimelineOffset>& GetTimelineOffset() const {
    return timeline_offset_;
  }

  // TODO(smcgruer): The keyframe composite operation should be immutable.
  void SetComposite(EffectModel::CompositeOperation composite) {
    composite_ = composite;
  }
  std::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_); }

  // Track the original positioning in the list for tiebreaking during sort
  // when two keyframes have the same offset.
  void SetIndex(int index) { original_index_ = index; }
  std::optional<int> Index() { return original_index_; }

  // Returns an iterable collection of the properties represented in this
  // keyframe.
  const IterableProperties& Properties() const { return *properties_; }

  // Returns a copy of the properties represented in this keyframe.
  // Prefer iterating over Properties() when a copy is not needed.
  Vector<PropertyHandle> PropertiesVector() const;

  // 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;

  // Comparator for stable sorting keyframes by offset. In the event of a tie
  // we sort by original index of the keyframe if specified.
  static bool LessThan(const Member<Keyframe>& a, const Member<Keyframe>& b);

  // Compute the offset if dependent on a timeline range.  Returns true if the
  // offset changed.
  bool ResolveTimelineOffset(const TimelineRange&,
                             double range_start,
                             double range_end);

  // 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* visitor) const { visitor->Trace(properties_); }

  // 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;

    // 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 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:
  explicit Keyframe(IterableProperties* properties)
      : properties_(properties), easing_(LinearTimingFunction::Shared()) {}
  Keyframe(IterableProperties* properties,
           std::optional<double> offset,
           std::optional<TimelineOffset> timeline_offset,
           std::optional<EffectModel::CompositeOperation> composite,
           scoped_refptr<TimingFunction> easing)
      : properties_(properties),
        offset_(offset),
        timeline_offset_(timeline_offset),
        composite_(composite),
        easing_(std::move(easing)) {
    if (!easing_)
      easing_ = LinearTimingFunction::Shared();
  }

  Member<IterableProperties> properties_;

  // Either the specified offset or the offset resolved from a timeline offset.
  std::optional<double> offset_;
  // The computed offset will equal the specified or resolved timeline offset
  // if non-null. The computed offset is null if the keyframe has an unresolved
  // timeline offset. Otherwise, it is calculated based on a rule to equally
  // space within an anchored range.
  // See KeyframeEffectModelBase::GetComputedOffsets.
  std::optional<double> computed_offset_;
  // Offsets of the form <name> <percent>. These offsets are layout depending
  // and need to be re-resolved on a style change affecting the corresponding
  // timeline range. If the effect is not associated with an animation that is
  // attached to a timeline with a non-empty timeline range,
  // then the offset and computed offset will be null.
  std::optional<TimelineOffset> timeline_offset_;

  // The original index in the keyframe list is used to resolve ties in the
  // offset when sorting, and to conditionally recover the original order when
  // reporting.
  std::optional<int> original_index_;

  // To avoid having multiple CompositeOperation enums internally (one with
  // 'auto' and one without), we use a std::optional for composite_. A
  // std::nullopt value represents 'auto'.
  std::optional<EffectModel::CompositeOperation> composite_;
  scoped_refptr<TimingFunction> easing_;
};

using PropertySpecificKeyframe = Keyframe::PropertySpecificKeyframe;

}  // namespace blink

#endif  // THIRD_PARTY_BLINK_RENDERER_CORE_ANIMATION_KEYFRAME_H_