Source code

Revision control

Other Tools

1
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
3
/* This Source Code Form is subject to the terms of the Mozilla Public
4
* License, v. 2.0. If a copy of the MPL was not distributed with this
5
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7
#include "AnimationInfo.h"
8
#include "mozilla/LayerAnimationInfo.h"
9
#include "mozilla/layers/WebRenderLayerManager.h"
10
#include "mozilla/layers/AnimationHelper.h"
11
#include "mozilla/layers/CompositorThread.h"
12
#include "mozilla/dom/Animation.h"
13
#include "nsIContent.h"
14
#include "PuppetWidget.h"
15
16
namespace mozilla {
17
namespace layers {
18
19
AnimationInfo::AnimationInfo() : mCompositorAnimationsId(0), mMutated(false) {}
20
21
AnimationInfo::~AnimationInfo() = default;
22
23
void AnimationInfo::EnsureAnimationsId() {
24
if (!mCompositorAnimationsId) {
25
mCompositorAnimationsId = AnimationHelper::GetNextCompositorAnimationsId();
26
}
27
}
28
29
Animation* AnimationInfo::AddAnimation() {
30
MOZ_ASSERT(!CompositorThreadHolder::IsInCompositorThread());
31
// Here generates a new id when the first animation is added and
32
// this id is used to represent the animations in this layer.
33
EnsureAnimationsId();
34
35
MOZ_ASSERT(!mPendingAnimations, "should have called ClearAnimations first");
36
37
Animation* anim = mAnimations.AppendElement();
38
39
mMutated = true;
40
41
return anim;
42
}
43
44
Animation* AnimationInfo::AddAnimationForNextTransaction() {
45
MOZ_ASSERT(!CompositorThreadHolder::IsInCompositorThread());
46
MOZ_ASSERT(mPendingAnimations,
47
"should have called ClearAnimationsForNextTransaction first");
48
49
Animation* anim = mPendingAnimations->AppendElement();
50
51
return anim;
52
}
53
54
void AnimationInfo::ClearAnimations() {
55
mPendingAnimations = nullptr;
56
57
if (mAnimations.IsEmpty() && mPropertyAnimationGroups.IsEmpty()) {
58
return;
59
}
60
61
mAnimations.Clear();
62
mPropertyAnimationGroups.Clear();
63
mTransformData.reset();
64
mCachedMotionPath = nullptr;
65
66
mMutated = true;
67
}
68
69
void AnimationInfo::ClearAnimationsForNextTransaction() {
70
// Ensure we have a non-null mPendingAnimations to mark a future clear.
71
if (!mPendingAnimations) {
72
mPendingAnimations = MakeUnique<AnimationArray>();
73
}
74
75
mPendingAnimations->Clear();
76
}
77
78
void AnimationInfo::SetCompositorAnimations(
79
const CompositorAnimations& aCompositorAnimations) {
80
mCompositorAnimationsId = aCompositorAnimations.id();
81
82
AnimationStorageData data =
83
AnimationHelper::ExtractAnimations(aCompositorAnimations.animations());
84
mPropertyAnimationGroups.SwapElements(data.mAnimation);
85
mTransformData = std::move(data.mTransformData);
86
mCachedMotionPath.swap(data.mCachedMotionPath);
87
}
88
89
bool AnimationInfo::StartPendingAnimations(const TimeStamp& aReadyTime) {
90
bool updated = false;
91
for (size_t animIdx = 0, animEnd = mAnimations.Length(); animIdx < animEnd;
92
animIdx++) {
93
Animation& anim = mAnimations[animIdx];
94
95
// If the animation is doing an async update of its playback rate, then we
96
// want to match whatever its current time would be at *aReadyTime*.
97
if (!std::isnan(anim.previousPlaybackRate()) && anim.startTime().isSome() &&
98
!anim.originTime().IsNull() && !anim.isNotPlaying()) {
99
TimeDuration readyTime = aReadyTime - anim.originTime();
100
anim.holdTime() = dom::Animation::CurrentTimeFromTimelineTime(
101
readyTime, anim.startTime().ref(), anim.previousPlaybackRate());
102
// Make start time null so that we know to update it below.
103
anim.startTime() = Nothing();
104
}
105
106
// If the animation is play-pending, resolve the start time.
107
if (anim.startTime().isNothing() && !anim.originTime().IsNull() &&
108
!anim.isNotPlaying()) {
109
TimeDuration readyTime = aReadyTime - anim.originTime();
110
anim.startTime() = Some(dom::Animation::StartTimeFromTimelineTime(
111
readyTime, anim.holdTime(), anim.playbackRate()));
112
updated = true;
113
}
114
}
115
return updated;
116
}
117
118
void AnimationInfo::TransferMutatedFlagToLayer(Layer* aLayer) {
119
if (mMutated) {
120
aLayer->Mutated();
121
mMutated = false;
122
}
123
}
124
125
bool AnimationInfo::ApplyPendingUpdatesForThisTransaction() {
126
if (mPendingAnimations) {
127
mPendingAnimations->SwapElements(mAnimations);
128
mPendingAnimations = nullptr;
129
return true;
130
}
131
132
return false;
133
}
134
135
bool AnimationInfo::HasTransformAnimation() const {
136
const nsCSSPropertyIDSet& transformSet =
137
LayerAnimationInfo::GetCSSPropertiesFor(DisplayItemType::TYPE_TRANSFORM);
138
for (uint32_t i = 0; i < mAnimations.Length(); i++) {
139
if (transformSet.HasProperty(mAnimations[i].property())) {
140
return true;
141
}
142
}
143
return false;
144
}
145
146
/* static */
147
Maybe<uint64_t> AnimationInfo::GetGenerationFromFrame(
148
nsIFrame* aFrame, DisplayItemType aDisplayItemKey) {
149
MOZ_ASSERT(aFrame->IsPrimaryFrame() ||
150
nsLayoutUtils::IsFirstContinuationOrIBSplitSibling(aFrame));
151
152
layers::Layer* layer =
153
FrameLayerBuilder::GetDedicatedLayer(aFrame, aDisplayItemKey);
154
if (layer) {
155
return layer->GetAnimationInfo().GetAnimationGeneration();
156
}
157
158
// In case of continuation, KeyframeEffectReadOnly uses its first frame,
159
// whereas nsDisplayItem uses its last continuation, so we have to use the
160
// last continuation frame here.
161
if (nsLayoutUtils::IsFirstContinuationOrIBSplitSibling(aFrame)) {
162
aFrame = nsLayoutUtils::LastContinuationOrIBSplitSibling(aFrame);
163
}
164
RefPtr<WebRenderAnimationData> animationData =
165
GetWebRenderUserData<WebRenderAnimationData>(aFrame,
166
(uint32_t)aDisplayItemKey);
167
if (animationData) {
168
return animationData->GetAnimationInfo().GetAnimationGeneration();
169
}
170
171
return Nothing();
172
}
173
174
/* static */
175
void AnimationInfo::EnumerateGenerationOnFrame(
176
const nsIFrame* aFrame, const nsIContent* aContent,
177
const CompositorAnimatableDisplayItemTypes& aDisplayItemTypes,
178
const AnimationGenerationCallback& aCallback) {
179
if (XRE_IsContentProcess()) {
180
if (nsIWidget* widget = nsContentUtils::WidgetForContent(aContent)) {
181
// In case of child processes, we might not have yet created the layer
182
// manager. That means there is no animation generation we have, thus
183
// we call the callback function with |Nothing()| for the generation.
184
//
185
// Note that we need to use nsContentUtils::WidgetForContent() instead of
186
// BrowserChild::GetFrom(aFrame->PresShell())->WebWidget() because in the
187
// case of child popup content PuppetWidget::mBrowserChild is the same as
188
// the parent's one, which means mBrowserChild->IsLayersConnected() check
189
// in PuppetWidget::GetLayerManager queries the parent state, it results
190
// the assertion in the function failure.
191
if (widget->GetOwningBrowserChild() &&
192
!static_cast<widget::PuppetWidget*>(widget)->HasLayerManager()) {
193
for (auto displayItem : LayerAnimationInfo::sDisplayItemTypes) {
194
aCallback(Nothing(), displayItem);
195
}
196
return;
197
}
198
}
199
}
200
201
RefPtr<LayerManager> layerManager =
202
nsContentUtils::LayerManagerForContent(aContent);
203
204
if (layerManager &&
205
layerManager->GetBackendType() == layers::LayersBackend::LAYERS_WR) {
206
// In case of continuation, nsDisplayItem uses its last continuation, so we
207
// have to use the last continuation frame here.
208
if (nsLayoutUtils::IsFirstContinuationOrIBSplitSibling(aFrame)) {
209
aFrame = nsLayoutUtils::LastContinuationOrIBSplitSibling(aFrame);
210
}
211
212
for (auto displayItem : LayerAnimationInfo::sDisplayItemTypes) {
213
// For transform animations, the animation is on the primary frame but
214
// |aFrame| is the style frame.
215
const nsIFrame* frameToQuery =
216
displayItem == DisplayItemType::TYPE_TRANSFORM
217
? nsLayoutUtils::GetPrimaryFrameFromStyleFrame(aFrame)
218
: aFrame;
219
RefPtr<WebRenderAnimationData> animationData =
220
GetWebRenderUserData<WebRenderAnimationData>(frameToQuery,
221
(uint32_t)displayItem);
222
Maybe<uint64_t> generation;
223
if (animationData) {
224
generation = animationData->GetAnimationInfo().GetAnimationGeneration();
225
}
226
aCallback(generation, displayItem);
227
}
228
return;
229
}
230
231
FrameLayerBuilder::EnumerateGenerationForDedicatedLayers(aFrame, aCallback);
232
}
233
234
} // namespace layers
235
} // namespace mozilla