|
1 /* vim: set shiftwidth=2 tabstop=8 autoindent cindent expandtab: */ |
|
2 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
3 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
5 |
|
6 #include "AnimationCommon.h" |
|
7 #include "nsTransitionManager.h" |
|
8 #include "nsAnimationManager.h" |
|
9 |
|
10 #include "gfxPlatform.h" |
|
11 #include "nsRuleData.h" |
|
12 #include "nsCSSValue.h" |
|
13 #include "nsStyleContext.h" |
|
14 #include "nsIFrame.h" |
|
15 #include "nsLayoutUtils.h" |
|
16 #include "mozilla/LookAndFeel.h" |
|
17 #include "Layers.h" |
|
18 #include "FrameLayerBuilder.h" |
|
19 #include "nsDisplayList.h" |
|
20 #include "mozilla/MemoryReporting.h" |
|
21 #include "RestyleManager.h" |
|
22 #include "nsStyleSet.h" |
|
23 #include "nsStyleChangeList.h" |
|
24 |
|
25 |
|
26 using mozilla::layers::Layer; |
|
27 |
|
28 namespace mozilla { |
|
29 namespace css { |
|
30 |
|
31 /* static */ bool |
|
32 IsGeometricProperty(nsCSSProperty aProperty) |
|
33 { |
|
34 switch (aProperty) { |
|
35 case eCSSProperty_bottom: |
|
36 case eCSSProperty_height: |
|
37 case eCSSProperty_left: |
|
38 case eCSSProperty_right: |
|
39 case eCSSProperty_top: |
|
40 case eCSSProperty_width: |
|
41 return true; |
|
42 default: |
|
43 return false; |
|
44 } |
|
45 } |
|
46 |
|
47 CommonAnimationManager::CommonAnimationManager(nsPresContext *aPresContext) |
|
48 : mPresContext(aPresContext) |
|
49 { |
|
50 PR_INIT_CLIST(&mElementData); |
|
51 } |
|
52 |
|
53 CommonAnimationManager::~CommonAnimationManager() |
|
54 { |
|
55 NS_ABORT_IF_FALSE(!mPresContext, "Disconnect should have been called"); |
|
56 } |
|
57 |
|
58 void |
|
59 CommonAnimationManager::Disconnect() |
|
60 { |
|
61 // Content nodes might outlive the transition or animation manager. |
|
62 RemoveAllElementData(); |
|
63 |
|
64 mPresContext = nullptr; |
|
65 } |
|
66 |
|
67 void |
|
68 CommonAnimationManager::RemoveAllElementData() |
|
69 { |
|
70 while (!PR_CLIST_IS_EMPTY(&mElementData)) { |
|
71 CommonElementAnimationData *head = |
|
72 static_cast<CommonElementAnimationData*>(PR_LIST_HEAD(&mElementData)); |
|
73 head->Destroy(); |
|
74 } |
|
75 } |
|
76 |
|
77 /* |
|
78 * nsISupports implementation |
|
79 */ |
|
80 |
|
81 NS_IMPL_ISUPPORTS(CommonAnimationManager, nsIStyleRuleProcessor) |
|
82 |
|
83 nsRestyleHint |
|
84 CommonAnimationManager::HasStateDependentStyle(StateRuleProcessorData* aData) |
|
85 { |
|
86 return nsRestyleHint(0); |
|
87 } |
|
88 |
|
89 nsRestyleHint |
|
90 CommonAnimationManager::HasStateDependentStyle(PseudoElementStateRuleProcessorData* aData) |
|
91 { |
|
92 return nsRestyleHint(0); |
|
93 } |
|
94 |
|
95 bool |
|
96 CommonAnimationManager::HasDocumentStateDependentStyle(StateRuleProcessorData* aData) |
|
97 { |
|
98 return false; |
|
99 } |
|
100 |
|
101 nsRestyleHint |
|
102 CommonAnimationManager::HasAttributeDependentStyle(AttributeRuleProcessorData* aData) |
|
103 { |
|
104 return nsRestyleHint(0); |
|
105 } |
|
106 |
|
107 /* virtual */ bool |
|
108 CommonAnimationManager::MediumFeaturesChanged(nsPresContext* aPresContext) |
|
109 { |
|
110 return false; |
|
111 } |
|
112 |
|
113 /* virtual */ size_t |
|
114 CommonAnimationManager::SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const |
|
115 { |
|
116 // Measurement of the following members may be added later if DMD finds it is |
|
117 // worthwhile: |
|
118 // - mElementData |
|
119 // |
|
120 // The following members are not measured |
|
121 // - mPresContext, because it's non-owning |
|
122 |
|
123 return 0; |
|
124 } |
|
125 |
|
126 /* virtual */ size_t |
|
127 CommonAnimationManager::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const |
|
128 { |
|
129 return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf); |
|
130 } |
|
131 |
|
132 /* static */ bool |
|
133 CommonAnimationManager::ExtractComputedValueForTransition( |
|
134 nsCSSProperty aProperty, |
|
135 nsStyleContext* aStyleContext, |
|
136 nsStyleAnimation::Value& aComputedValue) |
|
137 { |
|
138 bool result = |
|
139 nsStyleAnimation::ExtractComputedValue(aProperty, aStyleContext, |
|
140 aComputedValue); |
|
141 if (aProperty == eCSSProperty_visibility) { |
|
142 NS_ABORT_IF_FALSE(aComputedValue.GetUnit() == |
|
143 nsStyleAnimation::eUnit_Enumerated, |
|
144 "unexpected unit"); |
|
145 aComputedValue.SetIntValue(aComputedValue.GetIntValue(), |
|
146 nsStyleAnimation::eUnit_Visibility); |
|
147 } |
|
148 return result; |
|
149 } |
|
150 |
|
151 already_AddRefed<nsStyleContext> |
|
152 CommonAnimationManager::ReparentContent(nsIContent* aContent, |
|
153 nsStyleContext* aParentStyle) |
|
154 { |
|
155 nsStyleSet* styleSet = mPresContext->PresShell()->StyleSet(); |
|
156 nsIFrame* primaryFrame = nsLayoutUtils::GetStyleFrame(aContent); |
|
157 if (!primaryFrame) { |
|
158 return nullptr; |
|
159 } |
|
160 |
|
161 dom::Element* element = aContent->IsElement() |
|
162 ? aContent->AsElement() |
|
163 : nullptr; |
|
164 |
|
165 nsRefPtr<nsStyleContext> newStyle = |
|
166 styleSet->ReparentStyleContext(primaryFrame->StyleContext(), |
|
167 aParentStyle, element); |
|
168 primaryFrame->SetStyleContext(newStyle); |
|
169 ReparentBeforeAndAfter(element, primaryFrame, newStyle, styleSet); |
|
170 |
|
171 return newStyle.forget(); |
|
172 } |
|
173 |
|
174 /* static */ void |
|
175 CommonAnimationManager::ReparentBeforeAndAfter(dom::Element* aElement, |
|
176 nsIFrame* aPrimaryFrame, |
|
177 nsStyleContext* aNewStyle, |
|
178 nsStyleSet* aStyleSet) |
|
179 { |
|
180 if (nsIFrame* before = nsLayoutUtils::GetBeforeFrame(aPrimaryFrame)) { |
|
181 nsRefPtr<nsStyleContext> beforeStyle = |
|
182 aStyleSet->ReparentStyleContext(before->StyleContext(), |
|
183 aNewStyle, aElement); |
|
184 before->SetStyleContext(beforeStyle); |
|
185 } |
|
186 if (nsIFrame* after = nsLayoutUtils::GetBeforeFrame(aPrimaryFrame)) { |
|
187 nsRefPtr<nsStyleContext> afterStyle = |
|
188 aStyleSet->ReparentStyleContext(after->StyleContext(), |
|
189 aNewStyle, aElement); |
|
190 after->SetStyleContext(afterStyle); |
|
191 } |
|
192 } |
|
193 |
|
194 nsStyleContext* |
|
195 CommonAnimationManager::UpdateThrottledStyle(dom::Element* aElement, |
|
196 nsStyleContext* aParentStyle, |
|
197 nsStyleChangeList& aChangeList) |
|
198 { |
|
199 NS_ASSERTION(mPresContext->TransitionManager()->GetElementTransitions( |
|
200 aElement, |
|
201 nsCSSPseudoElements::ePseudo_NotPseudoElement, |
|
202 false) || |
|
203 mPresContext->AnimationManager()->GetElementAnimations( |
|
204 aElement, |
|
205 nsCSSPseudoElements::ePseudo_NotPseudoElement, |
|
206 false), "element not animated"); |
|
207 |
|
208 nsIFrame* primaryFrame = nsLayoutUtils::GetStyleFrame(aElement); |
|
209 if (!primaryFrame) { |
|
210 return nullptr; |
|
211 } |
|
212 |
|
213 nsStyleContext* oldStyle = primaryFrame->StyleContext(); |
|
214 nsRuleNode* ruleNode = oldStyle->RuleNode(); |
|
215 nsTArray<nsStyleSet::RuleAndLevel> rules; |
|
216 do { |
|
217 if (ruleNode->IsRoot()) { |
|
218 break; |
|
219 } |
|
220 |
|
221 nsStyleSet::RuleAndLevel curRule; |
|
222 curRule.mLevel = ruleNode->GetLevel(); |
|
223 |
|
224 if (curRule.mLevel == nsStyleSet::eAnimationSheet) { |
|
225 ElementAnimations* ea = |
|
226 mPresContext->AnimationManager()->GetElementAnimations( |
|
227 aElement, |
|
228 oldStyle->GetPseudoType(), |
|
229 false); |
|
230 NS_ASSERTION(ea, |
|
231 "Rule has level eAnimationSheet without animation on manager"); |
|
232 |
|
233 mPresContext->AnimationManager()->EnsureStyleRuleFor(ea); |
|
234 curRule.mRule = ea->mStyleRule; |
|
235 } else if (curRule.mLevel == nsStyleSet::eTransitionSheet) { |
|
236 ElementTransitions *et = |
|
237 mPresContext->TransitionManager()->GetElementTransitions( |
|
238 aElement, |
|
239 oldStyle->GetPseudoType(), |
|
240 false); |
|
241 NS_ASSERTION(et, |
|
242 "Rule has level eTransitionSheet without transition on manager"); |
|
243 |
|
244 et->EnsureStyleRuleFor(mPresContext->RefreshDriver()->MostRecentRefresh()); |
|
245 curRule.mRule = et->mStyleRule; |
|
246 } else { |
|
247 curRule.mRule = ruleNode->GetRule(); |
|
248 } |
|
249 |
|
250 if (curRule.mRule) { |
|
251 rules.AppendElement(curRule); |
|
252 } |
|
253 } while ((ruleNode = ruleNode->GetParent())); |
|
254 |
|
255 nsRefPtr<nsStyleContext> newStyle = mPresContext->PresShell()->StyleSet()-> |
|
256 ResolveStyleForRules(aParentStyle, oldStyle, rules); |
|
257 |
|
258 // We absolutely must call CalcStyleDifference in order to ensure the |
|
259 // new context has all the structs cached that the old context had. |
|
260 // We also need it for processing of the changes. |
|
261 nsChangeHint styleChange = |
|
262 oldStyle->CalcStyleDifference(newStyle, nsChangeHint(0)); |
|
263 aChangeList.AppendChange(primaryFrame, primaryFrame->GetContent(), |
|
264 styleChange); |
|
265 |
|
266 primaryFrame->SetStyleContext(newStyle); |
|
267 |
|
268 ReparentBeforeAndAfter(aElement, primaryFrame, newStyle, |
|
269 mPresContext->PresShell()->StyleSet()); |
|
270 |
|
271 return newStyle; |
|
272 } |
|
273 |
|
274 NS_IMPL_ISUPPORTS(AnimValuesStyleRule, nsIStyleRule) |
|
275 |
|
276 /* virtual */ void |
|
277 AnimValuesStyleRule::MapRuleInfoInto(nsRuleData* aRuleData) |
|
278 { |
|
279 nsStyleContext *contextParent = aRuleData->mStyleContext->GetParent(); |
|
280 if (contextParent && contextParent->HasPseudoElementData()) { |
|
281 // Don't apply transitions or animations to things inside of |
|
282 // pseudo-elements. |
|
283 // FIXME (Bug 522599): Add tests for this. |
|
284 return; |
|
285 } |
|
286 |
|
287 for (uint32_t i = 0, i_end = mPropertyValuePairs.Length(); i < i_end; ++i) { |
|
288 PropertyValuePair &cv = mPropertyValuePairs[i]; |
|
289 if (aRuleData->mSIDs & nsCachedStyleData::GetBitForSID( |
|
290 nsCSSProps::kSIDTable[cv.mProperty])) |
|
291 { |
|
292 nsCSSValue *prop = aRuleData->ValueFor(cv.mProperty); |
|
293 if (prop->GetUnit() == eCSSUnit_Null) { |
|
294 #ifdef DEBUG |
|
295 bool ok = |
|
296 #endif |
|
297 nsStyleAnimation::UncomputeValue(cv.mProperty, cv.mValue, *prop); |
|
298 NS_ABORT_IF_FALSE(ok, "could not store computed value"); |
|
299 } |
|
300 } |
|
301 } |
|
302 } |
|
303 |
|
304 #ifdef DEBUG |
|
305 /* virtual */ void |
|
306 AnimValuesStyleRule::List(FILE* out, int32_t aIndent) const |
|
307 { |
|
308 for (int32_t index = aIndent; --index >= 0; ) fputs(" ", out); |
|
309 fputs("[anim values] { ", out); |
|
310 for (uint32_t i = 0, i_end = mPropertyValuePairs.Length(); i < i_end; ++i) { |
|
311 const PropertyValuePair &pair = mPropertyValuePairs[i]; |
|
312 nsAutoString value; |
|
313 nsStyleAnimation::UncomputeValue(pair.mProperty, pair.mValue, value); |
|
314 fprintf(out, "%s: %s; ", nsCSSProps::GetStringValue(pair.mProperty).get(), |
|
315 NS_ConvertUTF16toUTF8(value).get()); |
|
316 } |
|
317 fputs("}\n", out); |
|
318 } |
|
319 #endif |
|
320 |
|
321 void |
|
322 ComputedTimingFunction::Init(const nsTimingFunction &aFunction) |
|
323 { |
|
324 mType = aFunction.mType; |
|
325 if (mType == nsTimingFunction::Function) { |
|
326 mTimingFunction.Init(aFunction.mFunc.mX1, aFunction.mFunc.mY1, |
|
327 aFunction.mFunc.mX2, aFunction.mFunc.mY2); |
|
328 } else { |
|
329 mSteps = aFunction.mSteps; |
|
330 } |
|
331 } |
|
332 |
|
333 static inline double |
|
334 StepEnd(uint32_t aSteps, double aPortion) |
|
335 { |
|
336 NS_ABORT_IF_FALSE(0.0 <= aPortion && aPortion <= 1.0, "out of range"); |
|
337 uint32_t step = uint32_t(aPortion * aSteps); // floor |
|
338 return double(step) / double(aSteps); |
|
339 } |
|
340 |
|
341 double |
|
342 ComputedTimingFunction::GetValue(double aPortion) const |
|
343 { |
|
344 switch (mType) { |
|
345 case nsTimingFunction::Function: |
|
346 return mTimingFunction.GetSplineValue(aPortion); |
|
347 case nsTimingFunction::StepStart: |
|
348 // There are diagrams in the spec that seem to suggest this check |
|
349 // and the bounds point should not be symmetric with StepEnd, but |
|
350 // should actually step up at rather than immediately after the |
|
351 // fraction points. However, we rely on rounding negative values |
|
352 // up to zero, so we can't do that. And it's not clear the spec |
|
353 // really meant it. |
|
354 return 1.0 - StepEnd(mSteps, 1.0 - aPortion); |
|
355 default: |
|
356 NS_ABORT_IF_FALSE(false, "bad type"); |
|
357 // fall through |
|
358 case nsTimingFunction::StepEnd: |
|
359 return StepEnd(mSteps, aPortion); |
|
360 } |
|
361 } |
|
362 |
|
363 } /* end sub-namespace css */ |
|
364 |
|
365 bool |
|
366 StyleAnimation::IsRunningAt(TimeStamp aTime) const |
|
367 { |
|
368 if (IsPaused() || mIterationDuration.ToMilliseconds() <= 0.0 || |
|
369 mStartTime.IsNull()) { |
|
370 return false; |
|
371 } |
|
372 |
|
373 double iterationsElapsed = ElapsedDurationAt(aTime) / mIterationDuration; |
|
374 return 0.0 <= iterationsElapsed && iterationsElapsed < mIterationCount; |
|
375 } |
|
376 |
|
377 bool |
|
378 StyleAnimation::HasAnimationOfProperty(nsCSSProperty aProperty) const |
|
379 { |
|
380 for (uint32_t propIdx = 0, propEnd = mProperties.Length(); |
|
381 propIdx != propEnd; ++propIdx) { |
|
382 if (aProperty == mProperties[propIdx].mProperty) { |
|
383 return true; |
|
384 } |
|
385 } |
|
386 return false; |
|
387 } |
|
388 |
|
389 namespace css { |
|
390 |
|
391 bool |
|
392 CommonElementAnimationData::CanAnimatePropertyOnCompositor(const dom::Element *aElement, |
|
393 nsCSSProperty aProperty, |
|
394 CanAnimateFlags aFlags) |
|
395 { |
|
396 bool shouldLog = nsLayoutUtils::IsAnimationLoggingEnabled(); |
|
397 if (!gfxPlatform::OffMainThreadCompositingEnabled()) { |
|
398 if (shouldLog) { |
|
399 nsCString message; |
|
400 message.AppendLiteral("Performance warning: Compositor disabled"); |
|
401 LogAsyncAnimationFailure(message); |
|
402 } |
|
403 return false; |
|
404 } |
|
405 |
|
406 nsIFrame* frame = nsLayoutUtils::GetStyleFrame(aElement); |
|
407 if (IsGeometricProperty(aProperty)) { |
|
408 if (shouldLog) { |
|
409 nsCString message; |
|
410 message.AppendLiteral("Performance warning: Async animation of geometric property '"); |
|
411 message.Append(nsCSSProps::GetStringValue(aProperty)); |
|
412 message.AppendLiteral("' is disabled"); |
|
413 LogAsyncAnimationFailure(message, aElement); |
|
414 } |
|
415 return false; |
|
416 } |
|
417 if (aProperty == eCSSProperty_transform) { |
|
418 if (frame->Preserves3D() && |
|
419 frame->Preserves3DChildren()) { |
|
420 if (shouldLog) { |
|
421 nsCString message; |
|
422 message.AppendLiteral("Gecko bug: Async animation of 'preserve-3d' transforms is not supported. See bug 779598"); |
|
423 LogAsyncAnimationFailure(message, aElement); |
|
424 } |
|
425 return false; |
|
426 } |
|
427 if (frame->IsSVGTransformed()) { |
|
428 if (shouldLog) { |
|
429 nsCString message; |
|
430 message.AppendLiteral("Gecko bug: Async 'transform' animations of frames with SVG transforms is not supported. See bug 779599"); |
|
431 LogAsyncAnimationFailure(message, aElement); |
|
432 } |
|
433 return false; |
|
434 } |
|
435 if (aFlags & CanAnimate_HasGeometricProperty) { |
|
436 if (shouldLog) { |
|
437 nsCString message; |
|
438 message.AppendLiteral("Performance warning: Async animation of 'transform' not possible due to presence of geometric properties"); |
|
439 LogAsyncAnimationFailure(message, aElement); |
|
440 } |
|
441 return false; |
|
442 } |
|
443 } |
|
444 bool enabled = nsLayoutUtils::AreAsyncAnimationsEnabled(); |
|
445 if (!enabled && shouldLog) { |
|
446 nsCString message; |
|
447 message.AppendLiteral("Performance warning: Async animations are disabled"); |
|
448 LogAsyncAnimationFailure(message); |
|
449 } |
|
450 bool propertyAllowed = (aProperty == eCSSProperty_transform) || |
|
451 (aProperty == eCSSProperty_opacity) || |
|
452 (aFlags & CanAnimate_AllowPartial); |
|
453 return enabled && propertyAllowed; |
|
454 } |
|
455 |
|
456 /* static */ bool |
|
457 CommonElementAnimationData::IsCompositorAnimationDisabledForFrame(nsIFrame* aFrame) |
|
458 { |
|
459 void* prop = aFrame->Properties().Get(nsIFrame::RefusedAsyncAnimation()); |
|
460 return bool(reinterpret_cast<intptr_t>(prop)); |
|
461 } |
|
462 |
|
463 /* static */ void |
|
464 CommonElementAnimationData::LogAsyncAnimationFailure(nsCString& aMessage, |
|
465 const nsIContent* aContent) |
|
466 { |
|
467 if (aContent) { |
|
468 aMessage.AppendLiteral(" ["); |
|
469 aMessage.Append(nsAtomCString(aContent->Tag())); |
|
470 |
|
471 nsIAtom* id = aContent->GetID(); |
|
472 if (id) { |
|
473 aMessage.AppendLiteral(" with id '"); |
|
474 aMessage.Append(nsAtomCString(aContent->GetID())); |
|
475 aMessage.AppendLiteral("'"); |
|
476 } |
|
477 aMessage.AppendLiteral("]"); |
|
478 } |
|
479 aMessage.AppendLiteral("\n"); |
|
480 printf_stderr(aMessage.get()); |
|
481 } |
|
482 |
|
483 bool |
|
484 CommonElementAnimationData::CanThrottleTransformChanges(TimeStamp aTime) |
|
485 { |
|
486 if (!nsLayoutUtils::AreAsyncAnimationsEnabled()) { |
|
487 return false; |
|
488 } |
|
489 |
|
490 // If we know that the animation cannot cause overflow, |
|
491 // we can just disable flushes for this animation. |
|
492 |
|
493 // If we don't show scrollbars, we don't care about overflow. |
|
494 if (LookAndFeel::GetInt(LookAndFeel::eIntID_ShowHideScrollbars) == 0) { |
|
495 return true; |
|
496 } |
|
497 |
|
498 // If this animation can cause overflow, we can throttle some of the ticks. |
|
499 if ((aTime - mStyleRuleRefreshTime) < TimeDuration::FromMilliseconds(200)) { |
|
500 return true; |
|
501 } |
|
502 |
|
503 // If the nearest scrollable ancestor has overflow:hidden, |
|
504 // we don't care about overflow. |
|
505 nsIScrollableFrame* scrollable = nsLayoutUtils::GetNearestScrollableFrame( |
|
506 nsLayoutUtils::GetStyleFrame(mElement)); |
|
507 if (!scrollable) { |
|
508 return true; |
|
509 } |
|
510 |
|
511 ScrollbarStyles ss = scrollable->GetScrollbarStyles(); |
|
512 if (ss.mVertical == NS_STYLE_OVERFLOW_HIDDEN && |
|
513 ss.mHorizontal == NS_STYLE_OVERFLOW_HIDDEN && |
|
514 scrollable->GetLogicalScrollPosition() == nsPoint(0, 0)) { |
|
515 return true; |
|
516 } |
|
517 |
|
518 return false; |
|
519 } |
|
520 |
|
521 bool |
|
522 CommonElementAnimationData::CanThrottleAnimation(TimeStamp aTime) |
|
523 { |
|
524 nsIFrame* frame = nsLayoutUtils::GetStyleFrame(mElement); |
|
525 if (!frame) { |
|
526 return false; |
|
527 } |
|
528 |
|
529 bool hasTransform = HasAnimationOfProperty(eCSSProperty_transform); |
|
530 bool hasOpacity = HasAnimationOfProperty(eCSSProperty_opacity); |
|
531 if (hasOpacity) { |
|
532 Layer* layer = FrameLayerBuilder::GetDedicatedLayer( |
|
533 frame, nsDisplayItem::TYPE_OPACITY); |
|
534 if (!layer || mAnimationGeneration > layer->GetAnimationGeneration()) { |
|
535 return false; |
|
536 } |
|
537 } |
|
538 |
|
539 if (!hasTransform) { |
|
540 return true; |
|
541 } |
|
542 |
|
543 Layer* layer = FrameLayerBuilder::GetDedicatedLayer( |
|
544 frame, nsDisplayItem::TYPE_TRANSFORM); |
|
545 if (!layer || mAnimationGeneration > layer->GetAnimationGeneration()) { |
|
546 return false; |
|
547 } |
|
548 |
|
549 return CanThrottleTransformChanges(aTime); |
|
550 } |
|
551 |
|
552 void |
|
553 CommonElementAnimationData::UpdateAnimationGeneration(nsPresContext* aPresContext) |
|
554 { |
|
555 mAnimationGeneration = |
|
556 aPresContext->RestyleManager()->GetAnimationGeneration(); |
|
557 } |
|
558 |
|
559 } |
|
560 } |