Bug 1216843 - Part 2: Implement effect iteration composition. r=birtles, r=smaug

MozReview-Commit-ID: 6u7WtXwL3y3
This commit is contained in:
Hiroyuki Ikezoe 2016-09-13 11:48:44 +09:00
parent acded2cbb2
commit f98523cf02
11 changed files with 148 additions and 80 deletions

View File

@ -126,6 +126,22 @@ KeyframeEffect::SetTarget(const Nullable<ElementOrCSSPseudoElement>& aTarget)
}
}
void
KeyframeEffect::SetIterationComposite(
const IterationCompositeOperation& aIterationComposite)
{
if (mEffectOptions.mIterationComposite == aIterationComposite) {
return;
}
if (mAnimation && mAnimation->IsRelevant()) {
nsNodeUtils::AnimationChanged(mAnimation);
}
mEffectOptions.mIterationComposite = aIterationComposite;
RequestRestyle(EffectCompositor::RestyleType::Layer);
}
void
KeyframeEffect::SetSpacing(JSContext* aCx,
const nsAString& aSpacing,

View File

@ -67,6 +67,8 @@ public:
void SetTarget(const Nullable<ElementOrCSSPseudoElement>& aTarget);
void SetSpacing(JSContext* aCx, const nsAString& aSpacing, ErrorResult& aRv);
void SetIterationComposite(
const IterationCompositeOperation& aIterationComposite);
};
} // namespace dom

View File

@ -9,6 +9,11 @@
#include "nsCSSProps.h"
#include "nsString.h"
// X11 has a #define for None
#ifdef None
#undef None
#endif
#include "mozilla/dom/KeyframeEffectBinding.h" // IterationCompositeOperation
namespace mozilla {
@ -51,8 +56,9 @@ struct KeyframeEffectParams
nsAString& aInvalidPacedProperty,
ErrorResult& aRv);
// FIXME: Bug 1216843: Add IterationCompositeOperations and
// Bug 1216844: Add CompositeOperation
dom::IterationCompositeOperation mIterationComposite =
dom::IterationCompositeOperation::Replace;
// FIXME: Bug 1216844: Add CompositeOperation
SpacingMode mSpacingMode = SpacingMode::distribute;
nsCSSPropertyID mPacedProperty = eCSSProperty_UNKNOWN;
};

View File

@ -77,7 +77,7 @@ KeyframeEffectReadOnly::WrapObject(JSContext* aCx,
IterationCompositeOperation
KeyframeEffectReadOnly::IterationComposite() const
{
return IterationCompositeOperation::Replace;
return mEffectOptions.mIterationComposite;
}
CompositeOperation
@ -373,12 +373,42 @@ KeyframeEffectReadOnly::ComposeStyle(RefPtr<AnimValuesStyleRule>& aStyleRule,
aStyleRule = new AnimValuesStyleRule();
}
StyleAnimationValue fromValue = segment->mFromValue;
StyleAnimationValue toValue = segment->mToValue;
// Iteration composition for accumulate
if (mEffectOptions.mIterationComposite ==
IterationCompositeOperation::Accumulate &&
computedTiming.mCurrentIteration > 0) {
const AnimationPropertySegment& lastSegment =
prop.mSegments.LastElement();
// FIXME: Bug 1293492: Add a utility function to calculate both of
// below StyleAnimationValues.
DebugOnly<bool> accumulateResult =
StyleAnimationValue::Accumulate(prop.mProperty,
fromValue,
lastSegment.mToValue,
computedTiming.mCurrentIteration);
// We can't check the accumulation result in case of filter property.
// That's because some filter property can't accumulate,
// e.g. 'contrast(2) brightness(2)' onto 'brightness(1) contrast(1)'
// because of mismatch of the order.
MOZ_ASSERT(accumulateResult || prop.mProperty == eCSSProperty_filter,
"could not accumulate value");
accumulateResult =
StyleAnimationValue::Accumulate(prop.mProperty,
toValue,
lastSegment.mToValue,
computedTiming.mCurrentIteration);
MOZ_ASSERT(accumulateResult || prop.mProperty == eCSSProperty_filter,
"could not accumulate value");
}
// Special handling for zero-length segments
if (segment->mToKey == segment->mFromKey) {
if (computedTiming.mProgress.Value() < 0) {
aStyleRule->AddValue(prop.mProperty, segment->mFromValue);
aStyleRule->AddValue(prop.mProperty, Move(fromValue));
} else {
aStyleRule->AddValue(prop.mProperty, segment->mToValue);
aStyleRule->AddValue(prop.mProperty, Move(toValue));
}
continue;
}
@ -394,14 +424,14 @@ KeyframeEffectReadOnly::ComposeStyle(RefPtr<AnimValuesStyleRule>& aStyleRule,
MOZ_ASSERT(IsFinite(valuePosition), "Position value should be finite");
StyleAnimationValue val;
if (StyleAnimationValue::Interpolate(prop.mProperty,
segment->mFromValue,
segment->mToValue,
fromValue,
toValue,
valuePosition, val)) {
aStyleRule->AddValue(prop.mProperty, Move(val));
} else if (valuePosition < 0.5) {
aStyleRule->AddValue(prop.mProperty, segment->mFromValue);
aStyleRule->AddValue(prop.mProperty, Move(fromValue));
} else {
aStyleRule->AddValue(prop.mProperty, segment->mToValue);
aStyleRule->AddValue(prop.mProperty, Move(toValue));
}
}
}
@ -482,6 +512,7 @@ KeyframeEffectParamsFromUnion(const OptionsType& aOptions,
result.mPacedProperty,
aInvalidPacedProperty,
aRv);
result.mIterationComposite = options.mIterationComposite;
}
return result;
}

