Bug 1687263: part 4) Defer and in some cases avoid removing spellchecking-ranges...
[gecko.git] / layout / painting / ActiveLayerTracker.cpp
blob729ec344fc2af6cd3e4afd61df74413381eec04a
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"
31 namespace mozilla {
33 using namespace gfx;
35 /**
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.
45 class LayerActivity {
46 public:
47 enum ActivityIndex {
48 ACTIVITY_OPACITY,
49 ACTIVITY_TRANSFORM,
50 ACTIVITY_LEFT,
51 ACTIVITY_TOP,
52 ACTIVITY_RIGHT,
53 ACTIVITY_BOTTOM,
54 ACTIVITY_BACKGROUND_POSITION,
56 ACTIVITY_SCALE,
57 ACTIVITY_TRIGGERED_REPAINT,
59 // keep as last item
60 ACTIVITY_COUNT
63 explicit LayerActivity(nsIFrame* aFrame)
64 : mFrame(aFrame), mContent(nullptr), mContentActive(false) {
65 PodArrayZero(mRestyleCounts);
67 ~LayerActivity();
68 nsExpirationState* GetExpirationState() { return &mState; }
69 uint8_t& RestyleCountForProperty(nsCSSPropertyID aProperty) {
70 return mRestyleCounts[GetActivityIndexForProperty(aProperty)];
73 static ActivityIndex GetActivityIndexForProperty(nsCSSPropertyID aProperty) {
74 switch (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:
88 return ACTIVITY_LEFT;
89 case eCSSProperty_top:
90 return ACTIVITY_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;
101 default:
102 MOZ_ASSERT(false);
103 return ACTIVITY_OPACITY;
107 static ActivityIndex GetActivityIndexForPropertySet(
108 const nsCSSPropertyIDSet& aPropertySet) {
109 if (aPropertySet.IsSubsetOf(
110 nsCSSPropertyIDSet::TransformLikeProperties())) {
111 return ACTIVITY_TRANSFORM;
113 MOZ_ASSERT(
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.
122 nsIFrame* mFrame;
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];
139 bool mContentActive;
142 class LayerActivityTracker final
143 : public nsExpirationTracker<LayerActivity, 4> {
144 public:
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 {
153 mDestroying = true;
154 AgeAllGenerations();
157 void NotifyExpired(LayerActivity* aObject) override;
159 public:
160 WeakFrame mCurrentScrollHandlerFrame;
162 private:
163 bool mDestroying;
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);
182 MarkUsed(aObject);
183 return;
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");
197 if (f) {
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());
205 } else {
206 c->RemoveProperty(nsGkAtoms::LayerActivity);
210 static LayerActivity* GetLayerActivity(nsIFrame* aFrame) {
211 if (!aFrame->HasAnyStateBits(NS_FRAME_HAS_LAYER_ACTIVITY_PROPERTY)) {
212 return nullptr;
214 return aFrame->GetProperty(LayerActivityProperty());
217 static LayerActivity* GetLayerActivityForUpdate(nsIFrame* aFrame) {
218 LayerActivity* layerActivity = GetLayerActivity(aFrame);
219 if (layerActivity) {
220 gLayerActivityTracker->MarkUsed(layerActivity);
221 } else {
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));
238 /* static */
239 void ActiveLayerTracker::TransferActivityToContent(nsIFrame* aFrame,
240 nsIContent* aContent) {
241 if (!aFrame->HasAnyStateBits(NS_FRAME_HAS_LAYER_ACTIVITY_PROPERTY)) {
242 return;
244 LayerActivity* layerActivity = aFrame->TakeProperty(LayerActivityProperty());
245 aFrame->RemoveStateBits(NS_FRAME_HAS_LAYER_ACTIVITY_PROPERTY);
246 if (!layerActivity) {
247 return;
249 layerActivity->mFrame = nullptr;
250 layerActivity->mContent = aContent;
251 aContent->SetProperty(nsGkAtoms::LayerActivity, layerActivity,
252 nsINode::DeleteProperty<LayerActivity>, true);
255 /* static */
256 void ActiveLayerTracker::TransferActivityToFrame(nsIContent* aContent,
257 nsIFrame* aFrame) {
258 auto* layerActivity = static_cast<LayerActivity*>(
259 aContent->TakeProperty(nsGkAtoms::LayerActivity));
260 if (!layerActivity) {
261 return;
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]);
278 return;
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());
288 Matrix transform2D;
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]);
294 return;
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]);
307 /* static */
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);
319 /* static */
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]);
332 /* static */
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;
349 /* static */
350 void ActiveLayerTracker::NotifyAnimatedFromScrollHandler(
351 nsIFrame* aFrame, nsCSSPropertyID aProperty, nsIFrame* aScrollFrame) {
352 if (aFrame->PresContext() != aScrollFrame->PresContext()) {
353 // Don't allow cross-document dependencies.
354 return;
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()) {
373 return true;
375 // Treat timeouts/setintervals as scripted animation callbacks for our
376 // purposes.
377 nsPIDOMWindowInner* win = aPresContext->Document()->GetInnerWindow();
378 return win && win->IsRunningTimeout();
381 /* static */
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(
391 aFrame, aProperty,
392 gLayerActivityTracker->mCurrentScrollHandlerFrame.GetFrame());
396 /* static */
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] =
403 0xFF;
404 } else {
405 IncrementMutationCount(
406 &layerActivity
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()) {
416 return false;
419 nsIScrollableFrame* scrollFrame =
420 do_QueryFrame(aLayerActivity->mAnimatingScrollHandlerFrame.GetFrame());
421 if (scrollFrame &&
422 (!aBuilder ||
423 scrollFrame->IsScrollingActiveNotMinimalDisplayPort(aBuilder))) {
424 return true;
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();
431 return false;
434 /* static */
435 bool ActiveLayerTracker::IsBackgroundPositionAnimated(
436 nsDisplayListBuilder* aBuilder, nsIFrame* aFrame) {
437 LayerActivity* layerActivity = GetLayerActivity(aFrame);
438 if (layerActivity) {
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.
447 if (layerActivity
448 ->mRestyleCounts[LayerActivity::ACTIVITY_TRIGGERED_REPAINT] < 2) {
449 return true;
452 if (CheckScrollInducedActivity(layerActivity, activityIndex, aBuilder)) {
453 return true;
456 return nsLayoutUtils::HasEffectiveAnimation(
457 aFrame, nsCSSPropertyIDSet({eCSSProperty_background_position_x,
458 eCSSProperty_background_position_y}));
461 static bool IsMotionPathAnimated(nsDisplayListBuilder* aBuilder,
462 nsIFrame* aFrame) {
463 return ActiveLayerTracker::IsStyleAnimated(
464 aBuilder, aFrame, nsCSSPropertyIDSet{eCSSProperty_offset_path}) ||
465 (!aFrame->StyleDisplay()->mOffsetPath.IsNone() &&
466 ActiveLayerTracker::IsStyleAnimated(
467 aBuilder, aFrame,
468 nsCSSPropertyIDSet{eCSSProperty_offset_distance,
469 eCSSProperty_offset_rotate,
470 eCSSProperty_offset_anchor}));
473 /* static */
474 bool ActiveLayerTracker::IsTransformAnimated(nsDisplayListBuilder* aBuilder,
475 nsIFrame* aFrame) {
476 return IsStyleAnimated(aBuilder, aFrame,
477 nsCSSPropertyIDSet::CSSTransformProperties()) ||
478 IsMotionPathAnimated(aBuilder, aFrame);
481 /* static */
482 bool ActiveLayerTracker::IsTransformMaybeAnimated(nsIFrame* aFrame) {
483 return IsStyleAnimated(nullptr, aFrame,
484 nsCSSPropertyIDSet::CSSTransformProperties()) ||
485 IsMotionPathAnimated(nullptr, aFrame);
488 /* static */
489 bool ActiveLayerTracker::IsStyleAnimated(
490 nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
491 const nsCSSPropertyIDSet& aPropertySet) {
492 MOZ_ASSERT(
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) &&
508 (!aBuilder ||
509 aBuilder->IsInWillChangeBudget(aFrame, aFrame->GetSize()))) {
510 return true;
512 if ((aFrame->StyleDisplay()->mWillChange.bits &
513 StyleWillChangeBits::OPACITY) &&
514 aPropertySet.Intersects(nsCSSPropertyIDSet::OpacityProperties()) &&
515 (!aBuilder ||
516 aBuilder->IsInWillChangeBudget(aFrame, aFrame->GetSize()))) {
517 return true;
520 LayerActivity* layerActivity = GetLayerActivity(aFrame);
521 if (layerActivity) {
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.
530 if (layerActivity
531 ->mRestyleCounts[LayerActivity::ACTIVITY_TRIGGERED_REPAINT] <
532 2 ||
533 (aPropertySet.Intersects(transformSet) &&
534 IsScaleSubjectToAnimation(aFrame))) {
535 return true;
538 if (CheckScrollInducedActivity(layerActivity, activityIndex, aBuilder)) {
539 return true;
543 if (nsLayoutUtils::HasEffectiveAnimation(aFrame, aPropertySet)) {
544 return true;
547 if (!aPropertySet.Intersects(transformSet) ||
548 !aFrame->Combines3DTransformWithAncestors()) {
549 return false;
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
554 // return true.
555 return IsStyleAnimated(aBuilder, aFrame->GetParent(), aPropertySet);
558 /* static */
559 bool ActiveLayerTracker::IsOffsetStyleAnimated(nsIFrame* aFrame) {
560 LayerActivity* layerActivity = GetLayerActivity(aFrame);
561 if (layerActivity) {
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) {
566 return true;
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.
574 return false;
577 /* static */
578 bool ActiveLayerTracker::IsScaleSubjectToAnimation(nsIFrame* aFrame) {
579 // Check whether JavaScript is animating this frame's scale.
580 LayerActivity* layerActivity = GetLayerActivity(aFrame);
581 if (layerActivity &&
582 layerActivity->mRestyleCounts[LayerActivity::ACTIVITY_SCALE] >= 2) {
583 return true;
586 return AnimationUtils::FrameHasAnimatedScale(aFrame);
589 /* static */
590 void ActiveLayerTracker::NotifyContentChange(nsIFrame* aFrame) {
591 LayerActivity* layerActivity = GetLayerActivityForUpdate(aFrame);
592 layerActivity->mContentActive = true;
595 /* static */
596 bool ActiveLayerTracker::IsContentActive(nsIFrame* aFrame) {
597 LayerActivity* layerActivity = GetLayerActivity(aFrame);
598 return layerActivity && layerActivity->mContentActive;
601 /* static */
602 void ActiveLayerTracker::SetCurrentScrollHandlerFrame(nsIFrame* aFrame) {
603 if (!gLayerActivityTracker) {
604 gLayerActivityTracker =
605 new LayerActivityTracker(GetMainThreadSerialEventTarget());
607 gLayerActivityTracker->mCurrentScrollHandlerFrame = aFrame;
610 /* static */
611 void ActiveLayerTracker::Shutdown() {
612 delete gLayerActivityTracker;
613 gLayerActivityTracker = nullptr;
616 } // namespace mozilla