Bug 1402219 - Compute css variables with custom properties in keyframes for getKeyframes(). r?birtles draft
authorHiroyuki Ikezoe <hikezoe@mozilla.com>
Wed, 27 Sep 2017 16:49:21 +0900
changeset 670945 c4b5b40ce56147427ddd29e9718f5d791ffe7422
parent 670944 8b0226b32c32e3b8cf961bd573976344db006849
child 733365 8c4c5182b662ebbedf42268167cf3b1f3da0a512
push id81772
push userhikezoe@mozilla.com
push dateWed, 27 Sep 2017 07:49:35 +0000
reviewersbirtles
bugs1402219
milestone58.0a1
Bug 1402219 - Compute css variables with custom properties in keyframes for getKeyframes(). r?birtles MozReview-Commit-ID: 7CMnWbzzemY
dom/animation/KeyframeEffectReadOnly.cpp
dom/animation/test/css-animations/file_keyframeeffect-getkeyframes.html
layout/style/ServoBindingList.h
--- a/dom/animation/KeyframeEffectReadOnly.cpp
+++ b/dom/animation/KeyframeEffectReadOnly.cpp
@@ -1250,28 +1250,49 @@ KeyframeEffectReadOnly::GetKeyframes(JSC
     }
 
     JS::Rooted<JS::Value> keyframeJSValue(aCx);
     if (!ToJSValue(aCx, keyframeDict, &keyframeJSValue)) {
       aRv.Throw(NS_ERROR_FAILURE);
       return;
     }
 
+    RefPtr<RawServoDeclarationBlock> customProperties;
+    // A workaround for CSS Animations in servo backend, custom properties in
+    // keyframe are stored in a servo's declaration block. Find the declaration
+    // block to resolve CSS variables in the keyframe.
+    // This workaround will be solved by bug 1391537.
+    if (isServo && isCSSAnimation) {
+      for (const PropertyValuePair& propertyValue : keyframe.mPropertyValues) {
+        if (propertyValue.mProperty ==
+              nsCSSPropertyID::eCSSPropertyExtra_variable) {
+          customProperties = propertyValue.mServoDeclarationBlock;
+          break;
+        }
+      }
+    }
+
     JS::Rooted<JSObject*> keyframeObject(aCx, &keyframeJSValue.toObject());
     for (const PropertyValuePair& propertyValue : keyframe.mPropertyValues) {
       nsAutoString stringValue;
       if (isServo) {
+        // Don't serialize the custom properties for this keyframe.
+        if (propertyValue.mProperty ==
+              nsCSSPropertyID::eCSSPropertyExtra_variable) {
+          continue;
+        }
         if (propertyValue.mServoDeclarationBlock) {
           const ServoStyleContext* servoStyleContext =
             styleContext ? styleContext->AsServo() : nullptr;
           Servo_DeclarationBlock_SerializeOneValue(
             propertyValue.mServoDeclarationBlock,
             propertyValue.mProperty,
             &stringValue,
-            servoStyleContext);
+            servoStyleContext,
+            customProperties);
         } else {
           RawServoAnimationValue* value =
             mBaseStyleValuesForServo.GetWeak(propertyValue.mProperty);
 
           if (value) {
             Servo_AnimationValue_Serialize(value,
                                            propertyValue.mProperty,
                                            &stringValue);
--- a/dom/animation/test/css-animations/file_keyframeeffect-getkeyframes.html
+++ b/dom/animation/test/css-animations/file_keyframeeffect-getkeyframes.html
@@ -131,23 +131,31 @@
 }
 
 @keyframes anim-background-size {
   to { background-size: 50%, 6px, contain }
 }
 
 :root {
   --var-100px: 100px;
+  --end-color: rgb(255, 0, 0);
 }
 @keyframes anim-variables {
   to { transform: translate(var(--var-100px), 0) }
 }
 @keyframes anim-variables-shorthand {
   to { margin: var(--var-100px) }
 }
+@keyframes anim-custom-property-in-keyframe {
+  to { --end-color: rgb(0, 255, 0); color: var(--end-color) }
+}
+@keyframes anim-only-custom-property-in-keyframe {
+  from { transform: translate(100px, 0) }
+  to { --not-used: 200px }
+}
 </style>
 <body>
 <script>
 "use strict";
 
 function getKeyframes(e) {
   return e.getAnimations()[0].effect.getKeyframes();
 }
@@ -694,11 +702,52 @@ test(function(t) {
       marginRight: "100px",
       marginTop: "100px" },
   ];
   for (var i = 0; i < frames.length; i++) {
     assert_frames_equal(frames[i], expected[i], "ComputedKeyframe #" + i);
   }
 }, 'KeyframeEffectReadOnly.getKeyframes() returns expected values for ' +
    'animations with CSS variables as keyframe values in a shorthand property');
