Bug 1354947 - Fill in missing keyframe values. r?birtles
This is mostly a mimic of what we do in
GeckoCSSAnimationBuilder::FillInMissingKeyframeValues().
In Gecko we iterate over the properties just once because we can take the
index for both the synthesized start and end keyframe and easily look them up
as needed. However, in this patch we synthesize the start and end keyframes
separately and iterate over the properties twice because that's easier than
getting two indices and then later calling another FFI to dereference each of
them, and neater than getting back two pointers
MozReview-Commit-ID: 1e0R9AKzgaG
--- a/js/src/devtools/rootAnalysis/analyzeHeapWrites.js
+++ b/js/src/devtools/rootAnalysis/analyzeHeapWrites.js
@@ -189,16 +189,18 @@ function treatAsSafeArgument(entry, varN
["Gecko_ClearPODTArray", "aArray", null],
["Gecko_ClearAndResizeStyleContents", "aContent", null],
[/Gecko_ClearAndResizeCounter/, "aContent", null],
[/Gecko_CopyCounter.*?From/, "aContent", null],
[/Gecko_SetContentData/, "aContent", null],
[/Gecko_EnsureStyle.*?ArrayLength/, "aArray", null],
["Gecko_AnimationAppendKeyframe", "aKeyframes", null],
["Gecko_GetOrCreateKeyframeAtStart", "aKeyframes", null],
+ ["Gecko_GetOrCreateInitialKeyframe", "aKeyframes", null],
+ ["Gecko_GetOrCreateFinalKeyframe", "aKeyframes", null],
["Gecko_SetStyleCoordCalcValue", null, null],
["Gecko_StyleClipPath_SetURLValue", "aClip", null],
["Gecko_nsStyleFilter_SetURLValue", "aEffects", null],
["Gecko_nsStyleSVGPaint_CopyFrom", "aDest", null],
["Gecko_nsStyleSVGPaint_SetURLValue", "aPaint", null],
["Gecko_nsStyleSVGPaint_Reset", "aPaint", null],
["Gecko_nsStyleSVG_SetDashArrayLength", "aSvg", null],
["Gecko_nsStyleSVG_CopyDashArray", "aDst", null],
@@ -371,16 +373,18 @@ function ignoreContents(entry)
/nsCSSProps::LookupPropertyValue/,
/nsCSSProps::ValueToKeyword/,
/nsCSSKeywords::GetStringValue/,
// The analysis can't cope with the indirection used for the objects
// being initialized here.
"Gecko_AnimationAppendKeyframe",
"Gecko_GetOrCreateKeyframeAtStart",
+ "Gecko_GetOrCreateInitialKeyframe",
+ "Gecko_GetOrCreateFinalKeyframe",
"Gecko_NewStyleQuoteValues",
"Gecko_NewCSSValueSharedList",
"Gecko_NewGridTemplateAreasValue",
/nsCSSValue::SetCalcValue/,
/CSSValueSerializeCalcOps::Append/,
"Gecko_CSSValue_SetFunction",
"Gecko_CSSValue_SetArray",
"Gecko_EnsureMozBorderColors",
--- a/layout/style/ServoBindings.cpp
+++ b/layout/style/ServoBindings.cpp
@@ -1463,48 +1463,112 @@ Gecko_AnimationAppendKeyframe(RawGeckoKe
aTimingFunction->mType != nsTimingFunction::Type::Linear) {
keyframe->mTimingFunction.emplace();
keyframe->mTimingFunction->Init(*aTimingFunction);
}
return keyframe;
}
-Keyframe*
-Gecko_GetOrCreateKeyframeAtStart(nsTArray<Keyframe>* aKeyframes,
- float aOffset,
- const nsTimingFunction* aTimingFunction)
+enum class KeyframeSearchDirection {
+ Forwards,
+ Backwards,
+};
+
+enum class KeyframeInsertPosition {
+ Prepend,
+ LastForOffset,
+};
+
+static Keyframe*
+GetOrCreateKeyframe(nsTArray<Keyframe>* aKeyframes,
+ float aOffset,
+ const nsTimingFunction* aTimingFunction,
+ KeyframeSearchDirection aSearchDirection,
+ KeyframeInsertPosition aInsertPosition)
{
MOZ_ASSERT(aKeyframes, "The keyframe array should be valid");
MOZ_ASSERT(aTimingFunction, "The timing function should be valid");
MOZ_ASSERT(aOffset >= 0. && aOffset <= 1.,
"The offset should be in the range of [0.0, 1.0]");
- MOZ_ASSERT(aKeyframes->IsEmpty() ||
- aKeyframes->ElementAt(0).mOffset.value() >= aOffset,
- "The offset should be less than or equal to the first keyframe's "
- "offset if there are exisiting keyframes");
size_t keyframeIndex;
- if (nsAnimationManager::FindMatchingKeyframe(*aKeyframes,
- aOffset,
- *aTimingFunction,
- keyframeIndex)) {
- return &(*aKeyframes)[keyframeIndex];
+ switch (aSearchDirection) {
+ case KeyframeSearchDirection::Forwards:
+ if (nsAnimationManager::FindMatchingKeyframe(*aKeyframes,
+ aOffset,
+ *aTimingFunction,
+ keyframeIndex)) {
+ return &(*aKeyframes)[keyframeIndex];
+ }
+ break;
+ case KeyframeSearchDirection::Backwards:
+ if (nsAnimationManager::FindMatchingKeyframe(Reversed(*aKeyframes),
+ aOffset,
+ *aTimingFunction,
+ keyframeIndex)) {
+ return &(*aKeyframes)[aKeyframes->Length() - 1 - keyframeIndex];
+ }
+ keyframeIndex = aKeyframes->Length() - 1;
+ break;
}
- Keyframe* keyframe = aKeyframes->InsertElementAt(0);
+ Keyframe* keyframe =
+ aKeyframes->InsertElementAt(
+ aInsertPosition == KeyframeInsertPosition::Prepend
+ ? 0
+ : keyframeIndex);
keyframe->mOffset.emplace(aOffset);
if (aTimingFunction->mType != nsTimingFunction::Type::Linear) {
keyframe->mTimingFunction.emplace();
keyframe->mTimingFunction->Init(*aTimingFunction);
}
return keyframe;
}
+Keyframe*
+Gecko_GetOrCreateKeyframeAtStart(nsTArray<Keyframe>* aKeyframes,
+ float aOffset,
+ const nsTimingFunction* aTimingFunction)
+{
+ MOZ_ASSERT(aKeyframes->IsEmpty() ||
+ aKeyframes->ElementAt(0).mOffset.value() >= aOffset,
+ "The offset should be less than or equal to the first keyframe's "
+ "offset if there are exisiting keyframes");
+
+ return GetOrCreateKeyframe(aKeyframes,
+ aOffset,
+ aTimingFunction,
+ KeyframeSearchDirection::Forwards,
+ KeyframeInsertPosition::Prepend);
+}
+
+Keyframe*
+Gecko_GetOrCreateInitialKeyframe(nsTArray<Keyframe>* aKeyframes,
+ const nsTimingFunction* aTimingFunction)
+{
+ return GetOrCreateKeyframe(aKeyframes,
+ 0.,
+ aTimingFunction,
+ KeyframeSearchDirection::Forwards,
+ KeyframeInsertPosition::LastForOffset);
+}
+
+Keyframe*
+Gecko_GetOrCreateFinalKeyframe(nsTArray<Keyframe>* aKeyframes,
+ const nsTimingFunction* aTimingFunction)
+{
+ return GetOrCreateKeyframe(aKeyframes,
+ 1.,
+ aTimingFunction,
+ KeyframeSearchDirection::Backwards,
+ KeyframeInsertPosition::LastForOffset);
+}
+
void
Gecko_ResetStyleCoord(nsStyleUnit* aUnit, nsStyleUnion* aValue)
{
nsStyleCoord::Reset(*aUnit, *aValue);
}
void
Gecko_SetStyleCoordCalcValue(nsStyleUnit* aUnit, nsStyleUnion* aValue, nsStyleCoord::CalcValue aCalc)
--- a/layout/style/ServoBindings.h
+++ b/layout/style/ServoBindings.h
@@ -387,16 +387,33 @@ mozilla::Keyframe* Gecko_AnimationAppend
// Keyframe is found, to set on the created Keyframe.
//
// @returns The matching or created Keyframe.
mozilla::Keyframe* Gecko_GetOrCreateKeyframeAtStart(
RawGeckoKeyframeListBorrowedMut keyframes,
float offset,
const nsTimingFunction* timingFunction);
+// As with Gecko_GetOrCreateKeyframeAtStart except that this method will search
+// from the beginning of |keyframes| for a Keyframe with matching timing
+// function and an offset of 0.0.
+// Furthermore, if a matching Keyframe is not found, a new Keyframe will be
+// inserted after the *last* Keyframe in |keyframes| with offset 0.0.
+mozilla::Keyframe* Gecko_GetOrCreateInitialKeyframe(
+ RawGeckoKeyframeListBorrowedMut keyframes,
+ const nsTimingFunction* timingFunction);
+
+// As with Gecko_GetOrCreateKeyframeAtStart except that this method will search
+// from the *end* of |keyframes| for a Keyframe with matching timing function
+// and an offset of 1.0. If a matching Keyframe is not found, a new Keyframe
+// will be appended to the end of |keyframes|.
+mozilla::Keyframe* Gecko_GetOrCreateFinalKeyframe(
+ RawGeckoKeyframeListBorrowedMut keyframes,
+ const nsTimingFunction* timingFunction);
+
// Clean up pointer-based coordinates
void Gecko_ResetStyleCoord(nsStyleUnit* unit, nsStyleUnion* value);
// Set an nsStyleCoord to a computed `calc()` value
void Gecko_SetStyleCoordCalcValue(nsStyleUnit* unit, nsStyleUnion* value, nsStyleCoord::CalcValue calc);
void Gecko_CopyShapeSourceFrom(mozilla::StyleShapeSource* dst, const mozilla::StyleShapeSource* src);