View File

@ -69,8 +69,7 @@ partial interface KeyframeEffectReadOnly {
optional (unrestricted double or KeyframeEffectOptions) options)]
interface KeyframeEffect : KeyframeEffectReadOnly {
inherit attribute (Element or CSSPseudoElement)? target;
// Bug 1216843 - implement animation composition
// inherit attribute IterationCompositeOperation iterationComposite;
inherit attribute IterationCompositeOperation iterationComposite;
// Bug 1216844 - implement additive animation
// inherit attribute CompositeOperation composite;
[SetterThrows]

View File

@ -16,6 +16,7 @@
#include "mozilla/WidgetUtils.h" // for ComputeTransformForRotation
#include "mozilla/dom/KeyframeEffectReadOnly.h"
#include "mozilla/dom/AnimationEffectReadOnlyBinding.h" // for dom::FillMode
#include "mozilla/dom/KeyframeEffectBinding.h" // for dom::IterationComposite
#include "mozilla/gfx/BaseRect.h" // for BaseRect
#include "mozilla/gfx/Point.h" // for RoundedToInt, PointTyped
#include "mozilla/gfx/Rect.h" // for RoundedToInt, RectTyped
@ -553,18 +554,45 @@ AsyncCompositionManager::AlignFixedAndStickyLayers(Layer* aTransformedSubtreeRoo
}
static void
SampleValue(float aPortion, Animation& aAnimation, StyleAnimationValue& aStart,
StyleAnimationValue& aEnd, Animatable* aValue, Layer* aLayer)
SampleValue(float aPortion, Animation& aAnimation,
const StyleAnimationValue& aStart, const StyleAnimationValue& aEnd,
const StyleAnimationValue& aLastValue, uint64_t aCurrentIteration,
Animatable* aValue, Layer* aLayer)
{
StyleAnimationValue interpolatedValue;
NS_ASSERTION(aStart.GetUnit() == aEnd.GetUnit() ||
aStart.GetUnit() == StyleAnimationValue::eUnit_None ||
aEnd.GetUnit() == StyleAnimationValue::eUnit_None,
"Must have same unit");
StyleAnimationValue startValue = aStart;
StyleAnimationValue endValue = aEnd;
// Iteration composition for accumulate
if (static_cast<dom::IterationCompositeOperation>
(aAnimation.iterationComposite()) ==
dom::IterationCompositeOperation::Accumulate &&
aCurrentIteration > 0) {
// FIXME: Bug 1293492: Add a utility function to calculate both of
// below StyleAnimationValues.
DebugOnly<bool> accumulateResult =
StyleAnimationValue::Accumulate(aAnimation.property(),
startValue,
aLastValue,
aCurrentIteration);
MOZ_ASSERT(accumulateResult, "could not accumulate value");
accumulateResult =
StyleAnimationValue::Accumulate(aAnimation.property(),
endValue,
aLastValue,
aCurrentIteration);
MOZ_ASSERT(accumulateResult, "could not accumulate value");
}
StyleAnimationValue interpolatedValue;
// This should never fail because we only pass transform and opacity values
// to the compositor and they should never fail to interpolate.
DebugOnly<bool> uncomputeResult =
StyleAnimationValue::Interpolate(aAnimation.property(), aStart, aEnd,
StyleAnimationValue::Interpolate(aAnimation.property(),
startValue, endValue,
aPortion, interpolatedValue);
MOZ_ASSERT(uncomputeResult, "could not uncompute value");
@ -683,8 +711,12 @@ SampleAnimations(Layer* aLayer, TimeStamp aPoint)
// interpolate the property
Animatable interpolatedValue;
SampleValue(portion, animation, animData.mStartValues[segmentIndex],
animData.mEndValues[segmentIndex], &interpolatedValue, layer);
SampleValue(portion, animation,
animData.mStartValues[segmentIndex],
animData.mEndValues[segmentIndex],
animData.mEndValues.LastElement(),
computedTiming.mCurrentIteration,
&interpolatedValue, layer);
LayerComposite* layerComposite = layer->AsLayerComposite();
switch (animation.property()) {
case eCSSProperty_opacity:

View File

@ -204,6 +204,7 @@ struct Animation {
float playbackRate;
// This is used in the transformed progress calculation.
TimingFunction easingFunction;
uint8_t iterationComposite;
};
// Change a layer's attributes

View File

@ -430,6 +430,9 @@ AddAnimationForProperty(nsIFrame* aFrame, const AnimationProperty& aProperty,
animation->playbackRate() = aAnimation->PlaybackRate();
animation->data() = aData;
animation->easingFunction() = ToTimingFunction(timing.mFunction);
animation->iterationComposite() =
static_cast<uint8_t>(aAnimation->GetEffect()->
AsKeyframeEffect()->IterationComposite());
for (uint32_t segIdx = 0; segIdx < aProperty.mSegments.Length(); segIdx++) {
const AnimationPropertySegment& segment = aProperty.mSegments[segIdx];

View File

@ -2801,6 +2801,26 @@ StyleAnimationValue::AddWeighted(nsCSSPropertyID aProperty,
return false;
}
bool
StyleAnimationValue::Accumulate(nsCSSPropertyID aProperty,
StyleAnimationValue& aDest,
const StyleAnimationValue& aValueToAccumulate,
uint64_t aCount)
{
Unit commonUnit =
GetCommonUnit(aProperty, aDest.GetUnit(), aValueToAccumulate.GetUnit());
switch (commonUnit) {
// FIXME: implement them!
//case eUnit_Color:
//case eUnit_Shadow:
//case eUnit_Filter:
default:
return Add(aProperty, aDest, aValueToAccumulate, aCount);
}
MOZ_ASSERT_UNREACHABLE("Can't accumulate using the given common unit");
return false;
}
already_AddRefed<css::StyleRule>
BuildStyleRule(nsCSSPropertyID aProperty,
dom::Element* aTargetElement,

View File

@ -129,6 +129,27 @@ public:
double aCoeff2, const StyleAnimationValue& aValue2,
StyleAnimationValue& aResultValue);
/**
* Accumulates |aValueToAccumulate| onto |aDest| |aCount| times.
* The result is stored in |aDest| on success.
*
* @param aDest The base value to be accumulated.
* @param aValueToAccumulate The value to accumulate.
* @param aCount The number of times to accumulate
* aValueToAccumulate.
* @return true on success, false on failure.
*
* NOTE: This function will work as a wrapper of StyleAnimationValue::Add()
* if |aProperty| isn't color or shadow or filter. For these properties,
* this function may return a color value that at least one of its components
* has a value which is outside the range [0, 1] so that we can calculate
* plausible values as interpolation with the return value.
*/
static MOZ_MUST_USE bool
Accumulate(nsCSSPropertyID aProperty, StyleAnimationValue& aDest,
const StyleAnimationValue& aValueToAccumulate,
uint64_t aCount);
// Type-conversion methods
// -----------------------
/**

View File

@ -1,74 +1,11 @@
[iterationComposite.html]
type: testharness
[iterationComposite of <length> type animation]
expected: FAIL
[iterationComposite of <percentage> type animation]
expected: FAIL
[iterationComposite of <color> type animation]
expected: FAIL
[iterationComposite of <number> type animation]
expected: FAIL
[iterationComposite of <shape> type animation]
expected: FAIL
[iterationComposite of <calc()> value animation]
expected: FAIL
[iterationComposite of opacity animation]
expected: FAIL
[iterationComposite of filter blur animation]
expected: FAIL
[iterationComposite of filter brightness for different unit animation]
expected: FAIL
[iterationComposite of filter drop-shadow animation]
expected: FAIL
[iterationComposite of same filter list animation]
expected: FAIL
[iterationComposite of discrete filter list because of mismatch of the order]
expected: FAIL
[iterationComposite of different length filter list animation]
expected: FAIL
[iterationComposite of transform: [ scale(1), scale(2) \] animation]
expected: FAIL
[iterationComposite of transform: scale(2) animation]
expected: FAIL
[iterationComposite of transform list animation]
expected: FAIL
[iterationComposite starts with non-zero value animation]
expected: FAIL
[iterationComposite with negative final value animation]
expected: FAIL
[interationComposite changes]
expected: FAIL
[duration changes with iterationComposite(accumulate)]
expected: FAIL
[iterationComposite of box-shadow animation]
expected: FAIL
[iterationComposite of <color> type animation that green component is decreasing]
expected: FAIL
[iterationComposite of <calc()> value animation that the values can'tbe reduced]
expected: FAIL
[iterationComposite of transform list animation whose order is mismatched]
expected: FAIL