+
+test(function(t) {
+  var div = addDiv(t);
+  div.style.animation = 'anim-custom-property-in-keyframe 100s';
+
+  var frames = getKeyframes(div);
+
+  assert_equals(frames.length, 2, "number of frames");
+
+  var expected = [
+    { offset: 0, computedOffset: 0, easing: "ease",
+      color: "rgb(0, 0, 0)" },
+    { offset: 1, computedOffset: 1, easing: "ease",
+      color: "rgb(0, 255, 0)" },
+  ];
+  for (var i = 0; i < frames.length; i++) {
+    assert_frames_equal(frames[i], expected[i], "ComputedKeyframe #" + i);
+  }
+}, 'KeyframeEffectReadOnly.getKeyframes() returns expected values for ' +
+   'animations with a CSS variable which is overriden by the value in keyframe');
+
+test(function(t) {
+  var div = addDiv(t);
+  div.style.animation = 'anim-only-custom-property-in-keyframe 100s';
+
+  var frames = getKeyframes(div);
+
+  assert_equals(frames.length, 2, "number of frames");
+
+  var expected = [
+    { offset: 0, computedOffset: 0, easing: "ease",
+      transform: "translate(100px, 0px)" },
+    { offset: 1, computedOffset: 1, easing: "ease",
+      transform: "none" },
+  ];
+  for (var i = 0; i < frames.length; i++) {
+    assert_frames_equal(frames[i], expected[i], "ComputedKeyframe #" + i);
+  }
+}, 'KeyframeEffectReadOnly.getKeyframes() returns expected values for ' +
+   'animations with only custom property in a keyframe');
+
 done();
 </script>
 </body>
--- a/layout/style/ServoBindingList.h
+++ b/layout/style/ServoBindingList.h
@@ -386,17 +386,18 @@ SERVO_BINDING_FUNC(Servo_DeclarationBloc
                    RawServoDeclarationBlockBorrowed a,
                    RawServoDeclarationBlockBorrowed b)
 SERVO_BINDING_FUNC(Servo_DeclarationBlock_GetCssText, void,
                    RawServoDeclarationBlockBorrowed declarations,
                    nsAString* result)
 SERVO_BINDING_FUNC(Servo_DeclarationBlock_SerializeOneValue, void,
                    RawServoDeclarationBlockBorrowed declarations,
                    nsCSSPropertyID property, nsAString* buffer,
-                   ServoStyleContextBorrowedOrNull computed_values)
+                   ServoStyleContextBorrowedOrNull computed_values,
+                   RawServoDeclarationBlockBorrowedOrNull custom_properties)
 SERVO_BINDING_FUNC(Servo_DeclarationBlock_Count, uint32_t,
                    RawServoDeclarationBlockBorrowed declarations)
 SERVO_BINDING_FUNC(Servo_DeclarationBlock_GetNthProperty, bool,
                    RawServoDeclarationBlockBorrowed declarations,
                    uint32_t index, nsAString* result)
 SERVO_BINDING_FUNC(Servo_DeclarationBlock_GetPropertyValue, void,
                    RawServoDeclarationBlockBorrowed declarations,
                    const nsACString* property, nsAString* value)