Bug 1637114 [wpt PR 23518] - Handle k-rate AudioParam inputs for AudioWorkletNode...
[gecko.git] / layout / painting / ActiveLayerTracker.cpp
blob41fafa48e44840efb9e6a2f4f7ed6dc70500985e
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/. */
7 #include "ActiveLayerTracker.h"
9 #include "mozilla/AnimationUtils.h"
10 #include "mozilla/ArrayUtils.h"
11 #include "mozilla/gfx/gfxVars.h"
12 #include "mozilla/gfx/Matrix.h"
13 #include "mozilla/EffectSet.h"
14 #include "mozilla/MotionPathUtils.h"
15 #include "mozilla/PodOperations.h"
16 #include "gfx2DGlue.h"
17 #include "nsExpirationTracker.h"
18 #include "nsContainerFrame.h"
19 #include "nsIContent.h"
20 #include "nsRefreshDriver.h"
21 #include "nsPIDOMWindow.h"
22 #include "mozilla/dom/Document.h"
23 #include "nsAnimationManager.h"
24 #include "nsStyleTransformMatrix.h"
25 #include "nsTransitionManager.h"
26 #include "nsDisplayList.h"
27 #include "nsDOMCSSDeclaration.h"
29 namespace mozilla {
31 using namespace gfx;
33 /**
34 * This tracks the state of a frame that may need active layers due to
35 * ongoing content changes or style changes that indicate animation.
37 * When no changes of *any* kind are detected after 75-100ms we remove this
38 * object. Because we only track all kinds of activity with a single
39 * nsExpirationTracker, it's possible a frame might remain active somewhat
40 * spuriously if different kinds of changes kept happening, but that almost
41 * certainly doesn't matter.
43 class LayerActivity {
44 public:
45 enum ActivityIndex {
46 ACTIVITY_OPACITY,
47 ACTIVITY_TRANSFORM,
48 ACTIVITY_LEFT,
49 ACTIVITY_TOP,
50 ACTIVITY_RIGHT,
51 ACTIVITY_BOTTOM,
52 ACTIVITY_BACKGROUND_POSITION,
54 ACTIVITY_SCALE,
55 ACTIVITY_TRIGGERED_REPAINT,
57 // keep as last item
58 ACTIVITY_COUNT
61 explicit LayerActivity(nsIFrame* aFrame)
62 : mFrame(aFrame), mContent(nullptr), mContentActive(false) {
63 PodArrayZero(mRestyleCounts);
65 ~LayerActivity();
66 nsExpirationState* GetExpirationState() { return &mState; }
67 uint8_t& RestyleCountForProperty(nsCSSPropertyID aProperty) {
68 return mRestyleCounts[GetActivityIndexForProperty(aProperty)];
71 static ActivityIndex GetActivityIndexForProperty(nsCSSPropertyID aProperty) {
72 switch (aProperty) {
73 case eCSSProperty_opacity:
74 return ACTIVITY_OPACITY;
75 case eCSSProperty_transform:
76 case eCSSProperty_translate:
77 case eCSSProperty_rotate:
78 case eCSSProperty_scale:
79 case eCSSProperty_offset_path:
80 case eCSSProperty_offset_distance:
81 case eCSSProperty_offset_rotate:
82 case eCSSProperty_offset_anchor:
83 // TODO: Bug 1559232: Add offset-position.
84 return ACTIVITY_TRANSFORM;
85 case eCSSProperty_left:
86 return ACTIVITY_LEFT;
87 case eCSSProperty_top:
88 return ACTIVITY_TOP;
89 case eCSSProperty_right:
90 return ACTIVITY_RIGHT;
91 case eCSSProperty_bottom:
92 return ACTIVITY_BOTTOM;
93 case eCSSProperty_background_position:
94 return ACTIVITY_BACKGROUND_POSITION;
95 case eCSSProperty_background_position_x:
96 return ACTIVITY_BACKGROUND_POSITION;
97 case eCSSProperty_background_position_y:
98 return ACTIVITY_BACKGROUND_POSITION;
99 default:
100 MOZ_ASSERT(false);
101 return ACTIVITY_OPACITY;
105 static ActivityIndex GetActivityIndexForPropertySet(
106 const nsCSSPropertyIDSet& aPropertySet) {
107 if (aPropertySet.IsSubsetOf(
108 nsCSSPropertyIDSet::TransformLikeProperties())) {
109 return ACTIVITY_TRANSFORM;
111 MOZ_ASSERT(
112 aPropertySet.IsSubsetOf(nsCSSPropertyIDSet::OpacityProperties()));
113 return ACTIVITY_OPACITY;
116 // While tracked, exactly one of mFrame or mContent is non-null, depending
117 // on whether this property is stored on a frame or on a content node.
118 // When this property is expired by the layer activity tracker, both mFrame
119 // and mContent are nulled-out and the property is deleted.
120 nsIFrame* mFrame;
121 nsIContent* mContent;
123 nsExpirationState mState;
125 // Previous scale due to the CSS transform property.
126 Maybe<Size> mPreviousTransformScale;
128 // The scroll frame during for which we most recently received a call to
129 // NotifyAnimatedFromScrollHandler.
130 WeakFrame mAnimatingScrollHandlerFrame;
131 // The set of activities that were triggered during
132 // mAnimatingScrollHandlerFrame's scroll event handler.
133 EnumSet<ActivityIndex> mScrollHandlerInducedActivity;
135 // Number of restyle operations detected
136 uint8_t mRestyleCounts[ACTIVITY_COUNT];
137 bool mContentActive;
140 class LayerActivityTracker final
141 : public nsExpirationTracker<LayerActivity, 4> {
142 public:
143 // 75-100ms is a good timeout period. We use 4 generations of 25ms each.
144 enum { GENERATION_MS = 100 };
146 explicit LayerActivityTracker(nsIEventTarget* aEventTarget)
147 : nsExpirationTracker<LayerActivity, 4>(
148 GENERATION_MS, "LayerActivityTracker", aEventTarget),
149 mDestroying(false) {}
150 ~LayerActivityTracker() override {
151 mDestroying = true;
152 AgeAllGenerations();
155 void NotifyExpired(LayerActivity* aObject) override;
157 public:
158 WeakFrame mCurrentScrollHandlerFrame;
160 private:
161 bool mDestroying;
164 static LayerActivityTracker* gLayerActivityTracker = nullptr;
166 LayerActivity::~LayerActivity() {
167 if (mFrame || mContent) {
168 NS_ASSERTION(gLayerActivityTracker, "Should still have a tracker");
169 gLayerActivityTracker->RemoveObject(this);
173 // Frames with this property have NS_FRAME_HAS_LAYER_ACTIVITY_PROPERTY set
174 NS_DECLARE_FRAME_PROPERTY_DELETABLE(LayerActivityProperty, LayerActivity)
176 void LayerActivityTracker::NotifyExpired(LayerActivity* aObject) {
177 if (!mDestroying && aObject->mAnimatingScrollHandlerFrame.IsAlive()) {
178 // Reset the restyle counts, but let the layer activity survive.
179 PodArrayZero(aObject->mRestyleCounts);
180 MarkUsed(aObject);
181 return;
184 RemoveObject(aObject);
186 nsIFrame* f = aObject->mFrame;
187 nsIContent* c = aObject->mContent;
188 aObject->mFrame = nullptr;
189 aObject->mContent = nullptr;
191 MOZ_ASSERT((f == nullptr) != (c == nullptr),
192 "A LayerActivity object should always have a reference to either "
193 "its frame or its content");
195 if (f) {
196 // The pres context might have been detached during the delay -
197 // that's fine, just skip the paint.
198 if (f->PresContext()->GetContainerWeak() && !gfxVars::UseWebRender()) {
199 f->SchedulePaint(nsIFrame::PAINT_DEFAULT, false);
201 f->RemoveStateBits(NS_FRAME_HAS_LAYER_ACTIVITY_PROPERTY);
202 f->RemoveProperty(LayerActivityProperty());
203 } else {
204 c->RemoveProperty(nsGkAtoms::LayerActivity);
208 static LayerActivity* GetLayerActivity(nsIFrame* aFrame) {
209 if (!aFrame->HasAnyStateBits(NS_FRAME_HAS_LAYER_ACTIVITY_PROPERTY)) {
210 return nullptr;
212 return aFrame->GetProperty(LayerActivityProperty());
215 static LayerActivity* GetLayerActivityForUpdate(nsIFrame* aFrame) {
216 LayerActivity* layerActivity = GetLayerActivity(aFrame);
217 if (layerActivity) {
218 gLayerActivityTracker->MarkUsed(layerActivity);
219 } else {
220 if (!gLayerActivityTracker) {
221 gLayerActivityTracker =
222 new LayerActivityTracker(GetMainThreadSerialEventTarget());
224 layerActivity = new LayerActivity(aFrame);
225 gLayerActivityTracker->AddObject(layerActivity);
226 aFrame->AddStateBits(NS_FRAME_HAS_LAYER_ACTIVITY_PROPERTY);
227 aFrame->SetProperty(LayerActivityProperty(), layerActivity);
229 return layerActivity;
232 static void IncrementMutationCount(uint8_t* aCount) {
233 *aCount = uint8_t(std::min(0xFF, *aCount + 1));
236 /* static */
237 void ActiveLayerTracker::TransferActivityToContent(nsIFrame* aFrame,
238 nsIContent* aContent) {
239 if (!aFrame->HasAnyStateBits(NS_FRAME_HAS_LAYER_ACTIVITY_PROPERTY)) {
240 return;
242 LayerActivity* layerActivity = aFrame->TakeProperty(LayerActivityProperty());
243 aFrame->RemoveStateBits(NS_FRAME_HAS_LAYER_ACTIVITY_PROPERTY);
244 if (!layerActivity) {
245 return;
247 layerActivity->mFrame = nullptr;
248 layerActivity->mContent = aContent;
249 aContent->SetProperty(nsGkAtoms::LayerActivity, layerActivity,
250 nsINode::DeleteProperty<LayerActivity>, true);
253 /* static */
254 void ActiveLayerTracker::TransferActivityToFrame(nsIContent* aContent,
255 nsIFrame* aFrame) {
256 auto* layerActivity = static_cast<LayerActivity*>(
257 aContent->TakeProperty(nsGkAtoms::LayerActivity));
258 if (!layerActivity) {
259 return;
261 layerActivity->mContent = nullptr;
262 layerActivity->mFrame = aFrame;
263 aFrame->AddStateBits(NS_FRAME_HAS_LAYER_ACTIVITY_PROPERTY);
264 aFrame->SetProperty(LayerActivityProperty(), layerActivity);
267 static void IncrementScaleRestyleCountIfNeeded(nsIFrame* aFrame,
268 LayerActivity* aActivity) {
269 const nsStyleDisplay* display = aFrame->StyleDisplay();
270 if (!display->HasTransformProperty() && !display->HasIndividualTransform() &&
271 display->mOffsetPath.IsNone()) {
272 // The transform was removed.
273 aActivity->mPreviousTransformScale = Nothing();
274 IncrementMutationCount(
275 &aActivity->mRestyleCounts[LayerActivity::ACTIVITY_SCALE]);
276 return;
279 // Compute the new scale due to the CSS transform property.
280 // Note: Motion path doesn't contribute to scale factor. (It only has 2d
281 // translate and 2d rotate, so we use Nothing() for it.)
282 nsStyleTransformMatrix::TransformReferenceBox refBox(aFrame);
283 Matrix4x4 transform = nsStyleTransformMatrix::ReadTransforms(
284 display->mTranslate, display->mRotate, display->mScale, Nothing(),
285 display->mTransform, refBox, AppUnitsPerCSSPixel());
286 Matrix transform2D;
287 if (!transform.Is2D(&transform2D)) {
288 // We don't attempt to handle 3D transforms; just assume the scale changed.
289 aActivity->mPreviousTransformScale = Nothing();
290 IncrementMutationCount(
291 &aActivity->mRestyleCounts[LayerActivity::ACTIVITY_SCALE]);
292 return;
295 Size scale = transform2D.ScaleFactors(true);
296 if (aActivity->mPreviousTransformScale == Some(scale)) {
297 return; // Nothing changed.
300 aActivity->mPreviousTransformScale = Some(scale);
301 IncrementMutationCount(
302 &aActivity->mRestyleCounts[LayerActivity::ACTIVITY_SCALE]);
305 /* static */
306 void ActiveLayerTracker::NotifyRestyle(nsIFrame* aFrame,
307 nsCSSPropertyID aProperty) {
308 LayerActivity* layerActivity = GetLayerActivityForUpdate(aFrame);
309 uint8_t& mutationCount = layerActivity->RestyleCountForProperty(aProperty);
310 IncrementMutationCount(&mutationCount);
312 if (nsCSSPropertyIDSet::TransformLikeProperties().HasProperty(aProperty)) {
313 IncrementScaleRestyleCountIfNeeded(aFrame, layerActivity);
317 /* static */
318 void ActiveLayerTracker::NotifyOffsetRestyle(nsIFrame* aFrame) {
319 LayerActivity* layerActivity = GetLayerActivityForUpdate(aFrame);
320 IncrementMutationCount(
321 &layerActivity->mRestyleCounts[LayerActivity::ACTIVITY_LEFT]);
322 IncrementMutationCount(
323 &layerActivity->mRestyleCounts[LayerActivity::ACTIVITY_TOP]);
324 IncrementMutationCount(
325 &layerActivity->mRestyleCounts[LayerActivity::ACTIVITY_RIGHT]);
326 IncrementMutationCount(
327 &layerActivity->mRestyleCounts[LayerActivity::ACTIVITY_BOTTOM]);
330 /* static */
331 void ActiveLayerTracker::NotifyAnimated(nsIFrame* aFrame,
332 nsCSSPropertyID aProperty,
333 const nsACString& aNewValue,
334 nsDOMCSSDeclaration* aDOMCSSDecl) {
335 LayerActivity* layerActivity = GetLayerActivityForUpdate(aFrame);
336 uint8_t& mutationCount = layerActivity->RestyleCountForProperty(aProperty);
337 if (mutationCount != 0xFF) {
338 nsAutoString oldValue;
339 aDOMCSSDecl->GetPropertyValue(aProperty, oldValue);
340 if (NS_ConvertUTF16toUTF8(oldValue) != aNewValue) {
341 // We know this is animated, so just hack the mutation count.
342 mutationCount = 0xFF;
347 /* static */
348 void ActiveLayerTracker::NotifyAnimatedFromScrollHandler(
349 nsIFrame* aFrame, nsCSSPropertyID aProperty, nsIFrame* aScrollFrame) {
350 if (aFrame->PresContext() != aScrollFrame->PresContext()) {
351 // Don't allow cross-document dependencies.
352 return;
354 LayerActivity* layerActivity = GetLayerActivityForUpdate(aFrame);
355 LayerActivity::ActivityIndex activityIndex =
356 LayerActivity::GetActivityIndexForProperty(aProperty);
358 if (layerActivity->mAnimatingScrollHandlerFrame.GetFrame() != aScrollFrame) {
359 // Discard any activity of a different scroll frame. We only track the
360 // most recent scroll handler induced activity.
361 layerActivity->mScrollHandlerInducedActivity.clear();
362 layerActivity->mAnimatingScrollHandlerFrame = aScrollFrame;
365 layerActivity->mScrollHandlerInducedActivity += activityIndex;
368 static bool IsPresContextInScriptAnimationCallback(
369 nsPresContext* aPresContext) {
370 if (aPresContext->RefreshDriver()->IsInRefresh()) {
371 return true;
373 // Treat timeouts/setintervals as scripted animation callbacks for our
374 // purposes.
375 nsPIDOMWindowInner* win = aPresContext->Document()->GetInnerWindow();
376 return win && win->IsRunningTimeout();
379 /* static */
380 void ActiveLayerTracker::NotifyInlineStyleRuleModified(
381 nsIFrame* aFrame, nsCSSPropertyID aProperty, const nsACString& aNewValue,
382 nsDOMCSSDeclaration* aDOMCSSDecl) {
383 if (IsPresContextInScriptAnimationCallback(aFrame->PresContext())) {
384 NotifyAnimated(aFrame, aProperty, aNewValue, aDOMCSSDecl);
386 if (gLayerActivityTracker &&
387 gLayerActivityTracker->mCurrentScrollHandlerFrame.IsAlive()) {
388 NotifyAnimatedFromScrollHandler(
389 aFrame, aProperty,
390 gLayerActivityTracker->mCurrentScrollHandlerFrame.GetFrame());
394 /* static */
395 void ActiveLayerTracker::NotifyNeedsRepaint(nsIFrame* aFrame) {
396 LayerActivity* layerActivity = GetLayerActivityForUpdate(aFrame);
397 if (IsPresContextInScriptAnimationCallback(aFrame->PresContext())) {
398 // This is mirroring NotifyInlineStyleRuleModified's NotifyAnimated logic.
399 // Just max out the restyle count if we're in an animation callback.
400 layerActivity->mRestyleCounts[LayerActivity::ACTIVITY_TRIGGERED_REPAINT] =
401 0xFF;
402 } else {
403 IncrementMutationCount(
404 &layerActivity
405 ->mRestyleCounts[LayerActivity::ACTIVITY_TRIGGERED_REPAINT]);
409 static bool CheckScrollInducedActivity(
410 LayerActivity* aLayerActivity, LayerActivity::ActivityIndex aActivityIndex,
411 nsDisplayListBuilder* aBuilder) {
412 if (!aLayerActivity->mScrollHandlerInducedActivity.contains(aActivityIndex) ||
413 !aLayerActivity->mAnimatingScrollHandlerFrame.IsAlive()) {
414 return false;
417 nsIScrollableFrame* scrollFrame =
418 do_QueryFrame(aLayerActivity->mAnimatingScrollHandlerFrame.GetFrame());
419 if (scrollFrame && (!aBuilder || scrollFrame->IsScrollingActive(aBuilder))) {
420 return true;
423 // The scroll frame has been destroyed or has become inactive. Clear it from
424 // the layer activity so that it can expire.
425 aLayerActivity->mAnimatingScrollHandlerFrame = nullptr;
426 aLayerActivity->mScrollHandlerInducedActivity.clear();
427 return false;
430 /* static */
431 bool ActiveLayerTracker::IsBackgroundPositionAnimated(
432 nsDisplayListBuilder* aBuilder, nsIFrame* aFrame) {
433 LayerActivity* layerActivity = GetLayerActivity(aFrame);
434 if (layerActivity) {
435 LayerActivity::ActivityIndex activityIndex =
436 LayerActivity::ActivityIndex::ACTIVITY_BACKGROUND_POSITION;
437 if (layerActivity->mRestyleCounts[activityIndex] >= 2) {
438 // If the frame needs to be repainted frequently, we probably don't get
439 // much from treating the property as animated, *unless* this frame's
440 // 'scale' (which includes the bounds changes of a rotation) is changing.
441 // Marking a scaling transform as animating allows us to avoid resizing
442 // the texture, even if we have to repaint the contents of that texture.
443 if (layerActivity
444 ->mRestyleCounts[LayerActivity::ACTIVITY_TRIGGERED_REPAINT] < 2) {
445 return true;
448 if (CheckScrollInducedActivity(layerActivity, activityIndex, aBuilder)) {
449 return true;
452 return nsLayoutUtils::HasEffectiveAnimation(
453 aFrame, nsCSSPropertyIDSet({eCSSProperty_background_position_x,
454 eCSSProperty_background_position_y}));
457 static bool IsMotionPathAnimated(nsDisplayListBuilder* aBuilder,
458 nsIFrame* aFrame) {
459 return ActiveLayerTracker::IsStyleAnimated(
460 aBuilder, aFrame, nsCSSPropertyIDSet{eCSSProperty_offset_path}) ||
461 (!aFrame->StyleDisplay()->mOffsetPath.IsNone() &&
462 ActiveLayerTracker::IsStyleAnimated(
463 aBuilder, aFrame,
464 nsCSSPropertyIDSet{eCSSProperty_offset_distance,
465 eCSSProperty_offset_rotate,
466 eCSSProperty_offset_anchor}));
469 /* static */
470 bool ActiveLayerTracker::IsTransformAnimated(nsDisplayListBuilder* aBuilder,
471 nsIFrame* aFrame) {
472 return IsStyleAnimated(aBuilder, aFrame,
473 nsCSSPropertyIDSet::CSSTransformProperties()) ||
474 IsMotionPathAnimated(aBuilder, aFrame);
477 /* static */
478 bool ActiveLayerTracker::IsTransformMaybeAnimated(nsIFrame* aFrame) {
479 return IsStyleAnimated(nullptr, aFrame,
480 nsCSSPropertyIDSet::CSSTransformProperties()) ||
481 IsMotionPathAnimated(nullptr, aFrame);
484 /* static */
485 bool ActiveLayerTracker::IsStyleAnimated(
486 nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
487 const nsCSSPropertyIDSet& aPropertySet) {
488 MOZ_ASSERT(
489 aPropertySet.IsSubsetOf(nsCSSPropertyIDSet::TransformLikeProperties()) ||
490 aPropertySet.IsSubsetOf(nsCSSPropertyIDSet::OpacityProperties()),
491 "Only subset of opacity or transform-like properties set calls this");
493 // For display:table content, transforms are applied to the table wrapper
494 // (primary frame) but their will-change style will be specified on the style
495 // frame and, unlike other transform properties, not inherited.
496 // As a result, for transform properties only we need to be careful to look up
497 // the will-change style on the _style_ frame.
498 const nsIFrame* styleFrame = nsLayoutUtils::GetStyleFrame(aFrame);
499 const nsCSSPropertyIDSet transformSet =
500 nsCSSPropertyIDSet::TransformLikeProperties();
501 if ((styleFrame && (styleFrame->StyleDisplay()->mWillChange.bits &
502 StyleWillChangeBits::TRANSFORM)) &&
503 aPropertySet.Intersects(transformSet) &&
504 (!aBuilder ||
505 aBuilder->IsInWillChangeBudget(aFrame, aFrame->GetSize()))) {
506 return true;
508 if ((aFrame->StyleDisplay()->mWillChange.bits &
509 StyleWillChangeBits::OPACITY) &&
510 aPropertySet.Intersects(nsCSSPropertyIDSet::OpacityProperties()) &&
511 (!aBuilder ||
512 aBuilder->IsInWillChangeBudget(aFrame, aFrame->GetSize()))) {
513 return true;
516 LayerActivity* layerActivity = GetLayerActivity(aFrame);
517 if (layerActivity) {
518 LayerActivity::ActivityIndex activityIndex =
519 LayerActivity::GetActivityIndexForPropertySet(aPropertySet);
520 if (layerActivity->mRestyleCounts[activityIndex] >= 2) {
521 // If the frame needs to be repainted frequently, we probably don't get
522 // much from treating the property as animated, *unless* this frame's
523 // 'scale' (which includes the bounds changes of a rotation) is changing.
524 // Marking a scaling transform as animating allows us to avoid resizing
525 // the texture, even if we have to repaint the contents of that texture.
526 if (layerActivity
527 ->mRestyleCounts[LayerActivity::ACTIVITY_TRIGGERED_REPAINT] <
528 2 ||
529 (aPropertySet.Intersects(transformSet) &&
530 IsScaleSubjectToAnimation(aFrame))) {
531 return true;
534 if (CheckScrollInducedActivity(layerActivity, activityIndex, aBuilder)) {
535 return true;
539 if (nsLayoutUtils::HasEffectiveAnimation(aFrame, aPropertySet)) {
540 return true;
543 if (!aPropertySet.Intersects(transformSet) ||
544 !aFrame->Combines3DTransformWithAncestors()) {
545 return false;
548 // For preserve-3d, we check if there is any transform animation on its parent
549 // frames in the 3d rendering context. If there is one, this function will
550 // return true.
551 return IsStyleAnimated(aBuilder, aFrame->GetParent(), aPropertySet);
554 /* static */
555 bool ActiveLayerTracker::IsOffsetStyleAnimated(nsIFrame* aFrame) {
556 LayerActivity* layerActivity = GetLayerActivity(aFrame);
557 if (layerActivity) {
558 if (layerActivity->mRestyleCounts[LayerActivity::ACTIVITY_LEFT] >= 2 ||
559 layerActivity->mRestyleCounts[LayerActivity::ACTIVITY_TOP] >= 2 ||
560 layerActivity->mRestyleCounts[LayerActivity::ACTIVITY_RIGHT] >= 2 ||
561 layerActivity->mRestyleCounts[LayerActivity::ACTIVITY_BOTTOM] >= 2) {
562 return true;
565 // We should also check for running CSS animations of these properties once
566 // bug 1009693 is fixed. Until that happens, layerization isn't useful for
567 // animations of these properties because we'll invalidate the layer contents
568 // on every change anyway.
569 // See bug 1151346 for a patch that adds a check for CSS animations.
570 return false;
573 /* static */
574 bool ActiveLayerTracker::IsScaleSubjectToAnimation(nsIFrame* aFrame) {
575 // Check whether JavaScript is animating this frame's scale.
576 LayerActivity* layerActivity = GetLayerActivity(aFrame);
577 if (layerActivity &&
578 layerActivity->mRestyleCounts[LayerActivity::ACTIVITY_SCALE] >= 2) {
579 return true;
582 return AnimationUtils::FrameHasAnimatedScale(aFrame);
585 /* static */
586 void ActiveLayerTracker::NotifyContentChange(nsIFrame* aFrame) {
587 LayerActivity* layerActivity = GetLayerActivityForUpdate(aFrame);
588 layerActivity->mContentActive = true;
591 /* static */
592 bool ActiveLayerTracker::IsContentActive(nsIFrame* aFrame) {
593 LayerActivity* layerActivity = GetLayerActivity(aFrame);
594 return layerActivity && layerActivity->mContentActive;
597 /* static */
598 void ActiveLayerTracker::SetCurrentScrollHandlerFrame(nsIFrame* aFrame) {
599 if (!gLayerActivityTracker) {
600 gLayerActivityTracker =
601 new LayerActivityTracker(GetMainThreadSerialEventTarget());
603 gLayerActivityTracker->mCurrentScrollHandlerFrame = aFrame;
606 /* static */
607 void ActiveLayerTracker::Shutdown() {
608 delete gLayerActivityTracker;
609 gLayerActivityTracker = nullptr;
612 } // namespace mozilla