Coverage Report

Created: 2018-09-25 14:53

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