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"
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.
52 ACTIVITY_BACKGROUND_POSITION
,
55 ACTIVITY_TRIGGERED_REPAINT
,
61 explicit LayerActivity(nsIFrame
* aFrame
)
62 : mFrame(aFrame
), mContent(nullptr), mContentActive(false) {
63 PodArrayZero(mRestyleCounts
);
66 nsExpirationState
* GetExpirationState() { return &mState
; }
67 uint8_t& RestyleCountForProperty(nsCSSPropertyID aProperty
) {
68 return mRestyleCounts
[GetActivityIndexForProperty(aProperty
)];
71 static ActivityIndex
GetActivityIndexForProperty(nsCSSPropertyID 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
:
87 case eCSSProperty_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
;
101 return ACTIVITY_OPACITY
;
105 static ActivityIndex
GetActivityIndexForPropertySet(
106 const nsCSSPropertyIDSet
& aPropertySet
) {
107 if (aPropertySet
.IsSubsetOf(
108 nsCSSPropertyIDSet::TransformLikeProperties())) {
109 return ACTIVITY_TRANSFORM
;
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.
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
];
140 class LayerActivityTracker final
141 : public nsExpirationTracker
<LayerActivity
, 4> {
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
{
155 void NotifyExpired(LayerActivity
* aObject
) override
;
158 WeakFrame mCurrentScrollHandlerFrame
;
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
);
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");
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());
204 c
->RemoveProperty(nsGkAtoms::LayerActivity
);
208 static LayerActivity
* GetLayerActivity(nsIFrame
* aFrame
) {
209 if (!aFrame
->HasAnyStateBits(NS_FRAME_HAS_LAYER_ACTIVITY_PROPERTY
)) {
212 return aFrame
->GetProperty(LayerActivityProperty());
215 static LayerActivity
* GetLayerActivityForUpdate(nsIFrame
* aFrame
) {
216 LayerActivity
* layerActivity
= GetLayerActivity(aFrame
);
218 gLayerActivityTracker
->MarkUsed(layerActivity
);
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));
237 void ActiveLayerTracker::TransferActivityToContent(nsIFrame
* aFrame
,
238 nsIContent
* aContent
) {
239 if (!aFrame
->HasAnyStateBits(NS_FRAME_HAS_LAYER_ACTIVITY_PROPERTY
)) {
242 LayerActivity
* layerActivity
= aFrame
->TakeProperty(LayerActivityProperty());
243 aFrame
->RemoveStateBits(NS_FRAME_HAS_LAYER_ACTIVITY_PROPERTY
);
244 if (!layerActivity
) {
247 layerActivity
->mFrame
= nullptr;
248 layerActivity
->mContent
= aContent
;
249 aContent
->SetProperty(nsGkAtoms::LayerActivity
, layerActivity
,
250 nsINode::DeleteProperty
<LayerActivity
>, true);
254 void ActiveLayerTracker::TransferActivityToFrame(nsIContent
* aContent
,
256 auto* layerActivity
= static_cast<LayerActivity
*>(
257 aContent
->TakeProperty(nsGkAtoms::LayerActivity
));
258 if (!layerActivity
) {
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
]);
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());
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
]);
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
]);
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
);
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
]);
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;
348 void ActiveLayerTracker::NotifyAnimatedFromScrollHandler(
349 nsIFrame
* aFrame
, nsCSSPropertyID aProperty
, nsIFrame
* aScrollFrame
) {
350 if (aFrame
->PresContext() != aScrollFrame
->PresContext()) {
351 // Don't allow cross-document dependencies.
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()) {
373 // Treat timeouts/setintervals as scripted animation callbacks for our
375 nsPIDOMWindowInner
* win
= aPresContext
->Document()->GetInnerWindow();
376 return win
&& win
->IsRunningTimeout();
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(
390 gLayerActivityTracker
->mCurrentScrollHandlerFrame
.GetFrame());
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
] =
403 IncrementMutationCount(
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()) {
417 nsIScrollableFrame
* scrollFrame
=
418 do_QueryFrame(aLayerActivity
->mAnimatingScrollHandlerFrame
.GetFrame());
419 if (scrollFrame
&& (!aBuilder
|| scrollFrame
->IsScrollingActive(aBuilder
))) {
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();
431 bool ActiveLayerTracker::IsBackgroundPositionAnimated(
432 nsDisplayListBuilder
* aBuilder
, nsIFrame
* aFrame
) {
433 LayerActivity
* layerActivity
= GetLayerActivity(aFrame
);
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.
444 ->mRestyleCounts
[LayerActivity::ACTIVITY_TRIGGERED_REPAINT
] < 2) {
448 if (CheckScrollInducedActivity(layerActivity
, activityIndex
, aBuilder
)) {
452 return nsLayoutUtils::HasEffectiveAnimation(
453 aFrame
, nsCSSPropertyIDSet({eCSSProperty_background_position_x
,
454 eCSSProperty_background_position_y
}));
457 static bool IsMotionPathAnimated(nsDisplayListBuilder
* aBuilder
,
459 return ActiveLayerTracker::IsStyleAnimated(
460 aBuilder
, aFrame
, nsCSSPropertyIDSet
{eCSSProperty_offset_path
}) ||
461 (!aFrame
->StyleDisplay()->mOffsetPath
.IsNone() &&
462 ActiveLayerTracker::IsStyleAnimated(
464 nsCSSPropertyIDSet
{eCSSProperty_offset_distance
,
465 eCSSProperty_offset_rotate
,
466 eCSSProperty_offset_anchor
}));
470 bool ActiveLayerTracker::IsTransformAnimated(nsDisplayListBuilder
* aBuilder
,
472 return IsStyleAnimated(aBuilder
, aFrame
,
473 nsCSSPropertyIDSet::CSSTransformProperties()) ||
474 IsMotionPathAnimated(aBuilder
, aFrame
);
478 bool ActiveLayerTracker::IsTransformMaybeAnimated(nsIFrame
* aFrame
) {
479 return IsStyleAnimated(nullptr, aFrame
,
480 nsCSSPropertyIDSet::CSSTransformProperties()) ||
481 IsMotionPathAnimated(nullptr, aFrame
);
485 bool ActiveLayerTracker::IsStyleAnimated(
486 nsDisplayListBuilder
* aBuilder
, nsIFrame
* aFrame
,
487 const nsCSSPropertyIDSet
& aPropertySet
) {
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
) &&
505 aBuilder
->IsInWillChangeBudget(aFrame
, aFrame
->GetSize()))) {
508 if ((aFrame
->StyleDisplay()->mWillChange
.bits
&
509 StyleWillChangeBits::OPACITY
) &&
510 aPropertySet
.Intersects(nsCSSPropertyIDSet::OpacityProperties()) &&
512 aBuilder
->IsInWillChangeBudget(aFrame
, aFrame
->GetSize()))) {
516 LayerActivity
* layerActivity
= GetLayerActivity(aFrame
);
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.
527 ->mRestyleCounts
[LayerActivity::ACTIVITY_TRIGGERED_REPAINT
] <
529 (aPropertySet
.Intersects(transformSet
) &&
530 IsScaleSubjectToAnimation(aFrame
))) {
534 if (CheckScrollInducedActivity(layerActivity
, activityIndex
, aBuilder
)) {
539 if (nsLayoutUtils::HasEffectiveAnimation(aFrame
, aPropertySet
)) {
543 if (!aPropertySet
.Intersects(transformSet
) ||
544 !aFrame
->Combines3DTransformWithAncestors()) {
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
551 return IsStyleAnimated(aBuilder
, aFrame
->GetParent(), aPropertySet
);
555 bool ActiveLayerTracker::IsOffsetStyleAnimated(nsIFrame
* aFrame
) {
556 LayerActivity
* layerActivity
= GetLayerActivity(aFrame
);
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) {
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.
574 bool ActiveLayerTracker::IsScaleSubjectToAnimation(nsIFrame
* aFrame
) {
575 // Check whether JavaScript is animating this frame's scale.
576 LayerActivity
* layerActivity
= GetLayerActivity(aFrame
);
578 layerActivity
->mRestyleCounts
[LayerActivity::ACTIVITY_SCALE
] >= 2) {
582 return AnimationUtils::FrameHasAnimatedScale(aFrame
);
586 void ActiveLayerTracker::NotifyContentChange(nsIFrame
* aFrame
) {
587 LayerActivity
* layerActivity
= GetLayerActivityForUpdate(aFrame
);
588 layerActivity
->mContentActive
= true;
592 bool ActiveLayerTracker::IsContentActive(nsIFrame
* aFrame
) {
593 LayerActivity
* layerActivity
= GetLayerActivity(aFrame
);
594 return layerActivity
&& layerActivity
->mContentActive
;
598 void ActiveLayerTracker::SetCurrentScrollHandlerFrame(nsIFrame
* aFrame
) {
599 if (!gLayerActivityTracker
) {
600 gLayerActivityTracker
=
601 new LayerActivityTracker(GetMainThreadSerialEventTarget());
603 gLayerActivityTracker
->mCurrentScrollHandlerFrame
= aFrame
;
607 void ActiveLayerTracker::Shutdown() {
608 delete gLayerActivityTracker
;
609 gLayerActivityTracker
= nullptr;
612 } // namespace mozilla