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