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 "nsIScrollableFrame.h"
21 #include "nsRefreshDriver.h"
22 #include "nsPIDOMWindow.h"
23 #include "mozilla/dom/Document.h"
24 #include "nsAnimationManager.h"
25 #include "nsStyleTransformMatrix.h"
26 #include "nsTransitionManager.h"
27 #include "nsDisplayList.h"
28 #include "nsDOMCSSDeclaration.h"
29 #include "nsLayoutUtils.h"
36 * This tracks the state of a frame that may need active layers due to
37 * ongoing content changes or style changes that indicate animation.
39 * When no changes of *any* kind are detected after 75-100ms we remove this
40 * object. Because we only track all kinds of activity with a single
41 * nsExpirationTracker, it's possible a frame might remain active somewhat
42 * spuriously if different kinds of changes kept happening, but that almost
43 * certainly doesn't matter.
54 ACTIVITY_BACKGROUND_POSITION
,
57 ACTIVITY_TRIGGERED_REPAINT
,
63 explicit LayerActivity(nsIFrame
* aFrame
)
64 : mFrame(aFrame
), mContent(nullptr), mContentActive(false) {
65 PodArrayZero(mRestyleCounts
);
68 nsExpirationState
* GetExpirationState() { return &mState
; }
69 uint8_t& RestyleCountForProperty(nsCSSPropertyID aProperty
) {
70 return mRestyleCounts
[GetActivityIndexForProperty(aProperty
)];
73 static ActivityIndex
GetActivityIndexForProperty(nsCSSPropertyID aProperty
) {
75 case eCSSProperty_opacity
:
76 return ACTIVITY_OPACITY
;
77 case eCSSProperty_transform
:
78 case eCSSProperty_translate
:
79 case eCSSProperty_rotate
:
80 case eCSSProperty_scale
:
81 case eCSSProperty_offset_path
:
82 case eCSSProperty_offset_distance
:
83 case eCSSProperty_offset_rotate
:
84 case eCSSProperty_offset_anchor
:
85 // TODO: Bug 1559232: Add offset-position.
86 return ACTIVITY_TRANSFORM
;
87 case eCSSProperty_left
:
89 case eCSSProperty_top
:
91 case eCSSProperty_right
:
92 return ACTIVITY_RIGHT
;
93 case eCSSProperty_bottom
:
94 return ACTIVITY_BOTTOM
;
95 case eCSSProperty_background_position
:
96 return ACTIVITY_BACKGROUND_POSITION
;
97 case eCSSProperty_background_position_x
:
98 return ACTIVITY_BACKGROUND_POSITION
;
99 case eCSSProperty_background_position_y
:
100 return ACTIVITY_BACKGROUND_POSITION
;
103 return ACTIVITY_OPACITY
;
107 static ActivityIndex
GetActivityIndexForPropertySet(
108 const nsCSSPropertyIDSet
& aPropertySet
) {
109 if (aPropertySet
.IsSubsetOf(
110 nsCSSPropertyIDSet::TransformLikeProperties())) {
111 return ACTIVITY_TRANSFORM
;
114 aPropertySet
.IsSubsetOf(nsCSSPropertyIDSet::OpacityProperties()));
115 return ACTIVITY_OPACITY
;
118 // While tracked, exactly one of mFrame or mContent is non-null, depending
119 // on whether this property is stored on a frame or on a content node.
120 // When this property is expired by the layer activity tracker, both mFrame
121 // and mContent are nulled-out and the property is deleted.
123 nsIContent
* mContent
;
125 nsExpirationState mState
;
127 // Previous scale due to the CSS transform property.
128 Maybe
<Size
> mPreviousTransformScale
;
130 // The scroll frame during for which we most recently received a call to
131 // NotifyAnimatedFromScrollHandler.
132 WeakFrame mAnimatingScrollHandlerFrame
;
133 // The set of activities that were triggered during
134 // mAnimatingScrollHandlerFrame's scroll event handler.
135 EnumSet
<ActivityIndex
> mScrollHandlerInducedActivity
;
137 // Number of restyle operations detected
138 uint8_t mRestyleCounts
[ACTIVITY_COUNT
];
142 class LayerActivityTracker final
143 : public nsExpirationTracker
<LayerActivity
, 4> {
145 // 75-100ms is a good timeout period. We use 4 generations of 25ms each.
146 enum { GENERATION_MS
= 100 };
148 explicit LayerActivityTracker(nsIEventTarget
* aEventTarget
)
149 : nsExpirationTracker
<LayerActivity
, 4>(
150 GENERATION_MS
, "LayerActivityTracker", aEventTarget
),
151 mDestroying(false) {}
152 ~LayerActivityTracker() override
{
157 void NotifyExpired(LayerActivity
* aObject
) override
;
160 WeakFrame mCurrentScrollHandlerFrame
;
166 static LayerActivityTracker
* gLayerActivityTracker
= nullptr;
168 LayerActivity::~LayerActivity() {
169 if (mFrame
|| mContent
) {
170 NS_ASSERTION(gLayerActivityTracker
, "Should still have a tracker");
171 gLayerActivityTracker
->RemoveObject(this);
175 // Frames with this property have NS_FRAME_HAS_LAYER_ACTIVITY_PROPERTY set
176 NS_DECLARE_FRAME_PROPERTY_DELETABLE(LayerActivityProperty
, LayerActivity
)
178 void LayerActivityTracker::NotifyExpired(LayerActivity
* aObject
) {
179 if (!mDestroying
&& aObject
->mAnimatingScrollHandlerFrame
.IsAlive()) {
180 // Reset the restyle counts, but let the layer activity survive.
181 PodArrayZero(aObject
->mRestyleCounts
);
186 RemoveObject(aObject
);
188 nsIFrame
* f
= aObject
->mFrame
;
189 nsIContent
* c
= aObject
->mContent
;
190 aObject
->mFrame
= nullptr;
191 aObject
->mContent
= nullptr;
193 MOZ_ASSERT((f
== nullptr) != (c
== nullptr),
194 "A LayerActivity object should always have a reference to either "
195 "its frame or its content");
198 // The pres context might have been detached during the delay -
199 // that's fine, just skip the paint.
200 if (f
->PresContext()->GetContainerWeak() && !gfxVars::UseWebRender()) {
201 f
->SchedulePaint(nsIFrame::PAINT_DEFAULT
, false);
203 f
->RemoveStateBits(NS_FRAME_HAS_LAYER_ACTIVITY_PROPERTY
);
204 f
->RemoveProperty(LayerActivityProperty());
206 c
->RemoveProperty(nsGkAtoms::LayerActivity
);
210 static LayerActivity
* GetLayerActivity(nsIFrame
* aFrame
) {
211 if (!aFrame
->HasAnyStateBits(NS_FRAME_HAS_LAYER_ACTIVITY_PROPERTY
)) {
214 return aFrame
->GetProperty(LayerActivityProperty());
217 static LayerActivity
* GetLayerActivityForUpdate(nsIFrame
* aFrame
) {
218 LayerActivity
* layerActivity
= GetLayerActivity(aFrame
);
220 gLayerActivityTracker
->MarkUsed(layerActivity
);
222 if (!gLayerActivityTracker
) {
223 gLayerActivityTracker
=
224 new LayerActivityTracker(GetMainThreadSerialEventTarget());
226 layerActivity
= new LayerActivity(aFrame
);
227 gLayerActivityTracker
->AddObject(layerActivity
);
228 aFrame
->AddStateBits(NS_FRAME_HAS_LAYER_ACTIVITY_PROPERTY
);
229 aFrame
->SetProperty(LayerActivityProperty(), layerActivity
);
231 return layerActivity
;
234 static void IncrementMutationCount(uint8_t* aCount
) {
235 *aCount
= uint8_t(std::min(0xFF, *aCount
+ 1));
239 void ActiveLayerTracker::TransferActivityToContent(nsIFrame
* aFrame
,
240 nsIContent
* aContent
) {
241 if (!aFrame
->HasAnyStateBits(NS_FRAME_HAS_LAYER_ACTIVITY_PROPERTY
)) {
244 LayerActivity
* layerActivity
= aFrame
->TakeProperty(LayerActivityProperty());
245 aFrame
->RemoveStateBits(NS_FRAME_HAS_LAYER_ACTIVITY_PROPERTY
);
246 if (!layerActivity
) {
249 layerActivity
->mFrame
= nullptr;
250 layerActivity
->mContent
= aContent
;
251 aContent
->SetProperty(nsGkAtoms::LayerActivity
, layerActivity
,
252 nsINode::DeleteProperty
<LayerActivity
>, true);
256 void ActiveLayerTracker::TransferActivityToFrame(nsIContent
* aContent
,
258 auto* layerActivity
= static_cast<LayerActivity
*>(
259 aContent
->TakeProperty(nsGkAtoms::LayerActivity
));
260 if (!layerActivity
) {
263 layerActivity
->mContent
= nullptr;
264 layerActivity
->mFrame
= aFrame
;
265 aFrame
->AddStateBits(NS_FRAME_HAS_LAYER_ACTIVITY_PROPERTY
);
266 aFrame
->SetProperty(LayerActivityProperty(), layerActivity
);
269 static void IncrementScaleRestyleCountIfNeeded(nsIFrame
* aFrame
,
270 LayerActivity
* aActivity
) {
271 const nsStyleDisplay
* display
= aFrame
->StyleDisplay();
272 if (!display
->HasTransformProperty() && !display
->HasIndividualTransform() &&
273 display
->mOffsetPath
.IsNone()) {
274 // The transform was removed.
275 aActivity
->mPreviousTransformScale
= Nothing();
276 IncrementMutationCount(
277 &aActivity
->mRestyleCounts
[LayerActivity::ACTIVITY_SCALE
]);
281 // Compute the new scale due to the CSS transform property.
282 // Note: Motion path doesn't contribute to scale factor. (It only has 2d
283 // translate and 2d rotate, so we use Nothing() for it.)
284 nsStyleTransformMatrix::TransformReferenceBox
refBox(aFrame
);
285 Matrix4x4 transform
= nsStyleTransformMatrix::ReadTransforms(
286 display
->mTranslate
, display
->mRotate
, display
->mScale
, Nothing(),
287 display
->mTransform
, refBox
, AppUnitsPerCSSPixel());
289 if (!transform
.Is2D(&transform2D
)) {
290 // We don't attempt to handle 3D transforms; just assume the scale changed.
291 aActivity
->mPreviousTransformScale
= Nothing();
292 IncrementMutationCount(
293 &aActivity
->mRestyleCounts
[LayerActivity::ACTIVITY_SCALE
]);
297 Size scale
= transform2D
.ScaleFactors();
298 if (aActivity
->mPreviousTransformScale
== Some(scale
)) {
299 return; // Nothing changed.
302 aActivity
->mPreviousTransformScale
= Some(scale
);
303 IncrementMutationCount(
304 &aActivity
->mRestyleCounts
[LayerActivity::ACTIVITY_SCALE
]);
308 void ActiveLayerTracker::NotifyRestyle(nsIFrame
* aFrame
,
309 nsCSSPropertyID aProperty
) {
310 LayerActivity
* layerActivity
= GetLayerActivityForUpdate(aFrame
);
311 uint8_t& mutationCount
= layerActivity
->RestyleCountForProperty(aProperty
);
312 IncrementMutationCount(&mutationCount
);
314 if (nsCSSPropertyIDSet::TransformLikeProperties().HasProperty(aProperty
)) {
315 IncrementScaleRestyleCountIfNeeded(aFrame
, layerActivity
);
320 void ActiveLayerTracker::NotifyOffsetRestyle(nsIFrame
* aFrame
) {
321 LayerActivity
* layerActivity
= GetLayerActivityForUpdate(aFrame
);
322 IncrementMutationCount(
323 &layerActivity
->mRestyleCounts
[LayerActivity::ACTIVITY_LEFT
]);
324 IncrementMutationCount(
325 &layerActivity
->mRestyleCounts
[LayerActivity::ACTIVITY_TOP
]);
326 IncrementMutationCount(
327 &layerActivity
->mRestyleCounts
[LayerActivity::ACTIVITY_RIGHT
]);
328 IncrementMutationCount(
329 &layerActivity
->mRestyleCounts
[LayerActivity::ACTIVITY_BOTTOM
]);
333 void ActiveLayerTracker::NotifyAnimated(nsIFrame
* aFrame
,
334 nsCSSPropertyID aProperty
,
335 const nsACString
& aNewValue
,
336 nsDOMCSSDeclaration
* aDOMCSSDecl
) {
337 LayerActivity
* layerActivity
= GetLayerActivityForUpdate(aFrame
);
338 uint8_t& mutationCount
= layerActivity
->RestyleCountForProperty(aProperty
);
339 if (mutationCount
!= 0xFF) {
340 nsAutoCString oldValue
;
341 aDOMCSSDecl
->GetPropertyValue(aProperty
, oldValue
);
342 if (oldValue
!= aNewValue
) {
343 // We know this is animated, so just hack the mutation count.
344 mutationCount
= 0xFF;
350 void ActiveLayerTracker::NotifyAnimatedFromScrollHandler(
351 nsIFrame
* aFrame
, nsCSSPropertyID aProperty
, nsIFrame
* aScrollFrame
) {
352 if (aFrame
->PresContext() != aScrollFrame
->PresContext()) {
353 // Don't allow cross-document dependencies.
356 LayerActivity
* layerActivity
= GetLayerActivityForUpdate(aFrame
);
357 LayerActivity::ActivityIndex activityIndex
=
358 LayerActivity::GetActivityIndexForProperty(aProperty
);
360 if (layerActivity
->mAnimatingScrollHandlerFrame
.GetFrame() != aScrollFrame
) {
361 // Discard any activity of a different scroll frame. We only track the
362 // most recent scroll handler induced activity.
363 layerActivity
->mScrollHandlerInducedActivity
.clear();
364 layerActivity
->mAnimatingScrollHandlerFrame
= aScrollFrame
;
367 layerActivity
->mScrollHandlerInducedActivity
+= activityIndex
;
370 static bool IsPresContextInScriptAnimationCallback(
371 nsPresContext
* aPresContext
) {
372 if (aPresContext
->RefreshDriver()->IsInRefresh()) {
375 // Treat timeouts/setintervals as scripted animation callbacks for our
377 nsPIDOMWindowInner
* win
= aPresContext
->Document()->GetInnerWindow();
378 return win
&& win
->IsRunningTimeout();
382 void ActiveLayerTracker::NotifyInlineStyleRuleModified(
383 nsIFrame
* aFrame
, nsCSSPropertyID aProperty
, const nsACString
& aNewValue
,
384 nsDOMCSSDeclaration
* aDOMCSSDecl
) {
385 if (IsPresContextInScriptAnimationCallback(aFrame
->PresContext())) {
386 NotifyAnimated(aFrame
, aProperty
, aNewValue
, aDOMCSSDecl
);
388 if (gLayerActivityTracker
&&
389 gLayerActivityTracker
->mCurrentScrollHandlerFrame
.IsAlive()) {
390 NotifyAnimatedFromScrollHandler(
392 gLayerActivityTracker
->mCurrentScrollHandlerFrame
.GetFrame());
397 void ActiveLayerTracker::NotifyNeedsRepaint(nsIFrame
* aFrame
) {
398 LayerActivity
* layerActivity
= GetLayerActivityForUpdate(aFrame
);
399 if (IsPresContextInScriptAnimationCallback(aFrame
->PresContext())) {
400 // This is mirroring NotifyInlineStyleRuleModified's NotifyAnimated logic.
401 // Just max out the restyle count if we're in an animation callback.
402 layerActivity
->mRestyleCounts
[LayerActivity::ACTIVITY_TRIGGERED_REPAINT
] =
405 IncrementMutationCount(
407 ->mRestyleCounts
[LayerActivity::ACTIVITY_TRIGGERED_REPAINT
]);
411 static bool CheckScrollInducedActivity(
412 LayerActivity
* aLayerActivity
, LayerActivity::ActivityIndex aActivityIndex
,
413 nsDisplayListBuilder
* aBuilder
) {
414 if (!aLayerActivity
->mScrollHandlerInducedActivity
.contains(aActivityIndex
) ||
415 !aLayerActivity
->mAnimatingScrollHandlerFrame
.IsAlive()) {
419 nsIScrollableFrame
* scrollFrame
=
420 do_QueryFrame(aLayerActivity
->mAnimatingScrollHandlerFrame
.GetFrame());
423 scrollFrame
->IsScrollingActiveNotMinimalDisplayPort(aBuilder
))) {
427 // The scroll frame has been destroyed or has become inactive. Clear it from
428 // the layer activity so that it can expire.
429 aLayerActivity
->mAnimatingScrollHandlerFrame
= nullptr;
430 aLayerActivity
->mScrollHandlerInducedActivity
.clear();
435 bool ActiveLayerTracker::IsBackgroundPositionAnimated(
436 nsDisplayListBuilder
* aBuilder
, nsIFrame
* aFrame
) {
437 LayerActivity
* layerActivity
= GetLayerActivity(aFrame
);
439 LayerActivity::ActivityIndex activityIndex
=
440 LayerActivity::ActivityIndex::ACTIVITY_BACKGROUND_POSITION
;
441 if (layerActivity
->mRestyleCounts
[activityIndex
] >= 2) {
442 // If the frame needs to be repainted frequently, we probably don't get
443 // much from treating the property as animated, *unless* this frame's
444 // 'scale' (which includes the bounds changes of a rotation) is changing.
445 // Marking a scaling transform as animating allows us to avoid resizing
446 // the texture, even if we have to repaint the contents of that texture.
448 ->mRestyleCounts
[LayerActivity::ACTIVITY_TRIGGERED_REPAINT
] < 2) {
452 if (CheckScrollInducedActivity(layerActivity
, activityIndex
, aBuilder
)) {
456 return nsLayoutUtils::HasEffectiveAnimation(
457 aFrame
, nsCSSPropertyIDSet({eCSSProperty_background_position_x
,
458 eCSSProperty_background_position_y
}));
461 static bool IsMotionPathAnimated(nsDisplayListBuilder
* aBuilder
,
463 return ActiveLayerTracker::IsStyleAnimated(
464 aBuilder
, aFrame
, nsCSSPropertyIDSet
{eCSSProperty_offset_path
}) ||
465 (!aFrame
->StyleDisplay()->mOffsetPath
.IsNone() &&
466 ActiveLayerTracker::IsStyleAnimated(
468 nsCSSPropertyIDSet
{eCSSProperty_offset_distance
,
469 eCSSProperty_offset_rotate
,
470 eCSSProperty_offset_anchor
}));
474 bool ActiveLayerTracker::IsTransformAnimated(nsDisplayListBuilder
* aBuilder
,
476 return IsStyleAnimated(aBuilder
, aFrame
,
477 nsCSSPropertyIDSet::CSSTransformProperties()) ||
478 IsMotionPathAnimated(aBuilder
, aFrame
);
482 bool ActiveLayerTracker::IsTransformMaybeAnimated(nsIFrame
* aFrame
) {
483 return IsStyleAnimated(nullptr, aFrame
,
484 nsCSSPropertyIDSet::CSSTransformProperties()) ||
485 IsMotionPathAnimated(nullptr, aFrame
);
489 bool ActiveLayerTracker::IsStyleAnimated(
490 nsDisplayListBuilder
* aBuilder
, nsIFrame
* aFrame
,
491 const nsCSSPropertyIDSet
& aPropertySet
) {
493 aPropertySet
.IsSubsetOf(nsCSSPropertyIDSet::TransformLikeProperties()) ||
494 aPropertySet
.IsSubsetOf(nsCSSPropertyIDSet::OpacityProperties()),
495 "Only subset of opacity or transform-like properties set calls this");
497 // For display:table content, transforms are applied to the table wrapper
498 // (primary frame) but their will-change style will be specified on the style
499 // frame and, unlike other transform properties, not inherited.
500 // As a result, for transform properties only we need to be careful to look up
501 // the will-change style on the _style_ frame.
502 const nsIFrame
* styleFrame
= nsLayoutUtils::GetStyleFrame(aFrame
);
503 const nsCSSPropertyIDSet transformSet
=
504 nsCSSPropertyIDSet::TransformLikeProperties();
505 if ((styleFrame
&& (styleFrame
->StyleDisplay()->mWillChange
.bits
&
506 StyleWillChangeBits::TRANSFORM
)) &&
507 aPropertySet
.Intersects(transformSet
) &&
509 aBuilder
->IsInWillChangeBudget(aFrame
, aFrame
->GetSize()))) {
512 if ((aFrame
->StyleDisplay()->mWillChange
.bits
&
513 StyleWillChangeBits::OPACITY
) &&
514 aPropertySet
.Intersects(nsCSSPropertyIDSet::OpacityProperties()) &&
516 aBuilder
->IsInWillChangeBudget(aFrame
, aFrame
->GetSize()))) {
520 LayerActivity
* layerActivity
= GetLayerActivity(aFrame
);
522 LayerActivity::ActivityIndex activityIndex
=
523 LayerActivity::GetActivityIndexForPropertySet(aPropertySet
);
524 if (layerActivity
->mRestyleCounts
[activityIndex
] >= 2) {
525 // If the frame needs to be repainted frequently, we probably don't get
526 // much from treating the property as animated, *unless* this frame's
527 // 'scale' (which includes the bounds changes of a rotation) is changing.
528 // Marking a scaling transform as animating allows us to avoid resizing
529 // the texture, even if we have to repaint the contents of that texture.
531 ->mRestyleCounts
[LayerActivity::ACTIVITY_TRIGGERED_REPAINT
] <
533 (aPropertySet
.Intersects(transformSet
) &&
534 IsScaleSubjectToAnimation(aFrame
))) {
538 if (CheckScrollInducedActivity(layerActivity
, activityIndex
, aBuilder
)) {
543 if (nsLayoutUtils::HasEffectiveAnimation(aFrame
, aPropertySet
)) {
547 if (!aPropertySet
.Intersects(transformSet
) ||
548 !aFrame
->Combines3DTransformWithAncestors()) {
552 // For preserve-3d, we check if there is any transform animation on its parent
553 // frames in the 3d rendering context. If there is one, this function will
555 return IsStyleAnimated(aBuilder
, aFrame
->GetParent(), aPropertySet
);
559 bool ActiveLayerTracker::IsOffsetStyleAnimated(nsIFrame
* aFrame
) {
560 LayerActivity
* layerActivity
= GetLayerActivity(aFrame
);
562 if (layerActivity
->mRestyleCounts
[LayerActivity::ACTIVITY_LEFT
] >= 2 ||
563 layerActivity
->mRestyleCounts
[LayerActivity::ACTIVITY_TOP
] >= 2 ||
564 layerActivity
->mRestyleCounts
[LayerActivity::ACTIVITY_RIGHT
] >= 2 ||
565 layerActivity
->mRestyleCounts
[LayerActivity::ACTIVITY_BOTTOM
] >= 2) {
569 // We should also check for running CSS animations of these properties once
570 // bug 1009693 is fixed. Until that happens, layerization isn't useful for
571 // animations of these properties because we'll invalidate the layer contents
572 // on every change anyway.
573 // See bug 1151346 for a patch that adds a check for CSS animations.
578 bool ActiveLayerTracker::IsScaleSubjectToAnimation(nsIFrame
* aFrame
) {
579 // Check whether JavaScript is animating this frame's scale.
580 LayerActivity
* layerActivity
= GetLayerActivity(aFrame
);
582 layerActivity
->mRestyleCounts
[LayerActivity::ACTIVITY_SCALE
] >= 2) {
586 return AnimationUtils::FrameHasAnimatedScale(aFrame
);
590 void ActiveLayerTracker::NotifyContentChange(nsIFrame
* aFrame
) {
591 LayerActivity
* layerActivity
= GetLayerActivityForUpdate(aFrame
);
592 layerActivity
->mContentActive
= true;
596 bool ActiveLayerTracker::IsContentActive(nsIFrame
* aFrame
) {
597 LayerActivity
* layerActivity
= GetLayerActivity(aFrame
);
598 return layerActivity
&& layerActivity
->mContentActive
;
602 void ActiveLayerTracker::SetCurrentScrollHandlerFrame(nsIFrame
* aFrame
) {
603 if (!gLayerActivityTracker
) {
604 gLayerActivityTracker
=
605 new LayerActivityTracker(GetMainThreadSerialEventTarget());
607 gLayerActivityTracker
->mCurrentScrollHandlerFrame
= aFrame
;
611 void ActiveLayerTracker::Shutdown() {
612 delete gLayerActivityTracker
;
613 gLayerActivityTracker
= nullptr;
616 } // namespace mozilla