Line data Source code
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 "AnimationHelper.h"
8 : #include "mozilla/ComputedTimingFunction.h" // for ComputedTimingFunction
9 : #include "mozilla/dom/AnimationEffectReadOnlyBinding.h" // for dom::FillMode
10 : #include "mozilla/dom/KeyframeEffectBinding.h" // for dom::IterationComposite
11 : #include "mozilla/dom/KeyframeEffectReadOnly.h" // for dom::KeyFrameEffectReadOnly
12 : #include "mozilla/layers/CompositorThread.h" // for CompositorThreadHolder
13 : #include "mozilla/layers/LayerAnimationUtils.h" // for TimingFunctionToComputedTimingFunction
14 : #include "mozilla/StyleAnimationValue.h" // for StyleAnimationValue, etc
15 : #include "nsDeviceContext.h" // for AppUnitsPerCSSPixel
16 : #include "nsDisplayList.h" // for nsDisplayTransform, etc
17 :
18 : namespace mozilla {
19 : namespace layers {
20 :
21 0 : struct StyleAnimationValueCompositePair {
22 : StyleAnimationValue mValue;
23 : dom::CompositeOperation mComposite;
24 : };
25 :
26 : void
27 29 : CompositorAnimationStorage::Clear()
28 : {
29 29 : MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
30 :
31 29 : mAnimatedValues.Clear();
32 29 : mAnimations.Clear();
33 29 : }
34 :
35 : void
36 0 : CompositorAnimationStorage::ClearById(const uint64_t& aId)
37 : {
38 0 : MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
39 :
40 0 : mAnimatedValues.Remove(aId);
41 0 : mAnimations.Remove(aId);
42 0 : }
43 :
44 : AnimatedValue*
45 0 : CompositorAnimationStorage::GetAnimatedValue(const uint64_t& aId) const
46 : {
47 0 : MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
48 0 : return mAnimatedValues.Get(aId);
49 : }
50 :
51 : Maybe<float>
52 0 : CompositorAnimationStorage::GetAnimationOpacity(const uint64_t& aId) const
53 : {
54 0 : auto value = GetAnimatedValue(aId);
55 0 : if (!value || value->mType != AnimatedValue::OPACITY) {
56 0 : return Nothing();
57 : }
58 :
59 0 : return Some(value->mOpacity);
60 : }
61 :
62 : Maybe<gfx::Matrix4x4>
63 0 : CompositorAnimationStorage::GetAnimationTransform(const uint64_t& aId) const
64 : {
65 0 : auto value = GetAnimatedValue(aId);
66 0 : if (!value || value->mType != AnimatedValue::TRANSFORM) {
67 0 : return Nothing();
68 : }
69 :
70 0 : gfx::Matrix4x4 transform = value->mTransform.mFrameTransform;
71 0 : const TransformData& data = value->mTransform.mData;
72 0 : float scale = data.appUnitsPerDevPixel();
73 0 : gfx::Point3D transformOrigin = data.transformOrigin();
74 :
75 : // Undo the rebasing applied by
76 : // nsDisplayTransform::GetResultingTransformMatrixInternal
77 0 : transform.ChangeBasis(-transformOrigin);
78 :
79 : // Convert to CSS pixels (this undoes the operations performed by
80 : // nsStyleTransformMatrix::ProcessTranslatePart which is called from
81 : // nsDisplayTransform::GetResultingTransformMatrix)
82 : double devPerCss =
83 0 : double(scale) / double(nsDeviceContext::AppUnitsPerCSSPixel());
84 0 : transform._41 *= devPerCss;
85 0 : transform._42 *= devPerCss;
86 0 : transform._43 *= devPerCss;
87 :
88 0 : return Some(transform);
89 : }
90 :
91 : void
92 0 : CompositorAnimationStorage::SetAnimatedValue(uint64_t aId,
93 : gfx::Matrix4x4&& aTransformInDevSpace,
94 : gfx::Matrix4x4&& aFrameTransform,
95 : const TransformData& aData)
96 : {
97 0 : MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
98 : AnimatedValue* value = new AnimatedValue(Move(aTransformInDevSpace),
99 : Move(aFrameTransform),
100 0 : aData);
101 0 : mAnimatedValues.Put(aId, value);
102 0 : }
103 :
104 : void
105 0 : CompositorAnimationStorage::SetAnimatedValue(uint64_t aId,
106 : gfx::Matrix4x4&& aTransformInDevSpace)
107 : {
108 0 : MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
109 0 : const TransformData dontCare = {};
110 : AnimatedValue* value = new AnimatedValue(Move(aTransformInDevSpace),
111 0 : gfx::Matrix4x4(),
112 0 : dontCare);
113 0 : mAnimatedValues.Put(aId, value);
114 0 : }
115 :
116 : void
117 0 : CompositorAnimationStorage::SetAnimatedValue(uint64_t aId,
118 : const float& aOpacity)
119 : {
120 0 : MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
121 0 : AnimatedValue* value = new AnimatedValue(aOpacity);
122 0 : mAnimatedValues.Put(aId, value);
123 0 : }
124 :
125 : AnimationArray*
126 0 : CompositorAnimationStorage::GetAnimations(const uint64_t& aId) const
127 : {
128 0 : MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
129 0 : return mAnimations.Get(aId);
130 : }
131 :
132 : void
133 0 : CompositorAnimationStorage::SetAnimations(uint64_t aId, const AnimationArray& aValue)
134 : {
135 0 : MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
136 0 : AnimationArray* value = new AnimationArray(aValue);
137 0 : mAnimations.Put(aId, value);
138 0 : }
139 :
140 : static StyleAnimationValue
141 0 : SampleValue(double aPortion, const layers::Animation& aAnimation,
142 : const StyleAnimationValueCompositePair& aStart,
143 : const StyleAnimationValueCompositePair& aEnd,
144 : const StyleAnimationValue& aLastValue,
145 : uint64_t aCurrentIteration,
146 : const StyleAnimationValue& aUnderlyingValue)
147 : {
148 0 : NS_ASSERTION(aStart.mValue.IsNull() || aEnd.mValue.IsNull() ||
149 : aStart.mValue.GetUnit() == aEnd.mValue.GetUnit(),
150 : "Must have same unit");
151 :
152 : StyleAnimationValue startValue =
153 0 : dom::KeyframeEffectReadOnly::CompositeValue(aAnimation.property(),
154 : aStart.mValue,
155 : aUnderlyingValue,
156 0 : aStart.mComposite);
157 : StyleAnimationValue endValue =
158 0 : dom::KeyframeEffectReadOnly::CompositeValue(aAnimation.property(),
159 : aEnd.mValue,
160 : aUnderlyingValue,
161 0 : aEnd.mComposite);
162 :
163 : // Iteration composition for accumulate
164 0 : if (static_cast<dom::IterationCompositeOperation>
165 0 : (aAnimation.iterationComposite()) ==
166 0 : dom::IterationCompositeOperation::Accumulate &&
167 : aCurrentIteration > 0) {
168 : // FIXME: Bug 1293492: Add a utility function to calculate both of
169 : // below StyleAnimationValues.
170 : startValue =
171 0 : StyleAnimationValue::Accumulate(aAnimation.property(),
172 0 : aLastValue.IsNull()
173 : ? aUnderlyingValue
174 : : aLastValue,
175 0 : Move(startValue),
176 0 : aCurrentIteration);
177 : endValue =
178 0 : StyleAnimationValue::Accumulate(aAnimation.property(),
179 0 : aLastValue.IsNull()
180 : ? aUnderlyingValue
181 : : aLastValue,
182 0 : Move(endValue),
183 0 : aCurrentIteration);
184 : }
185 :
186 0 : StyleAnimationValue interpolatedValue;
187 : // This should never fail because we only pass transform and opacity values
188 : // to the compositor and they should never fail to interpolate.
189 : DebugOnly<bool> uncomputeResult =
190 0 : StyleAnimationValue::Interpolate(aAnimation.property(),
191 : startValue, endValue,
192 0 : aPortion, interpolatedValue);
193 0 : MOZ_ASSERT(uncomputeResult, "could not uncompute value");
194 0 : return interpolatedValue;
195 : }
196 :
197 : bool
198 215 : AnimationHelper::SampleAnimationForEachNode(TimeStamp aTime,
199 : AnimationArray& aAnimations,
200 : InfallibleTArray<AnimData>& aAnimationData,
201 : StyleAnimationValue& aAnimationValue,
202 : bool& aHasInEffectAnimations)
203 : {
204 215 : bool activeAnimations = false;
205 :
206 215 : if (aAnimations.IsEmpty()) {
207 215 : return activeAnimations;
208 : }
209 :
210 : // Process in order, since later aAnimations override earlier ones.
211 0 : for (size_t i = 0, iEnd = aAnimations.Length(); i < iEnd; ++i) {
212 0 : Animation& animation = aAnimations[i];
213 0 : AnimData& animData = aAnimationData[i];
214 :
215 0 : activeAnimations = true;
216 :
217 0 : MOZ_ASSERT((!animation.originTime().IsNull() &&
218 : animation.startTime().type() ==
219 : MaybeTimeDuration::TTimeDuration) ||
220 : animation.isNotPlaying(),
221 : "If we are playing, we should have an origin time and a start"
222 : " time");
223 : // If the animation is not currently playing, e.g. paused or
224 : // finished, then use the hold time to stay at the same position.
225 : TimeDuration elapsedDuration =
226 0 : animation.isNotPlaying() ||
227 0 : animation.startTime().type() != MaybeTimeDuration::TTimeDuration
228 0 : ? animation.holdTime()
229 0 : : (aTime - animation.originTime() -
230 0 : animation.startTime().get_TimeDuration())
231 0 : .MultDouble(animation.playbackRate());
232 : TimingParams timing {
233 0 : animation.duration(),
234 0 : animation.delay(),
235 0 : animation.endDelay(),
236 0 : animation.iterations(),
237 0 : animation.iterationStart(),
238 0 : static_cast<dom::PlaybackDirection>(animation.direction()),
239 0 : static_cast<dom::FillMode>(animation.fillMode()),
240 0 : Move(AnimationUtils::TimingFunctionToComputedTimingFunction(
241 0 : animation.easingFunction()))
242 0 : };
243 :
244 : ComputedTiming computedTiming =
245 : dom::AnimationEffectReadOnly::GetComputedTimingAt(
246 0 : Nullable<TimeDuration>(elapsedDuration), timing,
247 0 : animation.playbackRate());
248 :
249 0 : if (computedTiming.mProgress.IsNull()) {
250 0 : continue;
251 : }
252 :
253 0 : uint32_t segmentIndex = 0;
254 0 : size_t segmentSize = animation.segments().Length();
255 0 : AnimationSegment* segment = animation.segments().Elements();
256 0 : while (segment->endPortion() < computedTiming.mProgress.Value() &&
257 0 : segmentIndex < segmentSize - 1) {
258 0 : ++segment;
259 0 : ++segmentIndex;
260 : }
261 :
262 : double positionInSegment =
263 0 : (computedTiming.mProgress.Value() - segment->startPortion()) /
264 0 : (segment->endPortion() - segment->startPortion());
265 :
266 : double portion =
267 0 : ComputedTimingFunction::GetPortion(animData.mFunctions[segmentIndex],
268 : positionInSegment,
269 0 : computedTiming.mBeforeFlag);
270 :
271 : StyleAnimationValueCompositePair from {
272 0 : animData.mStartValues[segmentIndex],
273 0 : static_cast<dom::CompositeOperation>(segment->startComposite())
274 0 : };
275 : StyleAnimationValueCompositePair to {
276 0 : animData.mEndValues[segmentIndex],
277 0 : static_cast<dom::CompositeOperation>(segment->endComposite())
278 0 : };
279 : // interpolate the property
280 0 : aAnimationValue = SampleValue(portion,
281 : animation,
282 : from, to,
283 0 : animData.mEndValues.LastElement(),
284 : computedTiming.mCurrentIteration,
285 0 : aAnimationValue);
286 0 : aHasInEffectAnimations = true;
287 : }
288 :
289 : #ifdef DEBUG
290 : // Sanity check that all of animation data are the same.
291 0 : const AnimationData& lastData = aAnimations.LastElement().data();
292 0 : for (const Animation& animation : aAnimations) {
293 0 : const AnimationData& data = animation.data();
294 0 : MOZ_ASSERT(data.type() == lastData.type(),
295 : "The type of AnimationData should be the same");
296 0 : if (data.type() == AnimationData::Tnull_t) {
297 0 : continue;
298 : }
299 :
300 0 : MOZ_ASSERT(data.type() == AnimationData::TTransformData);
301 0 : const TransformData& transformData = data.get_TransformData();
302 0 : const TransformData& lastTransformData = lastData.get_TransformData();
303 0 : MOZ_ASSERT(transformData.origin() == lastTransformData.origin() &&
304 : transformData.transformOrigin() ==
305 : lastTransformData.transformOrigin() &&
306 : transformData.bounds() == lastTransformData.bounds() &&
307 : transformData.appUnitsPerDevPixel() ==
308 : lastTransformData.appUnitsPerDevPixel(),
309 : "All of members of TransformData should be the same");
310 : }
311 : #endif
312 0 : return activeAnimations;
313 : }
314 :
315 : static inline void
316 0 : SetCSSAngle(const CSSAngle& aAngle, nsCSSValue& aValue)
317 : {
318 0 : aValue.SetFloatValue(aAngle.value(), nsCSSUnit(aAngle.unit()));
319 0 : }
320 :
321 : static nsCSSValueSharedList*
322 0 : CreateCSSValueList(const InfallibleTArray<TransformFunction>& aFunctions)
323 : {
324 0 : nsAutoPtr<nsCSSValueList> result;
325 0 : nsCSSValueList** resultTail = getter_Transfers(result);
326 0 : for (uint32_t i = 0; i < aFunctions.Length(); i++) {
327 0 : RefPtr<nsCSSValue::Array> arr;
328 0 : switch (aFunctions[i].type()) {
329 : case TransformFunction::TRotationX:
330 : {
331 0 : const CSSAngle& angle = aFunctions[i].get_RotationX().angle();
332 0 : arr = StyleAnimationValue::AppendTransformFunction(eCSSKeyword_rotatex,
333 0 : resultTail);
334 0 : SetCSSAngle(angle, arr->Item(1));
335 0 : break;
336 : }
337 : case TransformFunction::TRotationY:
338 : {
339 0 : const CSSAngle& angle = aFunctions[i].get_RotationY().angle();
340 0 : arr = StyleAnimationValue::AppendTransformFunction(eCSSKeyword_rotatey,
341 0 : resultTail);
342 0 : SetCSSAngle(angle, arr->Item(1));
343 0 : break;
344 : }
345 : case TransformFunction::TRotationZ:
346 : {
347 0 : const CSSAngle& angle = aFunctions[i].get_RotationZ().angle();
348 0 : arr = StyleAnimationValue::AppendTransformFunction(eCSSKeyword_rotatez,
349 0 : resultTail);
350 0 : SetCSSAngle(angle, arr->Item(1));
351 0 : break;
352 : }
353 : case TransformFunction::TRotation:
354 : {
355 0 : const CSSAngle& angle = aFunctions[i].get_Rotation().angle();
356 0 : arr = StyleAnimationValue::AppendTransformFunction(eCSSKeyword_rotate,
357 0 : resultTail);
358 0 : SetCSSAngle(angle, arr->Item(1));
359 0 : break;
360 : }
361 : case TransformFunction::TRotation3D:
362 : {
363 0 : float x = aFunctions[i].get_Rotation3D().x();
364 0 : float y = aFunctions[i].get_Rotation3D().y();
365 0 : float z = aFunctions[i].get_Rotation3D().z();
366 0 : const CSSAngle& angle = aFunctions[i].get_Rotation3D().angle();
367 : arr =
368 0 : StyleAnimationValue::AppendTransformFunction(eCSSKeyword_rotate3d,
369 0 : resultTail);
370 0 : arr->Item(1).SetFloatValue(x, eCSSUnit_Number);
371 0 : arr->Item(2).SetFloatValue(y, eCSSUnit_Number);
372 0 : arr->Item(3).SetFloatValue(z, eCSSUnit_Number);
373 0 : SetCSSAngle(angle, arr->Item(4));
374 0 : break;
375 : }
376 : case TransformFunction::TScale:
377 : {
378 : arr =
379 0 : StyleAnimationValue::AppendTransformFunction(eCSSKeyword_scale3d,
380 0 : resultTail);
381 0 : arr->Item(1).SetFloatValue(aFunctions[i].get_Scale().x(), eCSSUnit_Number);
382 0 : arr->Item(2).SetFloatValue(aFunctions[i].get_Scale().y(), eCSSUnit_Number);
383 0 : arr->Item(3).SetFloatValue(aFunctions[i].get_Scale().z(), eCSSUnit_Number);
384 0 : break;
385 : }
386 : case TransformFunction::TTranslation:
387 : {
388 : arr =
389 0 : StyleAnimationValue::AppendTransformFunction(eCSSKeyword_translate3d,
390 0 : resultTail);
391 0 : arr->Item(1).SetFloatValue(aFunctions[i].get_Translation().x(), eCSSUnit_Pixel);
392 0 : arr->Item(2).SetFloatValue(aFunctions[i].get_Translation().y(), eCSSUnit_Pixel);
393 0 : arr->Item(3).SetFloatValue(aFunctions[i].get_Translation().z(), eCSSUnit_Pixel);
394 0 : break;
395 : }
396 : case TransformFunction::TSkewX:
397 : {
398 0 : const CSSAngle& x = aFunctions[i].get_SkewX().x();
399 0 : arr = StyleAnimationValue::AppendTransformFunction(eCSSKeyword_skewx,
400 0 : resultTail);
401 0 : SetCSSAngle(x, arr->Item(1));
402 0 : break;
403 : }
404 : case TransformFunction::TSkewY:
405 : {
406 0 : const CSSAngle& y = aFunctions[i].get_SkewY().y();
407 0 : arr = StyleAnimationValue::AppendTransformFunction(eCSSKeyword_skewy,
408 0 : resultTail);
409 0 : SetCSSAngle(y, arr->Item(1));
410 0 : break;
411 : }
412 : case TransformFunction::TSkew:
413 : {
414 0 : const CSSAngle& x = aFunctions[i].get_Skew().x();
415 0 : const CSSAngle& y = aFunctions[i].get_Skew().y();
416 0 : arr = StyleAnimationValue::AppendTransformFunction(eCSSKeyword_skew,
417 0 : resultTail);
418 0 : SetCSSAngle(x, arr->Item(1));
419 0 : SetCSSAngle(y, arr->Item(2));
420 0 : break;
421 : }
422 : case TransformFunction::TTransformMatrix:
423 : {
424 : arr =
425 0 : StyleAnimationValue::AppendTransformFunction(eCSSKeyword_matrix3d,
426 0 : resultTail);
427 0 : const gfx::Matrix4x4& matrix = aFunctions[i].get_TransformMatrix().value();
428 0 : arr->Item(1).SetFloatValue(matrix._11, eCSSUnit_Number);
429 0 : arr->Item(2).SetFloatValue(matrix._12, eCSSUnit_Number);
430 0 : arr->Item(3).SetFloatValue(matrix._13, eCSSUnit_Number);
431 0 : arr->Item(4).SetFloatValue(matrix._14, eCSSUnit_Number);
432 0 : arr->Item(5).SetFloatValue(matrix._21, eCSSUnit_Number);
433 0 : arr->Item(6).SetFloatValue(matrix._22, eCSSUnit_Number);
434 0 : arr->Item(7).SetFloatValue(matrix._23, eCSSUnit_Number);
435 0 : arr->Item(8).SetFloatValue(matrix._24, eCSSUnit_Number);
436 0 : arr->Item(9).SetFloatValue(matrix._31, eCSSUnit_Number);
437 0 : arr->Item(10).SetFloatValue(matrix._32, eCSSUnit_Number);
438 0 : arr->Item(11).SetFloatValue(matrix._33, eCSSUnit_Number);
439 0 : arr->Item(12).SetFloatValue(matrix._34, eCSSUnit_Number);
440 0 : arr->Item(13).SetFloatValue(matrix._41, eCSSUnit_Number);
441 0 : arr->Item(14).SetFloatValue(matrix._42, eCSSUnit_Number);
442 0 : arr->Item(15).SetFloatValue(matrix._43, eCSSUnit_Number);
443 0 : arr->Item(16).SetFloatValue(matrix._44, eCSSUnit_Number);
444 0 : break;
445 : }
446 : case TransformFunction::TPerspective:
447 : {
448 0 : float perspective = aFunctions[i].get_Perspective().value();
449 : arr =
450 0 : StyleAnimationValue::AppendTransformFunction(eCSSKeyword_perspective,
451 0 : resultTail);
452 0 : arr->Item(1).SetFloatValue(perspective, eCSSUnit_Pixel);
453 0 : break;
454 : }
455 : default:
456 0 : NS_ASSERTION(false, "All functions should be implemented?");
457 : }
458 : }
459 0 : if (aFunctions.Length() == 0) {
460 0 : result = new nsCSSValueList();
461 0 : result->mValue.SetNoneValue();
462 : }
463 0 : return new nsCSSValueSharedList(result.forget());
464 : }
465 :
466 : static StyleAnimationValue
467 0 : ToStyleAnimationValue(const Animatable& aAnimatable)
468 : {
469 0 : StyleAnimationValue result;
470 :
471 0 : switch (aAnimatable.type()) {
472 : case Animatable::Tnull_t:
473 0 : break;
474 : case Animatable::TArrayOfTransformFunction: {
475 : const InfallibleTArray<TransformFunction>& transforms =
476 0 : aAnimatable.get_ArrayOfTransformFunction();
477 0 : result.SetTransformValue(CreateCSSValueList(transforms));
478 0 : break;
479 : }
480 : case Animatable::Tfloat:
481 0 : result.SetFloatValue(aAnimatable.get_float());
482 0 : break;
483 : default:
484 0 : MOZ_ASSERT_UNREACHABLE("Unsupported type");
485 : }
486 :
487 0 : return result;
488 : }
489 :
490 : void
491 124 : AnimationHelper::SetAnimations(AnimationArray& aAnimations,
492 : InfallibleTArray<AnimData>& aAnimData,
493 : StyleAnimationValue& aBaseAnimationStyle)
494 : {
495 124 : for (uint32_t i = 0; i < aAnimations.Length(); i++) {
496 0 : Animation& animation = aAnimations[i];
497 : // Adjust fill mode to fill forwards so that if the main thread is delayed
498 : // in clearing this animation we don't introduce flicker by jumping back to
499 : // the old underlying value
500 0 : switch (static_cast<dom::FillMode>(animation.fillMode())) {
501 : case dom::FillMode::None:
502 0 : animation.fillMode() = static_cast<uint8_t>(dom::FillMode::Forwards);
503 0 : break;
504 : case dom::FillMode::Backwards:
505 0 : animation.fillMode() = static_cast<uint8_t>(dom::FillMode::Both);
506 0 : break;
507 : default:
508 0 : break;
509 : }
510 :
511 0 : if (animation.baseStyle().type() != Animatable::Tnull_t) {
512 0 : aBaseAnimationStyle = ToStyleAnimationValue(animation.baseStyle());
513 : }
514 :
515 0 : AnimData* data = aAnimData.AppendElement();
516 : InfallibleTArray<Maybe<ComputedTimingFunction>>& functions =
517 0 : data->mFunctions;
518 0 : const InfallibleTArray<AnimationSegment>& segments = animation.segments();
519 0 : for (uint32_t j = 0; j < segments.Length(); j++) {
520 0 : TimingFunction tf = segments.ElementAt(j).sampleFn();
521 :
522 : Maybe<ComputedTimingFunction> ctf =
523 0 : AnimationUtils::TimingFunctionToComputedTimingFunction(tf);
524 0 : functions.AppendElement(ctf);
525 : }
526 :
527 : // Precompute the StyleAnimationValues that we need if this is a transform
528 : // animation.
529 0 : InfallibleTArray<StyleAnimationValue>& startValues = data->mStartValues;
530 0 : InfallibleTArray<StyleAnimationValue>& endValues = data->mEndValues;
531 0 : for (const AnimationSegment& segment : segments) {
532 0 : startValues.AppendElement(ToStyleAnimationValue(segment.startState()));
533 0 : endValues.AppendElement(ToStyleAnimationValue(segment.endState()));
534 : }
535 : }
536 124 : }
537 :
538 : uint64_t
539 0 : AnimationHelper::GetNextCompositorAnimationsId()
540 : {
541 : static uint32_t sNextId = 0;
542 0 : ++sNextId;
543 :
544 0 : uint32_t procId = static_cast<uint32_t>(base::GetCurrentProcId());
545 0 : uint64_t nextId = procId;
546 0 : nextId = nextId << 32 | sNextId;
547 0 : return nextId;
548 : }
549 :
550 : void
551 0 : AnimationHelper::SampleAnimations(CompositorAnimationStorage* aStorage,
552 : TimeStamp aTime)
553 : {
554 0 : MOZ_ASSERT(aStorage);
555 :
556 : // Do nothing if there are no compositor animations
557 0 : if (!aStorage->AnimationsCount()) {
558 0 : return;
559 : }
560 :
561 : //Sample the animations in CompositorAnimationStorage
562 0 : for (auto iter = aStorage->ConstAnimationsTableIter();
563 0 : !iter.Done(); iter.Next()) {
564 0 : bool hasInEffectAnimations = false;
565 0 : AnimationArray* animations = iter.UserData();
566 0 : StyleAnimationValue animationValue;
567 0 : InfallibleTArray<AnimData> animationData;
568 : AnimationHelper::SetAnimations(*animations,
569 : animationData,
570 0 : animationValue);
571 : AnimationHelper::SampleAnimationForEachNode(aTime,
572 : *animations,
573 : animationData,
574 : animationValue,
575 0 : hasInEffectAnimations);
576 :
577 0 : if (!hasInEffectAnimations) {
578 0 : continue;
579 : }
580 :
581 : // Store the AnimatedValue
582 0 : Animation& animation = animations->LastElement();
583 0 : switch (animation.property()) {
584 : case eCSSProperty_opacity: {
585 0 : aStorage->SetAnimatedValue(iter.Key(),
586 0 : animationValue.GetFloatValue());
587 0 : break;
588 : }
589 : case eCSSProperty_transform: {
590 0 : nsCSSValueSharedList* list = animationValue.GetCSSValueSharedListValue();
591 0 : const TransformData& transformData = animation.data().get_TransformData();
592 0 : nsPoint origin = transformData.origin();
593 : // we expect all our transform data to arrive in device pixels
594 0 : gfx::Point3D transformOrigin = transformData.transformOrigin();
595 : nsDisplayTransform::FrameTransformProperties props(list,
596 0 : transformOrigin);
597 :
598 : gfx::Matrix4x4 transform =
599 : nsDisplayTransform::GetResultingTransformMatrix(props, origin,
600 0 : transformData.appUnitsPerDevPixel(),
601 0 : 0, &transformData.bounds());
602 0 : gfx::Matrix4x4 frameTransform = transform;
603 : // If the parent has perspective transform, then the offset into reference
604 : // frame coordinates is already on this transform. If not, then we need to ask
605 : // for it to be added here.
606 0 : if (!transformData.hasPerspectiveParent()) {
607 0 : nsLayoutUtils::PostTranslate(transform, origin,
608 0 : transformData.appUnitsPerDevPixel(),
609 0 : true);
610 : }
611 :
612 0 : transform.PostScale(transformData.inheritedXScale(),
613 0 : transformData.inheritedYScale(),
614 0 : 1);
615 :
616 0 : aStorage->SetAnimatedValue(iter.Key(),
617 0 : Move(transform), Move(frameTransform),
618 0 : transformData);
619 0 : break;
620 : }
621 : default:
622 0 : MOZ_ASSERT_UNREACHABLE("Unhandled animated property");
623 : }
624 : }
625 : }
626 :
627 : } // namespace layers
628 : } // namespace mozilla
|