Bug 768440 Part 2: Animate CSS Transitions on the compositor r=roc,dbaron
This commit is contained in:
@@ -11,6 +11,7 @@
|
|||||||
#include "nsChangeHint.h"
|
#include "nsChangeHint.h"
|
||||||
#include "nsINode.h"
|
#include "nsINode.h"
|
||||||
#include "nsIDocument.h" // for IsInHTMLDocument
|
#include "nsIDocument.h" // for IsInHTMLDocument
|
||||||
|
#include "nsCSSProperty.h"
|
||||||
|
|
||||||
// Forward declarations
|
// Forward declarations
|
||||||
class nsIAtom;
|
class nsIAtom;
|
||||||
|
|||||||
@@ -39,6 +39,7 @@
|
|||||||
#include "nsSVGClipPathFrame.h"
|
#include "nsSVGClipPathFrame.h"
|
||||||
#include "sampler.h"
|
#include "sampler.h"
|
||||||
#include "nsAnimationManager.h"
|
#include "nsAnimationManager.h"
|
||||||
|
#include "nsTransitionManager.h"
|
||||||
#include "nsIViewManager.h"
|
#include "nsIViewManager.h"
|
||||||
|
|
||||||
#include "mozilla/StandardInteger.h"
|
#include "mozilla/StandardInteger.h"
|
||||||
@@ -267,13 +268,85 @@ ToTimingFunction(css::ComputedTimingFunction& aCTF)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
AddTransformAnimations(ElementAnimations* ea, Layer* aLayer,
|
AddAnimationsForProperty(nsIFrame* aFrame, nsCSSProperty aProperty,
|
||||||
const nsPoint& aOrigin)
|
ElementAnimation* ea, Layer* aLayer,
|
||||||
|
AnimationData& aData)
|
||||||
{
|
{
|
||||||
if (!ea)
|
|
||||||
return;
|
|
||||||
NS_ASSERTION(aLayer->AsContainerLayer(), "Should only animate ContainerLayer");
|
NS_ASSERTION(aLayer->AsContainerLayer(), "Should only animate ContainerLayer");
|
||||||
nsIFrame* frame = ea->mElement->GetPrimaryFrame();
|
nsStyleContext* styleContext = aFrame->GetStyleContext();
|
||||||
|
nsPresContext* presContext = aFrame->PresContext();
|
||||||
|
nsRect bounds = nsDisplayTransform::GetFrameBoundsForTransform(aFrame);
|
||||||
|
float scale = nsDeviceContext::AppUnitsPerCSSPixel();
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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, styleContext,
|
||||||
|
presContext, bounds,
|
||||||
|
scale, fromFunctions);
|
||||||
|
|
||||||
|
list = segment->mToValue.GetCSSValueListValue();
|
||||||
|
InfallibleTArray<TransformFunction> toFunctions;
|
||||||
|
AddTransformFunctions(list, styleContext,
|
||||||
|
presContext, bounds,
|
||||||
|
scale, toFunctions);
|
||||||
|
|
||||||
|
segments.AppendElement(AnimationSegment(fromFunctions, toFunctions,
|
||||||
|
segment->mFromKey, segment->mToKey,
|
||||||
|
ToTimingFunction(segment->mTimingFunction)));
|
||||||
|
} 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(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);
|
nsRect bounds = nsDisplayTransform::GetFrameBoundsForTransform(frame);
|
||||||
float scale = nsDeviceContext::AppUnitsPerCSSPixel();
|
float scale = nsDeviceContext::AppUnitsPerCSSPixel();
|
||||||
gfxPoint3D offsetToTransformOrigin =
|
gfxPoint3D offsetToTransformOrigin =
|
||||||
@@ -288,96 +361,55 @@ AddTransformAnimations(ElementAnimations* ea, Layer* aLayer,
|
|||||||
perspective = disp->mChildPerspective.GetCoordValue();
|
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++) {
|
for (PRUint32 animIdx = 0; animIdx < ea->mAnimations.Length(); animIdx++) {
|
||||||
ElementAnimation* anim = &ea->mAnimations[animIdx];
|
ElementAnimation* anim = &ea->mAnimations[animIdx];
|
||||||
if (!anim->CanPerformOnCompositor(ea->mElement, TimeStamp::Now())) {
|
if (!anim->CanPerformOnCompositor(ea->mElement, currentTime)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
float iterations = anim->mIterationCount != NS_IEEEPositiveInfinity()
|
AddAnimationsForProperty(frame, aProperty, anim,
|
||||||
? anim->mIterationCount : -1;
|
aLayer, data);
|
||||||
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];
|
|
||||||
nsCSSValueList* list = segment->mFromValue.GetCSSValueListValue();
|
|
||||||
InfallibleTArray<TransformFunction> fromFunctions;
|
|
||||||
AddTransformFunctions(list, frame->GetStyleContext(),
|
|
||||||
frame->PresContext(), bounds,
|
|
||||||
scale, fromFunctions);
|
|
||||||
|
|
||||||
list = segment->mToValue.GetCSSValueListValue();
|
|
||||||
InfallibleTArray<TransformFunction> toFunctions;
|
|
||||||
AddTransformFunctions(list, frame->GetStyleContext(),
|
|
||||||
frame->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];
|
|
||||||
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()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
nsDisplayListBuilder::nsDisplayListBuilder(nsIFrame* aReferenceFrame,
|
nsDisplayListBuilder::nsDisplayListBuilder(nsIFrame* aReferenceFrame,
|
||||||
Mode aMode, bool aBuildCaret)
|
Mode aMode, bool aBuildCaret)
|
||||||
: mReferenceFrame(aReferenceFrame),
|
: mReferenceFrame(aReferenceFrame),
|
||||||
@@ -2321,12 +2353,7 @@ nsDisplayOpacity::BuildLayer(nsDisplayListBuilder* aBuilder,
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
container->SetOpacity(mFrame->GetStyleDisplay()->mOpacity);
|
container->SetOpacity(mFrame->GetStyleDisplay()->mOpacity);
|
||||||
|
AddAnimationsAndTransitionsToLayer(container, this, eCSSProperty_opacity);
|
||||||
container->ClearAnimations();
|
|
||||||
ElementAnimations* ea =
|
|
||||||
nsAnimationManager::GetAnimationsForCompositor(mFrame->GetContent(),
|
|
||||||
eCSSProperty_opacity);
|
|
||||||
AddOpacityAnimations(ea, container);
|
|
||||||
|
|
||||||
return container.forget();
|
return container.forget();
|
||||||
}
|
}
|
||||||
@@ -2354,7 +2381,7 @@ nsDisplayOpacity::GetLayerState(nsDisplayListBuilder* aBuilder,
|
|||||||
!IsItemTooSmallForActiveLayer(this))
|
!IsItemTooSmallForActiveLayer(this))
|
||||||
return LAYER_ACTIVE;
|
return LAYER_ACTIVE;
|
||||||
if (mFrame->GetContent()) {
|
if (mFrame->GetContent()) {
|
||||||
if (nsAnimationManager::GetAnimationsForCompositor(mFrame->GetContent(),
|
if (nsLayoutUtils::HasAnimationsForCompositor(mFrame->GetContent(),
|
||||||
eCSSProperty_opacity)) {
|
eCSSProperty_opacity)) {
|
||||||
return LAYER_ACTIVE;
|
return LAYER_ACTIVE;
|
||||||
}
|
}
|
||||||
@@ -3338,12 +3365,7 @@ already_AddRefed<Layer> nsDisplayTransform::BuildLayer(nsDisplayListBuilder *aBu
|
|||||||
container->SetContentFlags(container->GetContentFlags() | Layer::CONTENT_PRESERVE_3D);
|
container->SetContentFlags(container->GetContentFlags() | Layer::CONTENT_PRESERVE_3D);
|
||||||
}
|
}
|
||||||
|
|
||||||
container->ClearAnimations();
|
AddAnimationsAndTransitionsToLayer(container, this, eCSSProperty_transform);
|
||||||
ElementAnimations* ea =
|
|
||||||
nsAnimationManager::GetAnimationsForCompositor(mFrame->GetContent(),
|
|
||||||
eCSSProperty_transform);
|
|
||||||
AddTransformAnimations(ea, container, ToReferenceFrame());
|
|
||||||
|
|
||||||
return container.forget();
|
return container.forget();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3359,7 +3381,7 @@ nsDisplayTransform::GetLayerState(nsDisplayListBuilder* aBuilder,
|
|||||||
if (!GetTransform(mFrame->PresContext()->AppUnitsPerDevPixel()).Is2D() || mFrame->Preserves3D())
|
if (!GetTransform(mFrame->PresContext()->AppUnitsPerDevPixel()).Is2D() || mFrame->Preserves3D())
|
||||||
return LAYER_ACTIVE;
|
return LAYER_ACTIVE;
|
||||||
if (mFrame->GetContent()) {
|
if (mFrame->GetContent()) {
|
||||||
if (nsAnimationManager::GetAnimationsForCompositor(mFrame->GetContent(),
|
if (nsLayoutUtils::HasAnimationsForCompositor(mFrame->GetContent(),
|
||||||
eCSSProperty_transform)) {
|
eCSSProperty_transform)) {
|
||||||
return LAYER_ACTIVE;
|
return LAYER_ACTIVE;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -83,6 +83,8 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "sampler.h"
|
#include "sampler.h"
|
||||||
|
#include "nsAnimationManager.h"
|
||||||
|
#include "nsTransitionManager.h"
|
||||||
|
|
||||||
using namespace mozilla;
|
using namespace mozilla;
|
||||||
using namespace mozilla::layers;
|
using namespace mozilla::layers;
|
||||||
@@ -113,6 +115,32 @@ static ContentMap& GetContentMap() {
|
|||||||
return *sContentMap;
|
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
|
bool
|
||||||
nsLayoutUtils::Are3DTransformsEnabled()
|
nsLayoutUtils::Are3DTransformsEnabled()
|
||||||
|
|||||||
@@ -1497,6 +1497,13 @@ public:
|
|||||||
nsMallocSizeOfFun aMallocSizeOf,
|
nsMallocSizeOfFun aMallocSizeOf,
|
||||||
bool clear);
|
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.
|
* Checks if CSS 3D transforms are currently enabled.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -93,6 +93,7 @@
|
|||||||
#include "nsAbsoluteContainingBlock.h"
|
#include "nsAbsoluteContainingBlock.h"
|
||||||
#include "nsFontInflationData.h"
|
#include "nsFontInflationData.h"
|
||||||
#include "nsAnimationManager.h"
|
#include "nsAnimationManager.h"
|
||||||
|
#include "nsTransitionManager.h"
|
||||||
|
|
||||||
#include "mozilla/Preferences.h"
|
#include "mozilla/Preferences.h"
|
||||||
#include "mozilla/LookAndFeel.h"
|
#include "mozilla/LookAndFeel.h"
|
||||||
@@ -940,14 +941,16 @@ nsIFrame::IsTransformed() const
|
|||||||
(GetStyleDisplay()->HasTransform() ||
|
(GetStyleDisplay()->HasTransform() ||
|
||||||
IsSVGTransformed() ||
|
IsSVGTransformed() ||
|
||||||
(mContent &&
|
(mContent &&
|
||||||
nsAnimationManager::GetAnimationsForCompositor(mContent, eCSSProperty_transform))));
|
nsLayoutUtils::HasAnimationsForCompositor(mContent,
|
||||||
|
eCSSProperty_transform))));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
nsIFrame::HasOpacity() const
|
nsIFrame::HasOpacity() const
|
||||||
{
|
{
|
||||||
return GetStyleDisplay()->mOpacity < 1.0f || (mContent &&
|
return GetStyleDisplay()->mOpacity < 1.0f || (mContent &&
|
||||||
nsAnimationManager::GetAnimationsForCompositor(mContent, eCSSProperty_opacity));
|
nsLayoutUtils::HasAnimationsForCompositor(mContent,
|
||||||
|
eCSSProperty_opacity));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
@@ -1774,9 +1777,12 @@ nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder,
|
|||||||
nsRect clipPropClip;
|
nsRect clipPropClip;
|
||||||
const nsStyleDisplay* disp = GetStyleDisplay();
|
const nsStyleDisplay* disp = GetStyleDisplay();
|
||||||
// We can stop right away if this is a zero-opacity stacking context and
|
// We can stop right away if this is a zero-opacity stacking context and
|
||||||
// we're painting.
|
// we're painting, and we're not animating opacity.
|
||||||
if (disp->mOpacity == 0.0 && aBuilder->IsForPainting())
|
if (disp->mOpacity == 0.0 && aBuilder->IsForPainting() &&
|
||||||
|
!nsLayoutUtils::HasAnimationsForCompositor(mContent,
|
||||||
|
eCSSProperty_opacity)) {
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
bool applyClipPropClipping =
|
bool applyClipPropClipping =
|
||||||
ApplyClipPropClipping(aBuilder, disp, this, &clipPropClip);
|
ApplyClipPropClipping(aBuilder, disp, this, &clipPropClip);
|
||||||
@@ -1921,7 +1927,6 @@ nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder,
|
|||||||
// resultList was emptied
|
// resultList was emptied
|
||||||
resultList.AppendToTop(item);
|
resultList.AppendToTop(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If there are any SVG effects, wrap the list up in an SVG effects 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
|
* (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
|
* item even if resultList is empty, since a filter can produce graphical
|
||||||
|
|||||||
@@ -22,6 +22,8 @@
|
|||||||
#include "nsEventDispatcher.h"
|
#include "nsEventDispatcher.h"
|
||||||
#include "nsGUIEvent.h"
|
#include "nsGUIEvent.h"
|
||||||
#include "mozilla/dom/Element.h"
|
#include "mozilla/dom/Element.h"
|
||||||
|
#include "nsIFrame.h"
|
||||||
|
#include "nsCSSFrameConstructor.h"
|
||||||
|
|
||||||
using mozilla::TimeStamp;
|
using mozilla::TimeStamp;
|
||||||
using mozilla::TimeDuration;
|
using mozilla::TimeDuration;
|
||||||
@@ -36,7 +38,6 @@ ElementTransitions::ElementTransitions(mozilla::dom::Element *aElement, nsIAtom
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
double
|
double
|
||||||
ElementPropertyTransition::ValuePortionFor(TimeStamp aRefreshTime) const
|
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 *
|
* nsTransitionManager *
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
@@ -298,10 +334,6 @@ nsTransitionManager::StyleContextChanged(dom::Element *aElement,
|
|||||||
// rule.
|
// rule.
|
||||||
|
|
||||||
nsRefPtr<css::AnimValuesStyleRule> coverRule = new css::AnimValuesStyleRule;
|
nsRefPtr<css::AnimValuesStyleRule> coverRule = new css::AnimValuesStyleRule;
|
||||||
if (!coverRule) {
|
|
||||||
NS_WARNING("out of memory");
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsTArray<ElementPropertyTransition> &pts = et->mPropertyTransitions;
|
nsTArray<ElementPropertyTransition> &pts = et->mPropertyTransitions;
|
||||||
for (PRUint32 i = 0, i_end = pts.Length(); i < i_end; ++i) {
|
for (PRUint32 i = 0, i_end = pts.Length(); i < i_end; ++i) {
|
||||||
@@ -347,9 +379,19 @@ nsTransitionManager::ConsiderStartingTransition(nsCSSProperty aProperty,
|
|||||||
pt.mStartValue) &&
|
pt.mStartValue) &&
|
||||||
ExtractComputedValueForTransition(aProperty, aNewStyleContext,
|
ExtractComputedValueForTransition(aProperty, aNewStyleContext,
|
||||||
pt.mEndValue);
|
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 =
|
bool shouldAnimate =
|
||||||
haveValues &&
|
haveValues &&
|
||||||
pt.mStartValue != pt.mEndValue &&
|
(haveChange || haveOMTA) &&
|
||||||
// Check that we can interpolate between these values
|
// Check that we can interpolate between these values
|
||||||
// (If this is ever a performance problem, we could add a
|
// (If this is ever a performance problem, we could add a
|
||||||
// CanInterpolate method, but it seems fine for now.)
|
// CanInterpolate method, but it seems fine for now.)
|
||||||
@@ -450,6 +492,7 @@ nsTransitionManager::ConsiderStartingTransition(nsCSSProperty aProperty,
|
|||||||
// reduce positive delays.
|
// reduce positive delays.
|
||||||
if (delay < 0.0f)
|
if (delay < 0.0f)
|
||||||
delay *= valuePortion;
|
delay *= valuePortion;
|
||||||
|
|
||||||
duration *= valuePortion;
|
duration *= valuePortion;
|
||||||
|
|
||||||
pt.mStartForReversingTest = oldPT.mEndValue;
|
pt.mStartForReversingTest = oldPT.mEndValue;
|
||||||
@@ -461,7 +504,6 @@ nsTransitionManager::ConsiderStartingTransition(nsCSSProperty aProperty,
|
|||||||
pt.mStartTime = mostRecentRefresh + TimeDuration::FromMilliseconds(delay);
|
pt.mStartTime = mostRecentRefresh + TimeDuration::FromMilliseconds(delay);
|
||||||
pt.mDuration = TimeDuration::FromMilliseconds(duration);
|
pt.mDuration = TimeDuration::FromMilliseconds(duration);
|
||||||
pt.mTimingFunction.Init(tf);
|
pt.mTimingFunction.Init(tf);
|
||||||
|
|
||||||
if (!aElementTransitions) {
|
if (!aElementTransitions) {
|
||||||
aElementTransitions =
|
aElementTransitions =
|
||||||
GetElementTransitions(aElement, aNewStyleContext->GetPseudoType(),
|
GetElementTransitions(aElement, aNewStyleContext->GetPseudoType(),
|
||||||
@@ -495,6 +537,7 @@ nsTransitionManager::ConsiderStartingTransition(nsCSSProperty aProperty,
|
|||||||
nsCSSPseudoElements::ePseudo_NotPseudoElement ?
|
nsCSSPseudoElements::ePseudo_NotPseudoElement ?
|
||||||
eRestyle_Self : eRestyle_Subtree;
|
eRestyle_Self : eRestyle_Subtree;
|
||||||
presContext->PresShell()->RestyleForAnimation(aElement, hint);
|
presContext->PresShell()->RestyleForAnimation(aElement, hint);
|
||||||
|
// XXXdz: invalidate the frame here, once animations are throttled.
|
||||||
|
|
||||||
*aStartedAny = true;
|
*aStartedAny = true;
|
||||||
aWhichStarted->AddProperty(aProperty);
|
aWhichStarted->AddProperty(aProperty);
|
||||||
@@ -535,6 +578,9 @@ nsTransitionManager::GetElementTransitions(dom::Element *aElement,
|
|||||||
delete et;
|
delete et;
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
if (propName == nsGkAtoms::transitionsProperty) {
|
||||||
|
aElement->SetMayHaveAnimations();
|
||||||
|
}
|
||||||
|
|
||||||
AddElementData(et);
|
AddElementData(et);
|
||||||
}
|
}
|
||||||
@@ -688,8 +734,6 @@ nsTransitionManager::WillRefresh(mozilla::TimeStamp aTime)
|
|||||||
// completion. See comment below.
|
// completion. See comment below.
|
||||||
et->mPropertyTransitions.RemoveElementAt(i);
|
et->mPropertyTransitions.RemoveElementAt(i);
|
||||||
} else if (pt.mStartTime + pt.mDuration <= aTime) {
|
} else if (pt.mStartTime + pt.mDuration <= aTime) {
|
||||||
// This transition has completed.
|
|
||||||
|
|
||||||
// Fire transitionend events only for transitions on elements
|
// Fire transitionend events only for transitions on elements
|
||||||
// and not those on pseudo-elements, since we can't target an
|
// and not those on pseudo-elements, since we can't target an
|
||||||
// event at pseudo-elements.
|
// event at pseudo-elements.
|
||||||
@@ -723,6 +767,9 @@ nsTransitionManager::WillRefresh(mozilla::TimeStamp aTime)
|
|||||||
nsRestyleHint hint = et->mElementProperty == nsGkAtoms::transitionsProperty ?
|
nsRestyleHint hint = et->mElementProperty == nsGkAtoms::transitionsProperty ?
|
||||||
eRestyle_Self : eRestyle_Subtree;
|
eRestyle_Self : eRestyle_Subtree;
|
||||||
mPresContext->PresShell()->RestyleForAnimation(et->mElement, hint);
|
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()) {
|
if (et->mPropertyTransitions.IsEmpty()) {
|
||||||
et->Destroy();
|
et->Destroy();
|
||||||
|
|||||||
@@ -22,6 +22,8 @@ struct nsTransition;
|
|||||||
|
|
||||||
struct ElementPropertyTransition
|
struct ElementPropertyTransition
|
||||||
{
|
{
|
||||||
|
ElementPropertyTransition() {}
|
||||||
|
|
||||||
nsCSSProperty mProperty;
|
nsCSSProperty mProperty;
|
||||||
nsStyleAnimation::Value mStartValue, mEndValue;
|
nsStyleAnimation::Value mStartValue, mEndValue;
|
||||||
mozilla::TimeStamp mStartTime; // actual start plus transition delay
|
mozilla::TimeStamp mStartTime; // actual start plus transition delay
|
||||||
@@ -62,6 +64,9 @@ struct ElementPropertyTransition
|
|||||||
// assign the null time stamp
|
// assign the null time stamp
|
||||||
mStartTime = mozilla::TimeStamp();
|
mStartTime = mozilla::TimeStamp();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CanPerformOnCompositor(mozilla::dom::Element* aElement,
|
||||||
|
mozilla::TimeStamp aTime) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ElementTransitions : public mozilla::css::CommonElementAnimationData
|
struct ElementTransitions : public mozilla::css::CommonElementAnimationData
|
||||||
@@ -71,8 +76,10 @@ struct ElementTransitions : public mozilla::css::CommonElementAnimationData
|
|||||||
|
|
||||||
void EnsureStyleRuleFor(mozilla::TimeStamp aRefreshTime);
|
void EnsureStyleRuleFor(mozilla::TimeStamp aRefreshTime);
|
||||||
|
|
||||||
|
|
||||||
|
bool HasTransitionOfProperty(nsCSSProperty aProperty) const;
|
||||||
// True if this animation can be performed on the compositor thread.
|
// 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:
|
// Either zero or one for each CSS property:
|
||||||
nsTArray<ElementPropertyTransition> mPropertyTransitions;
|
nsTArray<ElementPropertyTransition> mPropertyTransitions;
|
||||||
|
|
||||||
@@ -97,6 +104,26 @@ 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
|
||||||
*
|
*
|
||||||
|
|||||||
Reference in New Issue
Block a user