mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-20 00:35:44 +00:00
Bug 1216030 - Part 16: Move CanThrottleAnimation and CanThrottleTransformChanges from AnimationCollection into KeyframeEffectReadOnly::CanThrottle. r=bbirtles
The preference check has been removed from CanThrottleTransformChanges because we already perform that check that when deciding if we should run an animation on the compositor (in CanPerformOnCompositorThread, as called by GetAnimationsForCompositor). Hence if the "is running on compositor" flag is true, we can assume the preference is set (or was set when we decided to put the animation on the compositor-- we don't worry about pulling the animation off the compositor immediately if the preference changes while it is running)
This commit is contained in:
parent
6e809a002a
commit
325530125c
@ -9,8 +9,10 @@
|
||||
#include "mozilla/dom/KeyframeEffectBinding.h"
|
||||
#include "mozilla/dom/PropertyIndexedKeyframesBinding.h"
|
||||
#include "mozilla/FloatingPoint.h"
|
||||
#include "mozilla/LookAndFeel.h" // For LookAndFeel::GetInt
|
||||
#include "mozilla/StyleAnimationValue.h"
|
||||
#include "AnimationCommon.h"
|
||||
#include "Layers.h" // For Layer
|
||||
#include "nsCSSParser.h"
|
||||
#include "nsCSSPropertySet.h"
|
||||
#include "nsCSSProps.h" // For nsCSSProps::PropHasFlags
|
||||
@ -1726,14 +1728,110 @@ KeyframeEffectReadOnly::GetFrames(JSContext*& aCx,
|
||||
bool
|
||||
KeyframeEffectReadOnly::CanThrottle() const
|
||||
{
|
||||
// Animation::CanThrottle checks for finished and not in effect animations
|
||||
// before calling this.
|
||||
MOZ_ASSERT(IsInEffect() && IsCurrent(),
|
||||
"Effect should be in effect and current");
|
||||
|
||||
nsIFrame* frame = GetAnimationFrame();
|
||||
if (!frame) {
|
||||
// There are two possible cases here.
|
||||
// a) No target element
|
||||
// b) The target element has no frame, e.g. because it is in a display:none
|
||||
// subtree.
|
||||
// In either case we can throttle the animation because there is no
|
||||
// need to update on the main thread.
|
||||
return true;
|
||||
}
|
||||
|
||||
// First we need to check layer generation and transform overflow
|
||||
// prior to the IsPropertyRunningOnCompositor check because we should
|
||||
// occasionally unthrottle these animations even if the animations are
|
||||
// already running on compositor.
|
||||
for (const LayerAnimationInfo::Record& record :
|
||||
LayerAnimationInfo::sRecords) {
|
||||
// Skip properties that are overridden in the cascade.
|
||||
// (GetAnimationOfProperty, as called by HasAnimationOfProperty,
|
||||
// only returns an animation if it currently wins in the cascade.)
|
||||
if (!HasAnimationOfProperty(record.mProperty)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
AnimationCollection* collection = GetCollection();
|
||||
MOZ_ASSERT(collection,
|
||||
"CanThrottle should be called on an effect associated with an animation");
|
||||
layers::Layer* layer =
|
||||
FrameLayerBuilder::GetDedicatedLayer(frame, record.mLayerType);
|
||||
// Unthrottle if the layer needs to be brought up to date with the animation.
|
||||
if (!layer ||
|
||||
collection->mAnimationGeneration > layer->GetAnimationGeneration()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If this is a transform animation that affects the overflow region,
|
||||
// we should unthrottle the animation periodically.
|
||||
if (record.mProperty == eCSSProperty_transform &&
|
||||
!CanThrottleTransformChanges(*frame)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
for (const AnimationProperty& property : mProperties) {
|
||||
if (!IsPropertyRunningOnCompositor(property.mProperty)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
KeyframeEffectReadOnly::CanThrottleTransformChanges(nsIFrame& aFrame) const
|
||||
{
|
||||
// If we know that the animation cannot cause overflow,
|
||||
// we can just disable flushes for this animation.
|
||||
|
||||
// If we don't show scrollbars, we don't care about overflow.
|
||||
if (LookAndFeel::GetInt(LookAndFeel::eIntID_ShowHideScrollbars) == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
nsPresContext* presContext = GetPresContext();
|
||||
// CanThrottleTransformChanges is only called as part of a refresh driver tick
|
||||
// in which case we expect to has a pres context.
|
||||
MOZ_ASSERT(presContext);
|
||||
|
||||
TimeStamp now =
|
||||
presContext->RefreshDriver()->MostRecentRefresh();
|
||||
|
||||
AnimationCollection* collection = GetCollection();
|
||||
MOZ_ASSERT(collection,
|
||||
"CanThrottleTransformChanges should be involved with animation collection");
|
||||
TimeStamp styleRuleRefreshTime = collection->mStyleRuleRefreshTime;
|
||||
// If this animation can cause overflow, we can throttle some of the ticks.
|
||||
if (!styleRuleRefreshTime.IsNull() &&
|
||||
(now - styleRuleRefreshTime) < TimeDuration::FromMilliseconds(200)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// If the nearest scrollable ancestor has overflow:hidden,
|
||||
// we don't care about overflow.
|
||||
nsIScrollableFrame* scrollable =
|
||||
nsLayoutUtils::GetNearestScrollableFrame(&aFrame);
|
||||
if (!scrollable) {
|
||||
return true;
|
||||
}
|
||||
|
||||
ScrollbarStyles ss = scrollable->GetScrollbarStyles();
|
||||
if (ss.mVertical == NS_STYLE_OVERFLOW_HIDDEN &&
|
||||
ss.mHorizontal == NS_STYLE_OVERFLOW_HIDDEN &&
|
||||
scrollable->GetLogicalScrollPosition() == nsPoint(0, 0)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
nsIFrame*
|
||||
KeyframeEffectReadOnly::GetAnimationFrame() const
|
||||
{
|
||||
|
@ -328,6 +328,9 @@ protected:
|
||||
|
||||
private:
|
||||
nsIFrame* GetAnimationFrame() const;
|
||||
|
||||
bool CanThrottleTransformChanges(nsIFrame& aFrame) const;
|
||||
|
||||
// Returns true unless Gecko limitations prevent performing transform
|
||||
// animations for |aFrame|. Any limitations that are encountered are
|
||||
// logged using |aContent| to describe the affected content.
|
||||
|
@ -17,9 +17,7 @@
|
||||
#include "nsStyleContext.h"
|
||||
#include "nsIFrame.h"
|
||||
#include "nsLayoutUtils.h"
|
||||
#include "mozilla/LookAndFeel.h"
|
||||
#include "LayerAnimationInfo.h" // For LayerAnimationInfo::sRecords
|
||||
#include "Layers.h"
|
||||
#include "FrameLayerBuilder.h"
|
||||
#include "nsDisplayList.h"
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
@ -29,7 +27,6 @@
|
||||
#include "nsStyleSet.h"
|
||||
#include "nsStyleChangeList.h"
|
||||
|
||||
using mozilla::layers::Layer;
|
||||
using mozilla::dom::Animation;
|
||||
using mozilla::dom::KeyframeEffectReadOnly;
|
||||
|
||||
@ -603,91 +600,6 @@ AnimationCollection::EnsureStyleRuleFor(TimeStamp aRefreshTime)
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
AnimationCollection::CanThrottleTransformChanges(TimeStamp aTime)
|
||||
{
|
||||
if (!nsLayoutUtils::AreAsyncAnimationsEnabled()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If we know that the animation cannot cause overflow,
|
||||
// we can just disable flushes for this animation.
|
||||
|
||||
// If we don't show scrollbars, we don't care about overflow.
|
||||
if (LookAndFeel::GetInt(LookAndFeel::eIntID_ShowHideScrollbars) == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// If this animation can cause overflow, we can throttle some of the ticks.
|
||||
if (!mStyleRuleRefreshTime.IsNull() &&
|
||||
(aTime - mStyleRuleRefreshTime) < TimeDuration::FromMilliseconds(200)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
dom::Element* element = GetElementToRestyle();
|
||||
if (!element) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If the nearest scrollable ancestor has overflow:hidden,
|
||||
// we don't care about overflow.
|
||||
nsIScrollableFrame* scrollable = nsLayoutUtils::GetNearestScrollableFrame(
|
||||
nsLayoutUtils::GetStyleFrame(element));
|
||||
if (!scrollable) {
|
||||
return true;
|
||||
}
|
||||
|
||||
ScrollbarStyles ss = scrollable->GetScrollbarStyles();
|
||||
if (ss.mVertical == NS_STYLE_OVERFLOW_HIDDEN &&
|
||||
ss.mHorizontal == NS_STYLE_OVERFLOW_HIDDEN &&
|
||||
scrollable->GetLogicalScrollPosition() == nsPoint(0, 0)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
AnimationCollection::CanThrottleAnimation(TimeStamp aTime)
|
||||
{
|
||||
dom::Element* element = GetElementToRestyle();
|
||||
if (!element) {
|
||||
return false;
|
||||
}
|
||||
nsIFrame* frame = nsLayoutUtils::GetStyleFrame(element);
|
||||
if (!frame) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (const LayerAnimationInfo::Record& record :
|
||||
LayerAnimationInfo::sRecords) {
|
||||
// We only need to worry about *current* animations here.
|
||||
// - If we have a newly-finished animation, Animation::CanThrottle will
|
||||
// detect that and force an unthrottled sample.
|
||||
// - If we have a newly-idle animation, then whatever caused the animation
|
||||
// to be idle will update the animation generation so we'll return false
|
||||
// from the layer generation check below for any other running compositor
|
||||
// animations (and if no other compositor animations exist we won't get
|
||||
// this far).
|
||||
if (!HasCurrentAnimationOfProperty(record.mProperty)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Layer* layer = FrameLayerBuilder::GetDedicatedLayer(
|
||||
frame, record.mLayerType);
|
||||
if (!layer || mAnimationGeneration > layer->GetAnimationGeneration()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (record.mProperty == eCSSProperty_transform &&
|
||||
!CanThrottleTransformChanges(aTime)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
AnimationCollection::ClearIsRunningOnCompositor(nsCSSProperty aProperty)
|
||||
{
|
||||
@ -729,15 +641,6 @@ AnimationCollection::RequestRestyle(RestyleType aRestyleType)
|
||||
return;
|
||||
}
|
||||
|
||||
// Upgrade throttled restyles if other factors prevent
|
||||
// throttling (e.g. async animations are not enabled).
|
||||
if (aRestyleType == RestyleType::Throttled) {
|
||||
TimeStamp now = presContext->RefreshDriver()->MostRecentRefresh();
|
||||
if (!CanThrottleAnimation(now)) {
|
||||
aRestyleType = RestyleType::Standard;
|
||||
}
|
||||
}
|
||||
|
||||
if (aRestyleType >= RestyleType::Standard) {
|
||||
mHasPendingAnimationRestyle = true;
|
||||
PostRestyleForAnimation(presContext);
|
||||
|
@ -259,11 +259,6 @@ struct AnimationCollection : public LinkedListElement<AnimationCollection>
|
||||
void RequestRestyle(RestyleType aRestyleType);
|
||||
void ClearIsRunningOnCompositor(nsCSSProperty aProperty);
|
||||
|
||||
private:
|
||||
|
||||
bool CanThrottleAnimation(TimeStamp aTime);
|
||||
bool CanThrottleTransformChanges(TimeStamp aTime);
|
||||
|
||||
public:
|
||||
// True if this animation can be performed on the compositor thread.
|
||||
//
|
||||
|
Loading…
Reference in New Issue
Block a user