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
cc / paint / skottie_serialization_history.h [blame]
// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CC_PAINT_SKOTTIE_SERIALIZATION_HISTORY_H_
#define CC_PAINT_SKOTTIE_SERIALIZATION_HISTORY_H_
#include "base/containers/flat_map.h"
#include "base/synchronization/lock.h"
#include "base/thread_annotations.h"
#include "cc/paint/paint_export.h"
#include "cc/paint/paint_flags.h"
#include "cc/paint/paint_image.h"
#include "cc/paint/skottie_frame_data.h"
#include "cc/paint/skottie_resource_metadata.h"
#include "cc/paint/skottie_text_property_value.h"
namespace cc {
class SkottieWrapper;
// For each frame of a Skottie animation that uses out-of-process rasterization:
// 1) The animation's state is captured in a DrawSkottieOp object.
// 2) The object is serialized, transmitted over IPC, then deserialized.
// 3) The animation's state is updated in the target raster process.
// 4) The new frame is rendered/rasterized.
//
// SkottieSerializationHistory keeps track of past animation state that has
// been serialized and transmitted for rasterization. This allows the pipeline
// to be optimized such that only "new"/"updated" animation state is transmitted
// for each frame rather than re-transmitting everything. In other words, step
// 2) can use this history to filter out existing animation state that is
// already reflected in the target process from a previous frame in step 3).
//
// This class is thread-safe.
class CC_PAINT_EXPORT SkottieSerializationHistory {
public:
// Number of RequestInactiveAnimationsPurge() calls that must be made before
// trying to purge stale skottie animations from history (referred to as
// doing a "purge check"). If an animation has had no activity since the last
// purge check, it gets deleted.
static constexpr int kDefaultPurgePeriod = 1000;
explicit SkottieSerializationHistory(int purge_period = kDefaultPurgePeriod);
SkottieSerializationHistory(const SkottieSerializationHistory&) = delete;
SkottieSerializationHistory& operator=(const SkottieSerializationHistory&) =
delete;
~SkottieSerializationHistory();
// Given the set of |images| and the |text_map| in the |skottie| animation's
// new frame, filter out the entries whose contents have not changed since the
// last frame. If an entry *has* changed, it is kept in its corresponding
// output argument and the history is updated internally.
void FilterNewSkottieFrameState(const SkottieWrapper& skottie,
SkottieFrameDataMap& images,
SkottieTextPropertyValueMap& text_map);
// Purges the history of any Skottie animations that have been inactive for
// a while. Although an animation's history is rather light-weight, this is
// done as a safeguard to prevent accumulating stale data in the long run.
//
// Note this method is intentionally designed to be called frequently; it's
// cheap and does not trigger an actual purge most of the time. Ideally, an
// animation's history would be automatically purged when the animation
// finishes, but that is difficult to observe at this layer of the code.
void RequestInactiveAnimationsPurge();
private:
// Uniquely identifies the contents of a SkottieFrameData instance (used to
// tell when an image asset's contents change from one animation frame to
// another).
struct SkottieFrameDataId {
explicit SkottieFrameDataId(const SkottieFrameData& frame_data);
bool operator==(const SkottieFrameDataId& other) const;
bool operator!=(const SkottieFrameDataId& other) const;
// Only store the id. Storing the whole PaintImage is doable but can
// potentially keep some ref-counted members alive longer than necessary. So
// just store the bare minimum to identify the image.
PaintImage::Id paint_image_id;
PaintFlags::FilterQuality quality;
};
// History for an individual SkottieWrapper (animation instance).
class SkottieWrapperHistory {
public:
static constexpr int kInitialSequenceId = 1;
SkottieWrapperHistory(const SkottieFrameDataMap& initial_images,
const SkottieTextPropertyValueMap& initial_text_map);
SkottieWrapperHistory(const SkottieWrapperHistory& other);
SkottieWrapperHistory& operator=(const SkottieWrapperHistory& other);
~SkottieWrapperHistory();
void FilterNewState(SkottieFrameDataMap& images,
SkottieTextPropertyValueMap& text_map);
// The "sequence_id" is incremented each time the caller tries to update an
// animation's history, regardless of whether its history is ultimately
// mutated. This is just used an indicator that the animation is still alive
// and playing, not for judging when its state has changed.
int current_sequence_id() const { return current_sequence_id_; }
int sequence_id_at_last_purge_check() const {
return sequence_id_at_last_purge_check_;
}
void update_sequence_id_at_last_purge_check() {
sequence_id_at_last_purge_check_ = current_sequence_id_;
}
private:
void FilterNewFrameImages(SkottieFrameDataMap& images);
void FilterNewTextPropertyValues(SkottieTextPropertyValueMap& text_map);
int current_sequence_id_ = kInitialSequenceId;
int sequence_id_at_last_purge_check_ = kInitialSequenceId;
base::flat_map<SkottieResourceIdHash, SkottieFrameDataId>
last_frame_data_per_asset_;
SkottieTextPropertyValueMap accumulated_text_map_;
};
base::Lock mutex_;
base::flat_map</*SkottieWrapper id*/ uint32_t, SkottieWrapperHistory>
history_per_animation_ GUARDED_BY(mutex_);
int GUARDED_BY(mutex_) purge_period_counter_ = 0;
const int purge_period_;
};
} // namespace cc
#endif // CC_PAINT_SKOTTIE_SERIALIZATION_HISTORY_H_