Line data Source code
1 : /* This Source Code Form is subject to the terms of the Mozilla Public
2 : * License, v. 2.0. If a copy of the MPL was not distributed with this
3 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4 :
5 : #include "ActiveLayerTracker.h"
6 :
7 : #include "mozilla/AnimationUtils.h"
8 : #include "mozilla/ArrayUtils.h"
9 : #include "mozilla/gfx/Matrix.h"
10 : #include "mozilla/EffectSet.h"
11 : #include "mozilla/PodOperations.h"
12 : #include "gfx2DGlue.h"
13 : #include "nsExpirationTracker.h"
14 : #include "nsContainerFrame.h"
15 : #include "nsIContent.h"
16 : #include "nsRefreshDriver.h"
17 : #include "nsPIDOMWindow.h"
18 : #include "nsIDocument.h"
19 : #include "nsAnimationManager.h"
20 : #include "nsStyleTransformMatrix.h"
21 : #include "nsTransitionManager.h"
22 : #include "nsDisplayList.h"
23 : #include "nsDOMCSSDeclaration.h"
24 :
25 : namespace mozilla {
26 :
27 : using namespace gfx;
28 :
29 : /**
30 : * This tracks the state of a frame that may need active layers due to
31 : * ongoing content changes or style changes that indicate animation.
32 : *
33 : * When no changes of *any* kind are detected after 75-100ms we remove this
34 : * object. Because we only track all kinds of activity with a single
35 : * nsExpirationTracker, it's possible a frame might remain active somewhat
36 : * spuriously if different kinds of changes kept happening, but that almost
37 : * certainly doesn't matter.
38 : */
39 : class LayerActivity {
40 : public:
41 : enum ActivityIndex {
42 : ACTIVITY_OPACITY,
43 : ACTIVITY_TRANSFORM,
44 : ACTIVITY_LEFT,
45 : ACTIVITY_TOP,
46 : ACTIVITY_RIGHT,
47 : ACTIVITY_BOTTOM,
48 : ACTIVITY_MARGIN_LEFT,
49 : ACTIVITY_MARGIN_TOP,
50 : ACTIVITY_MARGIN_RIGHT,
51 : ACTIVITY_MARGIN_BOTTOM,
52 : ACTIVITY_BACKGROUND_POSITION,
53 :
54 : ACTIVITY_SCALE,
55 :
56 : // keep as last item
57 : ACTIVITY_COUNT
58 : };
59 :
60 9 : explicit LayerActivity(nsIFrame* aFrame)
61 9 : : mFrame(aFrame)
62 : , mContent(nullptr)
63 9 : , mContentActive(false)
64 : {
65 9 : PodArrayZero(mRestyleCounts);
66 9 : }
67 : ~LayerActivity();
68 47 : nsExpirationState* GetExpirationState() { return &mState; }
69 21 : uint8_t& RestyleCountForProperty(nsCSSPropertyID aProperty)
70 : {
71 21 : return mRestyleCounts[GetActivityIndexForProperty(aProperty)];
72 : }
73 :
74 30 : static ActivityIndex GetActivityIndexForProperty(nsCSSPropertyID aProperty)
75 : {
76 30 : switch (aProperty) {
77 21 : case eCSSProperty_opacity: return ACTIVITY_OPACITY;
78 9 : case eCSSProperty_transform: return ACTIVITY_TRANSFORM;
79 0 : case eCSSProperty_left: return ACTIVITY_LEFT;
80 0 : case eCSSProperty_top: return ACTIVITY_TOP;
81 0 : case eCSSProperty_right: return ACTIVITY_RIGHT;
82 0 : case eCSSProperty_bottom: return ACTIVITY_BOTTOM;
83 0 : case eCSSProperty_margin_left: return ACTIVITY_MARGIN_LEFT;
84 0 : case eCSSProperty_margin_top: return ACTIVITY_MARGIN_TOP;
85 0 : case eCSSProperty_margin_right: return ACTIVITY_MARGIN_RIGHT;
86 0 : case eCSSProperty_margin_bottom: return ACTIVITY_MARGIN_BOTTOM;
87 0 : case eCSSProperty_background_position: return ACTIVITY_BACKGROUND_POSITION;
88 0 : case eCSSProperty_background_position_x: return ACTIVITY_BACKGROUND_POSITION;
89 0 : case eCSSProperty_background_position_y: return ACTIVITY_BACKGROUND_POSITION;
90 0 : default: MOZ_ASSERT(false); return ACTIVITY_OPACITY;
91 : }
92 : }
93 :
94 : // While tracked, exactly one of mFrame or mContent is non-null, depending
95 : // on whether this property is stored on a frame or on a content node.
96 : // When this property is expired by the layer activity tracker, both mFrame
97 : // and mContent are nulled-out and the property is deleted.
98 : nsIFrame* mFrame;
99 : nsIContent* mContent;
100 :
101 : nsExpirationState mState;
102 :
103 : // Previous scale due to the CSS transform property.
104 : Maybe<gfxSize> mPreviousTransformScale;
105 :
106 : // The scroll frame during for which we most recently received a call to
107 : // NotifyAnimatedFromScrollHandler.
108 : WeakFrame mAnimatingScrollHandlerFrame;
109 : // The set of activities that were triggered during
110 : // mAnimatingScrollHandlerFrame's scroll event handler.
111 : EnumSet<ActivityIndex> mScrollHandlerInducedActivity;
112 :
113 : // Number of restyle operations detected
114 : uint8_t mRestyleCounts[ACTIVITY_COUNT];
115 : bool mContentActive;
116 : };
117 :
118 : class LayerActivityTracker final : public nsExpirationTracker<LayerActivity,4> {
119 : public:
120 : // 75-100ms is a good timeout period. We use 4 generations of 25ms each.
121 : enum { GENERATION_MS = 100 };
122 1 : explicit LayerActivityTracker(nsIEventTarget* aEventTarget)
123 1 : : nsExpirationTracker<LayerActivity,4>(GENERATION_MS,
124 : "LayerActivityTracker",
125 : aEventTarget)
126 1 : , mDestroying(false)
127 1 : {}
128 0 : ~LayerActivityTracker() {
129 0 : mDestroying = true;
130 0 : AgeAllGenerations();
131 0 : }
132 :
133 : virtual void NotifyExpired(LayerActivity* aObject);
134 :
135 : public:
136 : WeakFrame mCurrentScrollHandlerFrame;
137 :
138 : private:
139 : bool mDestroying;
140 : };
141 :
142 : static LayerActivityTracker* gLayerActivityTracker = nullptr;
143 :
144 14 : LayerActivity::~LayerActivity()
145 : {
146 7 : if (mFrame || mContent) {
147 0 : NS_ASSERTION(gLayerActivityTracker, "Should still have a tracker");
148 0 : gLayerActivityTracker->RemoveObject(this);
149 : }
150 7 : }
151 :
152 : // Frames with this property have NS_FRAME_HAS_LAYER_ACTIVITY_PROPERTY set
153 99 : NS_DECLARE_FRAME_PROPERTY_DELETABLE(LayerActivityProperty, LayerActivity)
154 :
155 : void
156 7 : LayerActivityTracker::NotifyExpired(LayerActivity* aObject)
157 : {
158 7 : if (!mDestroying && aObject->mAnimatingScrollHandlerFrame.IsAlive()) {
159 : // Reset the restyle counts, but let the layer activity survive.
160 0 : PodArrayZero(aObject->mRestyleCounts);
161 0 : MarkUsed(aObject);
162 0 : return;
163 : }
164 :
165 7 : RemoveObject(aObject);
166 :
167 7 : nsIFrame* f = aObject->mFrame;
168 7 : nsIContent* c = aObject->mContent;
169 7 : aObject->mFrame = nullptr;
170 7 : aObject->mContent = nullptr;
171 :
172 7 : MOZ_ASSERT((f == nullptr) != (c == nullptr),
173 : "A LayerActivity object should always have a reference to either its frame or its content");
174 :
175 7 : if (f) {
176 : // The pres context might have been detached during the delay -
177 : // that's fine, just skip the paint.
178 7 : if (f->PresContext()->GetContainerWeak()) {
179 7 : f->SchedulePaint();
180 : }
181 7 : f->RemoveStateBits(NS_FRAME_HAS_LAYER_ACTIVITY_PROPERTY);
182 7 : f->DeleteProperty(LayerActivityProperty());
183 : } else {
184 0 : c->DeleteProperty(nsGkAtoms::LayerActivity);
185 : }
186 : }
187 :
188 : static LayerActivity*
189 4510 : GetLayerActivity(nsIFrame* aFrame)
190 : {
191 4510 : if (!aFrame->HasAnyStateBits(NS_FRAME_HAS_LAYER_ACTIVITY_PROPERTY)) {
192 4427 : return nullptr;
193 : }
194 83 : return aFrame->GetProperty(LayerActivityProperty());
195 : }
196 :
197 : static LayerActivity*
198 21 : GetLayerActivityForUpdate(nsIFrame* aFrame)
199 : {
200 21 : LayerActivity* layerActivity = GetLayerActivity(aFrame);
201 21 : if (layerActivity) {
202 12 : gLayerActivityTracker->MarkUsed(layerActivity);
203 : } else {
204 9 : if (!gLayerActivityTracker) {
205 1 : gLayerActivityTracker = new LayerActivityTracker(
206 2 : SystemGroup::EventTargetFor(TaskCategory::Other));
207 : }
208 9 : layerActivity = new LayerActivity(aFrame);
209 9 : gLayerActivityTracker->AddObject(layerActivity);
210 9 : aFrame->AddStateBits(NS_FRAME_HAS_LAYER_ACTIVITY_PROPERTY);
211 9 : aFrame->SetProperty(LayerActivityProperty(), layerActivity);
212 : }
213 21 : return layerActivity;
214 : }
215 :
216 : static void
217 21 : IncrementMutationCount(uint8_t* aCount)
218 : {
219 21 : *aCount = uint8_t(std::min(0xFF, *aCount + 1));
220 21 : }
221 :
222 : /* static */ void
223 111 : ActiveLayerTracker::TransferActivityToContent(nsIFrame* aFrame, nsIContent* aContent)
224 : {
225 111 : if (!aFrame->HasAnyStateBits(NS_FRAME_HAS_LAYER_ACTIVITY_PROPERTY)) {
226 111 : return;
227 : }
228 0 : LayerActivity* layerActivity = aFrame->RemoveProperty(LayerActivityProperty());
229 0 : aFrame->RemoveStateBits(NS_FRAME_HAS_LAYER_ACTIVITY_PROPERTY);
230 0 : if (!layerActivity) {
231 0 : return;
232 : }
233 0 : layerActivity->mFrame = nullptr;
234 0 : layerActivity->mContent = aContent;
235 0 : aContent->SetProperty(nsGkAtoms::LayerActivity, layerActivity,
236 0 : nsINode::DeleteProperty<LayerActivity>, true);
237 : }
238 :
239 : /* static */ void
240 469 : ActiveLayerTracker::TransferActivityToFrame(nsIContent* aContent, nsIFrame* aFrame)
241 : {
242 : LayerActivity* layerActivity = static_cast<LayerActivity*>(
243 469 : aContent->UnsetProperty(nsGkAtoms::LayerActivity));
244 469 : if (!layerActivity) {
245 469 : return;
246 : }
247 0 : layerActivity->mContent = nullptr;
248 0 : layerActivity->mFrame = aFrame;
249 0 : aFrame->AddStateBits(NS_FRAME_HAS_LAYER_ACTIVITY_PROPERTY);
250 0 : aFrame->SetProperty(LayerActivityProperty(), layerActivity);
251 : }
252 :
253 : static void
254 0 : IncrementScaleRestyleCountIfNeeded(nsIFrame* aFrame, LayerActivity* aActivity)
255 : {
256 0 : const nsStyleDisplay* display = aFrame->StyleDisplay();
257 0 : if (!display->mSpecifiedTransform) {
258 : // The transform was removed.
259 0 : aActivity->mPreviousTransformScale = Nothing();
260 0 : IncrementMutationCount(&aActivity->mRestyleCounts[LayerActivity::ACTIVITY_SCALE]);
261 0 : return;
262 : }
263 :
264 : // Compute the new scale due to the CSS transform property.
265 0 : nsPresContext* presContext = aFrame->PresContext();
266 0 : RuleNodeCacheConditions dummy;
267 : bool dummyBool;
268 0 : nsStyleTransformMatrix::TransformReferenceBox refBox(aFrame);
269 : Matrix4x4 transform =
270 0 : nsStyleTransformMatrix::ReadTransforms(display->mSpecifiedTransform->mHead,
271 : aFrame->StyleContext(),
272 : presContext,
273 : dummy, refBox,
274 0 : presContext->AppUnitsPerCSSPixel(),
275 0 : &dummyBool);
276 0 : Matrix transform2D;
277 0 : if (!transform.Is2D(&transform2D)) {
278 : // We don't attempt to handle 3D transforms; just assume the scale changed.
279 0 : aActivity->mPreviousTransformScale = Nothing();
280 0 : IncrementMutationCount(&aActivity->mRestyleCounts[LayerActivity::ACTIVITY_SCALE]);
281 0 : return;
282 : }
283 :
284 0 : gfxSize scale = ThebesMatrix(transform2D).ScaleFactors(true);
285 0 : if (aActivity->mPreviousTransformScale == Some(scale)) {
286 0 : return; // Nothing changed.
287 : }
288 :
289 0 : aActivity->mPreviousTransformScale = Some(scale);
290 0 : IncrementMutationCount(&aActivity->mRestyleCounts[LayerActivity::ACTIVITY_SCALE]);
291 : }
292 :
293 : /* static */ void
294 21 : ActiveLayerTracker::NotifyRestyle(nsIFrame* aFrame, nsCSSPropertyID aProperty)
295 : {
296 21 : LayerActivity* layerActivity = GetLayerActivityForUpdate(aFrame);
297 21 : uint8_t& mutationCount = layerActivity->RestyleCountForProperty(aProperty);
298 21 : IncrementMutationCount(&mutationCount);
299 :
300 21 : if (aProperty == eCSSProperty_transform) {
301 0 : IncrementScaleRestyleCountIfNeeded(aFrame, layerActivity);
302 : }
303 21 : }
304 :
305 : /* static */ void
306 0 : ActiveLayerTracker::NotifyOffsetRestyle(nsIFrame* aFrame)
307 : {
308 0 : LayerActivity* layerActivity = GetLayerActivityForUpdate(aFrame);
309 0 : IncrementMutationCount(&layerActivity->mRestyleCounts[LayerActivity::ACTIVITY_LEFT]);
310 0 : IncrementMutationCount(&layerActivity->mRestyleCounts[LayerActivity::ACTIVITY_TOP]);
311 0 : IncrementMutationCount(&layerActivity->mRestyleCounts[LayerActivity::ACTIVITY_RIGHT]);
312 0 : IncrementMutationCount(&layerActivity->mRestyleCounts[LayerActivity::ACTIVITY_BOTTOM]);
313 0 : }
314 :
315 : /* static */ void
316 0 : ActiveLayerTracker::NotifyAnimated(nsIFrame* aFrame,
317 : nsCSSPropertyID aProperty,
318 : const nsAString& aNewValue,
319 : nsDOMCSSDeclaration* aDOMCSSDecl)
320 : {
321 0 : LayerActivity* layerActivity = GetLayerActivityForUpdate(aFrame);
322 0 : uint8_t& mutationCount = layerActivity->RestyleCountForProperty(aProperty);
323 0 : if (mutationCount != 0xFF) {
324 0 : nsAutoString oldValue;
325 0 : aDOMCSSDecl->GetPropertyValue(aProperty, oldValue);
326 0 : if (aNewValue != oldValue) {
327 : // We know this is animated, so just hack the mutation count.
328 0 : mutationCount = 0xFF;
329 : }
330 : }
331 0 : }
332 :
333 : /* static */ void
334 0 : ActiveLayerTracker::NotifyAnimatedFromScrollHandler(nsIFrame* aFrame, nsCSSPropertyID aProperty,
335 : nsIFrame* aScrollFrame)
336 : {
337 0 : if (aFrame->PresContext() != aScrollFrame->PresContext()) {
338 : // Don't allow cross-document dependencies.
339 0 : return;
340 : }
341 0 : LayerActivity* layerActivity = GetLayerActivityForUpdate(aFrame);
342 0 : LayerActivity::ActivityIndex activityIndex = LayerActivity::GetActivityIndexForProperty(aProperty);
343 :
344 0 : if (layerActivity->mAnimatingScrollHandlerFrame.GetFrame() != aScrollFrame) {
345 : // Discard any activity of a different scroll frame. We only track the
346 : // most recent scroll handler induced activity.
347 0 : layerActivity->mScrollHandlerInducedActivity.clear();
348 0 : layerActivity->mAnimatingScrollHandlerFrame = aScrollFrame;
349 : }
350 :
351 0 : layerActivity->mScrollHandlerInducedActivity += activityIndex;
352 : }
353 :
354 : static bool
355 0 : IsPresContextInScriptAnimationCallback(nsPresContext* aPresContext)
356 : {
357 0 : if (aPresContext->RefreshDriver()->IsInRefresh()) {
358 0 : return true;
359 : }
360 : // Treat timeouts/setintervals as scripted animation callbacks for our
361 : // purposes.
362 0 : nsPIDOMWindowInner* win = aPresContext->Document()->GetInnerWindow();
363 0 : return win && win->IsRunningTimeout();
364 : }
365 :
366 : /* static */ void
367 0 : ActiveLayerTracker::NotifyInlineStyleRuleModified(nsIFrame* aFrame,
368 : nsCSSPropertyID aProperty,
369 : const nsAString& aNewValue,
370 : nsDOMCSSDeclaration* aDOMCSSDecl)
371 : {
372 0 : if (IsPresContextInScriptAnimationCallback(aFrame->PresContext())) {
373 0 : NotifyAnimated(aFrame, aProperty, aNewValue, aDOMCSSDecl);
374 : }
375 0 : if (gLayerActivityTracker &&
376 0 : gLayerActivityTracker->mCurrentScrollHandlerFrame.IsAlive()) {
377 0 : NotifyAnimatedFromScrollHandler(aFrame, aProperty,
378 0 : gLayerActivityTracker->mCurrentScrollHandlerFrame.GetFrame());
379 : }
380 0 : }
381 :
382 : /* static */ bool
383 24 : ActiveLayerTracker::IsStyleMaybeAnimated(nsIFrame* aFrame, nsCSSPropertyID aProperty)
384 : {
385 24 : return IsStyleAnimated(nullptr, aFrame, aProperty);
386 : }
387 :
388 : /* static */ bool
389 198 : ActiveLayerTracker::IsBackgroundPositionAnimated(nsDisplayListBuilder* aBuilder,
390 : nsIFrame* aFrame)
391 : {
392 396 : return IsStyleAnimated(aBuilder, aFrame, eCSSProperty_background_position_x) ||
393 396 : IsStyleAnimated(aBuilder, aFrame, eCSSProperty_background_position_y);
394 : }
395 :
396 : static bool
397 9 : CheckScrollInducedActivity(LayerActivity* aLayerActivity,
398 : LayerActivity::ActivityIndex aActivityIndex,
399 : nsDisplayListBuilder* aBuilder)
400 : {
401 9 : if (!aLayerActivity->mScrollHandlerInducedActivity.contains(aActivityIndex) ||
402 0 : !aLayerActivity->mAnimatingScrollHandlerFrame.IsAlive()) {
403 9 : return false;
404 : }
405 :
406 : nsIScrollableFrame* scrollFrame =
407 0 : do_QueryFrame(aLayerActivity->mAnimatingScrollHandlerFrame.GetFrame());
408 0 : if (scrollFrame && (!aBuilder || scrollFrame->IsScrollingActive(aBuilder))) {
409 0 : return true;
410 : }
411 :
412 : // The scroll frame has been destroyed or has become inactive. Clear it from
413 : // the layer activity so that it can expire.
414 0 : aLayerActivity->mAnimatingScrollHandlerFrame = nullptr;
415 0 : aLayerActivity->mScrollHandlerInducedActivity.clear();
416 0 : return false;
417 : }
418 :
419 : /* static */ bool
420 1060 : ActiveLayerTracker::IsStyleAnimated(nsDisplayListBuilder* aBuilder,
421 : nsIFrame* aFrame, nsCSSPropertyID aProperty)
422 : {
423 : // TODO: Add some abuse restrictions
424 4240 : if ((aFrame->StyleDisplay()->mWillChangeBitField & NS_STYLE_WILL_CHANGE_TRANSFORM) &&
425 2120 : aProperty == eCSSProperty_transform &&
426 1060 : (!aBuilder || aBuilder->IsInWillChangeBudget(aFrame, aFrame->GetSize()))) {
427 0 : return true;
428 : }
429 4240 : if ((aFrame->StyleDisplay()->mWillChangeBitField & NS_STYLE_WILL_CHANGE_OPACITY) &&
430 2120 : aProperty == eCSSProperty_opacity &&
431 1060 : (!aBuilder || aBuilder->IsInWillChangeBudget(aFrame, aFrame->GetSize()))) {
432 0 : return true;
433 : }
434 :
435 1060 : LayerActivity* layerActivity = GetLayerActivity(aFrame);
436 1060 : if (layerActivity) {
437 9 : LayerActivity::ActivityIndex activityIndex = LayerActivity::GetActivityIndexForProperty(aProperty);
438 9 : if (layerActivity->mRestyleCounts[activityIndex] >= 2) {
439 0 : return true;
440 : }
441 9 : if (CheckScrollInducedActivity(layerActivity, activityIndex, aBuilder)) {
442 0 : return true;
443 : }
444 : }
445 1060 : if (aProperty == eCSSProperty_transform && aFrame->Combines3DTransformWithAncestors()) {
446 0 : return IsStyleAnimated(aBuilder, aFrame->GetParent(), aProperty);
447 : }
448 1060 : return nsLayoutUtils::HasEffectiveAnimation(aFrame, aProperty);
449 : }
450 :
451 : /* static */ bool
452 3429 : ActiveLayerTracker::IsOffsetOrMarginStyleAnimated(nsIFrame* aFrame)
453 : {
454 3429 : LayerActivity* layerActivity = GetLayerActivity(aFrame);
455 3429 : if (layerActivity) {
456 124 : if (layerActivity->mRestyleCounts[LayerActivity::ACTIVITY_LEFT] >= 2 ||
457 124 : layerActivity->mRestyleCounts[LayerActivity::ACTIVITY_TOP] >= 2 ||
458 124 : layerActivity->mRestyleCounts[LayerActivity::ACTIVITY_RIGHT] >= 2 ||
459 124 : layerActivity->mRestyleCounts[LayerActivity::ACTIVITY_BOTTOM] >= 2 ||
460 124 : layerActivity->mRestyleCounts[LayerActivity::ACTIVITY_MARGIN_LEFT] >= 2 ||
461 124 : layerActivity->mRestyleCounts[LayerActivity::ACTIVITY_MARGIN_TOP] >= 2 ||
462 124 : layerActivity->mRestyleCounts[LayerActivity::ACTIVITY_MARGIN_RIGHT] >= 2 ||
463 62 : layerActivity->mRestyleCounts[LayerActivity::ACTIVITY_MARGIN_BOTTOM] >= 2) {
464 0 : return true;
465 : }
466 : }
467 : // We should also check for running CSS animations of these properties once
468 : // bug 1009693 is fixed. Until that happens, layerization isn't useful for
469 : // animations of these properties because we'll invalidate the layer contents
470 : // on every change anyway.
471 : // See bug 1151346 for a patch that adds a check for CSS animations.
472 3429 : return false;
473 : }
474 :
475 : /* static */ bool
476 0 : ActiveLayerTracker::IsScaleSubjectToAnimation(nsIFrame* aFrame)
477 : {
478 : // Check whether JavaScript is animating this frame's scale.
479 0 : LayerActivity* layerActivity = GetLayerActivity(aFrame);
480 0 : if (layerActivity && layerActivity->mRestyleCounts[LayerActivity::ACTIVITY_SCALE] >= 2) {
481 0 : return true;
482 : }
483 :
484 : // Check if any animations, transitions, etc. associated with this frame may
485 : // animate its scale.
486 0 : EffectSet* effects = EffectSet::GetEffectSet(aFrame);
487 0 : if (effects &&
488 0 : AnimationUtils::EffectSetContainsAnimatedScale(*effects, aFrame)) {
489 0 : return true;
490 : }
491 :
492 0 : return false;
493 : }
494 :
495 : /* static */ void
496 0 : ActiveLayerTracker::NotifyContentChange(nsIFrame* aFrame)
497 : {
498 0 : LayerActivity* layerActivity = GetLayerActivityForUpdate(aFrame);
499 0 : layerActivity->mContentActive = true;
500 0 : }
501 :
502 : /* static */ bool
503 0 : ActiveLayerTracker::IsContentActive(nsIFrame* aFrame)
504 : {
505 0 : LayerActivity* layerActivity = GetLayerActivity(aFrame);
506 0 : return layerActivity && layerActivity->mContentActive;
507 : }
508 :
509 : /* static */ void
510 0 : ActiveLayerTracker::SetCurrentScrollHandlerFrame(nsIFrame* aFrame)
511 : {
512 0 : if (!gLayerActivityTracker) {
513 0 : gLayerActivityTracker = new LayerActivityTracker(
514 0 : SystemGroup::EventTargetFor(TaskCategory::Other));
515 : }
516 0 : gLayerActivityTracker->mCurrentScrollHandlerFrame = aFrame;
517 0 : }
518 :
519 : /* static */ void
520 0 : ActiveLayerTracker::Shutdown()
521 : {
522 0 : delete gLayerActivityTracker;
523 0 : gLayerActivityTracker = nullptr;
524 0 : }
525 :
526 : } // namespace mozilla
|