Bug 1305325 - Part 12: Pass base value for opacity or transform to the compositor. r?birtles,mstange
MozReview-Commit-ID: 3mxatMvsNKk
--- a/gfx/layers/Layers.cpp
+++ b/gfx/layers/Layers.cpp
@@ -418,16 +418,38 @@ CreateCSSValueList(const InfallibleTArra
}
if (aFunctions.Length() == 0) {
result = new nsCSSValueList();
result->mValue.SetNoneValue();
}
return new nsCSSValueSharedList(result.forget());
}
+static StyleAnimationValue
+ToStyleAnimationValue(const Animatable& aAnimatable)
+{
+ StyleAnimationValue result;
+
+ switch (aAnimatable.type()) {
+ case Animatable::TArrayOfTransformFunction: {
+ const InfallibleTArray<TransformFunction>& transforms =
+ aAnimatable.get_ArrayOfTransformFunction();
+ result.SetTransformValue(CreateCSSValueList(transforms));
+ break;
+ }
+ case Animatable::Tfloat:
+ result.SetFloatValue(aAnimatable.get_float());
+ break;
+ default:
+ MOZ_ASSERT_UNREACHABLE("Unsupported type");
+ }
+
+ return result;
+}
+
void
Layer::SetAnimations(const AnimationArray& aAnimations)
{
MOZ_LAYERS_LOG_IF_SHADOWABLE(this, ("Layer::Mutated(%p) SetAnimations", this));
mAnimations = aAnimations;
mAnimationData.Clear();
for (uint32_t i = 0; i < mAnimations.Length(); i++) {
@@ -441,50 +463,40 @@ Layer::SetAnimations(const AnimationArra
break;
case dom::FillMode::Backwards:
animation.fillMode() = static_cast<uint8_t>(dom::FillMode::Both);
break;
default:
break;
}
+ if (animation.baseStyle().type() != BaseAnimationStyle::Tnull_t) {
+ mBaseAnimationStyle =
+ ToStyleAnimationValue(animation.baseStyle().get_Animatable());
+ }
+
AnimData* data = mAnimationData.AppendElement();
InfallibleTArray<Maybe<ComputedTimingFunction>>& functions =
data->mFunctions;
const InfallibleTArray<AnimationSegment>& segments = animation.segments();
for (uint32_t j = 0; j < segments.Length(); j++) {
TimingFunction tf = segments.ElementAt(j).sampleFn();
Maybe<ComputedTimingFunction> ctf =
AnimationUtils::TimingFunctionToComputedTimingFunction(tf);
functions.AppendElement(ctf);
}
// Precompute the StyleAnimationValues that we need if this is a transform
// animation.
InfallibleTArray<StyleAnimationValue>& startValues = data->mStartValues;
InfallibleTArray<StyleAnimationValue>& endValues = data->mEndValues;
- for (uint32_t j = 0; j < segments.Length(); j++) {
- const AnimationSegment& segment = segments[j];
- StyleAnimationValue* startValue = startValues.AppendElement();
- StyleAnimationValue* endValue = endValues.AppendElement();
- if (segment.endState().type() == Animatable::TArrayOfTransformFunction) {
- const InfallibleTArray<TransformFunction>& startFunctions =
- segment.startState().get_ArrayOfTransformFunction();
- startValue->SetTransformValue(CreateCSSValueList(startFunctions));
-
- const InfallibleTArray<TransformFunction>& endFunctions =
- segment.endState().get_ArrayOfTransformFunction();
- endValue->SetTransformValue(CreateCSSValueList(endFunctions));
- } else {
- NS_ASSERTION(segment.endState().type() == Animatable::Tfloat,
- "Unknown Animatable type");
- startValue->SetFloatValue(segment.startState().get_float());
- endValue->SetFloatValue(segment.endState().get_float());
- }
+ for (const AnimationSegment& segment : segments) {
+ startValues.AppendElement(ToStyleAnimationValue(segment.startState()));
+ endValues.AppendElement(ToStyleAnimationValue(segment.endState()));
}
}
Mutated();
}
void
Layer::StartPendingAnimations(const TimeStamp& aReadyTime)
--- a/gfx/layers/Layers.h
+++ b/gfx/layers/Layers.h
@@ -1933,16 +1933,18 @@ protected:
// If this layer is used for OMTA, then this counter is used to ensure we
// stay in sync with the animation manager
uint64_t mAnimationGeneration;
#ifdef MOZ_DUMP_PAINTING
nsTArray<nsCString> mExtraDumpInfo;
#endif
// Store display list log.
nsCString mDisplayListLog;
+
+ StyleAnimationValue mBaseAnimationStyle;
};
/**
* A Layer which we can paint into. It is a conceptually
* infinite surface, but each PaintedLayer has an associated "valid region"
* of contents that it is currently storing, which is finite. PaintedLayer
* implementations can store content between paints.
*
--- a/gfx/layers/ipc/LayersMessages.ipdlh
+++ b/gfx/layers/ipc/LayersMessages.ipdlh
@@ -155,16 +155,21 @@ union TransformFunction {
TransformMatrix;
};
union Animatable {
float;
TransformFunction[];
};
+union BaseAnimationStyle {
+ null_t;
+ Animatable;
+};
+
struct AnimationSegment {
Animatable startState;
Animatable endState;
float startPortion;
float endPortion;
TimingFunction sampleFn;
};
@@ -216,16 +221,21 @@ struct Animation {
AnimationData data;
float playbackRate;
// This is used in the transformed progress calculation.
TimingFunction easingFunction;
uint8_t iterationComposite;
// True if the animation has a fixed current time (e.g. paused and
// forward-filling animations).
bool isNotPlaying;
+ // The base style that animations should composite with. This is only set for
+ // animations with a composite mode of additive or accumulate, and only for
+ // the first animation in the set (i.e. the animation that is lowest in the
+ // stack). In all other cases the value is null_t.
+ BaseAnimationStyle baseStyle;
};
// Change a layer's attributes
struct CommonLayerAttributes {
IntRect layerBounds;
LayerIntRegion visibleRegion;
EventRegions eventRegions;
TransformMatrix transform;
--- a/layout/painting/nsDisplayList.cpp
+++ b/layout/painting/nsDisplayList.cpp
@@ -381,34 +381,84 @@ ToTimingFunction(const Maybe<ComputedTim
spline->X2(), spline->Y2()));
}
uint32_t type = aCTF->GetType() == nsTimingFunction::Type::StepStart ? 1 : 2;
return TimingFunction(StepFunction(aCTF->GetSteps(), type));
}
static void
+SetAnimatable(nsCSSPropertyID aProperty,
+ const StyleAnimationValue& aAnimationValue,
+ nsIFrame* aFrame,
+ const TransformReferenceBox& aRefBox,
+ layers::Animatable& aAnimatable)
+{
+ MOZ_ASSERT(aFrame);
+
+ switch (aProperty) {
+ case eCSSProperty_opacity:
+ if (!aAnimationValue.IsNull()) {
+ aAnimatable = aAnimationValue.GetFloatValue();
+ } else {
+ aAnimatable = 0.0;
+ }
+ break;
+ case eCSSProperty_transform:
+ aAnimatable = InfallibleTArray<TransformFunction>();
+ if (!aAnimationValue.IsNull()) {
+ nsCSSValueSharedList* list =
+ aAnimationValue.GetCSSValueSharedListValue();
+ TransformReferenceBox refBox(aFrame);
+ AddTransformFunctions(list->mHead,
+ aFrame->StyleContext(),
+ aFrame->PresContext(),
+ refBox,
+ aAnimatable.get_ArrayOfTransformFunction());
+ }
+ break;
+ default:
+ MOZ_ASSERT_UNREACHABLE("Unsupported property");
+ }
+}
+
+static void
+SetBaseAnimationStyle(nsCSSPropertyID aProperty,
+ nsIFrame* aFrame,
+ const TransformReferenceBox& aRefBox,
+ layers::BaseAnimationStyle& aBaseStyle)
+{
+ MOZ_ASSERT(aFrame);
+
+ EffectSet* effects = EffectSet::GetEffectSet(aFrame);
+ StyleAnimationValue baseValue = effects->GetBaseStyle(aProperty);
+ MOZ_ASSERT(!baseValue.IsNull(),
+ "The base value should be already there");
+
+ layers::Animatable animatable;
+ SetAnimatable(aProperty, baseValue, aFrame, aRefBox, animatable);
+ aBaseStyle = animatable;
+}
+
+static void
AddAnimationForProperty(nsIFrame* aFrame, const AnimationProperty& aProperty,
dom::Animation* aAnimation, Layer* aLayer,
AnimationData& aData, bool aPending)
{
MOZ_ASSERT(aLayer->AsContainerLayer(), "Should only animate ContainerLayer");
MOZ_ASSERT(aAnimation->GetEffect(),
"Should not be adding an animation without an effect");
MOZ_ASSERT(!aAnimation->GetCurrentOrPendingStartTime().IsNull() ||
!aAnimation->IsPlaying() ||
(aAnimation->GetTimeline() &&
aAnimation->GetTimeline()->TracksWallclockTime()),
"If the animation has an unresolved start time it should either"
" be static (so we don't need a start time) or else have a"
" timeline capable of converting TimeStamps (so we can calculate"
" one later");
- nsStyleContext* styleContext = aFrame->StyleContext();
- nsPresContext* presContext = aFrame->PresContext();
- TransformReferenceBox refBox(aFrame);
layers::Animation* animation =
aPending ?
aLayer->AddAnimationForNextTransaction() :
aLayer->AddAnimation();
const TimingParams& timing = aAnimation->GetEffect()->SpecifiedTiming();
@@ -454,36 +504,41 @@ AddAnimationForProperty(nsIFrame* aFrame
animation->playbackRate() = aAnimation->PlaybackRate();
animation->data() = aData;
animation->easingFunction() = ToTimingFunction(timing.mFunction);
animation->iterationComposite() =
static_cast<uint8_t>(aAnimation->GetEffect()->
AsKeyframeEffect()->IterationComposite());
animation->isNotPlaying() = !aAnimation->IsPlaying();
+ TransformReferenceBox refBox(aFrame);
+
+ // If the animation is additive or accumulates, we need to pass its base value
+ // to the compositor.
+ if (aAnimation->GetEffect()->AsKeyframeEffect()->
+ NeedsBaseStyle(aProperty.mProperty)) {
+ SetBaseAnimationStyle(aProperty.mProperty,
+ aFrame, refBox,
+ animation->baseStyle());
+ } else {
+ animation->baseStyle() = null_t();
+ }
+
for (uint32_t segIdx = 0; segIdx < aProperty.mSegments.Length(); segIdx++) {
const AnimationPropertySegment& segment = aProperty.mSegments[segIdx];
AnimationSegment* animSegment = animation->segments().AppendElement();
- if (aProperty.mProperty == eCSSProperty_transform) {
- animSegment->startState() = InfallibleTArray<TransformFunction>();
- animSegment->endState() = InfallibleTArray<TransformFunction>();
-
- nsCSSValueSharedList* list =
- segment.mFromValue.GetCSSValueSharedListValue();
- AddTransformFunctions(list->mHead, styleContext, presContext, refBox,
- animSegment->startState().get_ArrayOfTransformFunction());
-
- list = segment.mToValue.GetCSSValueSharedListValue();
- AddTransformFunctions(list->mHead, styleContext, presContext, refBox,
- animSegment->endState().get_ArrayOfTransformFunction());
- } else if (aProperty.mProperty == eCSSProperty_opacity) {
- animSegment->startState() = segment.mFromValue.GetFloatValue();
- animSegment->endState() = segment.mToValue.GetFloatValue();
- }
+ SetAnimatable(aProperty.mProperty,
+ segment.mFromValue,
+ aFrame, refBox,
+ animSegment->startState());
+ SetAnimatable(aProperty.mProperty,
+ segment.mToValue,
+ aFrame, refBox,
+ animSegment->endState());
animSegment->startPortion() = segment.mFromKey;
animSegment->endPortion() = segment.mToKey;
animSegment->sampleFn() = ToTimingFunction(segment.mTimingFunction);
}
}
static void