Bug 1244590 - Part 4: Rewrite ApplyDistributeSpacing.
Rename it to ApplySpacing, and let it handle both distribute and paced mode.
MozReview-Commit-ID: 2kGA6LMHUsz
--- a/dom/animation/KeyframeEffect.cpp
+++ b/dom/animation/KeyframeEffect.cpp
@@ -464,17 +464,21 @@ void
KeyframeEffectReadOnly::SetKeyframes(nsTArray<Keyframe>&& aKeyframes,
nsStyleContext* aStyleContext)
{
if (KeyframesEqualIgnoringComputedOffsets(aKeyframes, mKeyframes)) {
return;
}
mKeyframes = Move(aKeyframes);
- KeyframeUtils::ApplyDistributeSpacing(mKeyframes);
+ // Apply distribute spacing irrespective of the spacing mode. We will apply
+ // the specified spacing mode when we generate computed animation property
+ // values from the keyframes since both operations require a style context
+ // and need to be performed whenever the style context changes.
+ KeyframeUtils::ApplySpacing(mKeyframes, SpacingMode::distribute);
if (mAnimation && mAnimation->IsRelevant()) {
nsNodeUtils::AnimationChanged(mAnimation);
}
if (aStyleContext) {
UpdateProperties(aStyleContext);
}
--- a/dom/animation/KeyframeUtils.cpp
+++ b/dom/animation/KeyframeUtils.cpp
@@ -378,16 +378,18 @@ GetKeyframeListFromPropertyIndexedKeyfra
JS::Handle<JS::Value> aValue,
nsTArray<Keyframe>& aResult,
ErrorResult& aRv);
static bool
RequiresAdditiveAnimation(const nsTArray<Keyframe>& aKeyframes,
nsIDocument* aDocument);
+static void
+DistributeRange(const Range<Keyframe>& aKeyframes);
// ------------------------------------------------------------------
//
// Public API
//
// ------------------------------------------------------------------
/* static */ nsTArray<Keyframe>
@@ -444,48 +446,55 @@ KeyframeUtils::GetKeyframesFromObject(JS
aRv.Throw(NS_ERROR_DOM_ANIM_MISSING_PROPS_ERR);
keyframes.Clear();
}
return keyframes;
}
/* static */ void
-KeyframeUtils::ApplyDistributeSpacing(nsTArray<Keyframe>& aKeyframes)
+KeyframeUtils::ApplySpacing(nsTArray<Keyframe>& aKeyframes,
+ SpacingMode aSpacingMode)
{
if (aKeyframes.IsEmpty()) {
return;
}
- // If the first or last keyframes have an unspecified offset,
- // fill them in with 0% and 100%. If there is only a single keyframe,
- // then it gets 100%.
- Keyframe& lastElement = aKeyframes.LastElement();
- lastElement.mComputedOffset = lastElement.mOffset.valueOr(1.0);
+ // If the first keyframes have an unspecified offset, fill it in with 0%.
+ // If there is only a single keyframe, then it gets 100%.
if (aKeyframes.Length() > 1) {
Keyframe& firstElement = aKeyframes[0];
firstElement.mComputedOffset = firstElement.mOffset.valueOr(0.0);
+ // We will fill in the last keyframe's offset below
+ } else {
+ Keyframe& lastElement = aKeyframes.LastElement();
+ lastElement.mComputedOffset = lastElement.mOffset.valueOr(1.0);
}
// Fill in remaining missing offsets.
- size_t i = 0;
- while (i < aKeyframes.Length() - 1) {
- double start = aKeyframes[i].mComputedOffset;
- size_t j = i + 1;
- while (aKeyframes[j].mOffset.isNothing() && j < aKeyframes.Length() - 1) {
- ++j;
+ const Keyframe* const last = aKeyframes.cend() - 1;
+ RangedPtr<Keyframe> keyframeA(aKeyframes.begin(), aKeyframes.Length());
+ while (keyframeA != last) {
+ // Find keyframe A and keyframe B *between* which we will apply spacing.
+ RangedPtr<Keyframe> keyframeB = keyframeA + 1;
+ while (keyframeB.get()->mOffset.isNothing() && keyframeB != last) {
+ ++keyframeB;
}
- double end = aKeyframes[j].mOffset.valueOr(1.0);
- size_t n = j - i;
- for (size_t k = 1; k < n; ++k) {
- double offset = start + double(k) / n * (end - start);
- aKeyframes[i + k].mComputedOffset = offset;
+ keyframeB.get()->mComputedOffset = keyframeB.get()->mOffset.valueOr(1.0);
+
+ // Fill computed offsets in (keyframe A, keyframe B).
+ if (aSpacingMode == SpacingMode::distribute) {
+ DistributeRange(Range<Keyframe>(keyframeA.get(),
+ keyframeB - keyframeA + 1));
+ } else {
+ // TODO
+ MOZ_ASSERT(false, "not implement yet");
}
- i = j;
- aKeyframes[j].mComputedOffset = end;
+
+ keyframeA = keyframeB;
}
}
/* static */ nsTArray<AnimationProperty>
KeyframeUtils::GetAnimationPropertiesFromKeyframes(
nsStyleContext* aStyleContext,
dom::Element* aElement,
CSSPseudoElementType aPseudoType,
@@ -1130,17 +1139,17 @@ RequiresAdditiveAnimation(const nsTArray
} else if (aOffset == 1.0) {
propertiesWithToValue.AddProperty(aProperty);
}
};
for (size_t i = 0, len = aKeyframes.Length(); i < len; i++) {
const Keyframe& frame = aKeyframes[i];
- // We won't have called ApplyDistributeSpacing when this is called so
+ // We won't have called ApplySpacing when this is called so
// we can't use frame.mComputedOffset. Instead we do a rough version
// of that algorithm that substitutes null offsets with 0.0 for the first
// frame, 1.0 for the last frame, and 0.5 for everything else.
double computedOffset = i == len - 1
? 1.0
: i == 0 ? 0.0 : 0.5;
double offsetToUse = frame.mOffset
? frame.mOffset.value()
@@ -1167,9 +1176,28 @@ RequiresAdditiveAnimation(const nsTArray
}
}
}
return !propertiesWithFromValue.Equals(properties) ||
!propertiesWithToValue.Equals(properties);
}
+/**
+ * Evenly distribute the computed offsets in (A, B). We should pass the
+ * range keyframes in [A, B] and use A, B to calculate computed offsets in
+ * (A, B).
+ *
+ * @param aKeyframes The sequence of keyframes between whose endpoints we should
+ * apply distribute spacing.
+ */
+static void
+DistributeRange(const Range<Keyframe>& aKeyframes)
+{
+ const size_t n = aKeyframes.length() - 1;
+ const double startOffset = aKeyframes[0].mComputedOffset;
+ const double diffOffset = aKeyframes[n].mComputedOffset - startOffset;
+ for (size_t i = 1; i < n; ++i) {
+ aKeyframes[i].mComputedOffset = startOffset + double(i) / n * diffOffset;
+ }
+}
+
} // namespace mozilla
--- a/dom/animation/KeyframeUtils.h
+++ b/dom/animation/KeyframeUtils.h
@@ -48,23 +48,25 @@ public:
*/
static nsTArray<Keyframe>
GetKeyframesFromObject(JSContext* aCx,
JS::Handle<JSObject*> aFrames,
ErrorResult& aRv);
/**
* Fills in the mComputedOffset member of each keyframe in the given array
- * using the "distribute" spacing algorithm.
+ * using the specified spacing mode.
*
- * http://w3c.github.io/web-animations/#distribute-keyframe-spacing-mode
+ * https://w3c.github.io/web-animations/#spacing-keyframes
*
- * @param keyframes The set of keyframes to adjust.
+ * @param aKeyframes The set of keyframes to adjust.
+ * @param aSpacingMode The spacing mode to apply.
*/
- static void ApplyDistributeSpacing(nsTArray<Keyframe>& aKeyframes);
+ static void ApplySpacing(nsTArray<Keyframe>& aKeyframes,
+ SpacingMode aSpacingMode);
/**
* Converts an array of Keyframe objects into an array of AnimationProperty
* objects. This involves expanding shorthand properties into longhand
* properties, creating an array of computed values for each longhand
* property and determining the offset and timing function to use for each
* value.
*