mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 768440 Part 2: Animate CSS Transitions on the compositor r=roc,dbaron
This commit is contained in:
parent
3328afd1c5
commit
8c734bee81
@ -11,6 +11,7 @@
|
||||
#include "nsChangeHint.h"
|
||||
#include "nsINode.h"
|
||||
#include "nsIDocument.h" // for IsInHTMLDocument
|
||||
#include "nsCSSProperty.h"
|
||||
|
||||
// Forward declarations
|
||||
class nsIAtom;
|
||||
|
@ -39,6 +39,7 @@
|
||||
#include "nsSVGClipPathFrame.h"
|
||||
#include "sampler.h"
|
||||
#include "nsAnimationManager.h"
|
||||
#include "nsTransitionManager.h"
|
||||
#include "nsIViewManager.h"
|
||||
|
||||
#include "mozilla/StandardInteger.h"
|
||||
@ -267,116 +268,147 @@ ToTimingFunction(css::ComputedTimingFunction& aCTF)
|
||||
}
|
||||
|
||||
static void
|
||||
AddTransformAnimations(ElementAnimations* ea, Layer* aLayer,
|
||||
const nsPoint& aOrigin)
|
||||
AddAnimationsForProperty(nsIFrame* aFrame, nsCSSProperty aProperty,
|
||||
ElementAnimation* ea, Layer* aLayer,
|
||||
AnimationData& aData)
|
||||
{
|
||||
if (!ea)
|
||||
return;
|
||||
NS_ASSERTION(aLayer->AsContainerLayer(), "Should only animate ContainerLayer");
|
||||
nsIFrame* frame = ea->mElement->GetPrimaryFrame();
|
||||
nsRect bounds = nsDisplayTransform::GetFrameBoundsForTransform(frame);
|
||||
nsStyleContext* styleContext = aFrame->GetStyleContext();
|
||||
nsPresContext* presContext = aFrame->PresContext();
|
||||
nsRect bounds = nsDisplayTransform::GetFrameBoundsForTransform(aFrame);
|
||||
float scale = nsDeviceContext::AppUnitsPerCSSPixel();
|
||||
gfxPoint3D offsetToTransformOrigin =
|
||||
nsDisplayTransform::GetDeltaToMozTransformOrigin(frame, scale, &bounds);
|
||||
gfxPoint3D offsetToPerspectiveOrigin =
|
||||
nsDisplayTransform::GetDeltaToMozPerspectiveOrigin(frame, scale);
|
||||
nscoord perspective = 0.0;
|
||||
nsStyleContext* parentStyleContext = frame->GetStyleContext()->GetParent();
|
||||
if (parentStyleContext) {
|
||||
const nsStyleDisplay* disp = parentStyleContext->GetStyleDisplay();
|
||||
if (disp && disp->mChildPerspective.GetUnit() == eStyleUnit_Coord) {
|
||||
perspective = disp->mChildPerspective.GetCoordValue();
|
||||
}
|
||||
}
|
||||
|
||||
for (PRUint32 animIdx = 0; animIdx < ea->mAnimations.Length(); animIdx++) {
|
||||
ElementAnimation* anim = &ea->mAnimations[animIdx];
|
||||
if (!anim->CanPerformOnCompositor(ea->mElement, TimeStamp::Now())) {
|
||||
float iterations = ea->mIterationCount != NS_IEEEPositiveInfinity()
|
||||
? ea->mIterationCount : -1;
|
||||
for (PRUint32 propIdx = 0; propIdx < ea->mProperties.Length(); propIdx++) {
|
||||
AnimationProperty* property = &ea->mProperties[propIdx];
|
||||
InfallibleTArray<AnimationSegment> segments;
|
||||
|
||||
if (aProperty != property->mProperty) {
|
||||
continue;
|
||||
}
|
||||
float iterations = anim->mIterationCount != NS_IEEEPositiveInfinity()
|
||||
? anim->mIterationCount : -1;
|
||||
for (PRUint32 propIdx = 0; propIdx < anim->mProperties.Length(); propIdx++) {
|
||||
AnimationProperty* property = &anim->mProperties[propIdx];
|
||||
InfallibleTArray<AnimationSegment> segments;
|
||||
|
||||
if (property->mProperty != eCSSProperty_transform) {
|
||||
continue;
|
||||
}
|
||||
for (PRUint32 segIdx = 0; segIdx < property->mSegments.Length(); segIdx++) {
|
||||
AnimationPropertySegment* segment = &property->mSegments[segIdx];
|
||||
|
||||
for (PRUint32 segIdx = 0; segIdx < property->mSegments.Length(); segIdx++) {
|
||||
AnimationPropertySegment* segment = &property->mSegments[segIdx];
|
||||
if (aProperty == eCSSProperty_transform) {
|
||||
nsCSSValueList* list = segment->mFromValue.GetCSSValueListValue();
|
||||
InfallibleTArray<TransformFunction> fromFunctions;
|
||||
AddTransformFunctions(list, frame->GetStyleContext(),
|
||||
frame->PresContext(), bounds,
|
||||
AddTransformFunctions(list, styleContext,
|
||||
presContext, bounds,
|
||||
scale, fromFunctions);
|
||||
|
||||
list = segment->mToValue.GetCSSValueListValue();
|
||||
InfallibleTArray<TransformFunction> toFunctions;
|
||||
AddTransformFunctions(list, frame->GetStyleContext(),
|
||||
frame->PresContext(), bounds,
|
||||
AddTransformFunctions(list, styleContext,
|
||||
presContext, bounds,
|
||||
scale, toFunctions);
|
||||
|
||||
segments.AppendElement(AnimationSegment(fromFunctions, toFunctions,
|
||||
segment->mFromKey, segment->mToKey,
|
||||
ToTimingFunction(segment->mTimingFunction)));
|
||||
}
|
||||
|
||||
if (segments.Length() == 0) {
|
||||
continue;
|
||||
}
|
||||
aLayer->AddAnimation(Animation(anim->mStartTime,
|
||||
anim->mIterationDuration,
|
||||
segments,
|
||||
iterations,
|
||||
anim->mDirection,
|
||||
TransformData(aOrigin, offsetToTransformOrigin,
|
||||
offsetToPerspectiveOrigin,
|
||||
bounds, perspective)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
AddOpacityAnimations(ElementAnimations* ea, Layer* aLayer)
|
||||
{
|
||||
if (!ea)
|
||||
return;
|
||||
NS_ASSERTION(aLayer->AsContainerLayer(), "Should only animate ContainerLayer");
|
||||
for (PRUint32 animIdx = 0; animIdx < ea->mAnimations.Length(); animIdx++) {
|
||||
ElementAnimation* anim = &ea->mAnimations[animIdx];
|
||||
float iterations = anim->mIterationCount != NS_IEEEPositiveInfinity()
|
||||
? anim->mIterationCount : -1;
|
||||
if (!anim->CanPerformOnCompositor(ea->mElement, TimeStamp::Now())) {
|
||||
continue;
|
||||
}
|
||||
for (PRUint32 propIdx = 0; propIdx < anim->mProperties.Length(); propIdx++) {
|
||||
AnimationProperty* property = &anim->mProperties[propIdx];
|
||||
InfallibleTArray<AnimationSegment> segments;
|
||||
if (property->mProperty != eCSSProperty_opacity) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (PRUint32 segIdx = 0; segIdx < property->mSegments.Length(); segIdx++) {
|
||||
AnimationPropertySegment* segment = &property->mSegments[segIdx];
|
||||
} else if (aProperty == eCSSProperty_opacity) {
|
||||
segments.AppendElement(AnimationSegment(Opacity(segment->mFromValue.GetFloatValue()),
|
||||
Opacity(segment->mToValue.GetFloatValue()),
|
||||
segment->mFromKey,
|
||||
segment->mToKey,
|
||||
ToTimingFunction(segment->mTimingFunction)));
|
||||
}
|
||||
}
|
||||
|
||||
aLayer->AddAnimation(Animation(anim->mStartTime,
|
||||
anim->mIterationDuration,
|
||||
segments,
|
||||
iterations,
|
||||
anim->mDirection,
|
||||
null_t()));
|
||||
}
|
||||
aLayer->AddAnimation(Animation(ea->mStartTime,
|
||||
ea->mIterationDuration,
|
||||
segments,
|
||||
iterations,
|
||||
ea->mDirection,
|
||||
aData));
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
AddAnimationsAndTransitionsToLayer(Layer* aLayer, nsDisplayItem* aItem,
|
||||
nsCSSProperty aProperty)
|
||||
{
|
||||
aLayer->ClearAnimations();
|
||||
|
||||
nsIFrame* frame = aItem->GetUnderlyingFrame();
|
||||
nsIContent* aContent = frame->GetContent();
|
||||
ElementTransitions* et =
|
||||
nsTransitionManager::GetTransitionsForCompositor(aContent, aProperty);
|
||||
|
||||
ElementAnimations* ea =
|
||||
nsAnimationManager::GetAnimationsForCompositor(aContent, aProperty);
|
||||
|
||||
if (!ea && !et) {
|
||||
return;
|
||||
}
|
||||
|
||||
mozilla::TimeStamp currentTime =
|
||||
frame->PresContext()->RefreshDriver()->MostRecentRefresh();
|
||||
AnimationData data;
|
||||
if (aProperty == eCSSProperty_transform) {
|
||||
nsRect bounds = nsDisplayTransform::GetFrameBoundsForTransform(frame);
|
||||
float scale = nsDeviceContext::AppUnitsPerCSSPixel();
|
||||
gfxPoint3D offsetToTransformOrigin =
|
||||
nsDisplayTransform::GetDeltaToMozTransformOrigin(frame, scale, &bounds);
|
||||
gfxPoint3D offsetToPerspectiveOrigin =
|
||||
nsDisplayTransform::GetDeltaToMozPerspectiveOrigin(frame, scale);
|
||||
nscoord perspective = 0.0;
|
||||
nsStyleContext* parentStyleContext = frame->GetStyleContext()->GetParent();
|
||||
if (parentStyleContext) {
|
||||
const nsStyleDisplay* disp = parentStyleContext->GetStyleDisplay();
|
||||
if (disp && disp->mChildPerspective.GetUnit() == eStyleUnit_Coord) {
|
||||
perspective = disp->mChildPerspective.GetCoordValue();
|
||||
}
|
||||
}
|
||||
nsPoint origin = aItem->ToReferenceFrame();
|
||||
|
||||
data = TransformData(origin, offsetToTransformOrigin,
|
||||
offsetToPerspectiveOrigin, bounds, perspective);
|
||||
} else if (aProperty == eCSSProperty_opacity) {
|
||||
data = null_t();
|
||||
}
|
||||
|
||||
if (et) {
|
||||
for (PRUint32 tranIdx = 0; tranIdx < et->mPropertyTransitions.Length(); tranIdx++) {
|
||||
ElementPropertyTransition* pt = &et->mPropertyTransitions[tranIdx];
|
||||
if (!pt->CanPerformOnCompositor(et->mElement, currentTime)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ElementAnimation anim;
|
||||
anim.mIterationCount = 1;
|
||||
anim.mDirection = NS_STYLE_ANIMATION_DIRECTION_NORMAL;
|
||||
anim.mFillMode = NS_STYLE_ANIMATION_FILL_MODE_NONE;
|
||||
anim.mStartTime = pt->mStartTime;
|
||||
anim.mIterationDuration = pt->mDuration;
|
||||
|
||||
AnimationProperty& prop = *anim.mProperties.AppendElement();
|
||||
prop.mProperty = pt->mProperty;
|
||||
|
||||
AnimationPropertySegment& segment = *prop.mSegments.AppendElement();
|
||||
segment.mFromKey = 0;
|
||||
segment.mToKey = 1;
|
||||
segment.mFromValue = pt->mStartValue;
|
||||
segment.mToValue = pt->mEndValue;
|
||||
segment.mTimingFunction = pt->mTimingFunction;
|
||||
|
||||
AddAnimationsForProperty(frame, aProperty, &anim,
|
||||
aLayer, data);
|
||||
}
|
||||
}
|
||||
|
||||
if (ea) {
|
||||
for (PRUint32 animIdx = 0; animIdx < ea->mAnimations.Length(); animIdx++) {
|
||||
ElementAnimation* anim = &ea->mAnimations[animIdx];
|
||||
if (!anim->CanPerformOnCompositor(ea->mElement, currentTime)) {
|
||||
continue;
|
||||
}
|
||||
AddAnimationsForProperty(frame, aProperty, anim,
|
||||
aLayer, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nsDisplayListBuilder::nsDisplayListBuilder(nsIFrame* aReferenceFrame,
|
||||
Mode aMode, bool aBuildCaret)
|
||||
@ -2321,12 +2353,7 @@ nsDisplayOpacity::BuildLayer(nsDisplayListBuilder* aBuilder,
|
||||
return nullptr;
|
||||
|
||||
container->SetOpacity(mFrame->GetStyleDisplay()->mOpacity);
|
||||
|
||||
container->ClearAnimations();
|
||||
ElementAnimations* ea =
|
||||
nsAnimationManager::GetAnimationsForCompositor(mFrame->GetContent(),
|
||||
eCSSProperty_opacity);
|
||||
AddOpacityAnimations(ea, container);
|
||||
AddAnimationsAndTransitionsToLayer(container, this, eCSSProperty_opacity);
|
||||
|
||||
return container.forget();
|
||||
}
|
||||
@ -2354,8 +2381,8 @@ nsDisplayOpacity::GetLayerState(nsDisplayListBuilder* aBuilder,
|
||||
!IsItemTooSmallForActiveLayer(this))
|
||||
return LAYER_ACTIVE;
|
||||
if (mFrame->GetContent()) {
|
||||
if (nsAnimationManager::GetAnimationsForCompositor(mFrame->GetContent(),
|
||||
eCSSProperty_opacity)) {
|
||||
if (nsLayoutUtils::HasAnimationsForCompositor(mFrame->GetContent(),
|
||||
eCSSProperty_opacity)) {
|
||||
return LAYER_ACTIVE;
|
||||
}
|
||||
}
|
||||
@ -3338,12 +3365,7 @@ already_AddRefed<Layer> nsDisplayTransform::BuildLayer(nsDisplayListBuilder *aBu
|
||||
container->SetContentFlags(container->GetContentFlags() | Layer::CONTENT_PRESERVE_3D);
|
||||
}
|
||||
|
||||
container->ClearAnimations();
|
||||
ElementAnimations* ea =
|
||||
nsAnimationManager::GetAnimationsForCompositor(mFrame->GetContent(),
|
||||
eCSSProperty_transform);
|
||||
AddTransformAnimations(ea, container, ToReferenceFrame());
|
||||
|
||||
AddAnimationsAndTransitionsToLayer(container, this, eCSSProperty_transform);
|
||||
return container.forget();
|
||||
}
|
||||
|
||||
@ -3359,8 +3381,8 @@ nsDisplayTransform::GetLayerState(nsDisplayListBuilder* aBuilder,
|
||||
if (!GetTransform(mFrame->PresContext()->AppUnitsPerDevPixel()).Is2D() || mFrame->Preserves3D())
|
||||
return LAYER_ACTIVE;
|
||||
if (mFrame->GetContent()) {
|
||||
if (nsAnimationManager::GetAnimationsForCompositor(mFrame->GetContent(),
|
||||
eCSSProperty_transform)) {
|
||||
if (nsLayoutUtils::HasAnimationsForCompositor(mFrame->GetContent(),
|
||||
eCSSProperty_transform)) {
|
||||
return LAYER_ACTIVE;
|
||||
}
|
||||
}
|
||||
|
@ -108,10 +108,10 @@ public:
|
||||
* display lists that we make.
|
||||
*/
|
||||
enum Mode {
|
||||
PAINTING,
|
||||
EVENT_DELIVERY,
|
||||
PLUGIN_GEOMETRY,
|
||||
OTHER
|
||||
PAINTING,
|
||||
EVENT_DELIVERY,
|
||||
PLUGIN_GEOMETRY,
|
||||
OTHER
|
||||
};
|
||||
nsDisplayListBuilder(nsIFrame* aReferenceFrame, Mode aMode, bool aBuildCaret);
|
||||
~nsDisplayListBuilder();
|
||||
|
@ -83,6 +83,8 @@
|
||||
#endif
|
||||
|
||||
#include "sampler.h"
|
||||
#include "nsAnimationManager.h"
|
||||
#include "nsTransitionManager.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::layers;
|
||||
@ -113,6 +115,32 @@ static ContentMap& GetContentMap() {
|
||||
return *sContentMap;
|
||||
}
|
||||
|
||||
bool
|
||||
nsLayoutUtils::HasAnimationsForCompositor(nsIContent* aContent,
|
||||
nsCSSProperty aProperty)
|
||||
{
|
||||
if (!aContent->MayHaveAnimations())
|
||||
return false;
|
||||
ElementAnimations* animations =
|
||||
static_cast<ElementAnimations*>(aContent->GetProperty(nsGkAtoms::animationsProperty));
|
||||
if (animations) {
|
||||
bool propertyMatches = animations->HasAnimationOfProperty(aProperty);
|
||||
if (propertyMatches && animations->CanPerformOnCompositorThread()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
ElementTransitions* transitions =
|
||||
static_cast<ElementTransitions*>(aContent->GetProperty(nsGkAtoms::transitionsProperty));
|
||||
if (transitions) {
|
||||
bool propertyMatches = transitions->HasTransitionOfProperty(aProperty);
|
||||
if (propertyMatches && transitions->CanPerformOnCompositorThread()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
nsLayoutUtils::Are3DTransformsEnabled()
|
||||
|
@ -1497,6 +1497,13 @@ public:
|
||||
nsMallocSizeOfFun aMallocSizeOf,
|
||||
bool clear);
|
||||
|
||||
/**
|
||||
* Returns true if the content node has animations or transitions that can be
|
||||
* performed on the compositor.
|
||||
*/
|
||||
static bool HasAnimationsForCompositor(nsIContent* aContent,
|
||||
nsCSSProperty aProperty);
|
||||
|
||||
/**
|
||||
* Checks if CSS 3D transforms are currently enabled.
|
||||
*/
|
||||
|
@ -93,6 +93,7 @@
|
||||
#include "nsAbsoluteContainingBlock.h"
|
||||
#include "nsFontInflationData.h"
|
||||
#include "nsAnimationManager.h"
|
||||
#include "nsTransitionManager.h"
|
||||
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/LookAndFeel.h"
|
||||
@ -940,14 +941,16 @@ nsIFrame::IsTransformed() const
|
||||
(GetStyleDisplay()->HasTransform() ||
|
||||
IsSVGTransformed() ||
|
||||
(mContent &&
|
||||
nsAnimationManager::GetAnimationsForCompositor(mContent, eCSSProperty_transform))));
|
||||
nsLayoutUtils::HasAnimationsForCompositor(mContent,
|
||||
eCSSProperty_transform))));
|
||||
}
|
||||
|
||||
bool
|
||||
nsIFrame::HasOpacity() const
|
||||
{
|
||||
return GetStyleDisplay()->mOpacity < 1.0f || (mContent &&
|
||||
nsAnimationManager::GetAnimationsForCompositor(mContent, eCSSProperty_opacity));
|
||||
nsLayoutUtils::HasAnimationsForCompositor(mContent,
|
||||
eCSSProperty_opacity));
|
||||
}
|
||||
|
||||
bool
|
||||
@ -1774,9 +1777,12 @@ nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder,
|
||||
nsRect clipPropClip;
|
||||
const nsStyleDisplay* disp = GetStyleDisplay();
|
||||
// We can stop right away if this is a zero-opacity stacking context and
|
||||
// we're painting.
|
||||
if (disp->mOpacity == 0.0 && aBuilder->IsForPainting())
|
||||
// we're painting, and we're not animating opacity.
|
||||
if (disp->mOpacity == 0.0 && aBuilder->IsForPainting() &&
|
||||
!nsLayoutUtils::HasAnimationsForCompositor(mContent,
|
||||
eCSSProperty_opacity)) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
bool applyClipPropClipping =
|
||||
ApplyClipPropClipping(aBuilder, disp, this, &clipPropClip);
|
||||
@ -1791,7 +1797,7 @@ nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder,
|
||||
// Trying to back-transform arbitrary rects gives us really weird results. I believe
|
||||
// this is from points that lie beyond the vanishing point. As a workaround we transform t
|
||||
// he overflow rect into screen space and compare in that coordinate system.
|
||||
|
||||
|
||||
// Transform the overflow rect into screen space
|
||||
nsRect overflow = GetVisualOverflowRectRelativeToSelf();
|
||||
nsPoint offset = aBuilder->ToReferenceFrame(this);
|
||||
@ -1921,7 +1927,6 @@ nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder,
|
||||
// resultList was emptied
|
||||
resultList.AppendToTop(item);
|
||||
}
|
||||
|
||||
/* If there are any SVG effects, wrap the list up in an SVG effects item
|
||||
* (which also handles CSS group opacity). Note that we create an SVG effects
|
||||
* item even if resultList is empty, since a filter can produce graphical
|
||||
|
@ -22,6 +22,8 @@
|
||||
#include "nsEventDispatcher.h"
|
||||
#include "nsGUIEvent.h"
|
||||
#include "mozilla/dom/Element.h"
|
||||
#include "nsIFrame.h"
|
||||
#include "nsCSSFrameConstructor.h"
|
||||
|
||||
using mozilla::TimeStamp;
|
||||
using mozilla::TimeDuration;
|
||||
@ -36,7 +38,6 @@ ElementTransitions::ElementTransitions(mozilla::dom::Element *aElement, nsIAtom
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
double
|
||||
ElementPropertyTransition::ValuePortionFor(TimeStamp aRefreshTime) const
|
||||
{
|
||||
@ -107,6 +108,41 @@ ElementTransitions::EnsureStyleRuleFor(TimeStamp aRefreshTime)
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
ElementPropertyTransition::CanPerformOnCompositor(mozilla::dom::Element* aElement,
|
||||
TimeStamp aTime) const {
|
||||
return css::CommonElementAnimationData::
|
||||
CanAnimatePropertyOnCompositor(aElement, mProperty) && !IsRemovedSentinel() &&
|
||||
mStartTime < aTime && aTime < mStartTime + mDuration;
|
||||
}
|
||||
|
||||
bool
|
||||
ElementTransitions::HasTransitionOfProperty(nsCSSProperty aProperty) const
|
||||
{
|
||||
for (PRUint32 tranIdx = mPropertyTransitions.Length(); tranIdx-- != 0; ) {
|
||||
if (aProperty == mPropertyTransitions[tranIdx].mProperty) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
ElementTransitions::CanPerformOnCompositorThread() const
|
||||
{
|
||||
for (PRUint32 i = 0, i_end = mPropertyTransitions.Length(); i < i_end; ++i) {
|
||||
const ElementPropertyTransition &pt = mPropertyTransitions[i];
|
||||
if (pt.IsRemovedSentinel()) {
|
||||
continue;
|
||||
}
|
||||
if (!css::CommonElementAnimationData::CanAnimatePropertyOnCompositor(mElement,
|
||||
pt.mProperty)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* nsTransitionManager *
|
||||
*****************************************************************************/
|
||||
@ -298,10 +334,6 @@ nsTransitionManager::StyleContextChanged(dom::Element *aElement,
|
||||
// rule.
|
||||
|
||||
nsRefPtr<css::AnimValuesStyleRule> coverRule = new css::AnimValuesStyleRule;
|
||||
if (!coverRule) {
|
||||
NS_WARNING("out of memory");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsTArray<ElementPropertyTransition> &pts = et->mPropertyTransitions;
|
||||
for (PRUint32 i = 0, i_end = pts.Length(); i < i_end; ++i) {
|
||||
@ -347,9 +379,19 @@ nsTransitionManager::ConsiderStartingTransition(nsCSSProperty aProperty,
|
||||
pt.mStartValue) &&
|
||||
ExtractComputedValueForTransition(aProperty, aNewStyleContext,
|
||||
pt.mEndValue);
|
||||
|
||||
bool haveChange = pt.mStartValue != pt.mEndValue;
|
||||
bool haveOMTA = false;
|
||||
if (!aNewStyleContext->GetPseudoType()) {
|
||||
ElementTransitions* et = nsTransitionManager::GetTransitions(aElement);
|
||||
if (et) {
|
||||
haveOMTA = et->CanPerformOnCompositorThread();
|
||||
}
|
||||
}
|
||||
|
||||
bool shouldAnimate =
|
||||
haveValues &&
|
||||
pt.mStartValue != pt.mEndValue &&
|
||||
(haveChange || haveOMTA) &&
|
||||
// Check that we can interpolate between these values
|
||||
// (If this is ever a performance problem, we could add a
|
||||
// CanInterpolate method, but it seems fine for now.)
|
||||
@ -450,6 +492,7 @@ nsTransitionManager::ConsiderStartingTransition(nsCSSProperty aProperty,
|
||||
// reduce positive delays.
|
||||
if (delay < 0.0f)
|
||||
delay *= valuePortion;
|
||||
|
||||
duration *= valuePortion;
|
||||
|
||||
pt.mStartForReversingTest = oldPT.mEndValue;
|
||||
@ -461,7 +504,6 @@ nsTransitionManager::ConsiderStartingTransition(nsCSSProperty aProperty,
|
||||
pt.mStartTime = mostRecentRefresh + TimeDuration::FromMilliseconds(delay);
|
||||
pt.mDuration = TimeDuration::FromMilliseconds(duration);
|
||||
pt.mTimingFunction.Init(tf);
|
||||
|
||||
if (!aElementTransitions) {
|
||||
aElementTransitions =
|
||||
GetElementTransitions(aElement, aNewStyleContext->GetPseudoType(),
|
||||
@ -495,6 +537,7 @@ nsTransitionManager::ConsiderStartingTransition(nsCSSProperty aProperty,
|
||||
nsCSSPseudoElements::ePseudo_NotPseudoElement ?
|
||||
eRestyle_Self : eRestyle_Subtree;
|
||||
presContext->PresShell()->RestyleForAnimation(aElement, hint);
|
||||
// XXXdz: invalidate the frame here, once animations are throttled.
|
||||
|
||||
*aStartedAny = true;
|
||||
aWhichStarted->AddProperty(aProperty);
|
||||
@ -535,6 +578,9 @@ nsTransitionManager::GetElementTransitions(dom::Element *aElement,
|
||||
delete et;
|
||||
return nullptr;
|
||||
}
|
||||
if (propName == nsGkAtoms::transitionsProperty) {
|
||||
aElement->SetMayHaveAnimations();
|
||||
}
|
||||
|
||||
AddElementData(et);
|
||||
}
|
||||
@ -688,8 +734,6 @@ nsTransitionManager::WillRefresh(mozilla::TimeStamp aTime)
|
||||
// completion. See comment below.
|
||||
et->mPropertyTransitions.RemoveElementAt(i);
|
||||
} else if (pt.mStartTime + pt.mDuration <= aTime) {
|
||||
// This transition has completed.
|
||||
|
||||
// Fire transitionend events only for transitions on elements
|
||||
// and not those on pseudo-elements, since we can't target an
|
||||
// event at pseudo-elements.
|
||||
@ -723,6 +767,9 @@ nsTransitionManager::WillRefresh(mozilla::TimeStamp aTime)
|
||||
nsRestyleHint hint = et->mElementProperty == nsGkAtoms::transitionsProperty ?
|
||||
eRestyle_Self : eRestyle_Subtree;
|
||||
mPresContext->PresShell()->RestyleForAnimation(et->mElement, hint);
|
||||
// XXXdz: if we have started a transition since the last tick and are
|
||||
// performing the transition off the main thread, we need to invalidate
|
||||
// the frame once we start throttling animation ticks.
|
||||
|
||||
if (et->mPropertyTransitions.IsEmpty()) {
|
||||
et->Destroy();
|
||||
|
@ -22,6 +22,8 @@ struct nsTransition;
|
||||
|
||||
struct ElementPropertyTransition
|
||||
{
|
||||
ElementPropertyTransition() {}
|
||||
|
||||
nsCSSProperty mProperty;
|
||||
nsStyleAnimation::Value mStartValue, mEndValue;
|
||||
mozilla::TimeStamp mStartTime; // actual start plus transition delay
|
||||
@ -29,7 +31,7 @@ struct ElementPropertyTransition
|
||||
// data from the relevant nsTransition
|
||||
mozilla::TimeDuration mDuration;
|
||||
mozilla::css::ComputedTimingFunction mTimingFunction;
|
||||
|
||||
|
||||
// This is the start value to be used for a check for whether a
|
||||
// transition is being reversed. Normally the same as mStartValue,
|
||||
// except when this transition started as the reversal of another
|
||||
@ -46,24 +48,27 @@ struct ElementPropertyTransition
|
||||
// in again when the transition is back to 2px, the mReversePortion
|
||||
// for the third transition (from 0px/2px to 10px) will be 0.8.
|
||||
double mReversePortion;
|
||||
|
||||
|
||||
// Compute the portion of the *value* space that we should be through
|
||||
// at the given time. (The input to the transition timing function
|
||||
// has time units, the output has value units.)
|
||||
double ValuePortionFor(mozilla::TimeStamp aRefreshTime) const;
|
||||
|
||||
|
||||
bool IsRemovedSentinel() const
|
||||
{
|
||||
return mStartTime.IsNull();
|
||||
}
|
||||
|
||||
|
||||
void SetRemovedSentinel()
|
||||
{
|
||||
// assign the null time stamp
|
||||
mStartTime = mozilla::TimeStamp();
|
||||
}
|
||||
|
||||
bool CanPerformOnCompositor(mozilla::dom::Element* aElement,
|
||||
mozilla::TimeStamp aTime) const;
|
||||
};
|
||||
|
||||
|
||||
struct ElementTransitions : public mozilla::css::CommonElementAnimationData
|
||||
{
|
||||
ElementTransitions(mozilla::dom::Element *aElement, nsIAtom *aElementProperty,
|
||||
@ -71,11 +76,13 @@ struct ElementTransitions : public mozilla::css::CommonElementAnimationData
|
||||
|
||||
void EnsureStyleRuleFor(mozilla::TimeStamp aRefreshTime);
|
||||
|
||||
|
||||
bool HasTransitionOfProperty(nsCSSProperty aProperty) const;
|
||||
// True if this animation can be performed on the compositor thread.
|
||||
// virtual CanPerformOnCompositorThread() const;
|
||||
bool CanPerformOnCompositorThread() const;
|
||||
// Either zero or one for each CSS property:
|
||||
nsTArray<ElementPropertyTransition> mPropertyTransitions;
|
||||
|
||||
|
||||
// This style rule overrides style data with the currently
|
||||
// transitioning value for an element that is executing a transition.
|
||||
// It only matches when styling with animation. When we style without
|
||||
@ -97,8 +104,28 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
static ElementTransitions* GetTransitions(nsIContent* aContent) {
|
||||
return static_cast<ElementTransitions*>
|
||||
(aContent->GetProperty(nsGkAtoms::transitionsProperty));
|
||||
}
|
||||
|
||||
static ElementTransitions*
|
||||
GetTransitionsForCompositor(nsIContent* aContent,
|
||||
nsCSSProperty aProperty)
|
||||
{
|
||||
if (!aContent->MayHaveAnimations())
|
||||
return nullptr;
|
||||
ElementTransitions* transitions = GetTransitions(aContent);
|
||||
if (!transitions ||
|
||||
!transitions->HasTransitionOfProperty(aProperty) ||
|
||||
!transitions->CanPerformOnCompositorThread()) {
|
||||
return nullptr;
|
||||
}
|
||||
return transitions;
|
||||
}
|
||||
|
||||
/**
|
||||
* StyleContextChanged
|
||||
* StyleContextChanged
|
||||
*
|
||||
* To be called from nsFrameManager::ReResolveStyleContext when the
|
||||
* style of an element has changed, to initiate transitions from
|
||||
|
Loading…
Reference in New Issue
Block a user